It is currently Wed Oct 21, 2020 2:52 am

All times are UTC + 1 hour




Post new topic Reply to topic  [ 6 posts ] 
Author Message
 Post subject: (PB Demo safe) Yet another brickbreaker clone
PostPosted: Thu Aug 27, 2020 6:34 am 
Offline
Addict
Addict

Joined: Sat Jul 11, 2009 4:57 am
Posts: 943
Location: United States
I posted this in another thread some time ago with the intention of bringing it to this forum after fixing it up, but I never got around to that.
It has a fixed time step and a probably really poor use and abuse of CallFunctionFast for pseudo objects. And it should compile and run in the demo version of purebasic(because that's all I had)! I've been away from this beautiful language for some time now so I expect there to be many mistakes or errors that I haven't encountered yet.

Image
Code:
Enumeration 0
  #Ball
  #Brick0
  #RGB1
  #RGB2
  #RGB3
  #RGB4
  #Text1
  #Text2
  #Text3
  #Paddle1
  #Particle1
  #Sheet1
  #Paddle2
  #Paddle3
  #Pickup0; base image
  #Pickup1
  #Pickup2;
  #Pickup3;
  #Pickup4;
  #Pickup5;
  #Pickup6;
  #Pickup7;
  #Pickup8;
  #Pickup9;
  #Pickup10;
  #Font1
EndEnumeration
;-Object structure
Structure Object
  id.l ; set when added to object list
  type.l ;
  *parent;
  x.d;
  y.d;
  w.d; ; width/height
  h.d;
  dir.d[2] ; movement vector
  speed.l
  intangible.b ; used for skipping objects that don't need collision testing such as particles
  removed.b; removes from object list
  expires.l ; similar to removed.b but delayed!
  ; function pointers
  *fnConstructor ; unused, but could probably replace type
  *fnDestructor
  *fnRender
  *fnStep
  *extends  ; pointer to an object defining structure
EndStructure
Structure BrickObject
  hp.l
  gfx.b;
EndStructure
Structure PickupObject
  type.l
EndStructure
Structure PaddleObject
  size.l
  x2.d
EndStructure
Structure BallObject
  lastParticleCreation.l
EndStructure
Structure ParticleObject
EndStructure
Structure Vector
  x.d
  y.d
EndStructure
Structure Profile
  tps.l
  tpsc.l
  tpst.l
  count1.l
  count2.l
EndStructure
;-Game state structure
Structure State
  width.l ; window dimensions
  height.l
  dt.l
  now.l
  running.b
  active.b ;
  score.l
  balls.l
  bricks.l
  gameover.b;
  continues.l
  drawing.Profile
  logic.Profile
  uuidAccumulator.l ; used to create unique id's for objects
  *paddle.Object; used for
  Array objectsList.Object(1)
  Array objectsQueue.Object(1)
EndStructure

;-Object declarations
Declare Paddle(*state.State, *ref.Object, x.l, y.l) ; constructor
Declare paddleDestructor(*ref.Object)
Declare paddleDraw(*ref.Object, dt.l)
Declare paddleStep(*ref.Object, *state.State)

Declare Ball(*state.State, *ref.Object, x.l, y.l)
Declare ballDestructor(*ref.Object)
Declare ballDraw(*ref.Object, dt.l)
Declare ballParticleSpawner(*this.Object, *state.State, delay.l=100, reverseDir.b = 1)
Declare ballStep(*ref.Object, *state.State)

Declare Brick(*state.State, *ref.Object, x.l, y.l, hp.l)
Declare brickDestructor(*ref.Object)
Declare brickDraw(*ref.Object, dt.l)
Declare brickStep(*ref.Object, *state.State)
Declare brickParticleSpawner(*this.BallObject, *state.State, delay.l=100, reverseDir.b=1)

Declare Particle(*state.State, *ref.Object, *parent.Object, x.l, y.l, *direction.Vector, expires.l)
Declare particleDestructor(*ref.Object)
Declare particleDraw(*ref.Object, dt.l)
Declare particleStep(*ref.Object, *state.State)

Declare Pickup(*state.State, *ref.Object, x.l, y.l, type.l)
Declare pickupDestructor(*ref.Object)
Declare pickupDraw(*ref.Object, dt.l)
Declare pickupStep(*ref.Object, *state.State)

; boring things declarations
Declare intersect2d(*a.Object, *b.Object)
Declare addObject(*game.State, *ref);
Declare flush(*state.State)
Declare update(*state.State)
Declare render(*state.State)
Declare isOffScreen(*this.Object, *state.State)
;Declare

;-Particle definition
Procedure Pickup(*state.State, *ref.Object, x.l, y.l, type.l);, reverseDir.b = 1)
  *ptr.PickupObject = AllocateStructure(PickupObject)
  *ptr\type = #Pickup0 + type
  With *ref
    \extends = *ptr
    \parent = *parent
    \x = x
    \y = y
    \w = 32 ;
    \h = 32
    \expires = 0
    \dir[0] = 0.0
    \dir[1] = 1.0
    \speed = 3
    \fnRender = @pickupDraw()
    \fnStep = @pickupStep()
    \fnConstructor = @Pickup()
    \fnDestructor = @pickupDestructor()
    \intangible = 0
  EndWith
EndProcedure
Procedure pickupDestructor(*ref.Object)
  FreeStructure(*ref\extends)
EndProcedure
Procedure pickupApply(*state.State, *this.Object, type.l=-1)
  *self.PickupObject = *this\extends
  *thatObj.PaddleObject = *state\paddle\extends
  If (type.l = -1)
    type = *self\type
  EndIf
 
  Select type
    Case #Pickup1:
      *state\continues+1
    Case  #Pickup4:
      *thatObj\size + 1
    Case  #Pickup5:
      If (*thatObj\size > 1)
        *thatObj\size - 1
      EndIf
    Case  #Pickup7:
      Ball(*state, obj.Object, *this\x, *this\y)
      addObject(*state, obj);
    Case  #Pickup8:
      pickupApply(*state, *this, Random(9,0));
    Default: *state\score = *state\score / 0.25
  EndSelect
  ProcedureReturn 0
EndProcedure
   
Procedure pickupStep(*this.Object, *state.State);
  *self.PickupObject = *this\extends
  With *this
    \x = \x + (\dir[0] * \speed)
    \y = \y + (\dir[1] * \speed)
  EndWith
  If (isOffScreen(*this, *state))
    *this\removed = 1
  EndIf
    *that.Object = *state\paddle
    collision = intersect2d(*this, *that)
    If (*that\fnConstructor = @Paddle() And collision > 0 And *this\removed = 0)
      pickupApply(*state, *this)
      *this\removed = 1
      ballParticleSpawner(*this, *state, 10, 1)
    EndIf
EndProcedure
Procedure pickupDraw(*this.Object, dt.l)
  *self.PickupObject = *this\extends
  DisplayTransparentSprite(#Pickup0, *this\x, *this\y);
  DisplayTransparentSprite(*self\type, *this\x, *this\y);
EndProcedure
;-Paddle definition
Procedure Paddle(*state.State, *ref.Object, x.l, y.l)
  *ptr.PaddleObject = AllocateStructure(PaddleObject)
  *ptr\size = 5
  With *ref
    \extends = *ptr
    \x = x
    \y = y
    \removed = 0
    \w = 100
    \h = 16
    \fnRender = @paddleDraw()
    \fnStep = @paddleStep()
    \fnConstructor = @Paddle()
    \fnDestructor = @paddleDestructor()
  EndWith
EndProcedure
Procedure paddleDestructor(*ref.Object)
EndProcedure
Procedure paddleParticleSpawner(*this.Object, *state.State, side.b);
  For k = 1 To 2
    dir.Vector\y = 1.0 + ((-4 + Random(8, 0)) / 10);;
    dir\x = 0.0  + ((-4 + Random(8, 0)) / 10)
    pos.Vector\x = *this\x + 5
    pos\y = *this\y + *this\h;
    If (side = 1)
      pos\x = *this\x + *this\w - 10
    EndIf
    Particle(*state, particleObj.Object, *this, pos\x, pos\y, dir, *state\dt + Random(300, 100))
    addObject(*state, particleObj)
  Next
EndProcedure
Procedure paddleStep(*this.Object, *state.State);
  *state\paddle = *this
  *self.PaddleObject = *this\extends
  *this\x = MouseX()
  *this\w = 32 + (*self\size * 6 * 2)
  If (*this\x + *this\w > *state\width)
    *this\x = *state\width - *this\w
  EndIf
  paddleParticleSpawner(*this, *state, 0)
  paddleParticleSpawner(*this, *state, 1)
EndProcedure
Procedure paddleDraw(*this.Object, dt.l)
  *self.PaddleObject = *this\extends
  size = *self\size * 2
  DisplayTransparentSprite(#Paddle1, *this\x, *this\y)
  DisplayTransparentSprite(#Paddle3, *this\x + 17 + (6 * size), *this\y)
  For l = 1 To size
    DisplayTransparentSprite(#Paddle2, *this\x + 5 + ( 6 * l), *this\y + 1)
  Next
EndProcedure
;-Ball definition
Procedure Ball(*state.State, *ref.Object, x.l, y.l)
  *state\balls + 1;
  *ptr.BallObject = AllocateStructure(BallObject)
  *ptr\lastParticleCreation = 0
  With *ref
    \extends = *ptr
    \parent = *parent
    \x = x;width / 2
    \y = y;height - 50 ;
    \removed = 0        ;
    \speed = 10
    \w = 16 ;
    \h = 16
    \dir[0] = 0.0
    \dir[1] = -1.0
    \fnRender = @ballDraw()
    \fnStep = @ballStep()
    \fnConstructor = @Ball()
    \fnDestructor = @ballDestructor()
  EndWith
EndProcedure
Procedure ballDestructor(*ref.Object)
  FreeStructure(*ref\extends)
EndProcedure
Procedure ballParticleSpawner(*this.Object, *state.State, delay.l=100, reverseDir.b = 1)
  *self.BallObject = *this\extends
  If (*state\dt > *self\lastParticleCreation + delay)
    *self\lastParticleCreation = *state\dt
    For i = 0 To 10
      dir.Vector\x = -((-8 + Random(16, 0)) / 10)
      dir\y = -((-8 + Random(16, 0)) / 10)
      Particle(*state, particleObj.Object, *this, *this\x, *this\y, dir, *state\dt + Random(300, 50))
      addObject(*state, particleObj)
    Next
  EndIf
EndProcedure
Procedure ballStep(*this.Object, *state.State);
  *self.BallObject = *this\extends
 
  If (*state\active = 1)
    tmp.Object
    With tmp ; a copy of the object with future transforms applied to it
      \x = *this\x + (*this\dir[0] * *this\speed)
      \y = *this\y + (*this\dir[1] * *this\speed)
      \w = *this\w
      \h = *this\h
    EndWith
   
    For i = 0 To ArraySize(*state\objectsList()) - 1
      that.Object = *state\objectsList(i);
      ; todo: collision will fail if a balls speed is more than the width or height of an object it could collide with
      collision = intersect2d(tmp, that)
      If (*this\id <> that\id And that\intangible = 0 And collision > 0)
        If (that\fnConstructor = @Brick())
          *ptr.BrickObject = that\extends
          *ptr\hp = *ptr\hp - 1
         
          top.Object\x = that\x + 1
          top\y = that\y - that\h
          top\w = that\w - 2
          top\h = that\h + 5
          bot.Object\x = that\x + 1;
          bot\y = that\y + that\h - 5
          bot\w = that\w - 2
          bot\h = that\h
         
         
          left.Object\x = that\x - that\w
          left\y = that\y + 1
          left\w = that\w + 5
          left\h = that\h - 2
          right.Object\x = that\x + that\w - 5;
          right\y = that\y + 1
          right\w = that\w
          right\h = that\h - 2
          If (intersect2d(tmp, top) Or intersect2d(tmp, bot))
            *this\dir[1] = -(*this\dir[1])
          ElseIf (intersect2d(tmp, left) Or intersect2d(tmp, right))
            *this\dir[0] = -(*this\dir[0])
          Else
            *this\dir[0] = -(*this\dir[0])
            *this\dir[1] = -(*this\dir[1])
          EndIf
         
          *state\score + 1
          ballParticleSpawner(*this, *state, 10, 1)
        ElseIf (that\fnConstructor = @Paddle())
          rads = (((that\x - *this\x) + ((that\w - *this\w )/2) )) * #PI
          *this\dir[0] = -Sin(rads / 180)
          *this\dir[1] = -Cos(rads / 180)
          ballParticleSpawner(*this, *state, 10, 1)
        EndIf
      EndIf
    Next
   
    c2 = isOffScreen(tmp, *state)
    If (c2 = 4) ; bottom of the screen hit
      *this\removed = 1
      *state\balls - 1
    ElseIf (c2 = 3) ; top
      *this\dir[1] = -(*this\dir[1])
    ElseIf (c2 > 0)
      *this\dir[0] = -(*this\dir[0])
    EndIf
   
    If (c2 > 0)
      ballParticleSpawner(*this, *state, 10, 0)
    EndIf
   
    With *this
      \x = \x + (\dir[0] * \speed)
      \y = \y + (\dir[1] * \speed)
    EndWith
  Else
    With *this
      \x = *state\paddle\x + ((*state\paddle\w/2) - (\w/2))
      \y = *state\paddle\y - 20
    EndWith
  EndIf
EndProcedure
Procedure ballDraw(*this.Object, dt.l)
  DisplayTransparentSprite(#Ball, *this\x, *this\y);
EndProcedure
;-Particle definition
Procedure Particle(*state.State, *ref.Object, *parent.Object, x.l, y.l, *direction.Vector, expires.l);, reverseDir.b = 1)
  *ptr.ParticleObject = AllocateStructure(ParticleObject)
  s = Random(5, 1)
  With *ref
    \extends = *ptr
    \parent = *parent
    \x = x
    \y = y
    \w = s ;
    \h = s
    \expires = expires
    \dir[0] = *direction\x
    \dir[1] = *direction\y
    \speed = Random(10, 0);
    \fnRender = @particleDraw()
    \fnStep = @particleStep()
    \fnConstructor = @Particle()
    \fnDestructor = @particleDestructor()
    \intangible = 1
  EndWith
EndProcedure
Procedure particleDestructor(*ref.Object)
  FreeStructure(*ref\extends)
EndProcedure
Procedure particleStep(*this.Object, *state.State);
  *self.ParticleObject = *this\extends
  With *this
    \x = \x + (\dir[0] * \speed)
    \y = \y + (\dir[1] * \speed)
    \speed = \speed/2; - \speed
  EndWith   
EndProcedure
Procedure particleDraw(*this.Object, dt.l)
  ZoomSprite(#Particle1, *this\w, *this\h)
  DisplayTransparentSprite(#Particle1, *this\x, *this\y);
EndProcedure
;-Brick definition
Procedure Brick(*state.State, *ref.Object, x.l, y.l, hp.l)
  *state\bricks + 1
  *ptr.BrickObject = AllocateStructure(BrickObject)
  *ptr\hp = hp
  *ptr\gfx = Random(3, 0);
  With *ref
    \extends = *ptr
    \x = x
    \y = y
    \removed = 0;
    \w = 64;
    \h = 32;
    \fnRender = @brickDraw()
    \fnStep = @brickStep()
    \fnConstructor = @Brick()
    \fnDestructor = @brickDestructor()
  EndWith
EndProcedure
Procedure brickDestructor(*ref.Object)
  ;*self.BrickObject = *ref\extends
  ;FreeMemory(*self\ptrtest)
  FreeStructure(*ref\extends)
EndProcedure

Procedure brickStep(*this.Object, *state.State);
  *self.BrickObject = *this\extends
  If (*self\hp < 1 And *this\removed = 0)
    *this\removed = 1
    *state\bricks - 1
    Pickup(*state, obj.Object, *this\x, *this\y, Random(10, 1))
    addObject(*state, obj);
  EndIf
EndProcedure
Procedure brickDraw(*this.Object, dt.l)
  *self.BrickObject = *this\extends
  DisplayTransparentSprite(#Brick0, *this\x, *this\y);
  DisplayTransparentSprite(#RGB1 + (*self\gfx), *this\x, *this\y);
EndProcedure
Procedure update(*state.State)
  size = ArraySize(*state\objectsList());
  For k = 0 To size - 1
    If (*state\objectsList(k)\removed = 1)
      Continue
    EndIf
   
    *addr = *state\objectsList(k)\fnStep;
    CallFunctionFast(*addr, *state\objectsList(k), *state);
  Next
  If (*state\bricks = 0 And *state\gameover = 0)
    *state\gameover = 1
  EndIf
  If (*state\balls = 0 And *state\gameover = 0)
    If (*state\continues = 0)
      *state\gameover = 2
    Else
      *state\continues - 1
      *state\active = 0
      Ball(*state, obj.Object, 0, 0)
      addObject(*state, obj)
    EndIf
  EndIf
  If (*state\active = 0 And MouseButton(#PB_MouseButton_Left) = 1)
    *state\active = 1
  EndIf
EndProcedure
Procedure render(*state.State)
  ClearScreen(RGB(50, 100, 140));

  For k = 0 To ArraySize(*state\objectsList()) - 1
    item.Object = *state\objectsList(k)
    If (item\removed = 1)
      Continue
    EndIf
    *addr = *state\objectsList(k)\fnRender;
    CallFunctionFast(*addr, *state\objectsList(k), *state);
    ;StartDrawing(ScreenOutput()) ; show bounds
    ;Line(item\x, item\y, item\w, 1, #Red)
    ;Line(item\x, item\y+item\h, item\w, 1, #Red)
    ;Line(item\x, item\y, 1, item\h, #Red)
    ;Line(item\x+item\w, item\y, 1, item\h, #Red)
    ;Line(item\x, item\y, item\w, item\h, #Red)
    ;StopDrawing()
  Next

  DisplayTransparentSprite(#Text1, *state\width - 150, 10);
  DisplayTransparentSprite(#Text2, 10, 10)
  If (*state\gameover > 0 Or *state\active = 0)
    DisplayTransparentSprite(#Text3, *state\width/2 - 150, *state\height/2)
  EndIf
   
  FlipBuffers();
EndProcedure
Procedure addObject(*game.State, *ref)
  o = ArraySize(*game\objectsQueue());
  ReDim *game\objectsQueue.Object(o+1);
  CopyStructure(*ref, @dref.Object, Object)
  *game\objectsQueue(o) = dref;
EndProcedure
Procedure remakeHUDSprite(*state.State)
  If (IsSprite(#Text2))
    FreeSprite(#Text2)
  EndIf
 
  CreateSprite(#Text2, 200, 75);
  StartDrawing(SpriteOutput(#Text2))
  DrawingMode(#PB_2DDrawing_Transparent)
  DrawText(0, 0, "Score: " + Str(*state\score), RGB(1, 0, 0));
  DrawText(0, 20, "Continues: " + Str(*state\continues), RGB(1, 0, 0));
  StopDrawing()
EndProcedure
Procedure remakeGameOverSprite(*state.State, msg.s)
  If (IsSprite(#Text3))
    FreeSprite(#Text3)
  EndIf
  CreateSprite(#Text3, 300, 100);
  StartDrawing(SpriteOutput(#Text3))
  DrawingMode(#PB_2DDrawing_Transparent)
  DrawingFont(FontID(#Font1))
  DrawText(0, 0, msg, RGB(1, 0, 0));
  StopDrawing()
EndProcedure
Procedure remakeProfileSprite(*state.State)
  If (IsSprite(#Text1))
    FreeSprite(#Text1)
  EndIf
 
  CreateSprite(#Text1, 200, 120);
  StartDrawing(SpriteOutput(#Text1))

  DrawingMode(#PB_2DDrawing_Transparent)
  DrawText(0, 0, Str(*state\drawing\tps) + " - frames per sec", RGB(1, 0, 0));
  DrawText(0, 20, Str(*state\logic\tps) + " - steps per sec", RGB(1, 0, 0));
  DrawText(0, 40, Str(*state\logic\count1) + " - object count", RGB(1, 0, 0)) ;
  DrawText(0, 60, Str(*state\logic\count2) + " - queue count", RGB(1, 0, 0))
  DrawText(0, 80, Str(*state\balls) + " - balls", RGB(1, 0, 0))
  DrawText(0, 100, Str(*state\bricks) + " - bricks", RGB(1, 0, 0))  ;
  StopDrawing()
EndProcedure
Procedure init(*state.State)
  LoadFont(#Font1, "Arial", 32, #PB_Font_Bold)
  remakeProfileSprite(*state);
  remakeHUDSprite(*state)
  remakeGameOverSprite(*state, "Click to Start!")
  LoadSprite(#Sheet1, "E:/assets/brickbreaker.png", #PB_Sprite_AlphaBlending);
 
  CopySprite(#Sheet1, #Paddle1, #PB_Sprite_AlphaBlending) ; left
  ClipSprite(#Paddle1, 0, 0, 16, 16)
  CopySprite(#Sheet1, #Paddle2, #PB_Sprite_AlphaBlending) ; blue thing
  ClipSprite(#Paddle2, 16, 0, 16, 16)
  CopySprite(#Sheet1, #Paddle3, #PB_Sprite_AlphaBlending) ; right
  ClipSprite(#Paddle3, 32, 0, 16, 16)
 
  CopySprite(#Sheet1, #Ball, #PB_Sprite_AlphaBlending)
  ClipSprite(#Ball, 16 * 3, 0, 16, 16)
 
  CopySprite(#Sheet1, #Brick0, #PB_Sprite_AlphaBlending)
  ClipSprite(#Brick0, 0, 64, 64, 32)

  CreateSprite(#Particle1, 25, 25);
  StartDrawing(SpriteOutput(#Particle1))
  Box(0, 0, 20, 20, RGB(0, 0, 0))       ;
  DrawingMode(#PB_2DDrawing_Default)
  Box(0, 0, 50, 25, RGB(255, 255, 255));
  StopDrawing()
 
  For k = 0 To 3
    CreateSprite(#RGB1 + k, 64, 32, #PB_Sprite_AlphaBlending);
    StartDrawing(SpriteOutput(#RGB1 + k))
    DrawingMode(#PB_2DDrawing_AlphaChannel)
    Box(0, 0, 64, 32, $00000000)
    DrawingMode(#PB_2DDrawing_AlphaBlend)
    Box(0, 0, 64, 32, RGBA(Random(255, 0), Random(255, 0), Random(255, 0), 100))
    DrawingMode(#PB_2DDrawing_AlphaChannel)
    Box(0, 0, 2, 2, $00000000)
    Box(62, 0, 2, 2, $00000000)
    Box(0, 30, 2, 2, $00000000)
    Box(62, 30, 2, 2, $00000000)
    StopDrawing()
  Next
 
  CopySprite(#Sheet1, #Pickup0, #PB_Sprite_AlphaBlending)
  ClipSprite(#Pickup0, 64, 0, 16, 16)
  ZoomSprite(#Pickup0, 32, 32)
  For k = 0 To 10
    CopySprite(#Sheet1, #Pickup1 + k, #PB_Sprite_AlphaBlending)
    ClipSprite(#Pickup1 + k, (16 * k), 16, 16, 16)
    ZoomSprite(#Pickup1 + k, 32, 32)
  Next
   
  Paddle(*state, paddleObj.Object, *state\width / 2 - 50, *state\height - 100)
  addObject(*state, paddleObj)
 
  Ball(*state, ballObj.Object, 0, 0)
  addObject(*state, ballObj)
 
  For x = 0 To 59;99
    tx = 50 + ((x % 10) * 70)
    ty = 100 + ((x / 10) * 50)
    Brick(*state, brickObj.Object, tx, ty, 1+(ty%3))
    addObject(*state, brickObj)
  Next
EndProcedure
Procedure isOffScreen(*this.Object, *state.State)
  If (*this\x < 0) : ProcedureReturn 1 ; left
  ElseIf (*this\x + *this\w > *state\width) : ProcedureReturn 2 ; right
  ElseIf (*this\y < 0) : ProcedureReturn 3 ; top
  ElseIf (*this\y + *this\h > *state\height) : ProcedureReturn 4 : EndIf ; bottom
  ProcedureReturn 0
EndProcedure
Procedure intersect2d(*o.Object, *b.Object)
  ax.d = *o\x
  ay.d = *o\y
  au.d = *o\x + *o\w
  av.d = *o\y + *o\h
   
  bx.d = *b\x
  by.d = *b\y
  bu.d = *b\x + *b\w
  bv.d = *b\y + *b\h
 
  If (ax <= bu And au >= bx And ay <= bv And av >= by)
    ProcedureReturn 1
  EndIf
  ProcedureReturn 0
EndProcedure
Procedure flush(*state.State)
  size = ArraySize(*state\objectsList())
  For i = 0 To size - 1 ; clean up objects that were marked for removal
    If (*state\objectsList(i)\removed = 1 Or (*state\objectsList(i)\expires > 0 And *state\dt > *state\objectsList(i)\expires))
      *addr = *state\objectsList(i)\fnDestructor;
      CallFunctionFast(*addr, *state\objectsList(i));
      ; i dont know how to properly resize arrays in purebasic so hopefully this won't be too slow :(
      *state\objectsList(i) = *state\objectsList(size - 1) ; swap removing object with one at end
      ReDim *state\objectsList.Object(size - 1)
      size = size -1; have to modify loop or bad things will happen
      i = i - 1; the object that was swapped must also be checked for removal
    EndIf
  Next

  n = ArraySize(*state\objectsQueue());
  If (n > 0) ; merge queued objects into the object list
    o = ArraySize(*state\objectsList());
    If (o >= 1000) ; this is just an arbitrary size limit for the number of objects to allow
      ReDim *state\objectsQueue(0);
      ProcedureReturn
    EndIf

    ReDim *state\objectsList(o+n);
    For k = 0 To n ; the merge part
      *state\uuidAccumulator = *state\uuidAccumulator + 1
      *state\objectsList(o+k) = *state\objectsQueue(k);
      *state\objectsList(o+k)\id = *state\uuidAccumulator
      If (*state\objectsList(o+k)\fnConstructor = @Paddle())
        *state\paddle = *state\objectsList(o+k)
      EndIf
    Next
    ReDim *state\objectsQueue(0)
  EndIf
EndProcedure

With game.State
  \width = 800
  \height = 800
  \running = 1
  \score = 0
  \continues = 1
  \now = ElapsedMilliseconds()
  \dt = ElapsedMilliseconds();
  Dim \objectsQueue.Object(0)
  Dim \objectsList.Object(0)
EndWith

InitSprite()
InitMouse()
UsePNGImageDecoder()

OpenWindow(0, 0, 0, game\width, game\height, "Nostalgia", #PB_Window_ScreenCentered | #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget);
OpenWindowedScreen(WindowID(0), 0, 0, game\width, game\height, #False, #Null, #Null, #PB_Screen_NoSynchronization );

init(game)
;-Loop
While game\running = 1
  Select WindowEvent()
    Case #PB_Event_CloseWindow
      game\running = 0
  EndSelect

  ExamineMouse()

  If (game\dt > game\drawing\tpst + 1000)
    game\drawing\tps = game\drawing\tpsc;
    game\drawing\tpsc = 0  ;
    game\logic\tps = game\drawing\tpsc;
    game\logic\tpsc = 0  ;
    game\drawing\tpst = game\dt ;
    game\logic\count1 = ArraySize(game\objectsList())
    game\logic\count2 = ArraySize(game\objectsQueue())
    remakeProfileSprite(game);
  EndIf
 
  flush(game)
 
  game\now = ElapsedMilliseconds();
  If (game\now - game\dt > 1000) ; skip some logic steps because previous one took too long
    game\dt = game\now;
  EndIf
 
  CopyStructure(@game, @prev.State, State) ; a copy of state to compare with after updating
  While game\dt < game\now ; step game objects at a constant rate
    game\dt = game\dt + 1000/30;
    update(game);
    game\logic\tpsc=game\logic\tpsc+1;
  Wend
 
  If (prev\score <> game\score Or prev\continues <> game\continues)
    remakeHUDSprite(game)
  EndIf
  If (prev\gameover <> game\gameover Or prev\active <> game\active)
    msg.s = "Click to start!"
    If (game\gameover = 2)
      msg.s = "Game over!!"
    ElseIf (game\gameover = 1)
      msg.s = "You win!"
    EndIf
    remakeGameOverSprite(game, msg)
  EndIf
   
  render(game)
  game\drawing\tpsc=game\drawing\tpsc+1;
Wend

_________________
▓▓▓▓▓▒▒▒▒▒░░░░░


Top
 Profile  
Reply with quote  
 Post subject: Re: (PB Demo safe) Yet another brickbreaker clone
PostPosted: Thu Aug 27, 2020 6:47 am 
Offline
Enthusiast
Enthusiast

Joined: Wed Mar 11, 2009 4:06 pm
Posts: 322
Location: NL
A little object support through extending the structure type by PB (a bit like GameMaker's GML did recently) would make this code much easier to look at ;)
Wishful thinking. Couldn't help it.


Top
 Profile  
Reply with quote  
 Post subject: Re: (PB Demo safe) Yet another brickbreaker clone
PostPosted: Thu Aug 27, 2020 4:32 pm 
Offline
Addict
Addict

Joined: Sat Jul 11, 2009 4:57 am
Posts: 943
Location: United States
I have no idea what any of that means but I saw mention of objects.. Tell me the secrets!

_________________
▓▓▓▓▓▒▒▒▒▒░░░░░


Top
 Profile  
Reply with quote  
 Post subject: Re: (PB Demo safe) Yet another brickbreaker clone
PostPosted: Fri Aug 28, 2020 2:03 am 
Offline
Enthusiast
Enthusiast

Joined: Wed Mar 11, 2009 4:06 pm
Posts: 322
Location: NL
Dont get excited, its missing from PB and missed by a lot of users.

Im talking about adding the minimum language syntax to support function pointers in structures and a self reference and while were at it default values (which it already has, but not customizable in any way). A basic way of (optional) encapsulation of data and behavior and hiding of complexity and keeping things together. Object inspired programming in PB always ends in a mess because only half of essentials were added while it would be easy to fix by just implementing the final few missing pieces. It would also be a better replacement of the current modules if anything.

GLBasic has it: http://www.glbasic.com/forum/index.php?topic=8579.0
GML 2.3 has it after demands for ways to create better structured/organized code: https://www.yoyogames.com/blog/549/game ... l-features (Structs) . GML is not even afraid of making breaking changes when needed.
Blitzmax all the way tutorial: https://blitzmax.org/docs/en/tutorials/oop_tutorial/


Top
 Profile  
Reply with quote  
 Post subject: Re: (PB Demo safe) Yet another brickbreaker clone
PostPosted: Fri Aug 28, 2020 11:32 pm 
Offline
Addict
Addict

Joined: Sat Jun 30, 2007 8:04 pm
Posts: 3371
This was really fun. I love breakout-like games!

Thanks for sharing. :)


Top
 Profile  
Reply with quote  
 Post subject: Re: (PB Demo safe) Yet another brickbreaker clone
PostPosted: Sat Aug 29, 2020 12:36 am 
Offline
User
User

Joined: Sat Sep 21, 2019 4:24 pm
Posts: 28
Rinzwind wrote:
Dont get excited, its missing from PB and missed by a lot of users.

Im talking about adding the minimum language syntax to support function pointers in structures...

It is possible to have function pointers inside structures:
Code:
Prototype UpdateSpriteProc(Elapsed.f, *Sprite) : Prototype DrawSpriteProc(SpriteType.a, Width.a, Height.a, ZoomLevel.f, x.f, y.f, Transparency.a, *Sprite = #Null)
Structure TSprite
  x.f : y.f : LastX.f : LastY.f : Width.a : Height.a : Lives.b : XVelocity.f : YVelocity.f : SpriteType.a
  ZoomLevel.f : Mass.f : Transparency.a : Map References.i() : UpdateSprite.UpdateSpriteProc : DrawSprite.DrawSpriteProc
  Timer1.f : Timer2.f : State1.a : State2.a : Deleted.a
EndStructure


In the example above is possible to assign UpdateSprite and DrawSprite to different procedures that have the same signature as the prototypes but different behaviors.

_________________
You can check my games at:
https://ricardo-sdl.itch.io/


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 6 posts ] 

All times are UTC + 1 hour


Who is online

Users browsing this forum: No registered users and 15 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
Jump to:  

 


Powered by phpBB © 2008 phpBB Group
subSilver+ theme by Canver Software, sponsor Sanal Modifiye