This commit is contained in:
2026-02-08 17:04:26 +09:00
commit bc132f8e85
11 changed files with 291 additions and 0 deletions
+74
View File
@@ -0,0 +1,74 @@
extends Camera3D
## ターゲットとなるNode3Dオブジェクト
@export var target: Node3D
## カメラの回転感度
@export var mouse_sensitivity: float = 0.003
## ターゲットからの距離
@export var distance: float = 5.0
## 最小・最大距離
@export var min_distance: float = 2.0
@export var max_distance: float = 20.0
## ズーム速度
@export var zoom_speed: float = 0.5
## 縦方向の回転制限(ラジアン)
@export var min_pitch: float = -PI / 2 + 0.1
@export var max_pitch: float = PI / 2 - 0.1
## マウスボタン(右クリックでカメラ操作)
@export var rotate_button: MouseButton = MOUSE_BUTTON_RIGHT
# 内部変数
var _yaw: float = 0.0 # 水平回転
var _pitch: float = 0.0 # 垂直回転
var _is_rotating: bool = false
func _ready() -> void:
# 初期角度を設定
if target:
var direction = global_position - target.global_position
_yaw = atan2(direction.x, direction.z)
_pitch = asin(direction.y / direction.length())
func _unhandled_input(event: InputEvent) -> void:
# マウスボタンの押下/離す
if event is InputEventMouseButton:
if event.button_index == rotate_button:
_is_rotating = event.pressed
# マウスホイールでズーム
elif event.button_index == MOUSE_BUTTON_WHEEL_UP:
distance = clamp(distance - zoom_speed, min_distance, max_distance)
elif event.button_index == MOUSE_BUTTON_WHEEL_DOWN:
distance = clamp(distance + zoom_speed, min_distance, max_distance)
# マウス移動で回転
elif event is InputEventMouseMotion and _is_rotating:
_yaw -= event.relative.x * mouse_sensitivity
_pitch += event.relative.y * mouse_sensitivity
_pitch = clamp(_pitch, min_pitch, max_pitch)
func _process(_delta: float) -> void:
if not target:
return
# 球面座標系でカメラ位置を計算
var offset = Vector3(
cos(_pitch) * sin(_yaw),
sin(_pitch),
cos(_pitch) * cos(_yaw)
) * distance
# カメラ位置を設定
global_position = target.global_position + offset
# ターゲットを見る
look_at(target.global_position, Vector3.UP)
+1
View File
@@ -0,0 +1 @@
uid://d1hs43512acpp
+73
View File
@@ -0,0 +1,73 @@
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
+1
View File
@@ -0,0 +1 @@
uid://cwg212lk7rfi2