日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

cocos2dx3.2开发 RPG《Flighting》(五)只能行走的战斗场景

發布時間:2023/12/20 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 cocos2dx3.2开发 RPG《Flighting》(五)只能行走的战斗场景 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、前言

前面幾節好像與我們一開始說的游戲不太相關,現在我們正式進入戰斗場景的開發。

不過凡事不要心急,要循序漸進,我們先搭建一個能夠讓角色在上面行走的戰斗場景吧。


二、正文

首先精簡一下Role類,讓他能夠實現移動功能就好了。

顧名思義,role就是角色,在戰斗場景出現的一個一個人都是一個role,廢話不多說,直接貼上經過精簡過得Role頭文件

class Role : public Node{ public:Role(); /*create 之前,請先確認已經將文件添加到ArmatureManager*/static Role* create(const std::string& name,FlightLayer* layer);virtual bool init(const std::string& name,FlightLayer* layer);void setControlable(bool b);virtual Rect getBoundingBox();virtual inline void setArmOffsetX(int x){m_arm_offsetX = x;}virtual inline void setArmOffsetY(int y){m_arm_offsetY = y;}protected: /*update相關的*/virtual void update(float delta);virtual void update_pos();/*從RoleProtocol中繼承下來的方法*/ public:virtual bool onTouchBegan(Touch* touch,Event* event);virtual void onTouchMoved(Touch* touch,Event* event);virtual void onTouchEnded(Touch* touch,Event* event);protected:/*與顯示相關的*/bool m_controlable;Armature* m_arm;int m_arm_offsetX;int m_arm_offsetY;bool m_armFaceTo; //朝向,默認為true,向左public:/*外部調用接口*/virtual inline void setDesPoint(const Point& p){m_desPoint = p;}//IDvirtual inline int getId(){return m_id;}protected:/*與戰斗相關的數據*/int m_id; //idPoint m_desPoint;//目標位置int m_speed; //移動速度int m_initSpeed;}; #endif經過精簡后,Role類就剩下這些函數和變量了,現在的這個Role類只能簡單的移動。不要心急,那我們就先實現role的移動吧。


好的,先撇開我們精簡過得Role類,先看我們的GameScene

GameScene.h

class GameScene : public Scene{ public:CREATE_FUNC(GameScene);void setHeroTeam(const HeroMessage& h1,const HeroMessage& h2,const HeroMessage& h3);void setMonsterDeq(deque<MonsterMessage> deq); private:virtual bool init();FlightLayer* layer; };
GameScene的兩個接口setHeroTeam和setMonsterDeq在上一節的選人界面已經使用過了。

void GameScene::setHeroTeam(const HeroMessage& h1,const HeroMessage& h2,const HeroMessage& h3){layer->initTeam(h1,h2,h3); }void GameScene::setMonsterDeq(deque<MonsterMessage> deq){layer->initMonsterDeq(deq); }
GameScene也只是簡單地將信息傳遞給layer層罷了。


下面主要研究FlightLayer

class Role;typedef Role** Role_Ptr; class FlightLayer : public Layer{ friend class Role; /*外部提供接口*/ public:virtual bool init();CREATE_FUNC(FlightLayer);void addRole(Role* r);std::list<Role_Ptr> getRolesArray(){return m_rolesArray;}void initTeam(const HeroMessage& h1,const HeroMessage& h2,const HeroMessage& h3);void initMonsterDeq(deque<MonsterMessage> deq);/*內部使用函數*/ private:virtual void update(float delta);void initListener();bool comparePosY(Role_Ptr a,Role_Ptr b);/*更新layer中role的疊放次序*/void refreshLocalZOrder();/*保持m_cur_control的正確性*/void updateMyControl();virtual bool onTouchBegan(Touch* touch,Event* event);virtual void onTouchMoved(Touch* touch,Event* event);virtual void onTouchEnded(Touch* touch,Event* event);/*類成員變量*/ private:std::list<Role_Ptr> m_rolesArray;Role* m_cur_control;Role_Ptr m_cur_controlPtr; }; #endif
當然啦,這個FlightLayer也是被我精簡過得。

這里需要注意的是,我們將Role**這個二級指針typedef為Role_Ptr,并不是一個新的類啊,至于為啥要用二級指針(其實改為用智能指針也行),等下我會好好說的。


好的開始好好講FlightLayer的實現

bool FlightLayer::init(){this->scheduleUpdate();initListener();m_cur_controlPtr = nullptr;m_cur_control = nullptr;Size visibleSize = Director::getInstance()->getVisibleSize();Sprite* BG = Sprite::create("flightBG.jpg");BG->setAnchorPoint(Point(0.5f,0.5f));BG->setPosition(visibleSize.width/2,visibleSize.height/2);this->addChild(BG);return true; }init函數除了啟動update和調用initListener函數之外沒有其他特別的。

void FlightLayer::initListener(){EventListenerTouchOneByOne* touchListener = EventListenerTouchOneByOne::create();touchListener->onTouchBegan = CC_CALLBACK_2(FlightLayer::onTouchBegan,this);touchListener->onTouchMoved = CC_CALLBACK_2(FlightLayer::onTouchMoved,this);touchListener->onTouchEnded = CC_CALLBACK_2(FlightLayer::onTouchEnded,this);Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraphPriority(touchListener,this); }initListener函數也只是為layer添加觸摸事件監聽器而已。

bool FlightLayer::onTouchBegan(Touch* touch,Event* event){if(m_rolesArray.size() < 1){return false;}for(auto it = m_rolesArray.begin();it!=m_rolesArray.end();++it){if((**it)->onTouchBegan(touch,event)){m_cur_controlPtr = *it;m_cur_control = **it;return true;}}m_cur_controlPtr = nullptr;return false; }大致的意思是:當有點擊事件發生時,onTouchBegan方法被觸發,遍歷m_rolesArray,看哪個角色被選中(能夠接受觸摸事件),如果有角色被選中,就把觸摸事件交給那個角色處理。

m_roleArray是一個Role_Ptr(Role**)的list,用于保存現在存活的role

那么為什么要用二級指針呢?

考慮以下問題:假設現在有兩個角色,如果用一級指針的話,定義如下:

Role* A = Role::create();

Role* B = Role::create();

好了,現在A要攻擊,攻擊目標設置為B(所謂攻擊目標就是一直向目標走去,要時刻檢測目標的當前位置)

如何設置攻擊目標?一級指針的話不就是在Role類里面加一個Role*類型的成員變量(Role* attackTarget)代表攻擊目標就可以了嗎。?

好了,前提條件說完了,現在出現這樣一種情況,A的攻擊目標設置為B(A->attackTarget = B),這時候A會時刻檢測自己的attackTarget的位置,并且不斷地走過去。

但是,假如這個時刻B被C打死了。。那么這個時候B從場景中清除掉(調用removeFromParent)。那么A怎么知道B已經死了,被清除掉了呢?

聰明的同學可能會想:你判斷一下A->attackTarget 是不是等于null不就可以了嗎?但是很抱歉,cocos2dx里面,調用玩removeFromParent之后,原來那塊中間在這一幀結束之前,并不不會置為null。也就是說B 進行remove后,A->attackTarget不等于null,那么有人又問了,你這里的m_rolesArray數組檢測每一個role*(假設m_roleArray里面放入的是Role*而不是Role**),如果死了(Hp==0)就把它賦值為空,不可以嗎?這個就是很經典的C語言關于值傳遞和地址傳遞的問題。你把m_rolesArray里面的臨時變量置為null有什么用?m_rolesArray和A里面的attackTarget指針指向都是同一塊空間(B的實際空間),但是兩個是完全不同的變量,并不能說你把m_rolesArray的指針置為null,A的attackTarget也會變成null,二者是互不影響的。

好的,講了那么多,大家可能會不懂。因為我這里也繞了很久。不過最后還是覺得很有必要理清楚,不懂的同學可以看一下《Effective?C++》里面介紹的RAII思想。

最后,補充一點是,最好用智能指針代替二級指針,這里我懶得修改了,不好意思哈。


貌似繞開了話題了,我們回到FlightLayer吧。

剛剛講到有一個m_rolesArray的List負責保存在場景中還存活的角色。那么這個這些角色是什么時候放進去的呢?

void FlightLayer::initTeam(const HeroMessage& h1,const HeroMessage& h2,const HeroMessage& h3){Hero* hero1 = Hero::create(h1.r_name,this);hero1->setPosition(-100,380);hero1->setDesPoint(Point(200,380));hero1->initWithMessage(h1);this->addRole(hero1);Hero* hero2 = Hero::create(h2.r_name,this);hero2->setPosition(-100,260);hero2->setDesPoint(Point(400,260));hero2->initWithMessage(h2);this->addRole(hero2);Hero* hero3 = Hero::create(h3.r_name,this);hero3->setPosition(-100,140);hero3->setDesPoint(Point(200,140));hero3->initWithMessage(h3);this->addRole(hero3);}void FlightLayer::initMonsterDeq(deque<MonsterMessage> deq){this->m_monsterDeq = deq; }void FlightLayer::addRole(Role* r){//r->setDesPoint(r->getPosition());this->addChild(r);Role_Ptr temp = (Role_Ptr)malloc(sizeof(Role*));*temp = r;m_rolesArray.push_back(temp); }
對的,就是initTeam和initMonsterDeq這兩個接口。這里的addRole是一個基本操作,負責在堆里面開一個區域存放Role的實體。

再回過頭來看我們的三個觸摸事件觸發的回調函數。

bool FlightLayer::onTouchBegan(Touch* touch,Event* event){if(m_rolesArray.size() < 1){return false;}for(auto it = m_rolesArray.begin();it!=m_rolesArray.end();++it){if((**it)->onTouchBegan(touch,event)){m_cur_controlPtr = *it;m_cur_control = **it;return true;}}m_cur_controlPtr = nullptr;return false; }void FlightLayer::onTouchMoved(Touch* touch,Event* event){if(m_cur_control){m_cur_control->onTouchMoved(touch,event);}else{return;} }void FlightLayer::onTouchEnded(Touch* touch,Event* event){if(m_cur_control){m_cur_control->onTouchEnded(touch,event);Point tp = Director::getInstance()->convertToGL(touch->getLocationInView());if(!m_cur_control->getBoundingBox().containsPoint(tp)){m_cur_control->setDesPoint(m_cur_control->getEndPoint());}} }
這三個簡化后的函數應該不難看懂。大概流程是這樣的

1.onTouchBegan接受到觸摸事件之后,檢測m_rolesArray,看是否有Role被點中了,如果有m_cur_controlPtr 和 m_cur_control就設置好,然后把觸摸事件交給m_cur_control(Role)處理。

2.onTouchMoved,沒什么,也是依賴于m_cur_control的處理。

3.onTouchEnded,就是用來設置m_cur_control的終點的。


是不是兜兜轉轉又回到去了Role類,關于精簡過的Role類我們還是標上注釋吧。

class Role : public Node{ public:Role(); /*create 之前,請先確認已經將文件添加到ArmatureManager*/static Role* create(const std::string& name,FlightLayer* layer);virtual bool init(const std::string& name,FlightLayer* layer);void setControlable(bool b);<span style="white-space:pre"> </span>//設置是不是可以控制的virtual Rect getBoundingBox();<span style="white-space:pre"> </span>//獲取范圍virtual inline void setArmOffsetX(int x){m_arm_offsetX = x;}<span style="white-space:pre"> </span>//設置x,y的偏移量virtual inline void setArmOffsetY(int y){m_arm_offsetY = y;}protected: /*update相關的*/virtual void update(float delta);<span style="white-space:pre"> </span>//update函數virtual void update_pos();public:virtual bool onTouchBegan(Touch* touch,Event* event);virtual void onTouchMoved(Touch* touch,Event* event);virtual void onTouchEnded(Touch* touch,Event* event);protected:/*與顯示相關的*/bool m_controlable;<span style="white-space:pre"> </span>//是否可觸摸Armature* m_arm;<span style="white-space:pre"> </span>//骨骼動畫int m_arm_offsetX;<span style="white-space:pre"> </span>//xy偏移量int m_arm_offsetY;bool m_armFaceTo; //朝向,默認為true,向左public:/*外部調用接口*/virtual inline void setDesPoint(const Point& p){m_desPoint = p;} //設置終點位置//IDvirtual inline int getId(){return m_id;}protected:/*與戰斗相關的數據*/int m_id; //idPoint m_desPoint;//目標位置int m_speed; //移動速度int m_initSpeed;}; #endif

其實先跟大家說,Role的行走主要還是依賴于update函數

再解釋上面可能大家不太清楚的幾個名詞

1、xy的偏移量,因為我們用cocostudio做出來的骨骼動畫可能范圍和描點都不是和我們現在這個Role類(Node)完全重合的。所以可能要或多或少地調整一下骨骼動畫的位置。

2、朝向。就是我們的角色是面向哪里的,有左右之分(true/false)


三個觸摸回調函數實現在沒有講控制效果之前也就沒什么的。除了onTouchBegan要根據傳過來的觸摸點判斷是不是被點中。如果是,就返回true不是就返回false。


負責角色移動的還是要看update函數

</pre>update調用update_pos<pre name="code" class="cpp">void Role::update_pos(){if(m_desPoint.x > this->getPosition().x && m_armFaceTo == true){ m_armFaceTo = false;}if(m_desPoint.x < this->getPosition().x && m_armFaceTo == false){m_armFaceTo = true;}if(m_armFaceTo){m_arm->setVisible(false);m_arm->setPosition(m_arm_offsetX,m_arm_offsetY);m_arm->setScaleX(1.0f);m_arm->setVisible(true);}else{m_arm->setVisible(false);m_arm->setScaleX(-1.0f);m_arm->setPosition(-m_arm_offsetX,m_arm_offsetY);m_arm->setVisible(true);}if(!Rect(m_desPoint.x-m_speed/2,m_desPoint.y-m_speed/2,m_speed,m_speed).containsPoint(getPosition())){this->move();float distance = ccpDistance(getPosition(),m_desPoint);float t = distance / m_speed;float speed_x = (m_desPoint.x - getPositionX()) / t;float speed_y = (m_desPoint.y - getPositionY()) / t;setPositionX(getPositionX() + speed_x);setPositionY(getPositionY() + speed_y);}else{this->stand();}}
講一講邏輯就可以了,就是不斷更新Role的x和y,直到接近m_desPoint,要轉身的時候就轉身。


有兩個函數 move()和stand() 其實是用來控制骨骼動畫的。move負責播放跑步的動畫,stand負責播放待機的動畫


對了,好像Role的init函數還沒有講?

bool Role::init(const std::string& name,FlightLayer* layer){m_layer = layer;if(!m_arm){m_arm = Armature::create(name);m_arm->setPosition(m_arm_offsetX,m_arm_offsetY);setContentSize(m_arm->getContentSize());this->addChild(m_arm,1);m_armFaceTo = true;scheduleUpdate();return true;}else{return false;} }
很簡單吧。。也沒什么。


好吧,這節到此結束。

我的csdn地址:http://blog.csdn.net/hezijian22

郵箱地址:578690286@qq.com

如有問題或指教,歡迎與我交流,謝謝。




總結

以上是生活随笔為你收集整理的cocos2dx3.2开发 RPG《Flighting》(五)只能行走的战斗场景的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 日韩高清片 | 捆绑中国女人hd视频 | 91av中文字幕| 久久久久女教师免费一区 | 日韩第一视频 | 哈利波特3在线观看免费版英文版 | www.五月天婷婷 | 色伊人网 | 国产精品网站视频 | 久久久久久久性 | 亚洲天堂一区二区三区四区 | 亚洲专区一区 | 亚洲国产视频在线观看 | 手机天堂网 | 国产女主播喷水视频在线观看 | 国产精品成人一区二区网站软件 | 老女人一毛片 | 精品人妻伦一二三区免费 | 99在线视频观看 | www.18av| 婷婷五月综合激情 | 欧美激情第1页 | 成人黄色免费视频 | 日韩福利视频一区 | 男女激情啪啪 | 久久成人a毛片免费观看网站 | 国内激情视频 | 中文字幕一区二区三区在线不卡 | 男男play呻吟动漫网站 | 国产一区日韩精品 | 亚洲一级一区 | 久久精品国产久精国产 | 免费在线观看日韩av | 丰满白嫩尤物一区二区 | 亚洲香蕉网站 | 亚洲91网 | 久久在线免费 | 亚洲巨乳在线 | 林雅儿欧洲留学恋爱日记在线 | 婷婷日韩| 少妇69xx | 狠狠一区二区 | 第四色在线视频 | 中文字幕丰满乱子伦无码专区 | 亚洲激情三区 | 国产精品高潮呻吟av | 色婷婷天堂| www夜夜操| 午夜激情网站 | 久久av在线播放 | 高h视频在线观看 | 天堂av在线资源 | 大黄毛片 | 依依成人av | 日韩久久精品一区二区 | 精品人妻一区二区三区久久 | 国产性生活一级片 | 777久久久精品一区二区三区 | 丁香九月激情 | 五月情婷婷 | 国产精品香蕉国产 | 国产在线123| 中文av一区 | 一级黄色视 | 日韩在观看线 | 日韩精品1区2区3区 欧美一本 | 中文字幕精品无 | 中文字幕一区二区三区四区免费看 | 国产视频一区二区在线观看 | 91视频黄版 | 午夜影院a | 亚色中文字幕 | av网站免费在线观看 | 台湾佬美性中文娱乐 | 精品97人妻无码中文永久在线 | 亚洲精品日韩在线 | 日本高清视频一区二区三区 | 久久精品国产免费 | 自拍偷拍国产精品 | 蜜桃久久av | 亚洲大片精品 | 国产精品第6页 | 国产又黄又大又粗的视频 | 亚洲欧洲av | 美女扒开内裤让男人捅 | 国产精品变态另类虐交 | 女人十八毛片嫩草av | 亚洲激情第一页 | av鲁丝一区鲁丝二区鲁丝 | 秋霞黄色片| 亚洲国产高清国产精品 | 久久在线一区二区 | 久久免费网 | 131mm少妇做爰视频 | 二区视频在线观看 | 超碰伊人网| www.av在线视频 | 日韩视频在线播放 | 综合色av |