Page 3 of 4

Re: What am I doing wrong here?

Posted: Fri Apr 15, 2011 3:39 pm
by kikito
^^

I'm glad it worked nicely for you!

Object orientation is a nice evolution from functions + tables, but it's still no silver bullet. The same way it is sometimes difficult to divide the code into functions, it is also difficult to group data and functions into classes. Please post in the forum when you hit these difficulties (you will).

Re: What am I doing wrong here?

Posted: Fri Apr 15, 2011 4:05 pm
by Robin
+1 to everything nevon just said.
kikito wrote:but it's still no silver bullet.
Coming from you that shocks me greatly. :P

Also, this is not about OO specifically, but it's a tool. And in the world of games, it's a very natural and useful tool as well.

Re: What am I doing wrong here?

Posted: Fri Apr 15, 2011 8:10 pm
by Jasoco
Using this information I was able to come up with a sample enemy prototype framework to use in my future and current games..

Code: Select all

enemyPrototype = {}

enemyPrototype.goomba = {}
function enemyPrototype.goomba:new(x,y)
  local enemyInstance = {}
  setmetatable(enemyInstance, {__index = self})
  enemyInstance:reset(x,y)
  return enemyInstance
end
function enemyPrototype.goomba:reset(x,y)
  self.x = x
  self.y = y
end
function enemyPrototype.goomba:update(dt)
  self.x = self.x + math.cos(time)
  self.y = self.y + math.sin(time)
end
function enemyPrototype.goomba:draw()
  gr.setColor(100,50,10)
  gr.circle("fill", self.x, self.y, 8)
end

enemyPrototype.koopa = {}
function enemyPrototype.koopa:new(x,y)
  local enemyInstance = {}
  setmetatable(enemyInstance, {__index = self})
  enemyInstance:reset(x,y)
  return enemyInstance
end
function enemyPrototype.koopa:reset(x,y)
  self.x = x
  self.y = y
end
function enemyPrototype.koopa:update(dt)
  self.x = self.x + math.cos(time)
  self.y = self.y + math.sin(time)
end
function enemyPrototype.koopa:draw()
  gr.setColor(0,255,0)
  gr.circle("fill", self.x, self.y, 8)
end
Koopa and Goomba are used as examples. It's just an example for future use.
If I want to make say, a new Goomba, I call enemy[id] = enemyPrototype.goomba:new(x,y)

Another question would be about checking for collisions with each other. How would I go about that the best way? Have to iterate over the table of enemies and check all of them against the current one. But how would I know which is the current self without passing the table id into the update function first so I know which one is the current one so as not to check against itself?

Re: What am I doing wrong here?

Posted: Fri Apr 15, 2011 9:48 pm
by miko
Jasoco wrote: Another question would be about checking for collisions with each other. How would I go about that the best way? Have to iterate over the table of enemies and check all of them against the current one. But how would I know which is the current self without passing the table id into the update function first so I know which one is the current one so as not to check against itself?

Code: Select all

function ...:update(dt)
...
for id,e in pairs(enemy) do
  if e~=self then
      checkCollision(self, e)
  end
end
That would be "brute force" approach (ie. check every combination), and is not efficient (but could be good enough for small number of objects).
Note that you would check A against B and B against A - so half of those checks would be reduntant (if A collides with B, then B collides with A).
You could checkfor collisions only for those objects which have just changed their position (if some of them are not moving).
You could check for collisions between neighbours only, if you could tell which of them are close to each other (for example, google for "quad tree").
Finally, you need to define a collision. That could be collisions between points (the easiest), rectangles ("bounding boxes"), circles, or more complicated shapes. In practice, using rectangles or circles is good enough.

Re: What am I doing wrong here?

Posted: Sat Apr 16, 2011 8:54 am
by BlackBulletIV
nevon wrote:That said, I find it amazing that you were able to create your adventure game engine without knowing OOP. That must have been hell.
Here, here! Coding anything that's not small without OOP is a nightmare for me.

Re: What am I doing wrong here?

Posted: Sat Apr 16, 2011 3:44 pm
by kikito
Jasoco wrote:Using this information I was able to come up with a sample enemy prototype framework to use in my future and current games.. (...)
Well, I prefer classes to prototypes, but I'll keep an eye on your evolution there. It's certainly a less beaten path than classic object orientation.
Jasoco wrote:Another question would be about checking for collisions with each other. How would I go about that the best way? Have to iterate over the table of enemies and check all of them against the current one. But how would I know which is the current self without passing the table id into the update function first so I know which one is the current one so as not to check against itself?
There are lots of approaches here. The simplest approach is certainly comparing every enemy with every other enemy, on each iteration.

The simplest way avoid "comparing against self" is doing exactly that: if (other ~= current) then ....

The brute force approach is good enough when the number of objects being compared is more or less low. It increases its cost exponentially with each new object that you add. If you are going to have lots of entities simultaneously, you will probably want to trim down the number of comparisons that you do.

One approach is dividing the "space" into sections. You divide the screen into, say, 16 rectangular sections. Then, whenever you update the coordinates of each enemy, you also update the section on which that enemy is. And when you need to check for collisions, you only compare with the enemies on that section (there are special conditions for enemies "in between" sections).

Another approach is having a "hard map". A hard map is a 2d array representing your screen, usually at a smaller resolution. At the begining of each frame, the hardmap cells are reset to a "blank" state, for example the number 0. Then, on the update function, every enemy "draws itself" on the hard map. This is, it changes some 0s to 1s. Collision detection then is a matter of looking at the hardmap and checking for a 1. This method is the fastest but also the one with lowest resolution; there are occasions in which 2 entities draw a "1" on the hardmap but they don't really collide; they are just close. This is why this method is better for tile-based games, specially if movement is done tile-by-tile, and not incrementally.

Re: What am I doing wrong here?

Posted: Sat Apr 16, 2011 11:16 pm
by Robin
kikito wrote:The
I think you miss something there.

Re: What am I doing wrong here?

Posted: Sat Apr 16, 2011 11:59 pm
by kikito
It was a leftover from my edits. I've removed it now, thanks! (I also fixed incorrectly closed quotes)

Re: What am I doing wrong here?

Posted: Thu Jun 09, 2011 7:26 pm
by Jasoco
Here's a question.

How's come I can do this:

Code: Select all

enemySet.goomba = {}

function enemySet.goomba:setup(v)
  ...
end
But I can't do this:

Code: Select all

enemySet["goomba"] = {}

function enemySet["goomba"]:setup(v)
  ...
end

Re: What am I doing wrong here?

Posted: Thu Jun 09, 2011 7:32 pm
by bartbes
Not.. sure.., I know you can work around and do this, though:

Code: Select all

enemySet["goomba"].setup = function(self, v)
or:

Code: Select all

local goomba = enemySet["goomba"]
function goomba:setup(v)