Making a grid and reading through it

BlitzMax Forums/BlitzMax Beginners Area/Making a grid and reading through it

Apollonius(Posted 2007) [#1]
I'm trying to make a simple thing yet I'm getting error

4x4 Grid into an Array so basicly UCell[4,4]
		For Local i:Int = 0 To VCell
			For Local i2:Int = 0 To HCell
				If UCell[i,i2]=1 Then
					DrawRect XCell, YCell, Cell_Size, Cell_Size
				EndIf
			Next
		Next


I'm trying to go through all of them and only draw a rectangle for those with a value of 1 all the other must have a value of 0 by default...


Perturbatio(Posted 2007) [#2]
At work, so no BMax, but try



Who was John Galt?(Posted 2007) [#3]
I can't see anything wrong with that piece of code at all.


Apollonius(Posted 2007) [#4]
Basicly, I'm trying to make a modified version of tetris as a practice to improve my sloppy programming skills. But I'm trying to figure out the basic logic and I came up with GRIDS.

This is a code to test my Block Type which would be all the blocks in the game. It's a prototype...



EDITED

So basicly
4x4
[0][0][0][0]
[0][0][0][0]
[0][0][0][0]
[0][0][0][0]

0 doesn draw
1 draws on of the figure's cube

So let's say an L
[0][0][0][1]
[1][1][1][1]
[0][0][0][0]
[0][0][0][0]


Czar Flavius(Posted 2007) [#5]
I am making a Tetris game and found it to be more difficult than you might think.

Perturbatio's code shoud fix the error. You haven't specified what it is but I guess it is array index out of bounds. If you make an array of size 4, then the indexes are [0] [1] [2] and [3]. [4] is not a valid index. Yet in your for loop i/i2 goes 0, 1, 2, 3 and 4. Either put VCell-1 or use for local i:int = 0 until VCell, which goes up to but not including VCell and the same changes for HCell. (Personally I'd use x and y rather than i and i2 but it makes no difference).

Though it can be done with arrays, it is actually easier for each "block" or "shape" to have a list of 4 points/coordinates rather than a 4x4 array. If you make a TPoint type with int fields x and y, and give each shape an array of 4 TPoints. The T shape for instance would be (-1, 0) (0, 0) (1, 0) (0, 1), with (0, 0) being the centre square. Implemented as points[i].x = -1; points[i].y = 0; etc

The list of points methods makes rotating easier and you might want to investigate it. But it is possible using arrays.

Last night I was playing a simple game on my phone similar to tetris which you might find easier to implement. It will give you the chance to sort out program design and finishing a game but avoid some of the more complex problems with a tetris game. (Sorry if I am insulting your intelligence, but I am currently making a tetris game and finding it difficult and I would consider myself an Intermediate, or at least above beginner, programmer).

The game is called QuadraPop and you can see a screenshot here

If you are interested I can describe the game for you.


Jesse(Posted 2007) [#6]
Apollonius, either do what Perturbatio said or change "to" to "until"


Amon(Posted 2007) [#7]
Hi Apollonios. I just did a quick test to see if I could help out. I came up with this.

SuperStrict

Graphics 260, 500

Global LeftLArrWidth:Int = 3
Global leftLArrHeight:Int = 3

Global LeftLXOff:Int = 120
Global LeftLYOff:Int = 0

Global LXTemp:Int[4], LYTEmp:Int[4]

Global CreateLeftL:Int = 0
Global LeftLCreated:Int = 0

Global loopCount:Int = 0

Global LeftLTimer:Int = MilliSecs() 
Global CHeckAheadTImer:Int = MilliSecs() 

Global TimerSpeed:Int = 600

Global ReadDefData:Int = 0
Global RotL:Int = 0
Global RotCount:Int = 0

Global CanMoveLeft:Int = 1
Global CanMoveRight:Int = 1
Global LLCanRotate:Int = 1


Global ArrData:Int[20]

Global LeftL:Int[LeftLArrWidth, LeftLArrHeight]


Const GAMEARRAYWIDTH:Int = 13
Const GAMEARRAYHEIGHT:Int = 25

Global GameArray:Int[GAMEARRAYWIDTH, GAMEARRAYHEIGHT]

While not KeyHit(KEY_ESCAPE) 
	Cls
		DrawLine 0, 60, 260, 60
		
		CheckAhead() 
		
		For Local x:Int = 0 Until GAMEARRAYWIDTH
			For Local Y:Int = 0 Until GAMEARRAYHEIGHT
				If GameArray[x, y]= 1
					DrawRect x * 20, y * 20, 20, 20
					Else
					
				End If
			Next
		Next
		
		
		If LeftLCreated = 1
			If MilliSecs() > LeftLTimer + TimerSpeed
				LeftLYOff:+20
			'	If MilliSecs() > CHeckAheadTImer + 500
					 
				LeftLTimer = MilliSecs() 
			'	EndIf
			End If
			
			If KeyHit(KEY_EQUALS) 
				TimerSpeed:-200
			EndIf
			
			If KeyHit(KEY_MINUS) 
				TimerSpeed:+200
			End If
		End If
		
		
		If LeftLCreated = 1
			For Local x:Int = 0 Until 3
				For Local y:Int = 0 Until 3
					If LeftL[x, y]= 1
					
						DrawRect LeftLXOff + x * 20, LeftLYOff + Y * 20, 20, 20
							Select loopCount
								Case 0
									LXTemp[0]= LeftLXOff + x * 20
									LYTEmp[0]= LeftLYOff + Y * 20
								Case 1
									LXTemp[1]= LeftLXOff + x * 20
									LYTEmp[1]= LeftLYOff + Y * 20
								Case 2
									LXTemp[2]= LeftLXOff + x * 20
									LYTEmp[2]= LeftLYOff + Y * 20
								Case 3
									LXTemp[3]= LeftLXOff + x * 20
									LYTEmp[3]= LeftLYOff + Y * 20
							End Select
							loopCount:+1
					End If
					If loopCount > 3 Then loopCount = 0
				Next
			Next
		EndIf
		
		If KeyHit(KEY_SPACE) and LeftLCreated = 0
			RestoreData LeftL1
			For Local y:Int = 0 Until 3
				For Local x:Int = 0 Until 3
					ReadData ArrData[0]
					LeftL[x, y]= ArrData[0]
				Next
			Next
			LeftLCreated = 1
		End If
		
		If LeftLCReated = 1
			MoveRotate() 
		EndIf
		
		Local tx1:Int, tx2:Int, tx3:Int, tx4:Int
		Local ty1:Int, ty2:Int, ty3:Int, ty4:Int
		
		DrawText "tx1= " + LXTemp[0], 0, 0
		DrawText "ty1= " + LYTEmp[0], 80, 0
		DrawText "tx2= " + LXTemp[1], 0, 15
		DrawText "ty2= " + LYTEmp[1], 80, 15
		DrawText "tx3= " + LXTemp[2], 0, 25
		DrawText "ty3= " + LYTEmp[2], 80, 25
		DrawText "tx4= " + LXTemp[3], 0, 35
		DrawText "ty4= " + LYTEmp[3], 80, 35
		DrawText "LoopCount= " + loopCount, 0, 45
		DrawText "LeftlCReated= " + LeftLCreated, 0, 55
	Flip
Wend

Function CheckAhead() 

	If LYTEmp[0]>= 500 - 20 or LYTEmp[1]>= 500 - 20 or LYTEmp[2]>= 500 - 20 or LYTEmp[3]>= 500 - 20
		GameArray[LXTemp[0]/ 20, LYTEmp[0]/ 20]= 1
		GameArray[LXTemp[1]/ 20, LYTEmp[1]/ 20]= 1
		GameArray[LXTemp[2]/ 20, LYTEmp[2]/ 20]= 1
		GameArray[LXTemp[3]/ 20, LYTEmp[3]/ 20]= 1
		
		For Local iter:Int = 0 Until 4
			LXTemp[iter]= 0
			LYTEmp[iter]= 0
		Next
		LeftLXOff = 120
		LeftLYOff = 0
	'	LeftLCreated = 0
	End If
	
	If GameArray[LXTemp[0]/ 20, LYTEmp[0]/ 20 + 1]= 1 or GameArray[LXTemp[1]/ 20, LYTEmp[1]/ 20 + 1]= 1 or ..
		GameArray[LXTemp[2]/ 20, LYTEmp[2]/ 20 + 1]= 1 or GameArray[LXTemp[3]/ 20, LYTEmp[3]/ 20 + 1]= 1
		
		GameArray[LXTemp[0]/ 20, LYTEmp[0]/ 20]= 1
		GameArray[LXTemp[1]/ 20, LYTEmp[1]/ 20]= 1
		GameArray[LXTemp[2]/ 20, LYTEmp[2]/ 20]= 1
		GameArray[LXTemp[3]/ 20, LYTEmp[3]/ 20]= 1		

		For Local iter:Int = 0 Until 4
			LXTemp[iter]= 0
			LYTEmp[iter]= 0
		Next
		LeftLXOff = 120
		LeftLYOff = 0
	EndIf
			
End Function


Function MoveRotate() 
	
	If KeyHit(KEY_UP) and not KeyHit(KEY_DOWN) and LLCanRotate = 1
		ReadDefData = 1
		RotCount:+1
		RotL = 1
		If RotCount > 3 Then RotCount = 0
	ElseIf KeyHit(KEY_DOWN) and not KeyHit(KEY_UP) LLCanRotate = 1
		ReadDefData = 1
		RotCount:-1
		RotL = 1
		If RotCount < 0 Then RotCount = 3
	End If	
	
	
	
	If KeyHit(KEY_LEFT) and not KeyHit(KEY_RIGHT) 
		LeftLXOff:-20
 		If GameArray[LXTemp[0]/ 20 - 1, LYTEmp[0]/ 20]= 1 or GameArray[LXTemp[1]/ 20 - 1, LYTEmp[1]/ 20]= 1 or ..
			GameArray[LXTemp[2]/ 20 - 1, LYTEmp[2]/ 20]= 1 or GameArray[LXTemp[3]/ 20 - 1, LYTEmp[3]/ 20]= 1
		Else

		EndIf
		If LeftLXOff <= 0 Then LeftLXOff = 0
	EndIf
	
	If KeyHit(KEY_RIGHT) and not KeyHit(KEY_LEFT) 
		LeftLXOff:+20
 		If GameArray[LXTemp[0]/ 20 + 1, LYTEmp[0]/ 20]= 1 or GameArray[LXTemp[1]/ 20 + 1, LYTEmp[1]/ 20]= 1 or ..
			GameArray[LXTemp[2]/ 20 + 1, LYTEmp[2]/ 20]= 1 or GameArray[LXTemp[3]/ 20 + 1, LYTEmp[3]/ 20]= 1
		Else

		EndIf
		If LeftLXOff >= 500 Then LeftLXOff = 500
	End If
	
	If RotL = 1
		Select RotCount
			Case 0
				If ReadDefData = 1
					RestoreData LeftL1
					ReadDefData = 0
				End If
				For Local y:Int = 0 Until 3
					For Local x:Int = 0 Until 3
						ReadData ArrData[0]
						LeftL[x, y]= ArrData[0]
					Next
				Next
				RotL = 0
				ReadDefData = 0
			Case 1
				If ReadDefData = 1
					RestoreData LeftL2
					ReadDefData = 0
				End If
				For Local y:Int = 0 Until 3
					For Local x:Int = 0 Until 3
						ReadData ArrData[1]
						LeftL[x, y]= ArrData[1]
					Next
				Next
				RotL = 0
				ReadDefData = 0
			Case 2
				If ReadDefData = 1
					RestoreData LeftL3
					ReadDefData = 0
				End If
				For Local y:Int = 0 Until 3
					For Local x:Int = 0 Until 3
						ReadData ArrData[2]
						LeftL[x, y]= ArrData[2]
					Next
				Next
				RotL = 0
				ReadDefData = 0
			Case 3
				If ReadDefData = 1
					RestoreData LeftL4
					ReadDefData = 0
				End If
				For Local y:Int = 0 Until 3
					For Local x:Int = 0 Until 3
						ReadData ArrData[3]
						LeftL[x, y]= ArrData[3]
					Next
				Next
				RotL = 0
				ReadDefData = 0
		End Select
	End If
End Function

'#Region 
#LeftL1
DefData 0, 1, 0
DefData 0, 1, 0
DefData 1, 1, 0

#LeftL2
DefData 1, 0, 0
DefData 1, 1, 1
DefData 0, 0, 0

#LeftL3
DefData 0, 1, 1
DefData 0, 1, 0
DefData 0, 1, 0

#leftL4
DefData 0, 0, 0
DefData 1, 1, 1
DefData 0, 0, 1
'#End Region 


Press the + or - key to increase or decrease fall speed. There's no bounds checking for left and right but there is collidable stackable collision checking.

Hope you find it usefull. :)

[edit] Press space bar to drop first shape. There's only one shape. You should get an idea of how it's done though. Don't know if this is the way Tetris is made but it's all I could think of at the time. :)


Czar Flavius(Posted 2007) [#8]
Amon I can't get your code to work, and it is not easy to understand.


Apollonius(Posted 2007) [#9]
I understand your TPoint Concept. The TPoint and the Array idea seem quite similar to me though. I prefer working on the tetris idea, however my tetris won't be as simple as the normal tetris even though the normal tetris is not as easy as I though it would be.

As for my programming level, I'd be the in the clas of Monkey Programmer, sometimes I know, sometimes I don't and sometimes I just forgot. Reference is my guru~!

Oh and I almost forgot you know how the blocks go down cell by cell, would you use a global grid for the game board where the blocks are drawn or theres no need for this..

I'll figure it out eventually @__@


Amon: that's a nice piece of code u got there :o


Jesse(Posted 2007) [#10]
here it is your code correcterd:



Amon(Posted 2007) [#11]
Sorry, runs fine here. Press up/down arrow to rotate and left/right arrown to move left and right.

When the app starts press space to release the shape.

Itr should work, I just copied and pasted the code in to a new bmx file and ran it. It works.

Please note that it's not a full tetris game. Just an L Shape that drops, rotates and has collision to stack on top of another.


Czar Flavius(Posted 2007) [#12]
Ah Amon you didn't say about the space bar in your original post I read ;) Also the collision detection does not work perfectly. It is possible to overlap pieces by coming in on the horizontal side.

After having tried both the array and points concept in my program, I can definately say that the points method is easier to program, maintain and perform rotations with. Arrays deceptively seem like the best solution here but I disagree.

I hate to sound like an annoying know-it-all telling you the "best" ways to do things but I have researched into this quite a bit.

Yes you will need to have a "game board" grid to ultimately store the state of the game. Whether or not it is global will depend how you design your program. You will need to add methods to your blocks to add or remove themselves from the game board (and perform operations such as rotate and drop). To add, for example, simply use a double nested for-loop to go through the array adding those elements whose value is 1 and putting 1 on the game board, or for the points idea a single for loop going through the four elements and adding a 1 to the game board at each coordinate.

(Hopefully just from that you can see how the points idea is already simpler to program - hopefully lol)