Jump to content

[TOPIC: topicViewTemplate]
[GLOBAL: userSmallPhoto]
Photo

How can I detect object collision without physics?
Started by amar.masic6 Oct 30 2018 04:54 AM

7 replies to this topic
collision

Best Answer davebollinger , 30 October 2018 - 07:09 AM

you'll need an overlap test.  here's one:

--- pass me two rects and i'll return boolean true/false if they overlap
function overlap(a,b)
  a, b = a.contentBounds, b.contentBounds
  return (a.xMin <= b.xMax) and (a.xMax >= b.xMin) and (a.yMin <= b.yMax) and (a.yMax >= b.yMin)
end

but i'd also suggest you restructure some other things too.  you can consider it optional, but it'll make your life easier going forward.

 

first, let's give the player a "move" method.  insert this code after creating player:

player.move = function(self,dx,dy)
  self.x = self.x + dx
  self.y = self.y + dy
  -- self:collide() -- haven't written this yet, but this is where it'll go
end
 

then for your arrow taps, reword them to each use that move method:

leftArrow:addEventListener("tap", function() player:move(-5,0) end)
rightArrow:addEventListener("tap", function() player:move(5,0) end)
upArrow:addEventListener("tap", function() player:move(0,-5) end)
downArrow:addEventListener("tap", function() player:move(0,5) end)
 

then, create an array to hold all your blocks so it'll be easier to loop through them:

local blocks = {}
function addBlock(x,y,w,h)
  blocks[#blocks+1] = display.newRect(x,y,w,h)
end
addBlock(centerX, centerY - 50, 100, 220)
-- etc, add all the other blocks similarly

... now, finally!, you're set up to write the collide function for the player, fe:

player.collide = function(self)
  for _,block in pairs(blocks) do
    if (overlap(self,block)) then
      block:setFillColor(1,0,0) -- do "something" in response to the collision, up to you
    end
  end
end

then uncomment that call to collide inside move() and you should be good!

 

NOTE:  the code above is just to give you all the ideas, it's still up to you to implement them properly.  fe, if you just copy/paste the code here as is, rather than thinking about it how it all should fit together, then you may have scope issues (for example the player methods might not know what the "blocks" array is if it's defined later), so make sure you put things in a logical order. 

[TOPIC CONTROLS]
[/TOPIC CONTROLS]
[modOptionsDropdown]
[/modOptionsDropdown]
[reputationFilter]
[TOPIC: post.html]
#1

amar.masic6

[GLOBAL: userInfoPane.html]
amar.masic6
  • Observer

  • 8 posts
  • Corona SDK

All I have in my game is a player, which is this:

local player = display.newRect(30, centerY - 20, 20, 20)
player:setFillColor(0.5)

Movement buttons, which are these:

local upArrow = display.newImage("arrows/up.png", 50, centerY + 30)
local downArrow = display.newImage("arrows/down.png", 50, centerY + 130)
local rightArrow = display.newImage("arrows/right.png", 100, centerY + 80)
local leftArrow = display.newImage("arrows/left.png", 0, centerY + 80)

They work like this:

function moveUp( event )
     player.y = player.y - 5
end
upArrow:addEventListener("tap", moveUp)

And I have objects that I named blocks(which are these white "walls"):

local block1 = display.newRect(centerX, centerY - 50, 100, 220)
local block2 = display.newRect(centerX + 125, centerY + 135, 350, 80)
local block3 = display.newRect(centerX + 188, centerY + 45, 200, 100)
local block4 = display.newRect(centerX + 100, centerY - 100, 100, 125)
local block5 = display.newRect(centerX + 240, centerY - 50, 100, 100)
local block6 = display.newRect(centerX + 230, centerY - 160, 160, 50)

How could I detect the player hitting one of these blocks?

 

Attached Files



[TOPIC: post.html]
#2

XeduR @Spyric

[GLOBAL: userInfoPane.html]
XeduR @Spyric
  • Contributor

  • 293 posts
  • Corona SDK

You could write an enterframe function that compares the player's coordinates to those blocks. This kind of comparison would be easiest done if those blocks were in a table.

 

At its simplest, you know that the player is touching a block if the player's coordinates are located within a block. However, since your player is not 1 pixel by 1 pixel in size, you need to take its dimensions into account as well.

 

If you create an enterframe function that loops through each block, all you'd need to do is check if the player's x coordinates +/- half of its width are within a block's coordinates +/- half of the block's width, and same for the y values and the objects' heights.

You can (and should) add checks to the enterframe function to reduce the number of necessary calculations. For instance, first check to see only if a player is within the x bounds of a block. If it isn't, then the y bounds don't matter, etc. Depending on how you implement this system, there are numerous other means of improving its performance.



[TOPIC: post.html]
#3

davebollinger

[GLOBAL: userInfoPane.html]
davebollinger
  • Corona Geek

  • 1,236 posts
  • Enterprise

  Best Answer

you'll need an overlap test.  here's one:

--- pass me two rects and i'll return boolean true/false if they overlap
function overlap(a,b)
  a, b = a.contentBounds, b.contentBounds
  return (a.xMin <= b.xMax) and (a.xMax >= b.xMin) and (a.yMin <= b.yMax) and (a.yMax >= b.yMin)
end

but i'd also suggest you restructure some other things too.  you can consider it optional, but it'll make your life easier going forward.

 

first, let's give the player a "move" method.  insert this code after creating player:

player.move = function(self,dx,dy)
  self.x = self.x + dx
  self.y = self.y + dy
  -- self:collide() -- haven't written this yet, but this is where it'll go
end
 

then for your arrow taps, reword them to each use that move method:

leftArrow:addEventListener("tap", function() player:move(-5,0) end)
rightArrow:addEventListener("tap", function() player:move(5,0) end)
upArrow:addEventListener("tap", function() player:move(0,-5) end)
downArrow:addEventListener("tap", function() player:move(0,5) end)
 

then, create an array to hold all your blocks so it'll be easier to loop through them:

local blocks = {}
function addBlock(x,y,w,h)
  blocks[#blocks+1] = display.newRect(x,y,w,h)
end
addBlock(centerX, centerY - 50, 100, 220)
-- etc, add all the other blocks similarly

... now, finally!, you're set up to write the collide function for the player, fe:

player.collide = function(self)
  for _,block in pairs(blocks) do
    if (overlap(self,block)) then
      block:setFillColor(1,0,0) -- do "something" in response to the collision, up to you
    end
  end
end

then uncomment that call to collide inside move() and you should be good!

 

NOTE:  the code above is just to give you all the ideas, it's still up to you to implement them properly.  fe, if you just copy/paste the code here as is, rather than thinking about it how it all should fit together, then you may have scope issues (for example the player methods might not know what the "blocks" array is if it's defined later), so make sure you put things in a logical order. 


  • roaminggamer likes this

[TOPIC: post.html]
#4

Rob Miracle

[GLOBAL: userInfoPane.html]
Rob Miracle
  • Moderator

  • 24,860 posts
  • Corona Staff

We have a tutorial for that: http://docs.coronalabs.com/tutorial/games/nonPhysicalCollision/index.html

 

Rob



[TOPIC: post.html]
#5

amar.masic6

[GLOBAL: userInfoPane.html]
amar.masic6
  • Observer

  • 8 posts
  • Corona SDK

Thank you all for your help, davebollinger's answer worked for me.

 

I'm just wondering how isn't there a function or something to check for collision in Corona, it seems like a such a simple thing, but I guess it's not.



[TOPIC: post.html]
#6

Rob Miracle

[GLOBAL: userInfoPane.html]
Rob Miracle
  • Moderator

  • 24,860 posts
  • Corona Staff

Corona has collision detection support, but it's part of the physics engine. 

 

Rob



[TOPIC: post.html]
#7

davebollinger

[GLOBAL: userInfoPane.html]
davebollinger
  • Corona Geek

  • 1,236 posts
  • Enterprise

Thank you all for your help, davebollinger's answer worked for me.

 

I'm just wondering how isn't there a function or something to check for collision in Corona, it seems like a such a simple thing, but I guess it's not.

 

as Rob said, if you want full collision (contact detection and dynamics response) then physics lib, easy

 

but if you just want overlap testing, then DIY.  still easy, no big deal -- axis-aligned-rect-vs-rect overlap algorithm has been around since at least early 70's "Pong" and hasn't changed a bit since (SAT as proof that 4 tests suffice), so just grab the "one-liner" above and done. :)



[TOPIC: post.html]
#8

XeduR @Spyric

[GLOBAL: userInfoPane.html]
XeduR @Spyric
  • Contributor

  • 293 posts
  • Corona SDK

Collision detection for all simple convex and concave polygons is also easily doable without physics.




[topic_controls]
[/topic_controls]

Also tagged with one or more of these keywords: collision