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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

学习3 二维游戏动画合成(侠客行)

發(fā)布時(shí)間:2023/12/10 编程问答 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 学习3 二维游戏动画合成(侠客行) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

說明:

<學(xué)習(xí)>系列所有的源代碼均由《計(jì)算機(jī)游戲程序設(shè)計(jì)》提供。本人會(huì)在這些代碼中融入自己的想法,對(duì)其進(jìn)行迭代優(yōu)化,旨在個(gè)人學(xué)習(xí)。

?

教材源代碼示例:

示例代碼的迷之bug賊多,怪物AI也只有一套固定的行動(dòng)模式

優(yōu)化后的效果:

?

學(xué)習(xí)目標(biāo):

1.了解二維游戲動(dòng)畫合成原理。

2.熟悉Cocos2d-x中的用戶交互、觸摸事件、碰撞檢測(cè)機(jī)制。

3.熟悉CocoStudio動(dòng)畫編輯器的使用,了解骨骼動(dòng)畫。

主要修改內(nèi)容:

1.利用cocostudio修改人物骨骼,并將修改結(jié)果在游戲中讀取,從而改變?nèi)宋锿庑?#xff0c;動(dòng)作等,實(shí)現(xiàn)自定義人物骨骼動(dòng)畫效果。

2.增加英雄defend動(dòng)作,記錄成功/失敗次數(shù),增加計(jì)分板功能。

3.修復(fù)bug,使游戲能正常運(yùn)行。

4.怪物AI設(shè)計(jì)。

?

步驟與過程:

1.利用cocostudio修改人物骨骼,并將修改結(jié)果在游戲中讀取,從而改變?nèi)宋锿庑?#xff0c;動(dòng)作等,實(shí)現(xiàn)自定義人物骨骼動(dòng)畫效果。

?

CocoStudio Animation導(dǎo)入新的部位的圖片,如下圖的帽子和斧子:

圖 1

圖 2

?

創(chuàng)建新骨骼并對(duì)圖片進(jìn)行綁定,再綁定到相應(yīng)父骨骼上,得到新的角色外形:

圖 3

之后更新英雄角色每個(gè)動(dòng)作的角色外貌,如下圖奔跑動(dòng)畫:

圖 4

?

添加自制防御動(dòng)畫,如下圖所示:

圖 5

最后給每個(gè)動(dòng)作的最后一幀中的某個(gè)部位層添加一個(gè)“動(dòng)作名_end”的幀事件。如下圖添加攻擊動(dòng)作的幀事件:

圖 6

?

導(dǎo)出文件后替換掉源代碼中英雄文件,運(yùn)行程序,發(fā)現(xiàn)英雄外貌成功改變了:

圖 7

?

2.增加英雄defend動(dòng)作,記錄成功/失敗次數(shù),增加計(jì)分板功能。

?

在cocostudio中已制作了“防御”defend的動(dòng)畫,接下來只要將防御按鈕和動(dòng)作加到游戲中去就行。如下為AnimationScene.cpp文件中按鈕代碼:

圖 9

圖 10

為區(qū)分攻擊和防御鍵,另其分別使用兩張不同的按鈕照片。其中,攻擊按鈕為紅色,防御按鈕為藍(lán)色:

圖 11

枚舉類型中添加了防御DEFEND后,英雄類文件Hero中,簡單模仿攻擊方式的代碼寫一個(gè)防御方式,使點(diǎn)擊防御按鈕后實(shí)現(xiàn)防御功能,如下圖所示:

圖 12

關(guān)于防御功能的代碼及其相關(guān)完善,我將在后文的第5部分再詳細(xì)說明。

?

增加計(jì)分板:

重新新建一個(gè)文件SaveScore (.h和.cpp):

SavaScore.h

圖 13

SavaScore.cpp

圖 14

?

把SaveScore.h頭文件導(dǎo)入AnimationScene.h文件中被其引用。 SaveScore文件的功能為存儲(chǔ)英雄和怪物的比分,heroScore為英雄得分,enemyScore為敵人得分,剛開始都為0。這種做法好處在于,可在AnimationScene文件中直接對(duì)heroScore和enemyScore進(jìn)行操作,在AnimationScene場(chǎng)景被刷新后,計(jì)分值也不會(huì)改變,直接調(diào)用即可。

計(jì)分板代碼:

圖 15

update函數(shù)中不斷調(diào)用judge函數(shù),根據(jù)角色的血量來判斷輸贏,代碼為:

圖 16

圖 17

當(dāng)每輪游戲結(jié)束時(shí)(還沒到最終輸贏),需要刷新當(dāng)前場(chǎng)景,這里用scheduleOnce的方式調(diào)用了restart函數(shù),該函數(shù)里執(zhí)行的代碼可刷新場(chǎng)景。由于一輪游戲結(jié)束后場(chǎng)景不會(huì)被馬上刷新,而是在等待幾秒中后才刷新,所以這里的scheduleOnce對(duì)選擇器選擇的函數(shù)的執(zhí)行是在3秒后。

restart代碼:

圖 18

其中,場(chǎng)景過渡使用了部落格特效,持續(xù)1.2s 。

?

3.云朵移動(dòng)

尋找或自行扣掉一張沒有背景的云朵的png圖片,替換掉資源原有的cloud.png圖片 。

圖 19

AnimationScene.cpp初始化時(shí)創(chuàng)建3朵云,位置設(shè)置為不同,代碼較簡單,不顯示。

再在update函數(shù)中不斷修正其x軸方向位置,每朵云的位移距離不同。當(dāng)云朵移動(dòng)到鏡頭的一端看不見時(shí),在修正其位置到屏幕另一端,這樣就能得到循環(huán)播放的3朵云。

以1號(hào)云朵的位移代碼為例,其余類似:

圖 20

運(yùn)行效果圖:

圖 21

?

4.BUG修正

教材提供的示例代碼有許許多多的bug,主要原因是代碼邏輯寫得不好,這一部分花了大量的時(shí)間去Debug來修正。終于解決了游戲中存在的目前能找到的所有Bug,令游戲能正確且流暢的運(yùn)行起來。

由于游戲bug太多,下面根據(jù)解決方法的不同,總結(jié)為4類Bug:

  • 按攻擊鍵除了能控制英雄的攻擊動(dòng)作,也能控制怪物的攻擊動(dòng)作。
  • SMITTEN顫抖/硬直動(dòng)作沒有執(zhí)行、ATTACK動(dòng)作的動(dòng)畫可被打斷、角色被擊中后會(huì)原地卡在STAND或RUN動(dòng)作中執(zhí)行不了任何操作 ?等一系列稀奇古怪的動(dòng)作。
  • 莫名其妙連續(xù)多次扣血(不是指暴擊),在解決②的bug后,容易發(fā)現(xiàn)當(dāng)角色砍中另一角色時(shí),會(huì)繼續(xù)不斷使用attack。
  • 角色在奇怪的地方被砍中,或砍不到角色。

?

下面修正上述bug:

  • 攻擊鍵也能控制怪物攻擊。

????注釋掉或刪掉AnimationScene.cpp文件中的attackCallback函數(shù)中的紅框中代碼即可:

圖 22

?

  • SMITTEN動(dòng)作不執(zhí)行,被砍后不能操作,attack動(dòng)作被打斷 等奇怪舉動(dòng)的bug。

這個(gè)bug為該程序中最主要的bug,以英雄Hero為例,問題主要出現(xiàn)在下面三個(gè)地方:

  • AnimationScene.cpp中的update函數(shù)中的:
  • 圖 23

  • Hero.cpp中的play函數(shù):
  • 圖 24

  • Hero.cpp中的整個(gè)update函數(shù)(代碼太長,截取一部分)
  • 圖 25

    圖 26

    ?

    分析bug原因:

    可見,1)根據(jù)搖桿的操作情況,調(diào)用2)的Hero中play函數(shù),而3)能檢測(cè)Hero的狀態(tài),執(zhí)行動(dòng)作。

    因?yàn)?)在update函數(shù)中;2)被1)調(diào)用;3)是update函數(shù)。 所以理論上1)2)3)都是一直在運(yùn)作中的,沒有固定的先后順序。因此,由于不能確定運(yùn)作順序(除了 2)會(huì)在1)后運(yùn)行),導(dǎo)致程序容易出錯(cuò)。

    ?

    舉例:

    當(dāng)hero被攻擊,Hero的play函數(shù)會(huì)被傳入枚舉類型SMITTEN作為參數(shù),根據(jù)play代碼可知,此時(shí)受傷狀態(tài)變量m_ishurt會(huì)變?yōu)閠rue,當(dāng)前角色狀態(tài)m_state會(huì)被賦值為SMITTEN。 ?

    理論上來說,下一步該執(zhí)行Hero中的update函數(shù),判斷并執(zhí)行SMITTEN動(dòng)作了才對(duì)。 然而,這里也有可能在執(zhí)行Hero的update函數(shù)之前,先執(zhí)行了AnimationScene的update函數(shù)。

    如果先執(zhí)行了AnimationScene的update函數(shù),那么1)的“控制角色移動(dòng)”的代碼段就先被執(zhí)行了,如果此時(shí)沒有動(dòng)搖桿,那么枚舉類型STAND將作為Hero的play函數(shù)的參數(shù)傳進(jìn)去,之后就會(huì)重新賦值給m_state,SMITTEN狀態(tài)就會(huì)被STAND狀態(tài)給覆蓋掉了。

    此時(shí),m_state的值為STAND,而m_ishurt的狀態(tài)依然是true(因?yàn)镾MITTEN動(dòng)作沒有被執(zhí)行)。 再進(jìn)入Hero的update函數(shù)時(shí),由于m_ishurt也是各個(gè)動(dòng)作是否該執(zhí)行的判斷依據(jù),當(dāng)m_ishurt == true時(shí),這些動(dòng)作都不會(huì)被執(zhí)行。

    因此,當(dāng)hero被攻擊后,hero的操作都將失效。

    ?

    ?

    根據(jù)上面分析,想要解決這個(gè)bug必須要保證兩個(gè)前提(暫不討論DEFEND防御)

  • 狀態(tài)m_state一旦被改變后,只有執(zhí)行完了該動(dòng)作(ATTACK和SMITTEN)后,才能再次改變狀態(tài)m_state。
  • ATTACK和SMITTEN對(duì)應(yīng)動(dòng)作在執(zhí)行中時(shí),一定要運(yùn)行到最后一幀,不能被打斷。
  • 解決上述1)和2):

    ????1)在Hero.h中聲明新的布爾類型私有變量actionFlag,其作用為 ?當(dāng)m_state被賦值為ATTACK或SMITTEN時(shí),actionFlag被賦值為true,當(dāng)其為true時(shí),m_state不能被再改變,只有在ATTACK和SMITTEN動(dòng)畫運(yùn)行到最后一幀時(shí),actionFlag變?yōu)閒alse,此時(shí)m_state允許被賦值。

    修改相關(guān)代碼:

    圖 27

    圖 28

    ?

    ????2)研究源代碼中attack相關(guān)函數(shù),發(fā)現(xiàn)Hero中的m_isAttack的作用為判斷hero是否“正在攻擊”,這里指的是“動(dòng)作”而不是“狀態(tài)”。通過這一變量,在動(dòng)作執(zhí)行時(shí)(動(dòng)畫播放時(shí))才賦值為true,在最后一幀播放完了再賦值為false。把該變量作為動(dòng)作執(zhí)行的判斷依據(jù),能有效地控制并防止動(dòng)作的被打斷以及持續(xù)進(jìn)行(譬如一直點(diǎn)擊攻擊鍵,攻擊動(dòng)作不斷被打斷并重新執(zhí)行,只播放前幾幀);

    模仿m_isAttack變量,把m_ishurt變量的意義從原來的“受傷狀態(tài)”更改為“受傷動(dòng)作”。

    同時(shí),在監(jiān)聽幀事件的函數(shù)中,要在動(dòng)作執(zhí)行完后加入play(STAND)的代碼,防止其帶著原來的m_state先執(zhí)行Hero的update函數(shù)又引起什么奇怪的操作。

    模仿著更改代碼:

    圖 29

    圖 30

    ?

    ????同理修改Enemy的代碼即可。

    ?

    ?

    • 莫名其妙連續(xù)多次扣血(不是指暴擊),在解決②的bug后,容易發(fā)現(xiàn)當(dāng)角色砍中另一角色時(shí),會(huì)繼續(xù)不斷使用attack。

    查看碰撞檢測(cè)文件MyContactListener.cpp,查看其update函數(shù):

    圖 31

    以敵人攻擊英雄為例,關(guān)鍵代碼部分放大↓:

    圖 32

    分析:

    由上面代碼可知,當(dāng)其他條件滿足的前提下,Enemy的m_isAttack變量為true時(shí),表示此時(shí)敵人正在執(zhí)行攻擊動(dòng)作,if滿足條件,執(zhí)行Hero的hurt函數(shù),hero受傷掉血。然后Enemy執(zhí)行setAttack(false)把其m_isAttack置為false。

    然而,當(dāng)m_isAttack置為false后,在Enemy中,會(huì)把其視為攻擊動(dòng)作已經(jīng)結(jié)束,在m_state還是ATTACK時(shí),會(huì)把m_isAttack==false作為再次執(zhí)行攻擊動(dòng)作的判斷依據(jù)。而檢測(cè)碰撞文件的update函數(shù)又會(huì)很快的被再次執(zhí)行,m_enemy->isAttack()又會(huì)被視為true……如此地連續(xù)執(zhí)行,可能會(huì)造成角色的連續(xù)多次掉血,或者角色一旦攻擊到另一角色時(shí),會(huì)不斷地執(zhí)行攻擊動(dòng)作。

    ?

    解決:

    通過上述分析,我們了解到,解決問題的關(guān)鍵點(diǎn)在于不能在檢測(cè)碰撞中執(zhí)行m_enemy->setAttack(false)來改變破壞Enemy的攻擊動(dòng)作。

    綜上,我們保留其思想,但是不改變m_isAttack的值,為角色引入一個(gè)新的私有變量attackHurtFlag,表示被攻擊傷到傷害的標(biāo)志,增加set和get方法。以enemy攻擊hero為例,關(guān)鍵代碼為:

    圖 33

    ???

    ?Hero的update函數(shù)中:

    圖 34

    ?

    • 角色在奇怪的地方被砍中,或砍不到角色。

    ????觀察碰撞檢測(cè)文件MyContactListener.cpp,查看其update函數(shù)中enemy攻擊hero部分:

    圖 35

    分析:

    發(fā)現(xiàn)其碰撞檢測(cè)的基本原理為:為enemy的ax層(即enemy的斧子部件)添加2個(gè)檢測(cè)點(diǎn),再根據(jù)hero的位置創(chuàng)建一個(gè)矩形。當(dāng)enemy為攻擊狀態(tài),并且其斧子的2個(gè)檢測(cè)點(diǎn)在hero的矩形范圍內(nèi)時(shí),即為實(shí)現(xiàn)碰撞。

    因此,這里該如何創(chuàng)建矩形成為關(guān)鍵。

    分析Rect方法的參數(shù),其第1個(gè)參數(shù)為矩形左下角的x坐標(biāo),第2個(gè)參數(shù)為矩形左下角的y坐標(biāo),第3個(gè)參數(shù)為矩形的寬,第4個(gè)參數(shù)為矩形的高。

    結(jié)合游戲運(yùn)行圖來分析:

    假設(shè)在使用cocoStudio Animation時(shí),角色的中心點(diǎn)在身體的中心點(diǎn),隨意創(chuàng)建一個(gè)矩形,則有:

    圖 36

    假設(shè)還是同一程序,當(dāng)hero轉(zhuǎn)身后,其矩形不會(huì)根據(jù)角色的轉(zhuǎn)身而左右顛倒,如下圖所示:

    圖 37

    由上面兩張圖可知道,創(chuàng)建矩形時(shí),寬(即x軸)的中間位置的x坐標(biāo)最好落在角色中心點(diǎn)的x坐標(biāo)上。只有這樣,hero無論轉(zhuǎn)身與否,其前后的被攻擊的判定范圍都是一樣的,這樣才不會(huì)出現(xiàn)奇怪的“有時(shí)能砍到,有時(shí)又砍不到”的奇怪現(xiàn)象。

    最后只要不斷調(diào)整矩形的寬度即可(即調(diào)整第1個(gè)參數(shù)和第3個(gè)參數(shù))。而矩形的高度只要足以涵蓋住角色即可(即調(diào)整第2個(gè)參數(shù)和第4個(gè)參數(shù))。

    ?

    最終矩形參數(shù)修改為:

    圖 38

    圖 39

    ?

    5.防御機(jī)制

    防御機(jī)制設(shè)定為:

    • 點(diǎn)擊藍(lán)色按鈕進(jìn)入防御狀態(tài)
    • 防御狀態(tài)下,角色最后會(huì)保持防御動(dòng)畫的最后一幀
    • 防御狀態(tài)下能減少一段暴擊及暴擊傷害,受到的傷害值以藍(lán)色數(shù)

    值顯示

    • 防御狀態(tài)下,操作搖桿,點(diǎn)擊攻擊按鈕,能打斷防御狀態(tài),并執(zhí)行其他相應(yīng)動(dòng)作
    • 防御狀態(tài)下,再點(diǎn)擊一次防御按鈕可以取消防御狀態(tài)

    ?

    根據(jù)以上設(shè)定,編寫代碼:

    Hero中的update:

    圖 40

    并為每個(gè)動(dòng)作的執(zhí)行加上m_isDefend=false,以STAND站立動(dòng)作為例:

    圖 41

    Hero的showBloodTips函數(shù) “減少暴擊數(shù)和暴擊傷害”以及“防御狀態(tài)下傷害值為藍(lán)色”:

    圖 42

    圖 43

    運(yùn)行圖:

    圖 44

    6.AI設(shè)計(jì)

    觀察AI文件AIManager的原代碼,發(fā)現(xiàn)怪物AI僅僅是根據(jù)一套固有的動(dòng)作反復(fù)執(zhí)行而已,關(guān)鍵代碼為:

    圖 45

    分析上面代碼,可知這個(gè)AI并不智能。并且根據(jù)上面的執(zhí)行結(jié)果,可知moveLeft的動(dòng)作持續(xù)最久,因此游戲中的后半段,敵人emeny會(huì)一直往左邊界“推墻”,moveRight的持續(xù)時(shí)間太短,因此無法往右半邊回來。

    ?

    因此,重新編寫一個(gè)AI代碼文件,使其能夠根據(jù)hero的位置,實(shí)現(xiàn)自動(dòng)跟蹤,在適宜的位置進(jìn)行攻擊的功能。

    編寫后的關(guān)鍵代碼為(以hero在enemy的左方為例):

    圖 46

    hero在enemy的右方時(shí)也同理可得,而當(dāng)hero和enemy位置相同時(shí),enemy直接攻擊即可。

    ?

    由上述得到了敵人AI的最佳方案,但是如果直接把bestAI函數(shù)放到update函數(shù)不斷調(diào)用的話,會(huì)發(fā)現(xiàn)游戲會(huì)變得非常困難,幾乎沒有贏的可能性。并且,敵人enemy的行動(dòng)模式不夠隨機(jī)也反而顯得不是那么的“智能”。因此,在此基礎(chǔ)上減少bestAI的執(zhí)行次數(shù),插入隨機(jī)行動(dòng)模式,并適當(dāng)?shù)販p少攻擊頻率,讓游戲變得更簡單,令A(yù)I變得更隨機(jī)些。

    修改后的代碼為:

    圖 47

    bestAI()中以hero在enemy的左方為例:

    圖 48

    AI的隨機(jī)方案:

    圖 49

    通過上述操作后,敵人AI能夠保持在最佳行動(dòng)方案的基礎(chǔ)上,也進(jìn)行些許隨機(jī)行動(dòng)了。

    7.其余Label顯示細(xì)節(jié)

    ???① 每輪游戲開始時(shí)都會(huì)出現(xiàn)“Round X”,X表示游戲的第幾輪,1.5s后消失(移除)

    圖 50

    ???② 每一小輪游戲結(jié)束后,都會(huì)在對(duì)應(yīng)角色的血條下方顯示“win”字樣

    圖 51

    ③ 場(chǎng)景有部落格特效過渡

    ④ 游戲結(jié)束后會(huì)顯示玩家的輸贏,贏了顯示“YOU WIN!”;輸了顯示“YOU LOSE!”

    圖 52

    總結(jié)

    以上是生活随笔為你收集整理的学习3 二维游戏动画合成(侠客行)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。