Godot4 タイルマップのはしごを登り降りするけど先端で止まるスクリプト例

無料・軽快な 2D / 3D 用のゲームエンジン Godot Engine 4 で、操作キャラクターがタイルマップのはしごのタイルに触れているとき上下キーを押すと上下に昇降する実装をテストすると、はしごの先端でさらに昇降するとはしごを飛び出してしまうので、移動先にはしごがあるかを確認してはしごから飛び出さないスクリプト改良します。

※ GodotEngine 4.3 を使用しています。.NET 版ではありません。
※スクリプトは自己責任でご使用ください。

前回の記事

前回は、はしごのタイルに触れている際に上下キーを押すと昇降中の状態になり落下せずに上下移動するスクリプトとその実行結果を紹介しました。

しかし、はしごの先端でとまらないので、飛び出してしまう動作が気になりました。

Godot4 接触しているタイルが昇降可能なカスタムデータを持っていたら上下矢印キーで昇降します.はしまで登ると勢いでジャンプしてしまいます.SS1

はしごの先端で上り下りを止める処理

スクリプトのハイライトしている行が、今回追加した、はしごの先端で停止する処理です。

デバッグ変数 bool debug_stop_because_could_not_climb は、昇降の入力があった際に、その移動先が昇降不可の場合に、その昇降の入力を無視したフレームでのみ true になります。
このデバッグ変数は _draw イベント関数で X の赤い文字を描画する際に参照されます。

Godot4 昇降可能なタイルの上り下りで、次の移動先が昇降可能でない場合に停止する処理のテストSS1

予測される移動先は、 _physics_process イベント関数は _process イベント関数と異なり、ある程度一定間隔で呼び出される性質を利用しています。

一定間隔で呼び出されることを期待して、前回の呼び出しからの経過時間である delta (ミリ秒) を、移動量のベクトル掛けることで、「速さ×時間=距離」に似た方法で、予測される次フレームでの移動先を計算しています。
あとは、移動先でキャラクターが接触しているタイル群昇降可能なものがあるかを調べて、なければ昇降の入力を無視し、昇降可能ならば今まで通り、昇降のため移動量のベクトルの Y 軸に値を設定します。

※詳細についてはスクリプトのコメントを参照してください。

extends CharacterBody2D

## 操作キャラクターが干渉するタイルマップを設定します。はしごの上り下りなどの条件をこのタイルマップから調べます。
@export var tilemap_layer: TileMapLayer = null
@export var SPEED: float = 300.0 # 左右入力により設定する水平方向の加速度
@export var SPEED_REDUCE: float = 300.0	# 入力がない場合に、水平方向の加速度を減らすフレームあたりの上限値。とまりにくいキャラは SPEED より小さく設定します。
@export var JUMP_VELOCITY: float = -700. # ジャンプの加速度です。

# のっている地形の加速度。動いている地形でジャンプする場合に慣性をつけます。
var platform_velocity = Vector2(0, 0)

# はしごなどをのぼる動作が可能な位置にいる場合に TilemapStage ノードから値を true にされます。
@export var can_climb: bool = false
# はしごなどをのぼりおりしている状態の際に true に設定されます。
@export var is_climb: bool = false
# デバッグ用。はしごなどを昇降中、次の移動先がはしごの先端で昇降不可なので移動を停止させた場合に true を設定されます。
var debug_stop_because_could_not_climb: bool = false

## _physics_process で行う昇降可能の判定をデバッグするための描画を _draw で行う場合は true を設定します。
var debug_can_climb = true

func _ready():
	if debug_can_climb:
		SakuraCrowdTileMapLayer.enable_debug_get_entered_tiles = true
	
func _draw():
	# デバッグのフラグが有効ならば、接触しているタイル(赤)またはタイルのないセル(青)の枠を描画します。
	if debug_can_climb:
		if SakuraCrowdTileMapLayer.enable_debug_get_entered_tiles:
			# デバッグ用。キャラクターが接触しているタイルの枠線を描画します。
			for draw_info in SakuraCrowdTileMapLayer.debug_get_entered_tiles_info:
				# 本ノードの原点がグローバル座標の (0, 0) と異なっていたり、 scale が 1.0 ではない場合、
				# debug_get_entered_tiles_info に格納されたグローバル座標の rect2 を描画すると
				# ローカル座標として扱ってしまい位置がずれて大きさの異なる矩形が描画されてしまうので
				# グローバル座標をローカル座標に変換します。
				var local_rect2: Rect2 = SakuraCrowdUtil.rect2_to_local(draw_info.rect2, self)
				draw_rect(local_rect2, draw_info.color, false, 3 / scale.x, false)
				SakuraCrowdUtil.debug_print(str(draw_info.rect2), 100)
		# デバッグ用。キャラクターが昇降可能な状態の場合は^を描画します。
		if can_climb == true:
			# _draw の描画で指定した座標は、ローカル座標として扱うので、グローバル座標はローカル座標に変換します。
			# 文字サイズもノードの scale に影響されるので、scale.x の逆数で意図したサイズで描画されるようにします。
			draw_string(ThemeDB.fallback_font, to_local(global_position + Vector2(0, -8)), "^", HORIZONTAL_ALIGNMENT_CENTER, -1, 16 / scale.x, Color.GREEN)
		# 次の移動先が昇降不可なので入力に応じず上下(昇降)移動を停止した場合 ^ のとなりに X をつけます。。
		if debug_stop_because_could_not_climb:
			draw_string(ThemeDB.fallback_font, to_local(global_position + Vector2(8, -8)), "X", HORIZONTAL_ALIGNMENT_CENTER, -1, 16 / scale.x, Color.RED)	
	return

func _process(_delta):
	return

func _physics_process(delta):
	debug_stop_because_could_not_climb = false # デバッグ用。毎フレーム初期化します。
	
	# 現在接触しているタイル群のカスタムデータから、はしごなどの昇降や水中移動の動作が可能かを更新します。
	# $GodotSan の当たり判定領域に重なっている $TileMapLayer のタイル群を取得します。
	var enterd_tiles: Array[TileData] = SakuraCrowdTileMapLayer.get_entered_tiles(tilemap_layer, self)
	if debug_can_climb:
		queue_redraw()	# 接触しているタイルのデバッグ用の再描画を要求します。
		
	# 昇降可能なタイルに触れているかを確認します。
	can_climb = SakuraCrowdTileData.has_true_custom_data(enterd_tiles, "can_climb")
	
	# 着地しているかどうかを取得(複数回呼ぶのでキャッシュ変数に格納)
	var ret_is_on_floor:bool = is_on_floor()
	# Add the gravity.
	if not ret_is_on_floor and not is_climb:
		# 着地していない、はしごの昇降もしていない、空中にいる場合
		velocity += get_gravity() * delta # 重力により落下させます。

	# 着地しているかはしごなどを昇降中はジャンプの入力に対応します。
	if Input.is_action_just_pressed("ui_accept") and (ret_is_on_floor or is_climb):
		velocity.y = JUMP_VELOCITY
		velocity.x += platform_velocity.x # ジャンプ時に、のっている地形の水平方向の加速度を加えることで慣性のあるジャンプを表現します。
		is_climb = false	# はしごを昇降していた場合はその状態を無効にします。

	# Get the input direction and handle the movement/deceleration.
	# As good practice, you should replace UI actions with custom gameplay actions.
	var direction = Input.get_axis("ui_left", "ui_right") # 右入力: + の値, 左右入力なし: 0, 左入力: - の値
	if direction:
		# 左右どちらかに入力された場合
		velocity.x = direction * SPEED # 入力方向に加速
	else:
		# 左右の入力がない場合
		if ret_is_on_floor:
			# 左右移動せずに着地している場合
			
			# SPEED_REDUCE 単位で毎フレーム 0 に向けて減速します。
			# 氷の床などですべりやすくしたい場合、 SPEED_REDUCE をさらに減少させてください。
			velocity.x = move_toward(velocity.x, 0, SPEED_REDUCE) 

	# can_climb が false のエリアに移動した場合は、 is_climb の状態を無効にします。
	if can_climb == false:
		is_climb = false
	
	# can_climb が有効な場合、上下キーで昇降ができます。
	var direction_vertical = Input.get_axis("ui_up", "ui_down")
	if direction_vertical:
		if can_climb:
			is_climb = true	# 昇降可能なエリアにいて昇降の操作を行うと昇降中の状態になります。

			# もしも、移動先が is_climb のタイルが含まれていない場合、昇降の velocity.y をキャンセルする。
			var predicted_movement = Vector2(0, direction_vertical * SPEED * delta) # 次の _pyisics_process の呼び出しが delta と同じと仮定した場合の移動量
			var predicted_tiles: Array[TileData] = SakuraCrowdTileMapLayer.get_entered_tiles(tilemap_layer, self, predicted_movement)
			if SakuraCrowdTileData.has_true_custom_data(predicted_tiles, "can_climb"):
				velocity.y = direction_vertical * SPEED  # 昇降速度を入力方向に応じて設定
			else:
				velocity.y = 0	# 移動先が昇降可能ではないのでとまります。
				debug_stop_because_could_not_climb = true # デバッグ用。移動先が昇降不可なので停止したことをフラグに設定。
	else:
		if is_climb:
			velocity.y = move_toward(velocity.y, 0, SPEED_REDUCE)	# 昇降速度は 0 に向けて減速

	move_and_slide() # 現在の velocity (加速度)で移動して、衝突などの相互作用も行います。
	platform_velocity = get_platform_velocity() # のっている地形に加速度を更新します。move_and_slide() 後に有効です。
	return

テスト

F5 / F6 キーでタイルマップと操作キャラを配置したシーンを実行します。

はしごにぎりぎり触れている状態でさらに上に移動しようとすると、その入力が無視され、はしごの先端で止まりました。
デバッグ表示の X も表示されています。

Godot4 昇降可能なタイルの上り下りで、次の移動先が昇降可能でない場合に停止する処理のテストSS1

はしごを降りる際も、下側の先端で同様に止まりました。

Godot4 昇降可能なタイルの上り下りで、次の移動先が昇降可能でない場合に停止する処理のテストSS2

以下は、それらを確認した際の動画です。

まとめ

今回は、無料・軽快な 2D / 3D 用のゲームエンジン Godot Engine 4 で、操作キャラクターがタイルマップのはしごのタイルに触れているとき上下キーを押すと上下に昇降する実装をテストすると、はしごの先端でさらに昇降するとはしごを飛び出してしまうので、移動先にはしごがあるかを確認してはしごから飛び出さないスクリプト改良しました。

参照サイト Thank You!

記事一覧 → Compota-Soft-Press

コメント

Ads Blocker Image Powered by Code Help Pro

お願い - Ads Blocker Detected

このサイトは広告を掲載して運営しています。

ポップアップを閉じて閲覧できますが、よろしければ

このサイト内の広告を非表示にする拡張機能をオフにしていただけませんか?

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

We have detected that you are using extensions to block ads. Please support us by disabling these ads blocker.

タイトルとURLをコピーしました