Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Laggy game

edited August 2017 in Questions Posts: 35

Hello,

So I am currently in the process of making my own version of Pong that has a menu and levels, I have reached a stage though where I have noticed the game start to lag when I run the code on my iPad. This is my first time making a game so I have a hunch that how I have structured my code is the reason it's so slow, so I will try to explain how I have gone about it.

My game has menu, a paddle selector and a level selector, as well as an in game state. I have turned each of these different screen states into separate classes, in setup() I initialise them all and then call their different functions inside draw() ( inside the main function). However each function coming from these classes is surrounded by an if statement, so the menu screen will only draw if MENUSTATE == true else it will go to the next if statement till it finds a Game state that is true so it can run the code for that classes function. I will add screen shots to help understand what I mean if not I am happy to re word this.

Anyway, is this way of organising my classes using lots of memory because all the games classes are existing but not being used?

I also have a handful of 1000x1000 images in my game which could be the source of slowing the game?

Thanks

IMG_0111.PNG 175.6K
IMG_0112.PNG 65.3K
IMG_0114.PNG 256.6K

Comments

  • I don’t think you’ve shown enough code here to isolate a problem. In Codea’s main project screen, tap and hold on your project icon and choose Export and then Copy Project Code and paste it here and maybe someone can dig in some more.

  • Posts: 35

    Okay thankyou

  • Posts: 386

    if you have a lot of print statements in the output panel that will eventually slow things down a lot.

  • dave1707dave1707 Mod
    Posts: 7,605

    @rydergaz Instead of having so many seperate if statements, change them to if else statements.

    If ONEPLAYERSTATE == true then
            newpaddle:touched(touch)
    elseif MENUSTATE == true then
            menu:touched(touch) 
    elseif SELECTORSTATE == true then
            selector:touched(touch)
    elseif LEVELSELECTORSTATE == true then
            levelselector:touched(touch)
    end
    
  • dave1707dave1707 Mod
    Posts: 7,605

    @rydergaz You could add the line of code below for testing purposes just to see how many frames per second you're running at. 60 is the max.

    ~~~
    text(1//DeltaTime,WIDTH/2,HEIGHT-25)
    ~~

  • dave1707dave1707 Mod
    edited August 2017 Posts: 7,605

    @rydergaz Here's a simple example of a pong game that runs at approx 59 or 60 FPS on my iPad Air. Adding code to check for touch to determine where the paddles should be wouldn't affect the FPS much, maybe 1 FPS less. So if you're running a lot slower than this, then you have something else that's slowing your code down because the basic code of pong shouldn't.

    EDIT: Added code for touch and score. Slide your finger near the edge to move the paddle.

    supportedOrientations(PORTRAIT_ANY)
    displayMode(FULLSCREEN)
    function setup()
        p1Total,p2Total=0,0
        rectMode(CENTER)
        bx,by=WIDTH/2,HEIGHT/2
        vx=math.random(5,8)
        vy=math.random(8,16)
        p1x,p2x=WIDTH/2,WIDTH/2
    end
    
    function draw()
        background(40, 40, 50)
        fill(255)
        text(1//DeltaTime,50,HEIGHT-25)
        text(p1Total,WIDTH/2,HEIGHT-50)
        text(p2Total,WIDTH/2,50)
        bx=bx+vx
        by=by+vy
        if bx>WIDTH or bx<0 then
            vx=-vx
        end
        if by>HEIGHT then
            p2Total=p2Total+1
            vy=-vy
        end
        if by<0 then
            p1Total=p1Total+1
            vy=-vy
        end
        rect(p1x,HEIGHT-100,100,25)
        rect(p2x,100,100,25)
        ellipse(bx,by,20)
        if bx>p1x-50 and bx<p1x+50 and by>HEIGHT-115 and by<HEIGHT-95 then
            vy=-vy
        end
        if bx>p2x-50 and bx<p2x+50 and by>95 and by<115 then
            vy=-vy
        end
    end
    
    function touched(t)
        if t.state==MOVING then
            if t.y>HEIGHT/2 then
                p1x=p1x+t.deltaX
            else
                p2x=p2x+t.deltaX            
            end
        end
    end
    
  • Yeah, Pong is pretty simple and there shouldn't inherently be any performance issues with it (which is why I asked to see the full code). I don't want to toot my own horn (well, okay, I'm lying), but I've been working on a rather large project entirely within Codea that has tons going on each frame. You can see a slightly out of date video here: https://youtube.com/watch?v=i4qMxG1UDcc

  • dave1707dave1707 Mod
    Posts: 7,605

    @rydergaz I added code to the above example to control each paddle by sliding your finger back and forth. Also added code to score when the ball hits the wall behind the paddles. The code still runs at approx 59 FPS.

  • em2em2
    edited August 2017 Posts: 194

    Some suggestions (your game looks pretty good by the way):

    • Instead of using different variables for each of your game states, try using a single variable and change it to your current state, like "MENU", "LEVELSELECTOR", "GAME", ... (you probably see what I mean).
      A code example:
    function setup()
      GAME_STATE = "MENU"
    end
    
    function draw()
      if GAME_STATE == "MENU" then
        -- draw your menu here
      elseif GAME_STATE == "LEVELSELECTOR" then
        -- draw your level selector
      elseif GAME_STATE == "GAME" then
        -- draw paddles, ball, and score
      end
    end
    
    • Only setup your variables when you need them, and when the game is over, you can set them to nil and collectgarbage().
      When the game starts:
    function setupGame()
      paddle1 = Paddle(WIDTH/2,HEIGHT-80,"Pink")
      paddle2 = Paddle(WIDTH/2,80,"Blue")
      ball = Ball(WIDTH/2,HEIGHT/2)
    end
    

    When the game is over:

    paddle1 = nil
    paddle2 = nil
    ball = nil
    collectgarbage()
    

    (That should probably help)

    • As @piinthesky hinted, many calls to print inside draw can drastically slow down your game.
    • Finally, check out this link and this (more advanced) pdf guide, both not written by me.

    Hope this helps.

  • Posts: 35

    I tried outputting the frame rate and it changes quite rapidly but it seems to bounce between 50 and 60 and down to 40 now and again too.

    Thanks for the reply @em2 that's super helpful! if your setting everything to nil what does garbage collection remove?

  • Posts: 35

    Also what is the best way to call a method of a class from a method of the same class .e.g

    function Example:bounce()

    X = X + 10

    end

    function Example:draw(Example)

    Example.bounce

    Print(X)

    end

  • dave1707dave1707 Mod
    Posts: 7,605

    @rydergaz Here's an example of a way to call a class function from another function of the same class.

    function setup()
        t1=test("t1=",36,12)
        t2=test("t2=",12,2)
        t1:print()
        t2:print()
    end
    
    function draw()
        background(40, 40, 50)
    end
    
    test=class()
    
    function test:init(v,x,y)
        self.v=v
        self.x=x
        self.y=y
    end
    
    function test:print()
        print(self.v,self.x,self.y)
        print( self:calc() )     -- call a function in the same class
    end
    
    function test:calc()
        return self.x+self.y , self.x*self.y , self.x/self.y
    end
    
  • em2em2
    edited August 2017 Posts: 194

    @rydergaz I think collectgarbage is supposed to clear unused values from memory. Check out this link for an explanation (I'm not an expert at this). An example:

    -- Quick memory check function
    function checkMem()
        return string.format("%g kB\n",collectgarbage"count")
    end
    
    function setup()
        print"Initital Memory Usage:"
        print(checkMem()) -- check initial memory usage
        -- create a table with 10000 subtables
        t = {}
        for i = 1, 10000 do
            t[i] = {}
        end
    
        print"Memory after creating table with 10000 items:"
        print(checkMem()) -- check again
        t = nil -- set t to nil (table is still in memory)
    
        print"Memory after setting table to nil:"
        print(checkMem()) -- check again
    
        collectgarbage()
        print"Memory after collecting garbage:"
        print(checkMem())
    end
    

    Comments and print statements in the code should explain everything. collectgarbage "count" returns memory usage in kilobytes.

  • edited August 2017 Posts: 2,020

    Instead of branching if/ else statements, why not use classes to model different game states?


    -- some states --# MenuState MenuState = class() function MenuState:draw() -- draw menu end function MenuState:touched(touch) --handles touches end --# LevelSelectorState LevelSelectorState = class() function LevelSelectorState:draw() -- draw level select end --# GameState GameState = class() function GameState:draw() -- draw game end --# Main -- in setup you'd have: currentState = MenuState() -- then in draw, no need for a long if/ else block you just have: currentState:draw() --likewise in touched: function touched(touch) currentState:touched(touch) end -- to change state, eg, if the player dies, you put currentState = GameOver()

    This kind of simple state machine will really help to keep code encapsulated.

    If you want to get fancy, you could enforce rules about which states are allowed to follow other states (eg you can only get to the GameOver state from the GameState), or implement a stack of states in an array (so you can pop from PauseState back to GameState by removing the last item from the state stack).

  • All of this is good general information, but I feel like everyone is focusing on a handful of “if” branches that won’t make any measurable performance difference here. Whatever is causing OP’s laggy issues almost certainly has nothing with this scene and state management business. More likely it is something simpler - drawing images that are way bigger than they need to be, drawing more often than necessary, etc.

  • Posts: 2,020

    @BigZaphod you're right

  • Posts: 35
    Thank you all, I've sorted out the lagginness, was due to print statements.

    @yojimbo2000 I made classes for the different game states and then initialized them all in the main setup() and then used if statements to call the different classes draw functions. Is that not a similar method to what you are saying?
  • Posts: 386

    ahhh, thought so!

  • Posts: 2,020

    @rydergaz

    nearly there, but you could make it so much better by using a pointer to the current state, like it my suggestion above currentState = gameState or whatever. Long if else blocks are increasingly painful to read and maintain the more states that you add to the game, especially if you need to have them in draw, touched, orientationChanged etc.

  • edited August 2017 Posts: 35
    Ah I get it now, yeah that's really smart would simplify my code so much. Going to take me a while to clean up my messy code now aha

    Thanks
Sign In or Register to comment.