mirror of
https://github.com/jcreek/CosmicClash.git
synced 2026-07-12 18:43:49 +00:00
feat(*): Add better ball cam and movement system more like a spaceship
This commit is contained in:
+116
-65
@@ -1,12 +1,23 @@
|
||||
class_name Ship
|
||||
extends RigidBody3D
|
||||
|
||||
var speed = 10.0
|
||||
@export_group("Movement")
|
||||
var max_speed = 15.0
|
||||
var acceleration = 50.0
|
||||
var air_resistance = 0.98
|
||||
var turn_speed = 2.0
|
||||
|
||||
@export_group("Camera")
|
||||
var camera_distance = 8.0
|
||||
var camera_height = 4.0
|
||||
var camera_smoothing = 10.0
|
||||
|
||||
@onready var camera : Camera3D = get_node("Camera3D")
|
||||
@onready var ball = get_parent().get_node("Ball")
|
||||
@onready var timer_label = get_node("HUD/Control/TimerLabel")
|
||||
|
||||
var ball_cam_enabled = true
|
||||
|
||||
func _ready():
|
||||
var game_scene = get_parent()
|
||||
if game_scene and game_scene.has_signal("timer_updated"):
|
||||
@@ -15,73 +26,113 @@ func _ready():
|
||||
else:
|
||||
print("Game scene not found or doesn't have timer_updated signal")
|
||||
|
||||
func _input(event):
|
||||
if event.is_action_pressed("ui_accept"): # Enter key
|
||||
ball_cam_enabled = !ball_cam_enabled
|
||||
|
||||
func _on_timer_updated(minutes: int, seconds: int):
|
||||
timer_label.text = "%02d:%02d" % [minutes, seconds]
|
||||
|
||||
func _physics_process(_delta):
|
||||
if ball and camera:
|
||||
# Adjust the offset based on your scene scale
|
||||
# Increasing Y component to raise the camera higher above the vehicle
|
||||
var offset = Vector3(0, 2, -2) # Adjust Y to change height
|
||||
|
||||
# Position the camera behind and above the vehicle
|
||||
var behind_vehicle = global_transform.origin - global_transform.basis.z * offset.z
|
||||
behind_vehicle += global_transform.basis.y * offset.y
|
||||
|
||||
camera.global_transform.origin = behind_vehicle
|
||||
camera.look_at(ball.global_transform.origin, Vector3.UP)
|
||||
|
||||
func _integrate_forces(state):
|
||||
# input_vector represents the movement input relative to the vehicle
|
||||
var input_vector = get_input_vector()
|
||||
|
||||
# Scale the input_vector by speed
|
||||
input_vector = input_vector.normalized() * speed
|
||||
|
||||
# Set the linear velocity based on the input
|
||||
state.linear_velocity = input_vector
|
||||
|
||||
# Rotate the ship to face the movement direction
|
||||
if input_vector.length() > 0.1: # Only rotate if there's significant movement
|
||||
var target_direction = input_vector.normalized()
|
||||
# Create a transform that looks in the target direction
|
||||
var look_transform = Transform3D()
|
||||
look_transform.origin = global_transform.origin
|
||||
look_transform = look_transform.looking_at(global_transform.origin + target_direction, Vector3.UP)
|
||||
|
||||
# Apply the rotation to the ship
|
||||
state.transform.basis = look_transform.basis
|
||||
|
||||
func get_input_vector() -> Vector3:
|
||||
var input_vector = Vector3.ZERO
|
||||
|
||||
func _physics_process(delta):
|
||||
if camera:
|
||||
var camera_transform = camera.global_transform
|
||||
var forward_direction = -camera_transform.basis.z
|
||||
var right_direction = camera_transform.basis.x
|
||||
var y_movement = input_vector.y
|
||||
_update_camera(delta)
|
||||
|
||||
if Input.is_action_pressed("move_forward"):
|
||||
input_vector += forward_direction
|
||||
if Input.is_action_pressed("move_backward"):
|
||||
input_vector -= forward_direction
|
||||
if Input.is_action_pressed("move_left"):
|
||||
input_vector -= right_direction
|
||||
if Input.is_action_pressed("move_right"):
|
||||
input_vector += right_direction
|
||||
|
||||
# Zero out the Y component to restrict movement to the XZ plane
|
||||
input_vector.y = 0
|
||||
|
||||
# Add back the preserved Y movement
|
||||
input_vector.y = y_movement
|
||||
|
||||
if Input.is_action_pressed("move_up"):
|
||||
input_vector.y += 1
|
||||
if Input.is_action_pressed("move_down"):
|
||||
input_vector.y -= 1
|
||||
|
||||
return input_vector.normalized()
|
||||
func _update_camera(delta):
|
||||
if ball_cam_enabled and ball:
|
||||
_update_ball_cam(delta)
|
||||
else:
|
||||
print("Camera not found")
|
||||
return Vector3.ZERO
|
||||
_update_ship_cam(delta)
|
||||
|
||||
func _update_ball_cam(delta):
|
||||
# In ball cam, camera positions itself so the ship is between camera and ball
|
||||
var ship_pos = global_transform.origin
|
||||
var ball_pos = ball.global_transform.origin
|
||||
|
||||
# Calculate direction from ball to ship
|
||||
var ball_to_ship = (ship_pos - ball_pos).normalized()
|
||||
|
||||
# Position camera behind the ship relative to the ball's position
|
||||
# This ensures the ship is always between the camera and ball
|
||||
var camera_target_pos = ship_pos + ball_to_ship * camera_distance + Vector3.UP * camera_height
|
||||
|
||||
# Smoothly move camera to target position
|
||||
camera.global_transform.origin = camera.global_transform.origin.lerp(camera_target_pos, camera_smoothing * delta)
|
||||
|
||||
# Make camera look at the ball
|
||||
if camera.global_transform.origin.distance_to(ball_pos) > 0.1:
|
||||
# Calculate direction to ball
|
||||
var camera_pos = camera.global_transform.origin
|
||||
var to_ball = (ball_pos - camera_pos).normalized()
|
||||
|
||||
# Create look-at transform manually
|
||||
var camera_transform = Transform3D()
|
||||
camera_transform.origin = camera_pos
|
||||
camera_transform.basis = Basis.looking_at(to_ball, Vector3.UP)
|
||||
|
||||
# Apply the rotation smoothly
|
||||
camera.global_transform.basis = camera.global_transform.basis.slerp(camera_transform.basis, camera_smoothing * delta)
|
||||
|
||||
func _update_ship_cam(delta):
|
||||
# In ship cam, camera follows and looks in the same direction as the ship
|
||||
var ship_pos = global_transform.origin
|
||||
var ship_forward = -global_transform.basis.z
|
||||
|
||||
# Position camera behind and above the ship
|
||||
var camera_target_pos = ship_pos - ship_forward * camera_distance + Vector3.UP * camera_height
|
||||
|
||||
# Smoothly move camera
|
||||
camera.global_transform.origin = camera.global_transform.origin.lerp(camera_target_pos, camera_smoothing * delta)
|
||||
|
||||
# Make camera look in the same direction as the ship
|
||||
var look_target = ship_pos + ship_forward * 10.0 # Look ahead of the ship
|
||||
camera.look_at(look_target, Vector3.UP)
|
||||
|
||||
func _integrate_forces(state):
|
||||
# Get input in ship's local coordinate system
|
||||
var input = get_ship_input()
|
||||
|
||||
# Apply forces based on ship's orientation
|
||||
if input.length() > 0.01:
|
||||
var ship_forward = -global_transform.basis.z
|
||||
var ship_right = global_transform.basis.x
|
||||
|
||||
# Calculate movement direction based on ship orientation
|
||||
var movement_dir = Vector3.ZERO
|
||||
movement_dir += ship_forward * input.z # Forward/backward
|
||||
movement_dir += ship_right * input.x # Left/right
|
||||
movement_dir.y += input.y # Up/down
|
||||
|
||||
# Apply acceleration force
|
||||
var target_velocity = movement_dir.normalized() * max_speed
|
||||
var velocity_diff = target_velocity - state.linear_velocity
|
||||
var force = velocity_diff * acceleration * mass
|
||||
|
||||
state.apply_central_force(force)
|
||||
|
||||
# Turn the ship to face movement direction (only if moving horizontally)
|
||||
var horizontal_movement = Vector3(movement_dir.x, 0, movement_dir.z)
|
||||
if horizontal_movement.length() > 0.1:
|
||||
var target_transform = global_transform.looking_at(global_transform.origin + horizontal_movement, Vector3.UP)
|
||||
state.transform.basis = state.transform.basis.slerp(target_transform.basis, turn_speed * state.step)
|
||||
|
||||
# Apply air resistance
|
||||
state.linear_velocity *= air_resistance
|
||||
|
||||
func get_ship_input() -> Vector3:
|
||||
var input = Vector3.ZERO
|
||||
|
||||
# Get input as if controlling a ship (forward/backward/left/right relative to ship)
|
||||
if Input.is_action_pressed("move_forward"):
|
||||
input.z += 1.0
|
||||
if Input.is_action_pressed("move_backward"):
|
||||
input.z -= 1.0
|
||||
if Input.is_action_pressed("move_left"):
|
||||
input.x -= 1.0
|
||||
if Input.is_action_pressed("move_right"):
|
||||
input.x += 1.0
|
||||
if Input.is_action_pressed("move_up"):
|
||||
input.y += 1.0
|
||||
if Input.is_action_pressed("move_down"):
|
||||
input.y -= 1.0
|
||||
|
||||
return input
|
||||
|
||||
Reference in New Issue
Block a user