75 lines
2.0 KiB
GDScript
75 lines
2.0 KiB
GDScript
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)
|