Tutorial 6 - Building a MineSweeper game Part 1

Tutorial 6 (http://codeatuts.blogspot.com.au/) is out now!

I have also made the MineSweeper code downloadable by class to make it easier to paste into each tab.

  1. Main (https://www.dropbox.com/s/cf1b4fa258oyixx/Main.lua)
  2. Cell (https://www.dropbox.com/s/dd7msn9xgnrynts/Cell.lua)
  3. Button (https://www.dropbox.com/s/7hja2yp23xlmjwk/Button.lua)
  4. RoundBorder (https://www.dropbox.com/s/j6r5hpov9obu0by/RoundBorder.lua)
  5. SplashScreen (https://www.dropbox.com/s/jjk5zakqh0o16u7/SplashScreen.lua)
  6. Fader (https://www.dropbox.com/s/get4ah7vbww0n53/Fader.lua)
  7. Twinkle (https://www.dropbox.com/s/u39rxgxm1m41tq7/Twinkle.lua)
  8. IconImages (https://www.dropbox.com/s/jgrlivsf19xb8pb/IconImages.lua)

and you can still get it in one big file if you prefer:

https://www.dropbox.com/s/xsdi3u73mhbii6w/Tutorial_6_MineSweeper_v1.lua

Hi @Reefwing,

Just read your tutorial 6, always manage to learn something new on Lua, or in other words - I’m grateful that there are people like you around to remind me how Lua works. In particular -TABLES. Thanks.

I like the way you split the file, much more manageable. Have you thought about setting up on GitHub or Bitbucket. They’re free up to a point and easy to use.

Thanks again, keep up the good work.

Bri_G

:slight_smile:

@Bri_G - Thanks, it was your comments that gave me the idea of splitting the file by class. It is a bit more work but worth it I think. I agree regarding Lua, at first glance it appears simplistic but it has some real hidden depths. I’ve recently discovered closures which is the first time I have seen functionality of that nature. It’s on my list to write about next. The great thing is, the gurus here then get to have a look at it and can tell me if I really understand it or alternatively missed a trick somewhere.

I did consider GitHub, but Codea is integrated with DropBox so I thought it made sense to follow suit. I think @Simeon said somewhere that the next version of Codea had code sharing - I’m hoping that is via DropBox!

Just wanted to say thanks for taking the time to share quality tutorials with us. Great work. I know I can learn a lot from these.

@Reefwing I wish we could have code sharing. Unfortunately Apple will not allow that. The best we could have is allowing you to touch-and-hold your project and select “Copy” to copy the entire thing to the clipboard (this is in the current version).

Thank you for the quality tutorials, @reefwing. We do really appreciate it. Keep up the good work! :slight_smile:

@Keebo and @bee - Thanks for the thanks, glad you enjoy them. Happy to contribute.

@Simeon - bummer! Doesn’t seem to make sense since you can cut and paste code in, it just makes it harder.

@Reefwing - thanks for the tutorials. I just finished typing in the MineSweeper tutorial, and I’m getting the following: error: error: [string “Button = class()…”]:82: attempt to compare number with nil.

I’ve double checked my typing, but it matches what you have. Do you know what I could be doing wrong?

The code line is:

    local r
    local v =  {}
    if w > 100 or h > 100 then
        if w >= h then r = math.round(h/100) else r = math.round(w/100) end
    else
        r = 1
    end

Then it goes into the vertices, etc.

Hi @LadyJayne - I hope you haven’t typed the whole thing in!! You know you can download it and cut and paste it into Codea?

Have you defined the math.round() function somewhere? For MineSweeper I stuck this in the Main class but it probably should be in the Button class so that you can use this class by itself. It looks like:

function math.round(num)
    -- function courtesy of @Vega

    return math.floor(num + 0.5)
end

If that isn’t it let me know. I’m working on the next tutorial at the moment. I’ve just worked out how to do the high score functionality.

I wanted to type it in, so I could understand it better. :slight_smile: I did create the sprites in Spritely and copy/paste that code.

I have that function in Main(). I’m not familiar with meshes, so I don’t know what it is suppose to do, though.

@LadyJayne - that is very impressive, particularly redoing the sprites!

If it isn’t the math.round function then it sounds like either w or h isn’t defined. There is nothing wrong with the code you pasted above, so you either need to paste here your whole button class so I can have a look at it or just paste into Codea the working Button class available at https://www.dropbox.com/s/7hja2yp23xlmjwk/Button.lua

I double checked the Button() class and don’t see where w and h are defined. Here is my code:


Button = class()
--mesh button class courtesy of @Vega

function Button:init(text, location, width, height)
    -- you can accept and set parameters here
    self.state = "normal"
    self.text = text
    self.textColor = color(255,255,255,192)
    self.location = location
    self.width = width
    self.height = height
    self.visible = true
    self.fontSize = 28
    self.font = "ArialRoundedMTBold"
    self.color1 = color(255,255,255,96)
    self.color2 = color(128,128,128,32)
    self.presscolor1 = color(192,224,224,128)
    self.presscolor2 = color(96,192,224,128)
    self.verts = self:createVerts(self.width, self.height)
    self.myMesh = mesh()
    self.myMesh.vertices = triangulate(self.verts)
    self.vertColor = {}
    self:recolor()
    self.action = nil
    
end

function Button:setColors(c1,c2,p1,p2)
    self.color1 = c1
    self.color2 = c2
    self.presscolor1 = p1
    self.presscolor2 = p2
end

function Button:textOptions(fn, sz, col)
    self.font = fn
    self.fontSize = sz
    self.textColor = col
end

function Button:draw()
    -- Codea does not automatically call this method
    pushStyle()
    if self.visible == true then
        self:recolor()
        pushMatrix()
        translate(self.location.x, self.location.y)
        self.myMesh:draw()
        fill(self.textColor)
        fontSize(self.fontSize)
        font(self.font)
        text(self.text, self.width/2, self.height/2)
        self:drawLines(self.verts)
        popMatrix()
    end
    popStyle()
end

function Button:touched(touch)
    if self.visible then
        if touch.x>=self.location.x and touch.x<= self.location.x + self.width and touch.y>= self.location.y and touch.y<= self.location.y + self.height then
            if touch.state == BEGAN then
                self.state = "pressing"
                sound(SOUND_HIT, 14227)
            elseif touch.state == ENDED then
                if self.state == "pressing" then
                    self.state = "normal"
                end
                if self.action then
                    self.action()
                end
            end
        else
            self.state = "normal"
        end
    end
end

function Button:createVerts(w,h)
    local r
    local v =  {}
    if w > 100 or h > 100 then
        if w >= h then r = math.round(h/100) else r = math.round(w/100) end
    else
        r = 1
    end
    v[1] = vec2(w, 6*r)
    v[2] = vec2(w-r, 4*r)
    v[3] = vec2(w-2*4, 2*r)
    v[4] = vec2(w-4*r,r)
    v[5] = vec2(w-6*r,0)
    v[6] = vec2(6*r,0)
    v[7] = vec2(4*r,r)
    v[8] = vec2(2*r,2*r)
    v[9] = vec2(r,4*r)
    v[10] = vec2(0,6*r)
    v[11] = vec2(0,h-6*r)
    v[12] = vec2(r, h-4*r)
    v[13] = vec2(2*4, h-2*r)
    v[14] = vec2(4*r,h-r)
    v[15] = vec2(6*r, h)
    v[16] = vec2(w-6*r,h)
    v[17] = vec2(w-4*r,h-r)
    v[18] = vec2(w-2*r,h-2*r)
    v[19] = vec2(w-r,h-4*r)
    v[20] = vec2(w, h-6*r)
    return v
end

function Button:drawLines(v)
    noSmooth()
    strokeWidth(1)
    stroke(0,0,0,192)
    for i = 1, #v-1 do
        line(v[i].x,v[i].y,v[i+1].x,v[i+1].y)
    end
    line(v[#v].x,v[#v].y,v[1].x,v[1].y)
end

function Button:recolor()
    local lt, dk
    if self.state == "normal" then
        lt = self.color1
        dk = self.color2
    else
        lt = self.presscolor1
        dk = self.presscolor2
    end
    for i = 1, 3 * #self.verts - 6 do
        if self.myMesh.vertices[i].y> self.height/2 then
            self.vertColor[i] = lt
        else
            self.vertColor[i] = dk
        end
    end
    self.myMesh.colors = self.vertColor

end

I guess it might be tabs order problem…

Hmmm ok. I don’t know much about how that effects code. Here is the order of my tabs:

Main, Cell, Button, RoundBorder, SplashScreen, Fader, Twinkle, IconImages

Thanks

Hi @LadyJayne,

The tab order looks fine. Sorry I’m travelling at the moment and haven’t had a chance to have a detailed look at the code. I will have a look tonight.

Cheers,

Reefwing.

@LadyJayne - Firstly, your question above (where is w and h defined?). In the Button init function there is a line:

self.verts = self:createVerts(self.width, self.height)

and then the definition for the createVerts function is function Button:createVerts(w,h)

So w = self.width and h = self.height.

Now, to isolate the problem I pasted your button class above into a new project and used the following to test it:

function setup()

    location = vec2(WIDTH/2, HEIGHT/2)

    b = Button("Test", location, 180, 50)

end

function draw()

    background(0, 0, 0)

    b:draw()

end

function math.round(num)

    return math.floor(num + 0.5)

end

Which compiled without error, however the button corners at the top left and bottom right look dodgy. So checking your button code against the original I picked up some typos (e.g in createVerts(w,h) have a look at v[3]).

You need to correct these (or just paste the correct version in). I wouldn’t overly worry about understanding meshes just yet, although if you want to jump ahead @Vega did a good tute on them in the forum.

If you are still having problems then these are probably typos as well. Try isolating the problem like I did with the button class above.

If you are still stuck let me know. Happy Coding!

Thank you. I will work on this tonight.

Well. I had problems copying from Dropbox, so I ran your test, and the button class worked fine. I went through Main() – fixed some typos, and it still wouldn’t work. I’m getting the same error in the Button() class. I’m really confused. I did fix the typos in the Button() class as well.

Hi @LadyJayne,

Don’t get discouraged - you are making progress. If the standalone button test works fine then you can eliminate that as the problem.

So the next obvious candidate is the chunk which is calling the Button class. Use print to check what you are passing to the button. It sounds like one of those variables is nil. You could try commenting out all the buttons and then add them back one at a time to work out which is causing the crash.

I can email you the entire code if you want, drop me a line at dsuch@reefwing.com.au