基于HTML 5的橫版射擊游戲發(fā)布 附源碼
功能說(shuō)明:
基于HTML5的橫版射擊游戲,參考自flash游戲《雙面特工》。左右方向鍵控制移動(dòng),下方向鍵蹲下,上方向鍵跳躍,空格鍵射擊。體驗(yàn)前請(qǐng)先關(guān)閉輸入法。
該游戲基于自己開(kāi)發(fā)的HTML5游戲框架cnGameJS。
效果預(yù)覽:
實(shí)現(xiàn)分析:
1.關(guān)于多層地圖。
在上一個(gè)HTML5游戲《坦克后援隊(duì)》中,所用的地圖只為簡(jiǎn)單的單層地圖,意思是地圖中除了石頭就是空地,僅僅只有一層的地圖。但是這種單層地圖具有比較大的局限性,如果需要實(shí)現(xiàn)場(chǎng)景類(lèi)的游戲(例如超級(jí)瑪麗和上面的游戲),只有一層的地圖往往是不夠的,因?yàn)槲覀兂擞螒蛑鹘撬镜恼系K物外,還有游戲背景等元素(例如后面的墻壁等),因此我們需要為地圖對(duì)象分層,從而達(dá)到多層展示的目的。
新增的layer對(duì)象:
每個(gè)layer對(duì)象維護(hù)該層的sprite,負(fù)責(zé)更新和繪制它們,并且可以獲取指定坐標(biāo)在該層的矩陣上的值。layer對(duì)象源碼如下:
- /**
- *層對(duì)象
- **/
- var layer = function(id,mapMatrix, options) {
- if (!(this instanceof arguments.callee)) {
- return new arguments.callee(id,mapMatrix, options);
- }
- this.init(id,mapMatrix, options);
- }
- layer.prototype={
- /**
- *初始化
- **/
- init: function(id,mapMatrix,options) {
- /**
- *默認(rèn)對(duì)象
- **/
- var defaultObj = {
- cellSize: [32, 32], //方格寬,高
- x: 0, //layer起始x
- y: 0 //layer起始y
- };
- optionsoptions = options || {};
- options = cg.core.extend(defaultObj, options);
- this.id=options.id;
- this.mapMatrix = mapMatrix;
- this.cellSize = options.cellSize;
- this.x = options.x;
- this.y = options.y;
- this.row = mapMatrix.length; //有多少行
- thisthis.width=this.cellSize[0]* mapMatrix[0].length;
- thisthis.height=this.cellSize[1]* this.row;
- this.spriteList=new cg.SpriteList();//該層上的sprite列表
- this.imgsReference=options.imgsReference;//圖片引用字典:{"1":{src:"xxx.png",x:0,y:0},"2":{src:"xxx.png",x:1,y:1}}
- this.zIindex=options.zIndex;
- },
- /**
- *添加sprite
- **/
- addSprites:function(sprites){
- if (cg.core.isArray(sprites)) {
- for (var i = 0, len = sprites.length; i < len; i++) {
- arguments.callee.call(this, sprites[i]);
- }
- }
- else{
- this.spriteList.add(sprites);
- sprites.layer=this;
- }
- },
- /**
- *獲取特定對(duì)象在layer中處于的方格的值
- **/
- getPosValue: function(x, y) {
- if (cg.core.isObject(x)) {
- y = x.y;
- xx = x.x;
- }
- var isUndefined = cg.core.isUndefined;
- y = Math.floor(y / this.cellSize[1]);
- x = Math.floor(x / this.cellSize[0]);
- if (!isUndefined(this.mapMatrix[y]) && !isUndefined(this.mapMatrix[y][x])) {
- return this.mapMatrix[y][x];
- }
- return undefined;
- },
- /**
- *獲取特定對(duì)象在layer中處于的方格索引
- **/
- getCurrentIndex: function(x, y) {
- if (cg.core.isObject(x)) {
- y = x.y;
- xx = x.x;
- }
- return [Math.floor(x / this.cellSize[0]), Math.floor(y / this.cellSize[1])];
- },
- /**
- *獲取特定對(duì)象是否剛好與格子重合
- **/
- isMatchCell: function(x, y) {
- if (cg.core.isObject(x)) {
- y = x.y;
- xx = x.x;
- }
- return (x % this.cellSize[0] == 0) && (y % this.cellSize[1] == 0);
- },
- /**
- *設(shè)置layer對(duì)應(yīng)位置的值
- **/
- setPosValue: function(x, y, value) {
- this.mapMatrix[y][x] = value;
- },
- /**
- *更新層上的sprite列表
- **/
- update:function(duration){
- this.spriteList.update(duration);
- },
- /**
- *根據(jù)layer的矩陣?yán)L制layer和該layer上的所有sprite
- **/
- draw: function() {
- var mapMatrix = this.mapMatrix;
- var beginX = this.x;
- var beginY = this.y;
- var cellSize = this.cellSize;
- var currentRow;
- var currentCol
- var currentObj;
- var row = this.row;
- var img;
- var col;
- for (var i = beginY, ylen = beginY + row * cellSize[1]; i < ylen; i += cellSize[1]) { //根據(jù)地圖矩陣,繪制每個(gè)方格
- currentRow = (i - beginY) / cellSize[1];
- col=mapMatrix[currentRow].length;
- for (var j = beginX, xlen = beginX + col * cellSize[0]; j < xlen; j += cellSize[0]) {
- currentCol = (j - beginX) / cellSize[0];
- currentObj = this.imgsReference[mapMatrix[currentRow][currentCol]];
- if(currentObj){
- currentObjcurrentObj.x = currentObj.x || 0;
- currentObjcurrentObj.y = currentObj.y || 0;
- img = cg.loader.loadedImgs[currentObj.src];
- //繪制特定坐標(biāo)的圖像
- cg.context.drawImage(img, currentObj.x, currentObj.y, cellSize[0], cellSize[1], j, i, cellSize[0], cellSize[1]);
- }
- }
- }
- //更新該layer上所有sprite
- this.spriteList.draw();
- }
- }
之后我們可以很方便地創(chuàng)建不同的層,并添加到地圖中:
- /* 背景矩陣 */
- var bgMatrix = [
- [1,1,1],
- [1,1,1],
- [1,1,1]
- ];
- this.map = new cnGame.Map({width:3000,height:3000});
- var newnewLayer=new cnGame.Layer("bg",bgMatrix, { cellSize: [1000, 1000], width: this.map.width, height: this.map.height });
- newLayer.imgsReference={ "1": { src: srcObj.bg }};
- this.map.addLayer(newLayer);
2.關(guān)于移動(dòng)場(chǎng)景。
在上一次的HTML5《游戲超級(jí)瑪麗游戲demo》中,我們通過(guò)使游戲玩家的移動(dòng)轉(zhuǎn)換為游戲場(chǎng)景的移動(dòng)來(lái)實(shí)現(xiàn)玩家固定,場(chǎng)景移動(dòng)的效果,但是這種實(shí)現(xiàn)方法有比較大的問(wèn)題,因?yàn)樗缮媪说貓D和玩家的xy值的變化,因此會(huì)帶來(lái)很多不便。更好的實(shí)現(xiàn)方法是,保持玩家和地圖的xy值不變,只改變繪制它們時(shí)原點(diǎn)的坐標(biāo)。
view對(duì)象新增的方法:applyInView:
applyInView方法的作用是在不改變地圖和玩家實(shí)際坐標(biāo)的前提下,在繪制時(shí)使view固定,其他游戲元素相對(duì)于view移動(dòng),實(shí)現(xiàn)移動(dòng)背景的效果。例如,我們需要使玩家相對(duì)于view中點(diǎn)固定,該map上的其他所有游戲元素相對(duì)于view移動(dòng),我們只需要在初始化時(shí):
- this.view=new cnGame.View({map:this.map,x:0,y:0,width:cnGame.width,height:cnGame.height});
- this.view.centerElem(this.player,true);
在繪制時(shí):
- this.view.applyInView(function(){
- map.draw();
- });
這樣map內(nèi)所有元素都會(huì)相對(duì)于view而移動(dòng)。
而applyInView的實(shí)現(xiàn)原理也非常簡(jiǎn)單,它只是不斷使繪制的原點(diǎn)和view的坐標(biāo)等長(zhǎng)且相反:
- /**
- *使坐標(biāo)相對(duì)于view
- **/
- applyInView:function(func){
- cg.context.save();
- cg.context.translate(-this.x, -this.y);
- func();
- cg.context.restore();
- },
這樣無(wú)論view的坐標(biāo)如何變化,view在視覺(jué)上始終固定在canvas,其他元素的坐標(biāo)在視覺(jué)上始終相對(duì)于view。
該游戲所有源碼下載地址:點(diǎn)擊下載
原文:http://www.cnblogs.com/Cson/archive/2012/03/15/2398129.html
【編輯推薦】