この記事はこのシリーズ記事の 3 番目です。他の記事については、以下の投稿の目次をご覧ください
//m.sbmmt.com/html5-tutorial-354344 .html
この一連のチュートリアルは、私が初めて冗談めいた開発スタイルを採用したものです。記事の内容のほとんどはただ読むだけで大丈夫です。浸水すること。
このタイプの開発における最初のボトルネックはマテリアルです。多数のマテリアルの URL を提供してくれた netizen yorhomwang に感謝します。
以下はこの開発の結果です。最初にプレビューしてください。
今回見つけた素材はすべてgif形式の画像です。ゲーム内で使用したい場合は、gif画像の各フレームを取り出して新しい画像を作成する必要があります。 Flash は簡単な変換ツールを作成しましたので、必要な方は下記の URL をご利用ください。
http://lufylegend.com/flash/demo/GifToPng
黄将軍はしばらく私によって戦場から取り残されていたと言えますが、彼は最近非常に退屈しています。彼は戦場でナイフを持ち、斬り、走り、狂ったように咆哮を上げていました...
私はもう見るに耐えられず、彼の老人に楽しみを加えるために数行のコードを書き続けることにしました。
まず、戦場のマップを移動しましょう。変数を定義しても同じ場所を走ることはできません。
var back_run = true;
この変数が true の場合、戦場の背景マップを移動できます。それ以外の場合は移動できません。
次に、Player.js の move 関数に戦場の移動を制御するコードを追加します。なぜこれが Character.js ではなく Player.js にあるのでしょうか。主人公の黄将軍が移動したときにのみマップが移動するため、キャラクターは親クラスであり、後で敵もこのクラスを継承します。
Player.prototype.move = function (){ var self = this, mx = 0, my = 0; if(keyCtrl[KEY.LEFT] && charaLayer.x + self.x > 0){ mx = -1; }else if(keyCtrl[KEY.RIGHT] && charaLayer.x + self.x < LGlobal.width){ mx = 1; } if(keyCtrl[KEY.UP]){ my = -1; }else if(keyCtrl[KEY.DOWN]){ my = 1; } self.mx = mx; self.my = my; if(self.action == ACTION.RUN){ mx *= 2; my *= 2; }else if(self.action == ACTION.HIT){ mx = 2*(self.direction == DIRECTION.RIGHT ? 1 : -1); my = 0; } if(back_run && mx > 0 && charaLayer.x + self.x > LGlobal.width * 0.5){ var setX = mx*MOVE_STEP; if(backLayer.data.x + setX + backLayer.data.width > backLayer.data.image.width){ back_run = false; setX = backLayer.data.image.width - backLayer.data.width - backLayer.data.x; } charaLayer.x -= setX; backLayer.data.setCoordinate(backLayer.data.x + setX,backLayer.data.y); addEnemy(); } self.callParent("move",arguments); };
主人公が移動すると、マップ座標が逆方向に増減することがわかり、視覚的なマップ移動が実現されているかどうかを検出するための addEnemy 関数が呼び出される行があることに注意してください。敵を追加します。
孫尚香の資料をいくつか見つけましたので、一つずつ挙げることはしません。
以下に Enemy.js クラスを追加します
function Enemy(list,speed){ var self = this; base(this,Character,[list,speed]); self.belong = "enemy"; self.hp = 100; }; Enemy.prototype.onjump = function (){ var self = this; self.callParent("onjump",arguments); self.setLocation(); var index = self.anime.colIndex; self.yArr = [0,-10,-20,-30,-40,-40,-30,-20,-10,0]; self.anime.y += self.yArr[index]; }; Enemy.prototype.onjump_attack = function (){ var self = this; self.callParent("onjump_attack",arguments); self.setLocation(); var index = self.anime.colIndex; if(index >= self.yArr.length)return; self.anime.y += self.yArr[index]; }; Enemy.prototype.setAction = function (action,direction){ var self = this,yArr = new Array(); if(action == ACTION.MOVE && self.action == ACTION.JUMP)return; if(action == ACTION.JUMP_ATTACK){ var index = self.anime.colIndex,i; for(i = index;i0){ self.anime.y += self.yArr[0]; } }; Enemy.prototype.overActionRun = function (lastAction,animeAction){ var self = this; self.callParent("overActionRun",arguments); keylock = false; if(lastAction == ACTION.FALL){ if(self.direction == DIRECTION.LEFT){ self.x += 80; }else{ self.x -= 80; } } }; Enemy.prototype.move = function (){ var self = this, mx = 0, my = 0; self.mx = mx; self.my = my; self.callParent("move",arguments); };
このクラスは Player.js に似ていますが、どちらも Character クラスから継承していますが、関連するすべての配列をコンストラクターに渡さなくなった点が異なります。これは非常に面倒です。代わりに、設定する必要があるすべてのパラメータを含む配列リストが渡されます。
敵を追加するaddEnemy()関数を呼び出した場合、無制限に敵を追加することはできないので、追加する敵と追加するタイミングを事前に準備してください。
var enemy_list = new Array( {name:"sunji",x:800,y:350,when_x:300,back_run:false}, {name:"huangzhong",x:1200,y:280,when_x:800,back_run:true} ); function addEnemy(){ if(enemy_list.length == 0)return; if(enemy_list[0].when_x > hero.x)return; var charadata = CharacterList[enemy_list[0].name](); var enemy = new Enemy(charadata); enemy.x = enemy_list[0].x; enemy.y = enemy_list[0].y; charaLayer.addChild(enemy); enemy_list.shift(); }
敵を追加したときの when_x と、敵が出現した位置の座標、そして addEnemy 関数が呼び出されたときにマップの移動が停止するかどうかなどの情報を含む、enemies_list 配列を追加しました。 when_x と主人公の位置を使用して、敵を追加する必要があるかどうかを判断します。
敵と、攻める覚悟と攻められる覚悟について話しましょう。
攻撃の判定は実際には当たり判定になりますが、もちろんピクセルレベルの当たり判定を使用することもできますが、この種のゲームでは少しやりすぎで効率が低すぎるため、長方形の当たり判定を使用します。ここ。
lufylegend.js エンジンには、四角形が衝突するかどうかを検出するために使用できる LGlobal.hitTest() 関数があります。ただし、画像素材には空白領域が多いため、このメソッドでは少し誤差が大きすぎます。直接使用するため、キャラクターの各フレームで検出する必要がある攻撃範囲と攻撃範囲を設定します。以下の CharacterList.js のコードを参照してください。
var CharacterList = { huangzhong:function(){ //图片数据 var dataList = new Array(); dataList.push(new LBitmapData(imglist["player_stand"],0,0,106,77)); dataList.push(new LBitmapData(imglist["player_move"],0,0,115,85)); dataList.push(new LBitmapData(imglist["player_run"],0,0,125,87)); dataList.push(new LBitmapData(imglist["player_jump"],0,0,131,134)); dataList.push(new LBitmapData(imglist["player_attack"],0,0,242,143)); dataList.push(new LBitmapData(imglist["player_big_attack"],0,0,232,143)); dataList.push(new LBitmapData(imglist["player_jump_attack"],0,0,232,143)); dataList.push(new LBitmapData(imglist["player_hit"],0,0,161,88)); dataList.push(new LBitmapData(imglist["player_skill"],0,0,324,140)); dataList.push(new LBitmapData(imglist["player_big_skill"],0,0,441,166)); dataList.push(new LBitmapData(imglist["player_hert"],0,0,179,87)); dataList.push(new LBitmapData(imglist["player_fall"],0,0,298,157)); //图片分割数据 var coordinateList = new Array(); coordinateList.push(LGlobal.pideCoordinate(1272,77,1,12)); coordinateList.push(LGlobal.pideCoordinate(920,85,1,8)); coordinateList.push(LGlobal.pideCoordinate(750,87,1,6)); var jumpList = LGlobal.pideCoordinate(655,134,1,5); coordinateList.push([[jumpList[0][0],jumpList[0][0],jumpList[0][1],jumpList[0][1],jumpList[0][2],jumpList[0][2],jumpList[0][3],jumpList[0][3],jumpList[0][4],jumpList[0][4]]]); var attackList = LGlobal.pideCoordinate(484,143,1,2); coordinateList.push([[attackList[0][0],attackList[0][1],attackList[0][1],attackList[0][1]]]); var bigattackList = LGlobal.pideCoordinate(927,143,1,4); coordinateList.push(bigattackList); var jumpattackList = LGlobal.pideCoordinate(927,143,1,4); coordinateList.push(jumpattackList); coordinateList.push(LGlobal.pideCoordinate(966,88,1,6)); coordinateList.push(LGlobal.pideCoordinate(2268,140,1,7)); var bigskillList = LGlobal.pideCoordinate(2205,830,5,5); coordinateList.push([[bigskillList[0][0],bigskillList[0][1],bigskillList[0][2],bigskillList[0][3],bigskillList[0][4] ,bigskillList[1][0],bigskillList[1][1],bigskillList[1][2],bigskillList[1][3],bigskillList[1][4] ,bigskillList[2][0],bigskillList[2][1],bigskillList[2][2],bigskillList[2][3],bigskillList[2][4] ,bigskillList[3][0],bigskillList[3][1],bigskillList[3][2],bigskillList[3][3],bigskillList[3][4] ,bigskillList[4][0],bigskillList[4][1],bigskillList[4][2],bigskillList[4][3],bigskillList[4][4]]]); var hertList = LGlobal.pideCoordinate(358,87,1,2); coordinateList.push([[hertList[0][0],hertList[0][0],hertList[0][1],hertList[0][1]]]); var fallList = LGlobal.pideCoordinate(2682,157,1,9); coordinateList.push([[fallList[0][0],fallList[0][1],fallList[0][2],fallList[0][3],fallList[0][4],fallList[0][5],fallList[0][6],fallList[0][6],fallList[0][6],fallList[0][7],fallList[0][7],fallList[0][6],fallList[0][6],fallList[0][7],fallList[0][8]]]); //图片位置数据 var locationList = new Array(); locationList.push({x:0,y:0}); locationList.push({x:0,y:0}); locationList.push({x:0,y:0}); locationList.push({x:0,y:0}); locationList.push({x:20,y:20}); locationList.push({x:20,y:20}); locationList.push({x:20,y:20}); locationList.push({x:0,y:0}); locationList.push({x:100,y:0}); locationList.push({x:150,y:20}); locationList.push({x:5,y:0}); locationList.push({x:-30,y:10}); //被攻击范围 var hertList = [[[-30,-60,60,50],[-30,-60,60,50],[-30,-60,60,50],[-30,-60,60,50],[-30,-60,60,50],[-30,-60,60,50],[-30,-60,60,50],[-30,-60,60,50],[-30,-60,60,50],[-30,-60,60,50],[-30,-60,60,50],[-30,-60,60,50]], [[-30,-70,50,60],[-30,-70,50,60],[-30,-70,50,60],[-30,-70,50,60],[-30,-70,50,60],[-30,-70,50,60],[-30,-70,50,60],[-30,-70,50,60]], [[-30,-70,60,60],[-30,-70,60,60],[-30,-70,60,60],[-30,-70,60,60],[-30,-70,60,60],[-30,-70,60,60]], [[-25,-70,50,60],[-25,-70,50,60],[-25,-70,50,60],[-25,-70,50,60],[-25,-70,50,60]], [[-10,-60,30,60],[-10,-60,30,60],[-30,-60,30,60],[-30,-60,30,60]], [[0,-60,40,60],[0,-60,40,60],[-20,-60,30,60],[-20,-60,30,60]], [], [[-20,-60,30,60],[-20,-60,30,60],[-20,-60,30,60],[-20,-60,30,60],[-20,-60,30,60],[-20,-60,30,60]], [[0,-70,40,60],[0,-70,40,60]], [],[],[] ]; //攻击范围 var attackList = [[],[],[],[], [[0,0,0,0],[0,0,0,0],[-10,-70,115,60],[-10,-70,115,60]], [[0,0,0,0],[0,0,0,0],[-10,-100,140,90],[-10,-100,140,90]], [[0,0,0,0],[0,0,0,0],[-10,-130,115,60],[-10,-110,140,120]], [[10,-70,30,70],[10,-70,30,70],[10,-70,30,70],[10,-70,30,70],[10,-70,30,70],[10,-70,30,70]], [[0,0,0,0],[0,0,0,0],[-40,-70,80,60],[-60,-100,80,60],[20,-100,130,100],[20,-100,130,100]], [[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0], [50,-105,50,20],[60,-100,120,40],[60,-90,150,40],[50,-80,190,40],[50,-80,210,40], [50,-75,310,60],[50,-75,310,60],[50,-75,310,60],[50,-75,310,80]],[],[] ]; return [dataList,coordinateList,locationList,hertList,attackList]; }, sunji:function(){ //图片数据 var dataList = new Array(); dataList.push(new LBitmapData(imglist["sunji_stand"],0,0,129,89)); dataList.push(new LBitmapData(imglist["sunji_move"],0,0,128,97)); dataList.push(new LBitmapData(imglist["sunji_run"],0,0,125,77)); dataList.push(new LBitmapData(imglist["sunji_jump"],0,0,131,134)); dataList.push(new LBitmapData(imglist["sunji_attack"],0,0,197,103)); dataList.push(new LBitmapData(imglist["sunji_big_attack"],0,0,198,103)); dataList.push(new LBitmapData(imglist["sunji_jump_attack"],0,0,182,143)); dataList.push(new LBitmapData(imglist["sunji_hit"],0,0,238,86)); dataList.push(new LBitmapData(imglist["sunji_skill"],0,0,215,102)); dataList.push(new LBitmapData(imglist["sunji_big_skill"],0,0,275,139)); dataList.push(new LBitmapData(imglist["sunji_hert"],0,0,131,79)); dataList.push(new LBitmapData(imglist["sunji_fall"],0,0,249,136)); //图片分割数据 var coordinateList = new Array(); coordinateList.push(LGlobal.pideCoordinate(1548,89,1,12)); coordinateList.push(LGlobal.pideCoordinate(640,97,1,5)); coordinateList.push(LGlobal.pideCoordinate(1000,77,1,8)); var jumpList = LGlobal.pideCoordinate(655,134,1,5); coordinateList.push([[jumpList[0][0],jumpList[0][0],jumpList[0][1],jumpList[0][1],jumpList[0][2],jumpList[0][2],jumpList[0][3],jumpList[0][3],jumpList[0][4],jumpList[0][4]]]); var attackList = LGlobal.pideCoordinate(394,103,1,2); coordinateList.push([[attackList[0][0],attackList[0][1],attackList[0][1],attackList[0][1]]]); var bigattackList = LGlobal.pideCoordinate(792,103,1,4); coordinateList.push(bigattackList); var jumpattackList = LGlobal.pideCoordinate(728,143,1,4); coordinateList.push(jumpattackList); coordinateList.push(LGlobal.pideCoordinate(1428,86,1,6)); coordinateList.push(LGlobal.pideCoordinate(2365,102,1,11)); var bigskillList = LGlobal.pideCoordinate(1650,695,5,6); coordinateList.push([[bigskillList[0][0],bigskillList[0][1],bigskillList[0][2],bigskillList[0][3],bigskillList[0][4],bigskillList[0][5] ,bigskillList[1][0],bigskillList[1][1],bigskillList[1][2],bigskillList[1][3],bigskillList[1][4],bigskillList[1][5] ,bigskillList[2][0],bigskillList[2][1],bigskillList[2][2],bigskillList[2][3],bigskillList[2][4],bigskillList[2][5] ,bigskillList[3][0],bigskillList[3][1],bigskillList[3][2],bigskillList[3][3],bigskillList[3][4],bigskillList[3][5] ,bigskillList[4][0],bigskillList[4][1],bigskillList[4][2],bigskillList[4][3],bigskillList[4][4],bigskillList[4][5]]]); var hertList = LGlobal.pideCoordinate(262,79,1,2); coordinateList.push([[hertList[0][0],hertList[0][0],hertList[0][1],hertList[0][1]]]); var fallList = LGlobal.pideCoordinate(1245,544,4,5); coordinateList.push([[fallList[0][0],fallList[0][1],fallList[0][2],fallList[0][3],fallList[0][4],fallList[1][0],fallList[1][1],fallList[1][2],fallList[1][3],fallList[1][4],fallList[2][0],fallList[2][1],fallList[2][2],fallList[2][3],fallList[2][4],fallList[3][0],fallList[3][1],fallList[3][2],fallList[3][3],fallList[3][4]]]); //图片位置数据 var locationList = new Array(); locationList.push({x:0,y:0}); locationList.push({x:0,y:0}); locationList.push({x:0,y:0}); locationList.push({x:0,y:0}); locationList.push({x:40,y:8}); locationList.push({x:20,y:0}); locationList.push({x:20,y:20}); locationList.push({x:0,y:0}); locationList.push({x:0,y:0}); locationList.push({x:70,y:10}); locationList.push({x:5,y:0}); locationList.push({x:-35,y:0}); //被攻击范围 var hertList = [[[-25,-70,60,60],[-25,-70,60,60],[-25,-70,60,60],[-25,-70,60,60],[-25,-70,60,60],[-25,-70,60,60],[-25,-70,60,60],[-25,-70,60,60],[-25,-70,60,60],[-25,-70,60,60],[-25,-70,60,60],[-25,-70,60,60]], [[-25,-90,50,80],[-25,-90,50,80],[-25,-90,50,80],[-25,-90,50,80],[-25,-90,50,80],[-25,-90,50,80],[-25,-90,50,80],[-25,-90,50,80]], [[-30,-60,70,40],[-30,-60,70,40],[-30,-60,70,40],[-30,-60,70,40],[-30,-60,70,40],[-30,-60,70,40]], [[-25,-90,50,70],[-25,-90,50,70],[-25,-90,50,70],[-25,-90,50,70],[-25,-90,50,70]], [[-20,-80,50,70],[-20,-80,50,70],[-10,-60,70,50],[-10,-60,70,50]], [[-10,-80,50,60],[-10,-80,50,60],[-10,-80,50,60],[-10,-80,50,60]], [[-30,-80,50,70],[-30,-80,50,70],[-30,-80,50,70],[-30,-80,50,70]], [[-20,-70,60,60],[-20,-70,60,60],[-20,-70,60,60],[-20,-70,60,60],[-20,-70,60,60],[-20,-70,60,60]], [[-10,-80,40,70],[-10,-80,40,70]], [],[],[] ]; //攻击范围 var attackList = [[],[],[],[], [[0,0,0,0],[0,0,0,0],[30,-70,75,60],[30,-70,75,60]], [[0,0,0,0],[0,0,0,0],[20,-100,80,90],[20,-100,80,90]], [[0,0,0,0],[0,0,0,0],[-10,-90,100,80],[-10,-90,100,80]], [[10,-70,50,70],[10,-70,50,70],[10,-70,50,70],[10,-70,50,70],[10,-70,50,70],[10,-70,50,70]], [[0,0,0,0],[0,0,0,0],[-30,-70,90,60],[-90,-70,130,60],[-100,-80,140,70],[-40,-80,140,70]], [[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,-100,100,40],[0,-110,100,50],[0,-110,100,50], [0,0,0,0],[20,-120,140,120],[20,-120,130,120],[-50,-120,160,120],[-60,-80,180,80], [-20,-50,150,60],[-10,-60,150,60],[50,-60,90,60],[50,-75,150,70],[50,-75,150,70], [50,-75,150,70],[50,-75,150,70]],[],[] ]; return [dataList,coordinateList,locationList,hertList,attackList]; } }
このように、これらの事前設定された範囲を使用して衝突を検出するだけです。このような長方形の衝突を検出するにはどうすればよいでしょうか。もちろん、lufylegend.js エンジンの四角形クラス LRectangle を使用します。具体的な使い方は公式 API ドキュメントを参照してください。今回使用した衝突検出は、LRectangle が 2 つあるかどうかを検出するために使用されます。オブジェクトが重なるか、つまり衝突するかどうかです。
こちら側もこちらも攻撃される可能性があるため、攻撃判定を親クラスCharacterにロードし、Characterクラスのonframe関数に以下のコードを追加します。
if(self.action == ACTION.ATTACK || self.action == ACTION.BIG_ATTACK || self.action == ACTION.HIT || self.action == ACTION.JUMP_ATTACK || self.action == ACTION.SKILL || self.action == ACTION.BIG_SKILL){ for(key in charaLayer.childList){ chara = charaLayer.childList[key]; if(self.belong == chara.belong)continue; self.checkAction(chara); } }
つまり、現在のキャラクターのアクションが攻撃などのアクションであり、それが敵の場合、攻撃検出 checkAction 関数に入ります。 checkAction 関数は次のとおりです。
Character.prototype.checkAction = function (chara){ var self = this; var attack_rect = self.getAttackRect(); var hert_rect = chara.getHertRect(); if(!attack_rect || !hert_rect)return; if(attack_rect.intersects(hert_rect) && Math.abs(self.y - chara.y) < 30){ if(self.action == ACTION.ATTACK){ chara.setAction(ACTION.HERT,chara.direction); }else{ var dir = DIRECTION.RIGHT; if(self.x < chara.x)dir = DIRECTION.LEFT; chara.setAction(ACTION.FALL,dir); } } }
getAttackRect函数和getHertRect函数分别返回当前的攻击和被攻击的范围LRectangle对象,然后通过intersects函数判断是否攻击到了对方,如果是普通攻击,则被攻击方变为被攻击状态,其他攻击方式的话,变为摔倒状态。
getAttackRect和getHertRect函数如下。
Character.prototype.getAttackRect = function(){ var self = this; attackList = self.attackList[self.action]; if(self.anime.colIndex >= attackList.length)return false; var rect = attackList[self.anime.colIndex]; var x = rect[0],y=rect[1],w=rect[2],h=rect[3]; if(x == 0 && y == 0 && w == 0 && h == 0)return false; y += self.y; if(self.direction == DIRECTION.LEFT){ x = self.x - x - w; }else{ x = self.x +x; } return new LRectangle(x,y,w,h); } Character.prototype.getHertRect = function(){ var self = this; var hertList = self.hertList[self.action]; if(self.anime.colIndex >= hertList.length)return false; var rect = hertList[self.anime.colIndex]; var x = rect[0],y=rect[1],w=rect[2],h=rect[3]; if(x == 0 && y == 0 && w == 0 && h == 0)return false; y += self.y; if(self.direction == DIRECTION.LEFT){ x = self.x - x - w; }else{ x = self.x +x; } return new LRectangle(x,y,w,h); }
好了,剩下的敌人的AI和声效等部分,咱们留着以后再继续。现在,大家可以点击下面的测试连接,看看本次的成果了
http://lufy.netne.net/lufylegend-js/act03/index.html
黄老将军听说即将登场的是孙尚香后激动不已,那叫一个美啊,眼睛整个眯成了一个心形,大吼着,尚香啊,老夫等你几百年了。这是在令我大吃一惊,孙尚香不是刘备老婆吗,是这老家伙的主子啊,这真是太不像话了。可老将军在一旁兴奋的吼着,“靠!我会让你知道我暗恋她几百年吗?老夫绝对不会承认的。”,“如果当年我年轻个几十年,呸,我怎么会这么想,她毕竟是主公的老婆。”,“不对,主公也老了。啊,老夫可是忠臣,我是不会跟主公抢的。”,“老夫什么都没说。lufy,你给我听着,老夫什么都没说。”。我急忙说“啊啊,我什么都没听见啊……”
不过,这有什么用啊,这老家伙一上场,就开始往前跑,边跑边嘟囔“妞,给大爷摸一个……”。由于某种原因,这里省略1000字。
终于,孙尚香出现了,老黄忠一下子就扑了过去,刚伸手去摸了一把,就发现孙尚香被他打的满地跑,立马吼道“lufy,老夫要的是摸,不是砍啊”。
lufy:“哼哼,老色鬼,我岂能给你方便,让你得逞……”,另外他还不知道在前面,还给他准备了另一个黄忠,一个孙尚香,看他们怎么抢吧,哈哈。
唉,真是:
神箭威名数黄忠,斩将杀敌显神通。百年宝刀仍未老,一遇红颜梦成空。
现在给出本次源码下载,喜欢的可以看一下。
http://fsanguo.comoj.com/download.php?i=act03.rar
注意:该附件只包含本次文章源码,lufylegend.js引擎请到http://lufylegend.com/lufylegend进行下载。
以上就是[HTML5游戏开发]挑战横版ACT(三):遇红颜英雄亦多情的内容,更多相关内容请关注PHP中文网(m.sbmmt.com)!