iT邦幫忙

2023 iThome 鐵人賽

DAY 18
0
SideProject30

初探 Godot系列 第 18

[DAY 18] 障礙建置 Part.2 (export_enum, extends, match)

  • 分享至 

  • xImage
  •  

今日目標:建立碰撞效果選單


▍事前準備

我們在昨天建立了兩種障礙物,分別有會移動以及不會移動的兩種。不論移動或不移動都還會有不同的邏輯差異,但每次為了部份差異都要新增腳本會造成重複的程式碼大量複製,維護時也需要在不同檔案中更改。因此我們今天新增一個障礙物的基本定義腳本

準備昨天建立的場景來編輯,這次會修改 角色腳本移動的障礙物 腳本。


▍出發

因為目前不移動的障礙物還沒有其他需求,因此我們先在昨天不移動的障礙物場景根節點上附加腳本,這裡命名為 obstacle_base 開始編輯。

  • obstacle_base)建立碰撞的效果列舉並暴露在屬性面板方便編輯,這裡使用 @export_enum

    @export_enum("INVINCIBLE", "SLOW", "STOP", "END") var collision_action:String
    

    現在可以在屬性面板中選擇指定名稱給變數。
    我們試著在 ready 時印出變數,播放後可以看到選擇的字串被印出來。
    https://ithelp.ithome.com.tw/upload/images/20231003/201628752c5OccQM4Q.png

  • 編輯碰撞邏輯,當角色進入時發出訊號。

    1. 先回到我們的角色場景,點擊 CharacterBody2D 右邊的節點標籤頁新增群組,建立 player 群組作為稍後第3點用來判斷碰撞到的是不是我們要的物品使用,避免未來有其他的碰撞被錯誤觸發。
      https://ithelp.ithome.com.tw/upload/images/20231003/20162875saS1WR3d96.png
    2. 角色腳本)新增變數。
    var state:String = "DEFAULT"
    
    1. obstacle_base)編輯我們的碰撞邏輯。
    func _on_player_enter(player):
        # 檢查是否是在指定群組
        if player.is_in_group("player"):
            # 更新角色的 state 變數
            player.state = collision_action
    
    1. obstacle_baseready 時綁定到角色進入訊號上。
    func _ready():
        body_entered.connect(_on_player_enter)
    
    1. 角色腳本)在 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"

# 原本的移動腳本 <...>

現在在移動的障礙物屬性面板可以看到選單出現。
https://ithelp.ithome.com.tw/upload/images/20231003/20162875ZvzvA9SZRs.png

▍執行

這裡建立的障礙物僅作為測試,之後記得刪除回復。
可以看到下面的輸出效果。
Yes

▍完成

完整檔案

  1. player
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")
  1. obstacle_base
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
  1. obstacle_move
extends "obstacle_base.gd"

@export var speed:float = 2

var rotated_vector:Vector2 = Vector2.DOWN
var rand_rotate:float
# <下略,只更改第一行...>

:)


上一篇
[DAY 17] 障礙建置 Part.1 (randf_range)
下一篇
[DAY 19] 障礙建置 Part.3 (CollisionShape2D.disabled, const)
系列文
初探 Godot30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言