Howdy, Stranger!

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

Brickout example error

edited August 2012 in General Posts: 179

I notice in the Brickout example that it is impossible to reset the game after you lose due to a syntax error. In the reset game function it has this code:

gameOver = false

But it should be :

gameover = false --no capital O there

Making that change allows it to work as intended. I am thinking this example may be way overdue for a rewrite. When this program was written, Codea did not yet have a text function and so it line draws all the numbers and letters. If the program author doesn't want to do it, maybe I could be of service for the rewrite.

Comments

  • SimeonSimeon Admin Mod
    Posts: 5,193

    Thanks @Vega — I'll integrate this fix.

    If you are interested in enhancing or re-writing Brickout, I would be happy to include your updated version in Codea. I think direct-touch controls would help the game tremendously, too.

  • Posts: 179

    How are you thinking? Drag the paddle back and forth to move it? That seems like the most intuitive method.

  • Posts: 179

    By the way, I guess all of the samples that don't have a name on them are by you, @Simeon? I wasn't sure about that, but I probably should have guessed that.

  • Posts: 2,161

    I was thinking of doing a tilt version of brickout

  • Posts: 489

    All the example projects have listed Authors (readProjectInfo("Author")). I used that information to create this list on the wiki.

    The example projects can 'show off what Codea can do' and/or 'teach new users how to use Codea to do things'. Added functionality/complexity helps the first aim but may detract from the second aim - although good comments in the code may help with 'teaching'. As I was learning about Codea, I was most impressed by the examples that cleverly used small amounts of easy to follow code to show off what Codea could do.

  • Posts: 179

    I hear you, @mpilgrim, but replacing all the text line-drawing with text calls will actually simplify the code quite a bit and make it shorter. I also think it could have some updated controls without adding a whole lot of complexity.

  • Posts: 2,161

    Swapping out the text was easy enough (though I did like the look of the line-like numbers so I'm not sure what font to use to get closest to that), I tried making the paddle move with gravity but it's really hard to control if it is real gravity (ie acceleration is based on gravity) so I made it so that the tilt controls the speed. It is still quite tricky, but playable.

    Also made it widescreen.

  • edited August 2012 Posts: 179

    I see how it is, @Andrew_Stacey trying to steal my thunder. Well, I ALSO swapped out the text and made it widescreen and changed the controls to drag-style, not gravity/tilt. Here is the code for my current progress, if anyone wants to try it out and see how they like the drag. I think it works better than the way it is in the example.


    ------------------------ -- Main game functions -- ------------------------- supportedOrientations(LANDSCAPE_ANY) displayMode(FULLSCREEN) blocks = {} score = 0 lives = 3 ballIsMoving = false gameover = false won = false instructions = true level = 1 maxlevel = table.maxn(levels) -- Use this function to perform your initial setup function setup()     ball = Ball()     ball.vel.x = math.random(-3,3)     bat = Bat()     --makeBlocks()     --print("Tap the bat to lanch the ball.")     --print("Tap the far right side of the screen to move right, far left side to move left.")     --print("When the game is over tap the middle of the screen to restart.") end -- create table of blocks from level array function makeBlocks()     local blockSize = vec2(math.floor(WIDTH/12),math.floor(WIDTH/24))     for i = 1, 6 do         c = getColorForRow(i)         for j = 1, 10 do             if levels[level][i][j] > 0 then                 table.insert(blocks,Block((j*(blockSize.x+2)+WIDTH/24),HEIGHT-(i * (blockSize.y+2)+WIDTH/24),c))                              end         end     end end -- get color for current row function getColorForRow(row)     colChanger = row * 35     if level % 4 == 1 then         c = color(colChanger,0,255,255)     elseif level % 4 == 2 then         c = color(255,colChanger,0,255)     elseif level % 4 == 3 then         c = color(255,0,colChanger,255)     else         c = color(0,255,colChanger,255)     end     return c end -- Stop ball and put it back on bat function resetBall()     ballIsMoving = false     ball.pos.x = bat.pos.x     ball.pos.y = 41 end -- Reset game to original state function resetGame()     score = 0     lives = 3     level = 1     blocks = {}     makeBlocks()     instructions = false     gameover = false     won = false end -- Level up function nextLevel()     score = score + 100 * lives * level     --ball.vel.y = ball.vel.y + 0.5     resetBall()     if level < maxlevel then         level = level + 1         makeBlocks()     else         won = true     end end -- Lose a life function loseLife()     resetBall()     lives = lives - 1     if lives == 0 then         gameover = true     end end -- This function gets called once every frame function draw()     background(0, 0, 0, 255)     noSmooth()     -- Update the ball     if ballIsMoving then         if ball:update() == false then             loseLife()         end     else         ball.pos.x = bat.pos.x     end     -- Check collision with the bat     if bat:collide(ball) == false then         -- Check collision with the blocks - no need to do this if ball has hit bat.          -- Still does a lot of unecessary checks         for i = 1, table.maxn(blocks) do             if blocks[i]:collide(ball) then                 table.remove(blocks, i)                 score = score + 100                 if table.maxn(blocks) == 0 then                     nextLevel()                 end                 break             end         end     end     -- Draw game objects     bat:draw()     ball:draw()     for i = 1, table.maxn(blocks) do         blocks[i]:draw()     end     -- Draw score and lives     pushStyle() --Start using temporary styles         fill(255, 255, 255, 255)         noStroke()         text(score,40,HEIGHT-20)         text("x " .. lives, WIDTH - 20, HEIGHT - 20)         fill(253, 255, 0, 255)         ellipse(WIDTH - 50, HEIGHT - 19, 20)     popStyle()     -- Display messages (Win, lose, or instructions)     if gameover then         pushStyle() --Start using temporary styles             text("Game Over", WIDTH / 2, HEIGHT / 2)             text("Score: " .. score, WIDTH / 2, HEIGHT / 2 - 40)             text("Touch here to restart", WIDTH / 2, HEIGHT / 2 - 80)         popStyle()  --End temporary styles     elseif won then         pushStyle() --Start using temporary styles             text("Congratulations, all levels complete.", WIDTH / 2, HEIGHT / 2)             text("Score: " .. score, WIDTH / 2, HEIGHT / 2 - 40)             text("Touch here to restart", WIDTH / 2, HEIGHT / 2 - 80)         popStyle()  --End temporary styles     elseif instructions then         pushStyle() --Start using temporary styles             text("Tap the bat to launch the ball.", WIDTH / 2, HEIGHT / 2)             text("Drag the bat to move it left and right.", WIDTH / 2, HEIGHT / 2 - 40)             text("Touch here to Start game.", WIDTH / 2, HEIGHT / 2 - 80)         popStyle()  --End temporary styles     end end function touched(touch)     if touch.state == BEGAN or        touch.state == MOVING then         if gameover == false and won == false and instructions == false then             -- If bat is touched launch ball             if touch.x < bat:right() + 120 and                  touch.x > bat:left() - 120 and                  touch.y < bat:top() + 80 and                  touch.y > bat:bottom() - 10 then                 if ballIsMoving == false then                     ballIsMoving = true                 else                     if touch.x > bat:right() and bat:right() < WIDTH - math.floor(WIDTH/40) then                         bat.pos.x = bat.pos.x + math.floor(WIDTH/20) --Move Right                     elseif touch.x < bat:left() and bat:left() > math.floor(WIDTH/40) then                         bat.pos.x = bat.pos.x - math.floor(WIDTH/20) --Move Left                     end                 end             end         elseif gameover == true or won == true or instructions == true then             -- If center of screen is touched start game             if touch.y > 300 and touch.y < 448 and             touch.x > 130 and touch.x < WIDTH - 130 then                 resetGame()             end         end     end end ---------------- -- Ball Class -- ---------------- Ball = class() function Ball:init()     self.pos = vec2(WIDTH / 2, 41)     self.radius = 10     self.vel = vec2(0, 7) end function Ball:draw()     fill(253, 255, 0, 255)     noStroke()     ellipse(self.pos.x, self.pos.y, 2 * self.radius) end function Ball:update()     self.pos = self.pos + self.vel     if (self.pos.x + self.radius) >= WIDTH then         self.pos.x = WIDTH - self.radius         self.vel.x = -self.vel.x         sound(SOUND_JUMP)     elseif (self.pos.x - self.radius) <= 0 then         self.pos.x = self.radius         self.vel.x = -self.vel.x         sound(SOUND_JUMP)     elseif (self.pos.y + self.radius) >= HEIGHT then         self.pos.y = HEIGHT - self.radius         self.vel.y = -self.vel.y         sound(SOUND_JUMP)     elseif (self.pos.y - self.radius) <= 0 then         self.pos.y = self.radius         self.vel.y = -self.vel.y         sound(SOUND_EXPLODE)         return false     end     return true end function Ball:left()     return self.pos.x - self.radius end function Ball:right()     return self.pos.x + self.radius end function Ball:top()     return self.pos.y + self.radius end function Ball:bottom()     return self.pos.y - self.radius end
  • Posts: 179


    --------------- -- Bat Class -- --------------- Bat = class() function Bat:init()     self.pos = vec2(math.floor(WIDTH/2), math.floor(WIDTH/30)+1)     self.size = vec2(math.floor(WIDTH/7), math.floor(WIDTH/30)) end function Bat:draw()     fill(167, 170, 186, 255)     noStroke()     rectMode(CENTER)     ellipse(self.pos.x - self.size.x / 2 + 5, self.pos.y, math.floor(WIDTH/30))     ellipse(self.pos.x + self.size.x / 2 - 5, self.pos.y, math.floor(WIDTH/30))     rect(self.pos.x, self.pos.y, self.size.x, self.size.y) end function Bat:collide(ball)     if ball:left() <= self:right() and        ball:right() >= self:left() and        ball:top() >= self:bottom() and        ball:bottom() <= self:top() then         sound(SOUND_JUMP)         ball.vel.y = -ball.vel.y         -- change the x velocity depending on where the ball hit the bat         ball.pos.y = self:top() + ball.radius         pos = ball.pos.x - self.pos.x         ball.vel.x = pos / 10         return true     end     return false end function Bat:left()     return self.pos.x - self.size.x / 2 end function Bat:right()     return self.pos.x + self.size.x / 2 end function Bat:top()     return self.pos.y + self.size.y / 2 end function Bat:bottom()     return self.pos.y - self.size.y / 2 end ----------------- -- Block Class -- ----------------- Block = class() function Block:init(x, y, col)     self.pos = vec2(x, y)     self.size = vec2(math.floor(WIDTH/12),math.floor(WIDTH/24))     self.color = col end function Block:draw()     fill(self.color)     noStroke()     rectMode(CENTER)     rect(self.pos.x, self.pos.y, self.size.x, self.size.y) end function Block:collide(ball)     if ball:left() <= self:right() and        ball:right() >= self:left() and        ball:top() >= self:bottom() and        ball:bottom() <= self:top() then         sound(SOUND_BLIT)         if ball.pos.y <= self:top() and ball.pos.y >= self:bottom() then             ball.vel.x = -ball.vel.x         else             ball.vel.y = -ball.vel.y         end         return true     end     return false end function Block:left()     return self.pos.x - self.size.x / 2 end function Block:right()     return self.pos.x + self.size.x / 2 end function Block:top()     return self.pos.y + self.size.y / 2 end function Block:bottom()     return self.pos.y - self.size.y / 2 end ------------------ -- Levels array -- ------------------ levels = {      {{0,0,1,1,1,1,1,1,0,0},{0,1,1,0,0,0,0,1,1,0},{0,0,1,1,1,1,1,1,0,0}, {0,0,1,1,1,1,1,1,0,0},{0,1,1,0,0,0,0,1,1,0},{0,0,1,1,1,1,1,1,0,0}},      {{1,1,1,1,1,1,1,1,1,1},{1,0,0,1,0,0,1,0,0,1},{0,1,1,0,1,1,0,1,1,0}, {0,1,1,0,1,1,0,1,1,0},{1,0,1,1,0,0,1,0,0,1},{1,1,1,1,1,1,1,1,1,1}},      {{0,0,0,1,1,1,1,0,0,0},{0,0,1,1,1,1,1,1,0,0},{1,1,1,1,1,1,1,1,1,1}, {1,1,1,1,1,1,1,1,1,1},{0,1,1,1,1,1,1,1,1,0},{0,0,1,2,1,1,1,1,0,0}},      {{1,0,1,1,1,1,1,1,0,1},{1,1,1,0,1,1,0,1,1,1},{1,0,1,1,0,0,1,1,0,1}, {1,0,1,1,0,0,1,1,0,1},{1,1,1,0,1,1,0,1,1,1},{1,0,1,1,1,1,1,1,0,1}},      {{1,1,1,1,1,1,1,1,1,1},{1,0,1,1,0,0,1,1,0,1},{1,1,0,0,1,1,0,0,1,1}, {1,1,0,0,1,1,0,0,1,1},{1,0,1,1,0,0,1,1,0,1},{1,1,1,1,1,1,1,1,1,1}}      }

    I am thinking maybe I should speed up the ball as the levels increase.. What do you think?

  • SimeonSimeon Admin Mod
    edited August 2012 Posts: 5,193

    I had a go updating this project this morning as well. I added gradient bevelled bricks, motion blur on the ball, drag controls and particle effects.

    https://gist.github.com/3255183

    Brickout Enhanced

    If you guys want to make further changes I will be happy to include them.

  • Posts: 2,161

    Definitely not trying to steal thunder!

    The big thing for me is tilt control. When my kids first tried brickout then they were trying to control the bat by tilting the ipad. I think that the fact you can pick up and move an ipad is what sets it apart as an experience from ordinary computers. So to be a truly ipad game, it ought to involve the ipad itsrlf as the controller.

  • Posts: 2,161

    Interesting that you still draw the numbers! I've got some ideas on reducing the collison tests - I'll have a try-out tonight.

  • Posts: 2,161

    Don't like drag. My fingers are so fat that I can't see the paddle underneath.

    But I do like the updated bricks, bat, ball, and effects.

  • Posts: 489

    I have a (minor) suggestion for Bat:draw(). Is it more or less efficient to make use of the lineCapMode(ROUND) pattern (applied in the RoundRect() function in the Sounds Plus example project)? For example:

    function Bat:draw()
        stroke(167, 170, 186) -- Set the colour for the bat
        smooth()              -- Turn on for lineCapMode to work
        strokeWidth(24)       -- Set width of line
        lineCapMode(ROUND)    -- Set rounded ends
        line(self.pos.x - self.size.x / 2, self.pos.y,
            self.pos.x + self.size.x / 2, self.pos.y)
        noSmooth() -- Not clear to me why draw() sets noSmooth() repeatedly
    end
    
  • Posts: 489

    May I ask what determines the fonts available in the font picker for font()? On my iPad, I am offered different weights etc of:

    Academy Engraved
    American Typewriter
    Emoji
    Arial (various versions of it)
    Baskerville
    Copperplate
    Courier
    Courier New
    Didot
    Futura
    Georgia
    Gill Sans
    Helvetica Neue
    Hoefler Text
    Inconsolata
    Marion
    Marker Felt
    Myriad Pro
    Noteworthy
    Optima
    Palatino
    Papyrus
    Snell Roundhand
    Times New Roman (various versions of it)
    Verdana
    Zapf Dingbats TC
    Zapfino
    

    That appears to be a subset of the fonts listed in the in-app reference for font().

  • SimeonSimeon Admin Mod
    edited August 2012 Posts: 5,193

    @mpilgrem it's the same — ROUND lineCapMode actually draws a squared-off line and two ellipses.

    I did the bat this way so I could tweak the radius of the end caps by one pixel — I should really fix the issue in ROUND lines, though.

    @Andrew_Stacey what if it asked you at the start if you want to use tilt or touch controls?

    Edit: @mpilgrem That's correct about the fonts, I only display a subset because there are so many fonts that would clutter up the list for most people. Most of them would not be useful to the majority of Codea users. (The fonts shown are just the available fonts in your version of iOS.)

    Edit 2: @Andrew_Stacey I only left the numbers as-is because I was too lazy to ensure the layout worked well and select a nice font. I also didn't mind the retro look.

  • Posts: 489

    For the numbers, using font("DBLCDTTempBlack") might preserve the retro feel of the original example project. See my recent discussion here (it is font number 49, in that example).

  • Posts: 384

    How about a 3D version?

    He he just kidding. :) I think it's great there are lots of people willing and able to contribute like this in the community.

  • Posts: 179

    I was just playing, @Andrew_Stacey. ;-) I can imagine that playing with tilt might be fun, but I think touch may be the way to go on this one.

    I think the new version looks nice, @Simeon. Some things I did on my initial version I do like better, like I changed the code so that it would work in full screen, put the instructions on screen and converted to text for the numbers, etc., but you have better implemented drag controls, converted to meshes on the blocks and made them look nice, added cool particle effects, etc.

    So I will bow out here and feel content that I sparked the conversation that led to the neat new version of Brickout. Nice work.

  • SimeonSimeon Admin Mod
    Posts: 5,193

    @Vega I will try include your changes in the next update — It sounds like you took care of all the bits I didn't attempt.

  • Posts: 489

    @Simeon, further on the subject of the font picker: is there any practical benefit in the picker listing 'Emoji' (AppleColorEmoji) and 'Zapf Dingbats TC' (ZapfDingbatsITC) when those fonts have no interesting characters in the 0-255 range?

    Those slots in the picker might be used for one of the iOS fonts with interesting characters in the 0-255 range, such as "BradleyHandITCTT-Bold", "Chalkduster", "DBLCDTempBlack" or "PartyLetPlain".

  • SimeonSimeon Admin Mod
    Posts: 5,193

    You can use the Emoji fonts by enabling Emoji on the iPad keyboard. That way you can actually type little pictures into your code, and have them render.

    A number of people have done this for their games, given the wide variety of colourful symbols.

    Zapf is probably not as useful since there is no way to enable the extended characters on the keyboard outside of copy+paste.

  • Posts: 179

    I have been loafing around here, helping people as much as possible, testing things, and learning the language because I didn't really have any good ideas for a new game I'd like to make. While working on updating the Brickout example, I started to get a bit of an idea for a game and it has grown into a full-fledged game plan today.

    It really has little to do with Brickout, other than it does use a small ball (or several) bouncing around. I guess you never know what might inspire you or help your brain make a crucial connection.

    Someday, maybe I will sell 10k copies and look back remembering that time I worked on the Brickout game and suddenly had an epiphany :-)

  • SimeonSimeon Admin Mod
    Posts: 5,193

    Epiphanies are the best. Looking forward to seeing your game.

  • SimeonSimeon Admin Mod
    Posts: 5,193

    @Andrew_Stacey I think what sets the iPad apart as a controller is that you can directly touch the things you want to interact with. Creates a more direct connection between the player and the game elements.

    Tilt controls are interesting too, though I prefer direct-touch control where possible. I like tilt controls in Labyrinth-style games.

  • edited August 2012 Posts: 489

    @Simeon, thank you for explaining about the iPad keyboards and emoji - I did not know that. I also did not appreciate that the print() and text() functions implemented in Codea were Unicode-aware (at least, I assume the multiple bytes for each character are its Unicode).

    On the face of it, none of that would require (or be helped) by AppleColorEmoji being included in the font picker. However, my experiments suggest that text() behaves oddly at large - but not small - fontSize if the font is not Emoji. For example:

    (Edit: It looks like my attempt to copy-paste code with emoji characters has not worked. I will will try to explain what my experiment was in another way.

    Replace the text '[emoji characters]' below with six emoji characters entered using the emoji iPad keyboard.)

    function setup()
        str = "emoji: [emoji characters]" -- Entered with emoji iPad keyboard
        print(#str, str)             -- print() is Unicode-aware
        -- Multiple bytes for each emoji character
        for i = 1, #str do
            local c = str:byte(i)
            print (i, c, string.char(c))
        end
        fill(255)
    end
    
    function draw()
        background(0)
        fontSize(32 * (1.25 + math.sin(ElapsedTime)))
        font("ArialMT")
        text(str, WIDTH/2, HEIGHT*3/4) -- Unicode-aware, but emoji not scaled symmetrically
        font("AppleColorEmoji")
        text(str, WIDTH/2, HEIGHT/4) -- Unicode-aware, AND emoji are scaled    
    end
    
  • Posts: 2,161

    Simeon, you wouldn't say that if you'd seen my kids playing with my iPad. Maybe your compromise of an option at the start is best. I agree with Vega that a fullscreen game is better with the instructions at start-up - I'll post a variant of yours a bit later to show.

    Re text: yes, unicode works just fine so long as the font supports it (I wrote a crude font-chart project to see what the different fonts support, happy to share as always). You can get arbitrary unicode characters by passing the necessary numbers to string.char(). You need to take the decimal representation of the unicode entry. I have a library that does all of this.

  • Posts: 2,161

    Okay, here's Brickout with my modifications. Notably:

    1. Tilt controls. It takes a bit to get used to, and if you find it over/under-sensitive then tweak the parameter (currently set to 1600).
    2. Fullscreen. So the instructions are shown at start-up and then disappear for evermore.
    3. Collision Testing. Not sure if this will actually produce an improvement, but when testing the bat it tests the vertical first as that's most likely to fail, and for the blocks then it works out which block position the ball is in and tests only the neighbouring blocks.

    Code at http://www.math.ntnu.no/~stacey/documents/Codea/Brickout.lua

  • Posts: 489

    Hello @Andrew_Stacey. Thank you for the pointer to your UTF-8 library.

    In function utf8dec(a), I think the line:

    elseif a < 1114112 then -- 0x110000 = 2^20 + 2^16
    

    should be:

    elseif a < 2097152 then -- 0x200000 = 2^21; (21 = 3 + 6 + 6 + 6)
    
  • Posts: 2,161

    Looks right to me. Playing with numbers, my guess is that the error stems from the fact that 1114112 = 0x110000 so at some point I've obviously gotten confused with binary and hexadecimal. Shows how often I've used characters with such high unicode numbers!

    (And hooray for libraries: now I just have to change one number in only one file!)

    Thanks for the fix. Are there any more of my files I can interest you in? You seem to have a good eye for mistakes!

Sign In or Register to comment.