iT邦幫忙

2023 iThome 鐵人賽

DAY 19
0
SideProject30

初探 Godot系列 第 19

[DAY 19] 障礙建置 Part.3 (CollisionShape2D.disabled, const)

  • 分享至 

  • xImage
  •  

今日目標:根據障礙效果實作邏輯


▍事前準備

我們昨天定義好了不同的碰撞效果,今天要來實作部分效果邏輯。

這次會修改 角色 腳本。


▍出發

  • 在角色腳本中建立新的變數,暴露出我們希望的初始速度以及若進入 SLOW 狀態時的速度。

    @export var slow_speed:float = 1
    @export var base_speed:float = 5
    var speed:float = base_speed
    
  • 在角色場景根節點上建立三個計時器作為我們不同效果的持續時間使用,根據效果狀態重新命名並修改右邊屬性值,開啟one_shot、調整時間長度。
    https://ithelp.ithome.com.tw/upload/images/20231004/20162875gKUwLhTS00.png

  • 宣告這三個計時器,並在初始化時將剛剛建立的計時器連結到腳本上,同時將計時器的訊號連結到各自的方法上,這些方法我們在下一步實作。

    var invincible_timer:Timer
    var slow_timer:Timer
    var stop_timer:Timer
    
    func _ready():
        # <...> 之前的程式碼略過
        # 新增下面程式碼。
        invincible_timer = $"../InvincibleTimer"
        invincible_timer.timeout.connect(_on_invincible_timeout)
        slow_timer = $"../SlowTimer"
        slow_timer.timeout.connect(_on_slow_timeout)
        stop_timer = $"../StopTimer"
        stop_timer.timeout.connect(_on_stop_timeout)
    
  • 建立我們不同狀態時需要產生對應的效果

    1. 無敵狀態:在這個狀態下,我們將角色的碰撞功能關閉,不再受到碰撞影響達到無敵效果。這邊另外會重置速度回度初始狀態,開始計時。
    func handle_invincible_state():
        get_node("CollisionShape2D").disabled = true
        speed = base_speed
        invincible_timer.start()
    
    1. 無敵狀態結束:狀態結束時我們再次開啟碰撞功能並將狀態。
    func _on_invincible_timeout():
        get_node("CollisionShape2D").disabled = false
    
    1. 緩速狀態:此狀態我們更新我們的速度值,開始計時。
    func handle_slow_state():
        speed = slow_speed
        slow_timer.start()
    
    1. 緩速狀態結束:重置速度值。
    func _on_slow_timeout():
        speed = base_speed
    
    1. 停止狀態:此狀態將速度歸零,開始計時。
    func handle_stop_state():
        speed = 0
        stop_timer.start()
    
    1. 結束停止狀態:重置速度值。
    func _on_stop_timeout():
        speed = base_speed
    
    1. 結束遊戲狀態:這裡我們先不實作。
    func handle_end_state():
        pass
    
  • 將狀態處理的方法放回昨天建立的狀態判斷中。

    1. 這邊我們先將 DEFAULT 字串宣告成常數,方便未來如果更改可以只更改變宣告數值,不用在程式碼中一一尋找。宣告完成後可以所有要用到的地方都更新成常數。
    const DEFAULT = "DEFAULT"
    # 更新成常數
    var state:String = DEFAULT
    
    1. 更新狀態處理,並在處理完成後將狀態回復至初始狀態。
    func handle_player_state():
        match state:
            DEFAULT:
                pass
            "INVINCIBLE":
                handle_invincible_state()
            "SLOW":
                handle_slow_state()
            "STOP":
                handle_stop_state()
            "END":
                handle_end_state()
        state = DEFAULT
    
  • 最後我們根據不同狀態各自建立一個場景。

    1. 先在 scenes 資料夾下建立新資料夾 obstacles 方便管理。
    2. 接著將之前建立的會動吉不會動的障礙物場景移動到資料夾中。
    3. 最後我們根據不會動的障礙場景複製三個場景分別作為三種狀態的碰撞測試。
    4. 最後重新命名個自場景的根節點名稱方便辨識。
    5. 更改場景的屬性面板碰撞效果(INVINCIBLE, SLOW, STOP)、Polygon2D 顏色及碰撞範圍。
      https://ithelp.ithome.com.tw/upload/images/20231004/20162875i8vEjL1o11.png

▍執行

這裡建立的障礙物僅作為測試,之後記得刪除回復。
Yes

▍完成

完整檔案

extends CharacterBody2D

# CharacterBody2D
var direction:Vector2
var dragged:bool = false
var oriPos: Vector2
var player: CharacterBody2D
var player_anime: AnimatedSprite2D

# MovementUI
var movement_ui: Node2D

# Collision Handling
@export var slow_speed:float = 1
@export var base_speed:float = 5
var speed:float = base_speed

var invincible_timer:Timer
var slow_timer:Timer
var stop_timer:Timer
const DEFAULT = "DEFAULT"
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")
	
	invincible_timer = $"../InvincibleTimer"
	invincible_timer.timeout.connect(_on_invincible_timeout)
	slow_timer = $"../SlowTimer"
	slow_timer.timeout.connect(_on_slow_timeout)
	stop_timer = $"../StopTimer"
	stop_timer.timeout.connect(_on_stop_timeout)

# 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:
			pass
		"INVINCIBLE":
			handle_invincible_state()
		"SLOW":
			handle_slow_state()
		"STOP":
			handle_stop_state()
		"END":
			handle_end_state()
	state = DEFAULT

func handle_invincible_state():
	get_node("CollisionShape2D").disabled = true
	speed = base_speed
	invincible_timer.start()
	
func _on_invincible_timeout():
	get_node("CollisionShape2D").disabled = false
	
func handle_slow_state():
	speed = slow_speed
	slow_timer.start()
	
func _on_slow_timeout():
	speed = base_speed
	
func handle_stop_state():
	speed = 0
	stop_timer.start()
	
func _on_stop_timeout():
	speed = base_speed
	
func handle_end_state():
	pass

:)


上一篇
[DAY 18] 障礙建置 Part.2 (export_enum, extends, match)
下一篇
[DAY 20] 特效建置 (shader, set_shader_parameter)
系列文
初探 Godot30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言