Godot Version
4.2.2
Question
OK, new… I mean NEW with Godot.
Question is about impulse force and trying to get a force acted on a RidgidBody3D so that NO matter where the collision, the force is applied to the object in the direction of the projectile the script here is attached to. So if the player hits this thing at the edge… still I want that body to pushed in the exact direction the projectile is traveling. While central hits behave as you think… the edge hits are like playing pool, which isn’t the desired effect.
It’s first learning project, so tread lightly
GitHub
YouTube video of what it’s doing
extends RigidBody3D
@onready var raycast = $RayCast3D
@export var explosion_scene: PackedScene
@export var offset_distance: float = -0.25
@export var sound: AudioStream
@export var impulse_strength: float = 10.0
func _ready():
connect("body_entered", Callable(self, "_on_body_entered"))
func _on_body_entered(body: Node):
if body != self:
raycast.enabled = true
if raycast.is_colliding():
var trajectory_direction = -linear_velocity.normalized()
if body is RigidBody3D:
var impulse = trajectory_direction * impulse_strength
body.apply_central_impulse(impulse)
body.angular_velocity = Vector3.ZERO
if explosion_scene:
var explosion_instance = explosion_scene.instantiate()
if get_parent():
get_parent().add_child(explosion_instance)
explosion_instance.global_transform.origin = global_transform.origin - trajectory_direction * offset_distance
explosion_instance.look_at(global_transform.origin + trajectory_direction, Vector3.UP)
var audio_player = AudioStreamPlayer3D.new()
audio_player.stream = sound
get_parent().add_child(audio_player)
audio_player.global_transform.origin = global_transform.origin
audio_player.play(0)
queue_free()
Critique.
Banging my head against the wall…
the point to point direction wasn’t the fix totally… I’ll end up getting the direction in the same place I get the initial point (After we set the projectile on its way)
What I think was happening… we were reaching into the projectiles direction or velocity before the shooter script could send it on its way. Or at least it was the problem during or after versions in original post to this one. Either way, works as intended now
Why this way? Yea I get it… but later in a networked game… this simplifies how a game could be played especially when collisions are viewed by different players.
extends RigidBody3D
@onready var raycast = $RayCast3D
@export var explosion_scene: PackedScene
@export var sound: AudioStream
@export var impulse_strength: float = 10.0
var initial_position: Vector3
var has_started_moving: bool = false
func _ready():
connect("body_entered", Callable(self, "_on_body_entered"))
func _physics_process(delta: float):
if not has_started_moving and linear_velocity.length_squared() > 0.01:
initial_position = global_transform.origin
has_started_moving = true
func _on_body_entered(body: Node):
if body != self:
raycast.enabled = true
if raycast.is_colliding():
_apply_impulse(body)
_create_explosion()
_play_sound()
queue_free()
func _apply_impulse(body: Node):
if body is RigidBody3D:
var force_direction = initial_position.direction_to(global_transform.origin)
var impulse = force_direction * impulse_strength
body.apply_central_impulse(impulse)
body.angular_velocity = Vector3.ZERO
func _create_explosion():
if explosion_scene:
var explosion_instance = explosion_scene.instantiate()
if get_parent():
get_parent().add_child(explosion_instance)
explosion_instance.global_transform.origin = global_transform.origin
func _play_sound():
var audio_player = AudioStreamPlayer3D.new()
audio_player.stream = sound
get_parent().add_child(audio_player)
audio_player.global_transform.origin = global_transform.origin
audio_player.play(0)