Exclude values from math.random()

Hey there, I made an Android game called “Many Jumps” (https://play.google.com/store/apps/details?id=com.joe.games.manyjumps) In that game, you control a bouncy white ball by tilting your device and you must make it land on the platform. Upon collision, the platform teleports to a place with random coordinates and you must make the ball land on the platform again. The code below represents the game logic:

local function platformCollision(self, event)     if event.phase == "ended" then         if event.target.type == "platform" and event.other.type == "ball" then             timer.performWithDelay(1,                 function()                     self.x = math.random(0,300)                     self.y = math.random(50,300)                     self:setFillColor( math.random(0,1), math.random(0,1), math.random(0,1) )         end                                   )            score = score + 1            scoreText.text = "Score: " .. score            media.playSound( "jump.wav" )         end     end end

I received negative reviews because of the fact that the platform often appears right on top of the ball, making it bounce downwards and make you lose the game. I searched online for a way I could use math.random() while excluding ball.x and some values close to it, preventing the platform from appearing on top of the ball but unfortunately I couldn’t find a solution and I hope that one of the nice folks can help me sort out this quite disturbing problem. 

What you could do is get a random number between 1 and 2. If it’s a 1, generate a second random number that is left of your ball. If its a 2 generate a number to the right of your ball.  This is untested code, but something like:

local generateLeft = math.random(1, 2) if generateLeft == 1 then     object.x = math.random(0, self.x - 20) else     object.x = math.random( self.x + 20, display.contentWidth) end

The +/- 20 is a value for the amount of space you want on either side of the object.

Rob

I wrote your code and tried the game on my phone. The platform didn’t show up right on top of the ball, yet the game would lag a little everytime the ball collides with the platform. When I got a score of 10, I received a Runtime Error on the 11th collision: bad argument #2 to ‘random’ (interval is empty)

edit: The game doesn’t lag upon collision, my bad.

What line number did it say the error was on?  What line of code is there?

Does anything happen when you get to 10 points? i.e. you kill the player?

You will need to show more code in particular around where it says the error is happening.

Rob

The error message did not specify a line number. At 10 points, the ball is supposed to continue bouncing but the game just freezes. Once you close the error message the app crashes and a “Unfortunately Many Jumps has stopped” message appears. This error does not necessarily occur at a score of 10. Sometimes at score 2 sometimes at score 16 etc

If you got a run time error, then you have additional messages in your terminal window/console log that has more information. Please copy and paste that text into your next forum post.

Rob

Mmm The error appears after a score of minimum 2, which I can’t simulate on my PC as I can’t simulate accelerometer events with the Corona Simulator (I hope there is a free way to do this)

You will have to test that on device.

Rob

But how can I test it on my device with a terminal/consol running ?

If you are running one of the newer daily builds and you choose to let Corona SDK install and run the app for you, the device logs will show up in the new console window. If you have an older version, you will need to use “adb logcat”.  Please see:
 

http://docs.coronalabs.com/guide/basics/debugging/index.html

Rob

I found an easier way to debug. I added two buttons that let the ball move left and right, that way I can try my game on my PC without the need to accelerometer events. 

Here is the detailed error report:

loAK62e.jpg

I tried the game many times, and found out that when this error occurs, the platform is on either side of the screen, but it doesn’t occur every time the platform is on either side of the screen. If on the left side, the error is at line 83

self.x = math.random( 0, ball.x - 50 ) 

, if on the right side however, it’s at line 89 

self.x = math.random( ball.x + 50, display.actualContentWidth)

My interpretation of the error is the following:

If the platform is on the left side, for example let’s say ball.x = 0, self.x (the platform’s x coordinate) can take any value between  0 and ball.x  - 50, so it can take a value of 0 - 50 (which equals -50) a value that doesn’t belong to the (0, ball.x - 50) interval.

If the platform is on the right side, for example let’s say ball.x = display.actualContentWidth, self.x can take a value of ball.x + 50 which is greater that display.actualContentWidth and a value that doesn’t belong to the interval.

I added two new conditionals to prevent the platform from taking x coordinates that do not belong to the intervals:

oneTwo = math.random( 1,2 ) if oneTwo == 1 then self.x = math.random( 0, ball.x - 50 ) if self.x \< 0 then self.x = 0 end print(oneTwo) else self.x = math.random( ball.x + 50, display.actualContentWidth) if self.x \> display.actualContentWidth then self.x = display.actualContentWidth end print(oneTwo) end self.y = math.random(50,300) self:setFillColor( math.random(0,1), math.random(0,1), math.random(0,1) )

But when I tried the game, I got the same kind of error, which makes me realise that my interpretation is most probably erroneous. Really hope you can help me out.

You need to ask yourself why would ball.x be empty/nil? Are you destroying it somewhere? Is it possible that your collision function can’t see ball for some reason? 

I scratched my head thinking about this question to no avail, so I decided to try this instead:

local function platformCollision(self, event) if event.phase == "ended" then if event.target.type == "platform" and event.other.type == "ball" then timer.performWithDelay(1, --function() if ball.x == math.random( 0, display.contentCenterX ) then self.x = math.random( display.contentCenterX + 20, display.actualContentWidth) else if ball.x == math.random( display.contentCenterX, display.actualContentWidth ) then self.x = math.random( 0, display.contentCenterX - 20 ) end self.y = math.random(50,300) self:setFillColor( math.random(0,1), math.random(0,1), math.random(0,1) ) --end ) score = score + 1 scoreText.text = "Score: " .. score media.playSound( "jump.wav" ) end end end

Got this error upon clicking “Play”:

Runtime error error loading module 'level1' from file 'c:\users\user\documents\corona projects\many jumps\level1.lua': c:\users\user\documents\corona projects\many jumps\level1.lua:64: unexpected symbol near 'if' stack traceback: [C]: in function 'error' ?: in function 'gotoScene' c:\users\user\documents\corona projects\many jumps\menu.lua:33: in function \<c:\users\user\documents\corona projects\many jumps\menu.lua:29\> ?: in function \<?:221\>

The error is at line 64:

if ball.x == math.random( 0, display.contentCenterX ) then

It’s hopeless :frowning:

In line 63, you comment out the beginning of an anonymous function that you’re passing to timer.performWithDelay. Effectively this is the code you’re trying to run:

timer.performWithDelay(1, if ball.x == math.random( 0, display.contentCenterX ) then self.x = math.random( display.contentCenterX + 20, display.actualContentWidth) else if ball.x == math.random( display.contentCenterX, display.actualContentWidth ) then self.x = math.random( 0, display.contentCenterX - 20 ) end self.y = math.random(50,300) self:setFillColor( math.random(0,1), math.random(0,1), math.random(0,1) ) )

The second parameter to timer.performWithDelay() must be the address to a function. You are sticking arbitrary code in the timer. I don’t believe you intend this code to be inside the timer. So perhaps taking out the timer line and it’s matching ) at the end might get you moving.

Not sure if this is still a problem, but for me it seams that the first problem:

bad argument #2 to ‘random’ (interval is empty)

is a result of a negative range, i.e. the first value is bigger than the second value, like: math.random(0,-1) or math.random(10,5).

This can happen when the platform is too close to the left (or right) side when trying to move it in this direction.

I would try something like the following:

oneTwo = math.random( 1,2 ) --1: left, 2: right local minLeft = ball.x-50 --minimal left displacement local minRight = ball.x+50 --minimal right displacement if oneTwo == 1 then if minLeft \> 0 then --its possible to move it to the left side self.x = math.random( 0, minLeft ) else --we are too close to the left border, move it to the right side self.x = math.random( minRight, display.actualContentWidth) end else if minRight \< display.actualContentWidth then -- enough space to the right self.x = math.random( minRight, display.actualContentWidth) else --too close to the right, move it to the left side self.x = math.random( 0, minLeft ) end end

This code is untested and while writing I recognized how tired I really am…

(And I am furthermore not sure if it is still needed, as I saw that there actually appeared another, new problem :smiley: )

Anyway, maybe it helps anyway,

cheers,

Felix

Thank you Rob M and Felix B for your contribution :slight_smile: At last it finally worked :smiley:

What you could do is get a random number between 1 and 2. If it’s a 1, generate a second random number that is left of your ball. If its a 2 generate a number to the right of your ball.  This is untested code, but something like:

local generateLeft = math.random(1, 2) if generateLeft == 1 then &nbsp;&nbsp;&nbsp; object.x = math.random(0, self.x - 20) else &nbsp;&nbsp;&nbsp; object.x = math.random( self.x + 20, display.contentWidth) end

The +/- 20 is a value for the amount of space you want on either side of the object.

Rob

I wrote your code and tried the game on my phone. The platform didn’t show up right on top of the ball, yet the game would lag a little everytime the ball collides with the platform. When I got a score of 10, I received a Runtime Error on the 11th collision: bad argument #2 to ‘random’ (interval is empty)

edit: The game doesn’t lag upon collision, my bad.

What line number did it say the error was on?  What line of code is there?

Does anything happen when you get to 10 points? i.e. you kill the player?

You will need to show more code in particular around where it says the error is happening.

Rob

The error message did not specify a line number. At 10 points, the ball is supposed to continue bouncing but the game just freezes. Once you close the error message the app crashes and a “Unfortunately Many Jumps has stopped” message appears. This error does not necessarily occur at a score of 10. Sometimes at score 2 sometimes at score 16 etc