I am trying to draw a line showing the path that a RigidBody2D will travel once forces are applied to it. The idea is that the player character is clicked on and dragged in the opposite direction (like pulling back a slingshot), then released; based on how far the mouse was dragged away from the player, the further they will travel.
The player already travels in an arc, but I would like to add a line showing where they will land once the player releases it.
Right now I am trying the code from this post but the values it is setting are too extreme and don’t correlate to an arc. Is there a better way of doing this?
var pos = position
var velocity = Vector2.UP.rotated(rotation) * ($StrengthMeter.get_cast_to().y * 10)
for i in range(20):
$SwordThrowIndicator.add_point(pos - global_position, i)
velocity *= 0.1
pos += velocity
Right now it draws lines over and over again until it hits the limit and clears it out, but I’m just trying to get them to arc according to the player’s velocity for now.
Velocity is just a direction. It will change over time due to gravity. So in order to curve a line you need to calculate physics over a distance and time.
You got to add a gravity factor to your for loop. You only slow the velocity down but it will not curve like that.
I would use the Node function get_process_delta_time or get_physics_process_delta_time this will return a float typically seen in the _process(delta) and _physics_process(delta) respectively. if your frame rate is set to 60 fps, then this function will return a value of around 0.016, and that should be enough to run through your for loop to quickly simulate the physics and draw the trajectory line in one frame.
Looking at the relative changes the velocity.y step is ~ -155. Doing the inverse math we should expect to see around -980. Which is the default gravity for 2d projects.
Doing the same for velocity.x step we I see a step of +187 is the x velocity. ( update: the inverse math ends up being 1168 I missed this)
Both seem like expected outcomes.
I think now is a scaling problem. Maybe you should modify the velocity to fit your game view or change the view to fit your velocities.
The problem I see is that you apply gravity per axis. First to x then to y. It technically should only apply to y axis. But maybe you want gravity to change directions. In order to do that you should use vector math. It’s also cleaner.
extends Node2D
@onready var bird = $Bird
# Get the gravity from the project settings to be synced with RigidBody nodes.
var gravity = ProjectSettings.get_setting("physics/2d/default_gravity")
# Get the gravity from the project settings to be synced with RigidBody nodes.
var gravityv = ProjectSettings.get_setting("physics/2d/default_gravity_vector")
var point = []
func readraw_all():
point = [];
queue_redraw()
func _draw():
var ori : Vector2 = bird.original_position;
for i in range(300):
var neo : Vector2 = ori + (bird.original_velocity*0.948 + gravityv * gravity * i * get_physics_process_delta_time()) * get_physics_process_delta_time()
draw_line(ori, neo,Color.RED);
ori = neo
if (point.size() > 1):
for i in range(point.size()-1):
draw_line(point[i], point[i+1],Color.GREEN);
Bird.gd
extends RigidBody2D
var reset_state = false
@onready var original_position = position
@onready var parent = get_parent();
var original_velocity
# Called when the node enters the scene tree for the first time.
func _ready():
restart()
func _integrate_forces(state):
if reset_state:
state.transform = Transform2D(0.0, original_position)
reset_state = false
restart()
func restart():
original_velocity = Vector2(randi_range(50, 600), randi_range(-700,-200))
linear_velocity = original_velocity
parent.readraw_all()
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _physics_process(delta):
if (sleeping):
reset_state = true
if (position.x > 1200):
reset_state = true
if (position.y > 650):
reset_state = true
parent.point.append(position)
parent.queue_redraw();
The approximate path is draw on red while in green is draw the actual path take by the RigidBody2D
I don’t know why but i need a coefficient for the velocity in the calculation made in World.gd . With 0.948 it look pretty close to the original travel path.
You can see it here :
The problem with this is that I don’t have a way of getting the velocity of the sword before it’s thrown. You’re putting in random variables each time for the velocity, which doesn’t work in my case.
Assuming the very simply equation of velocity = distance / time, what would distance and time be in this scenario? Would time be delta? Would distance be the linear_velocity equation I posted earlier?
I also found this page on KidsCanCode which is exactly what I need, but trying to apply it to what I have doesn’t seem to be working. The problem is in the example it’s changing the position of the muzzle for some reason, and applying that to my example makes the sword move when the player is interacting with it which shouldn’t happen.
So you got all you need. In my equation you just need the initial position and initial velocity. The curve equation look like this : y = x * gravity * delta² + start_velocity * delta * 0.948 + start_pos
where delta is a constant value given by get_physics_process_delta_time()
I’m not understanding any of this. This gives error "Invalid operated 'int
and ‘Vector2’ in operator ‘+’.
var pos = position
var vel = linear_velocity
for i in range(20):
$SwordThrowIndicator.add_point(position, i)
vel.y = vel.x * ProjectSettings.get_setting("physics/2d/default_gravity") * get_physics_process_delta_time()^2 + vel * get_physics_process_delta_time() * 0.948 + pos
pos += vel * delta
My bad I write to fast my equation who’s not totally correct. You can try this :
var pos = position
var vel = linear_velocity
var step_size = 1 # reduce points counts
var points = []
var gravity = ProjectSettings.get_setting("physics/2d/default_gravity") * ProjectSettings.get_setting("physics/2d/default_gravity_vector")
var delta = get_physics_process_delta_time()
for i in range(0,20):
points.append(pos)
for j in range(step_size):
pos = (i * step_size + j) * gravity * delta * delta + vel * delta * 0.948 + pos
That is still not working, and points.append is not valid. Are you sure you have this typed out correctly?
var pos = position
var vel = linear_velocity
var stepSize = 1
for i in range(20):
$SwordThrowIndicator.add_point(pos, i)
for j in range(20):
pos = (i * stepSize + j) * ProjectSettings.get_setting("physics/2d/default_gravity") * delta * delta + vel * delta * 0.948 + pos
You forgot the delta variable and to set stepsize in the second loop range.
You also need to have a gravity as a vector that’s why I multiply the gravity by the vector in the gravity variable declaration.
var pos = position
var vel = linear_velocity
var gravity = ProjectSettings.get_setting("physics/2d/default_gravity") * ProjectSettings.get_setting("physics/2d/default_gravity_vector")
var stepSize = 1
var delta = get_physics_process_delta_time()
for i in range(20):
$SwordThrowIndicator.add_point(pos, i)
for j in range(stepSize):
pos = (i * stepSize + j) * gravity * delta * delta + vel * delta * 0.948 + pos