Godot キャラコン 13 「キャラを移動方向に向かせる」
移動方向に向かせるには、atan2(x, z)
という関数を使えばイイという事は分かっているので、スクリプトしていく。ただ結論として言えるのは、向くことは向くが、いきなり向くので見栄えは良くない。もっとスムーズに向きを変えてもらいたいのだが、今のところこんな感じ。アニメーションでなんとかならないかな。
スクリプト
[1]
L29
- 前回、インポートしたdaeを[シーンを追加]ボタンで追加した。アイコンを見ると「Spatial」ノードがルートになっている。これを操れるように変数を用意する。
[2]
L38
- ノードを操れるように代入してるだけ。他のと一緒。
[3]
L69
- 何の面白みもないが、ただ
atan2(x, z)
関数をズバリ使っただけ。 - "my_vel"には自分の進む方向が入っているので、".x"と".z"を持ってきてxz平面で考え、出てきた角度(ラジアン)を".roation.y"でセットしている。
以上。
結果と次回
カクっと180°向き変更。かっこわるい。
スムーズ回転にlerp()
(ラープ)関数を使ってみたが、
yyyy = lerp(yyyy, atan2(my_vel.x, my_vel.z), my_acl) my_body.rotation.y = yyyy
こんな感じ。
(スムーズと言えなくもないが)なんでもかんでも遠回りに回転するので、余計かっこわるい。
今20°で-10°になりたい時、右に30°回ればいいものを、ぐるっと左に330°回るって事。
線形で、ラジアンは0~2パイで動くから、20°から-10°へみたいに0°をまたぐ移行は出来ないよな。当たり前だな。
.
で、何か、スムーズに回転できないものかとネットを探してみたら、Quat
型で回転を制御し、slerp()
(スラープ)という関数を使えば近い方で回ってくれるらしい。
だが、何やってんだかサッパリ分からん。この辺を次回解決したい。
ぺ
extends KinematicBody # マウス var my_mou_sen = 0.003 # マウスセンシ (mouse sensitivity) var my_mou_rel = Vector2(0, 0) # マウスが動いた差分 (mouse relative) # ヘッド (カメラピボット) var my_head # ヘッドノード入れる用 var my_head_ang = 0.0 # ヘッドのうなづき角度(ラジアン) (head angle) var my_head_ang_max = PI / 3.0 # ヘッドのうなづき限界角度(60°) (head angle MAX) # カメラ var my_ray = [0, 1, 2, 3] # RayCast_L, _R, _U, _Dノード入れる用 var my_ray_dis = [5.0, 5.0, 5.0, 5.0] # RayCast_@がヒットした時その場所までの距離 (distance) var my_ray_dis_min = 5.0 # 距離の最小値を入れる用 var my_cam # カメラノード入れる用 var my_cam_dis = 5.0 # ヘッドとカメラまでの標準距離 (camera distance) # プレイヤ var my_dir = Vector3(0, 0, 0) # キー入力での移動方向 (direction) var my_vel = Vector3(0, 0, 0) # 目標移動地点 (velocity) var my_spd = 10.0 # 移動速度 秒速10m (run speed) var my_acl = 0.03 # 加速率 (acceleration) var my_dcl = 0.08 # 減速率 (deceleration) var my_gra = -10.0 # 重力 (gravity) var my_yyy = 0.0 # 現在のy方向の大きさ保管用 # ボディ var my_body # インポートdaeボディーのノード用 func _ready(): my_head = get_node("Spatial_Head") my_ray[0] = get_node("Spatial_Head/RayCast_L") my_ray[1] = get_node("Spatial_Head/RayCast_R") my_ray[2] = get_node("Spatial_Head/RayCast_U") my_ray[3] = get_node("Spatial_Head/RayCast_D") my_cam = get_node("Spatial_Head/Camera_Main") my_body = get_node("Dae_Player") func _input(event): if event is InputEventMouseMotion: my_mou_rel += event.relative func _physics_process(delta): # プレイヤ動かす # キー入力により移動方向をセットする my_dir = Vector3(0, 0, 0) if Input.is_action_pressed("my_forward"): my_dir = my_dir - my_head.global_transform.basis.z if Input.is_action_pressed("my_backward"): my_dir = my_dir + my_head.global_transform.basis.z if Input.is_action_pressed("my_right"): my_dir = my_dir + my_head.global_transform.basis.x if Input.is_action_pressed("my_left"): my_dir = my_dir - my_head.global_transform.basis.x my_dir.y = 0.0 my_dir = my_dir.normalized() # 加速・減速 if my_dir == Vector3(0, 0, 0): my_vel = my_vel.linear_interpolate(Vector3(0, 0, 0), my_dcl) else: my_vel = my_vel.linear_interpolate(my_dir * my_spd, my_acl) # 重力 my_vel.y = my_yyy + my_gra * delta # 移動とy保持 my_yyy = move_and_slide(my_vel).y #ボディーの方向セット my_body.rotation.y = atan2(my_vel.x, my_vel.z) # ヘッド動かす # 横回転 my_head.global_rotate(Vector3(0, 1, 0), -my_mou_rel.x * my_mou_sen) # 縦回転 my_head_ang = my_head_ang - my_mou_rel.y * my_mou_sen my_head_ang = clamp(my_head_ang, -my_head_ang_max, my_head_ang_max) my_head.rotation.x = my_head_ang # マウス移動がない時に勝手に動かない様、0に my_mou_rel = Vector2(0, 0) # 障害物に当たってたらカメラを前に、当たってなければ標準距離に # 当たり判定と距離取得 my_ray_hit(0) # 左レイ判定 my_ray_hit(1) # 右レイ判定 my_ray_hit(2) # 上レイ判定 my_ray_hit(3) # 下レイ判定 # 最小値取得 my_ray_dis_min = my_ray_dis[0] for i in [1, 2, 3]: my_ray_dis_min = min(my_ray_dis_min, my_ray_dis[i]) # カメラ位置セット my_cam.translation = Vector3(0, 0, my_ray_dis_min) func my_ray_hit(i): if my_ray[i].is_colliding(): my_ray_dis[i] = my_ray[i].global_transform.origin.distance_to(my_ray[i].get_collision_point()) else: my_ray_dis[i] = my_cam_dis