Use this space for questions related to what you're learning. For any other type of support (website, learning platform, payments, etc...) please get in touch using the contact form.
Finishing toucheseelSkillzAt this point in the code, the bouncer continues to pursue the player, even after crossing the finish line, so I added an extra function `stop` to the `res://lessons/bouncer.gd`.
```gdscript
# ...
func stop():
set_physics_process(false)
_runner_visual.animation_name = RunnerVisual.Animations.IDLE
```
and an extra line of code in the `res://lessons/game.gd`.
```gdscript
# ...
func _ready() -> void:
# ...
finish_line.body_entered.connect(func (body: Node) -> void:
if body is not Runner:
return
bouncer.stop() # This is the extra line
# ...
```
At first I simply used the `bouncer.set_physics_process(false)`, but that left the `bouncer` in the running animation, which looked weird.
P.S.: Subject line pun intended.31Dec. 11, 2024
Wow this so good!CelsLast month, I decided to step back from programming entirely. I felt overwhelmed and realized I didn’t yet have the knowledge or skills to create a full game. It was a tough decision, but taking that time off gave me clarity. Now, after reflection and learning, all the pieces have finally come together. I feel ready to move forward, and this is exactly the codes I needed to continue my journey as a game developer. Thanks a lot and make more11Nov. 28, 2024
Internal raycast collisionsMarcJJust FYI, I was getting odd movements from the avoidance force logic until I noticed the code in the completed bounder.gd in the _ready function at line 22
```gdscript
for raycast: RayCast2D in _raycasts.get_children():
raycast.add_exception(self)
```
I know the callout box "[Raycasts collide with nodes from the same scene by default!](https://school.gdquest.com/courses/learn_2d_gamedev_godot_4/top_down_movement/smarter_bouncer#)" mentions this, but it also says that raycasts shouldn't collide internally by default.91Nov. 12, 2024
Problem With adding the runner as an exceptionpikminfan71Hello, When I try to add The Runner as an exception it gives me the error: res://lessons/bouncer.gd:55 - Parse Error: Invalid argument for "add_exception()" function: argument 1 should be "CollisionObject2D" but is "PackedScene".
I don't really quite understand why and how to fix it and would love some help. thank you in advance!
extends CharacterBody2D
@export var current_max_speed := 250.0
@export var max_speed := 600.0
@export var acceleration := 1200.0
@export var deceleration := 1080.0
@export var avoidance_strength := 21000.0
@onready var _runner_visual: RunnerVisual = %RunnerVisualPurple
@onready var dust: GPUParticles2D = %Dust
@onready var hit_box: Area2D = %HitBox
@onready var raycasts: Node2D = %Raycasts
@onready var runner: PackedScene = preload("res://lessons/runner.tscn")
func _ready() -> void:
hit_box.body_entered.connect(func(body: Node):
if body == get_tree().root.get_node("Game/Runner"):
get_tree().call_deferred("reload_current_scene"))
func _physics_process(delta: float) -> void:
var direction := global_position.direction_to(get_global_player_position())
var distance := global_position.distance_to(get_global_player_position())
var desired_velocity := max_speed * direction
desired_velocity += calculate_avoidance_force() * delta
velocity = velocity.move_toward(desired_velocity, current_max_speed * delta)
if velocity.length() > 10.0:
_runner_visual.angle = rotate_toward(_runner_visual.angle, direction.orthogonal().angle(), 8.0 * delta)
raycasts.rotation = _runner_visual.angle
var current_speed := velocity.length() / max_speed
_runner_visual.animation_name = (
RunnerVisual.Animations.WALK
if current_speed < 0.8
else RunnerVisual.Animations.RUN
)
dust.emitting = true
else:
_runner_visual.animation_name = RunnerVisual.Animations.IDLE
dust.emitting = false
move_and_slide()
func get_global_player_position() -> Vector2:
return get_tree().root.get_node("Game/Runner").global_position
func set_animation_to_idle() -> void:
_runner_visual.animation_name = RunnerVisual.Animations.IDLE
dust.emitting = false
func calculate_avoidance_force() -> Vector2:
var avoidance_force := Vector2.ZERO
for raycast: RayCast2D in raycasts.get_children():
raycast.add_exception(runner)
if raycast.is_colliding():
var collision_position := raycast.get_collision_point()
var direction_away_from_obstacle := collision_position.direction_to(raycast.global_position)
var ray_length := raycast.target_position.length()
var intensity := 1.0 - collision_position.distance_to(raycast.global_position) / ray_length
var force := direction_away_from_obstacle * avoidance_strength * intensity
avoidance_force += force
return avoidance_force
30Jan. 18, 2025
This is a very fun and interesting lesson!AJ StudiosI've been having fun playing around with Raycasts in this lesson. I decided to take on the challenge that states: "Going Further"
- **Reversed logic:** We push the bouncer away from the obstacle if rays are colliding. Instead, another approach is to use the rays to determine in which direction the bouncer should move. In this variant, each ray represents a potential movement direction. If a ray is colliding, the bouncer should ignore that potential direction and move in the opposite direction.
Even though I have not been able to figure this out I've been having fun! Logically I understand what I have to do based on the description above. Programmatically I'm lost since everything I've tried so far is not correct (I get constant errors). In other words I'm having trouble with the syntax. I tried setting the following variables:
```gdscript
@onready var raycast_collided := _raycasts.get_collision_point().direction_to(_raycasts.global_position)
@onready var bouncer_new_direction := raycast_collided
```
This is so I can call `bouncer_new_direction` in the `calculate_avoidance_force()` function (since the for loop checks for raycast collisions) so if any of the raycast rays collide with an obstacle, then I can use the `rotate_toward()` function in the `_physics_process()` function to rotate the bouncer in the opposite direction. (this is the logic in my head) However, I got a error at the top of the script: Cannot infer the type of "raycast_collided" variable because the value doesn't have a set type.
I know this logic doesn't make sense and Godot doesn't understand it so I would like some help here to help me understand how to write the code and refactor if needed.
Note: even if I still don't fully understand the syntax in order to write the logic I love the challenge to think and come up with solutions to achieve the goal. I think I'm liking programming more little by little. Anyway, thanks in advanced for your help!70Jan. 03, 2025
Does the desired_velocity assignment need to be multiplied by delta for accurate collision detection?◆ LPWithout multiplying by delta, the raycast2D keeps the collision as true for a while even after being away from the collision shapes. This is results in way more movement in opposite direction than intended.
After I did `desired_velocity += calculate_avoidance_force() * delta`, the bouncer started running smoothly toward the player again.30Dec. 12, 2024
Thank you!few-apeThis has been a fantastic lesson!
I really appreciate the break down of the intensity formula as well.
I've begun working on a little project and there were so many moments where I thought to myself, "I didn't know you could do that!" during this lesson.
I really appreciate it!10Nov. 23, 2024
intensityram876Hi! After we included intensity in the calculations, if the runner stands behind an obstacle at right angles to the direction of the bouncer, then the bouncer began to get stuck. But I increased the avoidance_strength a lot and bouncer started pushing off obstacles again.10Nov. 07, 2024
Lesson Q&A
Use this space for questions related to what you're learning. For any other type of support (website, learning platform, payments, etc...) please get in touch using the contact form.