Collisions without physics

I am trying to work on something that involves using collision detections but is not using Physics. Physics will not work for what I need and I don’t want the answer I’m told just to be “use physics only for the detection part then”

I am using Peach’s tutorial from awhile ago for Arrow Movement and if I try to use physics for the detections it will not detect the collision if you hold down the arrow and go through the object.

I have all of my walls (the things I’m trying to detect collisions with) in an array and need to loop through them in my warp function to make sure the player is not moving through walls.

Right now my warp function looks like this

 local function warp ( event )  
 if (gameState == "Play") then  
  
 if ( myPlayer.x \< 15 ) then  
 myPlayer.x = 15  
 end  
  
 if ( myPlayer.x \> 780 ) then  
 myPlayer.x = 780  
 end  
  
 if ( myPlayer.y \< 15 ) then  
 myPlayer.y = 15  
 end   
  
 if ( myPlayer.y \> 820 ) then  
 myPlayer.y = 820  
 end  
  
 for i = 1, #wall do   
 if ( myPlayer.x \> ( wall[i].x + wall[i].width ) ) then return false   
 elseif ( ( myPlayer.x + myPlayer.width) \< wall[i].x) then return false   
 elseif ( myPlayer.y \> ( wall[i].y + ( wall[i].height/2 ) ) ) then return false   
 elseif ( ( myPlayer.y + myPlayer.height ) \< wall[i].y ) then return false   
 else  
 if ( playerDir == 1 ) then  
 myPlayer.y = myPlayer.y +3  
 elseif ( playerDir == 2 ) then  
 myPlayer.y = myPlayer.y -3  
 elseif ( playerDir == 3 ) then  
 myPlayer.x = myPlayer.x -3  
 elseif ( playerDir == 4 ) then  
 myPlayer.x = myPlayer.x +3  
 end   
 end   
 end   
  
 end  
 end  
  
 Runtime:addEventListener( "enterFrame", warp )  

The loop with the walls was taken from here and then edited a little - http://developer.anscamobile.com/forum/2011/09/05/best-method-collision-detection#comment-54441

This section of the code is where I’m having problems

 for i = 1, #wall do   
 if ( myPlayer.x \> ( wall[i].x + wall[i].width ) ) then return false   
 elseif ( ( myPlayer.x + myPlayer.width) \< wall[i].x) then return false   
 elseif ( myPlayer.y \> ( wall[i].y + ( wall[i].height/2 ) ) ) then return false   
 elseif ( ( myPlayer.y + myPlayer.height ) \< wall[i].y ) then return false   
 else  

I have two main problems right now.

My first problem is that this only loops though wall number one a bunch of times and the collision detection works for that wall but since it is not looping through any of the other walls their have no detection.

My second problem is that the walls Y is half way down the image when it is vertical so the detection only works with the bottom half of the wall and not the top. I then have the same problem with horizontal lines only blocking the right half and not the left.

I was wondering if anyone can help me with either (or both) of these problems. I have been trying different ways of this over the last few hours but haven’t been able to figure it out so I came to the forums now for some help.

Thanks,

  • Ertzel [import]uid: 69700 topic_id: 15809 reply_id: 315809[/import]

The reason you’re only checking wall #1 is that

[lua]if ( myPlayer.x > ( wall[i].x + wall[i].width ) ) then return false
elseif ( ( myPlayer.x + myPlayer.width) < wall[i].x) then return false
elseif ( myPlayer.y > ( wall[i].y + ( wall[i].height/2 ) ) ) then return false
elseif ( ( myPlayer.y + myPlayer.height ) < wall[i].y ) then return false [/lua]

*IS* returning false and breaking out of your for loop.

Try something like this:

[lua]local function hasCollided(myPlayer, wall)
if ( myPlayer.x > ( wall[i].x + wall[i].width ) ) then return false
elseif ( ( myPlayer.x + myPlayer.width) < wall[i].x) then return false
elseif ( myPlayer.y > ( wall[i].y + ( wall[i].height/2 ) ) ) then return false
elseif ( ( myPlayer.y + myPlayer.height ) < wall[i].y ) then return false
return true
end

for i = 1, #wall do
if hasCollieded(myPlayer, wall) == false then
if ( playerDir == 1 ) then
myPlayer.y = myPlayer.y +3
elseif ( playerDir == 2 ) then
myPlayer.y = myPlayer.y -3
elseif ( playerDir == 3 ) then
myPlayer.x = myPlayer.x -3
elseif ( playerDir == 4 ) then
myPlayer.x = myPlayer.x +3
end
end
end[/lua]

Now I’m making some assumptions. I’m assuming your math is returning false if you’ve hit something and you don’t want to move. Calling it “hasCollided” would indicate that we want true to be returned if you hit something. So I’ll leave it to you to figure out if those should be return false or return true statements (may need to flip them) so that the next block makes sense.

EDIT: fixed a C/JavaScript/PHP code bit… You can’t end Lua “if”'s with a curley brace. [import]uid: 19626 topic_id: 15809 reply_id: 58387[/import]

Thanks!

Using this as my code now All of my walls are blocking instead of just the one, so that fixed problem #1.

 local function hasCollided (i)  
 if ( myPlayer.x \> ( wall[i].x + wall[i].width ) ) then return false   
 elseif ( ( myPlayer.x + myPlayer.width) \< wall[i].x) then return false  
 elseif ( myPlayer.y \> ( wall[i].y + ( wall[i].height/2 ) ) ) then return false   
 elseif ( ( myPlayer.y + myPlayer.height ) \< wall[i].y ) then return false  
 else  
 return true  
 end  
 end  
  
 local function warp ( event )  
 if (gameState == "Play") then  
  
 if ( myPlayer.x \< 15 ) then  
 myPlayer.x = 15  
 end  
  
 if ( myPlayer.x \> 780 ) then  
 myPlayer.x = 780  
 end  
  
 if ( myPlayer.y \< 15 ) then  
 myPlayer.y = 15  
 end   
  
 if ( myPlayer.y \> 820 ) then  
 myPlayer.y = 820  
 end   
   
 for i = 1, #wall do   
 if hasCollided(i) == true then  
 if ( playerDir == 1 ) then  
 myPlayer.y = myPlayer.y +3  
 elseif ( playerDir == 2 ) then  
 myPlayer.y = myPlayer.y -3  
 elseif ( playerDir == 3 ) then  
 myPlayer.x = myPlayer.x -3  
 elseif ( playerDir == 4 ) then  
 myPlayer.x = myPlayer.x +3  
 end   
 end   
 end   
  
 end  
 end  

Now I just need help with problem #2 where only half of the wall is actually blocking. [import]uid: 69700 topic_id: 15809 reply_id: 58395[/import]

That could be a “center reference point” problem. Is the opposite wall blocking before target gets there?

Remember Corona SDK display objects are by default centered, that is if I create a 16px x 16px square image, and set it to .x = 0, .y = 0 then half the square will be off the screen to the left and half of the screen to the top.

So you’re math needs to be more like (object.x - object.width / 2) to find the left boundary and (object.x + object.width / 2) to find the right boundary. (same with the Y distances) [import]uid: 19626 topic_id: 15809 reply_id: 58401[/import]

The walls blocks do extend past the wall image by default for the cords. i fixed by doing .height/2 and .width/2

But that does not fix the other problem. It causes the block not go to past it’s image but it still only starts halfway down. I had it working last night but deleted what i did when I was trying something and can’t remember how I fixed it before. [import]uid: 69700 topic_id: 15809 reply_id: 58404[/import]

Can’t you add physics but with 0 gravity? [import]uid: 24111 topic_id: 15809 reply_id: 58419[/import]

Adding physics just to detect if two things ran into each other is a lot of overhead for a 6 line function and an if statement inside a enterFrame event handler.

[import]uid: 19626 topic_id: 15809 reply_id: 58430[/import]

And as I said in the first post, physic’s detection wont work for what I need.

I still haven’t been able to figure out the problem with only half of the object detecting the collision though using the code posted in here with the hasCollided function. [import]uid: 69700 topic_id: 15809 reply_id: 58442[/import]

Can you do a screen shot so we can see what’s going on? Perhaps also post your code where you create the walls?
[import]uid: 19626 topic_id: 15809 reply_id: 58450[/import]

There really is no need for a screen shot. What happens is the top half of a vertical wall does not detect collisions and the left half of a horizontal wall does not detect collisions.

This is an example of how my walls are created.

wall[1] = display.newImageRect( "wallblock.png", 5, 300 )  
wall[1].x = 388  
wall[1].y = 99  
 localGroup:insert(wall[1])  
  
wall[2] = display.newImageRect( "wallblock.png", 220, 5 )  
wall[2].x = 850  
wall[2].y = 248  
 localGroup:insert(wall[2])  
  
wall[3] = display.newImageRect( "wallblock.png", 220, 5 )  
wall[3].x = 495  
wall[3].y = 247  
 localGroup:insert(wall[3])  

I know this can be fixed since I had it working at one point but lost what I changed and cam’t remember how to fix it again. [import]uid: 69700 topic_id: 15809 reply_id: 58516[/import]

I still believe you are having a reference point problem.

The default for Corona SDK Display objects is for the X and Y values to be the center of the object.

( myPlayer.x + myPlayer.width) < wall[i].x

You’re only checking if its less than the center point of the wall or in other words only checking half the wall. Try plopping this in and see if it fixes your problems.

local function hasCollided(obj1, obj2)  
 if obj1 == nil then  
 return false  
 end  
 if obj2 == nil then  
 return false  
 end  
  
 local left = obj1.contentBounds.xMin \<= obj2.contentBounds.xMin and obj1.contentBounds.xMax \>= obj2.contentBounds.xMin  
 local right = obj1.contentBounds.xMin \>= obj2.contentBounds.xMin and obj1.contentBounds.xMin \<= obj2.contentBounds.xMax  
 local up = obj1.contentBounds.yMin \<= obj2.contentBounds.yMin and obj1.contentBounds.yMax \>= obj2.contentBounds.yMin  
 local down = obj1.contentBounds.yMin \>= obj2.contentBounds.yMin and obj1.contentBounds.yMin \<= obj2.contentBounds.yMax  
 return (left or right) and (up or down)  
end  

[import]uid: 19626 topic_id: 15809 reply_id: 58610[/import]

Thanks so much again robmiracle, using that code now for the hasCollidied function fixed the problem and the walls are blocking like they are suppose to. [import]uid: 69700 topic_id: 15809 reply_id: 58621[/import]