extends CharacterBody3D # Member variables const QUAKE = 0.0625 const g = -800 * QUAKE const MAX_SPEED = 320 * QUAKE const FRICTION = 4# * QUAKE const STOP_SPEED = 100 * QUAKE const ACCEL= 10# * QUAKE const FORWARD_SPEED = 400 * QUAKE const SIDE_SPEED = 350 * QUAKE const UP_SPEED = 270 * QUAKE # const DEACCEL= 8 # const MAX_SLOPE_ANGLE = 30 @onready var camera = $CSGMesh3D/Camera3D var _paused = false var _noclip = false func _ready(): Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED) func _physics_process(delta): # Shamelessly stolen code from quake :) var fmove = 0.0 var smove = 0.0 var upmove = 0.0 if Input.is_action_pressed("move_forward"): fmove += -FORWARD_SPEED if Input.is_action_pressed("move_backwards"): fmove += FORWARD_SPEED if Input.is_action_pressed("move_left"): smove += -SIDE_SPEED if Input.is_action_pressed("move_right"): smove += SIDE_SPEED if Input.is_action_pressed("jump"): upmove += UP_SPEED if Input.is_action_pressed("run"): fmove *= 2.0 smove *= 2.0 var wishvel = Vector3() var cam_xform: Transform3D = camera.get_global_transform() var cam_basis: Basis = cam_xform.basis wishvel = cam_basis.z * fmove + cam_basis.x * smove if _noclip: wishvel.y += upmove # else: # wishvel.y = upmove var wishdir = wishvel.normalized() var wishspeed = wishvel.length() if wishspeed > MAX_SPEED: wishvel *= MAX_SPEED / wishspeed wishspeed = MAX_SPEED if is_on_floor(): velocity.y += upmove var vel = velocity if _noclip: vel = wishvel elif is_on_floor(): vel = _apply_friction(vel, delta) vel = _apply_accel(vel, wishdir, wishspeed, delta) else: vel = _apply_air_accel(vel, wishvel, wishspeed, delta) if not _noclip: vel.y += g * delta velocity = vel move_and_slide() $Ball.global_position = camera.global_position - camera.global_transform.basis.z * 2.0 func _apply_friction(vel: Vector3, delta: float): var speed = sqrt(vel.x ** 2 + vel.z ** 2) if(speed == 0.0): return vel # TODO: edge detect friction? var friction = FRICTION var control = 0.0 if speed < STOP_SPEED: control = STOP_SPEED else: control = speed var newspeed = speed - delta * control * friction if newspeed < 0.0: newspeed = 0.0 newspeed /= speed return vel * newspeed func _apply_accel(vel: Vector3, wishdir: Vector3, wishspeed: float, delta: float): var currentspeed = vel.dot(wishdir) var addspeed = wishspeed - currentspeed if addspeed <= 0.0: return vel var accelspeed = ACCEL * delta * wishspeed if accelspeed > addspeed: accelspeed = addspeed return vel + accelspeed * wishdir func _apply_air_accel(vel: Vector3, wishvel: Vector3, wishspeed: float, delta: float): var wishveloc = wishvel.normalized() var wishspd = wishvel.length() if wishspd > 30 * QUAKE: wishspd = 30 * QUAKE var currentspeed = vel.dot(wishveloc) var addspeed = wishspd - currentspeed if addspeed <= 0: return vel var accelspeed = ACCEL * wishspeed * delta if accelspeed > addspeed: accelspeed = addspeed return vel + accelspeed * wishveloc func _input(event): if event.is_action_pressed("pause"): _paused = not _paused if _paused: Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE) else: Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED) if _paused: return if event.is_action_pressed('noclip'): _noclip = not _noclip if _noclip: $CollisionShape3D.disabled = true else: $CollisionShape3D.disabled = false # Check for mouse motion input if event is InputEventMouseMotion: rotation.y += -event.relative.x * 0.005 camera.rotation.x += -event.relative.y * 0.005 camera.rotation.x = clamp(camera.rotation.x, deg_to_rad(-70), deg_to_rad(70)) if event.is_action_pressed("interact"): var space_state = get_world_3d().direct_space_state # use global coordinates, not local to node var query = PhysicsRayQueryParameters3D.create(camera.global_position, $Ball.global_position) # Don't collide with ourselves query.exclude = [self] var result = space_state.intersect_ray(query) if result.has('collider'): var other: Node3D = result.collider if other.has_method('interact'): other.interact(self)