備忘錄_20160105(定位)
修改
回首頁
程式 2022-12-31 23:52:56 1672501976 100
Godot 3.5 初體驗
Godot 3.5 初體驗
◎◎事件
●單一節點的程式 *.gd
宣告:signal 事件子
呼叫:emit_signal("事件子")
●使用方
若是透過 UI 介面的實體化,
"事件子"會出現在被實體化的那個節點的事件上,
再用 connect 與程式碼連結。
若是用程式碼來宣告實體化,
則開頭要先 export (PackedScene) var 場景甲,
並在使用方節點的 Inspector 把 *.tscn 從資料夾拖曳到變數 場景甲 上面
事件會以 func _on_場景甲_事件子() 出現在使用方節點的程式裡
◎◎變數
export (int) var 變數名稱丙
用export的變數,會出現在 Inspector/ScriptVariables裡面,可在UI介面中設定數值
Project/Project Settings...
Display/Window/Size/Width→480, Height→720
Display/Window/Stretch/Mode→2d, Aspect→keep
Rendering/2D/Snapping/Use GPU Pixel Snap→勾選On
------ 玩家
(Add/Create a New Node)→Area2D→Create,改名Player_area2d
Scene/Save Scene→Player_area2d.tscn→Save
(以後只要遇到有 Select Node 字眼,就是先點選其他空白處,再點選回來)
Select Node Player_area2d, click [Make sure the object's children are not selectable.]
Select Node Player_area2d, (Add/Create a New Node)→AnimatedSprite→Create
Select Node AnimatedSprite, Inspector/AnimatedSprite/Frames/New SpriteFrames
Select Node AnimatedSprite, 下方 Animations/New Animation 兩次
將三個 animation 分別改名為 run, idle, hurt
點選 run,從左方 FileSystem 把對應的 *.png 拖曳到右邊 Animation Frames 的方框中,修改 Animations/Speed 為 8 FPS。
點選 idle,從左方 FileSystem 把對應的 *.png 拖曳到右邊 Animation Frames 的方框中,修改 Animations/Speed 為 8 FPS。
點選 hurt,從左方 FileSystem 把對應的 *.png 拖曳到右邊 Animation Frames 的方框中,修改 Animations/Speed 為 8 FPS。
Select Node AnimatedSprite, Inspector/AnimatedSprite/Offset→x=0, y=-5 (為了置中而調整)
Select Node Player_area2d, (Add/Create a New Node)→CollisionShape2D→Create
Inspector/CollisionShape2D/Shape→New RectangleShape2D
Workspace/2D/Viewport/調整框框,包住 Player_area2d
Select Node Player_area2d, Scene/綠色加號(Attach a new or existing script to the selected node)→Player_area2d.gd→Create
●Begin-Player_area2d.gd
extends Area2D
export (int) var speed
var velocity = Vector2()
var screensize = Vector2(480, 720)
●End-Player_area2d.gd
Select Node Player_area2d, Inspector→Player_area2d/Script Variables/Speed→350
Select Node Player_area2d, Workspace/Script 增加一鍵盤處理的函數
●Begin-Player_area2d.gd
func get_input():
velocity = Vector2()
if Input.is_action_pressed("ui_left"):
velocity.x -= 1
if Input.is_action_pressed("ui_right"):
velocity.x += 1
if Input.is_action_pressed("ui_up"):
velocity.y -= 1
if Input.is_action_pressed("ui_down"):
velocity.x += 1
if velocity.length() > 0:
velocity = velocity.normalized() * speed
●End-Player_area2d.gd
增加一標準處理的函數
●Begin-Player_area2d.gd
func _process(delta):
get_input()
position += velocity * delta
position.x = clamp(position.x, 0, screensize.x)
position.y = clamp(position.y, 0, screensize.y)
# 可透過錢字號來操控子節點
if velocity.length() > 0:
$AnimatedSprite.animation = "run"
$AnimatedSprite.flip_h = velocity.x < 0
else:
$AnimatedSprite.animation = "idle"
●End-Player_area2d.gd
增加開始與結束函數
●Begin-Player_area2d.gd
func start(pos):
set_process(true) # 使本節點可以運作
position = pos
$AnimatedSprite.animation = "idle"
func die():
$AnimatedSprite.animation = "hurt"
set_process(false) # 使本節點停止運作
●End-Player_area2d.gd
宣告事件名稱
●Begin-Player_area2d.gd
# 下兩行請放在 extends Area2D 之後
signal sig_pickup
signal sig_hurt
●End-Player_area2d.gd
Select Node Player_area2d, 右邊 Node/Signals/Area2D/area_entered(area: Area2D), 按右鍵, Connect..., Connect
●Begin-Player_area2d.gd
func _on_Player_area2d_area_entered(area):
if area.is_in_group("grp_coins"):
area.pickup()
emit_signal("sig_pickup")
if area.is_in_group("grp_obstacles"):
emit_signal("sig_hurt")
die()
●End-Player_area2d.gd
------ 錢幣
Scene/New Scene
(Add/Create a New Node)→Area2D→Create,改名Coin_area2d
Scene/Save Scene→Coin_area2d.tscn→Save
Select Node Coin_area2d, (Add/Create a New Node)→AnimatedSprite→Create
Select Node Coin_area2d, (Add/Create a New Node)→CollisionShape2D→Create
Select Node AnimatedSprite, Inspector/AnimatedSprite/Frames/New SpriteFrames
Select Node AnimatedSprite, 下方 Animations
點選 default,從左方 FileSystem 把對應的 *.png 拖曳到右邊 Animation Frames 的方框中,修改 Animations/Speed 為 12 FPS。
Inspector/AnimatedSprite/Node2D/Transform/Scale→x=0.5, y=0.5
Select Node CollisionShape2D
Inspector/CollisionShape2D/Shape→New RectangleShape2D
Workspace/2D/Viewport/調整框框,包住 Coin_area2d
Select Node Coin_area2d, 右邊 Node/Groups,填入 grp_coins,按下 Add
Select Node Coin_area2d, Scene/綠色加號(Attach a new or existing script to the selected node)→Coin_area2d.gd→Create
●Begin-Coin_area2d.gd
extends Area2D
var screensize = Vector2()
func pickup():
queue_free() # 移除自己這個節點
●End-Coin_area2d.gd
------ 主場景
Scene/New Scene
(Add/Create a New Node)→Node→Create,改名Main_node
Scene/Save Scene→Main_node.tscn→Save
Select Node Main_node, Scene/綠色加號(Attach a new or existing script to the selected node)→Main_node.gd→Create
Select Node Main_node, (Add/Create a New Node)→TextureRect→Create。重新命名為 tr_Background
Select Node Main_node, (鎖鏈形狀)Instance Child Scene→選取 Player_area2d.tscn→Open
Select Node Main_node, (Add/Create a New Node)→Node→Create。重新命名為 node_CoinContainer
Select Node Main_node, (Add/Create a New Node)→Position2D→Create。重新命名為 p2d_PlayerStart
Select Node Main_node, (Add/Create a New Node)→Timer→Create。重新命名為 tmr_GameTimer
Select Node tr_Background, 把 grass.png 從 (左下角)FileSystem 拖曳到 (右上角)Inspector/tr_Background/TextureRect/Texture 的右邊格子
Inspector/tr_Background/TextureRect/Stretch Mode→Tile
Workspace/2D/Viewport/Layout→Full Rect
Select Node p2d_PlayerStart, Inspector/p2d_PlayerStart/Node2D/Transform/Position→x=240, y=350
Select Node Main_node, Workspace/Script
●Begin-Main_node.gd
extends Node
export (PackedScene) var Coin_area2d # 只有宣告外部場景,還須到Inspector指定才行
export (int) var playtime
var level
var score
var time_left
var screensize
var playing = false
●End-Main_node.gd
Select Node Main_node,
從 FileSystem 把 Coin_area2d.tscn 拖曳到 Inspector/Main_node/Script Variables/Coin Area 2d 的右邊格子 # 裡面有宣告,外面有指定
Inspector/Main_node/Script Variables/Playtime→30 #(30秒是原本遊戲預設的時間)
Select Node Main_node, Workspace/Script
●Begin-Main_node.gd
func _ready():
randomize()
screensize = get_viewport().get_visible_rect().size
$Player_area2d.screensize = screensize
$Player_area2d.hide()
func new_game():
playing = true
level = 1
score = 0
time_left = playtime
$Player_area2d.start($p2d_PlayerStart.position) # 此start函數是自訂函數
$Player_area2d.show()
$tmr_GameTimer.start() # 此start函數是內建函數
spawn_coins()
func spawn_coins():
for i in range(4 + level):
var c = Coin_area2d.instance() # 進行實體化
$node_CoinContainer.add_child(c)
c.screensize = screensize
c.position = Vector2(rand_range(0, screensize.x), rand_range(0, screensize.y))
●End-Main_node.gd
為了測試,現在可以先把 new_game() 加到 _ready() 裡面最後一行
Project/Project Settings.../General/Application/Run/Main Scene→選取 Main_node.tscn→Close
Select Node Main_node, Workspace/Script
●Begin-Main_node.gd
func _process(delta):
if playing and $node_CoinContainer.get_child_count() == 0:
level += 1
time_left += 5
spawn_coins()
●End-Main_node.gd
------ 抬頭顯示器
Scene/New Scene
(Add/Create a New Node)→CanvasLayer→Create,改名HUD_cl
Select Node HUD_cl, (Add/Create a New Node)→Label→Create。重新命名為 MessageLabel
Select Node MessageLabel, Workspace/2D/Viewport/Layout→HCenter Wide
Inspector/MessageLabel/Label/Text→"Coin Dash!", Align→Center, V Align→Center
Inspector/MessageLabel/Control/Theme Overrides/Fonts/勾選 Font, 選取 New DynamicFont
Inspector/MessageLabel/Control/Theme Overrides/Fonts/點開 DynamicFont/Font/Font Data 右邊的格子,請從 FileSystem 拖曳字型(.ttf)到這裡
Inspector/MessageLabel/Control/Theme Overrides/Fonts/點開 DynamicFont/Settings/Size→48
Scene/Save Scene→HUD_cl.tscn→Save
Select Node HUD_cl, (Add/Create a New Node)→MarginContainer→Create。
Workspace/2D/Viewport/Layout→Top Wide
Inspector/MarginContainer/Control/Margin/Left→10, Top→10, Right→10
Select Node MessageLabel, Ctrl+D(複製) 兩次
將 MessageLabel2, MessageLabel3 拖曳到 MarginContainer 上方,放開
Scene/MessageLabel2 改名為 ml_ScoreLabel, MessageLabel3 改名為 ml_TimeLabel
Select Node ml_ScoreLabel
Inspector/ml_ScoreLabel/Label/Text→0, Align→Left
Select Node ml_TimeLabel
Inspector/ml_TimeLabel/Label/Text→0, Align→Right
Select Node HUD_cl, Scene/綠色加號(Attach a new or existing script to the selected node)→HUD_cl.gd→Create
●Begin-HUD_cl.gd
extends CanvasLayer
signal sig_start_game
func _ready():
pass
func update_score(value):
$MarginContainer/ml_ScoreLabel.text = str(value)
func update_timer(value):
$MarginContainer/ml_TimeLabel.text = str(value)
●End-HUD_cl.gd
Select Node HUD_cl, (Add/Create a New Node)→Timer→Create。重新命名為 MessageTimer
Inspector/MessageTimer/Timer/Wait Time→2, One Shot→勾選On
Select Node HUD_cl, Workspace/Script
●Begin-HUD_cl.gd
func show_message(text):
$MessageLabel.text = text
$MessageLabel.show()
$MessageTimer.start()
●End-HUD_cl.gd
Select Node MessageTimer, Node/Signals/Timer/timeout()→按右鍵 Connect...→Connect
●Begin-HUD_cl.gd
func _on_MessageTimer_timeout():
$MessageLabel.hide()
●End-HUD_cl.gd
Select Node HUD_cl, (Add/Create a New Node)→Button→Create。重新命名為 StartButton
Select Node StartButton,
Inspector/StartButton/Button/Text→Start
Inspector/StartButton/Control/Margin/Top→-150, Bottom→-50
Inspector/StartButton/Control/Theme Overrides/Fonts/勾選 Font, 右邊格子選 New DynamicFont,點選 DynamicFont
Settings/Size→48
Font/Font Data,右邊格子,把 *.ttf 拖曳過來
Select Node StartButton, Workspace/2D/Layout→Center Bottom
Select Node StartButton, Node/Signals/BaseButton/pressed() 按右鍵 Connect...→Connect
●Begin-HUD_cl.gd
func _on_StartButton_pressed():
$StartButton.hide()
$MessageLabel.hide()
emit_signal("sig_start_game")
func show_game_over():
show_message("Game Over")
yield($MessageTimer, "timeout") # 暫停執行,等待事件被觸發
$StartButton.show()
$MessageLabel.text = "Coin Dash!"
$MessageLabel.show()
●End-HUD_cl.gd
------ 重回主場景
在 FileSystem 把 Main_node.tscn 點兩下
Scene, Select Node Main_node, (Instance Child Secne)→選取 HUD_cl.tscn→Open
Select Node tmr_GameTimer, Node/Signals/Timer/timeout() 上面按右鍵,Connect ...→Connect
●Begin-Main_node.gd
func game_over():
playing = false
$tmr_GameTimer.stop()
for coin in $node_CoinContainer.get_children():
coin.queue_free()
$HUD_cl.show_game_over()
$Player_area2d.die()
func _on_tmr_GameTimer_timeout():
time_left -= 1
$HUD_cl.update_timer(time_left)
if time_left <= 0:
game_over()
func _on_Player_area2d_sig_pickup(): # 注意,這個函式也要從 Node 那邊 connect 喔
score += 1
$HUD_cl.update_score(score)
func _on_Player_area2d_sig_hurt(): # 注意,這個函式也要從 Node 那邊 connect 喔
game_over()
●End-Main_node.gd
Select Node HUD_cl, Node/Signals/HUD_cl.gd/sig_start_game() 上面按右鍵 Connect ...,在 Receiver Method 填入 new_game→Connect
到 _ready() 函數中,把 最後一行的 new_game() 刪除掉
來到 new_game() 函數中,在最後面,加入下面兩行
$HUD_cl.update_score(score)
$HUD_cl.update_timer(time_left)
------ 更進一步
Select Node Coin_area2d, (Add/Create a New Node)→Tween→Create
Select Node Coin_area2d, Workspace/Script
●Begin-Coin_area2d.gd
func _ready():
$Tween.interpolate_property($AnimatedSprite, 'scale', $AnimatedSprite.scale, $AnimatedSprite.scale * 3, 0.3, Tween.TRANS_QUAD, Tween.EASE_IN_OUT)
func pickup():
monitoring = false # 避免動畫途中,又有新事件觸發
$Tween.start()
# 原本的 queue_free() 就刪除囉。
●End-Coin_area2d.gd
Select Node Tween, Node/Signals/Tween/tween_all_completed 上面按右鍵 Connect...→Connect
●Begin-Coin_area2d.gd
func _on_Tween_tween_all_completed():
queue_free()
●End-Coin_area2d.gd
回頭修改效果
●Begin-Coin_area2d.gd
func _ready():
$Tween.interpolate_property($AnimatedSprite, 'scale', $AnimatedSprite.scale, $AnimatedSprite.scale * 3, 0.3, Tween.TRANS_QUAD, Tween.EASE_IN_OUT)
$Tween.interpolate_property($AnimatedSprite, 'modulate', Color(1,1,1,1), Color(1,1,1,0), 0.3, Tween.TRANS_QUAD, Tween.EASE_IN_OUT)
●End-Coin_area2d.gd
------ 更進一步,增加聲音
Select Node Main_node, (Add/Create a New Node)→AudioStreamPlayer→Create,重新命名為 asp_CoinSound
Select Node Main_node, (Add/Create a New Node)→AudioStreamPlayer→Create,重新命名為 asp_LevelSound
Select Node Main_node, (Add/Create a New Node)→AudioStreamPlayer→Create,重新命名為 asp_EndSound
上面三個 audiostreamplayer,依次從FileSystem那裡拖曳對應的聲音檔到 Inspector/asp_...Sound/AudioStreamPlayer/Stream 右邊的格子裡
Select Node Main_node, Workspace/Script
在 _on_Player_area2d_sig_pickup() 的最後面加入 $asp_CoinSound.play()
在 game_over() 的最後面加入 $asp_EndSound.play()
在 spawn_coins() 的最後面加入 $asp_LevelSound.play()
------ 更進一步,紅利措施
在 FileSystem 雙擊 Coin_area2d.tscn
Scene/Save Scene As→Powerup_area2d.tscn→Save
把 Scene 裡根節點的名字從 Coin_area2d 改成 Powerup_area2d
Select Node Powerup_area2d,點擊 Scene/紅色叉叉 (刪除script)
Select Node Powerup_area2d,確認 Node/Signals/Area2D/area_entered 已經 disconnect
Select Node Powerup_area2d,Node/Groups,新增 grp_powerups,刪除 grp_coins
Select Node AnimatedSprite, 在 Animations/Animation Frames 裡面,刪除全部圖檔,拖曳正確的圖檔進來
在 FileSystem 雙擊 Powerup_area2d.tscn
Scene/綠色加號(Attach a new or existing script to the selected node)→Powerup_area2d.gd→Create
在 FileSystem 雙擊 Coin_area2d.gd, Workspace/Script, 複製所有程式碼
在 FileSystem 雙擊 Powerup_area2d.tscn, Select Node Powerup_area2d, Workspace/Script, 貼上程式碼, 存檔
Select Node Powerup_area2d, (Add/Create a New Node)→Timer→Create, 重新命名為 tmr_Lifetime
Inspector/tmr_Lifetime/Timer/Wait Time→6, One Shot→勾選On, Autostart→勾選On
Select Node tmr_Lifetime, Node/Signals/Timer/timeout() 上面按右鍵,Connect...→Connect
●Begin-Powerup_area2d.gd
func _on_tmr_Lifetime_timeout():
queue_free()
●End-Powerup_area2d.gd
在 FileSystem 雙擊 Main_node, Scene/Select Node Main_node, (Add/Create a New Node)→Timer→Create, 重新命名為 tmr_PowerupTimer
Inspector/tmr_PowerupTimer/Timer/One Shot→勾選On
Select Node Main_node, (Add/Create a New Node)→AudioStreamPlayer→Create, 重新命名為 asp_Powerup
Inspector/asp_Powerup/AudioStreamPlayer/Stream, 把對應的音檔拖曳到右邊的格子內
Select Node tmr_PowerupTimer, Node/Signals/Timer/timeout 在上面按右鍵 Connect...→Connect
●Begin-Main_node.gd
# 下面一行,請插到最上方,另一個 export (PackedScene) ...... 的下面一行
export (PackedScene) var Powerup_area2d # 只有宣告外部場景,還須到Inspector指定才行
Select Node Main_node, Inspector/Main_node/Script Variables/Powerup Area 2d 右邊的格子,
請把 Powerup_area2d.tscn 從 FileSystem 拖曳到這裡
# 下面的函數,可以放到最後面
func _on_tmr_PowerupTimer_timeout():
var p = Powerup_area2d.instance()
add_child(p)
p.screensize = screensize
p.position = Vector2(rand_range(0, screensize.x), rand_range(0, screensize.y))
●End-Main_node.gd
Select Node Main_node, Workspace/Script, 找到 func _process(delta) 在最後面與 spawn_coins() 相同層次
新增兩行程式碼
$tmr_PowerupTimer.wait_time = rand_range(2,5)
$tmr_PowerupTimer.start()
雙擊 Player_area2d.tscn, Workspace/Script, 找到 _on_Player_area2d_area_entered 函數,並改成如下程式碼
●Begin-Player_area2d.gd
func _on_Player_area2d_area_entered(area):
if area.is_in_group("grp_coins"):
area.pickup()
emit_signal("sig_pickup", "coin")
if area.is_in_group("grp_powerups"):
area.pickup()
emit_signal("sig_pickup", "powerup")
if area.is_in_group("grp_obstacles"):
emit_signal("sig_hurt")
die()
●End-Player_area2d.gd
雙擊 Main_node.tscn, Workspace/Script, 將 _on_Player_area2d_sig_pickup 修改成如下樣子
●Begin-Main_node.gd
func _on_Player_area2d_sig_pickup(type):
match type:
"coin":
score += 1
$HUD_cl.update_score(score)
$asp_CoinSound.play()
"powerup":
time_left += 5
$asp_Powerup.play()
$HUD_cl.update_timer(time_left)
●End-Main_node.gd
雙擊 Coin_area2d.tscn
Select Node AnimatedSprite, Animations/default, Loop 取消
Select Node Coin_area2d, (Add/Create a New Node)→Timer→Create
把下兩行加到 _ready 後面
$Timer.wait_time = rand_range(3, 8)
$Timer.start()
Select Node Timer, Node/Signals/Timer/timeout() 上面按右鍵,Connect...→Connect
●Begin-Coin_area2d.gd
func _on_Timer_timeout():
$AnimatedSprite.frame = 0
$AnimatedSprite.play()
●End-Coin_area2d.gd