Created
June 11, 2011 09:58
-
-
Save jsermeno/1020426 to your computer and use it in GitHub Desktop.
Three.js Game - Animated Sprites + Backbone.js - http://catchvar.com/threejs-game-animated-sprites-backbonejs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Bind context | |
_.bindAll( this, "animate", "render", "update" ); | |
// Initialize camera | |
this.camera = new THREE.Camera( 45, window.innerWidth / window.innerHeight, -2000, 10000 ); | |
this.camera.projectionMatrix = THREE.Matrix4.makeOrtho( window.innerWidth / - 2, window.innerWidth / 2, window.innerHeight / 2, window.innerHeight / - 2, -2000, 10000 ); | |
this.camera.position.y = 70.711; | |
this.camera.position.x = 100; | |
this.camera.position.z = 100; | |
// Create scene | |
this.scene = new THREE.Scene(); | |
// Create projector | |
this.projector = new THREE.Projector(); | |
// Create renderer | |
renderer = new THREE.WebGLRenderer( { antialias: true } ); | |
renderer.setSize( window.innerWidth, window.innerHeight ); | |
// Load scene | |
appView = new Game.Views.App({ el: renderer.domElement }); | |
document.body.appendChild(renderer.domElement); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Game.Controllers.App = (function() { | |
var | |
renderer, | |
appView, | |
// Game loop | |
loops = 0, | |
nextGameTick = (new Date).getTime(), | |
// Constants | |
FPS = 60, | |
MAX_FRAME_SKIP = 10, | |
SKIP_TICKS = 1000 / FPS; | |
return { | |
// App variables | |
camera: null, | |
scene: null, | |
projector: null, | |
/* | |
Initialize scene | |
*/ | |
initialize: function() { | |
}, | |
/* | |
function animate | |
Game loop - requests each new frame | |
*/ | |
animate: function() { | |
}, | |
/* | |
function update | |
Handles game state updates | |
*/ | |
update: function() { | |
}, | |
/* | |
function render | |
*/ | |
render: function() { | |
} | |
}; | |
})(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
function animate | |
Game loop - requests each new frame | |
*/ | |
animate: function() { | |
requestAnimationFrame( this.animate ); | |
this.render(); | |
}, | |
/* | |
function update | |
Handles game state updates | |
*/ | |
update: function() { | |
appView.update(); | |
}, | |
/* | |
function render | |
Keeps updates at around 50 per second while trying to render the scene as fast as possible | |
*/ | |
render: function() { | |
loops = 0; | |
// Attempt to update as many times as possible to get to our nextGameTick 'timeslot' | |
// However, we only can update up to 10 times per frame | |
while ( (new Date).getTime() > nextGameTick && loops < MAX_FRAME_SKIP ) { | |
this.update(); | |
nextGameTick += SKIP_TICKS; | |
loops++; | |
} | |
// Render our scene | |
renderer.render( this.scene, this.camera ); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Game.Views.App = Backbone.View.extend({ | |
events: { | |
"click": "clickWorld" | |
}, | |
/* | |
function initialize | |
*/ | |
initialize: function() { | |
}, | |
/* | |
function update | |
*/ | |
update: function() { | |
}, | |
/* | |
function renderLand | |
Renders the landscape of the world and attaches to scene | |
*/ | |
initLand: function() { | |
}, | |
/* | |
function clickWorld | |
Handles clicks for the entire world, since we don't really have sub-elements of the canvas | |
*/ | |
clickWorld: function(e) { | |
} | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Game.Views.App = Backbone.View.extend({ | |
events: { | |
"click": "clickWorld" | |
}, | |
/* | |
function initialize | |
*/ | |
initialize: function() { | |
_.bindAll( this, "update" ); | |
this.initLand(); | |
this.characterView = new Game.Views.Character(); | |
}, | |
/* | |
function update | |
*/ | |
update: function() { | |
this.characterView.update(); | |
}, | |
/* | |
function renderLand | |
Renders the landscape of the world and attaches to scene | |
*/ | |
initLand: function() { | |
var | |
grass, | |
plane, | |
uvs, i, j, | |
mesh; | |
// Load texture | |
grass = THREE.ImageUtils.loadTexture( "textures/grass.gif" ); | |
grass.wrapT = grass.wrapS = THREE.RepeatWrapping; | |
// Create plane | |
plane = new THREE.Plane(8, 8, 8, 8); | |
plane.doubleSided = true; | |
// Create plane texture mapping | |
for ( i = 0; i < plane.faceVertexUvs[ 0 ].length; i ++ ) { | |
uvs = plane.faceVertexUvs[ 0 ][ i ]; | |
for ( j = 0; j < uvs.length; j ++ ) { | |
uvs[ j ].u *= 8; | |
uvs[ j ].v *= 8; | |
} | |
} | |
// Create mesh for plane | |
mesh = new THREE.Mesh( plane, new THREE.MeshBasicMaterial( { map: grass, wireframe: false} )); | |
mesh.rotation.x = -90 * Math.PI / 180; | |
mesh.scale.x = mesh.scale.y = mesh.scale.z = 100; | |
// Add object to scene | |
Game.Controllers.App.scene.addObject( mesh ); | |
}, | |
/* | |
function clickWorld | |
Handles clicks for the entire world, since we don't really have sub-elements of the canvas | |
*/ | |
clickWorld: function(e) { | |
// Move character | |
this.characterView.moveCharacter(e); | |
} | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
window.Game = { | |
Models: {}, | |
Controllers: {}, | |
Views: {} | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Game.Views.Character = Backbone.View.extend({ | |
// View variables | |
startVector: new THREE.Vector3(), | |
endVector: new THREE.Vector3(), | |
dirVector: new THREE.Vector3(), | |
goalVector: new THREE.Vector3(), | |
isWalking: false, | |
SPEED: 10, | |
IMAGE_OFFSET: .04167, | |
/* | |
Initialize the character | |
*/ | |
initialize: function() { | |
}, | |
/* | |
Update character | |
*/ | |
update: function() { | |
}, | |
/* | |
Create character sprite, collision detection, and add to scene | |
*/ | |
initCharacter: function() { | |
}, | |
/* | |
function setPosition | |
utility function to set position of both boundingMesh and sprite at the same time | |
*/ | |
setPosition: function(x, y, z) { | |
}, | |
/* | |
function moveCharacter | |
translates x, y coordinates to world space and updates character | |
*/ | |
moveCharacter: function(e) { | |
} | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Game.Views.Character = Backbone.View.extend({ | |
// View variables | |
startVector: new THREE.Vector3(), | |
endVector: new THREE.Vector3(), | |
dirVector: new THREE.Vector3(), | |
goalVector: new THREE.Vector3(), | |
isWalking: false, | |
SPEED: 10, | |
IMAGE_OFFSET: .04167, | |
/* | |
Initialize the character | |
*/ | |
initialize: function() { | |
_.bindAll( this, "moveCharacter", "update" ); | |
this.initCharacter(); | |
}, | |
/* | |
Update character | |
*/ | |
update: function() { | |
var | |
dir, | |
camera = Game.Controllers.App.camera; | |
if ( this.isWalking ) { | |
dir = new THREE.Vector3(); | |
dir.sub( this.goalVector, this.sprite.position); | |
if (Math.abs( dir.x ) < 1 && Math.abs( dir.z ) < 1) { | |
this.isWalking = false; | |
} | |
dir.normalize(); | |
// Position movement | |
this.sprite.position.x += this.SPEED * dir.x; | |
this.sprite.position.z += this.SPEED * dir.z; | |
// Texture animation | |
this.sprite.uvOffset.x += this.IMAGE_OFFSET; | |
if (this.sprite.uvOffset.x > 1.0) { | |
this.sprite.uvOffset.x = 0.0; | |
} | |
// Change camera position to match character | |
camera.position.x += this.SPEED * dir.x; | |
camera.position.z += this.SPEED * dir.z; | |
camera.target.position.x += this.SPEED * dir.x; | |
camera.target.position.z += this.SPEED * dir.z; | |
} | |
}, | |
/* | |
Create character sprite, collision detection, and add to scene | |
*/ | |
initCharacter: function() { | |
var | |
texture; | |
// Load sprite map | |
texture = THREE.ImageUtils.loadTexture( "assets/ball_sprite_red_upper_right.png" ); | |
// Create sprite | |
this.sprite = new THREE.Sprite( { map: texture, useScreenCoordinates: false, affectedByDistance: true} ); | |
// Set scale to 1/24 of image (200px) | |
this.sprite.scale.y = .041667 / client.innerHeight; | |
this.sprite.scale.x = -0.041167 / client.innerHeight; | |
// Set offset to first sprite of 24 images | |
this.sprite.uvOffset.x = .95834; | |
this.sprite.uvScale.x = 0.041167; | |
// Add collision detection | |
this.sprite.boundingMesh = new THREE.Mesh( new THREE.Cube(60, 60, 60, 1, 1, 1) ); | |
THREE.Collisions.colliders.push( THREE.CollisionUtils.MeshOBB(this.sprite.boundingMesh) ); | |
// Center sprite at 0, 0, 0 of world | |
this.setPosition(0, 40, 0); | |
Game.Controllers.App.scene.addObject( this.sprite ); | |
Game.Controllers.App.scene.addObject( this.sprite.boundingMesh ); | |
}, | |
/* | |
function setPosition | |
utility function to set position of both boundingMesh and sprite at the same time | |
*/ | |
setPosition: function(x, y, z) { | |
this.sprite.position.set(x, y, z); | |
this.sprite.boundingMesh.position.set(x, y, z); | |
}, | |
/* | |
function moveCharacter | |
translates x, y coordinates to world space and updates character | |
*/ | |
moveCharacter: function(e) { | |
var | |
camera = Game.Controllers.App.camera, | |
projector = Game.Controllers.App.projector, | |
x, | |
y, | |
t; | |
// Convert screen coordinates to NDC coordinates -1.0 to 1.0 | |
x = ( e.clientX / window.innerWidth ) * 2 - 1; | |
y = - ( e.clientY / window.innerHeight ) * 2 + 1; | |
// Obtain one vector at click position for each side of the cube mapping | |
this.startVector.set( x, y, -1.0 ); | |
this.endVector.set( x, y, 1.0 ); | |
console.log("x :" + x + ", y: " + y); | |
// Convert coordinates back to world coordinates | |
this.startVector = projector.unprojectVector( this.startVector, camera ); | |
this.endVector = projector.unprojectVector( this.endVector, camera ); | |
// Get direction from startVector to endVector | |
this.dirVector.sub( this.endVector, this.startVector ); | |
this.dirVector.normalize(); | |
// Find intersection where y = 0 | |
t = this.startVector.y / - ( this.dirVector.y ); | |
// Start walking | |
this.goalVector.set( this.startVector.x + t * this.dirVector.x, | |
this.startVector.y + t * this.dirVector.y, | |
this.startVector.z + t * this.dirVector.z ); | |
this.isWalking = true; | |
} | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<title>Three.js - Game</title> | |
<meta charset="utf-8"> | |
<style> | |
body { | |
/*background-color: #31C23B;*/ | |
margin: 0; | |
padding: 0; | |
overflow: hidden; | |
} | |
</style> | |
<!-- libs --> | |
<script type="text/javascript" src="js/lib/Three.js"></script> | |
<script type="text/javascript" src="js/lib/RequestAnimationFrame.js"></script> | |
<script type="text/javascript" src="js/lib/jquery-1.6.1.min.js"></script> | |
<script type="text/javascript" src="js/lib/underscore-min.js"></script> | |
<script type="text/javascript" src="js/lib/backbone.js"></script> | |
<!-- app --> | |
<script type="text/javascript" src="js/app.js"></script> | |
<script type="text/javascript" src="js/views/characterView.js"></script> | |
<script type="text/javascript" src="js/views/appView.js"></script> | |
<script type="text/javascript" src="js/controllers/appController.js"></script> | |
</head> | |
<body> | |
<script type="text/javascript"> | |
Game.Controllers.App.initialize(); | |
Game.Controllers.App.animate(); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment