I just have a somewhat simple question on coding practices. I have never written a large application before and I am currently working on building a game engine in JavaScript. The part that confuses me is what the best method of organization is in this particular case.
I have my base engine class, Engine
, a graphics class, GFXSystem
, and I eventually plan on adding a physics system class. I am utilizing the entity component model, so each object in the game world is represented as an entity and various data classes, called components, are added to an entity to represent its state and allow it to do things.
Some components need to report to the GFXSystem
so that it knows to include them when it renders to the screen. The engine class is the all encompassing class that keeps track of both the entities and the graphics system, and calls the update method each frame to run update on each component on each entity and tells the GFXSystem
to draw the next frame. An engine will always have one GFXSystem
.
I started off exposing both the engine and the graphics system to window. I decided against this and then tried letting the engine have a reference to the graphics system and instead had the entity store a reference to the engine it was attached to. This then resulted in the components having to call the following to tell the GFX system that it needed to be rendered, which seems wrong:
this.entity.engine.gfx.addToDraw(this)
Is that really how I should be doing things or is there some better structure I could follow? Not all components even need to do anything outside their own data.
Here is a sample of some of my code, bear with me, it is a bit hastily done since I am still in the initial stage of writing things just to get it to work.
var Engine = function(){
this.graphics = new GFXSystem();
this.keyboard;
this.keys;
this.mouse;
this.__entityList = new EntityList();
//window.engine = this;
//window.renderer = this.__renderer;
this.start = function(){
this.graphics.start();
this.keyboard = new Keyboard();
this.keys = new Keys();
this.mouse = new Mouse();
}
this.update = function(time){
for(var handle = this.__entityList.head; handle != null; handle = handle.next){
handle.entity.updateComponents(time);
}
this.graphics.update(time);
};
this.addEntity = function(entity){
this.__entityList.Add(entity);
entity.engine = this;
};
};
Graphics
var GFXSystem = function(){
this.renderer = null;
this.width = document.body.clientWidth;
this.height = document.body.clientHeight;
this.camera = null;
this.scene = null;
this.__list = new EntityList();
this.start = function(){
this.renderer = new THREE.WebGLRenderer({antialias: true});
this.renderer.setSize(this.width, this.height);
document.body.appendChild(this.renderer.domElement);
this.renderer.setClearColorHex(0xeeeeee, 1.0);
this.renderer.clear();
//this.camera = new THREE.PerspectiveCamera(45, this.width/this.height, 1, 10000);
//this.camera.position.z = 300;
this.scene = new THREE.Scene();
}
this.update = function(time){
/*
this.camera.position.x = Math.sin(time/1000)*300;
this.camera.position.y = 150;
this.camera.position.z = Math.cos(time/1000)*300;
*/
// you need to update lookAt on every frame
this.renderer.render(this.scene, this.camera.camera);
}
this.registerEntity = function(entity){
this.__list.Add(entity);
this.scene.add(entity.getComponent('render').model);
}
this.removeEntity = function(entity){
this.__list.Remove(entity);
this.scene.remove(entity.getComponent('render').model);
}
}
Component
var RenderComponent = function(model){
this.model = model;
this.start = function(){
var pos = this.entity.getComponent('position');
model.position.x = pos.x;
model.position.y = pos.y;
model.position.z = pos.z;
this.entity.engine.graphics.renderer.registerEntity(this.entity);
};
this.update = function(time){
var pos = this.entity.getComponent('position');
model.position.x = pos.x;
model.position.y = pos.y;
model.position.z = pos.z;
};
this.stop = function(){
this.entity.engine.graphics.removeEntity(this.entity);
};
};
RenderComponent.prototype = new Component();
My old code set window.graphics = this.graphics
and window.engine = this.engine
inside of the engine's start method.