歩いた時の土煙的なエフェクトを作ってみたい!【Godot 4.7】

カテゴリ: Godot

よくあるキャラクターが歩いた後にぽつぽつと出る土煙みたいなエフェクトを作ってみたいのです。

前にAIさんに線香花火のエフェクトを作ってもらったときに使っていた「パーティクル」を使えば多分それっぽくできるのでは!?!と思っているのでね!!!

やってみよう

https://docs.godotengine.org/en/stable/tutorials/2d/particle_systems_2d.html

ということでまずは初めて公式のパーティクルのチュートリアルページを眺めました(ついでに2Dカテゴリの記事もザーッと見た感じ。色々学びたくて見ている部分は多いからね)

alt text

でとりあえずサクサクっと移動できるキャラクターに上に上がっていくだけのパーティクルをつけてみましたが・・・

うーん・・・観察して違和感を見つけていきましょう・・・

  • 移動していないときにも出ている
    • まぁ、これはただパーティクルをくっつけただけだからね。スクリプトで調整していきましょう
    • ついでに空中にいるときにも出ているのも違和感だよね
  • 煙の形状
    • ほぼ円形になって入るのが違和感?
    • 実際の動きを考えても、地面に沿って煙は出るはずだから半球状?まあぁ地面に接している側が丸い感じなのが違和感なのだろうか?
    • でかい?
    • 円形のものと半円のものを別で出したらいいかな?半円寄りのもの?は地面を這うような感じで出ていって、円形のものは煙的なイメージのモノ
  • 出し方
    • どこまでできるかなぁ・・・歩き初めにぼぼってちょっと溜まって出て、そこからはポツポツと出る感じがイメージに近いのだろうか?
      • それでいうと、最初の方のエフェクトのサイズは少し大きめで、そのあとのぽつぽつ出る感じのものは小さめになるイメージかも

というかエフェクトって本当にこういうパーティクルを利用する方式が一般的なんだろうか?それ以外の方法とかってどういうのがあるのだろうか??

残留の仕方みたいなのも調整できたら良さそうな感じかなぁ・・・

ちょっと変えてみた

少し変えてみました!!!

  • ふたつのノードにエフェクトを分けてみました
    • 一つは丸で上に浮上する感じのモノ
    • 一つは地面を這う感じのモノ
  • 時間経過と共に消えていくようにしました!
    • これが面白い!
    • Color Curves内のAlppha Curveの設定で、Curveを設定することで、時間経過していった際の透過度を指定することができるのですね!!
  • 後は上に上がっていくものに関して、サイズがランダムになってくれないかなぁという気持ちでDisplayのScaleのminとmax値を変更してみました

後はこれをコード側からいい感じに使えないかなぁ~といった感じですね!!!

ってことでコードも書いてみました。

dust_effect.gdっていうのを作ってあげて、それで出すタイミングとかを調整してみました。

dust_effect.gd
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
extends Node2D

@onready var rising_smoke: GPUParticles2D = $RisingSmoke
@onready var crawling_smoke: GPUParticles2D = $CrawlingSmoke

# エフェクトの方向の初期値を設定
@onready var rising_smoke_gravity_direction: Vector3 = rising_smoke.get_process_material().get_gravity()
@onready var crawling_smoke_gravity_direction: Vector3 = crawling_smoke.get_process_material().get_gravity()

# エフェクト反転方向の値を設定
@onready var converted_rising_smoke_gravity_direction: Vector3 = rising_smoke_gravity_direction * Vector3(-1, 1, 1)
@onready var converted_crawling_smoke_gravity_direction: Vector3 = crawling_smoke_gravity_direction * Vector3(-1, 1, 1)

# キャラクターが動いているかどうかを取得する
var is_charactor_moving = false

# キャラクター呼び出す。キャラクタの動き止まったことを示す。
func charactor_move_stop() -> void:
	is_charactor_moving = false
	# 常時排出(上に上がっていくものを停止する)
	rising_smoke.set_emitting(false)

func emission_effect(charactor_direction_fliped: bool) -> void:
	# 前の移動状態を取得する
	var before_is_charactor_moving = is_charactor_moving
	
	# 移動状態更新する
	is_charactor_moving = true
	
	# キャラクター移動方向合わせてエフェクト方向を調整する
	if charactor_direction_fliped:
		# キャラクタが逆方向に進んでいるのでエフェクト向きも反転させる
		rising_smoke.get_process_material().set_gravity(converted_rising_smoke_gravity_direction) 
		crawling_smoke.get_process_material().set_gravity(converted_crawling_smoke_gravity_direction)
	else:
		rising_smoke.get_process_material().set_gravity(rising_smoke_gravity_direction) 
		crawling_smoke.get_process_material().set_gravity(crawling_smoke_gravity_direction)
	
	# 上に上がっていく煙の排出行われていなかったら行うように更新する
	if rising_smoke.is_emitting() == false:
		rising_smoke.set_emitting(true)
	
	# 前と移動状態が切り替わっていたら這う煙を排出する
	if before_is_charactor_moving != is_charactor_moving:
		crawling_smoke.set_emitting(true)
		
player.gd
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
func _physics_process(delta: float) -> void:
	# Add the gravity.
	if not is_on_floor():
		velocity += get_gravity() * delta

	# Handle jump.
	if Input.is_action_just_pressed("ui_accept") and is_on_floor():
		velocity.y = JUMP_VELOCITY

	# 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")
	if direction:
		velocity.x = direction * SPEED
		anim.play("run")
		anim.flip_h = direction > 0
		if is_on_floor():
			# エフェクトを出す
			var fliped_charactor = direction < 0
			dust_effect.emission_effect(fliped_charactor)
	else:
		velocity.x = move_toward(velocity.x, 0, SPEED)
		# エフェクト止める
		dust_effect.charactor_move_stop()
		if is_on_floor():
			anim.play("idle")

とりあえずplayer側はこんな感じ。動いているかどうか~に合わせてエフェクトの方のメソッドを読んでいっている感じですね~~

alt text

う~~~ん・・・まだ微妙な感じがするけど・・・

まぁ一旦こんな感じですね!!!なんかドキュメントを真面目に眺めながらプログラミングをするの久しぶりな気がしますね!Godotはサクッとドキュメントを開くことができて良さげかも・・・