Skip to content

Instantly share code, notes, and snippets.

@distributedlife
Created July 16, 2012 09:37
Show Gist options
  • Save distributedlife/3121835 to your computer and use it in GitHub Desktop.
Save distributedlife/3121835 to your computer and use it in GitHub Desktop.
How best to model thi
draw = function() {
painter.clear();
things.forEach(function(thing) {
if(thing.active) {
painter.draw(thing);
}
});
};
animate = function() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
};
Someone at some point needs to called animate() to kick of the animation loop.
this.collide = function(other_thing) {
if (other_thing.team == Team.Earth) {
this.active = false;
scene.remove(this.mesh);
}
};
this.collide = function(other_thing) {
if (other_thing.team == Team.Earth) {
this.active = false;
mesh.visible = false;
}
};
things.forEach(function(thing) {
if(thing.active) {
scene.remove(the_mesh_of_thing);
}
});
So Mike (and Scott, I'm bringing you in for ye opinion.)
So i'm switching over the testinvaders code from atom/canvas to three.js/webgl. Why? Because it's the future and because I can.
I'm mulling about how to model everything. There are some differences between how atom and three.js work. Mainly three.js doing things that are generally more performant or susceptible to better performance.
In atom; we drew like <exhibit_a.js>
In three.js; we draw like <exhibit_b.js>
The main difference is we don't iterate our list of things and only draw those that are active. Three.js just draws whatever is in the scene graph.
So now we have to answer the problem or who is responsible for putting something in and removing something from a scene. We also have to deal with meshes. The mesh is what will be rendered. The prior implementation just blatted a sprite to a screen using x and y coordinates. Now we have one mesh per drawable thing all of which are placed into the scene graph. Updating the position of the mesh draws will cause the scene to be rebuilt with the mesh in the correct spot.
So there:
- is a scene
- are scene objects (invader mesh, tank mesh, etc)
- are our domain objects (invader, tank, etc)
From past experience I have merged the invader and invader-mesh code so that domain objects knew about their representation. I'm not so sure now thinking from a nicer model perspective.
The trick is that when an invader dies it sets itself to inactive. The scene needs to be told not to render that invader mesh. So scene.remove(mesh) or mesh.visbile = false.
If a thing knows about the scene then we can do exhibit_c.js
If a thing knows about the mesh then we can do exhibit_d.js
If a thing knows about nothing; then someone else needs to do some work.
I think it'll be pointless to put in a loop every frame to see if we should draw a thing: exhibit_e.js
An option is to use the observer pattern. So that when thing becomes inactive it tells it's observers. The observer then removes the thing from the sccene graph. Or the observer is the thing_mesh which tells it's observer to remove itself from the scene so that thing_mesh doesn't know about the scene graph and just looks after it's own representation.
This means we would have a scene graph object that observes a list of thing_mesh objects that each observe their domain model counterpart.
I think this works nicely because if we have 3 different invaders then you just have different invader_mesh classes while their domain model is a plain old invader (unless they end up with different behaviour).
On the other hand is it that bad to give each thing it's own mesh. Have the scene setup put the thing.mesh into the graph and then each thing can use visible=true/false to control whether they are visible.
Advice please.
@quad
Copy link

quad commented Jul 16, 2012

Then I'd say the simplicity gained from merging the two is limited.

I'd have a separate domain and scene objects and do one of three things:

  1. Functional transformation. If building the scene objects gets expensive, then memoize.
  2. MVC with the controller actions triggered by an event stream from the model. (create, update, delete)
  3. Middle ground: pure event stream (addInvader, invaderTranslate, invaderAnimDie, invaderAnimShoot, deleteInvader)

@distributedlife
Copy link
Author

Yep; you've convinced me. Separate them.

Hmmm... MVC starts to make sense. However, I'm not sure what you mean by a functional transformation approach. Can you point me to an a good example?

@quad
Copy link

quad commented Jul 17, 2012

I used a really messy draw_list transformation approach in the original invader.love. Each domain object emitted the instructions for rendering.

https://github.com/quad/invader.love/blob/master/main.lua#L28

The more classic approach is to walk the domain objects as a tree, creating scene graph objects on traversal.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment