我們在昨天建立了兩種障礙物,分別有會移動以及不會移動的兩種。不論移動或不移動都還會有不同的邏輯差異,但每次為了部份差異都要新增腳本會造成重複的程式碼大量複製,維護時也需要在不同檔案中更改。因此我們今天新增一個障礙物的基本定義腳本
。
準備昨天建立的場景來編輯,這次會修改 角色腳本
、移動的障礙物
腳本。
因為目前不移動的障礙物還沒有其他需求,因此我們先在昨天不移動的障礙物場景根節點上附加腳本,這裡命名為 obstacle_base
開始編輯。
(obstacle_base
)建立碰撞的效果列舉並暴露在屬性面板方便編輯,這裡使用 @export_enum
。
@export_enum("INVINCIBLE", "SLOW", "STOP", "END") var collision_action:String
現在可以在屬性面板中選擇指定名稱給變數。
我們試著在 ready
時印出變數,播放後可以看到選擇的字串被印出來。
編輯碰撞邏輯,當角色進入時發出訊號。
CharacterBody2D
右邊的節點標籤頁新增群組,建立 player
群組作為稍後第3點用來判斷碰撞到的是不是我們要的物品使用,避免未來有其他的碰撞被錯誤觸發。角色腳本
)新增變數。var state:String = "DEFAULT"
obstacle_base
)編輯我們的碰撞邏輯。func _on_player_enter(player):
# 檢查是否是在指定群組
if player.is_in_group("player"):
# 更新角色的 state 變數
player.state = collision_action
obstacle_base
)ready
時綁定到角色進入訊號上。func _ready():
body_entered.connect(_on_player_enter)
角色腳本
)在 process
中新增處理狀態方法。func _process(delta):
if dragged:
player.position += direction*speed
# 新增下面這行
handle_player_state()
(角色腳本
)建立方法,實際邏輯先留著下次改,為了方便觀察先印狀態就好,這裡使用 match
來執行對應邏輯。
func handle_player_state():
match state:
# 當 state == "DEFAULT"
"DEFAULT":
# 執行這裡的邏輯
print("DEFAULT")
# 同上,state == "INVINCIBLE"
"INVINCIBLE":
print("INVINCIBLE")
"SLOW":
print("SLOW")
"STOP":
print("STOP")
"END":
print("END")
昨天移動的障礙物
的腳本,為了讓它也能繼承障礙物的基本屬性我們,我們將該腳本最上方的 extends Area2D
改成繼承我們的基本屬性腳本即可。
extends Area2D
# 原本的移動腳本 <...>
改成
extends "obstacle_base.gd"
# 原本的移動腳本 <...>
現在在移動的障礙物屬性面板可以看到選單出現。
這裡建立的障礙物僅作為測試,之後記得刪除回復。
可以看到下面的輸出效果。
完整檔案
extends CharacterBody2D
var direction:Vector2
var speed:float = 5
var dragged:bool = false
var oriPos: Vector2
var player: CharacterBody2D
var player_anime: AnimatedSprite2D
var movement_ui: Node2D
var state:String = "DEFAULT"
# Called when the node enters the scene tree for the first time.
func _ready():
movement_ui = $"../MovementUI"
movement_ui.visible = false
player = $"."
player_anime = player.get_node("AnimatedSprite2D")
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta):
if dragged:
player.position += direction*speed
handle_player_state()
func _input(event):
if event is InputEventScreenTouch:
if event.is_pressed():
oriPos = event.position
dragged = true
player_anime.play()
movement_ui.visible = true
movement_ui.position = event.position
elif event.is_released():
direction = Vector2.ZERO
dragged = false
player_anime.stop()
movement_ui.visible = false
if event is InputEventScreenDrag:
direction = (event.position - oriPos).normalized()
movement_ui.rotation = Vector2.UP.angle_to(direction)
if abs(direction.y) > abs(direction.x):
player_anime.animation = "default"
elif direction.x > 0:
player_anime.animation = "turn_right"
elif direction.x < 0:
player_anime.animation = "turn_left"
func handle_player_state():
match state:
"DEFAULT":
print("DEFAULT")
"INVINCIBLE":
print("INVINCIBLE")
"SLOW":
print("SLOW")
"STOP":
print("STOP")
"END":
print("END")
extends Area2D
@export_enum("INVINCIBLE", "SLOW", "STOP", "END") var collision_action:String
# Called when the node enters the scene tree for the first time.
func _ready():
body_entered.connect(_on_player_enter)
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta):
pass
func _on_player_enter(player):
if player.is_in_group("player"):
player.state = collision_action
extends "obstacle_base.gd"
@export var speed:float = 2
var rotated_vector:Vector2 = Vector2.DOWN
var rand_rotate:float
# <下略,只更改第一行...>
:)