NaaLaa
Naalaanoid (another arkanoid clone) - Printable Version

+- NaaLaa (https://www.naalaa.com/forum)
+-- Forum: NaaLaa (https://www.naalaa.com/forum/forum-1.html)
+--- Forum: NaaLaa 7 Code (https://www.naalaa.com/forum/forum-4.html)
+--- Thread: Naalaanoid (another arkanoid clone) (/thread-207.html)



Naalaanoid (another arkanoid clone) - Marcus - 03-16-2025

Here's another arkanoid clone!

   

Code:
' naalaanoid.n7
' -------------

#win32

include "tilemap.n7"
include "sfx.n7"
include "file.n7"

' Level generation thing.
visible SEED = 241' 239
' Bonuses.
constant BIG_PADDLE = 1, SMALL_PADDLE = 2, SPEED_UP = 3, SPEED_DOWN = 4, MULTIBALL = 5, CANNONS = 6

' Images.
visible vTilemapImage
visible vBgImage
visible vRedBrickImage, vGreenBrickImage, vBlueBrickImage, vYellowBrickImage, vMagentaBrickImage
visible vCyanBrickImage, vBrickHitImage
visible vPaddleImage, vCannonImage
visible vBallImage, vBulletImage
visible vBigPaddleBonusImage, vSmallPaddleBonusImage, vSpeedUpBonusImage, vSpeedDownBonusImage
visible vMultiballBonusImage, vCannonsBonusImage
visible vNaalaanoidTextImage, vGetReadyTextImage, vGameOverTextImage

' Colors.
visible vRedColor = [157, 40, 92], vGreenColor = [0, 118, 69], vBlueColor = [0, 110, 138]
visible vYellowColor = [179, 175, 12], vMagentaColor = [149, 31, 169], vCyanColor = [71, 193, 197]
visible vWhiteColor = [252, 252, 252], vBlackColor = [0, 0, 0], vGrayColor = [185, 185, 185]
visible vDarkRedColor = [90, 0, 24], vDarkGreenColor = [0, 57, 36], vDarkBlueColor = [9, 19, 128]
visible vDarkMagentaColor = [85, 0, 86]

' Sound effects.
visible vPaddleSound, vBrickHitSound, vBrickDestroyedSound, vWallSound, vLifeLostSound, vBonusSound
visible vShootSound

' Sprite lists.
visible vBalls = []
visible vBullets = []
visible vAnims = []
visible vBonuses = []

' Flying texts.
visible vFlyingTexts = FlyingTexts(64)

' Stats.
visible vScore, vTopScore
visible vBrickCount, vBricksLeft

' Create window.
set window "Naalaanoid", 256, 240, false, int((screenh() - 160)/240)
set redraw off

' Create and set save folder.
folder = GetPathCombined(GetAppDataDirectory(), "naalaa7")
CreateDirectory(folder)
saveFilename = GetPathCombined(folder, "naalaanoid.bin")
f = openfile(saveFilename, true)
if typeof(f)
    vTopScore = fread(f, 32)
    free file f
else
    vTopScore = 0
endif

' Generate assets.
CreateAssets()
vBgImage = createimage(256, 240)
create font 1, "courier new", 13
set font 1

TM_SetImage(vTilemapImage)
TM_SetBorder(true, true, true, false)
for i = 0 to 17  TM_SetObstacle(i, true)

do
    ' Show title screen, returns false if user wants to quit.
    if not TextScreen(vNaalaanoidTextImage, ["TOP SCORE: " + str(vTopScore, 5), "",
            "PRESS ESC TO QUIT"])  break
    level = 1
    lives = 3
    vScore = 0

    do
        ' Init level.
        BuildLevel(level)
        TextScreen(vGetReadyTextImage, ["STAGE " + str(level, 2)])
        clear vAnims
        clear vBonuses
        clear vBalls
        clear vBullets
        vFlyingTexts.Clear()
        paddleX = mousex()
        paddleY = 248
        paddleW = 40
        paddleWantedW = 40
        paddleBullets = 0
        vBalls[0] = Ball(paddleX, paddleY - 3, 0, -1)
        vBalls[0].SetCaptured(true)
        helpTimer = -1   
        do
            ' Fetch ball.
            if sizeof(vBalls)
                paddleY = max(paddleY - 1, 208)
            elseif vBricksLeft > 0
                paddleY = min(paddleY + 2, 248)
                if paddleY = 248
                    lives = lives - 1
                    if lives >= 0
                        vBalls[0] = Ball(paddleX, paddleY - 3, 0, -1)
                        vBalls[0].SetCaptured(true)
                    else
                        break
                    endif
                endif
            endif
            ' Change paddle size.
            if paddleW < paddleWantedW  paddleW = min(paddleW + 1, paddleWantedW)
            elseif paddleW > paddleWantedW  paddleW = max(paddleW - 1, paddleWantedW)
            ' Move.
            paddleX = TM_ToWorldX(min(max(mousex(), 8), 216))
            ' Launch ball or fire bullets.
            if mousebutton(0, true)
                if sizeof(vBalls) = 1 and vBalls[0].captured and paddleY < 216
                    vBalls[0].SetCaptured(false)
                    vBalls[0].SetDir((vBalls[0].X() - paddleX)/paddleW, -0.5)
                elseif paddleBullets > 0
                    paddleBullets = paddleBullets - 1
                    vBullets[sizeof(vBullets)] = Bullet(paddleX - paddleW/2 + 5, paddleY - 4)
                    vBullets[sizeof(vBullets)] = Bullet(paddleX + paddleW/2 - 5, paddleY - 4)
                    play sound vShootSound
                endif
            endif
            ' Add helping powerups every now and then if there are few bricks left.
            if vBricksLeft/vBrickCount < 0.25
                helpTimer = helpTimer - 1
                if helpTimer <= 0
                    if sizeof(vBalls) <= 2 and paddleBullets <= 0
                        helpTimer = 10*60
                        if rnd(2) = 0  AddBonus(MULTIBALL, rnd(13)*16 + 8, -8)
                        else  AddBonus(CANNONS, rnd(13)*16 + 8, -8)
                    else
                        helpTimer = 3*60
                    endif
                endif
            endif
            ' Update sprites.
            before = sizeof(vBalls)
            UpdateSprites(vBalls)
            if sizeof(vBalls) = 0 and before > 0  play sound vLifeLostSound
            UpdateSprites(vBullets)
            UpdateSprites(vBonuses)
            UpdateSprites(vAnims)
            vFlyingTexts.Update()
            ' Update captured balls and collisions with paddle.
            foreach b in vBalls
                if b.captured
                    b.SetPos(min(max(b.X(), paddleX - paddleW/2), paddleX + paddleW/2), paddleY - 3)
                elseif b.dy > 0 and b.y + 6 >= paddleY and b.y < paddleY + 8
                    x = b.x + 3;  dx = x - paddleX
                    if |dx| < paddleW/2 + 3
                        b.SetDir(dx/paddleW, -0.5)
                        play sound vPaddleSound
                    endif
                endif
            next
            ' Pick up bonuses.
            i = 0
            px = paddleX - paddleW/2
            while i < sizeof(vBonuses)
                p = vBonuses[i]
                if p.x + 16 >= px and p.x < px + paddleW and p.y + 8 >= paddleY and p.y < paddleY + 8
                    vScore = vScore + 10
                    select p.type
                    case BIG_PADDLE
                        if paddleWantedW < 80  paddleWantedW = paddleWantedW + 8
                        txt = "BIG PADDLE"
                    case SMALL_PADDLE
                        if paddleWantedW > 24 paddleWantedW = paddleWantedW - 8
                        txt = "SMALL PADDLE"
                    case SPEED_UP
                        foreach b in vBalls  b.IncSpeed()
                        txt = "SPEED UP"
                    case SPEED_DOWN
                        foreach b in vBalls  b.DecSpeed()
                        txt = "SPEED DOWN"
                    case MULTIBALL
                        foreach b in vBalls  if not b.captured
                            a = atan2(b.dy, b.dx)
                            vBalls[sizeof(vBalls)] = Ball(b.X(), b.Y(), cos(a + PI/4), sin(a + PI/4))
                            vBalls[sizeof(vBalls)] = Ball(b.X(), b.Y(), cos(a - PI/4), sin(a - PI/4))
                        endif
                        txt = "MULTIBALL"                    
                    case CANNONS
                        paddleBullets = paddleBullets + 10
                        txt = "CANNONS"
                    endsel
                    free key vBonuses, i
                    vFlyingTexts.Add(txt, 1, p.X(), p.Y(), 0.5, 2)
                    play sound vBonusSound
                else
                    i = i + 1
                endif
            wend
           
            ' Draw.
            set color 255, 255, 255
            draw image vBgImage, 0, 0
            TM_Render()
            DrawPaddle(TM_ToScreenX(paddleX), TM_ToScreenY(paddleY), paddleW, paddleBullets > 0)
            draw image vBgImage, 0, paddleY, 0, paddleY, 8, 240 - paddleY
            draw image vBgImage, 216, paddleY, 216, paddleY, 256 - 216, 240 - paddleY
            DrawSprites(vAnims)
            DrawSprites(vBalls)
            DrawSprites(vBullets)
            DrawSprites(vBonuses)
            vFlyingTexts.Draw()
            clear clip rect
            set caret 256 - 16, 0
            set color vWhiteColor;  center "STAGE"
            set color vBlueColor;  center str(level, 2)
            center
            set color vWhiteColor;  center "LIVES"
            set color vRedColor;  center max(lives, 0)
            center
            set color vWhiteColor;  center "SCORE"
            set color vYellowColor;  center str(vScore, 5)
           
            redraw
            fwait 60
        until vBricksLeft = 0 and vFlyingTexts.IsEmpty() or keydown(KEY_ESCAPE, true)
        if vBricksLeft = 0  level = level + 1
        else  break
    loop
    if lives < 0
        if vScore > vTopScore
            vTopScore = vScore
            f = createfile(saveFilename, true)
            if typeof(f)
                write file f, vScore, 32
                free file f
            endif
            TextScreen(vGameOverTextImage, ["NEW HIGH SCORE: " + str(vScore, 5)])
        else
            TextScreen(vGameOverTextImage, ["SCORE: " + str(vScore, 5)])
        endif
    endif
loop

' TextScreen
' ----------
function TextScreen(img, texts)
    set color 0, 0, 0;  cls;  redraw;  wait 500
    blinkTimer = 40
    abort = false
    do
        if keydown(KEY_ESCAPE, true)
            abort = true
            break
        endif
        if mousebutton(0, true)  break
        blinkTimer = (blinkTimer - 1)%80
        set color 0, 0, 0;  cls
        set color 255, 255, 255
        draw image img, (width(primary) - width(img))/2, height(primary)/3 - height(img)/2
        set caret width(primary)/2, height(primary)/2 - sizeof(texts)*fheight()/2
        set color vWhiteColor;  for i = 0 to sizeof(texts) - 1  center texts[i]
        center
        if blinkTimer < 40
            set caret width(primary)/2, 2*height(primary)/3 - fheight()/2
            center "CLICK TO CONTINUE ..."
        endif
        redraw
        fwait 60
    loop
    set color 0, 0, 0;  cls;  redraw;  wait 500
    return not abort
endfunc

' UpdateSprites
' -------------
function UpdateSprites(list)
    i = 0
    while i < sizeof(list)  if list[i].Update()  i = i + 1
    else  free key list, i
endfunc

' DrawSprites
' -----------
function DrawSprites(list)
    if sizeof(list)  for i = 0 to sizeof(list) - 1  list[i].Draw()
endfunc

' BuildLevel
' ----------
function BuildLevel(level)
    ' Build level from random rectangles.
    if level = 1  blobCount = 2
    else  blobCount = 3 + min(int((level - 1)*0.6), 24);  levelHeight = 16 + min(int(level/2), 6)
    randomize SEED + level
    TM_InitMap(13, levelHeight)
    TM_SetView(8, 8, 13*16, levelHeight*8)
    for i = 1 to blobCount
        bw = 1 + rnd(5);  bh = 1 + rnd(5);  bx = rnd(7);  by = 1 + rnd(levelHeight - bh - 1)
        innerCel = rnd(min(6 + 6*int((level - 1)*0.5), 18))
        outerCel = rnd(min(6 + 6*int((level)*0.5), 18))
        for y = by to by + bh - 1  for x = bx to bx + bw - 1  if x <= 6
            if x = bx or x = bx + bw - 1 or y = by or y = by + bh - 1  cel = outerCel
            else  cel = innerCel
            TM_SetCel(x, y, cel)
            if x < 6  TM_SetCel(6 + (6 - x), y, cel)
        endif
    next
    ' Count bricks and add powerups.
    vBrickCount = 0
    for y = 0 to levelHeight - 1  for x = 0 to 12  if TM_GetCel(x, y) >= 0
        vBrickCount = vBrickCount + 1
        if rnd(5) = 0  TM_SetFlag(x, y, 1 + rnd(6))
    endif
    vBricksLeft = vBrickCount
   
    ' Create background image.
    patternImage = createimage(16, 16)
    set image patternImage
    select rnd(4)
    case 0  set color vDarkRedColor
    case 1  set color vDarkGreenColor
    case 2  set color vDarkBlueColor
    case 3  set color vDarkMagentaColor
    endsel
    cls
    set color 0, 0, 0
    for i = 1 to 4
        select rnd(3)
            case 0  draw ellipse rnd(16), rnd(16), rnd(12), rnd(12), false
            case 1  draw rect rnd(16), rnd(16), rnd(12), rnd(12), false
            case 2  draw line rnd(16), rnd(16), rnd(16), rnd(16)
        endsel
    next
    set image primary
    set image vBgImage
    set color 0, 0, 0;  cls
    set color 255, 255, 255
    for y = 0 to 14  for x = 0 to 12  draw image patternImage, 8 + x*16, 8 + y*16
    free image patternImage
    set color vGrayColor
    draw rect 0, 8, 8, 232, true;  draw rect 216, 8, 8, 232, true;  draw rect 8, 0, 208, 8, true
    set clip rect 0, 0, 8, 8;  draw ellipse 8, 8, 8, 8, true
    set clip rect 216, 0, 8, 8;  draw ellipse 215, 8, 8, 8, true
    clear clip rect
    set color 0, 0, 0
    draw line 8, 7, 215, 7;  draw line 7, 8, 7, 240;  draw line 216, 8, 216, 240
    set image primary
endfunc

' Ball
' ----
function Ball(x, y, dx, dy)
    b = []
    b.SetCaptured = function(value)
        this.captured = value
    endfunc
    b.SetPos = function(x, y)
        this.x = min(max(x - 3, 0), 202)
        this.y = y - 3
    endfunc
    b.X = function();  return this.x + 3;  endfunc
    b.Y = function();  return this.y + 3;  endfunc
    b.SetDir = function(dx, dy)
        k = 1/sqr(dx*dx + dy*dy)
        this.dx = k*dx
        this.dy = k*dy
    endfunc
    b.IncSpeed = function()
        this.spd = this.spd + 0.5
        this.spdt = 0
    endfunc
    b.DecSpeed = function()
        this.spd = max(this.spd - 0.5, 1)
        if this.spd < 2  this.spdt = 60*10
    endfunc
    b.Update = function()
        if this.captured  return true
        if this.spdt > 0
            this.spdt = this.spdt - 1
            if this.spdt = 0  this.IncSpeed()
        endif
        ' Move one unit at a time for the brick hits to work better.
        move = this.spd
        res = -1
        while move > 0
            spd = min(move, 1)
            move = move - 1
            TM_MoveSprite(this, this.dx*spd, this.dy*spd)
            if TM_CollisionUp()
                ixl = floor((this.x)/16);  ixr = floor((this.x + 5)/16);  y = floor((this.y - 4)/8)
                res = max(res, HitBrick(ixl, y))
                if ixr <> ixl  res = max(res, HitBrick(ixr, y))
                this.dy = |this.dy|
            elseif TM_CollisionDown()
                ixl = floor((this.x)/16);  ixr = floor((this.x + 5)/16);  y = floor((this.y + 10)/8)
                res = max(res, HitBrick(ixl, y))
                if ixr <> ixl  res = max(res, HitBrick(ixr, y))
                this.dy = - |this.dy|
            endif
            if TM_CollisionLeft()
                iyt = floor((this.y)/8);  iyb = floor((this.y + 5)/8);  x = floor((this.x - 8)/16)
                res = max(res, HitBrick(x, iyt))
                if iyb <> iyt  res = max(res, HitBrick(x, iyb))
                this.dx = |this.dx|
            elseif TM_CollisionRight()
                iyt = floor((this.y)/8);  iyb = floor((this.y + 5)/8);  x = floor((this.x + 14)/16)
                res = max(res, HitBrick(x, iyt))
                if iyb <> iyt  res = max(res, HitBrick(x, iyb))
                this.dx = -|this.dx|
            endif
        wend
        ' Prevent ball from going too much horizontally.
        if |this.dy| < 0.1
            if this.dy < 0  this.SetDir(this.dx, -0.15)
            else  this.SetDir(this.dx, 0.15)
        endif
        'endif
        if res = 0  play sound vWallSound
        elseif res = 1  play sound vBrickHitSound
        elseif res = 2  play sound vBrickDestroyedSound
        a = atan2(this.dy, this.dx)
        return this.y < 240
    endfunc
    b.Draw = function()
        draw image vBallImage, TM_ToScreenX(this.x), TM_ToScreenY(this.y)
    endfunc
    b.captured = false
    b.r = 3
    b.w = 6
    b.h = 6
    b.spd = 2
    b.spdt = 0
    b.SetPos(x, y)
    b.SetDir(dx, dy)
   
    return b
endfunc

' Bullet
' ------
function Bullet(x, y)
    return [x: x - width(vBulletImage)/2, y: y - height(vBulletImage)/2,
            w: width(vBulletImage), h: height(vBulletImage),
            Update: function()
                TM_MoveSprite(this, 0, -4)
                if TM_CollisionUp()
                    ixl = floor(this.x/16);  ixr = floor((this.x + 4)/16)
                    iy = floor((this.y - 4)/8)
                    res = HitBrick(ixl, iy)
                    if ixr <> ixl  res = max(res, HitBrick(ixr, iy))
                    if res = 0  play sound vWallSound
                    elseif res = 1  play sound vBrickHitSound
                    elseif res = 2  play sound vBrickDestroyedSound
                    return false
                endif
                return true
            endfunc,
            Draw: function()
                draw image vBulletImage, TM_ToScreenX(this.x), TM_ToScreenY(this.y)
            endfunc]
endfunc

' AddAnim
' -------
function AddAnim(img, x, y, spd, startCel)
    vAnims[sizeof(vAnims)] = [
            img: img, cel: startCel, x: x, y: y, spd: spd,
            Update: function()
                this.cel = this.cel + this.spd
                return this.cel < cels(this.img)
            endfunc,
            Draw: function()
                draw image this.img, this.x, this.y, int(this.cel)
            endfunc]
endfunc

' HitBrick
' --------
function HitBrick(x, y)
    cel = TM_GetCel(x, y)
    if cel >= 0
        cel = cel - 6
        if cel >= 0
            TM_SetCel(x, y, cel)
            AddAnim(vBrickHitImage, 8 + x*16, 8 + y*8, 0.25, 1 - int(cel/6))
            return 1
        else
            vBricksLeft = vBricksLeft - 1
            vScore = vScore + 5
            TM_SetCel(x, y, -1)
            pu = TM_GetFlag(x, y)
            if pu > 0  AddBonus(pu, x*16 + 8, y*8 + 4)
            vFlyingTexts.Add(5, 1, x*16 + 8, y*8 + 4, 0.5, 1)
            return 2
        endif
    else
        return 0
    endif
endfunc

' AddBonus
' --------
function AddBonus(type, x, y)
    select type
        case BIG_PADDLE  img = vBigPaddleBonusImage
        case SMALL_PADDLE  img = vSmallPaddleBonusImage
        case SPEED_UP  img = vSpeedUpBonusImage
        case SPEED_DOWN  img = vSpeedDownBonusImage
        case MULTIBALL  img = vMultiballBonusImage
        case CANNONS  img = vCannonsBonusImage
        default  img = unset
    endsel
    assert img, "AddBonus: Invalid type"
    vBonuses[sizeof(vBonuses)] = [
            type: type, img: img, x: x - 8, y: y - 4, spd: 1,
            X: function();  return this.x + 8;  endfunc,
            Y: function();  return this.y + 4;  endfunc,
            Update: function()
                this.y = this.y + this.spd
                return this.y < 240
            endfunc,
            Draw: function()
                draw image this.img, TM_ToScreenX(this.x), TM_ToScreenY(this.y)
            endfunc]
endfunc

' DrawPaddle
' ----------
function DrawPaddle(x, y, w, cannons)
    x = x - int(w/2)
    draw image vPaddleImage, x, y, 0
    draw image vPaddleImage, x + w - 8, y, 2
    set clip rect x + 8, 0, w - 16, height(primary)
    for i = 1 to int(w/8) - 1  draw image vPaddleImage, x + i*8, y, 1
    clear clip rect
    if cannons
        h = height(vCannonImage)
        draw image vCannonImage, x + 2, y - h
        draw image vCannonImage, x + w - 2 - width(vCannonImage), y - h
    endif
endfunc

' CreateAssets
' ------------
function CreateAssets()
    ' Brick images.
    brickBitmap = [
            [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
            [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3],
            [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3],
            [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3],
            [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3],
            [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3],
            [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3],
            [1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3],
            [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
            [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3],
            [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3],
            [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3],
            [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3],
            [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3],
            [1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3],
            [1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1],
            [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
            [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3],
            [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3],
            [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3],
            [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3],
            [1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3],
            [1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 3],
            [1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1]]
    vRedBrickImage = Create3ColorImage(brickBitmap, [vRedColor, vWhiteColor, vBlackColor])
    vGreenBrickImage = Create3ColorImage(brickBitmap, [vGreenColor, vWhiteColor, vBlackColor])
    vBlueBrickImage = Create3ColorImage(brickBitmap, [vBlueColor, vWhiteColor, vBlackColor])
    vYellowBrickImage = Create3ColorImage(brickBitmap, [vYellowColor, vWhiteColor, vBlackColor])
    vMagentaBrickImage = Create3ColorImage(brickBitmap, [vMagentaColor, vWhiteColor, vBlackColor])
    vCyanBrickImage = Create3ColorImage(brickBitmap, [vCyanColor, vWhiteColor, vBlackColor])
    set image grid vRedBrickImage, 1, 3
    set image grid vGreenBrickImage, 1, 3
    set image grid vBlueBrickImage, 1, 3
    set image grid vYellowBrickImage, 1, 3
    set image grid vMagentaBrickImage, 1, 3
    set image grid vCyanBrickImage, 1, 3
    vTilemapImage = createimage(16*6, 24)
    set image vTilemapImage
    set color 255, 255, 255
    draw image vRedBrickImage, 0, 0
    draw image vGreenBrickImage, 16, 0
    draw image vBlueBrickImage, 32, 0
    draw image vYellowBrickImage, 48, 0
    draw image vMagentaBrickImage, 64, 0
    draw image vCyanBrickImage, 80, 0
    set image primary
    set image grid vTilemapImage, 6, 3
    ' Brick hit anim.
    vBrickHitImage = Create3ColorImage([
            [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0],
            [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0],
            [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0],
            [1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [1, 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],
            [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0],
            [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0],
            [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [1, 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],
            [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0],
            [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [1, 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]],
            [vWhiteColor, unset, unset])
    set image grid vBrickHitImage, 1, 3
    ' Paddle.
    vPaddleImage = Create3ColorImage([
            [0, 0, 2, 2, 2, 2, 2, 3,  1, 1, 1, 1, 1, 1, 1, 1,  3, 2, 2, 2, 2, 2, 0, 0],
            [0, 2, 2, 2, 2, 2, 2, 1,  1, 1, 1, 1, 1, 1, 1, 1,  1, 2, 2, 2, 2, 2, 2, 0],
            [2, 2, 2, 2, 2, 2, 2, 1,  1, 1, 1, 1, 1, 1, 1, 1,  1, 2, 2, 2, 2, 2, 2, 2],
            [2, 2, 2, 2, 2, 2, 2, 1,  1, 1, 1, 1, 1, 1, 1, 1,  1, 2, 2, 2, 2, 2, 2, 2],
            [2, 2, 2, 2, 2, 2, 2, 1,  1, 1, 1, 1, 1, 1, 1, 1,  1, 2, 2, 2, 2, 2, 2, 2],
            [3, 2, 2, 2, 2, 2, 2, 3,  1, 1, 1, 1, 1, 1, 1, 1,  3, 2, 2, 2, 2, 2, 2, 3],
            [0, 3, 2, 2, 2, 2, 2, 3,  1, 1, 1, 1, 1, 1, 1, 1,  3, 2, 2, 2, 2, 2, 3, 0],
            [0, 0, 3, 3, 3, 3, 3, 3,  3, 3, 3, 3, 3, 3, 3, 3,  3, 3, 3, 3, 3, 3, 0, 0]],
            [vGrayColor, vRedColor, vBlackColor])
    set image grid vPaddleImage, 3, 1
    ' Cannon.
    vCannonImage = Create3ColorImage([
            [0, 0, 1, 1, 0, 0],
            [0, 0, 3, 3, 0, 0],
            [0, 0, 1, 1, 0, 0],
            [0, 0, 1, 1, 0, 0],
            [0, 0, 1, 1, 0, 0],
            [1, 1, 1, 1, 1, 1]],
            [vGrayColor, vWhiteColor, vBlackColor])
    ' Ball.
    vBallImage = Create3ColorImage([
            [0, 1, 1, 1, 1, 0],
            [1, 1, 2, 1, 1, 1],
            [1, 2, 2, 2, 1, 1],
            [1, 1, 2, 1, 1, 1],
            [1, 1, 1, 1, 1, 1],
            [0, 1, 1, 1, 1, 0]],
            [vGrayColor, vWhiteColor, vBlackColor])
    'Bullet.
    vBulletImage = Create3ColorImage([
            [0, 3, 3, 0],
            [3, 2, 2, 3],
            [3, 1, 1, 3],
            [3, 1, 1, 3],
            [0, 2, 2, 0],
            [0, 2, 2, 0],
            [0, 3, 3, 0]],
            [vWhiteColor, vYellowColor, vRedColor])
    ' Powerups.
    vBigPaddleBonusImage = Create3ColorImage([
            [0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0],
            [0, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 0],
            [1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1],
            [1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1],
            [1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1],
            [3, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 3],
            [0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 0],
            [0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0]],
            [vGreenColor, vWhiteColor, vBlackColor])
    vSmallPaddleBonusImage = Create3ColorImage([
            [0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0],
            [0, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 0],
            [1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1],
            [1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1],
            [1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1],
            [3, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 3],
            [0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 0],
            [0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0]],
            [vRedColor, vWhiteColor, vBlackColor])
    vSpeedUpBonusImage = Create3ColorImage([
            [0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0],
            [0, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 0],
            [1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1],
            [1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1],
            [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
            [3, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 3],
            [0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 0],
            [0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0]],
            [vMagentaColor, vWhiteColor, vBlackColor])
    vSpeedDownBonusImage = Create3ColorImage([
            [0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0],
            [0, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 0],
            [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
            [1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1],
            [1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1],
            [3, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 3],
            [0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 0],
            [0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0]],
            [vYellowColor, vWhiteColor, vBlackColor])
    vMultiballBonusImage = Create3ColorImage([
            [0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0],
            [0, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 0],
            [1, 1, 2, 2, 1, 1, 2, 2, 2, 2, 1, 1, 2, 2, 1, 1],
            [1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1],
            [1, 2, 2, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2, 2, 2, 1],
            [3, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 3],
            [0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 0],
            [0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0]],
            [vCyanColor, vWhiteColor, vBlackColor])
    vCannonsBonusImage = Create3ColorImage([
            [0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0],
            [0, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 0],
            [1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1],
            [1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1],
            [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
            [3, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 3],
            [0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 0],
            [0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0]],
            [vBlueColor, vWhiteColor, vBlackColor])
    ' Cool texts.
    vNaalaanoidTextImage = CreateCoolText("NAALAANOID", 3, vWhiteColor, vBlueColor)
    vGetReadyTextImage = CreateCoolText("GET READY!", 2, vWhiteColor, vDarkGreenColor)
    vGameOverTextImage = CreateCoolText("GAME OVER!", 2, vWhiteColor, vRedColor)
    ' Sound effects (stealing from the example breakout3d.n7).
    sfx = SFX()
    vPaddleSound = sfx.SineWave(0.15, [350], [0.5, 0])
    vBrickHitSound = sfx.SquareWave(0.1, [800], [0.15, 0, 0])
    vBrickDestroyedSound = sfx.SquareWave(0.15, [500], [0.5, 0, 0])
    vWallSound = sfx.Noise(0.15, [100, 1000], [0.25, 0])
    vLifeLostSound = sfx.Noise(0.54, [1000, 5000], [0.75, 0])
    vBonusSound = sfx.SineWave(0.25, [500, 1500], [0.5, 0])
    vShootSound = sfx.SineWave(0.15, [1000, 2000, 1000], [0.4, 0])
endfunc

' Create3ColorImage
' -----------------
function Create3ColorImage(data, colors)
    img = createimage(sizeof(data[0]), sizeof(data))
    set image img
    for y = 0 to sizeof(data) - 1  for x = 0 to sizeof(data[0]) - 1
        if data[y][x] > 0  set color colors[data[y][x] - 1]
        else  set color 0, 0, 0, 0
        set pixel x, y
    next
    set image primary
    return img
endfunc

' CreateCoolText
' --------------
function CreateCoolText(txt, size, borderColor, fillColor)
    w = fwidth(txt);  h = fheight()
    tmp = createimage(w, h)
    set image tmp
    set caret 0, 0;  set color 255, 255, 255;  write txt
    set image primary
    res = createimage(w*size + 2, h*size + 2)
    set image res
    set color 0, 0, 0, 0;  for y = 0 to height(res) - 1  for x = 0 to width(res) - 1  set pixel x, y
    for y = 0 to h - 1  for x = 0 to w - 1  if pixeli(tmp, x, y)%256
        t = pixeli(tmp, x, y - 1)%256;  b = pixeli(tmp, x, y + 1)%256
        l = pixeli(tmp, x - 1, y)%256;  r = pixeli(tmp, x + 1, y)%256
        set color fillColor;  draw rect x*size, y*size, size, size, true
        set color borderColor
        if not t  draw line x*size, y*size - 1, x*size + size - 1, y*size - 1
        if not b  draw line x*size, y*size + size, x*size + size - 1, y*size + size
        if not l  draw line x*size - 1, y*size, x*size - 1, y*size + size - 1
        if not r  draw line x*size + size, y*size, x*size + size, y*size + size - 1
    endif
    set image primary
    free image tmp
    return res
endfunc

' FlyingTexts
' -----------
' Encapsulate flying texts.
function FlyingTexts(maxTexts)
    ft = []
    ft.texts = fill(
        [txt: unset,
        fnt: unset,
        x: 0,
        y: 0,
        spd: 0],
        maxTexts)
   
    ft.empty = true
    ' Clear
    ' -----
    ft.Clear = function()
        foreach t in this.texts  t.txt = unset
    endfunc
   
    ' IsEmpty
    ' -------
    ft.IsEmpty = function()
        return .empty
    endfunc
   
    ' Add
    ' ---
    ft.Add = function(txt, fnt, x, y, spd, duration)
        foreach t in this.texts  if not t.txt
            t.txt = txt
            t.fnt = fnt
            t.x = x
            t.y = y - fheight(fnt)/2
            t.spd = spd
            t.t = 60*duration
            break
        endif
    endfunc
   
    ' Update
    ' ------
    ft.Update = function()
        .empty = true
        foreach t in this.texts  if t.txt
            .empty = false
            t.t = t.t - 1
            if t.t > 0
                t.y = t.y - t.spd
            else
                t.txt = unset
            endif
        endif
    endfunc
   
    ' Draw
    ' ----
    ft.Draw = function()
        foreach t in this.texts  if t.txt
            set font t.fnt
            set caret TM_ToScreenX(t.x), TM_ToScreenY(t.y)
            center t.txt
        endif
    endfunc
   
    return ft
endfunc



RE: Naalaanoid (another arkanoid clone) - johnno56 - 03-16-2025

Gotta love the classics!

Stage 1... Introduced to the "small paddle" and "speed up"... thank you very much... lol
Aw, man...Stages 4+... Most of those bricks are made of granite! Quite a workout... lol

Brilliant game!

J


RE: Naalaanoid (another arkanoid clone) - 1micha.elok - 03-17-2025

Another Arkanoid? I say, "Why not?"
As long as it’s chaos, I'm loving this plot
So bring on the bonuses, and more
I’ll keep on playing till my wrist is sore

A cannon appears—now that’s quite a twist
Blasting those bricks? Too hard to resist
I’m grinning, I’m cheering, what a great thrill,
With multiballs flying, you are king of the skill


RE: Naalaanoid (another arkanoid clone) - Marcus - 03-17-2025

(03-17-2025, 02:40 AM)1micha.elok Wrote: Another Arkanoid? I say, "Why not?"
As long as it’s chaos, I'm loving this plot
So bring on the bonuses, and more
I’ll keep on playing till my wrist is sore

A cannon appears—now that’s quite a twist
Blasting those bricks? Too hard to resist
I’m grinning, I’m cheering, what a great thrill,
With multiballs flying, you are king of the skill

“You're entirely bonkers. But I'll tell you a secret: All the best people are.” Smile


RE: Naalaanoid (another arkanoid clone) - johnno56 - 03-17-2025

Ouch! What about those of us that are just a 'little' bonkers? *sigh* lol


RE: Naalaanoid (another arkanoid clone) - 1micha.elok - 03-18-2025

(03-17-2025, 08:05 PM)johnno56 Wrote: Ouch! What about those of us that are just a 'little' bonkers? *sigh* lol

Oh, my friend, don’t hang your head,
Arkanoid's a game well-spread.
A little bonkers? That’s just fine,
Madness fuels the grand design.

The best weren’t born with perfect aim,
They bricked and missed but stayed in the game.
So laugh it off, give fate a wink,
Soon you'll break those walls—just think


RE: Naalaanoid (another arkanoid clone) - kevin - 03-18-2025

An excellent version Marcus. One of my favourite games, I remember also this was probably one of the first types of game that i tried to program (in basic) probably 40+ years ago. It ran soooo slow Smile


RE: Naalaanoid (another arkanoid clone) - Marcus - 03-21-2025

(03-18-2025, 03:27 PM)kevin Wrote: An excellent version Marcus. One of my favourite games, I remember also this was probably one of the first types of game that i tried to program (in basic) probably 40+ years ago. It ran soooo slow Smile

Same here! When I was young, I knew an older guy. He was my best friend's older brother's friend. I found out he was a programmer, and after failing in creating an arkanoid clone I simply knocked on his door and asked him if he could help me out. So we sat in his room an entire evening and made an arkanoid game, one of the best nights in my life Smile I believe I still have the game (written in AMOS) on a floppy disk somewhere!

I'll make an upgraded version of naalaanoid, with bettrr graphics, music and stuff.