Construct 2教學-第7節
HJ Online Learning Center
APP開發線上教學
  • Register

Construct 2 教學-第7節

第7節-進階主角設計(下)

 

大家好,我是傅老師。歡迎來到我的Construct 2教學。

上一節我們實作了蛋蛋老師的子彈,讓她可以用子彈進行遠距離攻擊。這一節我們來多加一個近距離揮棒攻擊模式給她。這樣她就可以遠近通吃,左右開弓囉~

本節重點在於<Pin>、<Rotate>行為特性的應用,血量判斷與血表的製作,音樂音效的加入。

 
 
 
 


 

7-1 為主角新增swing狀態

專案預處理

請下載本節的Sprite包:

http://www.memoryabc.com/c2_example/L7_sprite.zip

1. 比照2-5節所介紹的方式,將<egg_swing>目錄內的動畫幀新增給[Player],命名為"swing"動畫組。(請記得裁切、設置參數、修改原點)

新增swing動畫組

2. 新增球棒。新增一個<Sprite>物件命名為[w1](意指weapon1),將Sprite包內<weapon>目錄的<stick.png>導入,原點設置在正左方 (0,9)位置。將[w1]放置於佈局外側,並為其增加<Destroy outside layout>行為特性,這樣遊戲開始他就會自動被刪掉,待我們揮 棒時再新增即可。

新增球棒

3. 新增血量表符號。新增一個<Tiled background>物件命名為[heart],將Sprite包內<heart>目錄的<heart.png>導入,先放到佈局外側。

新增血量符號

 

新增swing狀態

在5-1中我們為蛋蛋老師設計了attack狀態,可以讓蛋蛋老師發射子彈。實際遊玩時發現,如果能夠再加一個近身攻擊的狀態就更有趣了。所以現在我們仿造 attack的內容來新增一個swing(揮棒)狀態,看到attack狀態是位於第34條,首先先複製一份第34條事件(可先收合第34條事件,方便檢 視):

複製指令

複製完畢後調整新增的第46條事件,將該事件的條件式改為state = "swing"。改完展開事件,只留下第47、48條事件,其他子事件全部砍掉。

刪除部份指令

接下來修改swing狀態:

1. 第47條指令原本是用來顯示投擲動畫的,現在得改成顯示新的swing揮棒動畫,另外還要為swing添加球棒(可參考38、39條事件加入子彈的方 式)。

2. 第48條代表近身攻擊時被敵人打到,此時應該要把手上的棒子刪除掉。

3. 新增第49條,偵測當動畫撥到第9幀時,把蛋蛋老師從"swing"狀態切換回"move"狀態。

4. 接下來加入球棒。:

 

Eventsheet1
->47 Player Is playing Animation:"swing"
  Player Set animation Animation:"swing"
From:beginning
System Create object Object to create:[w1]
Layer:"game"
X:Player.ImagePointX("Origin")
Y:Player.ImagePointY("Origin")
w1 Set angle Angle:-90
->48 Player Is overlapping another object Object:[E1]
  Player Set value Instance variable:state
Value:"hit"
  w1 Destroy  
->49 Player Compare frame Comparison:<= Equal to>
Number:9
  w1 Destroy  
Player Set value Instance variable:state
Value:"move"

完成如下圖:

修改事件表



5. 最後,上次是以偵測<shift>鍵是否被按下來切換蛋蛋老師的"attack"狀態,這次我們將近身攻擊鍵設為</>,這個鍵應該在右<shift>鍵的隔壁。找到第 32條將其複製於第33條,改成下面的樣子:

Eventsheet1
->32 Keyboard Key is down Key:<shift>
  Player Set value Instance variable:state
Value:attack
->33 Keyboard Key is down Key:</>
  Player Set value Instance variable:state
Value:swing

 

綁定近身攻擊鍵

修改事件表

 

完成。按下<F4>預覽,使用</>鍵攻擊看看。

沒有揮舞的感覺啊~

疑?蛋蛋老師動作是很確實,但是球棒沒有揮舞的感覺啊~別急別急,接下來就讓我們將揮舞的感覺細緻地實作出來吧!


 

7-2 以<Rotate>製作揮舞動感

增加<Rotate>行為 特 性

我們期望蛋蛋老師揮舞球棒時,球棒應當要在空中以圓弧狀軌跡畫過去,這個可以透過為[w1]增加<Rotate>行為特效來達成。於專案區點擊選取 [w1],點選左方參數區Add behavior連結,為[w1]加入<Rotate>行為特性。<Rotate>的參數意義如下:

參 數 功 能
Speed 旋 轉速度。正值代表順時針方向。
Acceleration 旋轉加速度。正值代表順時針方向

將[w1]<Rotate>的速度設為500:

棒子會旋轉了~

新增w1錨點

棒子會旋轉了~可是持棒的位置有問題,棒子應該要黏在蛋蛋老師的手腕附近才對。好,讓我們為 swing動畫組新增一個手腕附近的錨點。比照4-2的步驟,為swing新增一個叫"w1"的錨點,放在(49,78)這個位置。記得加完後要選<Apply to whole animation>,這樣才會將這個錨點套用到swing的每一幀。

新增w1錨點

加上錨點後對以下事件進行修改。

 

Eventsheet1
#47 Player Compare instance variable Instance variable:state
Comparison:<= Equal to>
Value:"swing"
  w1 Set position X:Player.ImagePointX("w1")
Y:Player.ImagePointY("w1")
->48 Player Is playing Animation:"swing"
  Player Set animation Animation:"swing"
From:beginning
System Create object Object to create:[w1]
Layer:"game"
X:Player.ImagePointX("w1")
Y:Player.ImagePointY("w1")
w1 Set angle Angle:-90
->49 Player Is overlapping another object Object:[E1]
  Player Set value Instance variable:state
Value:"hit"
  w1 Destroy  
->50 Player Compare frame Comparison:<= Equal to>
Number:9
  w1 Destroy  
Player Set value Instance variable:state
Value:"move"

在第47條後面我們補上了一個動作,每次進47條就將[w1]的位置放到[Player]的w1錨點上,這樣棒子就會黏在蛋蛋老師手上了。同樣的,第48條 內create[w1]的動作,也要把其create座標設在[Player]的w1錨點上(此處在上表中以紅色表示,請務必看清並做對應修改)。修改完如 下:

修改事件

改好後按<F4>預覽,Good~現在棒子有揮舞的感覺了~但是揮一揮後發現有兩個問題:

1. 無法往左揮舞,

2. 純然只有旋轉,這樣的揮動很生硬。

太簡單了~底下我們來快速地修正吧。

 


 

7-3 修改swing效果

項目1 解決無法往左揮舞的問題

球棒是在第48條事件擺上去的,只需要在其內判斷蛋蛋老師面對方向,並將球棒的旋轉方向逆向就可以了。逆轉的方式也很簡單,就是將目前w1旋轉的速度乘上 -1即可。目前w1的旋轉速度可由w1.Rotate.Speed這個表達示讀得。請新增底下的第49條事件:

Eventsheet1
->48 Player Is playing Animation:"swing"
  Player Set animation Animation:"swing"
From:beginning
System Create object Object to create:[w1]
Layer:"game"
X:Player.ImagePointX("w1")
Y:Player.ImagePointY("w1")
w1 Set angle Angle:-90
-->49
Player
Is mirrored


w1
(Rotate)Set spped
Speed:w1.Rotate.Speed * -1

修改事件

項目2 解決揮舞生硬的問 題

在真實世界揮棒的動作不是等速率的,揮棒快結束時應該會放慢,最後結尾時應該要反向旋轉收棒。我們假設收棒時刻是swing動畫的第5幀,在第5幀把旋轉速 度再次反向即可。此外,再第5幀把球棒挪到蛋蛋老師前方,這樣看起來也較為真實些。將以上收棒的動作加為第52條:

 

Eventsheet1
->52 Player Compare frame Comparison:<= Equal to>
Number:5
  w1 Move to object Where:<in front>
Object:[Player]
w1 (Rotate)Set speed Speed:-260
-->53 Player Is mirrored  
  w1 (Rotate)Set speed Speed:260

我們把收棒的速度設為260,另外增加53條是為了顧及面向左側時的收棒動作。

修改完成,對應事件表如下。

修改事件

按<F4>預覽,非常OK~接下來我們要給予棒子真正的殺傷力,讓小史嘗嘗棍棒的利害囉~

 



7-4 近身攻擊最後設定

結至目前為止,蛋蛋老師的揮舞已經有模有樣了,只是還沒有真正的殺傷力。為了要完成殺傷力,我們還有以下的項目要完成:

1. 設置球棒的攻擊力。

2. 偵測球棒與小史的碰撞,碰撞發生時依球棒攻擊力扣小史的生命值。

3. 球棒擊中小史時讓他稍做後退。

底下開始修改。

 

項 目1 設置球棒的攻擊力

設置攻擊力可比照6-3中為子彈添加att實件變數的做法,假設球棒的攻擊力是6,則我們可為[w1]新增一個初始值為6的實件變數att。

新增球棒攻擊力實件變數att

未來要讀取球棒攻擊力時,可以用w1.att讀得這個值。

 

項 目2 處理小史與球棒的碰撞

 

這一項可以完全比照6-3為小史插入dead判斷式的部份。請將以下事件加入為第59條事件(注意需與57條位置切齊):

Eventsheet1
#59 w1 On collision with another object Object:[E1]
  E1 (Timer)Start timer Duration:0.1
Type:<Once>
Tag:"flash"
習 題1
E1 Substract from Instance variable:<hp>
Value:w1.att
->60 E1 Compare instance variable Instance variable:hp
Comparison:<<= Less or equal>
Value:0
  E1 Set value Instance variable:<AI_mode>
Value:"dead"
  E1 (Timer)Stop timer Tag:"E1_AI"

大致上與之前子彈攻擊的指令類似,特別要注意的是扣血的時候要扣w1.att這個值(不要扣成b1.att,那是子彈的攻擊力)。Timer "E1_AI"是第4-4設計小史AI的時候所加入的,不明白的話請參閱該節。標註習題1之處請參考習題1,自行做出對應修正。

 

項 目3 小史被擊中時讓他稍做後退

如果小史被棒子打到沒有退後的話,那玩家可以趕快拼命揮棒,立刻打第二下。雖然這也是一種style,不過傅老師還是想設計讓小史有向後彈的感覺,最好還可 以微微向上彈起。這可以透過<Platform>行為特性的<Set vector X>以及<Set vector Y>來達成。但要注意兩點:

1. 小史的Max Speed值應該在100,這個值有點小,彈的不是很明顯。所以在後彈之前要先將Max Speed暫時拉大到600左右,等到閃爍兩次後再恢復到100。

2. 小史不知道自己後彈的方向是左還是右,得要看棒子是在他左方還是右方。棒子在左,他就要向右彈;棒子在右,他就要向左彈。這裡要透過一個特殊的表達式來完成: (A?B:C)。這個表達式會先檢查A是否邏輯上為真,一但為真整個表達式的值就等於B;反之若A為偽,則整個表達式的值就設為C。我們可以寫 500*((E1.X > w1.X)?1:-1),做為vectorX的值。

修改第59條,新增66條(與65切齊)如下:

Eventsheet1
#59 w1 On collision with another object Object:[E1]
  E1 (Timer)Start timer Duration:0.1
Type:<Once>
Tag:"flash"
習 題1
E1 Substract from Instance variable:<hp>
Value:w1.att
E1 (Platform)Set max speed Max speed:600
E1 (Platform)Set vector Y Vector Y:-250
E1 (Platform)Set vector X Vector X:500 * ((E1.X > w1.X) ? 1 : -1)
Eventsheet1
->66 E1 Compare instance variable Instance variable:flash_count
Comparison:<= Equal to>
Value:2
  E1 (Platform)Set max speed Max speed:100

完成!按<F4>預覽,現在蛋蛋老師可以近距離攻擊囉!呀呼~

(完工程式碼參考章末)

 



7-5 增加血表

增加血表

遊戲中,玩家的資訊通常會放在螢幕正上方,稱為HUD(Head Up Display)。這裡我們來簡單做一個蛋蛋老師的血表。

選取UI層,新增一個大小為64x64的Sprite物件,取名為[Hud_background],內容填滿黑色。新增完畢後修改其參數:位置 (560,32),大小(1472,128),不透明度50。把預處理時入的[heart]物件也做參數調整: 位置(48,28),大小(192,64), 把 [heart]的Z-order移到最上方。

HUD

 

為[Player]增加一個實件參數hp,初始值為6。以後蛋蛋老師誕生就有6點的生命值啦~

主角hp

被小史打到要扣血,每次hp扣1點算是合理的。當hp扣到小於等於0時,視同主角受攻擊死亡,切換到一個新的"dead"狀態(因為沒有要做什麼事情,可暫 時不實現此狀態)。但是,死亡前我們讓主角小跳一下,讓整件事不要發生的太突然。最後,小跳起來後要關掉使用者的輸入,並且讓蛋蛋老師受地心引力落下,掉出畫 面即視為本局結束。

綜合以上,找到hit狀態下第55條,修改55條並插入第56條(注意56條是55的子事件):

Eventsheet1
->55 Player Is playing Animation:"dead"
  Player Set animation Animation:"dead"
From:<beginning>
Player Substract from Instance variable:<hp>
Value:1
-->56 Player Compare instance variable Instance variable:hp
Comparison:<<= Less or equal>
Value:0
  Player Set value Instance variable:<state>
Value:"dead"
Player (Platform)Set ignoring input Input:<Start ignoring>
Player (Platform)Set vector Y Vector Y:-500
Player Set collisions enabled Collisions:<Disabled>

 

新增67條事件,視[Player]hp值動態調整血表長度。

Eventsheet1
#67 System Every tick  
  heart Set width Width:Player.hp * 64 / 2

完成後按<F4>預覽,Good~依原訂計劃修改完成!

(完工程式碼參考章末)

 



7-6 來點音樂吧(Audio)

這個遊戲打打殺殺很精采,但是沒有音樂好像就少了什麼東西...這節結束前大贈送,我們來加個音樂音效!

匯 入音樂音效檔

首先請至下列網址下載本節的音樂音效包:

http://www.memoryabc.com/c2_example/L7_audio.zip

下載完回到C2編輯器,到專案區以滑鼠右鍵點擊<Sound>音效目錄,選擇<Import sounds>將<e1_ouch3.wav>、<egg_ha2.wav>、<egg_ha5.wav>、<egg_ouch.wav>、<fight4_2.wav> 匯入到<Sound>目錄下。

匯入音效

C2會熱心的幫我們把wav檔轉成m4a以及ogg檔,點選<import>即開始轉檔。

轉檔

接著再來匯入音樂。到專案區以滑鼠右鍵點擊<Music>音樂目錄,選擇<Import sounds>將<13.Rolling.wav>匯入到<Music> 目錄下。一樣點選<import>後C2會自動轉檔。完成後會看到專案區的<Sound>、<Music>目錄下出現了許多可以在遊戲中撥放的音樂音效檔案。

音樂音效匯入完成

為 專案加入<Audio>物件。

以滑鼠左鍵雙擊佈局空白區,選擇<Audio>插件即可為專案添加[Audio]物件。[Audio]物件每個專案只能有一個,但他是全域物件,所以一但加 入後所有佈局都可透過他來放音樂。撥放的方法很簡單,只要使用[Audio]物件的<Play>動作即可,<Play>動作的參數如下:

參 數 功 能
Audio file 要 撥放的音檔,可從下拉選單來選擇。
Loop 是否循環撥放?設為looping即可循環撥放。
Volume 聲音大小,單位為dB。(每6分貝聲音振幅減半)
Tag(optional) 付予本次撥放一個標簽,方便以後暫停或是進一步操作。(不須進一步 操作者,本項可留空字串)

增加音效

找到適合撥放音效的程式位置,插入[Audio]的<Play>動作。比如說,小史的死亡音效<e1_ouch>適合加在第15條事件內,讓他一切 到"dead"狀態就放<e1_ouch>音效。請依下表將所有音效找到位置插入:

Eventsheet1
-->15 ... 中略...


  Audio Play Audio file:<e1_ouch3>
Loop:<not looping>
Volume:0
-->36 ... 中略...


  Audio Play Audio file:<egg_ha5>
Loop:<not looping>
Volume:0
-->48 ... 中略...


  Audio Play Audio file:<egg_ha2>
Loop:<not looping>
Volume:0
-->55 ... 中略...

  Audio Play Audio file:<egg_ouch>
Loop:<not looping>
Volume:0
#58 ... 中略...


  Audio Play Audio file:<fight4_2>
Loop:<not looping>
Volume:0
#60 ... 中略...


  Audio Play Audio file:<fight4_2>
Loop:<not looping>
Volume:0

增加背景音樂

背景音樂的撥放應該在遊戲進入佈局之時,可以使用[System]物件的<On start of layout>事件來攔截此時間點。讓我們新增第69條事件放在尾端。請注意,背景音樂必須循環撥放(looping)。

Eventsheet1
#69 System On start of layout  
  Audio Play Audio file:<13.Rolling>
Loop:<looping
Volume:0

按下<F4>預覽,哇!效果還不錯耶~太棒了,存檔休息一下囉!

煥然一新的遊戲

 



7-7 結語

在本節裡我們完成了主角的近身攻擊功能,做了一個簡單的HUD,加了音樂跟音效,整個遊戲主體已經完成80%了。接下來我們會在後面的章節把開頭畫面、計分 功 能做完,把遊戲發佈出去。

 



7-8 傅老師鼓勵你...

 

  1. 將w1.att改為0,對小史狂敲猛攻,會發現常會出現反應亂掉的狀況。像是閃爍不正常或是速度不正常。為什麼?怎麼解決?(提示在7-4節)
  2. 添加地形與敵人,增加關卡難度。

7-9 完工程式碼

code

code

code

code

code

code

code

code