Help with game lag

General discussion about LÖVE, Lua, game development, puns, and unicorns.
User avatar
Sefhi
Prole
Posts: 1
Joined: Fri Nov 14, 2014 2:19 pm

Help with game lag

Post by Sefhi »

First of all a couple of things, it's my first post so i dont know if it's in the right place, and second english isn't my native language so sorry if i write bad or some sentences don't have coherence xD.

I'm making my first game with Löve (and my first game in general) , and the problem probably is that i'm doing wrong a lot of things, anyway. Today i woke up and started coding, but when i ran the game, it was soooooooooooooooooo laggy, laggy as hell. And yesterday the game ran perfect, no lag, no screeen shakes, so i dont know what the f*** i changed. The last files i wrote was enemyNormal, enemyWave and the game. I attach the .love file so you can check the game and the code.

Well, i'll be glad if someone can help me, and of course, tell me what i'm doing wrong coding and if something is right :crazy: , see ya!
Attachments
2042.love
The game in question.
(178.58 KiB) Downloaded 247 times
User avatar
SpotlightKid
Prole
Posts: 6
Joined: Mon Nov 10, 2014 7:57 am
Location: Cologne, Germany

Re: Help with game lag

Post by SpotlightKid »

I don't have any advice on your code but rather on coding practice. Maybe you already do, but if you don't, get in the habit of putting your code into a version control system (e.g. git, mercurial, subversion) right away when you start a project and commit your changes often. Especially when you finish a coding session, e.g. when you go to bed, make sure, you have a clean working space and have commited your latest changes with meaningful commit log messages. Don't leave committing your changes until the next day / coding session, because by then you might not remember all the details of what you changed and, more importantly, why.

This way, the next day, when you're wondering why your code isn't working as before, you have a way of finding out what you changed exactly and, more importantly of going back to a known working state.

Update: I had a quck look at your main.lua. One thing that caught my attention immediately is that you are not handling modules correctly.

In love.load() you do:

Code: Select all

local splash = require"splash"
which assigns the return value from splash.lua to a local variable, which is only in scope within that function. But you then use

Code: Select all

splash.update(dt)
in your love.update() function. But splash here isn't the local variable you assigned with require in love.load(). It's a global variable that is assigned when require loads the splash.lua file, because in splash.lua you don't make splash local. So it works, but only accidentally and you may experience strange behaviour if you aren't aware which variables are global and which local and what your modules are doing to the global variable namespace.

I suggest reading the section on modules in the book "Programming in Lua" to get this straight.
jjmafiae
Party member
Posts: 1331
Joined: Tue Jul 24, 2012 8:22 am

Re: Help with game lag

Post by jjmafiae »

Disclaimer: I haven't looked at your code I just have some general tips

tip 1: Only draw what's visible
tip 2: Do as little love.graphics.setColor() as possible
tip 3: read this: http://www.love2d.org/wiki/Optimising
tip 4: use locals and remove any unused globals
User avatar
Positive07
Party member
Posts: 1014
Joined: Sun Aug 12, 2012 4:34 pm
Location: Argentina

Re: Help with game lag

Post by Positive07 »

jjmafiae wrote: tip 2: Do as little love.graphics.setColor() as possible
Why?? I use it like a thousand times and NOTHING, I dont think this is a bottleneck
for i, person in ipairs(everybody) do
[tab]if not person.obey then person:setObey(true) end
end
love.system.openURL(github.com/pablomayobre)
User avatar
s-ol
Party member
Posts: 1077
Joined: Mon Sep 15, 2014 7:41 pm
Location: Cologne, Germany
Contact:

Re: Help with game lag

Post by s-ol »

Positive07 wrote:
jjmafiae wrote: tip 2: Do as little love.graphics.setColor() as possible
Why?? I use it like a thousand times and NOTHING, I dont think this is a bottleneck
Well, it is a bottleneck. Replace it with pre-"compiled" meshes where possible (but don't build new ones in draw!) or use shades to both lose triangles and color change calls.

s-ol.nu /blog  -  p.s-ol.be /st8.lua  -  g.s-ol.be /gtglg /curcur

Code: Select all

print( type(love) )
if false then
  baby:hurt(me)
end
User avatar
undef
Party member
Posts: 438
Joined: Mon Jun 10, 2013 3:09 pm
Location: Berlin
Contact:

Re: Help with game lag

Post by undef »

I agree with SpotlightKid.
Also upon quick glance I noticed that you use a lot of if-statements without the use of else or elseif.
That causes your code to check every statement, even though some of them are always false if others are true.

For example:

Code: Select all

	if gameState == 0 then -- Splash screen, mango and dat stuff
    splash.update(dt)
	end
	if gameState == 1 then --Menu screen, simple animation, buttons and show the highscore
    menu.update(dt)
	end

Positive07 wrote:
jjmafiae wrote: tip 2: Do as little love.graphics.setColor() as possible
Why?? I use it like a thousand times and NOTHING, I dont think this is a bottleneck
I don't believe this is a bottleneck either...

Edit:
Just checked, and I can call love.graphics.setColor 42000 times per second before dropping in framerate on my old laptop.
twitter | steam | indieDB

Check out quadrant on Steam!
User avatar
s-ol
Party member
Posts: 1077
Joined: Mon Sep 15, 2014 7:41 pm
Location: Cologne, Germany
Contact:

Re: Help with game lag

Post by s-ol »

undef wrote:I agree with SpotlightKid.
Also upon quick glance I noticed that you use a lot of if-statements without the use of else or elseif.
That causes your code to check every statement, even though some of them are always false if others are true.

For example:

Code: Select all

	if gameState == 0 then -- Splash screen, mango and dat stuff
    splash.update(dt)
	end
	if gameState == 1 then --Menu screen, simple animation, buttons and show the highscore
    menu.update(dt)
	end

Positive07 wrote:
jjmafiae wrote: tip 2: Do as little love.graphics.setColor() as possible
Why?? I use it like a thousand times and NOTHING, I dont think this is a bottleneck
I don't believe this is a bottleneck either...

Edit:
Just checked, and I can call love.graphics.setColor 42000 times per second before dropping in framerate on my old laptop.
It's context dependent though, of course it runs rather fast like that.

s-ol.nu /blog  -  p.s-ol.be /st8.lua  -  g.s-ol.be /gtglg /curcur

Code: Select all

print( type(love) )
if false then
  baby:hurt(me)
end
Muris
Party member
Posts: 131
Joined: Fri May 23, 2014 9:18 am

Re: Help with game lag

Post by Muris »

I did quickly glance the code, and what I see is that what you are trying to do is OOP approach to the programming. The bad thing is though, nothing is encapsulated and everything is flooding global variables, which you can essentially think as static members in other languages. In other words they are visible from any other file and accessible from those.

I have some suggestions of possible points where there could be some performance issues, but I am not master of LUA, so don't take everything for granted for being the best solution.

I am not the best person to answer, but here are couple of things that I noticed:

Use of globals:

Code: Select all

-- In main.lua
function love.load()
	love.mouse.setVisible (false) -- disable the mouse
	gameState = 1 -- 0 splash screen, 1 menu, 2 game, 3 scores
gameState is now a global variable. If you know java, this would essentially be same as static int gameState = 1;

And local variable scope:

Code: Select all

-- inside love.load()
  local splash = require"splash"
  local game = require"game"
  local menu = require"menu"
  local over = require"gameover"

  -- Enemies
  local enemyWave = require"enemyWave"
  --local enemyBall = require"enemyBall"
  local enemyNormal = require"enemyNormal"
These variables are local meaning they are only visible inside love.load, essentially compared to other languages you can think it working same way as:

Code: Select all

{
   int size = 300;
}
size += 100; // <-- error, size does not exist outside the scope. This is what local does for variable.
How I would fix these problems:

Code: Select all


local splash = require"splash" -- now these splash, game etc are 
local game = require"game"
local menu = require"menu"
local over = require"gameover"

local gameState = game  -- now this variable is only visible inside main.lua, and not accessible from any other file.

-- Enemies
local enemyWave = require"enemyWave"
--local enemyBall = require"enemyBall"
local enemyNormal = require"enemyNormal"

function love.load()
	love.mouse.setVisible (false) -- disable the mouse
...

function love.update(dt)
   -- setting gameState value splash, game, menu or over essentially makes it possible to just call update through it
   gameState.update(dt) 
end

function setState( stateName )
   if( stateName == "game" ) gameState = game
   elseif( stateName == "splash" ) gameState = splash
   elseif( stateName == "menu" ) gameState = menu
   elseif( stateName == "gameover" ) gameState = over
   end
end

Then move the

Code: Select all

    enemyWave.update(dt)
    --enemyBall.update(dt)
    enemyNormal.update(dt)

into game.update(dt)

Now the OOP. The thing with lua is that it doesn't exactly have classes, but you can mimic this feature, and I think there are some lua-files for even greater way of providing classes than what the lua documentation suggests. I myself havent used those so probably someone else can give a better explanation on those. Here is the lua reference: http://lua-users.org/wiki/SimpleLuaClasses

What you basically do is create an array, then splash the methods into the object with the setmetatable. Something to notice tho, obj:func(a) is not the same as obj.func(a). The one with the semicolon uses the obj as reference, and one without it is kind of like just normal static function. As a matter of fact obj:func(a) is essentially same as obj.func(a, obj).

Then some other speed up suggestions:

Throughout the code there are lots of loops that iterate objects through. It would be better to try to reduce the amount of iterations and do as much as possible inside one loop. Also ipairs in general is something that isn't as recommended as simply indexing table,
So for example:

Code: Select all

-- enemyNormal.lua : update

  for i, enemy in ipairs(normalEnemies) do --movement of the ships
    enemy.x = enemy.x - (normalEnemy.speed * dt)
  end

  for i, enemy in ipairs(normalEnemies) do
    if enemy.x <= -80 then
      table.remove(normalEnemies, i) -- delete enemies when left screen
    end
    if enemy.health < 1 then
      table.remove(normalEnemies, i)-- delete enemies when hp is 0
    end
  end

  for i, bull in ipairs(bullets) do -- collisions with bullets and normal enemies
      for j, enemy in ipairs(normalEnemies) do
Changing this into:

Code: Select all

-- enemyNormal.lua : update
  local enemy
  local enemies = normalEnemie -- localising normalEnemy, to make it faster to look up
  for i = 1, #enemies do -- now using local  enemies. #enemies = enemies.size() in java for example.
     enemy = enemies[ i ]

     enemy.x = enemy.x - (normalEnemy.speed * dt)
     if enemy.x <= -80 or enemy.health < 1 then -- combining the check...
        -- some magic so that we dont need to call table.remove
        -- Although instead of throwing things into bit universe, it would be better to recycle this
        -- such as recycledEnemies[ #recycledEnemies + 1 ] = enemies[ i ], then pull the new enemy data
        -- from recycledEnemies when needing new ones.
        enemies[ i ] = enemies[ #enemies ]
        enemies[ #enemies ] = nil 
      else -- check collisions
        local bullets = bullets -- localising
        local bull 
        for j = 1, #bullets do 
          bull = bullets[j]
          if overlap(bull.x, bull.y, bull.width, bull.height, enemy.x, enemy.y, enemy.width, enemy.height) then
            enemy.health = enemy.health - 1

            -- some magic so that we dont need to call table.remove
            bullets[ i ] = bullets[ #bullets ]
            bullets[ #bullets ] = nil 
            j = j - 1 -- since we remove one, we should move backwards one
            explosionSound:play() -- hit sound
            score = score + 10 --add score
          end
        end
      end 
  end
Then last but not least, I would suggest checking out spritebatches for drawing stuffs. Since you are making tile-based game, spritebatches can give ernomous boost in drawing stuffs on the screen. https://love2d.org/wiki/Tutorial:Effici ... _Scrolling
User avatar
Lafolie
Inner party member
Posts: 809
Joined: Tue Apr 05, 2011 2:59 pm
Location: SR388
Contact:

Re: Help with game lag

Post by Lafolie »

jjmafiae wrote: tip 4: use locals and remove any unused globals
From what I've read there is actually little impact using globals over locals. Only in certain cases (intense physics simulations perhaps, something like that) do you start to encounter situations where globals significantly affect performance. They're mostly recommended because it helps to 'keep the scope clean' and makes your code somewhat easier to maintain. You should really read someone's source before offering advice.
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.
Muris
Party member
Posts: 131
Joined: Fri May 23, 2014 9:18 am

Re: Help with game lag

Post by Muris »

Lafolie wrote:
jjmafiae wrote: tip 4: use locals and remove any unused globals
makes your code somewhat easier to maintain.
Globals and easier to maintain code doesn't really sound like something I would put together in most cases, unless you are 100% sure that you know exactly what you are doing. I honestly think the worst thing about LUA is the fact that instead of crashing, it actually makes global variables by default unless especially told not to aka local.

The reason why I decided to go with libgdx on my project is mostly because I have a gut feeling that if the project size grows, the probability of me not being able to track bugs that comes from having accidentally created globals, and not being able to find a bug in my program. The other reason is that I feel that debugging in java is easier, but there could be good tools for lua too.

Still I honestly think that Love2D is probably the best 2d engine I have seen so far, and most productive thing I've found.
Post Reply

Who is online

Users browsing this forum: Ahrefs [Bot] and 5 guests