Tetris Game Development - BlitzMax

Started by Prinzeritz, October 21, 2017, 04:13:26

Previous topic - Next topic

Prinzeritz

Hi,

I've been working on a tetris game & below is the code I've came up with, please I need some assistance to complete the program:


' DrawBrick.bmx
Const BRICK_SIZE_IN_PIXELS = 20
Const GAME_BOARD_ROWS = 20
Const GAME_BOARD_COLS = 10

Type TGameObject Abstract
Method Update() Abstract
Method Draw() Abstract
End Type

Type TVelocity
Function GetMoveDown:TVector2D()
Global gTVelocity_MoveDown:TVector2D
If gTVelocity_MoveDown = Null Then
gTVelocity_MoveDown = TVector2D.Create(0,1)
EndIf
Return gTVelocity_MoveDown
End Function

Function GetMoveLeft:TVector2D()
Global gTVelocity_MoveLeft:TVector2D
If gTVelocity_MoveLeft= Null Then
gTVelocity_MoveLeft= TVector2D.Create(-1,0)
EndIf
Return gTVelocity_MoveLeft
End Function

Function GetMoveRight:TVector2D()
Global gTVelocity_MoveRight:TVector2D
If gTVelocity_MoveRight= Null Then
gTVelocity_MoveRight= TVector2D.Create(1,0)
EndIf
Return gTVelocity_MoveRight
End Function
End Type

Type TBlockRow
Field _blockList:TBlockGraphics[]
Field _GraphPos:TVector2D
Field _RowID : Int

Function Create:TBlockRow(aGraphPos:TVector2D, aRowID:Int)
Local vResult:TBlockRow = New TBlockRow
vResult._GraphPos = aGraphPos
vResult._RowID = aRowID
Return vResult
End Function

Method New()
_blockList = New TBlockGraphics[GAME_BOARD_COLS]
End Method

Method SetRowID:TBlockRow(aRowID:Int)
_RowID = aRowID
Return Self
End Method

Method Get:TBlockGraphics(aCol:Int)
If _IsInRange(aCol) Then
Return _blockList[aCol]
EndIf
Return TBlockGraphics.GetNullBlock()
End Method

Method Set(aCol:Int, aBlock:TBlockGraphics)
If _IsInRange(aCol) Then
_blockList[aCol] = aBlock
EndIf
End Method

Method HasEmptySpaces()
For Local i = 0 Until Len(_blockList)
If _blockList[i] = Null Then
Return True
EndIf
Next
Return False
End Method

Method Draw()
Local vCentre:Int = BRICK_SIZE_IN_PIXELS Shr 1
Local vPosY:Int = _GraphPos.y + (BRICK_SIZE_IN_PIXELS * _RowID)+vCentre
Local vPosX:Int = _GraphPos.x + vCentre
For Local i = 0 Until Len(_blockList)
Local vBlock:TBlockGraphics = _blockList[i]
If vBlock <> Null Then
vBlock.Draw(vPosX + (i*BRICK_SIZE_IN_PIXELS),vPosY)
EndIf
Next
End Method

Function _IsInRange:Int(aCol:Int)
Return (0 <= aCol) And (aCol < GAME_BOARD_COLS)
End Function

End Type

Type TGame Extends TGameObject
Field _GameBoard:TGameBoard
Field _CurrentBrick:TBrickBase
Field _NextBrick:TBrickBase
Field EndGame:Int
Field _CurrentPos:TVector2D
Field _NextPos:TVector2D
Field _BoardGraphicPos:TVector2D

Method New()
_BoardGraphicPos = TVector2D.Create(200,20)
_GameBoard = TGameBoard.Create(_BoardGraphicPos)
_NextPos = TVector2D.Create(350,200)

TBrickBase.getBrick(0).getTwin().SetGraphPos(_NextPos).getTwin().SetGraphPos(_BoardGraphicPos)
TBrickBase.getBrick(1).getTwin().SetGraphPos(_NextPos).getTwin().SetGraphPos(_BoardGraphicPos)
TBrickBase.getBrick(2).getTwin().SetGraphPos(_NextPos).getTwin().SetGraphPos(_BoardGraphicPos)
TBrickBase.getBrick(3).getTwin().SetGraphPos(_NextPos).getTwin().SetGraphPos(_BoardGraphicPos)
TBrickBase.getBrick(4).getTwin().SetGraphPos(_NextPos).getTwin().SetGraphPos(_BoardGraphicPos)
TBrickBase.getBrick(5).getTwin().SetGraphPos(_NextPos).getTwin().SetGraphPos(_BoardGraphicPos)

_CurrentBrick = TBrickBase.getBrick()
_NextBrick    = TBrickBase.getBrick().getTwin()
End Method

Method ComputeNextBlock()
_CurrentBrick = _NextBrick.getTwin().ResetPos()
_NextBrick    = TBrickBase.getBrick().getTwin()
End Method

Method Update()
EndGame = Not _CurrentBrick.CanMove(TVector2D.Zero())
_GameBoard.Update()
_CurrentBrick.Update()
End Method

Method Draw()
_GameBoard.Draw()
_CurrentBrick.Draw()
_NextBrick.Draw()
End Method

Method GetGameBoard:TGameBoard()
Return _GameBoard
End Method

Function GetInstance:TGame()
Global TGame_instance:TGame
If TGame_instance = Null Then
TGame_instance = New TGame
EndIf
Return TGame_instance
End Function
End Type

Type TGameBoard Extends TGameObject
Field _GraphPos:TVector2D
Field _board:TBlockRow[]
Field _isUpdated

Method New ()
_board = New TBlockRow[GAME_BOARD_ROWS]
End Method

Function _IsInRange(aRow:Int)
Return (0 <= aRow ) And (aRow < GAME_BOARD_ROWS)
End Function

Method IsBlockEmpty:Int (aBlock:TVector2D)
Local vRow = aBlock.y
If _IsInRange(vRow) Return  (_board[vRow].Get(aBlock.x) = Null)
Return False
End Method

Method PlaceBlock(aBlock:TVector2D,aBlockGraphics:TBlockGraphics)
_board[aBlock.y].Set(aBlock.x, aBlockGraphics)
_isUpdated = True
End Method

Method Update()

Rem *********************** Todo ******************************
This method check if the board has been updated i.e. _isUpdated
flag is set to 1.

If _isUpdated = 0 then check each row and remove ones with no
spaces

Then collapse the the reset of the spaces

You may Use the following code options to implement this method
You may use some code more than once
You may also use your our code

A For Local vRowId = GAME_BOARD_ROWS-1 To 0 Step -1
B If _isUpdated Then
C End If
D aNewboard[vCursor] = vRow.SetRowID(vCursor)
E aNewboard[vRowId] = TBlockRow.Create(_GraphPos, vRowId)
F For Local vRowId = 0 To vCursor
G If Not _board[vRowId].HasEmptySpaces() Then
H Local aNewboard:TBlockRow[] = New TBlockRow[GAME_BOARD_ROWS]
I For Local vRowId = 0 Until GAME_BOARD_ROWS
J vCursor :- 1
K Local vCursor = GAME_BOARD_ROWS-1
L _board[vRowId] = Null
M If vRow <> Null Then
N Local vRow:TBlockRow = _board[vRowId]
O Next
P _board = aNewboard
Q If aNewboard[vRowId] = Null Then
R _isUpdated = False
'***********************************************************
End Rem

End Method

Method Draw()
Local vWidth:Int = GAME_BOARD_COLS * BRICK_SIZE_IN_PIXELS + 4
Local vHeight:Int = GAME_BOARD_ROWS * BRICK_SIZE_IN_PIXELS + 4
Local vPosX:Int = _GraphPos.x-2
Local vPosY:Int = _GraphPos.y-2

DrawLine vPosX , vPosY , vPosX + vWidth , vPosY
DrawLine vPosX , vPosY , vPosX , vPosY + vHeight
DrawLine vPosX , vPosY + vHeight, vPosX + vWidth , vPosY + vHeight
DrawLine vPosX + vWidth , vPosY + vHeight, vPosX + vWidth , vPosY

For Local vRow:TBlockRow = EachIn _board
vRow.Draw()
Next
End Method

Function Create:TGameBoard(aGrapPos:TVector2D)
Local vResult:TGameBoard = New TGameBoard
vResult._GraphPos = TVector2D.Create(aGrapPos.x,aGrapPos.y)
For Local i = 0 Until GAME_BOARD_ROWS
vResult._board[i] = TBlockRow.Create(vResult._GraphPos,i)
Next
Return vResult
EndFunction
End Type

Type TBlockGraphics
Field _colour:Int
Method Draw(aX:Int, aY:Int)
SetColor _colour & $FF, (_colour Shr 8) & $FF, (_colour Shr 16) & $FF
Local vX = aX - (BRICK_SIZE_IN_PIXELS Shr 1)
Local vY = aY - (BRICK_SIZE_IN_PIXELS Shr 1)
DrawRect vX,vY,BRICK_SIZE_IN_PIXELS,BRICK_SIZE_IN_PIXELS
SetColor 255,255,255
End Method

Function Create:TBlockGraphics(aColour:Int)
Local vResult:TBlockGraphics = New TBlockGraphics
vResult._colour = aColour
Return vResult
End Function

Function GetNullBlock:TBlockGraphics()
Global TBlockGraphics_NullBlock:TBlockGraphics
If TBlockGraphics_NullBlock = Null
TBlockGraphics_NullBlock = TBlockGraphics.Create(0)
EndIf
Return TBlockGraphics_NullBlock
End Function
End Type

Type TBrickBase Extends TGameObject
Field _Blocks:TVector2D[]
Field _IntervalBase:Int
Field _BlockGraphics:TBlockGraphics
Field _Position:TVector2D
Field _DefaultPos:TVector2D
Field _GraphicPos:TVector2D
Field _GraphTwin:TBrickBase
Field _isGraphType:Int

Method New()
Self._Blocks = New TVector2D[4]
Self._Position = TVector2D.Create(0,0)
Self._GraphicPos = TVector2D.Create(0,0)
End Method

Method ResetPos:TBrickBase()
_Position.CopyFrom(_DefaultPos)
Return Self
End Method

Function _GetGraphPosGap:TVector2D()
Global TVector2D_GetGraphPosGap:TVector2D
If TVector2D_GetGraphPosGap = Null Then
Local vLen = BRICK_SIZE_IN_PIXELS Shr 1
TVector2D_GetGraphPosGap = TVector2D.Create(vLen, vLen)
EndIf
Return TVector2D_GetGraphPosGap
End Function

Method Clone:TBrickBase()
Local vResult:TBrickBase = New TBrickBase
vResult._Blocks = New TVector2D[4]
vResult._Blocks[0]     = Self._Blocks[0].Clone()
vResult._Blocks[1]     = Self._Blocks[1].Clone()
vResult._Blocks[2]     = Self._Blocks[2].Clone()
vResult._Blocks[3]     = Self._Blocks[3].Clone()
vResult._Position      = Self._Position.Clone()
vResult._GraphicPos    = Self._GraphicPos.Clone()
vResult._BlockGraphics = Self._BlockGraphics
Return vResult
End Method

Method IsInterval(aInterval:Int)
'DebugStop
Local vTimer:TTimer = TClock.GetInstance()
Return vTimer.Ticks - _IntervalBase >= aInterval
End Method

Method ResetInterval()
_IntervalBase = TClock.GetInstance().Ticks
End Method

Method CanMove(aVelocity:TVector2D)
Local vNextBlock:TVector2D = New TVector2D
Local vGameBoard:TGameBoard = TGame.GetInstance().GetGameBoard()
For Local vBlock:TVector2D = EachIn Self._Blocks
vNextBlock.CopyFrom(vBlock).Add(_Position).Add(aVelocity)
If Not vGameBoard.IsBlockEmpty(vNextBlock) Return False
Next
Return True
End Method

Method PlaceToGameBoard()
Local vNextBlock:TVector2D = New TVector2D
Local vGameBoard:TGameBoard = TGame.GetInstance().GetGameBoard()
For Local vBlock:TVector2D = EachIn Self._Blocks
vNextBlock.CopyFrom(vBlock).Add(_Position)
vGameBoard.PlaceBlock(vNextBlock,_BlockGraphics)
Next
End Method

Method CanRotate(aMatrix:TMatrix2D)
Local vNextBlock:TVector2D = New TVector2D
Local vGameBoard:TGameBoard = TGame.GetInstance().GetGameBoard()
For Local vBlock:TVector2D = EachIn Self._Blocks
aMatrix.multiply(vNextBlock.CopyFrom(vBlock)).Add(_Position)
If Not vGameBoard.IsBlockEmpty(vNextBlock) Return False
Next
Return True
End Method

Method SetPosition:TBrickBase(aX:Int, aY:Int)
_Position.SetValue(aX,aY)
Return Self
End Method

Method Update()
Local vTurnAntiClockwise = KeyHit(KEY_Z)
Local vTurnClockwise     = KeyHit(KEY_X)
Local vMoveLeft          = KeyHit(KEY_LEFT)
Local vMoveRight         = KeyHit(KEY_RIGHT)
Local vMoveDown          = KeyDown(KEY_DOWN)

Local vMatrix:TMatrix2D
Local vVelocity:TVector2D

Rem *********************** Todo **************************
This Method respond To different key press For the bricks

You may Use the following code options To implement this Method
You may use some code more than once
You may also use your our code

A vMatrix.multiply(vBlock)
B ElseIf vMoveRight Then
C If vTurnAntiClockwise  Then
D vMatrix = TMatrix2D.GetRotateClockwise()
E If _isGraphType Return
F Return
G If IsInterval(300) Or (vMoveDown And IsInterval(50)) Then
H vVelocity = TVelocity.GetMoveRight()
I vMatrix = TMatrix2D.GetRotateAntiClockwise()
J Next
K If  vMoveLeft Then
L vVelocity = TVelocity.GetMoveDown()
M TGame.GetInstance().ComputeNextBlock()
N If Not CanMove(vVelocity) Then
O If vVelocity = Null Then
P PlaceToGameBoard()
Q EndIf
R vVelocity = TVelocity.GetMoveLeft()
S If (vVelocity <> Null) And CanMove(vVelocity) Then
T If vMatrix <> Null And CanRotate(vMatrix) Then
U ResetInterval
V For Local vBlock:TVector2D = EachIn Self._Blocks
W _Position.add(vVelocity)
X ElseIf vTurnClockwise Then

'*********************************************************
End Rem
End Method

Method Draw()
Local vGraphic:TVector2D = New TVector2D
Local vGraphPos:TVector2D = _Position.clone().ScalarMul(BRICK_SIZE_IN_PIXELS).Add(_GraphicPos).Add(_GetGraphPosGap())
For Local vBlock:TVector2D = EachIn Self._Blocks
vGraphic.CopyFrom(vBlock).ScalarMul(BRICK_SIZE_IN_PIXELS).Add(vGraphPos)
_BlockGraphics.Draw(vGraphic.x, vGraphic.y)
Next
End Method

Method SetPosition2:TBrickBase(aPosition:TVector2D)
_Position = aPosition
Return Self
End Method

Method SetGraphPos:TBrickBase(aPosition:TVector2D)
_GraphicPos = aPosition
Return Self
End Method

Method GetTwin:TBrickBase()
If _GraphTwin = Null Then
_GraphTwin = Self.clone()
_GraphTwin._isGraphType = True
_GraphTwin._GraphTwin = Self
EndIf
Return _GraphTwin
End Method

Function GetBrick:TBrickBase(aTypeId:Int = -1)
Global TBrickBase_InstanceList:TBrickBase[]
If TBrickBase_InstanceList = Null Then
TBrickBase_InstanceList = New TBrickBase[6]
Local vCenter = GAME_BOARD_COLS Shr 1

Local vObj:TBrickBase = New TBrickBase
vObj._BlockGraphics = TBlockGraphics.Create($FF4300)
vObj._Blocks[0] = TVector2D.Create(0,-1)
vObj._Blocks[1] = TVector2D.Create(0,0)
vObj._Blocks[2] = TVector2D.Create(1,0)
vObj._Blocks[3] = TVector2D.Create(1,1)
vObj._DefaultPos = TVector2D.Create(vCenter,1)
vObj.resetPos()
TBrickBase_InstanceList[0] = vObj

vObj = New TBrickBase
vObj._BlockGraphics = TBlockGraphics.Create($FF0000)
vObj._Blocks[0] = TVector2D.Create(0,-2)
vObj._Blocks[1] = TVector2D.Create(0,-1)
vObj._Blocks[2] = TVector2D.Create(0,0)
vObj._Blocks[3] = TVector2D.Create(1,0)
vObj._DefaultPos = TVector2D.Create(vCenter,2)
vObj.resetPos()
TBrickBase_InstanceList[1] = vObj

vObj = New TBrickBase
vObj._BlockGraphics = TBlockGraphics.Create($F0430F)
vObj._Blocks[0] = TVector2D.Create(0,0)
vObj._Blocks[1] = TVector2D.Create(-1,0)
vObj._Blocks[2] = TVector2D.Create(-1,1)
vObj._Blocks[3] = TVector2D.Create(0,1)
vObj._DefaultPos = TVector2D.Create(vCenter,0)
vObj.resetPos()
TBrickBase_InstanceList[2] = vObj

vObj = New TBrickBase
vObj._BlockGraphics = TBlockGraphics.Create($0F4FF0)
vObj._Blocks[0] = TVector2D.Create(0,0)
vObj._Blocks[1] = TVector2D.Create(0,-1)
vObj._Blocks[2] = TVector2D.Create(-1,0)
vObj._Blocks[3] = TVector2D.Create(1,0)
vObj._DefaultPos = TVector2D.Create(vCenter,1)
vObj.resetPos()
TBrickBase_InstanceList[3] = vObj

vObj = New TBrickBase
vObj._BlockGraphics = TBlockGraphics.Create($F00FF0)
vObj._Blocks[0] = TVector2D.Create(0,0)
vObj._Blocks[1] = TVector2D.Create(0,-1)
vObj._Blocks[2] = TVector2D.Create(-1,-1)
vObj._Blocks[3] = TVector2D.Create(1,0)
vObj._DefaultPos = TVector2D.Create(vCenter,1)
vObj.resetPos()
TBrickBase_InstanceList[4] = vObj

vObj = New TBrickBase
vObj._BlockGraphics = TBlockGraphics.Create($0F43A0)
vObj._Blocks[0] = TVector2D.Create(0,-1)
vObj._Blocks[1] = TVector2D.Create(0,0)
vObj._Blocks[2] = TVector2D.Create(0,1)
vObj._Blocks[3] = TVector2D.Create(-1,1)
vObj._DefaultPos = TVector2D.Create(vCenter,1)
vObj.resetPos()
TBrickBase_InstanceList[5] = vObj
EndIf

If aTypeId < 0 aTypeId = RndFloat() * Len(TBrickBase_InstanceList)
Return TBrickBase_InstanceList[Max(Min(aTypeId,5),0)]
End Function
End Type

Type TClock
Function GetInstance:TTimer()
Global gTClock_Timer:TTimer
If gTClock_Timer = Null Then
gTClock_Timer = CreateTimer(1000)
EndIf
Return gTClock_Timer
End Function
End Type

Type TVector2D
'Field x:Float, y:Float
Field x:Int, y:Int

Method Add:TVector2D(aVec:TVector2D)
Self.x = Self.x + aVec.x
Self.y = Self.y + aVec.y
Return Self
End Method

Method ScalarMul:TVector2D(aValue:Float)
Self.x = Self.x * aValue
Self.y = Self.y * aValue
Return Self
End Method

Method SetByPolarValue:TVector2D(aDegree:Int,aRadius:Int)
Self.x = Sin(aDegree) * aRadius
Self.y = Cos(aDegree) * aRadius
Return Self
End Method

Method SetValue:TVector2D(aX:Int,aY:Int)
Self.x = aX
Self.y = aY
Return Self
End Method

Method CopyFrom:TVector2D(aSrc:TVector2D)
Return SetValue(aSrc.x,aSrc.y)
End Method

Method Clone:TVector2D()
Return (New TVector2D).CopyFrom(Self)
End Method

Function Create:TVector2D(aX:Float,aY:Float)
Local vResult:TVector2D = New TVector2D
vResult.x = aX
vResult.y = aY
Return vResult
End Function

Function Zero:TVector2D()
Global TVector2D_Zero:TVector2D
If TVector2D_Zero = Null Then
TVector2D_Zero = (New TVector2D).SetValue(0,0)
End If
Return TVector2D_Zero
End Function
End Type

Type TMatrix2D
Field x1:Float, y1:Float, x2:Float, y2:Float
Method multiply:TVector2D(aVec:TVector2D)
Local vX:Float, vY:Float
vX = aVec.x*Self.x1 + aVec.y*Self.y1
vY = aVec.x*Self.x2 + aVec.y*Self.y2
aVec.x = vX
aVec.y = vY
Return aVec
End Method

Function GetNegateX:TMatrix2D()
Global gTMatrix2D_NegateX:TMatrix2D
If gTMatrix2D_NegateX = Null Then
gTMatrix2D_NegateX = New TMatrix2D
gTMatrix2D_NegateX.x1 = -1
gTMatrix2D_NegateX.y1 = 0
gTMatrix2D_NegateX.x2 = 0
gTMatrix2D_NegateX.y2 = 1
EndIf

Return gTMatrix2D_NegateX
End Function

Function GetNegateY:TMatrix2D()
Global gTMatrix2D_NegateY:TMatrix2D
If gTMatrix2D_NegateY = Null Then
gTMatrix2D_NegateY = New TMatrix2D
gTMatrix2D_NegateY.x1 = 1
gTMatrix2D_NegateY.y1 = 0
gTMatrix2D_NegateY.x2 = 0
gTMatrix2D_NegateY.y2 = -1
EndIf
Return gTMatrix2D_NegateY
End Function

Function GetRotateClockwise:TMatrix2D()
Global gTMatrix2D_RotateClockwise:TMatrix2D
If gTMatrix2D_RotateClockwise = Null Then
gTMatrix2D_RotateClockwise =  _CreateByRotation(-90)
EndIf
Return gTMatrix2D_RotateClockwise
End Function

Function GetRotateAntiClockwise:TMatrix2D()
Global gTMatrix2D_GetRotateAntiClockwise:TMatrix2D
If gTMatrix2D_GetRotateAntiClockwise = Null Then
gTMatrix2D_GetRotateAntiClockwise =  _CreateByRotation(90)
EndIf
Return gTMatrix2D_GetRotateAntiClockwise
End Function

Function _CreateByRotation:TMatrix2D(aDegree:Float)
Local vResult:TMatrix2D = New TMatrix2D
'DebugStop
vResult.x1 = Cos(aDegree)
vResult.y1 = -Sin(aDegree)
vResult.x2 = Sin(aDegree)
vResult.y2 = Cos(aDegree)
Return vResult
End Function
End Type

Graphics 640,480

Local vGame:TGame = TGame.GetInstance()

Repeat
Cls
vGame.draw()
vGame.Update()
Flip
Until KeyHit(KEY_ESCAPE) Or vGame.EndGame


It is a school project so I need assistance ASAP.
The requirements are to see the scores as well.

Many thanks.

Derron

Without having it run:

- minor: Update() first, then Draw() your board. With a "hang/freeze" you will end up drawing something which is no longer valid (eg block already disappeared then)
- What exactly do you want from us to help with?

When trying to get it run:
Code (blitzmax) Select

   Method IsInterval(aInterval:Int)
      'DebugStop
      Local vTimer:TTimer = TClock.GetInstance()
      Return vTimer.Ticks - _IntervalBase >= aInterval   
   End Method

Compile Error: Types 'Int()' and 'Int' are unrelated

-> "vTimer.Ticks" is a method, and it is a very very good idea to add brackets after it ... so "vTimer.Ticks()".

It is a good practice to add at least "Strict" at the very beginning of the file. It helps catching some errors.



Ok, so I was able to run it: it has shown a board with 2 bricks but no movement. Seems you did write the "update" function yet - and it seems there was something provided by your teacher?

I assume, _before_anyone_of_us_ is helping you (or trying to help you) with code: what was written by the teacher, and what by yourself? I mean, you seem to ask a basic thing but the code contains lines like this:
Code (blitzmax) Select

Local vCentre:Int = BRICK_SIZE_IN_PIXELS Shr 1

...

SetColor _colour & $FF, (_colour Shr & $FF, (_colour Shr 16) & $FF
Local vX = aX - (BRICK_SIZE_IN_PIXELS Shr 1)
Local vY = aY - (BRICK_SIZE_IN_PIXELS Shr 1)

This is nothing a beginner would write.

I ask this to avoid nearly doing all your homework :-)



@ update
The logic is already there  - but commented out.
Basic idea (of how I would tackle it) is:
- update brick
-- check input to see if we need a rotation
-- downwards motion for your brick:
--- check if brick can move, if not, place the block on the current grid/position
--- if it could move, move the block one current grid position

- check board for "full lines"
-- check from top to bottom
-- count lines "in a row" (so you know if you cleared "4 in a row"), (pro mode: handle sub-groups to emit multiple "2 in a row" the same time)
-- remove every line you marked, add score for the lines (see "sub groups" mode for combos / score-multipliers)
-- move bricks downward (to move down _now_ loose brick parts)
-- run check board for "full lines" again - until no line was cleared _and_ no brick was moved down

- create next block (controllable and moving down... your "player block")


bye
Ron

Steve Elliott

Quote
It is a school project so I need assistance ASAP.

If it's a school project then you should complete it yourself.  No wonder everybody gets an A these days lol.
Win11 64Gb 12th Gen Intel i9 12900K 3.2Ghz Nvidia RTX 3070Ti 8Gb
Win11 16Gb 12th Gen Intel i5 12450H 2Ghz Nvidia RTX 2050 8Gb
Win11  Pro 8Gb Celeron Intel UHD Graphics 600
Win10/Linux Mint 16Gb 4th Gen Intel i5 4570 3.2GHz, Nvidia GeForce GTX 1050 2Gb
macOS 32Gb Apple M2Max
pi5 8Gb
Spectrum Next 2Mb

Pingus

#3
Any school project made with bmax should be encouraged (it may not happens that often that a teacher work with our favorite tool).

That said, that kind of coding is really hard to read. Is it the way coding is teached nowaday ?

Huh ? :       TBrickBase.getBrick(0).getTwin().SetGraphPos(_NextPos).getTwin().SetGraphPos(_BoardGraphicPos)

I'm on the basic side, I never use more than one '.' in a line :) (ok, sometimes 2 but it is very rare).
I would suggest OP to restart from scratch with something more basic-like.