上一講完成了基本項目的創(chuàng)建翎苫,這一講會帶著大家快速的實現(xiàn)角色之間的交互兔院,Godot中角色之間的交互使用信號來完成姿鸿。
一谆吴、角色之間的簡單交互
按照上一篇文章創(chuàng)建一個新的項目,添加assets和scene兩個文件夾苛预,在assets中加入一些圖片資源句狼。
首先創(chuàng)建一個新的2D場景,在2D場景中添加Sprite和一個Button热某。
在Sprite中添加相應(yīng)的代碼腻菇,讓角色開始運動
extends Sprite
var flag = false
func _process(delta):
if flag :
rotation += PI/2 * delta
設(shè)置了一個flag來控制角色的運動,之后需要為按鈕添加相應(yīng)的信號
添加成功之后有如下一些顯示
以上代碼代表著只要按下按鈕昔馋,之后就發(fā)_on_Button_pressed()
筹吐,這個信號是傳遞給這個節(jié)點的Sprite,在這個信號里面修改了flag的值秘遏。此時只要點擊按鈕丘薛,就可以角色就開始運動了。也可以直接使用set_process方法來進行處理垄提,此時就可以不需要flag標(biāo)簽了榔袋。
extends Sprite
#var flag = false
func _process(delta):
# if flag :
rotation += PI/2 * delta
func _on_Button_pressed():
# print("ok")
# flag = !flag
set_process(!is_processing())
二周拐、實現(xiàn)角色之間的復(fù)雜交互
下面將會實現(xiàn)一個Tank和齒輪之間的交互铡俐,通過這個例子讓我一起來體會一下信號的特點。
-
Saw角色的創(chuàng)建
為了進行碰撞妥粟,角色就不能僅僅只是Sprite了审丘,但是依然需要Sprite,通過Sprite可以插入Texture(圖片素材)勾给。按照流程添加角色的Scene(名稱是Saw)滩报,此時要添加碰撞檢測锅知,需要選擇Area2D。這個是帶碰撞檢測節(jié)點需要添加Sprite和CollistionShape2D并且為后者添加碰撞區(qū)域脓钾。
為Saw添加saw.gd的腳本代碼
extends Area2D
#export導(dǎo)出的變量可以在配置項中設(shè)置
export var max_dis = 100 #最大的距離售睹,默認(rèn)是100
export var move_dir = "h" #轉(zhuǎn)動的方向是水平 v是垂直
var dis = 0 #記錄移動的距離
var dir = 1 #移動的方向
func _process(delta):
dis += dir * 1
if dis >= max_dis*delta or dis <= -1 * max_dis*delta:
dir *= -1
if move_dir == "h":
position.x += 200 * dir * delta
if move_dir == "v":
position.y += 200 * dir * delta
rotation += -PI * delta #移動的過程中不斷進行旋轉(zhuǎn)。
以上代碼中創(chuàng)建了兩個變量max_dis和move_dir可训,一個用來存儲最大的移動距離昌妹,另一個用來確定移動方向,是水平還是垂直(在后續(xù)講解完成向量之后握截,會有更好的控制方法)飞崖。這兩個變量都設(shè)置為export,這表示可以在Saw的屬性欄進行值的修改谨胞。代碼的基本思路是固歪,讓Saw不斷反復(fù)移動,如果移動距離大于max_dis或者小于-max_dis胯努,就變向牢裳,相當(dāng)于修改dir的值,在移動端過程中不斷的旋轉(zhuǎn)康聂。
- 創(chuàng)建一個可以上下移動的角色
按照同樣一種方式創(chuàng)建一個Area2D贰健,之后添加兩個節(jié)點(Sprite和CollisionShape2D),Sprite為了加入材質(zhì)恬汁,CollisionShape2D加入碰撞檢測區(qū)域
var speed = 200
func _process(delta):
if Input.is_action_pressed("ui_up"):
position.y -= speed*delta
if Input.is_action_pressed("ui_down"):
position.y += speed*delta
if Input.is_action_pressed("ui_left"):
position.x -= speed*delta
if Input.is_action_pressed("ui_right"):
position.x += speed*delta
- 將角色添加到舞臺
啟動游戲之后伶椿,Saw開始運行,角色也開始根據(jù)鍵盤控制進行移動氓侧,但是角色現(xiàn)在和電鋸接觸之后沒有任何反應(yīng)脊另,下一步就要添加碰撞檢測。
- 添加碰撞檢測
只要是Area2D的角色都可以進行碰撞檢測约巷,碰撞檢測需要使用到信號(Signal)偎痛,具體的操作流程如下所示:
area_entered就是我們需要使用的信號,接下來独郎,實現(xiàn)的效果是當(dāng)tank碰到saw之后踩麦,有個生命,生命會減少氓癌。所以首先為Tank增加一個life的變量谓谦。
var life = 100
此時如果把信號添加在其中的一個Saw上會有一些問題,如圖所示
運行發(fā)現(xiàn)贪婉,只有第一個Saw節(jié)點能夠出發(fā)信號反粥。其他節(jié)點都沒有辦法觸發(fā)。這樣就需要為每個節(jié)點都添加。所以信號必須在tank上添加才顿,讓Saw節(jié)點來接收信號莫湘,此時就可以正常運行,但是代碼卻是在Saw中編寫郑气,這樣就需要在Saw中獲得Tank節(jié)點幅垮。
具體的代碼如下所示
func _on_Tank_area_entered(area):
# print("hit")
var tankNode = get_node("../Tank")
# print(tankNode.life)
if tankNode.life >= 0:
tankNode.life -= 10
print(tankNode.life)
需要強調(diào)一下,此處獲取節(jié)點使用了get_node(../Tank)
尾组,../
表示的是上一級路徑军洼,這種方式是非常不合理的一種獲取節(jié)點方法,在實際的應(yīng)用中都不會使用演怎,但是由于本章節(jié)的內(nèi)容只是讓大家概覽一下流程匕争,所以先使用這種不合理的方案,在后續(xù)的內(nèi)容中會更新更合理的處理方案爷耀。
接下來甘桑,坦克受傷的代碼客觀來說應(yīng)該在tank中編寫更合理一些,所以可以在坦克中創(chuàng)建一個方法歹叮,injured方法跑杭。
#Tank.gd中添加代碼
func injured(lost_life):
life -= lost_life
if life <= 0:
life = 0
print(life)
改造Saw中的代碼
func _on_Tank_area_entered(area):
var tankNode = get_node("../Tank")
# print(tankNode.life)
# if tankNode.life >= 0:
# tankNode.life -= 10
# print(tankNode.life)
tankNode.injured(10)#讓tank損失10點生命
接著來實現(xiàn)Tank受傷之后,有一些反饋咆耿,改變一下顏色德谅。首先為tank節(jié)點添加一個動畫。
點擊 Add Track添加一個軌道萨螺,選擇Property Track窄做,選擇Sprite節(jié)點,之后添加modulate慰技,通過這個可以設(shè)置Sprite的基本屬性椭盏。之后將幀調(diào)整為0.4,意味著可以設(shè)置4幀的動畫吻商。
modulate可以調(diào)整節(jié)點的顏色和透明度掏颊,之后添加五個關(guān)鍵幀,分別在0.1和0.3部分設(shè)置值即可艾帐。
播放之后會發(fā)現(xiàn)tank已經(jīng)開始閃動了乌叶,之后在tank的受傷的代碼中添加這個播放效果即可。
func injured(lost_life):
life -= lost_life
if life <= 0:
life = 0
# print(life)
get_node("AnimationPlayer").play("injured")
最后添加一個血條柒爸,血條需要使用TexureProcess節(jié)點准浴,所以先創(chuàng)建一個新的lifebar的scene,之后在assets中添加血條的圖片
下一步就是當(dāng)收到傷害的時候通知血條減少值即可,此時需要創(chuàng)建一個自定義的信號來進行處理揍鸟。
signal life_change(final_life)
在Main場景中兄裂,選中Tank,之后會發(fā)現(xiàn)多了一個信號life_change阳藻,之后將Lifebar拖入到主場景中晰奖,這個信號連接到Lifebar。連接Lifebar之前需要為Lifebar增加相應(yīng)的gdscript代碼
extends TextureProgress
func _on_Tank_life_change(final_life):
value = final_life
最后一步就是在Tank中發(fā)信號
func injured(lost_life):
life -= lost_life
if life <= 0:
life = 0
# print(life)
get_node("AnimationPlayer").play("injured")
emit_signal("life_change",life)#發(fā)信號life_change腥泥,傳入最終的值
實例中匾南,各個節(jié)點的代碼
#Tank
extends Area2D
var speed = 200
var life = 100
signal life_change(final_life)
func _ready():
position.x = 500
position.y = 200
func _process(delta):
if Input.is_action_pressed("ui_left"):
position.x -= speed * delta
if Input.is_action_pressed("ui_right"):
position.x += speed * delta
if Input.is_action_pressed("ui_up"):
position.y -= speed * delta
if Input.is_action_pressed("ui_down"):
position.y += speed * delta
func injured(lost_life):
life -= lost_life
if life <= 0:
life = 0
# print(life)
get_node("AnimationPlayer").play("injured")
emit_signal("life_change",life)#發(fā)信號life_change,傳入最終的值
Saw的代碼
extends Area2D
#export導(dǎo)出的變量可以在配置項中設(shè)置
export var max_dis = 100 #最大的距離蛔外,默認(rèn)是100
export var move_dir = "h" #轉(zhuǎn)動的方向是水平 v是垂直
var dis = 0 #記錄移動的距離
var dir = 1 #移動的方向
func _process(delta):
dis += dir * 1
if dis >= max_dis or dis <= -1 * max_dis:
dir *= -1
if move_dir == "h":
position.x += 200 * dir * delta
if move_dir == "v":
position.y += 200 * dir * delta
rotation += -PI * delta
func _on_Tank_area_entered(area):
# print("hit")
var tankNode = get_node("../Tank")
# print(tankNode.life)
# if tankNode.life >= 0:
# tankNode.life -= 10
# print(tankNode.life)
tankNode.injured(10)#讓tank損失10點生命
Lifebar的代碼
extends TextureProgress
func _on_Tank_life_change(final_life):
value = final_life
通過這個案例蛆楞,可以讓大家感受得到Godot編寫一個簡單游戲的流程,下一講夹厌,將會專門介紹向量數(shù)學(xué)方面的知識豹爹。