mirror of
https://github.com/Steffo99/nanogolf.git
synced 2024-11-21 23:54:21 +00:00
163 lines
5.1 KiB
GDScript
163 lines
5.1 KiB
GDScript
extends CharacterBody2D
|
|
class_name GolfBall
|
|
|
|
|
|
|
|
@export_category("References")
|
|
|
|
## The [PuttController] that this node should poll.
|
|
@export var putt_controller: PuttController
|
|
|
|
## The [HoleController] that this node should poll.
|
|
@export var hole_controller: HoleController
|
|
|
|
## The [AudioStreamPlayer2D] that this node should play when entering the hole.
|
|
@export var hole_sound: AudioStreamPlayer2D
|
|
|
|
## The [Label] where the name of this player should be displayed.
|
|
@export var player_label: Label
|
|
|
|
|
|
|
|
@export_category("Physics")
|
|
|
|
## Dynamic friction subtracted from the body's velocity on each physics step.
|
|
@export var physics_friction: float
|
|
|
|
## The maximum number of bounces that the collision algorithm will consider in a single physics step.
|
|
@export var physics_max_bounces: float
|
|
|
|
## A multiplier applied to the body's velocity every time it collides with something.
|
|
@export var physics_bounce_coefficient: float
|
|
|
|
## The scene to instantiate to play the collision sound
|
|
@export var collision_sound: PackedScene
|
|
|
|
|
|
|
|
@export_category("Sounds")
|
|
|
|
## Curve mapping relative putt power to putt sound volume.
|
|
@export var collision_volume_db: Curve
|
|
|
|
## The velocity at which the maximum volume of [member collision_volume_db] is played.
|
|
@export var collision_volume_max_velocity: float
|
|
|
|
|
|
## Emitted when the ball enters the hole.
|
|
signal entered_hole(strokes: int)
|
|
|
|
|
|
## How many strokes have been performed so far.
|
|
var strokes: int = 0
|
|
|
|
## Whether the ball has entered the hole.
|
|
var in_hole: bool = false
|
|
|
|
|
|
## The name of the player represented by this scene.
|
|
var player_name: String = "Player":
|
|
get:
|
|
return player_name
|
|
set(value):
|
|
player_name = value
|
|
if player_label:
|
|
player_label.text = value
|
|
|
|
## The color of the player represented by this scene.
|
|
var player_color: Color = Color.WHITE:
|
|
get:
|
|
return player_color
|
|
set(value):
|
|
player_color = value
|
|
modulate = value
|
|
|
|
|
|
func _on_putt(putt_vector: Vector2) -> void:
|
|
strokes += 1
|
|
velocity += putt_vector
|
|
|
|
|
|
func do_movement(delta: float) -> void:
|
|
# How much the body should move in this physics step.
|
|
var movement = velocity * delta
|
|
# How many times the body collided in the current physics step.
|
|
var bounces: int = 0
|
|
# While the body should still move some space, and it isn't stuck in a perpetual loop of bouncing...
|
|
while movement.length() > 0.0 and bounces < physics_max_bounces:
|
|
# Try to move!
|
|
var collision: KinematicCollision2D = move_and_collide(movement)
|
|
# If the body did not collide and performed its full movement, we're done!
|
|
if not collision:
|
|
break
|
|
# Let's try to handle the collision properly
|
|
bounces += 1
|
|
# Determine the normal of the collision (the direction the body should be pushed back in)
|
|
var collision_normal = collision.get_normal()
|
|
# Play the collision sound
|
|
if bounces == 1:
|
|
# Determine with how much speed the body collided
|
|
var collision_velocity = -collision_normal.dot(velocity)
|
|
# Create a new sound instance
|
|
var collision_sound_instance: AudioStreamPlayer2D = collision_sound.instantiate()
|
|
# Set the sound volume based on the relative collision velocity
|
|
collision_sound_instance.volume_db = min(0, collision_volume_db.sample(collision_velocity / collision_volume_max_velocity))
|
|
# Add the sound to the SceneTree so it starts playing
|
|
$"..".add_child(collision_sound_instance)
|
|
# Set the sound's global position to the current global position of the body
|
|
collision_sound_instance.global_position = global_position
|
|
# Change the velocity adequately
|
|
velocity = velocity.bounce(collision_normal)
|
|
# Reflect the remaining movement
|
|
movement = collision.get_remainder().bounce(collision_normal)
|
|
# If we collided with something in this step, we need to apply the bounce coefficient
|
|
if bounces > 0:
|
|
velocity *= physics_bounce_coefficient
|
|
|
|
|
|
## Reduce [field velocity] by [field physics_friction], taking the [param delta] into account.
|
|
func apply_friction(delta: float) -> void:
|
|
var new_velocity_length = max(0.0, velocity.length() - physics_friction * delta)
|
|
velocity = velocity.normalized() * new_velocity_length
|
|
|
|
|
|
## Return whether this object can be considered stopped or not.
|
|
func check_has_stopped() -> bool:
|
|
return velocity.length() == 0.0
|
|
|
|
## Return whether this object will enter the hole on this frame or not.
|
|
func check_has_entered_hole() -> bool:
|
|
return check_has_stopped() and hole_controller.over_hole
|
|
|
|
|
|
@rpc("authority", "call_local", "reliable")
|
|
func rpc_sync_enter_hole():
|
|
in_hole = true
|
|
visible = false
|
|
hole_sound.play()
|
|
entered_hole.emit(strokes)
|
|
Log.peer(self, "Entered hole in: %d" % strokes)
|
|
|
|
|
|
|
|
# FIXME: What happens on the server?
|
|
## Push this object's [field global_position] to all other clients.
|
|
@rpc("authority", "call_remote", "unreliable_ordered")
|
|
func rpc_sync_global_position(nposition: Vector2):
|
|
global_position = nposition
|
|
|
|
|
|
func _ready() -> void:
|
|
player_label.text = player_name
|
|
|
|
|
|
func _physics_process(delta) -> void:
|
|
if is_multiplayer_authority():
|
|
if not in_hole:
|
|
do_movement(delta)
|
|
rpc_sync_global_position.rpc(global_position)
|
|
apply_friction(delta)
|
|
if check_has_entered_hole():
|
|
rpc_sync_enter_hole.rpc()
|
|
if check_has_stopped():
|
|
putt_controller.can_putt = true
|