Cocos2d-html5《王者之剑》实现 (1)
生活随笔
收集整理的這篇文章主要介紹了
Cocos2d-html5《王者之剑》实现 (1)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
前面,《 手把手,快速搭建 Cocos2d-HTML5 開發調試環境》 與 《 如何自定義 Cocos2d-HTML5 Loading 界面》 兩篇文章,幫助了我們搭建了其開發環境,并了解了 H5 ( 以下對 Cocos2d-HTML5 簡稱 H5,顯然,它不是 * 流感,沒那么大破壞力) 的大致加載流程,此文開始就要使用 H5 來制作一個簡單的動作游戲 王者之劍,完成效果如下所示(所有的源碼你可以在 【 這里】查看),顯示效果可以在 【 這里】查看(請耐心等待加載):
這是一個簡單的游戲打斗場景,一個英雄,一個怪物,可以控制英雄來回走動并且攻擊,怪物實現簡單 AI 并且自動攻擊,有著不同的血量槽,控制系統,可以使用觸摸,但為了操作的體驗,同樣實現了 鍵盤映射 ,可以使用 W、A、S、D 來控制人物的走動,J、U、I 實現一個普通攻擊和兩個特效攻擊。
項目組織
為了使項目的代碼結構清晰,前期規劃好功能是必須的,先從整體看一下,項目的組織結構,然后會對其中內部實現做些必要的解說:
如上所示, Arthur 為游戲項目的主目錄,與它同級的目錄,是 H5 的庫目錄,當然截圖中,為了發布,刪除了一些不必要的文件,在 Arthut 目錄下,包含一般項目都包含的結構組織。
index.html :?這是游戲的展示界面,其中包含 “gameCanvas” ,作為游戲繪制的所在,它引用加載了 cocos2d.js
cocos2d.js :?項目初始化在這里進行,并完成系統庫和項目源碼的 js 加載,最后將控制權交給 main.js 文件
main.js :?當 H5 庫加載完畢,執行內中代碼,完成項目資源加載,并運行第一個場景
src :?此目錄包含了游戲中編寫的 js 源代碼文件
res :?游戲所需的資源,如圖片,字體等
在這個游戲中相對復雜一點的就是控制系統了, HudLayer 中添加實現了 ActionButton 普通攻擊按鈕, Joypad 可觸摸 360 度 搖桿功能,和 KeyMap 游戲控制鍵盤映射方案。Characters 實現了人物和怪物的功能,各種動作控制。Loading 替換了 H5 的默認加載界面,使用了一個進度條顯示加載進度。GameLayer 作為游戲的主場景,各種游戲的流程控制在這里進行。
360 度 可觸摸搖桿實現
這里的搖桿,默認是為了觸摸實現,之后添加的鍵盤映射,只是為了讓操作更為方便而已(在 PC 瀏覽器中),觸摸不同于搖桿的所在,就是這里的搖桿可以是 360 度以內的任意角度,也就是可以控制任意以任意方向移動,這是鍵盤所不具備的,上下左右四個鍵,再加上每兩個方向的組合也就八個方向。
var?Joypad?=?cc.Layer.extend({? _winSize:?null,? _pCenter:?null,? _pControlSprite:?null,? _pDefaultPoint:?null,? ?? _pDefaultRotation:?null,? _pRotation:?null,? ?? _pDelegate:?null,? _pKeyDown:?false,? ctor:function(){? ?this._super();? ?? _winSize?=?cc.Director.getInstance().getWinSize();? _pCenter?=?cc.p(_winSize.width?/?2,?_winSize.height?/?2);? ?? ?},? init:function(){? ?var?bRet?=?false;? ?if?(this._super()){? cc.log("Joypad?init?..");? ?//?控制桿所在位置? ?this._pDefaultPoint?=?cc.p(110,?110);? ?//?默認旋轉角度,以使開口正對右側? ?this._pDefaultRotation?=?26;? ?//?實際旋轉角度? ?this._pRotation?=?0;? ?? ?this.setPosition(this._pDefaultPoint);? ?? ?this.addChild(cc.Sprite.create(s_Joypad1));? ?this.addChild(cc.Sprite.create(s_Joypad2));? ?this._pControlSprite?=?cc.Sprite.create(s_Joypad3);? ?this.addChild(this._pControlSprite);? ?this.addChild(cc.Sprite.create(s_Joypad4));? ?? ?this.updateRotation();? ?? bRet?=?true;? ?}? ?return?bRet;? ?},? keyStart:function(degrees){? ?if?(this._pDelegate)? ?this._pDelegate.actionJoypadStart(this._pRotation);? ?},? keyUpdate:function(degrees){? ?this._pRotation?=?degrees;? ?this.updateRotation();? ?if?(this._pDelegate)? ?this._pDelegate.actionJoypadUpdate(this._pRotation);? ?},? keyEnded:function(degrees){? ?if?(this._pDelegate)? ?this._pDelegate.actionJoypadEnded(this._pRotation);? ?},? onEnter:function(){? ?this._super();? cc.Director.getInstance().getTouchDispatcher().addTargetedDelegate(this,?0,?true);? ?},? onTouchBegan:function?(touch,?event){? ?//?點擊點的范圍判斷? ?var?curPoint?=?touch.getLocation();? ?if?(curPoint.x?>?_winSize.width?/?2?||?curPoint.y?>?_winSize.height?/?2?){? ?return?false;? ?}? ?? ?//?var?sp?=?cc.pSub(this._pDefaultPoint,?curPoint);? ?//?var?angle?=?cc.pToAngle(sp);? ?? ?this.updateTouchRotation(touch,?event);? ?this.updateRotation();? ?if(this._pDelegate)? ?this._pDelegate.actionJoypadStart(this._pRotation);? ?else? cc.log('_pDelegate?is?null?...?');? ?? ?//?cc.log("Joypad?touch?...");? ?return?true;? ?},? onTouchMoved:function?(touch,?event){? ?this.updateTouchRotation(touch,?event);? ?this.updateRotation();? ?? ?if?(this._pDelegate)? ?this._pDelegate.actionJoypadUpdate(this._pRotation);? ?else? cc.log('_pDelegate?is?null?...?');? ?? ?//?var?a?=?cc.pAngleSigned(?curPoint,?this._pDefaultPoint);? ?//?cc.log("Joypad?touch?mvove?..."?+?rotation)?;? ?},? onTouchEnded:function?(touch,?event){? ?this.updateTouchRotation(touch,?event);? ?this.updateRotation();? ?if?(this._pDelegate)? ?this._pDelegate.actionJoypadEnded(this._pRotation);? ?else? cc.log('_pDelegate?is?null?...?');? ?},? updateTouchRotation:function(touch,?event){? ?var?curPoint?=?touch.getLocation();? ?var?sp?=?cc.pSub(curPoint,?this._pDefaultPoint);? ?var?angle?=?cc.pToAngle(sp)?;//?*?-57.29577951;? ?var?rotation?=?angle?*?-57.29577951;? rotation?=?rotation?<?0???360?+?rotation:?rotation;? ?this._pRotation?=?rotation;? ?},? updateRotation:function(){? ?this._pControlSprite.setRotation(this._pDefaultRotation?+?this._pRotation);? ?},? setDelegate:function(dg){? ?this._pDelegate?=?dg;? ?}? });?
在初始化方法中,加載了搖桿資源文件,它分解成幾個組成部分,以便于很好的控制,并且保存了可旋轉元素精靈的引用this._pControlSprite,以便于隨時控制它的旋轉角度,如圖中 Joypad3.png 圖片。 以觸摸的動作來控制動作的執行,Joypad 中包含了一個名為 _pDelegate 的屬性,它作為控制搖桿的代理,以通知其它 (如 人物),搖桿現在變動了,分別在 onTouchBegan 中調用, this._pDelegate.actionJoypadStart(this._pRotation);,onTouchMoved?中調用 this._pDelegate.actionJoypadUpdate(this._pRotation);?和在 onTouchEnded 中調用 this._pDelegate.actionJoypadEnded(this._pRotation);。 只需要在傳入的 _pDelegate 中實現此三種函數,就可以通過搖桿來控制其操作了,H5 使用 javascript 相比如 C++ 倒也省去了接口定義等繁雜的操作??梢钥匆?#xff0c;在三個函數調用中,所傳入的參數為觸摸的角度,在觸摸是通知控制顯示搖桿中 “羅盤” 的旋轉。Joypad 對內通過觸摸控制顯示,對外通過觸摸調用代理,以達到顯示和控制相一致的目的。通過觸摸的點相對搖桿原點的位置關系,很容計算出其角度。 由于這里的搖桿設計是 360 度任意角度,所以在 delegate 中傳出一個參數,以標示角度關系,如果并不需要那么復雜的控制,如前文所言,只需固定八個方向的控制,那么這里傳出的參數可以使用 枚舉 類型,代表八個不同的方向,也會使得游戲邏輯變得稍微簡單。 最后可以為 Joypad 層封裝一個簡單好用的調用方式:Joypad.create?=?function(){? ?var?joypad?=?new?Joypad();? ?if?(joypad?&&?joypad.init()){? ?return?joypad;? ?}? ?return?null;? };?
攻擊 與 特效攻擊
在這個游戲中,有一個普通攻擊和兩個特效攻擊,這兩個不同,但很顯然,他們都是攻擊,卻又相同,先看看他們的共同點:
//?ActionButton.js? ?? var?ActionButton?=?cc.Node.extend({? _sprite:?null,? _rect:?null,? _delegate:?null,? _attackType:?null,? ?? _childObj:?null,? rect:function(){? ?var?size?=?this._sprite.getContentSize();? ?return?cc.rect(-size.width?/?2,?-size.height?/?2,?size.width,?size.height);? ?},? setChindObj:function(obj){? ?this._childObj?=?obj;? ?},? init:function(image){? ?this._super();? ?? ?this._sprite?=?cc.Sprite.create(image);? ?this.addChild(this._sprite);? ?return?true;? ?},? setDelegate:function(delegate){? ?this._delegate?=?delegate;? ?},? setAttackType:function(at){? ?this._attackType?=?at;? ?},? getAttackType:function(){? ?return?this._attackType;? ?},? onEnter:function(){? cc.Director.getInstance().getTouchDispatcher().addTargetedDelegate(this,?0,?false);? ?this._super();? ?},? onExit:function(){? cc.Director.getInstance().getTouchDispatcher().removeDelegate(this);? ?this._super();? ?},? containsTouchLocation:function(touch){? ?return?cc.rectContainsPoint(this.rect(),?this.convertTouchToNodeSpace(touch));? ?},? onTouchBegan:function(touch,?event){? ?//?區域判斷? ?if?(!this.containsTouchLocation(touch))? ?return?false;? ?this.click();? ?//?播放點擊動畫? ?return?true;? ?},? click:function(){? ?if(this._delegate?&&?this._childObj.isCanClick()){? ?this._delegate.attackButtonClick(this.getAttackType());? ?this.beganAnimation();? ?}? ?},? onTouchEnded:function(touch,?event){? ?this.endedAnimation();? ?},? beganAnimation:function(){? ?},? endedAnimation:function(){? ?},? isCanClick:function(){? ?return?true;? ?}? });?
定義了一個 ActionButton 攻擊按鈕類型,它實現了 onTouchBegan 作為按鈕點擊的觸發場所,觸發了 click 事件,再由 click 處理調用代理的事件,傳出一個參數,以標示攻擊的類型 AttackType,在判斷點擊的時候還需要檢測點擊區域是否在按鈕的可點擊范圍之內,當然再觸發攻擊動作之時,按鈕本身也實現了一些動畫特效,如點擊效果,技能冷卻效果,它由beganAnimation 方法實現。
但我們看見在 ActionButton 并沒有實現 beganAnimation,在方法里面并沒有實現任何代碼,這因為 ActionButton 只是作為 攻擊按鈕 的抽象,它只定義了攻擊按鈕具體由那些功能,能做哪些事情,如可以播放點擊時的動畫,但具體的動畫內容,需要根據具體的攻擊按鈕有著不同的實現。
var?AttackButton?=?ActionButton.extend({? _pt:?null,? _ac:?null,? ?? _defaultScale:?0.35,? _maxScale:?0.5,? ?? _inAction:?null,? _outAction:?null,? ?? _timestamp:?null,? ctor:function(){? ?this._super();? ?this._pt=?cc.Sprite.create(s_AttackO);? ?this._pt.setScale(this._maxScale);? ?this.setChindObj(this);? ?? ?//?this.addChild(this._pt);? ?? ?var?aScale?=?cc.ScaleTo.create(0.1,?this._defaultScale);? ?var?aFadein?=?cc.FadeIn.create(0.1);? ?this._inAction?=?cc.Spawn.create(aScale,?aFadein);? ?? ?var?oScale?=?cc.ScaleTo.create(.2,?this._maxScale);? ?var?oFade?=?cc.FadeOut.create(0.2);? ?this._outAction?=?cc.Spawn.create(oScale,?oFade);? ?},? beganAnimation:function(){? ?var?timestamp?=?(new?Date()).valueOf();? ?this._timestamp?=?timestamp;? ?? ?this.removeChild(this._pt);? ?this.addChild(this._pt);? ?this._pt.runAction(this._inAction);? ?? ?},? endedAnimation:function(){? ?this._pt.stopAllActions();? ?this._pt.runAction(this._outAction);? ?},? clickUp:function(){? ?this.endedAnimation();? ?},? isCanClick:function(){? ?var?timestamp?=?(new?Date()).valueOf();? ?return?timestamp?-?this._timestamp?>?600;? ?}? });?
普通攻擊按鈕的效果,初始化設置圖片素材,播放動畫為一個光圈放大縮小顯示,它 繼承 自 ActionButton ,同樣實現了 beganAnimation 方法。另外一種是特效攻擊的實現:
var?AttackEffect?=?ActionButton.extend({? _pt:?null,? _ac:?null,? _isCanClick:?true,? ctor:function(){? ?this._super();? ?var?h?=?cc.Sprite.create(s_AttackFreeze);? ?this._pt?=?cc.ProgressTimer.create(h);? ?this._pt.setType(cc.PROGRESS_TIMER_TYPE_RADIAL);? ?this._pt.setReverseDirection(true);? ?this._pt.setScale(0.43);? ?? ?var?to?=?cc.ProgressTo.create(0,?99.999);? ?var?to1?=?cc.ProgressTo.create(2,?0);? ?var?ac2?=?cc.CallFunc.create(this.callBack,?this);? ?this._ac?=?cc.Sequence.create(to,?to1,?ac2);? ?this.setChindObj(this);? ?},? beganAnimation:function(){? ?this.removeChild(this._pt);? ?this.addChild(this._pt);? ?this._pt.runAction(this._ac);? ?this._isCanClick?=?false;? ?},? endedAnimation:function(){? ?},? callBack:function(){? ?//?cc.log("call?back");? ?this._isCanClick?=?true;? ?},? isCanClick:function(){? ?return?this._isCanClick;? ?}? });?
特效攻擊有個冷卻效果,不能在一定時間范圍內連續攻擊,使用一個 旋轉的 Progress 來達到這樣的效果。
在初始化方法中,加載了搖桿資源文件,它分解成幾個組成部分,以便于很好的控制,并且保存了可旋轉元素精靈的引用this._pControlSprite,以便于隨時控制它的旋轉角度,如圖中 Joypad3.png 圖片。 以觸摸的動作來控制動作的執行,Joypad 中包含了一個名為 _pDelegate 的屬性,它作為控制搖桿的代理,以通知其它 (如 人物),搖桿現在變動了,分別在 onTouchBegan 中調用, this._pDelegate.actionJoypadStart(this._pRotation);,onTouchMoved?中調用 this._pDelegate.actionJoypadUpdate(this._pRotation);?和在 onTouchEnded 中調用 this._pDelegate.actionJoypadEnded(this._pRotation);。 只需要在傳入的 _pDelegate 中實現此三種函數,就可以通過搖桿來控制其操作了,H5 使用 javascript 相比如 C++ 倒也省去了接口定義等繁雜的操作??梢钥匆?#xff0c;在三個函數調用中,所傳入的參數為觸摸的角度,在觸摸是通知控制顯示搖桿中 “羅盤” 的旋轉。Joypad 對內通過觸摸控制顯示,對外通過觸摸調用代理,以達到顯示和控制相一致的目的。通過觸摸的點相對搖桿原點的位置關系,很容計算出其角度。 由于這里的搖桿設計是 360 度任意角度,所以在 delegate 中傳出一個參數,以標示角度關系,如果并不需要那么復雜的控制,如前文所言,只需固定八個方向的控制,那么這里傳出的參數可以使用 枚舉 類型,代表八個不同的方向,也會使得游戲邏輯變得稍微簡單。 最后可以為 Joypad 層封裝一個簡單好用的調用方式:
總結
以上是生活随笔為你收集整理的Cocos2d-html5《王者之剑》实现 (1)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python批量拼接两个文件夹相同名字的
- 下一篇: 通过网址自动网页截图(Selenium实