2D Platformer with physics

Hey Everyone,
This is my first time posting but I have received a lot of help by searching through this forum. I am currently creating a 2D platformer with the assets provided by codea. I have most of my features working but I am running into a bit of trouble with physics and collisions. Most of the time everything works as expected, but on occassion my character ignores collisions with my ground tiles and falls through the map. I’ve included my code below and would really appreciate some feedback, also I feel like my level generator code is pretty easy and effective to use so feel free to use it in your own projects.

-- 2D Platformer
supportedOrientations(CurrentOrientation)
-- Use this function to perform your initial setup
function setup()
    --Character setup
    player = Character()
    --Level setup
    stage = Level() 
end


function draw()
    background(0, 92, 255, 255)
    strokeWidth(5)
    camera(mainCharacter.x-WIDTH/2, mainCharacter.y-HEIGHT/3, 10, mainCharacter.x-WIDTH/2, mainCharacter.y-HEIGHT/3, 1)
    player:draw()
    stage:draw()
end


function touched(touch)
    player:touched(touch)

end

function collide(contact)
    player:collide(contact)
end

Character = class()

function Character:init(x)
    -- you can accept and set parameters here
    spriteMode(CENTER)
    characterSize = 75
    characterSpeed = 6
    characterMaxSpeed = 250
    mainCharacter = physics.body(CIRCLE, characterSize/1.5)
    mainCharacter.gravityScale = 2
    mainCharacter.restitution = .2
    mainCharacter.x = WIDTH/2
    mainCharacter.y = HEIGHT/2
    characterGrounded = 0 -- 0 is false, 1 is true
    mainCharacter.friction = .2
    mainCharacter.fixedRotation = true
end

function Character:draw()
    -- Codea does not automatically call this method
    sprite("Platformer Art:Guy Standing", mainCharacter.x, mainCharacter.y, characterSize)
    --print(mainCharacter.linearVelocity.x)
if mainCharacter.linearVelocity.x < characterMaxSpeed and mainCharacter.linearVelocity.x > -characterMaxSpeed then
        mainCharacter:applyForce(vec2(Gravity.x*300, 0))
end
  --  mainCharacter.x = mainCharacter.x + Gravity.x * characterSpeed
end

function Character:touched(touch)
    -- Codea does not automatically call this method
end


function Character:collide(contact)
    if contact.state == BEGAN then
        print( contact.bodyA.info)
        if contact.bodyA ~= nil then
            if contact.bodyA.info == "ground" then
                characterGrounded = 1
                print("hit")
            end
        end
    end
end

function Character:touched(touch)
    if touch.state == BEGAN then
        if characterGrounded == 1 then
            
            mainCharacter:applyForce(vec2(0, 5000))
            characterGrounded=0
            print("jump")
        end
    end
end

Level = class()

function Level:init()
    -- you can accept and set parameters here
    rectMode(CENTER)
    --0: empty
    --1:ground
    --2: wall
    --3: cloud
    --4: levelEnd
    --5: coin
    
    levelLayout =
    {
    {0,0,0,0,0,0,0,0,0,0},
    {0,0,0,0,0,0,0,0,0,0},
    {0,0,0,0,0,0,0,0,0,0},
    {0,0,0,0,0,0,0,0,0,4},
    {1,0,0,0,0,0,0,0,5,1},
    {2,0,0,0,3,0,0,5,1,2},
    {2,0,0,0,0,0,5,1,2,2},
    {2,0,0,0,0,5,1,2,2,2},
    {2,0,0,0,0,1,2,2,2,2},
    {1,1,1,1,1,1,1,1,1,1}
    }

    for i, row in ipairs(levelLayout) do
        for j, block in pairs(row) do
            if levelLayout[i][j] == 1 or levelLayout[i][j] == 2 then
                --print(levelLayout[i][j])
                rectWidth = 100
                rectHeight = 100
                physicsRect = physics.body(POLYGON,
                    vec2(-rectWidth/2, -rectHeight/2), --bottom left
                    vec2(-rectWidth/2, rectHeight/2), --top left
                    vec2(rectWidth/2, rectHeight/2), --top right
                    vec2(rectWidth/2, -rectHeight/2) --bottom right
                )
               
                physicsRect.gravityScale = 0
                physicsRect.restitution = 0.1
                
                physicsRect.x = j*100
                physicsRect.y = HEIGHT-(100*i)
                
                physicsRect.type = STATIC
                physicsRect.friction = .2
                if levelLayout[i][j] == 1 then
                    physicsRect.info = "ground"
                end
                if levelLayout[i][j] == 2 then
                    physicsRect.info = "wall"
                end
            end
            if levelLayout[i][j] == 4 then
                starSize = 100
                star = physics.body(CIRCLE, starSize/2)
                star.gravityScale = 5
                star.restitution = .2
    
                star.x = j*100
                star.y = HEIGHT-(100*1)
                star.info = "star"
            end
        end
    end
end

function Level:draw()
    -- Codea does not automatically call this method
    for i, row in ipairs(levelLayout) do
        for j, block in pairs(row) do
            if levelLayout[i][j] == 1 then
                sprite("Platformer Art:Block Grass", j*100, HEIGHT-(100*i), 100, 100)
            end
            if levelLayout[i][j] == 2 then
                sprite("Platformer Art:Block Brick", j*100, HEIGHT-(100*i), 100, 100)
            end
             if levelLayout[i][j] == 3 then
                sprite("Platformer Art:Cloud 2", j*100, HEIGHT-(100*i), 200, 100)
            end
            
            if levelLayout[i][j] == 4 then
                sprite("Small World:Glow", j*100, HEIGHT-(100*i), 100, 100)
            end
            if levelLayout[i][j] == 5 then
                sprite("Platformer Art:Coin", j*100, HEIGHT-(100*i), 30, 30)
            end
        end
    end
    
end

function Level:touched(touch)
    -- Codea does not automatically call this method
end

@dkharley I think garbageCollect is removing your ground. I don’t see anyplace where you’re saving the ground pieces. You’re creating them in the variable physics.Rect in different places, but they all have that name. Each physics object needs a unique name or table position.

@dkharley You’re using classes, but they’re not being used correctly. To have individual class objects, you need to use self.

@dkharley, for more on classes, try

https://coolcodea.wordpress.com/2013/03/22/7-classes-in-codea/

And

https://coolcodea.wordpress.com/2013/03/23/8-classes-in-codea-2/

And to explain further what dave said about using variables for physics objects, Codea does something called garbage collection every now and then. It looks at your physics objects (which, remember, are invisible objects), and if any of them don’t have a variable name attached, it deletes them (because there is no way for you to use them without a variable name). If you create physics objects all with the same name, then only the last object keeps that name, and the others end up with no name, waiting for the garbage truck to delete them a minute later. So give them all individual names!

@dkharkey I’m not sure what you’re trying to do with the camera statement in the function draw.

@dkharley Welcome to the forum and congrats on your first post. Your game looks like it will be fun, you just need to fix a few things. But then that’s what we’re here for.

@dave1707 Adding my physics bodies into a table solved the problem of them being garbage collected. As for the camera statement in my draw function, I am attempting to make the camera follow my player as he moves through the level, there is probably a better way to do this.

@Ignatz Thanks for the tips on classes, I added self before my variable names, which as I understand is basically the difference between making a variable global or local.

@dkharley - each class “instance” is stored in a table, and self holds the address of that table. So when you say self.x, you are referencing an item x held in the table stored at address self.

For camera settings, see the end of this post (there are also several posts before and after that one, about 2D platform games)

https://coolcodea.wordpress.com/2014/09/15/160-2d-platform-game-5-managing-the-player/

Hey everyone, anyone have any tips on how to make ladders, moving saw blades, and lasers for the platformer? I’m using the platformer art off of http://kenney.nl/assets. I am also using the code provided above with a few minor tweaks. Thanks! @Ignatz @dave1707 @dkharley