Making a Level

As I’m a wannabe coder I’ve coded a lot in Game Maker. As ppl know, making a level in Game Maker is entirely visual based.
So my question is, how do I go about placing dirt blocks/walls and stuff in my game? The example game in Codea didn’t get through to me.

I’m assuming there’s gonna be a lot of “for loops” and stuff so I’m giving everyone permision to talk to me like I’m a child so as to help me understand better

EDIT: whistle whistle still waiting for a reply :slight_smile:

You could create a separate class for the level and the walls. Have you taken a look at the Dungeon Roller example? That’s a relatively straight forward example on how to draw walls around the screen.

It didn’t seem so straightforward to me @.@
I’ve looked at it and wound up more confused

function World:draw()
– Codea does not automatically call this method
itemDrawn = false
for y = #self.blocks[1],1,-1 do
for x = 1,#self.blocks do
self.blocks[x][y]:draw()
end
end
Since im not used to LUA syntax, i dont understand for loops yet, but i know he used a for loop on its constructor and draw function(i might be wrong but i think thats pretty much it…)

I’m glad someone responded but I’m afraid I’m even more confused.
doing a number map has something to do with it, right?

{0,0,0,0,0,0}
{0,1,1,1,1,0}
{0,1,1,2,1,0}
{0,0,0,0,0,0}

-- 0 = Wall
-- 1 = Grass
-- 2 = Character

or am I waay off base?
how does a for loop work exactly? And how does a for loop make my map above into sprite tiles?
And lastly is this something super basic that I’m not getting? I kinda feel like a retard right now :frowning:

RichGala1…I know what you’re talking about. I have programmed with GameMaker, as well. Making the switch to Codea was quite different. I’ve toyed around with Codea for a month or so now, and I have just learned (and gotten a lot of help from members of the forum!) how to set blocks on the screen in a configuration that I want. I did it with separate classes for level and block (like what ChrisF was referring to). I took from the Brickout example (Dungeon Roller is not self-explanatory to me either). Here is what I’ve come up with. There may be a better way to do it, but…

#level
levels = {

{{0,1,1,1,0},{1,1,0,1,1},{1,0,1,0,1}} 

} 

–first inside bracket is top row. The numbers are places where the walls will go. 0 = an empty spot. 1 = spot where the wall will be drawn. The outer brackets indicates level 1. In this example, I will have three rows of a possible 5 walls.

#wall
wall = class()

function wall:init(x,y)
    -- you can accept and set parameters here
    self.pos = vec2(x,y)
    self.size = vec2(101,171)
end

function wall:draw()
    -- Codea does not automatically call this method
    sprite("Planet Cute:Stone Block",self.pos.x,self.pos.y)
end

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

–this class is the wall block. self.pos is a vec2 with x, y values that will be identified in the #Main(). self.size is a vec2 with values for the width and height of the sprite being used.

#Main

displayMode(FULLSCREEN)
supportedOrientations(CurrentOrientation)

walls = {}
level = 1

function setup()
    
    makeWalls()
    
end

function makeWalls()
    for i = 1, 3 do --rows
        for j = 1, 5 do  --columns
            if levels[level][i][j] > 0 then
                table.insert(walls,wall(200 + (j * 103),HEIGHT - (i*85 + 35)))
            end
        end
    end
end


function draw()
    
    background(27, 27, 218, 255)
    
    for i = 1, table.maxn(walls, i) do
        walls[i]:draw()
    end

end

–‘walls’ is a table to hold the wall sprite so they can be drawn on the screen. I don’t know why makeWalls() has to be in the setup(), but the code won’t work without it there. If you play with the numbers in the table.insert, you’ll see how it effects the x or y shift, as well as the spacing between blocks.

I hope this helps. Good luck, and have fun.

Thank you so much! Someone who understands the transition :slight_smile:
I will try out the code immediately. I’ve only skimmed it so far and I can already tell that this is EXACTLY what I needed XD

I tried your code but it didn’t work. Codea says:

error: [string "..."]:15: attempt to index field '?' (a nil value)
Pausing playback
error: [string "..."]:31: attempt to call global 'maxn' (a nil value)
Pausing playback

Wasn’t sure what “maxn” was supposed to do…

turns out I just did something retarded XP
BUT what do I add if I want the “0”'s to be grass tiles and the 1’s to be walls?

@RichGala1: the table.maxn is telling the loop to go through to the maximum number of instances held in the table.

I’m not sure about the other question: making the 0’s a different tile. That may be better done with meshes, but I have not gotten that far. Hopefully someone else on the forum can answer that one for you.

@RichGala1

I think you might also want to take a loom at the 3d lab it has 3 declared meshes in its 2nd example:


Test2 = class()

function Test2:name()
    return "3D Blocks"
end

function Test2:init()
    -- all the unique vertices that make up a cube
    local vertices = {
      vec3(-0.5, -0.5,  0.5), -- Left  bottom front
      vec3( 0.5, -0.5,  0.5), -- Right bottom front
      vec3( 0.5,  0.5,  0.5), -- Right top    front
      vec3(-0.5,  0.5,  0.5), -- Left  top    front
      vec3(-0.5, -0.5, -0.5), -- Left  bottom back
      vec3( 0.5, -0.5, -0.5), -- Right bottom back
      vec3( 0.5,  0.5, -0.5), -- Right top    back
      vec3(-0.5,  0.5, -0.5), -- Left  top    back
    }


    -- now construct a cube out of the vertices above
    local cubeverts = {
      -- Front
      vertices[1], vertices[2], vertices[3],
      vertices[1], vertices[3], vertices[4],
      -- Right
      vertices[2], vertices[6], vertices[7],
      vertices[2], vertices[7], vertices[3],
      -- Back
      vertices[6], vertices[5], vertices[8],
      vertices[6], vertices[8], vertices[7],
      -- Left
      vertices[5], vertices[1], vertices[4],
      vertices[5], vertices[4], vertices[8],
      -- Top
      vertices[4], vertices[3], vertices[7],
      vertices[4], vertices[7], vertices[8],
      -- Bottom
      vertices[5], vertices[6], vertices[2],
      vertices[5], vertices[2], vertices[1],
    }

    -- all the unique texture positions needed
    local texvertices = { vec2(0.03,0.24),
                          vec2(0.97,0.24),
                          vec2(0.03,0.69),
                          vec2(0.97,0.69) }
                
    -- apply the texture coordinates to each triangle
    local cubetexCoords = {
      -- Front
      texvertices[1], texvertices[2], texvertices[4],
      texvertices[1], texvertices[4], texvertices[3],
      -- Right
      texvertices[1], texvertices[2], texvertices[4],
      texvertices[1], texvertices[4], texvertices[3],
      -- Back
      texvertices[1], texvertices[2], texvertices[4],
      texvertices[1], texvertices[4], texvertices[3],
      -- Left
      texvertices[1], texvertices[2], texvertices[4],
      texvertices[1], texvertices[4], texvertices[3],
      -- Top
      texvertices[1], texvertices[2], texvertices[4],
      texvertices[1], texvertices[4], texvertices[3],
      -- Bottom
      texvertices[1], texvertices[2], texvertices[4],
      texvertices[1], texvertices[4], texvertices[3],
    }
    
    -- now we make our 3 different block types
    self.ms = mesh()
    self.ms.vertices = cubeverts
    self.ms.texture = "Planet Cute:Stone Block"
    self.ms.texCoords = cubetexCoords
    self.ms:setColors(255,255,255,255)
    
    self.md = mesh()
    self.md.vertices = cubeverts
    self.md.texture = "Planet Cute:Dirt Block"
    self.md.texCoords = cubetexCoords
    self.md:setColors(255,255,255,255)
    
    self.mg = mesh()
    self.mg.vertices = cubeverts
    self.mg.texture = "Planet Cute:Grass Block"
    self.mg.texCoords = cubetexCoords
    self.mg:setColors(255,255,255,255)   
    
    -- currently doesnt work properly without backfaces
    self.mw = mesh()
    self.mw.vertices = cubeverts
    self.mw.texture = "Planet Cute:Water Block"
    self.mw.texCoords = cubetexCoords
    self.mw:setColors(255,255,255,100)
    
    -- stick 'em in a table
    self.blocks = { self.mg, self.md, self.ms }
    
    -- our scene itself
    -- numbers correspond to block positions in the blockTypes table
    --             bottom      middle      top
    self.scene = {   { {3, 3, 0}, {2, 0, 0}, {0, 0, 0} },
                     { {3, 3, 3}, {2, 2, 0}, {1, 0, 0} },
                     { {3, 3, 3}, {2, 2, 2}, {1, 1, 0} } }
end

function Test2:draw()
    pushMatrix()
    pushStyle()
    
    -- Make a floor
    translate(0,-Size/2,0)
    rotate(Angle,0,1,0)
    rotate(90,1,0,0)
    sprite("SpaceCute:Background", 0, 0, 300, 300) 

    -- render each block in turn
    for zi,zv in ipairs(self.scene) do
        for yi,yv in ipairs(zv) do
            for xi, xv in ipairs(yv) do
                -- apply each transform  need - rotate, scale, translate to the correct place
                resetMatrix()
                rotate(Angle,0,1,0)
                
                local s = Size*0.25
                scale(s,s,s)
                
                translate(xi-2, yi-2, zi-2)    -- renders based on corner
                                               -- so -2 fudges it near center
                
                if xv > 0 then
                    self.blocks[xv]:draw()
                end
            end
        end
    end
    
    popStyle()
    popMatrix()
end

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

You can completely ignore the 3d aspects of this I think this part in particular might help:

 -- now we make our 3 different block types
    self.ms = mesh()
    self.ms.vertices = cubeverts
    self.ms.texture = "Planet Cute:Stone Block"
    self.ms.texCoords = cubetexCoords
    self.ms:setColors(255,255,255,255)
    
    self.md = mesh()
    self.md.vertices = cubeverts
    self.md.texture = "Planet Cute:Dirt Block"
    self.md.texCoords = cubetexCoords
    self.md:setColors(255,255,255,255)
    
    self.mg = mesh()
    self.mg.vertices = cubeverts
    self.mg.texture = "Planet Cute:Grass Block"
    self.mg.texCoords = cubetexCoords
    self.mg:setColors(255,255,255,255)   
    
    -- currently doesnt work properly without backfaces
    self.mw = mesh()
    self.mw.vertices = cubeverts
    self.mw.texture = "Planet Cute:Water Block"
    self.mw.texCoords = cubetexCoords
    self.mw:setColors(255,255,255,100)
    
    -- stick 'em in a table
    self.blocks = { self.mg, self.md, self.ms }
    
    -- our scene itself
    -- numbers correspond to block positions in the blockTypes table
    --             bottom      middle      top
    self.scene = {   { {3, 3, 0}, {2, 0, 0}, {0, 0, 0} },
                     { {3, 3, 3}, {2, 2, 0}, {1, 0, 0} },
                     { {3, 3, 3}, {2, 2, 2}, {1, 1, 0} } }
end

And don’t forget you can draw your own sprites with spritely

You can change the wall draw function to draw different sprites by passing the value from the level class. The program posted above only draws a sprite if the value is greater than zero. In the example below 1 draws a grass block, 2 draws a stone block. Add more if statements as required.

#wall
wall = class()

function wall:init(x,y,i)
    -- you can accept and set parameters here
    self.pos = vec2(x,y)
    self.size = vec2(101,171)
    self.i=I
end

function wall:draw()
    -- Codea does not automatically call this method
if self.i==1 then
    sprite("Planet Cute:Grass Block",self.pos.x,self.pos.y)
end
if self.i==2 then
    sprite("Planet Cute:Stone Block",self.pos.x,self.pos.y)
end

end

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

And in main change the table.insert to pass the third variable of the value [j]

table.insert(walls,wall(200 + (j * 103),HEIGHT - (i*85 + 35),[j]))

I tried what you suggested, West. But for some reason Codea says there is something wrong with the " [ j ]" variable for the table.insert()

I thought maybe if I removed the “[ ]” but then only 2 columns show up, one column wall the other grass.

but WITH the “[ ]” a red pop-up says: Unexpected symbol near ‘[’


EDIT: I figured it out!!!

Not gonna lie, I feel AWESOME at the moment. I kinda feel retarded about not understanding but still! :stuck_out_tongue:

btw instead of “[j]” I put:

table.insert(walls,wall(200 + (j*103), HEIGHT - (i*85 + 35),levels[level][i][j]

Now I just need to figure out how to keep my character from running into the wall :slight_smile:

Oops - sorry for the error - didn’t test the code before posting. Glad you figured it out :wink:

Hi! I’ve been looking for this information for a while. First, thanks for the help.
I tried running the main, wall, and level class together as described above. All I get is a blue screen. Please help!! @.@

My code below:

@Kempoman, in walls you need to do “self.i = i”, not “self.i = I” because variables are case-sensitive. Here is working code:



--# Main
-- Level Making
displayMode(FULLSCREEN)
supportedOrientations(CurrentOrientation)

function setup()
    walls = {}
    
    levels = {

    {{2,1,1,1,3,3,3,1,1,2,1},{1,1,3,1,1,1,2,1,3,2,2},{1,3,1,3,1,1,1,2,1,3,1},            {2,1,1,1,3,3,3,1,1,2,1},{1,1,3,1,1,1,2,1,3,2,2},{1,3,1,3,1,1,1,2,1,3,1},{2,1,1,1,3,3,3,1,1,2,1},{1,1,3,1,1,1,2,1,3,2,2},{2,2,2,2,2,1,1,1,1,1,2}},

        {{1,1,2,1,3,2,3,1,2,2,3}, {1,1,3,2,1,3,1,1,3,2,1}, {2,3,2,3,1,3,1,1,1,3,2},{1,1,1,1,3,3,2,1,2,2,1}, {2,1,3,1,3,1,1,1,3,1,2}, {1,3,1,3,1,3,1,2,1,2,1}, {2,3,1,1,2,3,2,1,3,2,1}, {1,2,3,1,3,1,2,1,2,2,2}, {2,3,2,3,2,1,2,1,2,1,2}}

        } -- Creates a table of levels with two levels that have 9 rows and 11 collumns, each number 1-3 represents a different tile 

    level = 1 -- Select the first level
    
    makeWalls() -- Call the function to draw the tiles
end

function makeWalls()
    for i = 1, #levels[level] do --rows
        for j = 1, #levels[level][i] do  --columns
            if j > 0 then -- If the tile type isnt 0 make a tile
                table.insert(walls,wall((j * 101 - 50.5),HEIGHT - (i*85 - 50), levels[level][i][j]))
            end
        end
    end
end

function createRandomLevel()
    table.insert(levels, level, {}) -- Create a table in our levels table for the new level
    for i = 1, 9 do 
        table.insert(levels[level], {}) -- Create 9 rows
        for j = 1,11 do
            table.insert(levels[level][i], math.random(1,3)) -- Insert random tile values into the rows
        end
    end
    makeWalls() -- Have it make the blocks for the level we just created
end


function draw()
    background(0, 0, 0, 255) -- Set a black background
    
    for i = 1, #walls do -- For every block in the table walls 
        walls[i]:draw() -- draw the correct sprite
    end
    
    fill(255, 0, 0, 255)
    rect(WIDTH/2 - 50, HEIGHT-20, 100,20)
    fill(255, 255, 255, 255)
    text("FPS:"..1/DeltaTime, WIDTH/2, HEIGHT - 10)
end

function touched(touch)
    if CurrentTouch.state == ENDED then -- If touch is over then
        level = level + 1 -- change level
        for i = 1, #walls do
            table.remove(walls, i) -- Remove the old blocks from the table
        end
        if levels[level] == nil then -- If that level doesn't exist then
            createRandomLevel() -- Call the function to make a new level
        else -- if a level already exists then
            makeWalls() -- Have it make the blocks for the next level
        end
    end
end
        

--# wall
wall = class()

function wall:init(x,y,i)
    -- you can accept and set parameters here
    self.pos = vec2(x,y) -- Set the position based on the parameter given
    self.size = vec2(101,171) -- Size of the blocks
    self.i = i 
end

function wall:draw()
    -- Codea does not automatically call this method
if self.i == 1 then
    sprite("Planet Cute:Grass Block",self.pos.x,self.pos.y,self.size.x,self.size.y) -- Draw the grass block at the correct position and size specified above
end
if self.i == 2 then
    sprite("Planet Cute:Stone Block",self.pos.x,self.pos.y,self.size.x,self.size.y) -- Draw the stone block at the correct position and size specified above
end
if self.i == 3 then
    sprite("Planet Cute:Dirt Block",self.pos.x,self.pos.y,self.size.x,self.size.y) -- Draw the dirt block at the correct position and size specified above
end

end

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

EDIT: added comments and changed it to tile the whole screen, also added a random level generator



--# Main
-- Main

displayMode(FULLSCREEN)
supportedOrientations(CurrentOrientation)

walls = {}
level = 1

function setup()
    
    makeWalls()
    
end

function makeWalls()
    for i = 1, 3 do --rows
        for j = 1, 5 do  --columns
            if levels[level][i][j] > 0 then
                table.insert(walls, wall(200+(j*103), HEIGHT-(i*85+35), levels[level][i][j]))
            end
        end
    end
end


function draw()
    
    background(27, 27, 218, 255)
    
    for i = 1, table.maxn(walls, i) do
        walls[i]:draw()
    end

end

--# wall
wall = class()

function wall:init(x,y,i)
    -- you can accept and set parameters here
    self.pos = vec2(x,y)
    self.size = vec2(101,171)
    self.i = I
end

function wall:draw()
    -- Codea does not automatically call this method
    if self.i == 1 then
        sprite("Planet Cute:Grass Block", self.pos.x, self.pos.y)
    end
    if self.i == 2 then
        sprite("Planet Cute:Stone Block Tall", self.pos.x, self.pos.y)
    end
end

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

--# level


levels = {

{{0,1,1,1,0}, {1,1,0,1,1}, {1,0,1,0,1}}

}


@JakAttak Thanks so much!! I can’t believe how great the people on this forum are!!! If I ever figure this stuff out I will try to do the same!!

@Kempoman - this code can be improved quite a bit. For example, it’s probably a good idea to put the sprite names in a table, like so

sprites={“Planet Cute:Grass Block”,“Planet…”,“Planet…”,…}

then in wall:draw(), you just say

sprite(sprites[self.i],self.pos.x,self.pos.y, …etc)

actually, I wouldn’t have a wall class at all, for single blocks. I can see the sense in having a level class, though, because that could manage everything that happens in each level. Also, because you are going to use the same map until you change levels, that class could draw the map on an image, and just sprite that image on each draw, instead of having to draw each block separately.

Anyway, as long as you are having fun…!