Change the rebound angle

I’m all testing for the whole evening.

it seems that the best results are given by:

physics.setScale(10)

the cases have been reduced considerably.

As I said before I would have preferred a more “safe” solution but for now I will go ahead with this.

I thank you very much for helping me to improve my problem! :slight_smile:

I thought I’d quickly chime in.

@jake1987.jj, the code and the associated images that you posted is how the physics would work in reality. Intervening with how the ball bounces off the walls can be problematic because it will lead to unexpected behaviour and it will make it harder for the player to understand and predict how the ball will move in its environment.

Now, if you are determined that this is what you want, then there are several methods for approaching this issue. Perhaps the easiest method would be to utilise collision detection.

Whenever the ball collides with another object, store the collision event’s x and y coordinates, as well as the object that the ball collided with and at what time the collision occurred. So once the ball has collided once, you can compare all subsequent collisions with the previous collision.

First and foremost, when a new collision occurs, check if the object that the ball collided with is the same as the previous object. If it isn’t the same object, you don’t need to do anything. If it is the same object, then you may encounter that wall sliding, so then you’d check how much time has passed since the previous collision. You can set an arbitrary time window to control for this. If too little time has passed since the previous collision, then you may want to intervene. If you do decide to intervene, you can calculate the direction that the ball is travelling based on the previous collision’s x and y coordinates, as well as the current collision’s x and y coordinates. Now you could write another arbitrary rule for which direction the ball should bounce off to relative to the direction that you just calculated, such as the 90 degree angle that you previously mentioned.

@XeduR @Spyric

Thank you for intervening. In reality your approach is much more similar to mine than that of others who are intervented.

I had thought about your approach in recent days and some tests.

It also works well enough unique flaw and that it can be used mainly when we are already in step5 (see previous drawing). I hope to intervene already in step3 seen the angle is already quite large that is formed between ball and edge.

As I am writing to you I am thinking that a good solution could be that of aumtera as long as possible between one interview and another. But without exaggerating to avoid other problems. I do some tests now!

As I said before I am aware of the fact that it is not an extremely natural behavior. But I think that if corrected in the right way, it may seem natural enough

That solution could intervene as soon as step 2. It only depends on what time window you set. If you set a too long time window, then the code might run on every collision, whereas if it is too brief, then it might run too infrequently. But, as you said, this’ll need a lot of testing.

You can alternatively use number of frames instead of milliseconds to measure time.
 

Hey Jake,

If you can zip up a little sample to share with us, that would be helpful.

Question:  How did you make the outer circle?  Did you use a physics chain body or did you a program like physics editor to describe the object?

I probably sound like a broken record because I’m always the guy that says “Sheesh, why don’t you just write your own simple physics for something like this?” but I would repeat my statement here.

It would be a lot simpler and give you loads more control, from what I see here. If there are other parts of the physics mechanics not discussed here I stand corrected, but the things asked here are peanuts using simple math and some trigonometry.

@sporkfin,

When I saw that circle body, I actually realised that I might need something similar in one of my projects. I’ll write a function later today that’ll create (rough) vertices for a circle and I’ll share it on the forums. It shouldn’t be more than a 5 to 10 minute task.

Update : I’ve written the function and it’s available at https://forums.coronalabs.com/topic/73653-creating-vertices-for-a-circle/. I’ll be setting up a GitHub account at a later date and the code, as well as much more, will then be available there as well.

@sporkfin

If the bodies are circular, I use a function similar to the one posted by @XeduR @Spyric.

if instead I have polygons I do two things:

  1. If these forms only need one size, I use programs like physicsEditor

2. if these shapes need me more dimensions I create the vertices manually where each point is based on the dimension of the polygon itself (this takes me a lot of time)

If the polygon has more than 8 vertices then I use the string instead of a multi-element body.

For the zip file I hope to be able to achieve the effect I want and in that case I will not have problems sharing

@Jake

Just double checking - you have checked in physics drawmode to make sure you don’t have any errant vertices causing the ball to behave strangely?

@sporkfin

I had not done it carefully.

After your suggestion I did some checks but nothing unusual. Good idea anyway!

caveat: only gave it a “5 second” read, but i think the angle you’re calculating between vectors would be the 20-degree suppliment, not the 160-degree orange (referencing your first illustration)

Hi. It looks like this change will do it, at least with this example:

function Correct (vx, vy) -- velocity to correct local lx, ly = math2do.normalize(PrevVX, PrevVY) -- "left" (we don't care about the length) local ux, uy = ly, -lx -- "up" vx, vy = math2do.normalize(vx, vy) local dot = math2do.dot(lx, ly, vx, vy) local angle = math.acos(dot) if math.deg(angle) \> 20 then return ux \* ballSpeed, uy \* ballSpeed -- for corrections using other reflection angles (in radians), do: -- local ca, sa = math.cos(ref\_angle), math.sin(ref\_angle) -- local dir\_x, dir\_y = ca \* lx + sa \* ux, ca \* ly + sa \* uy -- return dir\_x \* ballSpeed, dir\_y \* ballSpeed else return vx \* ballSpeed, vy \* ballSpeed -- original direction fine end end

Following my earlier comments, you would actually have wanted

local lx, ly = math2do.normalize(-PrevVX, -PrevVY)

However, that will give you a 180 degree angle while falling and just get you stuck.  :slight_smile: It’s possible you’ll still run into this situation, say when hitting a wall at a right angle.

Hello, thank you very much!

I have tested the code in the example and it works well!

Then I did a test with other curved surfaces here and there and the problems persist.

At other times the ball moves strangely.

Given the scale of the problem, I think it’s impossible for me to solve and it would be too much to ask you.

I was therefore wondering, as a last hope, something.

Would it be possible (by removing the “Correct” method) to put a listen on the obstacle that detects these cases?

This would be enough for me. If the obstacle detects that the ball is slamming it at an angle near 180 I remove that obstacle.

Is this possible or equally complicated?

fwiw:  this seems like a strange game mechanic - i can’t imagine a real-world case where that type of reaction would be “expected”.  makes me wonder if you’re trying really hard to implement something that, in the end, won’t even be desirable.

having said that, what i’d instead do is “roughen” your obstacle geometry to achieve a similar effect.  imagine at each existing current vertex along the concave curve you “bump out” a tiny little “saw tooth” - then the physics engine will do all the work for you.

it’d be unlikely to give exactly 90 degrees, but might mimic it close enough, with little effort involved - don’t know your requirements, but maybe that would suffice.

Is this an attempt to fix/prevent wall-sliding?

 

@davebollinger

I know it seems unlikely but it was an example. I could decide if this event was confirmed to push the ball towards an area(rather than eliminating the obstacle). The important thing is that they do not slip.

Among other things, I do not ask for a rebound of exactly 90 °. It was just an example.

Let’s say that if the angle would be between about 180 (impossible) and 150, I would like to slam giving rise to a smaller angle (in the example 90 °) but also a little more or less purses do not slip

@roaminggamer

Exact!

 

I wish the ball did not slip into the wall

perhaps if you posted something that demonstrated the actual problem you’re trying to solve?

(ie, rather than asking for help to “fix your fix”, ask for help on the original problem.  maybe?)

I agree with @davebollinger here.

This is another case of the OP posting a solution that they think will fix their problem, but that they are unable to write.

I tell folks this all the time, but please don’t ask for help on solutions.  Ask for help on problems.

The actual problem here might have been stated as:

“I have balls that bounce around a room.  I have added code so they keep moving at the same rate.  This works for the most part, but sometimes:”

  • One or more balls will start sliding along a wall and never stop bouncing back and forth along that wall.

I need help preventing this behavior.  I want balls to keep bouncing around the room without any prolonged walls sliding.

@Jake,

I know this may come across as mean or critical, but I’m not trying to be.  I simply want to make the point that too many people who ask for help fail to ever state what the actual problem is.  More often than not they are asking for help writing a solution that they’ve guessed will help solve the actual problem.

A long time ago I wrote a rather lengthy post on asking questions that might help you and others in the future:  https://forums.coronalabs.com/topic/55780-ask-a-better-question-get-a-better-answer/

PS - Please do make a ‘micro’ (and I really mean tiny and neat ) example showing the problem and I’m sure you’ll get takers on helping with the original problem.  Just zip it up and attach it here.  

PPS - I should also say, the general quality of this and the prior post were good, but the point about not actually addressing the real problem still stands.

i was like:  “how the heck did he read all that out of this thread?!?!” :smiley:

if that is indeed the problem statement:  odds are that the “added code” is directly altering velocity instead of applying a force, and THAT is likely what is causing whatever issue with collision detection you mean by “slip/slide/slam”.

directly setting velocity (linear or angular) should be reserved for kinematic bodies - if at all possible.  because doing so on a dynamic body will “bypass” integration by the physics engine that may be necessary for proper contact detection and collision response.

@All

I have re-read everything.

I think I was wrong to concentrate the question of this tread as if it were the continuation of the previous one. I would have to reformulate the question in a different and more complete way.

@roaminggamer always manages to capture everything but probably for his experience. However, I think people should not spend “hours” just to understand the question so I apologize for this.

The text formulated by roaminggamer was therefore fine to add only 2 things:

  • I’m working with gravity set to 0;
  • the annoyance is not only given by the situations in which it slides up and down but also by the fact that it slips.

I attach as required a simple example in which the ball after having rebounded on an obstacle slips on another curved obstacle.

local physics = require("physics") physics.setDrawMode( "hybrid" ) --debug hybrid normal physics.start() physics.setGravity( 0, 0 ) --"math2do" taken from the examples of @roaminggamer local math2do = {} local mRad = math.rad local mCos = math.cos local mSin = math.sin local mSqrt = math.sqrt function math2do.scale( ... ) -- ( objA, scale [, altRet] ) or ( x1, y1, scale, [, altRet] ) if( type(arg[1]) == "number" ) then local x,y = arg[1] \* arg[3], arg[2] \* arg[3] if(arg[4]) then return { x=x, y=y } else return x,y end else local x,y = arg[1].x \* arg[2], arg[1].y \* arg[2] if(arg[3]) then return x,y else return { x=x, y=y } end end end function math2do.length( ... ) -- ( objA ) or ( x1, y1 ) local len if( type(arg[1]) == "number" ) then len = mSqrt(arg[1] \* arg[1] + arg[2] \* arg[2]) else len = mSqrt(arg[1].x \* arg[1].x + arg[1].y \* arg[1].y) end return len end function math2do.normalize( ... ) -- ( objA [, altRet] ) or ( x1, y1 [, altRet] ) if( type(arg[1]) == "number" ) then local len = math2do.length( arg[1], arg[2], false ) local x,y = arg[1]/len,arg[2]/len if(arg[3]) then return { x=x, y=y } else return x,y end else local len = math2do.length( arg[1], arg[2], true ) local x,y = arg[1].x/len,arg[1].y/len if(arg[2]) then return x,y else return { x=x, y=y } end end end function math2do.angle2Vector( angle, tableRet ) local screenAngle = mRad(-(angle+90)) local x = mCos(screenAngle) local y = mSin(screenAngle) if(tableRet == true) then return { x=-x, y=y } else return -x,y end end --====-- --ball-- --====-- local ballSpeed = 100 local ball = display.newCircle( 250, 350, 15 ) ball:setFillColor( 1, 0, 0 ) physics.addBody( ball, {density=0.1, radius = 15, bounce = 0.7, friction = 1 } ) ball.isBullet = true local enterFrame = function( self ) local vx,vy = self:getLinearVelocity() vx,vy = math2do.normalize( vx, vy ) vx,vy = math2do.scale( vx, vy, ballSpeed ) self:setLinearVelocity( vx, vy ) end local angleStart = 299 local vec = math2do.angle2Vector( angleStart, true ) vec = math2do.scale( vec, ballSpeed ) ball:setLinearVelocity( vec.x, vec.y ) ball.enterFrame = enterFrame Runtime:addEventListener( "enterFrame", ball ) --=========-- --obstacles-- --=========-- local points = { -7.8459095727845 ,99.691733373313, -15.643446504023 ,98.768834059514, -23.344536385591 ,97.236992039768, -30.901699437495 ,95.105651629515, -38.268343236509 ,92.387953251129, -45.399049973955 ,89.100652418837, -52.249856471595 ,85.264016435409, -58.778525229247 ,80.901699437495, -64.944804833018 ,76.040596560003, -70.710678118655 ,70.710678118655, -76.040596560003 ,64.944804833018, -80.901699437495 ,58.778525229247, -85.264016435409 ,52.249856471595, -89.100652418837 ,45.399049973955, -92.387953251129 ,38.268343236509, -95.105651629515 ,30.901699437495, -97.236992039768 ,23.344536385591, -98.768834059514 ,15.643446504023, -99.691733373313 ,7.8459095727845, -100, 2.4492935982947e-014, } local obstacle = display.newRect( 185, 292, 10, 10 ) physics.addBody( obstacle, "static", { chain = points, } ) local obstacle2 = display.newCircle( 100, 250, 10 ) physics.addBody( obstacle2, "static", {radius=10})