This commit is contained in:
Keisuke Hirata 2026-02-08 17:04:26 +09:00
commit bc132f8e85
11 changed files with 291 additions and 0 deletions

4
.editorconfig Normal file
View File

@ -0,0 +1,4 @@
root = true
[*]
charset = utf-8

2
.gitattributes vendored Normal file
View File

@ -0,0 +1,2 @@
# Normalize EOL for all files that Git considers text files.
* text=auto eol=lf

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
# Godot 4+ specific ignores
.godot/
/android/

65
game.tscn Normal file
View File

@ -0,0 +1,65 @@
[gd_scene format=3 uid="uid://be0hdhgh4p8b2"]
[ext_resource type="Script" uid="uid://d1hs43512acpp" path="res://scripts/camera_targeter.gd" id="1_80nbo"]
[ext_resource type="Script" uid="uid://cwg212lk7rfi2" path="res://scripts/physics_movement.gd" id="2_e2o6t"]
[ext_resource type="Texture2D" uid="uid://cjcpbpcen2su3" path="res://icon.svg" id="3_feb5d"]
[sub_resource type="PhysicsMaterial" id="PhysicsMaterial_e2o6t"]
rough = true
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_mwb40"]
albedo_color = Color(0.26666668, 0.16078432, 0.08627451, 1)
[sub_resource type="BoxMesh" id="BoxMesh_mwb40"]
material = SubResource("StandardMaterial3D_mwb40")
size = Vector3(20, 1, 20)
[sub_resource type="BoxShape3D" id="BoxShape3D_80nbo"]
size = Vector3(20, 1, 20)
[sub_resource type="PhysicsMaterial" id="PhysicsMaterial_feb5d"]
rough = true
bounce = 0.1
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_fc0e3"]
albedo_texture = ExtResource("3_feb5d")
[sub_resource type="SphereMesh" id="SphereMesh_7jktm"]
material = SubResource("StandardMaterial3D_fc0e3")
[sub_resource type="SphereShape3D" id="SphereShape3D_feb5d"]
[node name="Node3D" type="Node3D" unique_id=1911957]
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="." unique_id=207332981]
transform = Transform3D(1, 0, 0, 0, 0.37640214, 0.9264564, 0, -0.9264564, 0.37640214, 0, 10.185568, 1.1867445)
[node name="Camera3D" type="Camera3D" parent="." unique_id=1327314903 node_paths=PackedStringArray("target")]
transform = Transform3D(1, 0, 0, 0, 0.8711967, 0.49093416, 0, -0.49093416, 0.8711967, 0, 6.4932036, 7.1359625)
script = ExtResource("1_80nbo")
target = NodePath("../RigidBody3D")
[node name="StaticBody3D" type="StaticBody3D" parent="." unique_id=751264409]
physics_material_override = SubResource("PhysicsMaterial_e2o6t")
[node name="MeshInstance3D" type="MeshInstance3D" parent="StaticBody3D" unique_id=86151585]
mesh = SubResource("BoxMesh_mwb40")
skeleton = NodePath("../..")
[node name="CollisionShape3D" type="CollisionShape3D" parent="StaticBody3D" unique_id=433263418]
shape = SubResource("BoxShape3D_80nbo")
[node name="RigidBody3D" type="RigidBody3D" parent="." unique_id=779206838 node_paths=PackedStringArray("camera")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 5.177694, 0)
mass = 0.5
physics_material_override = SubResource("PhysicsMaterial_feb5d")
angular_damp = 1.0
script = ExtResource("2_e2o6t")
camera = NodePath("../Camera3D")
[node name="MeshInstance3D" type="MeshInstance3D" parent="RigidBody3D" unique_id=2053654807]
mesh = SubResource("SphereMesh_7jktm")
skeleton = NodePath("../..")
[node name="CollisionShape3D" type="CollisionShape3D" parent="RigidBody3D" unique_id=1975781434]
shape = SubResource("SphereShape3D_feb5d")

1
icon.svg Normal file
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128"><rect width="124" height="124" x="2" y="2" fill="#363d52" stroke="#212532" stroke-width="4" rx="14"/><g fill="#fff" transform="translate(12.322 12.322)scale(.101)"><path d="M105 673v33q407 354 814 0v-33z"/><path fill="#478cbf" d="m105 673 152 14q12 1 15 14l4 67 132 10 8-61q2-11 15-15h162q13 4 15 15l8 61 132-10 4-67q3-13 15-14l152-14V427q30-39 56-81-35-59-83-108-43 20-82 47-40-37-88-64 7-51 8-102-59-28-123-42-26 43-46 89-49-7-98 0-20-46-46-89-64 14-123 42 1 51 8 102-48 27-88 64-39-27-82-47-48 49-83 108 26 42 56 81zm0 33v39c0 276 813 276 814 0v-39l-134 12-5 69q-2 10-14 13l-162 11q-12 0-16-11l-10-65H446l-10 65q-4 11-16 11l-162-11q-12-3-14-13l-5-69z"/><path d="M483 600c0 34 58 34 58 0v-86c0-34-58-34-58 0z"/><circle cx="725" cy="526" r="90"/><circle cx="299" cy="526" r="90"/></g><g fill="#414042" transform="translate(12.322 12.322)scale(.101)"><circle cx="307" cy="532" r="60"/><circle cx="717" cy="532" r="60"/></g></svg>

After

Width:  |  Height:  |  Size: 995 B

44
icon.svg.import Normal file
View File

@ -0,0 +1,44 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://cjcpbpcen2su3"
path.s3tc="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.s3tc.ctex"
metadata={
"imported_formats": ["s3tc_bptc"],
"vram_texture": true
}
[deps]
source_file="res://icon.svg"
dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.s3tc.ctex"]
[params]
compress/mode=2
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0
svg/scale=1.0
editor/scale_with_editor_scale=false
editor/convert_colors_with_editor_theme=false

23
project.godot Normal file
View File

@ -0,0 +1,23 @@
; Engine configuration file.
; It's best edited using the editor UI and not directly,
; since the parameters that go here are not all obvious.
;
; Format:
; [section] ; section goes between []
; param=value ; assign values to parameters
config_version=5
[animation]
compatibility/default_parent_skeleton_in_mesh_instance_3d=true
[application]
config/name="tento-plus-1"
config/features=PackedStringArray("4.6", "Forward Plus")
config/icon="res://icon.svg"
[editor_plugins]
enabled=PackedStringArray("res://addons/flexcam/plugin.cfg")

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)

View File

@ -0,0 +1 @@
uid://d1hs43512acpp

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

View File

@ -0,0 +1 @@
uid://cwg212lk7rfi2