Documentation
Under development.
For now, be sure to check out the full example pages and the source code on GitHub. The code itself is well formed, commented, and split into files.
## Game3
This is the standard namespace for the `Game3` library. When you load this library on your webpage, the `Game3` object should be visible in the default scope as `window.Game3`.
### Members
### `.webgl {Boolean}`
Whether or not the client's browser has WebGL enabled. This may be useful for turning on/off certain optimizations.
## Game3.Class
All classes in `Game3` derive from the base `Class`. It supports a familiar inheritance model, and should prove useful in your object oriented designs.
### Static Methods
### `.extend([parameters])`
Extend a class. You get most of the features you would expect: inherit or override methods from the super class. We currently use [John Resig's](http://ejohn.org/blog/simple-javascript-inheritance/) implementation for classical inheritence.
var Person = Game3.Class.extend({
init: function(name) { this.name = name; },
talk: function() { return 'My name is ' + this.name + '!'; }
});
var Ninja = Person.extend({
talk: function() { return 'Drinks at the ' + this.name + '.'; }
});
var person = new Person('Foo');
var ninja = new Ninja('Bar');
person.talk() // My name is Foo!
ninja.talk() // Drinks at the Bar.
ninja instanceof Person // true
ninja instanceof Game3.Class // true
### Instance Methods
### `.after_init([args ...])`
This method is called right _after_ the `init()` method during construction. The intention here is to make it easy to wrap the logic of an overriden `init()` method (by a subclass, for example). This is to avoid calling the `_super()` method any time you need to do post set up work after some configuration.
__Note:__ `after_init()` is supplied the same arguments as the `init()` constructor.
var File = Game3.Class.extend({
init: function(name) { this.name = name; },
after_init: function(name) { this.full = this.name + '.txt'; }
});
var file = new File('foo');
file.name // foo
file.full // foo.txt
### `.before_init([args ...])`
This method is called right _before_ the `init()` method during construction. The intention here is to make it easy to wrap the logic of an overriden `init()` method (by a subclass, for example). This is to avoid calling the `_super()` method any time you need to do post set up work after some configuration.
__Note:__ `before_init()` is supplied the same arguments as the `init()` constructor.
var File = Game3.Class.extend({
before_init: function(name) { this.ext = '.txt'; }
init: function(name) { this.full = name + this.ext; },
});
var file = new File('foo');
file.ext // .txt
file.full // foo.txt
### `.init([args ...])`
This is the main constructor. Logic placed here will be executed when the object is instantiated. When you define an`init()` constructor for your class, you will override the superclass's `init()` method. You may still call the original method using `this._super(args ...)`.
var File = Game3.Class.extend({
init: function(name) { this.name = name + '.txt'; }
});
var file = new File('foo');
file.name // foo.txt
file instanceof Game3.Class // true
## Game3.Collision
A `Collision` object is sent to any model that has experienced a collision. You can read more about collisions under the `Collisions` class and how to handle collisions in the `Model` class.
### Members
### `.point {THREE.Vector3}`
The closest point of intersection on the _other_ object.
### `.face {THREE.Face?}`
A reference to the face of the mesh on the _other_ object where intersetion occurred. This can be useful for deriving normals and other data.
__Note:__ If the `face` attribute is `null`, it means the collision was computed without ray-tracing. This can occur if you use special case collision detectors. See the `Collisions` class for more details.
### `.other {Game3.Model}`
The other model that was collided with. Useful for performing an action on that model. For example, in physics we may want to exchange momentum in an elastic collision.
### Instance Methods
### `.normal() {THREE.Vector3}`
The normal of the collision. In other words, the orientation of the surface the model collided with. This can be derived for special cases.
### `.correction() {THREE.Vector3}`
The `correction()` vector offers you (free of charge) a way to handle collisions robustly. Because `timerfired()` is called at about 60 FPS, it is possible for objects in the scene to overlap _before_ triggering a collision. Adding the `correction()` back to your object's position can __prevent some nasty bugs__.
## Game3.Collisions
The `Collisions` class gives you a great way to handle collisions in your `scene`. You _could_ handle all this yourself, which comes in handy if you need heavy customization.
### Constructor
### `Collisions([models [, type]])`
__`models`:__ An optional argument. This is an `Array` of `Game3.Model` objects to register with the `Collisions` object. You can always add or remove from this set later on during execution (using `track()` for example).
__`type`:__ If `type` is not specified, then `Game3.COLLISIONS_GENERAL` is used. This specifies the type of collision checking function to use. General works for most geometries, but it is slower.
Currently the only supported types are `Game3.COLLISIONS_GENERAL` and `Game3.COLLISIONS_SPHERES`. _Later we want to support custom check functions, if provided._
init: function(el) {
// setup stuff ...
this.collisions = new Game3.Collisions(
[this.redBall, this.blueBall], Game3.COLLISIONS_SPHERES);
}
### Instance Methods
### `.check()`
This method iterates through every registered `Game3.Model` in the collection and determines whether or not a collision has occurred. If so, a `Collision` event object is created and sent to each model's respective collision handler. The `check()` method is usually called in `timerfired()`.
timerfired: function() {
this.collisions.check();
}
### `.track(model)`
__`model`:__ The model to add to the collection.
All models in the collection will be checked for collisions, and sent `Collision` events accordingly.
init: function(el) {
// setup stuff ...
this.collisions = new Game3.Collisions();
this.collisions.track(this.redBall);
this.collisions.track(this.blueBall);
}
## Game3.Event
This is the standard class for event objects sent to handlers in a `Game3.Model`. If the model has a handler for a particular event, it will recieve it. Read more about this under `Game3.Model`.
__Note:__ Right now, `Game3` only handles mouse events. These are the harder kind to handle, since identifying objects in the 3D scene with respect to 2D click coordinates requires ray tracing. Capturing keypresses is simple! _We are currently figuring out what kind of behavior we want from key events._
### Members
### `.distance {number?}`
The distance from the camera (your viewport) to the object you clicked on. If the distance is `null`, it means you did not click on anything in the scene.
### `.delta2D {THREE.Vector2}`
The change in `x` and `y` since the last mouse event. Useful for dragging without clicking and anything else you can think of!
### `.face {THREE.Face?}`
The particular face of the object you clicked on (if any). If you did not click on an object in the scene, this value will be `null`.
### `.mesh {THREE.Mesh?}`
A reference to the mesh that was sent a mouse event. If no object in the scene recieved a mouse event, this will be `null`.
### `.model {Game3.Model?}`
A reference to the model that recieved the mouse event. Again, if no object in the scene was clicked, this attribute will be `null`. Note: This is usually the same model that we are invoking the event handler for.
### `.native {Event}`
A reference to the native event object that triggered this interaction. You may find more useful metadata here.
### `.point2D {THREE.Vector2}`
The point on the canvas you clicked on. This is with respect to the `canvas` element, not to the `document` dimensions or the window.
### `.point3D {THREE.Vector3?}`
The point in the 3D scene that you clicked on. If you did not click on anything in the scene, this value may be `null`.
### Instance Methods
### `.scrollDelta() {THREE.Vector2?}`
If this was a scroll event, get the scroll deltas (both `x` and `y`). If this was not a scroll event, `scrollDelta()` returns `null`.
## Game3.Game
The `Game` class houses the highest layer logic for your app. The contructor for this class is the entry point of your program. In other words, all initialization and setup should be invoked with the `init()` method.
To create your own app, you will want to extend the `Game` class. A lot of work is done for you in the `before_init()` and `after_init()` handlers. However, you can always override these methods for customization (if or when you need it).
### Constructor
### `Game(el)`
__`el`__: This is the `HTMLElement` container you provide the app to live in.
You should call all setup and initialization logic in the `init()` method of your custom class that extends `Game3`.
var App = Game3.Game.extend({
init: function(el) {
// setup logic
}
});
### Members
### `.camera {THREE.PerspectiveCamera}`
An instance of the THREE.js `Camera` class. By default, the camera looks at the origin of the scene. You can move, rotate, and modify other properties of the camera as needed.
### `.canvas {HTMLCanvasElement}`
A reference to the actual `` element in the DOM. You may find this useful, especially if this app is part of a larger web page.
### `.el {HTMLElement}`
The container element for your `Game3` app. You must pass this container in when calling the `Game` constructor. The `Game` class automatically fits and binds a canvas to this element.
### `.height {number}`
The height of the canvas.
### `.renderer {THREE.Renderer}`
A reference to the THREE.js renderer instance that is powering all the 3D drawing. Unless you are on mobile or have an older browser, this should be an instance of `THREE.WebGLRenderer`. Otherwise we will use a (slower) `THREE.CanvasRenderer` which does not leverage WebGL.
### `.scene {THREE.Scene}`
The scene object tracks all the objects in the app's world. In general, you should be using the provided helpers for adding objects to your scene, as opposed to modifying the scene directly. I'm sure we left some stuff out, so you will have to make any custom tweaks manually for now.
### `.width {number}`
The width of the canvas.
### Instance Methods
### `.add(object) {boolean}`
__`object {Object}`:__ The object to add to your app.
__`@return {boolean}`:__ Whether or not the object was added to the scene.
init: function(el) {
// make a cube and a light
this.light = new Game3.Light(0xFFFFFF);
this.cube = new Cube(this);
// show objects
this.add(this.cube);
this.add(this.light);
}
To mimic polymorphism, `.add()` does the correct thing based on what you give it. Below is a brief description of the behavior based on the input.
- `Game3.Light`: Adds a light to the scene.
- `Game3.Model`: Adds the `.mesh()` to your scene and the `.hitbox()` to the events tracker, if your model is interactive.
- `THREE.Light`: Adds a light to the scene.
- `THREE.Object3D`: Adds a generic object to the scene. It receives no events.
### `.update(dt)`
__`dt {number}`:__ The time in milliseconds since the last `.timerfired()` was called. Use this delta for more robust animations and counters.
Call any logic that would change your game state every timestep. For example, animations may require you to update an object's position. This function is called _roughly_ 60 times a second (to achieve 60 FPS). However, if you are doing heavy computation in each timestep, this rate can drop.
__Note:__ Later on we may decided to pass `timerfired()` the time difference `dt` since the last time it was called. This will be a demand driven feature.
__Note:__ `Game3` correctly uses the `requestAnimationFrame()` shim.
## Game3.Model
The `Model` class represents objects in the scene, tracks their state, and handles events for them. If you are familiar with an MVC architecture, this class handles both the model and view logic.
__Note:__ Later on we may try and split the model and view logic. For now we try to stay light weight.
### Constructor
### `Model(game)`
__`game {Game3.Game}`__: A reference to your app. Many times the view logic needs to execute high level operations on the application. For this reason we think it's justified to have a public reference to the game.
The model constructor does nothing by default. You must pass a reference to the game to the constructor. The reference is saved in the `before_init()` method.
var Ball = Game3.Model.extend({
init: function(game, radius) {
// set up geometry
var grey = new THREE.MeshLambertMaterial({color: 0xCCCCCC});
this.ball = new THREE.Mesh(new THREE.SphereGeometry(radius), grey);
// set object
this.setMesh(this.ball);
}
});
### Members
### `.game {Game3.Game}`
A reference to your app.
### `.interactive {Boolean}`
Whether or not to send this model events. This is `false` by default. Making too many objects in the scene interactive can slow down your application.
__Note:__ You must set this flag before using `.add()` to register it in the system.
### Instance Methods
### `.handler(event) {Boolean?}`
__`event {Game3.Event}`__: A event object passed to your handler. It contains useful metadata. For more information, see the `Game3.Event` section.
__`@return {Boolean?}`__: Whether or not this handler __handles__ the event. By convention, a value of `undefined` is considered to be `true`.
Using event handlers for a `Model` is simple. Just define a handler function with the appropriate name:
click: function(event) {
// your event logic here
console.log(event);
}
`Game3` will automatically call the handler when your model receives the event. Remember, to recieve events, you must make your model `interactive`.
__Event bubbling:__ If `(handler() === false)`, we say that this handler does not _handle_ the event. Therefore, the event should __bubble__ to the `Game` class. If no handler _handles_ the event, the default action will be taken. That is, the events framework will __not__ call `preventDefault()` on the native event.
The following event handlers are currently supported:
- `click`
- `rightclick`
- `mouseover`
- `mouseout`
- `mousedrag`
- `mousedrop`
- `mousedown`
- `mouseup`
- `mousemove`
- `scroll`
### `.hitbox(hitbox)`
__`hitbox {THREE.Mesh?}`__: This argument is optional. If `hitbox` is provided, the hitbox for this model will be replaced. Otherwise, the `.hitbox()` returns the current hitbox.
Many times the visible geometry (rendered in the scene) is not the _interactive_ geometry you want to use. That is, the event handling framework will use the hitbox geometry if you provide one. If no `hitbox` is set, we will use the `mesh`.
### `.mesh(mesh)`
__`mesh {THREE.Mesh?}`__: This argument is optional. If `mesh` is provided, the mesh for this model will be replaced. Otherwise, the `.mesh()` returns the current mesh.
__Note:__ By convention, you would call `mesh()` at the end of your `init()` method.