经典的HTML5游戏及其源码分析
HTML5已经相当强大,在HTML5平台上,我们可以完成很多非常复杂的动画效果,包括游戏在内。早期我们只能利用flash来实现网络游戏,现在我们又多了一种选择,即用HTML5制作游戏。相比flash,HTML5更加灵活方便,随着浏览器技术的不断升级,HTML5一定会广泛使用,至少在网页动画方面,下面是一些利用HTML5完成的游戏作品。
HTML5版切水果游戏
这曾是风靡全球的一款手机APP游戏切水果,现在JS小组已经将其改版成HTML5,并将其开源。
核心Javascript代码:
Ucren.BasicDrag = Ucren.Class( /* constructor */ function( conf ){ conf = Ucren.fixConfig( conf ); this.type = Ucren.fixString( conf.type, "normal" ); var isTouch = this.isTouch = "ontouchstart" in window; this.TOUCH_START = isTouch ? "touchstart" : "mousedown", this.TOUCH_MOVE = isTouch ? "touchmove" : "mousemove", this.TOUCH_END = isTouch ? "touchend" : "mouseup"; }, /* methods */ { bind: function( el, handle ){ el = Ucren.Element( el ); handle = Ucren.Element( handle ) || el; var evt = {}; evt[this.TOUCH_START] = function( e ){ e = Ucren.Event( e ); this.startDrag(); e.cancelBubble = true; e.stopPropagation && e.stopPropagation(); return e.returnValue = false; }.bind( this ); handle.addEvents( evt ); this.target = el; }, //private getCoors: function( e ){ var coors = []; if ( e.targetTouches && e.targetTouches.length ) { // iPhone var thisTouch = e.targetTouches[0]; coors[0] = thisTouch.clientX; coors[1] = thisTouch.clientY; }else{ // all others coors[0] = e.clientX; coors[1] = e.clientY; } return coors; }, //private startDrag: function(){ var target, draging, e; target = this.target; draging = target.draging = {}; this.isDraging = true; draging.x = parseInt( target.style( "left" ), 10 ) || 0; draging.y = parseInt( target.style( "top" ), 10 ) || 0; e = Ucren.Event(); var coors = this.getCoors( e ); draging.mouseX = coors[0]; draging.mouseY = coors[1]; this.registerDocumentEvent(); }, //private endDrag: function(){ this.isDraging = false; this.unRegisterDocumentEvent(); }, //private registerDocumentEvent: function(){ var target, draging; target = this.target; draging = target.draging; draging.documentSelectStart = Ucren.addEvent( document, "selectstart", function( e ){ e = e || event; e.stopPropagation && e.stopPropagation(); e.cancelBubble = true; return e.returnValue = false; }); draging.documentMouseMove = Ucren.addEvent( document, this.TOUCH_MOVE, function( e ){ var ie, nie; e = e || event; ie = Ucren.isIe && e.button != 1; nie = !Ucren.isIe && e.button != 0; if( (ie || nie ) && !this.isTouch ) this.endDrag(); var coors = this.getCoors( e ); draging.newMouseX = coors[0]; draging.newMouseY = coors[1]; e.stopPropagation && e.stopPropagation(); return e.returnValue = false; }.bind( this )); draging.documentMouseUp = Ucren.addEvent( document, this.TOUCH_END, function(){ this.endDrag(); }.bind( this )); var lx, ly; clearInterval( draging.timer ); draging.timer = setInterval( function(){ var x, y, dx, dy; if( draging.newMouseX != lx && draging.newMouseY != ly ){ lx = draging.newMouseX; ly = draging.newMouseY; dx = draging.newMouseX - draging.mouseX; dy = draging.newMouseY - draging.mouseY; x = draging.x + dx; y = draging.y + dy; if( this.type == "calc" ){ this.returnValue( dx, dy, draging.newMouseX, draging.newMouseY ); }else{ target.left( x ).top( y ); } } }.bind( this ), 10 ); }, //private unRegisterDocumentEvent: function(){ var draging = this.target.draging; Ucren.delEvent( document, this.TOUCH_MOVE, draging.documentMouseMove ); Ucren.delEvent( document, this.TOUCH_END, draging.documentMouseUp ); Ucren.delEvent( document, "selectstart", draging.documentSelectStart ); clearInterval( draging.timer ); }, //private returnValue: function( dx, dy, x, y ){ //todo something } } ); // Ucren.Template Ucren.Template = Ucren.Class( /* constructor */ function(){ this.string = join.call( arguments, "" ); }, /* methods */ { apply: function( conf ){ return this.string.format( conf ); } } ); // Ucren.BasicElement Ucren.BasicElement = Ucren.Class( /* constructor */ function( el ){ this.dom = el; this.countMapping = {}; }, /* methods */ { isUcrenElement: true, attr: function( name, value ){ if( typeof value == "string" ){ this.dom.setAttribute( name, value ); }else{ return this.dom.getAttribute( name ); } return this; }, style: function( /* unknown1, unknown2 */ ){ var getStyle = Ucren.isIe ? function( name ){ return this.dom.currentStyle[name]; } : function( name ){ var style; style = document.defaultView.getComputedStyle( this.dom, null ); return style.getPropertyValue( name ); }; return function( unknown1, unknown2 ){ if( typeof unknown1 == "object" ){ Ucren.each( unknown1, function( value, key ){ this[key] = value; }.bind( this.dom.style )); }else if( typeof unknown1 == "string" && typeof unknown2 == "undefined" ){ return getStyle.call( this, unknown1 ); }else if( typeof unknown1 == "string" && typeof unknown2 != "undefined" ){ this.dom.style[unknown1] = unknown2; } return this; }; }(), hasClass: function( name ){ var className = " " + this.dom.className + " "; return className.indexOf( " " + name + " " ) > -1; }, setClass: function( name ){ if( typeof( name ) == "string" ) this.dom.className = name.trim(); return this; }, addClass: function( name ){ var el, className; el = this.dom; className = " " + el.className + " "; if( className.indexOf( " " + name + " " ) == -1 ){ className += name; className = className.trim(); className = className.replace( / +/g, " " ); el.className = className; } return this; }, delClass: function( name ){ var el, className; el = this.dom; className = " " + el.className + " "; if( className.indexOf( " " + name + " " ) > -1 ){ className = className.replace( " " + name + " ", " " ); className = className.trim(); className = className.replace( / +/g, " " ); el.className = className; } return this; }, html: function( html ){ var el = this.dom; if( typeof html == "string" ){ el.innerHTML = html; }else if( html instanceof Array ){ el.innerHTML = html.join( "" ); }else{ return el.innerHTML; } return this; }, left: function( number ){ var el = this.dom; if( typeof( number ) == "number" ){ el.style.left = number + "px"; this.fireEvent( "infect", [{ left: number }] ); }else{ return this.getPos().x; } return this; }, top: function( number ){ var el = this.dom; if( typeof( number ) == "number" ){ el.style.top = number + "px"; this.fireEvent( "infect", [{ top: number }] ); }else{ return this.getPos().y; } return this; }, width: function( unknown ){ var el = this.dom; if( typeof unknown == "number" ){ el.style.width = unknown + "px"; this.fireEvent( "infect", [{ width: unknown }] ); }else if( typeof unknown == "string" ){ el.style.width = unknown; this.fireEvent( "infect", [{ width: unknown }] ); }else{ return this.getSize().width; } return this; }, height: function( unknown ){ var el = this.dom; if( typeof unknown == "number" ){ el.style.height = unknown + "px"; this.fireEvent( "infect", [{ height: unknown }] ); }else if( typeof unknown == "string" ){ el.style.height = unknown; this.fireEvent( "infect", [{ height: unknown }] ); }else{ return this.getSize().height; } return this; }, count: function( name ){ return this.countMapping[name] = ++ this.countMapping[name] || 1; }, display: function( bool ){ var dom = this.dom; if( typeof( bool ) == "boolean" ){ dom.style.display = bool ? "block" : "none"; this.fireEvent( "infect", [{ display: bool }] ); }else{ return this.style( "display" ) != "none"; } return this; }, first: function(){ var c = this.dom.firstChild; while( c && !c.tagName && c.nextSibling ){ c = c.nextSibling; } return c; }, add: function( dom ){ var el; el = Ucren.Element( dom ); this.dom.appendChild( el.dom ); return this; }, remove: function( dom ){ var el; if( dom ){ el = Ucren.Element( dom ); el.html( "" ); this.dom.removeChild( el.dom ); }else{ el = Ucren.Element( this.dom.parentNode ); el.remove( this ); } return this; }, insert: function( dom ){ var tdom; tdom = this.dom; if( tdom.firstChild ){ tdom.insertBefore( dom, tdom.firstChild ); }else{ this.add( dom ); } return this; }, addEvents: function( conf ){ var blank, el, rtn; blank = {}; rtn = {}; el = this.dom; Ucren.each( conf, function( item, key ){ rtn[key] = Ucren.addEvent( el, key, item ); }); return rtn; }, removeEvents: function( conf ){ var blank, el; blank = {}; el = this.dom; Ucren.each( conf, function( item, key ){ Ucren.delEvent( el, key, item ); }); return this; }, getPos: function(){ var el, parentNode, pos, box, offset; el = this.dom; pos = {}; if( el.getBoundingClientRect ){ box = el.getBoundingClientRect(); offset = Ucren.isIe ? 2 : 0; var doc = document; var scrollTop = Math.max( doc.documentElement.scrollTop, doc.body.scrollTop ); var scrollLeft = Math.max( doc.documentElement.scrollLeft, doc.body.scrollLeft ); return { x: box.left + scrollLeft - offset, y: box.top + scrollTop - offset }; }else{ pos = { x: el.offsetLeft, y: el.offsetTop }; parentNode = el.offsetParent; if( parentNode != el ){ while( parentNode ){ pos.x += parentNode.offsetLeft; pos.y += parentNode.offsetTop; parentNode = parentNode.offsetParent; } } if( Ucren.isSafari && this.style( "position" ) == "absolute" ){ // safari doubles in some cases pos.x -= document.body.offsetLeft; pos.y -= document.body.offsetTop; } } if( el.parentNode ){ parentNode = el.parentNode; }else{ parentNode = null; } while( parentNode && parentNode.tagName.toUpperCase() != "BODY" && parentNode.tagName.toUpperCase() != "HTML" ){ // account for any scrolled ancestors pos.x -= parentNode.scrollLeft; pos.y -= parentNode.scrollTop; if( parentNode.parentNode ){ parentNode = parentNode.parentNode; }else{ parentNode = null; } } return pos; }, getSize: function(){ var dom = this.dom; var display = this.style( "display" ); if ( display && display !== "none" ) { return { width: dom.offsetWidth, height: dom.offsetHeight }; } var style = dom.style; var originalStyles = { visibility: style.visibility, position: style.position, display: style.display }; var newStyles = { visibility: "hidden", display: "block" }; if ( originalStyles.position !== "fixed" ) newStyles.position = "absolute"; this.style( newStyles ); var dimensions = { width: dom.offsetWidth, height: dom.offsetHeight }; this.style( originalStyles ); return dimensions; }, observe: function( el, fn ){ el = Ucren.Element( el ); el.on( "infect", fn.bind( this )); return this; }, usePNGbackground: function( image ){ var dom; dom = this.dom; if( /\.png$/i.test( image ) && Ucren.isIe6 ){ dom.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader( src='" + image + "',sizingMethod='scale' );"; /// _background: none; /// _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader( src='images/pic.png',sizingMethod='scale' ); }else{ dom.style.backgroundImage = "url( " + image + " )"; } return this; }, setAlpha: function(){ var reOpacity = /alpha\s*\(\s*opacity\s*=\s*([^\)]+)\)/; return function( value ){ var element = this.dom, es = element.style; if( !Ucren.isIe ){ es.opacity = value / 100; /* }else if( es.filter === "string" ){ */ }else{ if ( element.currentStyle && !element.currentStyle.hasLayout ) es.zoom = 1; if ( reOpacity.test( es.filter )) { value = value >= 99.99 ? "" : ( "alpha( opacity=" + value + " )" ); es.filter = es.filter.replace( reOpacity, value ); } else { es.filter += " alpha( opacity=" + value + " )"; } } return this; }; }(), fadeIn: function( callback ){ if( typeof this.fadingNumber == "undefined" ) this.fadingNumber = 0; this.setAlpha( this.fadingNumber ); var fading = function(){ this.setAlpha( this.fadingNumber ); if( this.fadingNumber == 100 ){ clearInterval( this.fadingInterval ); callback && callback(); }else this.fadingNumber += 10; }.bind( this ); this.display( true ); clearInterval( this.fadingInterval ); this.fadingInterval = setInterval( fading, Ucren.isIe ? 20 : 30 ); return this; }, fadeOut: function( callback ){ if( typeof this.fadingNumber == "undefined" ) this.fadingNumber = 100; this.setAlpha( this.fadingNumber ); var fading = function(){ this.setAlpha( this.fadingNumber ); if( this.fadingNumber == 0 ){ clearInterval( this.fadingInterval ); this.display( false ); callback && callback(); }else this.fadingNumber -= 10; }.bind( this ); clearInterval( this.fadingInterval ); this.fadingInterval = setInterval( fading, Ucren.isIe ? 20 : 30 ); return this; }, useMouseAction: function( className, actions ){ /** * 调用示例: el.useMouseAction( "xbutton", "over,out,down,up" ); * 使用效果: el 会在 "xbutton xbutton-over","xbutton xbutton-out","xbutton xbutton-down","xbutton xbutton-up" * 等四个 className 中根据相应的鼠标事件来进行切换。 * 特别提示: useMouseAction 可使用不同参数多次调用。 */ if( !this.MouseAction ) this.MouseAction = new Ucren.MouseAction({ element: this }); this.MouseAction.use( className, actions ); return this; } } ); if( Ucren.isIe ) document.execCommand( "BackgroundImageCache", false, true ); for( var i in Ucren ){ exports[i] = Ucren[i]; }; return exports; });
HTML5中国象棋游戏
这款HTML5中国象棋游戏还可以自定义游戏难度,皮肤也不错。
核心Javascript代码:
/*! 一叶孤舟 | qq:28701884 | 欢迎指教 */ var play = play||{}; play.init = function (){ play.my = 1; //玩家方 play.map = com.arr2Clone (com.initMap); //初始化棋盘 play.nowManKey = false; //现在要操作的棋子 play.pace = []; //记录每一步 play.isPlay = true ; //是否能走棋 play.mans = com.mans; play.bylaw = com.bylaw; play.show = com.show; play.showPane = com.showPane; play.isOffensive = true; //是否先手 play.depth = play.depth || 3; //搜索深度 play.isFoul = false; //是否犯规长将 com.pane.isShow = false; //隐藏方块 //初始化棋子 for (var i=0; i<play.map.length; i++){ for (var n=0; n<play.map[i].length; n++){ var key = play.map[i][n]; if (key){ com.mans[key].x=n; com.mans[key].y=i; com.mans[key].isShow = true; } } } play.show(); //绑定点击事件 com.canvas.addEventListener("click",play.clickCanvas) //clearInterval(play.timer); //com.get("autoPlay").addEventListener("click", function(e) { //clearInterval(play.timer); //play.timer = setInterval("play.AIPlay()",1000); // play.AIPlay() //}) /* com.get("offensivePlay").addEventListener("click", function(e) { play.isOffensive=true; play.isPlay=true ; com.get("chessRight").style.display = "none"; play.init(); }) com.get("defensivePlay").addEventListener("click", function(e) { play.isOffensive=false; play.isPlay=true ; com.get("chessRight").style.display = "none"; play.init(); }) */ com.get("regretBn").addEventListener("click", function(e) { play.regret(); }) /* var initTime = new Date().getTime(); for (var i=0; i<=100000; i++){ var h="" var h=play.map.join(); //for (var n in play.mans){ // if (play.mans[n].show) h+=play.mans[n].key+play.mans[n].x+play.mans[n].y //} } var nowTime= new Date().getTime(); z([h,nowTime-initTime]) */ } //悔棋 play.regret = function (){ var map = com.arr2Clone(com.initMap); //初始化所有棋子 for (var i=0; i<map.length; i++){ for (var n=0; n<map[i].length; n++){ var key = map[i][n]; if (key){ com.mans[key].x=n; com.mans[key].y=i; com.mans[key].isShow = true; } } } var pace= play.pace; pace.pop(); pace.pop(); for (var i=0; i<pace.length; i++){ var p= pace[i].split("") var x = parseInt(p[0], 10); var y = parseInt(p[1], 10); var newX = parseInt(p[2], 10); var newY = parseInt(p[3], 10); var key=map[y][x]; //try{ var cMan=map[newY][newX]; if (cMan) com.mans[map[newY][newX]].isShow = false; com.mans[key].x = newX; com.mans[key].y = newY; map[newY][newX] = key; delete map[y][x]; if (i==pace.length-1){ com.showPane(newX ,newY,x,y) } //} catch (e){ // com.show() // z([key,p,pace,map]) // } } play.map = map; play.my=1; play.isPlay=true; com.show(); } //点击棋盘事件 play.clickCanvas = function (e){ if (!play.isPlay) return false; var key = play.getClickMan(e); var point = play.getClickPoint(e); var x = point.x; var y = point.y; if (key){ play.clickMan(key,x,y); }else { play.clickPoint(x,y); } play.isFoul = play.checkFoul();//检测是不是长将 } //点击棋子,两种情况,选中或者吃子 play.clickMan = function (key,x,y){ var man = com.mans[key]; //吃子 if (play.nowManKey&&play.nowManKey != key && man.my != com.mans[play.nowManKey ].my){ //man为被吃掉的棋子 if (play.indexOfPs(com.mans[play.nowManKey].ps,[x,y])){ man.isShow = false; var pace=com.mans[play.nowManKey].x+""+com.mans[play.nowManKey].y //z(bill.createMove(play.map,man.x,man.y,x,y)) delete play.map[com.mans[play.nowManKey].y][com.mans[play.nowManKey].x]; play.map[y][x] = play.nowManKey; com.showPane(com.mans[play.nowManKey].x ,com.mans[play.nowManKey].y,x,y) com.mans[play.nowManKey].x = x; com.mans[play.nowManKey].y = y; com.mans[play.nowManKey].alpha = 1 play.pace.push(pace+x+y); play.nowManKey = false; com.pane.isShow = false; com.dot.dots = []; com.show() com.get("clickAudio").play(); setTimeout("play.AIPlay()",500); if (key == "j0") play.showWin (-1); if (key == "J0") play.showWin (1); } // 选中棋子 }else{ if (man.my===1){ if (com.mans[play.nowManKey]) com.mans[play.nowManKey].alpha = 1 ; man.alpha = 0.6; com.pane.isShow = false; play.nowManKey = key; com.mans[key].ps = com.mans[key].bl(); //获得所有能着点 com.dot.dots = com.mans[key].ps com.show(); //com.get("selectAudio").start(0); com.get("selectAudio").play(); } } } //点击着点 play.clickPoint = function (x,y){ var key=play.nowManKey; var man=com.mans[key]; if (play.nowManKey){ if (play.indexOfPs(com.mans[key].ps,[x,y])){ var pace=man.x+""+man.y //z(bill.createMove(play.map,man.x,man.y,x,y)) delete play.map[man.y][man.x]; play.map[y][x] = key; com.showPane(man.x ,man.y,x,y) man.x = x; man.y = y; man.alpha = 1; play.pace.push(pace+x+y); play.nowManKey = false; com.dot.dots = []; com.show(); com.get("clickAudio").play(); setTimeout("play.AIPlay()",500); }else{ //alert("不能这么走哦!") } } } //Ai自动走棋 play.AIPlay = function (){ //return play.my = -1 ; var pace=AI.init(play.pace.join("")) if (!pace) { play.showWin (1); return ; } play.pace.push(pace.join("")); var key=play.map[pace[1]][pace[0]] play.nowManKey = key; var key=play.map[pace[3]][pace[2]]; if (key){ play.AIclickMan(key,pace[2],pace[3]); }else { play.AIclickPoint(pace[2],pace[3]); } com.get("clickAudio").play(); } //检查是否长将 play.checkFoul = function(){ var p=play.pace; var len=parseInt(p.length,10); if (len>11&&p[len-1] == p[len-5] &&p[len-5] == p[len-9]){ return p[len-4].split(""); } return false; } play.AIclickMan = function (key,x,y){ var man = com.mans[key]; //吃子 man.isShow = false; delete play.map[com.mans[play.nowManKey].y][com.mans[play.nowManKey].x]; play.map[y][x] = play.nowManKey; play.showPane(com.mans[play.nowManKey].x ,com.mans[play.nowManKey].y,x,y) com.mans[play.nowManKey].x = x; com.mans[play.nowManKey].y = y; play.nowManKey = false; com.show() if (key == "j0") play.showWin (-1); if (key == "J0") play.showWin (1); } play.AIclickPoint = function (x,y){ var key=play.nowManKey; var man=com.mans[key]; if (play.nowManKey){ delete play.map[com.mans[play.nowManKey].y][com.mans[play.nowManKey].x]; play.map[y][x] = key; com.showPane(man.x,man.y,x,y) man.x = x; man.y = y; play.nowManKey = false; } com.show(); } play.indexOfPs = function (ps,xy){ for (var i=0; i<ps.length; i++){ if (ps[i][0]==xy[0]&&ps[i][1]==xy[1]) return true; } return false; } //获得点击的着点 play.getClickPoint = function (e){ var domXY = com.getDomXY(com.canvas); var x=Math.round((e.pageX-domXY.x-com.pointStartX-20)/com.spaceX) var y=Math.round((e.pageY-domXY.y-com.pointStartY-20)/com.spaceY) return {"x":x,"y":y} } //获得棋子 play.getClickMan = function (e){ var clickXY=play.getClickPoint(e); var x=clickXY.x; var y=clickXY.y; if (x < 0 || x>8 || y < 0 || y > 9) return false; return (play.map[y][x] && play.map[y][x]!="0") ? play.map[y][x] : false; } play.showWin = function (my){ play.isPlay = false; if (my===1){ alert("恭喜你,你赢了!"); }else{ alert("很遗憾,你输了!"); } }
HTML5五子棋游戏
HTML5版Flappy Bird游戏
Flappy Bird这款变态游戏也被改造成HTML5版,这也是意料之中的事情。
核心Javascript代码:
// Initialize Phaser, and creates a 400x490px game var game = new Phaser.Game(400, 490, Phaser.AUTO, 'game_div'); var game_state = {}; // Creates a new 'main' state that will contain the game game_state.main = function() { }; game_state.main.prototype = { // Function called first to load all the assets preload: function() { // Change the background color of the game this.game.stage.backgroundColor = '#71c5cf'; // Load the bird sprite this.game.load.image('bird', 'assets/bird.png'); // Load the pipe sprite this.game.load.image('pipe', 'assets/pipe.png'); }, // Fuction called after 'preload' to setup the game create: function() { // Display the bird on the screen this.bird = this.game.add.sprite(100, 245, 'bird'); // Add gravity to the bird to make it fall this.bird.body.gravity.y = 1000; // Call the 'jump' function when the spacekey is hit var space_key = this.game.input.keyboard.addKey(Phaser.Keyboard.SPACEBAR); space_key.onDown.add(this.jump, this); // Create a group of 20 pipes this.pipes = game.add.group(); this.pipes.createMultiple(20, 'pipe'); // Timer that calls 'add_row_of_pipes' ever 1.5 seconds this.timer = this.game.time.events.loop(1500, this.add_row_of_pipes, this); // Add a score label on the top left of the screen this.score = 0; var style = { font: "30px Arial", fill: "#ffffff" }; this.label_score = this.game.add.text(20, 20, "0", style); }, // This function is called 60 times per second update: function() { // If the bird is out of the world (too high or too low), call the 'restart_game' function if (this.bird.inWorld == false) this.restart_game(); // If the bird overlap any pipes, call 'restart_game' this.game.physics.overlap(this.bird, this.pipes, this.restart_game, null, this); }, // Make the bird jump jump: function() { // Add a vertical velocity to the bird this.bird.body.velocity.y = -350; }, // Restart the game restart_game: function() { // Remove the timer this.game.time.events.remove(this.timer); // Start the 'main' state, which restarts the game this.game.state.start('main'); }, // Add a pipe on the screen add_one_pipe: function(x, y) { // Get the first dead pipe of our group var pipe = this.pipes.getFirstDead(); // Set the new position of the pipe pipe.reset(x, y); // Add velocity to the pipe to make it move left pipe.body.velocity.x = -200; // Kill the pipe when it's no longer visible pipe.outOfBoundsKill = true; }, // Add a row of 6 pipes with a hole somewhere in the middle add_row_of_pipes: function() { var hole = Math.floor(Math.random()*5)+1; for (var i = 0; i < 8; i++) if (i != hole && i != hole +1) this.add_one_pipe(400, i*60+10); this.score += 1; this.label_score.content = this.score; }, }; // Add and start the 'main' state to start the game game.state.add('main', game_state.main); game.state.start('main');
HTML5太空战机游戏
很普通的战机游戏,但是用HTML5实现就略显高大上了。
核心Javascript代码:
var g_canvas; var g_context; var g_soundsLoaded; var g_isChr; var g_onscreenControls; var g_paused; var g_renderInterval; var g_clockInterval; var g_totalItems; var g_itemsLoaded; var g_background; var g_foreground; var g_ship; var g_gameState; var g_highScore; var g_powerups; var g_floatyText; var g_projectiles; var g_enemyProjectiles; var g_enemies; var g_afterEffects; var g_rainbow; var g_basicShotSound; var g_laserShotSound; var g_dinkSound; var g_smallExplodeSound; var g_bonusSound; var g_explodeSound; var g_artifact_chard_sound; var g_double_sound; var g_gem_sound; var g_gun_sound; var g_shot_sound; var g_speed_sound; var g_levelDirector; var g_shotsFired; var g_shotsRequired; var g_accuracy; var g_showAccuracy; var g_enemiesDestroyed; // // main() is called once the game has loaded and the user has clicked // on the "new game" button on the splash screen. This is a clean slate // with no registered timers or event listeners. // function main() { var level_1_loop = document.getElementById("level_1_loop"); var bossLoop = document.getElementById("boss_loop"); //dbg("engine = " + navigator.userAgent, false); g_rainbow = new Array("yellow", "orange", "white", "red"); document.addEventListener('keydown', keyDown, false); document.addEventListener('keyup', keyUp, false); if ( g_basicShotSound == null ) { g_basicShotSound = new Sound("basic_shot",5); g_laserShotSound = new Sound("laser",5); g_smallExplodeSound = new Sound("small_explode",5); g_bonusSound = new Sound("bonus_sound",4); g_explodeSound = new Sound("explode", 3); g_artifact_chard_sound = new Sound("artifact_chard_sound", 2); g_double_sound = new Sound("double_sound", 2); g_gem_sound = new Sound("gem_sound", 4); g_gun_sound = new Sound("gun_sound", 2); g_shot_sound = new Sound("shot_sound", 3); g_speed_sound = new Sound("speed_sound", 3); } g_highScore = 0; g_gameState = "setup"; g_levelDirector = new LevelDirector(); // // telling the level director to start will put the clock and // render loops on interval timers // g_levelDirector.startLevel(); } // // map a sound name to a global audio object // function lookupSound(name) { if ( name == "double_sound" ) return g_double_sound; else if ( name == "gem_sound" ) return g_gem_sound; else if ( name == "gun_sound" ) return g_gun_sound; else if ( name == "shot_sound" ) return g_shot_sound; else if ( name == "speed_sound" ) return g_speed_sound; dbg("Failed sound lookup: " + name, false); return null; } // // the level director will kick off an interval that calls // this function every 100ms // function clockLoop() { if ( g_paused ) return; g_levelDirector.myClock += 100; //dbg("Clock = " + g_levelDirector.myClock, false); g_levelDirector.launchSorties(); g_levelDirector.gameEvents(); } // // the LevelDirector will kick off an interval that calls this function // which redraws the entire screen. that interval determines the game's // fps. // function renderLoop() { if ( g_paused ) return; g_background.render(); g_ship.render(); var remainingPowerups = new Array(); for (var i = 0; i < g_powerups.length; ++i) { if (g_powerups[i].render()) { remainingPowerups.push(g_powerups[i]); } else delete g_powerups[i]; } delete g_powerups; g_powerups = remainingPowerups; var remainingText = new Array(); for (var i = 0; i < g_floatyText.length; ++i) { if (g_floatyText[i].render()) { remainingText.push(g_floatyText[i]); } else delete g_floatyText[i]; } delete g_floatyText; g_floatyText = remainingText; var remainingEnemies = new Array(); for (var i = 0; i < g_enemies.length; ++i) { if (g_enemies[i].render()) { remainingEnemies.push(g_enemies[i]); } else delete g_enemies[i]; } delete g_enemies; g_enemies = remainingEnemies; var remainingProjectiles = new Array(); for (var i = 0; i < g_projectiles.length; ++i) { if (g_projectiles[i].render()) { remainingProjectiles.push(g_projectiles[i]); } else delete g_projectiles[i]; } delete g_projectiles; g_projectiles = remainingProjectiles; var remainingEnemyProjectiles = new Array(); for (var i = 0; i < g_enemyProjectiles.length; ++i) { if (g_enemyProjectiles[i].render()) { remainingEnemyProjectiles.push(g_enemyProjectiles[i]); } else delete g_enemyProjectiles[i]; } delete g_enemyProjectiles; g_enemyProjectiles = remainingEnemyProjectiles; var remainingAfterEffects = new Array(); for (var i = 0; i < g_afterEffects.length; ++i) { if (g_afterEffects[i].render()) { remainingAfterEffects.push(g_afterEffects[i]); } else delete g_afterEffects[i]; } delete g_afterEffects; g_afterEffects = remainingAfterEffects; g_levelDirector.renderSpecialText(); g_foreground.render(); if ( g_onscreenControls ) { var ox = 40; var oy = 300; var ow = 30; var tx = 8; var ty = 22; g_context.fillStyle = "yellow"; g_context.strokeStyle = "yellow"; g_context.strokeRect(ox,oy,ow,ow); g_context.strokeRect(ox-35,oy+35,ow,ow); g_context.strokeRect(ox+35,oy+35,ow,ow); g_context.strokeRect(ox,oy+70,ow,ow); g_context.strokeRect(ox+520,oy+35,ow,ow); g_context.strokeRect(ox+270,oy+35,ow,ow); g_context.fillText("U",ox+tx,oy+ty); g_context.fillText("L", ox-35+tx,oy+35+ty); g_context.fillText("R", ox+35+tx,oy+35+ty); g_context.fillText("D", ox+tx,oy+70+ty); g_context.fillText("Z",ox+520+tx,oy+35+ty); g_context.fillText("P",ox+270+tx,oy+35+ty); } g_ship.renderPowers(); } //--------------------------- BEGIN MUSIC LOOPING FUNCTIONS-------------// // // no browser currently correctly implements the looping feature // of the Autdio object yet, so we have to listen for the ended event // on our background music and play it again // function start_level_1_loop(terminate) { var level_1_loop = document.getElementById("level_1_loop"); if ( terminate != undefined ) { if ( terminate.toString() == "boss" ) { level_1_loop.volume = 0; level_1_loop.removeEventListener("ended", l1_loopit, true); return; } else if ( terminate.toString() == "gameover" ) { level_1_loop.removeEventListener("ended", l1_loopit, true); level_1_loop.pause(); return; } } l1_loopit(); } function l1_loopit() { var level_1_loop = document.getElementById("level_1_loop"); level_1_loop.volume = 1; level_1_loop.play(); level_1_loop.addEventListener("ended", l1_loopit, true); } function startBossLoop(terminate) { var bossLoop = document.getElementById("boss_loop"); if ( terminate != undefined && terminate.toString() == "end_boss") { bossLoop.volume = 0; bossLoop.removeEventListener("ended", bos_loopit, true); return; } bos_loopit(); } function bos_loopit() { var bossLoop = document.getElementById("boss_loop"); bossLoop.volume = 1; bossLoop.play(); bossLoop.addEventListener("ended", bos_loopit, true); } function startLevel2Loop(terminate) { var penguinLoop = document.getElementById("level_2_loop"); if ( terminate != undefined && terminate.toString() == "terminate") { penguinLoop.volume = 0; penguinLoop.removeEventListener("ended", l2_loopit, true); return; } l2_loopit(); } function l2_loopit() { var penguinLoop = document.getElementById("level_2_loop"); penguinLoop.volume = 1; penguinLoop.play(); penguinLoop.addEventListener("ended", l2_loopit, true); } // // write message to debug area // function dbg(str, append) { var dbgObj = document.getElementById("dbg"); dbgObj.innerHTML = append? (dbgObj.innerHTML + str): str; } // // appends all game sounds to the document. called after the loading // screen itself is loaded. The GameSounds.php file does a base64_encode // on the actual .ogg files residing on the server. This is so the sound // objects can be repeatedly re-initialized without a network hit. This // is part of a workaround for Chrome because that browser does not // correctly re-play short audio sounds (which is just about every sound // effect in the game) // function loadGameSounds() { var fileref=document.createElement('script') fileref.setAttribute("type","text/javascript") fileref.setAttribute("src", "http://dougx.net/plunder/GameSounds.php") var agent = navigator.userAgent; if ( agent.indexOf("MSIE") != -1 ) { // // IE9 does not support OGG so we have to load a special // version of the file that has MP3 encoded sound // fileref.setAttribute("src", "GameSoundsIE9.php") } fileref.onload = function() { g_soundsLoaded = true; } document.getElementsByTagName("head")[0].appendChild(fileref) } function pause() { if (g_paused == null ) g_paused = false; g_paused = !g_paused; if ( g_paused ) dbg("Game Paused", false); else dbg("", false); }
HTML5超级玛丽游戏重体验
重温少年时的快乐,这是用HTML5改版的超级玛丽游戏。
HTML5跳伞游戏
跳伞游戏,比谁先安全着陆,点击鼠标开始下落,再点击鼠标展开降落伞,你要控制好时机,让自己最先安全着陆。