PB vs The World conversion to BlitzMax NG

Started by SToS, November 16, 2024, 16:27:26

Previous topic - Next topic

SToS

Here's another conversion/hack to BlitzMax NG.  Needs more work/tidying but it works.
See attachment for full source + data.

Version 2 (17-11-2024 05:30ish), cleanup and remove unused/superfluous variables/code.  Steer it towards more object orientated code. W.I.P....
SuperStrict

Rem
*****************************************************************************
*
* Birthday Punch : PureBasic 15 years of happiness
* PureBasic 5.31 x86
* 192 lines of 80 chars of code Or data as you want
*
* Name     : PB vs THE WORLD
* Author   : Ar-S - Music made with Music Maker Jam - thanks To Microdevweb For shoot linkedlist() helping
* date     : Nov/Oct 2015
* Notes    : Dedicated To my mom Apr 1940 - Sept 2015
*
* Use Arrows to move, space to shoot and left CTRL to use shield.
*
* Conversion to BlitMax NG by SToS/a.k.a Tantalus.
* First rough attempt with additional BlitzMax icon and ammendments/hacks.
* There's massive room for cleanup and improvement, not to mention OOP tarting.
*
* Thanks to original author and the "obfuscated/Macro" PureBASIC code.
End Rem

?win32
Framework SDL.d3d9sdlmax2d
?Not win32
Framework SDL.gl2sdlmax2d
?
Import SDL.SDLFreeAudio
Import BRL.PngLoader
Import BRL.OggLoader
Import BRL.FreeAudioAudio
Import BRL.FreeTypeFont
Import BRL.Random
Import BRL.StandardIO

SetAudioDriver("FreeAudio SDL")

Const t1:String = "PURE BASIC VS THE WORLD !"
Const t2:String = "HAPPY PURE BIRTHDAY"

Type TBullet
    Field x:Int
    Field y:Int
    Field id:Int
End Type

Type TSprite
    Field img:TImage
    Field x:Int
    Field y:Int
    Field w:Int
    Field h:Int
    Field n:Int
    Field ll:Int
    Field hh:Int
    Field v:Int
    Field r:Float
    Field angle:Float
    Field scalex:Float
    Field scaley:Float
End Type

Type TStar
    Field x:Int
    Field y:Int
    Field v:Int
    Field n:Int
End Type

Enum ShipForm:Int
    VULNERABLE, SHIELDED
End Enum
   
Type TPlayer
    Field x:Int
    Field y:Int
    Field ship:ShipForm
    Field shield:Int
    Field engine:Int
    Field life:Int
    Field score:Int
    Method New()
        Self.Reset()
    End Method
   
    Method Reset()
        x = 150
        y = 350
        life = 3
        score = 0
        ship = ShipForm.VULNERABLE
        shield = False
        engine = 11
    End Method
End Type

Global player:TPlayer = New TPlayer
Global bullet_list:TList = CreateList()
Global font1:TImageFont = LoadImageFont("Amelia-Normal.ttf", Rand(50, 80))
Global font2:TImageFont = LoadImageFont("Amelia-Normal.ttf", 24)

Global shoton:Int
Global rot:Float = 0.0
Global xi:Int = 2500
Global gameover:Int = False
Global ps:Int = True            ' Play music flag
Global txt:String = t1            ' Current scrolling text to display
Global xtx:Int = Rand(100, 500)        ' Scrolling text x position
Global ntxt:Int                ' Text choice counter

Global sprite:TSprite[] = New TSprite[16]
Global star:TStar[] = New TStar[100]
Global elapsed:Int = 0
Global sound20:TSound = LoadSound("01.ogg")
Global sound21:TSound = LoadSound("02.ogg")
Global sound22:TSound = LoadSound("03.ogg")
Global sound23:TSound = LoadSound("04.ogg")
Global sound23_channel:TChannel

Function RotateSprite(sprnum:Int, angle:Float)
    sprite[sprnum].angle = angle
End Function

SeedRnd(MilliSecs())

For Local i:Int = 0 To 99
    star[i] = New TStar
    star[i].x = Rand(0, 820)
    star[i].y = Rand(0, 600)
Next
For Local i:Int = 0 To 20
    star[i].n = 13
    star[i].v = 3
Next
For Local i:Int = 21 To 60
    star[i].n = 14
    star[i].v = 6
Next
For Local i:Int = 61 To 99
    star[i].n = 15
    star[i].v = 10
Next

Graphics 800, 600, 0

For Local i:Int = 0 To 15
    Local name:String = i + ".png"
    sprite[i] = New TSprite
    Print "Loading sprite #" + i + "..."
    sprite[i].img = LoadImage(name)
    Print name + " loaded."
    sprite[i].w = ImageWidth(sprite[i].img)
    sprite[i].h = ImageHeight(sprite[i].img)
    sprite[i].angle = 0.0
   
    sprite[i].ll = sprite[i].w / 2
    sprite[i].hh = sprite[i].h / 2
    sprite[i].scalex = (1.0 * sprite[i].ll) / sprite[i].w
    sprite[i].scaley = (1.0 * sprite[i].hh) / sprite[i].h
    sprite[i].v = Rand(2, 6)
   
    If i >= 2 And i <= 8 Then
        MidHandleImage(sprite[i].img)
    ElseIf i = 10
        sprite[10].x = 1500
        sprite[10].y = Rand(140, 460)
        sprite[i].scalex = 1.0
        sprite[i].scaley = 1.0
    EndIf
Next

SetAlpha(1)
SetBlend(SOLIDBLEND)

Repeat
    Local starttime:Int = MilliSecs()
    Cls

    If MilliSecs() - elapsed >= 350 Then
        shoton = True
        elapsed = MilliSecs()
    EndIf

    If Not gameover Then
        If ps Then
            sound23_channel = PlaySound(sound23)
            ps = Not ps
        EndIf
        For Local i:Int = 0 To 99
            Local j:Int = Rand(13, 15)
            SetScale(sprite[j].scalex, sprite[j].scaley)
            DrawImage(sprite[j].img, star[i].x, star[i].y)
            star[i].x :- star[i].v
            If star[i].x < 0 Then
                star[i].x = 805
                star[i].y = Rand(0, 600)
            EndIf
        Next

        SetScale(sprite[10].scalex, sprite[10].scaley)
        DrawImage(sprite[10].img, sprite[10].x, sprite[10].y)
       
        SetImageFont(font1)
        SetBlend(ALPHABLEND)
        If xi < -2500 Then
            ntxt :+ 1
            If ntxt < 2 Then
                txt = t1
            ElseIf ntxt = 2 Then
                txt = t2
            Else
                ntxt = 0
            EndIf
            xi = 2500
            xtx = Rand(100, 500)
        EndIf
        'SetScale(5.0, 5.0)
        SetColor(Rand(0, 255),Rand(0, 255),Rand(0, 255))
        DrawText(txt, xi, xtx)
        SetColor(255, 255, 255)
        xi :- 6
        sprite[1].x = sprite[0].x
        sprite[1].y = sprite[0].y
        For Local s:Int = 2 To 8
            SetScale(sprite[s].scalex, sprite[s].scaley)
            SetRotation(sprite[s].angle)
            DrawImage(sprite[s].img, sprite[s].x, sprite[s].y)
            SetRotation(0.0)
        Next
        If KeyDown(KEY_UP) Then
            player.y :- 5
            If KeyDown(KEY_LEFT) Then
                player.x :- 5
            ElseIf KeyDown(KEY_RIGHT) Then
                player.x :+ 5
            EndIf
        ElseIf KeyDown(KEY_DOWN) Then
            player.y :+ 5
            If KeyDown(KEY_LEFT) Then
                player.x :- 5
            ElseIf KeyDown(KEY_RIGHT) Then
                player.x :+ 5
            EndIf
        ElseIf KeyDown(KEY_LEFT) Then
            player.x :- 5
        ElseIf KeyDown(KEY_RIGHT) Then
            sprite[0].x = player.x
            player.x :+ 5
        EndIf
        If player.y < 25 Then
            player.y = 25
        ElseIf player.y > 530 Then
            player.y = 530
        EndIf
        If player.x < 0 Then
            player.x = 0
        ElseIf player.x > 700 Then
            player.x = 700
        EndIf

        sprite[0].x = player.x
        sprite[0].y = player.y
        sprite[11].x = player.x - 10
        sprite[11].y = player.y + 23
        sprite[12].x = sprite[11].x
        sprite[12].y = sprite[11].y

        If KeyDown(KEY_SPACE) And shoton
            Local bullet:TBullet = New TBullet
            bullet.x = sprite[1].x + 120
            bullet.y = sprite[1].y + 15
            bullet.id = 9
            ListAddLast(bullet_list, bullet)
            shoton = False
            PlaySound(sound20)
        EndIf
        If KeyDown(KEY_LCONTROL) Then
            player.shield = True
            PlaySound(sound22)
        Else
            player.shield = False
        EndIf
        If player.shield = False Then
            player.ship = ShipForm.VULNERABLE
        Else
            player.ship = ShipForm.SHIELDED
        EndIf
        SetScale(sprite[player.ship].scalex, sprite[player.ship].scaley)
        DrawImage(sprite[player.ship].img, player.x, player.y)
        player.engine = Rand(11, 12)
        SetScale(sprite[player.engine].scalex, sprite[player.engine].scaley)
        DrawImage(sprite[player.engine].img, sprite[player.engine].x, sprite[player.engine].y)
        For Local bullet:TBullet = EachIn bullet_list
            bullet.x :+ 6
            SetScale(sprite[bullet.id].scalex, sprite[bullet.id].scaley)
            DrawImage(sprite[bullet.id].img, bullet.x, bullet.y)
        Next    
        For Local enemy:Int = 2 To 8
            For Local bullet:TBullet = EachIn bullet_list
                If ImagesCollide(sprite[9].img,     bullet.x,        bullet.y,        0, ..
                                 sprite[enemy].img, sprite[enemy].x, sprite[enemy].y, 0) Then
                    player.score :+ 1
                    sprite[enemy].x = 820
                    sprite[enemy].y = Rand(100, 500)
                    sprite[enemy].v = Rand(2, 6)
                    If CountList(bullet_list) > 0 Then
                        ListRemove(bullet_list, bullet)
                    EndIf
                    PlaySound(sound21)
                EndIf
            Next
        Next
        For Local bullet:TBullet = EachIn bullet_list
            If CountList(bullet_list) > 0 And bullet.x > 810 Then
                ListRemove(bullet_list, bullet)
            EndIf
        Next
        For Local i:Int = 2 To 8
            sprite[i].x :- sprite[i].v
            RotateSprite(i, rot)
            rot :- 0.5
            If sprite[i].x < -100 Then
                sprite[i].x = 820
                sprite[i].y = Rand(100, 500)
                sprite[i].v = Rand(2, 6)
            EndIf
        Next
        For Local col:Int = 2 To 8
            If ImagesCollide(sprite[0].img,   sprite[0].x,   sprite[0].y,   0, ..
                             sprite[col].img, sprite[col].x, sprite[col].y, 0) Then
                If player.shield Then
                    player.score :- 1
                    If player.score <= 0
                        player.score = 0
                    EndIf
                Else 'player.shield = False
                    player.life :- 1
                    If player.life <= 0 Then
                        gameover = True
                    EndIf
                EndIf
                PlaySound(sound21)
                sprite[col].x = 820
                sprite[col].y = Rand(100, 500)
                sprite[col].v = Rand(2, 6)
            EndIf
        Next

        SetImageFont(font2)
        SetScale(1.0, 1.0)
        SetColor(255, 0, 0)
        DrawText("SCORE: " + player.score,  0, 0)
        DrawText("LIFE : " + player.life, 150, 0)
        SetColor(255, 255, 255)
        DrawText("ESCAPE to EXIT", 640, 0)
        sprite[10].x :- 1
        If sprite[10].x < -160 Then
            sprite[10].x = 1500
            sprite[10].y = Rand(140, 460)
        EndIf
    Else ' gameover True
        StopChannel(sound23_channel)
        ps = False
        SetImageFont(font1)
        Const tg:String = "GAME OVER"
        SetColor(255,255,255)
        DrawText(tg, Rand(398, 400) - TextWidth(TG) / 2, Rand(278, 280))
        SetImageFont(font2)
        DrawText("Press LMB to restart", Rand(248, 250), Rand(508, 510))
        DrawText("Score : " + player.score, Rand(288, 290), Rand(118, 120))
        If MouseDown(1) Then
            player.Reset()
            sprite[0].x = player.x
            ps = True
            gameover = False
        EndIf
    EndIf

    Flip
    Local deltatime:Float = (MilliSecs() - starttime) / 1000.0
Until KeyDown(KEY_ESCAPE)


source.zip
source_v2.zip 

Midimaster

Endless code lines like that:
sprite[1].ll = 234 / 2
sprite[1].hh = 139 / 2
ZoomSprite(1, 234 / 2, 139 / 2)
sprite[1].v = Rand(2, 6)

sprite[2].ll = 128 / 2
sprite[2].hh = 127 / 2
ZoomSprite(2, 128 / 2, 127 / 2)
sprite[2].v = Rand(2, 6)
.....

can you do this way:

Sprite[1].Set 234,139
Sprite[2].Set 128,127
...

Type TSprite
   ...
   Method Set(L:Int, H:Int)
      LL = L/2
      HH = H/2
      scalex = (1.0 * LL) / LL
      scaleY = (1.0 * HH) / HH
      v      = Rand(2,6)
   End Method
End Type
...back from North Pole.

SToS

Version 2 improvement added to root post.

Baggey

Quote from: SToS on November 17, 2024, 05:35:25Version 2 improvement added to root post.
Just freeze's on Executing game.exe here?
Running a PC that just Aint fast enough!? i7 4Ghz Quad core 32GB ram  2x1TB SSD and NVIDIA Quadro K1200 on Acer 24" . DID Technology stop! Or have we been assimulated!

Windows10, Parrot OS, Raspberry Pi Black Edition! , ZX Spectrum 48k, C64, Enterprise 128K, The SID chip. Im Misunderstood!

Midimaster

#4
To get to a more OOP I would still suggest to use Methods. This frees you to constantly use the complete name Sprite together with the field.

Example:
For Local i:Int = 0 To 15
    Local name:String = i + ".png"
    sprite[i] = New TSprite
    Print "Loading sprite #" + i + "..."
    sprite[i].img = LoadImage(name)
    Print name + " loaded."
    sprite[i].w = ImageWidth(sprite[i].img)
    sprite[i].h = ImageHeight(sprite[i].img)
    sprite[i].angle = 0.0
   
    sprite[i].ll = sprite[i].w / 2
    sprite[i].hh = sprite[i].h / 2
    sprite[i].scalex = (1.0 * sprite[i].ll) / sprite[i].w
    sprite[i].scaley = (1.0 * sprite[i].hh) / sprite[i].h
    sprite[i].v = Rand(2, 6)
   
    If i >= 2 And i <= 8 Then
        MidHandleImage(sprite[i].img)
    ElseIf i = 10
        sprite[10].x = 1500
        sprite[10].y = Rand(140, 460)
        sprite[i].scalex = 1.0
        sprite[i].scaley = 1.0
    EndIf
Next

shrinks to:

For Local i:Int = 0 To 15
    sprite[i] = New TSprite(i)
Next
sprite[10].x = 1500
...


Type TSprite
    Field img:TImage
    Field x:Int, y:Int, w:Int, h:Int, n:Int, ll:Int, hh:Int, v:Int
    Field r:Float, angle:Float, scalex:Float, scaley:Float

    Method New(ID:Int)
        Local Name:String = ID + ".png"
        Img     = LoadImage (Name)
        Print Name + " loaded."
        W       = ImageWidth(img)
        H       = ImageHeight(img)
        Angle   = 0.0
        ll      = W/2
        hh      = H/2
        ScaleX  = Float(ll) / w
        ScaleY  = Float(hh) / h
        V       = Rand(2, 6)
       
        If ID >= 2 And ID <= 8
            MidHandleImage(img)
        EndIf
    End Method
End Type

Now you only write the fields without the need of prefixes of the instance

Or here when you draw the Sprites:

Repeat
   ....
   For Local i:Int = 0 To 99
      Local j:Int = Rand(13, 15)
         SetScale(sprite[j].scalex, sprite[j].scaley)
         DrawImage(sprite[j].img, star[i].x, star[i].y)
        ...
  Next
  ....
  For Local s:Int = 2 To 8
      SetScale(sprite[s].scalex, sprite[s].scaley)
      SetRotation(sprite[s].angle)
      DrawImage(sprite[s].img, sprite[s].x, sprite[s].y)
      SetRotation(0.0)
  Next
  ...
  SetScale(sprite[player.ship].scalex, sprite[player.ship].scaley)
  DrawImage(sprite[player.ship].img, player.x, player.y)
  player.engine = Rand(11, 12)
  SetScale(sprite[player.engine].scalex, sprite[player.engine].scaley)
  DrawImage(sprite[player.engine].img, sprite[player.engine].x, sprite[player.engine].y)
  For Local bullet:TBullet = EachIn bullet_list
      bullet.x :+ 6
      SetScale(sprite[bullet.id].scalex, sprite[bullet.id].scaley)
      DrawImage(sprite[bullet.id].img, bullet.x, bullet.y)
  Next   

You could define a DRAW-Method, which bundles the drawing things:
Repeat
   ....
   For Local i:Int = 0 To 99
      Local j:Int = Rand(13, 15)
         Sprite[j].Draw   star[i].x, star[i].y
         ...
   Next
   ....
   For Local s:Int = 2 To 8
      Sprite[s].Draw
      SetRotation(0.0)
   Next
   ...
   Sprite[player.ship].Draw   player.x, player.y

   player.engine = Rand(11, 12)
   Sprite[player.engine].Draw

   For Local bullet:TBullet = EachIn bullet_list
      bullet.x :+ 6
      Sprite[bullet.id].Draw   bullet.x, bullet.y
   Next

Type TSprite
    ...
    Method New(ID:Int)
       ...
    End Method

    Method Draw(xx:Int=0, yy:Int=0)
       If xx=0 then xx=x
       If yy=0 then yy=y
       SetScale scalex, scaley
       SetRotation angle
       DrawImage img, xx, yy
       SetRotation 0.0
    End Method 
...back from North Pole.