Initial 3d controller and pawn
This commit is contained in:
@ -87,6 +87,46 @@ toggle_wiring_panel={
|
||||
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":true,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":70,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
|
||||
]
|
||||
}
|
||||
move_left_3d={
|
||||
"deadzone": 0.2,
|
||||
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":65,"key_label":0,"unicode":97,"location":0,"echo":false,"script":null)
|
||||
]
|
||||
}
|
||||
move_right_3d={
|
||||
"deadzone": 0.2,
|
||||
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":68,"key_label":0,"unicode":100,"location":0,"echo":false,"script":null)
|
||||
]
|
||||
}
|
||||
move_forward_3d={
|
||||
"deadzone": 0.2,
|
||||
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":87,"key_label":0,"unicode":119,"location":0,"echo":false,"script":null)
|
||||
]
|
||||
}
|
||||
move_backward_3d={
|
||||
"deadzone": 0.2,
|
||||
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":83,"key_label":0,"unicode":115,"location":0,"echo":false,"script":null)
|
||||
]
|
||||
}
|
||||
roll_right_3d={
|
||||
"deadzone": 0.2,
|
||||
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":69,"key_label":0,"unicode":101,"location":0,"echo":false,"script":null)
|
||||
]
|
||||
}
|
||||
roll_left_3d={
|
||||
"deadzone": 0.2,
|
||||
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":81,"key_label":0,"unicode":113,"location":0,"echo":false,"script":null)
|
||||
]
|
||||
}
|
||||
interact_3d={
|
||||
"deadzone": 0.2,
|
||||
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":70,"key_label":0,"unicode":102,"location":0,"echo":false,"script":null)
|
||||
]
|
||||
}
|
||||
spacebar_3d={
|
||||
"deadzone": 0.2,
|
||||
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":32,"key_label":0,"unicode":32,"location":0,"echo":false,"script":null)
|
||||
]
|
||||
}
|
||||
|
||||
[layer_names]
|
||||
|
||||
|
||||
31
scenes/tests/3d/player_controller_3d.gd
Normal file
31
scenes/tests/3d/player_controller_3d.gd
Normal file
@ -0,0 +1,31 @@
|
||||
# PlayerController3D.gd
|
||||
extends Node
|
||||
class_name PlayerController3D
|
||||
|
||||
@onready var possessed_pawn: ZeroGPawn = get_parent()
|
||||
|
||||
func _physics_process(_delta):
|
||||
if not is_multiplayer_authority() or not is_instance_valid(possessed_pawn):
|
||||
return
|
||||
|
||||
# 1. Gather Input
|
||||
var move_vec = Input.get_vector("move_left_3d", "move_right_3d", "move_forward_3d", "move_backward_3d")
|
||||
var roll_input = Input.get_action_strength("roll_right_3d") - Input.get_action_strength("roll_left_3d")
|
||||
var interact_pressed = Input.is_action_just_pressed("interact_3d")
|
||||
var interact_released = Input.is_action_just_released("interact_3d") # Send release too
|
||||
|
||||
# 2. Send via RPC
|
||||
server_process_input.rpc_id(1, move_vec, roll_input, interact_pressed, interact_released)
|
||||
|
||||
|
||||
@rpc("any_peer", "call_local")
|
||||
func server_process_input(move: Vector2, roll: float, interact_p: bool, interact_r: bool):
|
||||
if is_instance_valid(possessed_pawn):
|
||||
possessed_pawn.set_movement_input(move, roll)
|
||||
possessed_pawn.set_interaction_input(interact_p, interact_r)
|
||||
|
||||
|
||||
func possess(pawn_to_control: ZeroGPawn):
|
||||
possessed_pawn = pawn_to_control
|
||||
# You might want reparenting logic here depending on your scene structure
|
||||
print("PlayerController3D possessed: ", possessed_pawn.name)
|
||||
1
scenes/tests/3d/player_controller_3d.gd.uid
Normal file
1
scenes/tests/3d/player_controller_3d.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://vjfk3xnapfti
|
||||
27
scenes/tests/3d/zero_g_3d_test.tscn
Normal file
27
scenes/tests/3d/zero_g_3d_test.tscn
Normal file
@ -0,0 +1,27 @@
|
||||
[gd_scene load_steps=4 format=3 uid="uid://ddfsn0rtdnfda"]
|
||||
|
||||
[ext_resource type="PackedScene" uid="uid://7yc6a07xoccy" path="res://scenes/tests/3d/zero_g_pawn.tscn" id="1_nvgim"]
|
||||
|
||||
[sub_resource type="BoxMesh" id="BoxMesh_kateb"]
|
||||
size = Vector3(10, 1, 10)
|
||||
|
||||
[sub_resource type="BoxShape3D" id="BoxShape3D_25xtv"]
|
||||
size = Vector3(10, 1, 10)
|
||||
|
||||
[node name="ZeroG3DTest" type="Node3D"]
|
||||
|
||||
[node name="WorldEnvironment" type="WorldEnvironment" parent="."]
|
||||
|
||||
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="."]
|
||||
transform = Transform3D(0.743413, -0.535317, 0.400964, 0, 0.599499, 0.800376, -0.668832, -0.59501, 0.445675, 0, 0, 0)
|
||||
|
||||
[node name="StaticBody3D" type="StaticBody3D" parent="."]
|
||||
|
||||
[node name="MeshInstance3D" type="MeshInstance3D" parent="StaticBody3D"]
|
||||
mesh = SubResource("BoxMesh_kateb")
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="StaticBody3D"]
|
||||
shape = SubResource("BoxShape3D_25xtv")
|
||||
|
||||
[node name="ZeroGPawn" parent="." instance=ExtResource("1_nvgim")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2, 0)
|
||||
149
scenes/tests/3d/zero_g_pawn.gd
Normal file
149
scenes/tests/3d/zero_g_pawn.gd
Normal file
@ -0,0 +1,149 @@
|
||||
# ZeroGPawn.gd
|
||||
extends CharacterBody3D
|
||||
class_name ZeroGPawn
|
||||
|
||||
# --- Movement Parameters ---
|
||||
@export var move_speed: float = 5.0
|
||||
@export var roll_speed: float = 1.0
|
||||
@export var grab_check_distance: float = 1.0 # How close to a surface to attempt grabbing
|
||||
@export var launch_charge_rate: float = 20.0
|
||||
@export var max_launch_speed: float = 15.0
|
||||
|
||||
# --- State ---
|
||||
enum State { FLOATING, GRABBING, CHARGING_LAUNCH }
|
||||
var angular_velocity: Vector3 = Vector3.ZERO
|
||||
var current_state: State = State.FLOATING
|
||||
var grab_surface_normal: Vector3 = Vector3.ZERO # Normal of the surface we're grabbing
|
||||
var launch_direction: Vector3 = Vector3.ZERO
|
||||
var launch_charge: float = 0.0
|
||||
|
||||
# --- Input Buffers (Set by PlayerController3D) ---
|
||||
var _move_input: Vector2 = Vector2.ZERO # (Strafe, Forward/Backward)
|
||||
var _roll_input: float = 0.0
|
||||
var _interact_pressed: bool = false
|
||||
var _interact_released: bool = false
|
||||
|
||||
@onready var grab_ray: RayCast3D = $GrabRay # We'll need to add this node
|
||||
|
||||
func _physics_process(delta: float):
|
||||
# --- Update State ---
|
||||
_update_state()
|
||||
|
||||
# --- Apply Movement Based on State ---
|
||||
match current_state:
|
||||
State.FLOATING:
|
||||
_apply_floating_movement(delta)
|
||||
_handle_grab_attempt()
|
||||
State.GRABBING:
|
||||
_handle_grabbed_state(delta)
|
||||
State.CHARGING_LAUNCH:
|
||||
_handle_launch_charge(delta)
|
||||
|
||||
# --- Apply Velocity ---
|
||||
# In 3D, CharacterBody3D doesn't have move_and_slide for velocity directly.
|
||||
# We'll manage velocity manually for zero-G.
|
||||
position += velocity * delta
|
||||
|
||||
# --- Reset Inputs ---
|
||||
_move_input = Vector2.ZERO
|
||||
_roll_input = 0.0
|
||||
_interact_pressed = false
|
||||
_interact_released = false
|
||||
|
||||
|
||||
func _update_state():
|
||||
match current_state:
|
||||
State.FLOATING:
|
||||
if _interact_pressed:
|
||||
# Attempt to grab if near a surface
|
||||
if _check_for_grab_surface():
|
||||
current_state = State.GRABBING
|
||||
velocity = Vector3.ZERO # Stop movement instantly
|
||||
angular_velocity = Vector3.ZERO # Stop rotation instantly
|
||||
print("State: GRABBING")
|
||||
State.GRABBING:
|
||||
if _interact_released:
|
||||
current_state = State.FLOATING
|
||||
print("State: FLOATING (Released Grab)")
|
||||
elif _move_input != Vector2.ZERO: # Holding direction + interact
|
||||
current_state = State.CHARGING_LAUNCH
|
||||
launch_direction = (transform.basis.z * -_move_input.y + transform.basis.x * _move_input.x).normalized()
|
||||
launch_charge = 0.0
|
||||
print("State: CHARGING_LAUNCH")
|
||||
State.CHARGING_LAUNCH:
|
||||
if _interact_released:
|
||||
_execute_launch()
|
||||
current_state = State.FLOATING
|
||||
print("State: FLOATING (Launched)")
|
||||
elif _move_input == Vector2.ZERO: # Released direction while still holding interact
|
||||
current_state = State.GRABBING # Go back to just grabbing
|
||||
print("State: GRABBING (Cancelled Launch Charge)")
|
||||
|
||||
|
||||
func _apply_floating_movement(delta: float):
|
||||
# Apply linear velocity based on input relative to orientation
|
||||
var move_dir = (transform.basis.z * -_move_input.y + transform.basis.x * _move_input.x).normalized()
|
||||
velocity += move_dir * move_speed * delta
|
||||
|
||||
# Apply angular velocity for roll
|
||||
# Note: Managing 3D angular velocity directly is complex.
|
||||
# For simplicity, we directly rotate based on input.
|
||||
rotate_object_local(Vector3.FORWARD, _roll_input * roll_speed * delta)
|
||||
|
||||
|
||||
func _handle_grab_attempt():
|
||||
# If interact was pressed this frame AND we are floating
|
||||
if _interact_pressed:
|
||||
if _check_for_grab_surface():
|
||||
current_state = State.GRABBING
|
||||
velocity = Vector3.ZERO
|
||||
angular_velocity = Vector3.ZERO
|
||||
print("State: GRABBING")
|
||||
|
||||
|
||||
func _handle_grabbed_state(delta: float):
|
||||
# While grabbing, stay perfectly still
|
||||
velocity = Vector3.ZERO
|
||||
angular_velocity = Vector3.ZERO
|
||||
|
||||
# Check if starting to charge launch
|
||||
if _move_input != Vector2.ZERO:
|
||||
current_state = State.CHARGING_LAUNCH
|
||||
launch_direction = (transform.basis.z * -_move_input.y + transform.basis.x * _move_input.x).normalized()
|
||||
launch_charge = 0.0
|
||||
print("State: CHARGING_LAUNCH")
|
||||
|
||||
|
||||
func _handle_launch_charge(delta: float):
|
||||
# Increase charge while holding direction
|
||||
launch_charge = min(launch_charge + launch_charge_rate * delta, max_launch_speed)
|
||||
# Still holding interact key, so stay put
|
||||
velocity = Vector3.ZERO
|
||||
angular_velocity = Vector3.ZERO
|
||||
|
||||
|
||||
func _execute_launch():
|
||||
velocity = launch_direction * launch_charge
|
||||
print("Launched with speed: ", launch_charge)
|
||||
launch_charge = 0.0
|
||||
|
||||
|
||||
func _check_for_grab_surface() -> bool:
|
||||
# Use RayCast3D to check in multiple directions or based on movement
|
||||
# For simplicity, let's just check directly forward
|
||||
grab_ray.target_position = Vector3.FORWARD * -grab_check_distance # Ray points forward locally
|
||||
grab_ray.force_raycast_update()
|
||||
if grab_ray.is_colliding():
|
||||
grab_surface_normal = grab_ray.get_collision_normal()
|
||||
# Optional: Align player rotation to surface normal here
|
||||
return true
|
||||
return false
|
||||
|
||||
# --- Public Input Setters ---
|
||||
func set_movement_input(move: Vector2, roll: float):
|
||||
_move_input = move
|
||||
_roll_input = roll
|
||||
|
||||
func set_interaction_input(pressed: bool, released: bool):
|
||||
_interact_pressed = pressed
|
||||
_interact_released = released
|
||||
1
scenes/tests/3d/zero_g_pawn.gd.uid
Normal file
1
scenes/tests/3d/zero_g_pawn.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://buu6a8p00s05p
|
||||
31
scenes/tests/3d/zero_g_pawn.tscn
Normal file
31
scenes/tests/3d/zero_g_pawn.tscn
Normal file
@ -0,0 +1,31 @@
|
||||
[gd_scene load_steps=5 format=3 uid="uid://7yc6a07xoccy"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://buu6a8p00s05p" path="res://scenes/tests/3d/zero_g_pawn.gd" id="1_lm0u7"]
|
||||
[ext_resource type="Script" uid="uid://vjfk3xnapfti" path="res://scenes/tests/3d/player_controller_3d.gd" id="2_r62el"]
|
||||
|
||||
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_6vm80"]
|
||||
|
||||
[sub_resource type="CapsuleMesh" id="CapsuleMesh_6vm80"]
|
||||
|
||||
[node name="ZeroGPawn" type="CharacterBody3D"]
|
||||
script = ExtResource("1_lm0u7")
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
|
||||
shape = SubResource("CapsuleShape3D_6vm80")
|
||||
|
||||
[node name="MeshInstance3D" type="MeshInstance3D" parent="."]
|
||||
mesh = SubResource("CapsuleMesh_6vm80")
|
||||
|
||||
[node name="GrabRay" type="RayCast3D" parent="."]
|
||||
target_position = Vector3(0, 0, -1)
|
||||
collide_with_areas = true
|
||||
debug_shape_custom_color = Color(0.443137, 0, 0, 0.615686)
|
||||
|
||||
[node name="PlayerController3D" type="Node" parent="."]
|
||||
script = ExtResource("2_r62el")
|
||||
metadata/_custom_type_script = "uid://vjfk3xnapfti"
|
||||
|
||||
[node name="Node3D" type="Node3D" parent="."]
|
||||
|
||||
[node name="Camera3D" type="Camera3D" parent="Node3D"]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.5, 2)
|
||||
Reference in New Issue
Block a user