Files
Bullosseum/player.gd
T

159 lines
4.7 KiB
GDScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
extends CharacterBody3D
const WALK_SPEED = 6.0
const CHARGE_SPEED = 180.0
const WALK_ACCEL = 14.0
const CHARGE_ACCEL = 40.0
const DECELERATION = 12.0
const CHARGE_DECEL = 3.5
const WALK_TURN_FAST = 8.0
const WALK_TURN_SLOW = 3.5
const CHARGE_TURN = 0.55
const JUMP_VELOCITY = 4.5
# Hoof positions in bull_v10 local space — tweak y/z if hooves don't line up with the model
const HOOF_OFFSETS: Array = [
Vector3(-0.30, -0.25, -0.50),
Vector3( 0.30, -0.25, -0.50),
Vector3(-0.30, -0.25, 0.60),
Vector3( 0.30, -0.25, 0.60),
]
@export var visual_turn_speed: float = 12.0
@onready var camera_pivot: Node3D = $SpringArmPivot
@onready var cube_guy: Node3D = $bull_v10
var current_speed: float = 0.0
var facing_angle: float = 0.0
var _hoof_emitters: Array[CPUParticles3D] = []
enum _DustState { NONE, WALK, CHARGE }
var _dust_state: _DustState = _DustState.NONE
func _ready() -> void:
_setup_hoof_dust()
func _setup_hoof_dust() -> void:
var mat := StandardMaterial3D.new()
mat.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED
mat.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA
mat.vertex_color_use_as_albedo = true
mat.cull_mode = BaseMaterial3D.CULL_DISABLED
# 4×2 sphere = chunky low-poly diamond shape
var sphere := SphereMesh.new()
sphere.radius = 0.10
sphere.height = 0.20
sphere.radial_segments = 4
sphere.rings = 2
sphere.material = mat
# sand colour, fades to transparent over lifetime
var ramp := Gradient.new()
ramp.set_color(0, Color(0.80, 0.69, 0.46, 1.0))
ramp.set_color(1, Color(0.80, 0.69, 0.46, 0.0))
# puff blooms up then vanishes
var scale_curve := Curve.new()
scale_curve.add_point(Vector2(0.0, 0.2))
scale_curve.add_point(Vector2(0.4, 1.0))
scale_curve.add_point(Vector2(1.0, 0.0))
for offset: Vector3 in HOOF_OFFSETS:
var p := CPUParticles3D.new()
p.position = offset
p.emitting = false
p.amount = 12
p.lifetime = 0.9
p.explosiveness = 0.35
p.randomness = 0.6
p.local_coords = false
p.direction = Vector3(0.0, 1.0, 0.0)
p.spread = 45.0
p.gravity = Vector3(0.0, -1.5, 0.0)
p.initial_velocity_min = 0.8
p.initial_velocity_max = 1.8
p.scale_amount_min = 0.4
p.scale_amount_max = 0.7
p.mesh = sphere
p.color_ramp = ramp
p.scale_amount_curve = scale_curve
cube_guy.add_child(p)
_hoof_emitters.append(p)
func _set_dust_state(new_state: _DustState) -> void:
if new_state == _dust_state:
return
_dust_state = new_state
for p: CPUParticles3D in _hoof_emitters:
match new_state:
_DustState.NONE:
p.emitting = false
_DustState.WALK:
p.scale_amount_min = 0.35
p.scale_amount_max = 0.65
p.initial_velocity_min = 0.8
p.initial_velocity_max = 1.8
p.emitting = true
_DustState.CHARGE:
p.scale_amount_min = 1.0
p.scale_amount_max = 2.2
p.initial_velocity_min = 2.8
p.initial_velocity_max = 5.5
p.emitting = true
func _physics_process(delta: float) -> void:
if not is_on_floor():
velocity += get_gravity() * delta
if Input.is_action_just_pressed("jump") and is_on_floor():
velocity.y = JUMP_VELOCITY
var input_dir := Input.get_vector("move_left", "move_right", "move_forward", "move_back")
var cam_basis := camera_pivot.global_transform.basis
var flat_forward := -Vector3(cam_basis.z.x, 0.0, cam_basis.z.z).normalized()
var flat_right := Vector3(cam_basis.x.x, 0.0, cam_basis.x.z).normalized()
var direction := (flat_forward * -input_dir.y + flat_right * input_dir.x).normalized()
if direction:
var target_angle := atan2(direction.x, direction.z)
if current_speed < 0.01:
facing_angle = target_angle
var charging := Input.is_key_pressed(KEY_SHIFT)
var speed_t: float = clampf(current_speed / WALK_SPEED, 0.0, 1.0)
var turn_rate: float = CHARGE_TURN if charging else lerpf(WALK_TURN_FAST, WALK_TURN_SLOW, speed_t)
var diff := wrapf(target_angle - facing_angle, -PI, PI)
facing_angle += clampf(diff, -turn_rate * delta, turn_rate * delta)
var top_speed: float = CHARGE_SPEED if charging else WALK_SPEED
var accel: float = CHARGE_ACCEL if charging else WALK_ACCEL
current_speed = move_toward(current_speed, top_speed, accel * delta)
else:
var charging := Input.is_key_pressed(KEY_SHIFT)
var decel: float = CHARGE_DECEL if charging else DECELERATION
current_speed = move_toward(current_speed, 0.0, decel * delta)
velocity.x = sin(facing_angle) * current_speed
velocity.z = cos(facing_angle) * current_speed
cube_guy.rotation.y = lerp_angle(cube_guy.rotation.y, facing_angle, delta * visual_turn_speed)
move_and_slide()
var charging := Input.is_key_pressed(KEY_SHIFT)
if current_speed > 0.5 and is_on_floor():
_set_dust_state(_DustState.CHARGE if charging else _DustState.WALK)
else:
_set_dust_state(_DustState.NONE)