Moving objects to another object with dynamic coordinates

Hello Guys!

I have started developing with Corona SDK again recently and want to develop my first commercial game.

However, I came across some problems by moving objects to another movable object. 

Let me explain a few things first:

  • The app is playable in landscape view
  • The player is located on the left side and can move up and down (Y-Coordinate)
  • Enemies spawn on the right side and move to the player location
  • When the player moves, all enemies should follow him
  • The player can shoot the objects

HrdOuta.png

I have managed to archive this by the following methods

local function spawnEnemy() local zombie = display.newRect(midGroup, screenWidth, math.random(0, screenHeight), 100, 100 ) zombie.isEnemy = true zombie.name = "zombie" zombie.life = 10 physics.addBody(zombie, "dynamic", {bounce=0, radius=50}) transition.moveTo( zombie, {time=(zombie.x-player.x)\*speedFactor, x=playerGroundWidth/2, y=player.y} ) table.insert(zombieList, zombie) end local function movePlayer(event) local diffY = player.y - event.y local finalY if (event.y \>= screenHeight - 100) then finalY = screenHeight - playerHeight / 2 else finalY = event.y end transition.to( player, {time=math.abs(diffY) , x=player.x, y=finalY} ) for i=#zombieList, 1, -1 do local speed = math.sqrt(((event.x - zombieList[i].x) ^ 2) + ((event.y - zombieList[i].y) ^ 2)) transition.to(zombieList[i], {time=speed\*speedFactor, x=playerGroundWidth/2., y=event.y}) end end

However, there are a few problems

  1. Whenever the player moves, all enemies move to the new player position. This is ok, but the enemies should not move through other enemies. So each enemy should move closer to the player, but can’t pass other enemies if they are infront of them.

Imagine it like a bunch of kids are following an ice cream truck. They can’t go to the seller all the same time, they have to buy the ice one by one
 
2. The same goes when the player kills an enemy, so all remaining enemies move closer to the player. Guess it can be archived with the same method?

Of course the enemies can’t pass the player ground, I’ve added a static physics body to it.

tz1QIEn.png

Do you have any suggestion with this problem?

Best Regards

SSK2 has features that will help with this kind of game development and these calculations.

Additionally I have a TON of free examples here: https://github.com/roaminggamer/RG_FreeStuff

Among these examples/answers is one that is very similar to what you are looking for:

https://github.com/roaminggamer/RG_FreeStuff/raw/master/AskEd/2015/07/zombieFollow.zip

https://www.youtube.com/watch?v=Y4QQjSMo10M&feature=youtu.be

Better with SSK2.

As far as not wanting enemy overlap, that is actually quite complicated.

Some possibilities:

  1. Add bodies to each enemy and ensure they can collide with each other. That will stop them from overlapping each other. 

  2. If you want to skip using physics bodies, then you need to make a much more sophisticated movement algorithm including flocking and avoidance code.

The essence of the avoidance code would be:

  1. Zombie 1 wants to move
  2. Determine vector of movement.
  3. Determine distance of vector + twice the radius of zombie.
  4. Check all other zombies to see if distance from zombie 1 to each other zombie is less than distance in last step (3).
  5. If YES no not move Zombie 1 or only move a shorter distane.
  6. If NO, move
  7. Repeat for next zombie 2…
  8. Repeat for next zombie 3…
  9. Repeat for next zombie 4…
  10. Repeat for next zombie N…
  11. Start over on next move period.

You won’t want to use transitions for this.

Thanks for the help, the example App helped me with this problem, because I totally forgot about the “enterFrame” event listener.

This solved most of my problems.

If anyone wonders how I did that, here’s the code:

local function spawnEnemy() local moveEnemy = function(self) if (self.name == "zombie") then local velocityY = player.y - self.y if (velocityY \> 100) then velocityY = 100 elseif (velocityY \< -100)then velocityY = -100 end self:setLinearVelocity(-150,velocityY) end end local zombie = display.newCircle(midGroup, screenWidth, math.random(0, screenHeight), 40) zombie.isEnemy = true zombie.name = "zombie" zombie.life = 10 physics.addBody(zombie, "dynamic", {bounce=0, radius=40}) table.insert(zombieList, zombie) zombie.enterFrame = moveEnemy Runtime:addEventListener("enterFrame", zombie) end

By using this event listener, I can handle all the movement in this function

Of course if you delete the object, you have to unset the event listener , otherwise it will result in a nil object error

local function deleteObj(obj) display.remove(obj) obj = nil end local function enemyDies(obj) if (obj.name == "zombie") then updateScore(10) for i = #zombieList, 1, -1 do if (zombieList[i] == obj) then obj.enterFrame = nil table.remove(zombieList, i) deleteObj(obj) break end end end end

SSK2 has features that will help with this kind of game development and these calculations.

Additionally I have a TON of free examples here: https://github.com/roaminggamer/RG_FreeStuff

Among these examples/answers is one that is very similar to what you are looking for:

https://github.com/roaminggamer/RG_FreeStuff/raw/master/AskEd/2015/07/zombieFollow.zip

https://www.youtube.com/watch?v=Y4QQjSMo10M&feature=youtu.be

Better with SSK2.

As far as not wanting enemy overlap, that is actually quite complicated.

Some possibilities:

  1. Add bodies to each enemy and ensure they can collide with each other. That will stop them from overlapping each other. 

  2. If you want to skip using physics bodies, then you need to make a much more sophisticated movement algorithm including flocking and avoidance code.

The essence of the avoidance code would be:

  1. Zombie 1 wants to move
  2. Determine vector of movement.
  3. Determine distance of vector + twice the radius of zombie.
  4. Check all other zombies to see if distance from zombie 1 to each other zombie is less than distance in last step (3).
  5. If YES no not move Zombie 1 or only move a shorter distane.
  6. If NO, move
  7. Repeat for next zombie 2…
  8. Repeat for next zombie 3…
  9. Repeat for next zombie 4…
  10. Repeat for next zombie N…
  11. Start over on next move period.

You won’t want to use transitions for this.

Thanks for the help, the example App helped me with this problem, because I totally forgot about the “enterFrame” event listener.

This solved most of my problems.

If anyone wonders how I did that, here’s the code:

local function spawnEnemy() local moveEnemy = function(self) if (self.name == "zombie") then local velocityY = player.y - self.y if (velocityY \> 100) then velocityY = 100 elseif (velocityY \< -100)then velocityY = -100 end self:setLinearVelocity(-150,velocityY) end end local zombie = display.newCircle(midGroup, screenWidth, math.random(0, screenHeight), 40) zombie.isEnemy = true zombie.name = "zombie" zombie.life = 10 physics.addBody(zombie, "dynamic", {bounce=0, radius=40}) table.insert(zombieList, zombie) zombie.enterFrame = moveEnemy Runtime:addEventListener("enterFrame", zombie) end

By using this event listener, I can handle all the movement in this function

Of course if you delete the object, you have to unset the event listener , otherwise it will result in a nil object error

local function deleteObj(obj) display.remove(obj) obj = nil end local function enemyDies(obj) if (obj.name == "zombie") then updateScore(10) for i = #zombieList, 1, -1 do if (zombieList[i] == obj) then obj.enterFrame = nil table.remove(zombieList, i) deleteObj(obj) break end end end end