...menustart
...menuend
<body>
<canvas> id="my_canvas"</canvas>
</body>
<script>
var canvas = null ;
var context = null ;
setup = function() {
canvas = document.getElementById( "my_canvas" ) ;
context = canvas.getContext( '2d') ;
canvas.width = 1200 ; // windows.innerWidth ;
canvas.height = 720 ; // windows.innerHeight ;
} ;
setup();
</script>
- Declare a new Image() object
- Declare it's 'onload' method
- set Image.src = "url"
- as soon as the Image.src is set through a value , JS will kick off
onload
function. - because of this, we need to specify the callback function first before setting the source attribute
- as soon as the Image.src is set through a value , JS will kick off
setup = function() {
canvas = document.getElementById( "my_canvas" ) ;
context = canvas.getContext( '2d') ;
canvas.width = 1200 ; // windows.innerWidth ;
canvas.height = 720 ; // windows.innerHeight ;
img new Image();
img.onload = onImageLoad;
img.src = 'ralphyrobot.png'
} ;
onImageLoad = function() {
console.log( "Image" ) ;
}
var object = object.drawImage( ... )
- you can find API details in
webplatform.org
onImageLoad = function() {
console.log( "Image" ) ;
context.drawImage( img, 192, 192 ) ;
}
- load all animation image assets and place then in the frame array
- after you images are loaded , you should go through and fill out the rest of the animation function
- before this you need to have some logic that checks for whether or not the images are loaded
- and once all of the frames have been loaded , actually does a call to
setInterval
.
var frameRate = 1000/30 ;
var frame = 0 ;
var assets = [ 'xxx00.png' , 'xxx01.png' , ... ] ;
setup = function() {
...
for (var i =0; i < assets.length ; i++ ) {
frame.push( new Image() ) ;
frame[i].src = assets[i] ;
frame[i].src = assets[i] ;
}
setInterval ( animate , frameRate ) ;
} ;
var animate = function() {
context.clearRect( 0,0, canvas.width , canvas.height ) ;
context.drawImage( frames[frame] , 192,192 ) ;
frame = (frame +1) % frame.length
}
The canvas doesn't actually clear itself each frame. You need call clearRect to clear it.
- it's up to about 6 connection for a modern browse.
- when the upper limit is reached , the browse will actullay block subsequent requests until an open connection becomes available.
usign output from texture packer
defSprite: function ( name, x, y, w, h , cx ,cy ) {
var spt = {
"id" : name,
"x" : x,
"y" : y,
"w" : w,
"h" : h,
"cx" : cx==null ? 0 : cx ,
"cy" : cy==null ? 0 : cy ,
} ;
this.sprites.push(spt) ;
}
parseAtlasDefinition: function( atlasJson ) {
var parsed = JSON.parse( atlasJson ) ;
for( var key in parsed.frames ) {
var sprite = parsed.frames[key];
// define the center of the sprite as an offset
var cx = -sprite.frame.w * 0.5 ;
var cy = -sprite.frame.h * 0.5 ;
// define the sprite for this sheet
this.defSprite( key , sprite.frame.x , sprite.frame.y , sprite.frame.w, sprite.frame.h , cx, cy) ;
}
}
document.getElementById( 'canvas' ).addEventListener( 'mousemove' , onMouseMove ) ;
document.getElementById( 'canvas' ).addEventListener( 'keydown' , onKeyDown ) ;
function onMoseMove() {
var posx = event.clientX ;
var posy = event.clientY ;
}
function onKeyDown( event ) {
var keyId = event.keyID ; // ASCII value
}
- Input manager handle the event , and keep the input temporarily , for "update procedure" to comsume it later.
player: init()
{
var physDat = {
pos: {x,y} ,
maxx : 0 ,
size: {x:20, y:20} ,
velocity: {x:5 , y:5}
};
mpPhysBody = PhysicsEngine.newBody() ;
}
- Directly, the physics body itself exposes a function that allows us to set a linear velocity on it.
function update() {
var move_dir = new Vec2(0,0) ;
if(move_dir.LengthSquared()) {
move_dir.Normalize() ;
move_dir.Multiply( this.gPlayer0.walkSpeed ) ; // important
}
this.mpPhysBody.setLinearVelocity( move_dir.x , move_dir.y ) ;
}
gGameEngine.factory['WeaponInstance'] = WeaponInstanceClass ;
...
var ent = new( entityClass ) (x, y, es) ;
Tiled 工具 可以用来编辑相应的 entity object
可以把 运动物理前后两帧的 collision box 组成一个 大的 collision box , 做 碰撞检测 , 以防止 missing.
<script src="./box2d.min.js"> </script>
create: function() {
this.world = new World() {
new Vec2( 0 ,0 ) , // Gravity vector
false // Boolean for allowing sleep
} ;
}
upadte:
update: function() {
var start = Data.now();
// the more iterations, the more accurate the calculations
this.world.Step (
PHYSICS_LOOP_HZ , // frame-rate
10, // velocity iterations
10 // position iteration
) ;
// call the clearforces method of the world object to
// remove any forces at every physics update
this.world.ClearForces() ;
return (Date.now() - start);
}
registerBody: function( bodyDef ) {
var body = this.world.CreateBody( bodyDef ) ;
return body ;
}
addBody : function( entityDef ) {
var bodyDef = new BodyDef();
// type:
// Body.b2_staticBody
// Body.b2_dynamicBody
if (entityDef.type== "static") {
bodyDef.type = Body.b2_staticBody ;
} else {
bodyDef.type = Body.b2_dynamicBody ;
}
// Set the position{x,y} member object
// of your BodyDef object
bodyDef.position.x = entityDef.x ;
bodyDef.position.y = entityDef.y ;
var body = this.registBody(bodyDef) ;
var fixtureDefinition = new FixtureDef() ;
if (entityDef.useBouncyFixture ) {
fixtureDefinition.density = 1.0 ;
fixtureDefinition.friction = 0 ;
fixtureDefinition.restitution = 1.0 ;
}
// we now define the shape of this object as a box
fixtureDefinition.shape = new PolygonShape() ;
fixtureDefinition.shape.SetAsBox( entityDef.halfWidth, entityDef.halfHeight ) ;
body.CreateFixture( fixtureDefinition ) ;
return body ;
}
removeBody: function(obj) {
this.world.DestoryBody(obj) ;
}
一般的游戏, 只需要 Sound -> Gain -> OUTPUT 这条线
- Checking for Compatibility
try {
this._context = new webkitAudioContext();
}
catch( e ) {
alert( "web audio API not supported in this browse" ) ;
}
this._mainNode = this._context.createGainNode(0);
this._mainNode.connect( this._context.destination ) ;
- Asynchronous Loading
Loaded --> yes -----------------------> callback
|-> no --> Xml Http Request --> callback
loadAsync: function( path , callbackFcn ) {
if(this.clips[path]) {
callbackFcn( this.clips[path].s ) ;
return this.clip[path].s ;
}
var clip = { s: new Sound() , b: null , l: false } ;
this.clips[path] = clip ;
clip.s.path = path ;
var request = new XMLHttpRequest();
request.open( "GET" , path, true ) ;
request.responseType = "arraybuffer" ;
request.onload = function() {
gSM._context.decodeAudioData( request.response ,
function(buffer) {
clip.b = buffer ;
clip.l = true ;
callbackFcn( clip.s ) ;
}
function(data) {
Logger.log( "fail" )
} ) ;
}
request.send();
return clip.s ;
}
- Play Sound
playSound: function(path , settings) {
...
var sd = this.clips[path] ;
// creates a sound source
var currentClip = gSM._context.createBufferSource() ;
// tell the source which sound to play
currentClip.buffer = sd.b ;
currentClip.gain.value = volumen ;
currentClip.connect( gSM._mainNode ) ;
currentClip.loop = looping ;
// play the source now
currentClip.noteOn(0) ;
return true ;
}
- Stopping Sounds
- eg: stop all sound , while level changing
- The way we do that , is by simply disconnection our main node from the node graph ; creating a new one in its place, and connecting it to our output.
stopAll: function() {
this._mainNode.disconnect();
this._mainNode = this._context.createGainNode(0) ;
this._mainNode.connect( this._context.destination ) ;
}
- Muting Sounds
togglemute: function() {
if( this._mainNode.gain.value > 0 )
this._mainNode.gain.value = 0 ;
else
this._mainNode.gain.value = 1 ;
}
- Play World Sound ( 远近效果 )
playWorldSound: function( soundURL , x , y ) {
if(this.gPlayer0 === null ) return ;
var gMap = gGameEngine.gMap ;
// fade out volume based upon distance to me
var viewSize = Math.max(gMap.viewRect.w . gMap.viewRect.h) * 0.5 ;
var oCenter = this.gPlayer0.pos ;
var dx = Math.abs(oCenter.x -x ) ;
var dy = Math.abs(oCenter.y -y ) ;
var distToObserver = Math.sqrt( dx * dx , dy * dy ) ;
var normDist = distToObserver / viewSize ;
if(normDist > 1 ) normDist = 1 ;
if(normDist < 0 ) return ; // don't play
var volumn = 1.0 - normDist ;
var sound = gSM.loadAsync(soundURL , function( sObj) {
gSM.playSound(sObj.path , {
looping: false ,
volume: volume
} );
};
}
- all file I/O function in JavaScript are by definition asynchronous.
- Cached Asset management
- Async callbacks on load
- batches asset loading
- to allow us to pass a list of files to load , and receive one callback once they've all been loaded
function loadAssets(assetList, callbackFcn) {
// All the information we need to keep track of
// for this batch
var loadBatch = {
count: 0 ,
total: assetList.count ,
cb: callbackFcn
};
for (var i=0 ; i< assetList.length ; i ++ ) {
if(gCachedAssets[assetname] == null) {
var img = new Image() ;
img.onload = function() {
onLoadedCallback(img, loadBatch) ;
} ;
img.src = assetName ;
gCachedAssets[assetName] = img ;
} else {
onLoadedCallback( gCachedAssets[assetList[i]] , loadBatch )
}
}
}
function onLoadedCallback( asset , batch ) {
batch.count ++ ;
if(batch.count == batch.total) {
batch.cb(asset) ;
}
}