Help me decide what to do next?

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
User avatar
Robin
The Omniscient
Posts: 6506
Joined: Fri Feb 20, 2009 4:29 pm
Location: The Netherlands
Contact:

Re: Help me decide what to do next?

Post by Robin »

lesslucid wrote:So, does that mean that if I require modules, write helper functions, declare global variables, creates classes, &c &c, outside the love.load function, these are getting processed over and over again?
No!

That is, unless you're putting them in the other callbacks. In terms of what is being run, this is roughly the order of execution:

Code: Select all

boot.lua (internal, can't write it yourself)
    conf.lua
    love.conf()
    main.lua
    love.run() (a default one is given by boot.lua, you may override it if you want)
        love.load()
       {
        love.update()
        love.draw()
        other love callbacks
       } repeat this bit over and over
So it generally doesn't matter much if you put it inside love.load() or just in your main.lua, although there are exceptions, and it is generally considered cleaner to put them in love.load().
Help us help you: attach a .love.
lesslucid
Prole
Posts: 20
Joined: Sun Mar 20, 2011 8:25 am

Re: Help me decide what to do next?

Post by lesslucid »

Ah, great, thankyou!
lesslucid
Prole
Posts: 20
Joined: Sun Mar 20, 2011 8:25 am

Re: Help me decide what to do next?

Post by lesslucid »

Trying to program after a couple of months away from it hurts my brain.

Any suggestion on a nice gentle way back "in"?
User avatar
T-Bone
Inner party member
Posts: 1492
Joined: Thu Jun 09, 2011 9:03 am

Re: Help me decide what to do next?

Post by T-Bone »

Depends on how much you forgot. Maybe rewriting a pong game again would be a good place to start? Retracing your own steps is usually quite easy and fast (although a bit boring). It will probably make you remember everything.

Of course, it could be much more fun to do something completely new. In my experience, the general idea of programming can't be forgotten or unlearned once you've learnt it once. I think all you probably need is some simple practise to get the syntax back into your brain.
User avatar
Lafolie
Inner party member
Posts: 809
Joined: Tue Apr 05, 2011 2:59 pm
Location: SR388
Contact:

Re: Help me decide what to do next?

Post by Lafolie »

Well commented code is always a nice doorway into an older project.
Do you recognise when the world won't stop for you? Or when the days don't care what you've got to do? When the weight's too tough to lift up, what do you? Don't let them choose for you, that's on you.
User avatar
kikito
Inner party member
Posts: 3153
Joined: Sat Oct 03, 2009 5:22 pm
Location: Madrid, Spain
Contact:

Re: Help me decide what to do next?

Post by kikito »

Lafolie wrote:Well commented code is always a nice doorway into an older project.
Each comment is a failure.

Comments are used to clarify parts of the source code that are difficult to understand.

A more future proof solution: when you think you need to clarify some code, instead of writing a comment, make the code more clear.

There are many ways to do this. I've found that the directives in the Clean Code book help a lot. Here's a short abstract.
  • Use variable names that express intent (not implementation) and are readable (not abbreviation). opposingTeams instead of OpTe, ot, or otArray
  • Each function should do one thing, and one thing only. This usually means 6 lines of code or less, per function. You usually only have one if, while or for per function.
  • Each function should have preferentially no arguments, and 3 at most. Boolean arguments are not permitted (they implicitly make a function do two different things, and that is forbidden)
  • Maintain the same abstraction level inside a function. Inside the same function, you should not have a code that reads enemy = self.brain:getNearestEnemy() and self.x = x + 10 (that second part should be moved to another function, probably called self:moveTowardsTarget(enemy))
  • Respect Demeter's law.
The book is much more extense, of course. There's also a video series, from the same author, but it isn't cheap. I recommend starting with the book.
When I write def I mean function.
User avatar
kraftman
Party member
Posts: 277
Joined: Sat May 14, 2011 10:18 am

Re: Help me decide what to do next?

Post by kraftman »

Why is it forbidden for a function to do two different things? What would you use instead?

Why does lua include "..." if functions shouldnt have arguments? :P

IMO commenting is less explaining your complicated code, more explaining your complicated problem.
User avatar
Robin
The Omniscient
Posts: 6506
Joined: Fri Feb 20, 2009 4:29 pm
Location: The Netherlands
Contact:

Re: Help me decide what to do next?

Post by Robin »

kraftman wrote:Why is it forbidden for a function to do two different things? What would you use instead?
As he said, two functions.
kraftman wrote:Why does lua include "..." if functions shouldnt have arguments? :P
It's that philosophy "Clean Code" that dictates it. Functional programming, for example, requires arguments to pass information.

I find myself agreeing with most of those points, but the whole no arguments/no boolean arguments thing really doesn't make sense in my book.
kraftman wrote:IMO commenting is less explaining your complicated code, more explaining your complicated problem.
If you mean what I think it is you mean, then I agree with you. Comments should explain why you're doing something, not what you're doing.

Code: Select all

-- what follows may look like a giant hack, but it makes our inner loop O(n) rather than O(2^n)
Help us help you: attach a .love.
User avatar
bartbes
Sex machine
Posts: 4946
Joined: Fri Aug 29, 2008 10:35 am
Location: The Netherlands
Contact:

Re: Help me decide what to do next?

Post by bartbes »

It also helps to document what you're supposed to be doing/what you think you are doing, because reading this again later, or if someone else reads it, this might mean a bug is found easier.
User avatar
kikito
Inner party member
Posts: 3153
Joined: Sat Oct 03, 2009 5:22 pm
Location: Madrid, Spain
Contact:

Re: Help me decide what to do next?

Post by kikito »

kraftman wrote:Why is it forbidden for a function to do two different things?
There are many reasons. The first one is that functions are supposed to be reusable. If you divide a big function into smaller functions, you can reuse those smaller functions in other places. The other reason is that by giving proper names to those functions, your code looks more like English and less than machine code. It's easier to understand for humans.

A big function is like a landscape that one has to explore in order to "understand". When you have smaller functions with significant names, those names act as "signposts" indicating where the code "goes" to humans.
kraftman wrote:What would you use instead?
If a function does two things, you divide it in two functions, give those functions proper, significant, pronounceable names, and call those functions from the original one.

For example, if you have a big function like this one:

(Note: I'll be using my class library, middleclass, tangentially, just to show how a good design and object orientation facilitate making stuff)

Code: Select all

function Turret:update(dt)
  local t
  local dx,dy,d
  local cd = math.huge
  for _,p in ipairs(Game.players)
    dx = self.x - p.x
    dy = self.y - p.y
    d = dx*dx + dy*dy
    if d < cd then
      t = p
      cd = d
    end
  end

  if t then
    Bullet.new(self.x, self.y, math.atan2(self.x - t.x, self.y - t.y))
  end
end
The problem lesslucid has is that his functions look a lot like that one (or are even more complex). When you have lots of functions like that, your code tends to become unmanageable, especially if you return to it after not touching it for several months. It's a code that you understand while you are writing, and certainly the machine understands it, but it doesn't have "signposts" for future visitors. They have to "explore" it to know it.

One option is to put a couple comments.

Code: Select all

function Turret:update(dt)
  -- get nearest player within sight
  local t
  local dx,dy,d
  local cd = math.huge
  for _,p in ipairs(Game.players)
    dx = self.x - p.x
    dy = self.y - p.y
    d = dx*dx + dy*dy
    if d < cd then
      t = p
      cd = d
    end
  end

  -- shoot a bullet to the player
  if t then
    Bullet.new(self.x, self.y, math.atan2(self.x - t.x, self.y - t.y))
  end
end
A much, much better solution is extracting those two "different things" into functions, ditch the comments, and use better names for the variable while you are at it.

While you are doing this, you will suddenly realize that this function isn't really making two things. It's doing *LOTS* of things. Each one of those things belongs to a different function.

Like this:

Code: Select all

function Turret:update(dt)
  local target = self:getTarget()
  if target then self:shootAt(target) end
end

function Turret:getTarget()
  return self:getNearest(Game.players)
end

function Turret:getNearest(objects)
  local distance, nearest
  local shortestDistance = math.huge
  for _,object in ipairs(objects)
    distance = self:getSquaredDistance(object)
    if distance < shortestDistance then
      nearest = object
      shortestDistance = distance
    end
  end
  return nearest
end

function Turret:getSquaredDistance(object)
  local dx, dy = self.x - object.x, self.y - object.y
  return dx*dx + dy*dy
end

function Turret:shootAt(target)
  Bullet.new(self.x, self.y, self:getAngle(target))
end

function Turret:getAngle(object)
  return math.atan2(self.x - t.x, self.y - t.y)
end
I'm sorry but I could not make Turrent:getNearest any smaller.

Both programs do the same; for the machine, they are no different. But for programmers, they are so much easier to understand and maintain. Take a look at Turret:update()! Isn't it just beautiful?

And now that you have smaller functions, you can reuse them in other places. I could move getDistance and getAngle to a Vector class, for example. That way I could use code for calculating distances and angles in all Enemies and Players, not just in my Turret class.

Notice that the Turret is prepared to attack players, but it's very easy to subclass it now and create a turret that shoots other things, like asteroids. Actually, let me show you:

Code: Select all

AsteroidCleaningTurret = class('AsteroidCleaningTurret', Turret)
function AsteroidCleaningTurret:getTarget()
  return self:getNearest(Game.asteroids)
end
That's it. If I create an AsteroidCleaningTurret, it'll start shooting asteroids. In 4 lines. If the code of Turret:update() was the first version, I would have had to fiddle much more in order to do this. It's so easy to modify now! I could make a DrunkenTurret that calculates angles badly. Or one that shoots 4 bullets instead of just one. There're so many places you can tweak!

...

And I guess I'll just shut up now. I hope I made my point. Each function should do just one thing because that's better for the Universe.
When I write def I mean function.
Post Reply

Who is online

Users browsing this forum: No registered users and 49 guests