Howdy, Stranger!

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

Making a Level

edited June 2012 in Questions Posts: 68

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 :)

Tagged:

Comments

  • Posts: 18

    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.

  • Posts: 68

    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..)

  • edited June 2012 Posts: 68

    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 :(

  • Posts: 41

    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.

  • Posts: 68

    Thank you so much! Someone who understands the transition :)
    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

  • Posts: 68

    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..

  • Posts: 68

    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?

  • Posts: 41

    @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.

  • edited June 2012 Posts: 7

    @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

  • Posts: 718

    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]))
    
  • edited June 2012 Posts: 68

    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! :P

    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 :)

  • Posts: 718

    Oops - sorry for the error - didn't test the code before posting. Glad you figured it out ;-)

  • Posts: 37

    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!! @.@

  • edited July 2013 Posts: 37

    My code below:

  • Posts: 37


    --# 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}} }
  • edited July 2013 Posts: 2,042

    @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

  • Posts: 37

    @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!!

  • IgnatzIgnatz Mod
    Posts: 5,396

    @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...!

  • Posts: 37

    Wow! Thanks Ignatz!! That is some stellar advice. I will try putting the sprites in a table. I was not sure whether to make my map changeable by the player or not. I think that now I will keep everything as simple as I can while I'm learning and try out the single image level.

  • IgnatzIgnatz Mod
    Posts: 5,396

    good idea, start simple, add complexity a bit at a time...

  • Posts: 688

    This is an interesting thread with a lot of useful info, however (also as a GameMaker user) I do understand the question / point the OP raised.

    What would be REALLY cool for Codea would be to include more tools - like the room / level editor in Gamemaker in the labs section or as an example (like Spritely) so people could design 2D levels in a consistent manner and be able to export that data easily to their lua apps.

    This would really make Codea rock as a game prototyping tool.

  • edited July 2013 Posts: 391

    I have been working on a 2D map editor which includes auto-tiling, similar to how programs like RPG Maker generate their 2D grid maps. The project so far will take tile sheets and break them down into the necessary components to make the smooth transitions on the generated map. Basic auto-tiling consists of 13 parts: 4 outer corners, 4 inner corners, 4 edges, and a full tile.

    This type of map will most likely be used for RPG type games, but with some imagination it could be adopted to almost any genre. Check out some of the progress in the discussion below.

    http://twolivesleft.com/Codea/Talk/discussion/comment/24480

    Tilesheet set I have used for debugging:

    Character set I used for debugging:


    I chose to do auto-tiling similar to RPG Maker since there is an abundance of free tilesheet sets and character sets available in this format.

    I have sent the code to Ignatz as of yesterday for some help with documentation so it can be used by anyone with any amount of coding experience. There is no awesome GUI for the creation of the maps, but I did simplify it down to sets of 2D tables which are simply filled with numbers indicating which tile sheet is used. Tile sheets are stored in tables of their own with additional information such as the auto-tiling type (floor, roof/wall, waterfall/animated, and none) and whether or not the player would be allowed to walk on the tile. I have floor, roof/wall, and none types working with very minor graphical issues for certain tiles.

    Building and physically seeing your worlds come to life definitely keeps the motivation alive. This is why in my process of building an RPG, I chose to do the map generation first. When building large games, motivation is key.

  • edited July 2013 Posts: 37

    X

  • edited July 2013 Posts: 37

    X

  • edited July 2013 Posts: 37

    X

  • edited July 2013 Posts: 391

    I have released my code for 2D map generation with auto-tile using sprite sheets. Please check it out here:


    http://twolivesleft.com/Codea/Talk/discussion/3058/



    My code will keep your character centered on the screen and the map will move when you move your character. Not sure if that's what you were looking for, but the map generation part is still awesome as it reads from a simple 2D (grid) table.

  • edited July 2013 Posts: 37

    X

  • Posts: 391

    @kempoman, how come your last four posts now have a single X in them?

  • IgnatzIgnatz Mod
    Posts: 5,396

    he likes blowing kisses

  • edited July 2013 Posts: 2,042

    :P

  • Posts: 37

    I wanted to delete them. Sorry

Sign In or Register to comment.