+1 vote

Hi all,

Still making pong :-)

In this thread I learned about finding where my ball hits my bat and normalising the result. All good fun.

Now I'm trying to get the ball to fly off at a different angle.

I have this code (thank you /u/avencherus) that is being called every frame (when there's a collision):

var velocity = Vector2(cos(bounceAngle), -sin(bounceAngle)) * game.ballSpeed

If I try and use it though like so:

var velocity = Vector2(cos(bounceAngle), -sin(bounceAngle)) * game.ballSpeed
set_linear_velocity(velocity)

The ball bounces rapidly against the bat when it hits it. It's crazy times but not what I'm after.

I had a research and the docs say:

Set the body angular velocity. Can be used sporadically, but DON’T SET THIS IN EVERY FRAME, because physics may be running in another thread and definitely runs at a different granularity.

I'm wondering if anyone has some advice on how to approach this?

EDIT: It also says Use _integrate_forces as your process loop if you want to have precise control of the body state. but I got completely lost there. It's as if integrateforces just happens all the time without being called, so I am not sure how to control that? Is it treated like a fixedprocess of sorts?

in Engine by (824 points)

It's not very clear what kind of result you want. Did you want a collision response based on elastic collisions? A simple reflection of velocity? There's all kinds of ways to "bounce".

A note about the docs remark. Angular velocity deals with the rotation or spin of an object. Think of fan blades spinning, that's angular velocity. I don't think that's what you're looking for. I imagine in your game of pong you're not too interested in if the ball is spinning, unless you want to model some kind of ball spin from friction.

Sorry I copy / pasted the wrong part. I was going for this from set_linear_velocity:

Set the body linear velocity. Can be used sporadically, but DON’T SET THIS IN EVERY FRAME, because physics may be running in another thread and definitely runs at a different granularity

I'm after an effect where the ball hits the bat and bounces off at an angle that I determine based on the normalised position (-1 to 1). I've set my MaximumAngle to this:

const  MAXBOUNCEANGLE   = deg2rad(75)

... and then use it as such:

var bounceAngle = normalisedhitLocationY * MAXBOUNCEANGLE; 

Essentially:
- hit the top of the bat, big angle
- hit a bit below the top, slightly lower angle
- etc
- hit middle of bat, ball bounces off on a flat horizontal angle
- etc to bottom of bat where the angle is large again

I was trying to play with integrateforces() but anything in there happened all the time. Then it started to dawn on me, is integrateforces() to be used INSTEAD of fixedprocess(delta)? So I'd put all my logic, key / mouse controls, etc into integrateforces() rather than fixedprocess(delta)? OR, can they run next to each other / at the same time? I'm a little confused about it obviously. :-)

K so, an arbitrary angle based on where it hits.

I'll give an example, but the other questions I'd recommend splitting that off into their own questions.

1 Answer

+1 vote

For an angle on the position, you want to map it to radians in some way. One way is using LERP. You may want to print out some values to see how this works.

This example just shows the visual result of the angle itself given the range -1 to 1. These vectors in actuality will be emitting from the point of contact on the bat.

A lot of this is worked out around the unit circle that Godot uses. Where the Y axis heading down is 0, rotating along the right heading upwards ends on PI, and rotating along the left side goes to -PI. (It's worth exploring with visuals and print statements, it comes up a lot.)

I wrote a helper function to do the lerp, while clamping the input to -1 and 1, as well as giving a direction option. It can reflect the other way basically by multiplying a -1.

extends Node2D

const MAX_ANGLE = 45

const LEFT = -1
const RIGHT = 1

const DISTANCE = 100
const VEC_ZERO = Vector2()

onready var canvas_center = get_viewport().get_rect().size / 2
var color = Color(1,1,1,1)
var hit_angle_color = Color(1,0,0,1)

var center_angle = PI / 2 # 90 degrees ------>
var upper_angle = deg2rad(MAX_ANGLE/2 + 90)

func map_value_to_angle(value, direction):
    return lerp(center_angle, upper_angle, clamp(value, -1, 1)) * direction

func _draw():

    draw_circle(canvas_center, 5, color)

    var hit_angle_max = map_value_to_angle(  1, RIGHT)
    var hit_angle_75  = map_value_to_angle( .5, RIGHT)
    var hit_angle_mid = map_value_to_angle(  0, RIGHT)
    var hit_angle_25  = map_value_to_angle(-.5, RIGHT)
    var hit_angle_min = map_value_to_angle( -1, RIGHT)

    draw_line(canvas_center, canvas_center + Vector2(sin(hit_angle_max), cos(hit_angle_max)) * DISTANCE, hit_angle_color, 2)
    draw_line(canvas_center, canvas_center + Vector2(sin(hit_angle_75 ), cos(hit_angle_75 )) * DISTANCE, hit_angle_color, 2)
    draw_line(canvas_center, canvas_center + Vector2(sin(hit_angle_mid), cos(hit_angle_mid)) * DISTANCE, hit_angle_color, 2)
    draw_line(canvas_center, canvas_center + Vector2(sin(hit_angle_25 ), cos(hit_angle_25 )) * DISTANCE, hit_angle_color, 2)
    draw_line(canvas_center, canvas_center + Vector2(sin(hit_angle_min), cos(hit_angle_min)) * DISTANCE, hit_angle_color, 2)
by (5,202 points)

mmmm, that is interesting. I'm going to have to study that for a little while to learn what it all means. Thank you. It has helped to visualise that's for sure (when run).

I think in my example I do have a Vector2 with the velocity in X and Y that's required (at least I think I do). When I try and use it though, the ball bounces like crazy, and I suspect it's due to the setlinearvelocity() being called in the fixedprocess. Do you think that's the case and if so, should I be using _integrateforces()?

I recommend getting familiar with integrate forces if you plan on using rigid bodies. It's a big topic, but there is a demo project that's worth studying to answer all your questions about how to use it.

https://github.com/godotengine/godot-demo-projects/blob/80aea987476cecae876ef855237322b1d6874f89/2d/platformer_dcc/player.gd#L56

I would also make sure you have the option for using custom integration set as well. It's a flag.

In this project it's done in the options: https://github.com/godotengine/godot-demo-projects/blob/80aea987476cecae876ef855237322b1d6874f89/2d/platformer_dcc/player.tscn#L154

It's a flag, so you can set it via script if you prefer.

Either way, with it enabled it allows you to do things like query the linear_velocity, modify it, and feed it back as you see fit. The function executes every frame, the same way as fixed processing.

And by "bouncing around like crazy", hard to say what that means or what's causing it.

Maybe you're not using delta, maybe it's a bug in the code somewhere distant, could be the processing calls. You'd have to debug it until you've isolated it.

It could be a bug as there are two different ways I've tried to do it (both though with setlinearvelicity() and this is an example of the behavior:

link to gif
https://imgur.com/a/EUzK7 (if other link doesn't work)

The frame rate doesn't do it justice but you can see what I mean still.

Well it looks as if the heading is being flipped back to positive X at some point.

If that's actually just the bounce you get from the default integration, then it means you never reverse the velocity direction on impact.

So there you go, I didn't even consider that. I had no concept that I'd have to but it makes total sense now you say it. Thank you for all your help with this. It's really appreciated. I hope in time I can help others also.

Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to webmaster@godotengine.org with your username.