2021-08-21 Godot Engine > ナッツ&ミルクのはしごのようなものを実装

### 動作環境

```
Windows 10 Pro v21H1
Godot Engine v3.3.2.stable.official
```

### 参考

- Best way to detect collisions
    - https://godotforums.org/discussion/25828/best-way-to-detect-collisions
- KinematicBody2Dの使用
    - https://docs.godotengine.org/ja/stable/tutorials/physics/using_kinematic_body_2d.html

### 概要

- ジャンプができるエリア型の実装
    - 重力で落ちる
- ナッツ&ミルクのようなはしご
    - はしご接触時には重力落下をオフにする


### シーン

- Node2D
    - Area2D : はしご
        - CollisionShap2D
        - AnimatedSprite : はしご画像
    - KinemticBody2D : プレイヤー
        - AnimatedSprite
        - CollisionShap2D
    - TileMap : 地面

### キャラクタ操作

- 左、右カーソル : 横方向移動
- スペースキー : ジャンプ

### 実装

プレイヤーにアタッチしたスクリプト

```python:Player.gd
extends KinematicBody2D

export (int) var run_speed = 200
export (int) var gravity = 1000
export (int) var jump_speed = -400

var velocity = Vector2()
var jumping = false
var area_entered = false  # はしご接触中

onready var area = get_node("../Area2D")  # はしご

func _ready():
	pass # Replace with function body.
	
func get_input():
	velocity.x = 0
	var right = Input.is_action_pressed("ui_right")
	var left = Input.is_action_pressed("ui_left")
	var jump = Input.is_action_just_pressed("ui_accept")

	# はしごに接触しているか検知
	var isOverlap = false
	for body in area.get_overlapping_bodies():  # Area2DにPlayerが入ったことを検知
		isOverlap = true
	if isOverlap:
		area_entered = true
	else:
		area_entered = false

	# その他の処理
	if jump and is_on_floor():
		jumping = true
		velocity.y = jump_speed	
	if right:
		velocity.x += run_speed
	if left:
		velocity.x -= run_speed

func _physics_process(delta):
	get_input()	
	if area_entered:  # はしご接触中
		velocity.y = 0.0
	else:
		velocity.y += gravity * delta
	if jumping and is_on_floor():
		jumping = false
	velocity = move_and_slide(velocity, Vector2(0, -1))
```

### 実行結果

ジャンプしてはしごに乗った状態

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32870/45ba0676-dc27-94c3-bd3d-e5cc97e74910.png)


### 備考

ナッツ&ミルクにははしごの上下移動もあるけど、今回は未実装。処理は複雑ではない。


### はしご上下実装

上下移動を実装した。あまり良い実装ではない（備忘録）。

```python:Player.gd
extends KinematicBody2D

export (int) var run_speed = 200
export (int) var gravity = 1000
export (int) var jump_speed = -400

enum {
	YDIR_FALL = 0,
	YDIR_STOP,
	YDIR_UP,
	YDIR_DOWN,
}
var velocity = Vector2()
var jumping = false
var area_entered = false  # はしご接触中
var ydir_type = YDIR_FALL

onready var area = get_node("../Area2D")  # はしご


func _ready():
	pass # Replace with function body.
	
func get_input():
	velocity.x = 0
	var right = Input.is_action_pressed("ui_right")
	var left  = Input.is_action_pressed("ui_left")
	var up    = Input.is_action_pressed("ui_up")
	var down  = Input.is_action_pressed("ui_down")
	var jump  = Input.is_action_just_pressed("ui_accept")

	# はしごに接触しているか検知
	var isOverlap = false
	for body in area.get_overlapping_bodies():  # Area2DにPlayerが入ったことを検知
		isOverlap = true
	if isOverlap:
		area_entered = true
	else:
		area_entered = false

	# その他の処理
	if jump and is_on_floor():
		jumping = true
		velocity.y = jump_speed	
	if right:
		velocity.x += run_speed
	if left:
		velocity.x -= run_speed
	if area_entered:
		ydir_type = YDIR_STOP
		if up:
			ydir_type = YDIR_UP
		if down:
			ydir_type = YDIR_DOWN
	else:
		ydir_type = YDIR_FALL	

func _physics_process(delta):
	get_input()	
	if ydir_type == YDIR_STOP:  # はしご接触中
		velocity.y = 0.0
	elif ydir_type == YDIR_UP:
		velocity.y -= run_speed * delta
	elif ydir_type == YDIR_DOWN:
		velocity.y += run_speed * delta
	else:
		velocity.y += gravity * delta
	if jumping and is_on_floor():
		jumping = false
	velocity = move_and_slide(velocity, Vector2(0, -1))
```