extends RigidBody3D ## 移動の基準となるカメラ @export var camera: Camera3D ## 移動加速度 @export var move_force: float = 10.0 ## ジャンプ力 @export var jump_force: float = 8.0 ## 空中での移動制御(0.0-1.0、1.0で地上と同じ) @export var air_control: float = 0.3 ## 地面判定用のレイキャスト距離 @export var ground_check_distance: float = 0.6 # 内部変数 var _is_on_ground: bool = false var _ground_check_ray: RayCast3D func _ready() -> void: # 地面判定用のレイキャストを作成 _ground_check_ray = RayCast3D.new() _ground_check_ray.target_position = Vector3(0, -ground_check_distance, 0) _ground_check_ray.enabled = true add_child(_ground_check_ray) func _physics_process(delta: float) -> void: # レイキャストをグローバル座標系で下向きに固定 _ground_check_ray.global_rotation = Vector3.ZERO # 地面判定 _is_on_ground = _ground_check_ray.is_colliding() # 入力取得 var input_dir = Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down") # カメラ基準の移動方向を計算 var move_direction = _get_camera_relative_direction(input_dir) # 移動力を適用 if move_direction.length() > 0: var control_factor = air_control if not _is_on_ground else 1.0 var force = move_direction * move_force * control_factor apply_central_force(force) # ジャンプ if Input.is_action_just_pressed("ui_accept") and _is_on_ground: linear_velocity.y = jump_force func _get_camera_relative_direction(input_dir: Vector2) -> Vector3: if not camera: # カメラが設定されていない場合はワールド座標基準 return Vector3(input_dir.x, 0, input_dir.y).normalized() # カメラの前方向と右方向を取得(Y軸は無視して水平面に射影) var cam_forward = -camera.global_transform.basis.z cam_forward.y = 0 cam_forward = cam_forward.normalized() var cam_right = camera.global_transform.basis.x cam_right.y = 0 cam_right = cam_right.normalized() # 入力方向をカメラ基準に変換 var direction = (cam_right * input_dir.x + cam_forward * -input_dir.y).normalized() return direction