DIV ARENA FORUMS

How to make a Tetris game?

Dani_Karmann - 11-3-2017 at 09:34 PM

I want to make a Tetris style game for Div with the "feeling" and appearance of the "9999 in 1" lcd brick games. But I have a problem, I don't know how to make it. I know that I must use a struct for the rows and the columns, but I don't understand how to use the structs.

dom cook - 12-3-2017 at 07:16 AM

NOTE: In this explanation I've used curved brackets for square ones because the first time I posted it it deleted all the square ones.

Hi Dani, I'd like to help.
Structs are a lot simpler than they seem at first.
For example If I wanted to keep track of a process's previous position I'd need to have variables for storing this information. To do this I might declare variables and call them 'old_x' and 'old_y'. Alternatively, I could use a struct and declare them thus:

struct old;
x;
y;
end
Now in the code if I want to use these varables I just write 'old.x' or 'old.y'.

Apologies if you already knew this much.

If wanted to create a grid of cells which each needed its own set of data I'd do it a bit like this

grid_height=10;
grid_width=10
grid size=10*10=100

struct cell(100)
id
index;
row;
col;
state;
etc...
end




This struct is one dimensional and a grid is 2D so to assign the correct row and column to each cell you do this

for(i=0; i<grid_size; i+=1)
cell(i).row=i/grid_width;
cell(i).col=i mod grid_width;
end

Next you can create a bunch of processes for the cells

for (i=0; i<100; i+=1)
cell(i).id=cell();
cell(i)index=i;
end


Now you can lay out you cells in a grid like this
for(i=0; i<100;i+=1)
cell(i).id.x=cell(i).col*column_width;
cell(i).id.y=cell(i).row*row_height;
end

If you need to know the neighbours of each cell you can add that into the cell struct
You could even put a struct inside a struct like this

struct cell

struct neighbour_index
up;
down;
left;
right;
end
end

So,
cell(i).neighbour_index.up = i-10
cell(i).neighbour.index.right = i+1
cell(i).neighbour_index.down=i-10
cell(i).neighbour_index.left=i-1

Now you would be able to access these neighbours by writing for example
cell(cell(i).neighbour_index.up)

Anyway that's an intro. It's very generalised and obviously incomplete but it shows one way of doing what you want. If it doesn't help, I'm sure that if you refine your request I can refine my explanation.
Good luck with the project.




[Edited on 12-3-2017 by dom cook]

Dani_Karmann - 12-3-2017 at 11:06 AM

This is the grid that I want to use. The bricks are sprites, and there are 10 columns x 20 rows. As you can see, the cells are separated by 1 pixel.

I know that:
-First, the computer selects one of 7 pieces (or 12 in the "special version").
For example, "new_piece=rand(1,7)".

-The brick appears on screen (piece (x and y depending on brick shape)).

-The brick begins to fall at the actual level speed, controlled by the user until it reaches the ground or a previous block.

-Then I have to convert the actual brick to a set of cells in the grid, this is one of the things that I don't know how to do.

-The grid cells are updated and the score increases a bit for falling piece (for example, 10 points).

-If a set of 10 horizontal cells are aligned, then this line disappears and the upper cells fall and take the place of the older ones.

-And all the process repeats from the step 1.

But I don't know how to use structs, and how to convert process shapes to cells.

Do you recommend use grouped cells for every piece, or it is okay to use sprites?

Ah, I'm trying to write this into my program:

for(i=0; i<grid_size; i+=1)
cell(i).row=i/grid_width;
cell(i).col=i mod grid_width;
end

But DIV gives me an error message, "expresión sin sentido" ("expression with no sense") with "cell.i".



SCREEN.png - 302kB

CicTec - 12-3-2017 at 12:17 PM

Quote: Originally posted by Dani_Karmann  

But DIV gives me an error message, "expresión sin sentido" ("expression with no sense") with "cell.i".

Hi Dani_Karmann,

In DIV arrays are declared using brackets [ ], so:
Code:
global struct cell[9] // declare a array of struct of 10 elements row, col; end ... begin for(i=0; i<grid_size; i+=1) cell[i].row=i/grid_width; cell[i].col=i mod grid_width; end end


Dani_Karmann - 12-3-2017 at 05:43 PM

I've tried to copy and paste your code in my program.

In my grid every block has an 11x11 size, and it begins at the position x=84, y=10, and there are 20 rows and 10 columns. So, the first cell is located at the position x=89,y=15, the last block of the first row is at position 188,15. The first cell of the second row is located at 89,26, and the last one at 188,224, and so on. Then, the first block of the 20th row is located at 89,224, and the last one at 188,224.

Then, I need to put every cell from position x=89 separated 1 pixel of its neighbour. Am I right?
Then, I have to create 20x10= 200 cells into the grid, starting from x=89 and y=15, with a separation of 1 pixel for every block.
Then, every cell can be at two states: on(1) or off (0). Every active cell should look as a black square block.

Now, I have to begin to create the STRUCT like in your example. This will look this way:

for (i=0; i<200; i+=1)
cell(i).id=cell();
cell(i)index=i;
end

But I have a doubt: What is "cell" in this example, a variable or the name of the process?

And look at the screenshot, I just create the blocks, so now I have 200 of them in the correct position. Now I have to begin the game routine.




dos4gw_008.png - 302kB

[Edited on 12-3-2017 by Dani_Karmann]

Dani_Karmann - 12-3-2017 at 05:54 PM

Ah, I just realize that it's not necessary the 1 pixel separation, so the blocks can be located at its "natural" position.

dom cook - 12-3-2017 at 07:37 PM

Hi Dani,
Yes you're right it is confusing because I suggested a struct called cell and also a process called cell. They're different things.
Perhaps it would be better to call the struct cell_data.
Alternatively, a cell process isn't actually necessary, you could do the graphics using the map_put() function.

something like
for(i=0; i<grid_size; i+=1)
if(cell(i).state==0)
map_put(grid_graph,cell_graph_empty,cell(i).grid_x,cell(i).grid_y);
else
map_put(grid_graph,cell_graph_full,cell(i).grid_x,cell(i).grid_y);
end
end

where cell_graph_full and cell_graph_empty are your graphics for the 2 states of a cell.

(NB don't forget about the square brackets,
Can someone remind me how to embed code?)

dom cook - 12-3-2017 at 07:41 PM

By the way, am I right in assuming the falling bricks are to be rotatable in 90 degree steps?

Dani_Karmann - 12-3-2017 at 07:58 PM

Do you know the example program included in Div2 called OFUSTRIS? It's a Tetris game with "zeros" and "ones", but the author wrote a very, very confusing program.

I guess I need to create another struct variable for every piece shape and position.

The idea of using "map_put" seems good, but will it be fast enough to put all the squares in faster levels of falling blocks?

Part of the OFUSTRIS program:

STRUCT QQQ;
STRUCT OQ[3]QO[3];END;END;
STRUCT OOQ;
STRUCT OQ[3]QO[3];END;END;
STRUCT OQQ;
STRUCT OQ[20] QO[14];END;END;
QQOQ,QQQO;QQOQQO;QOQOQ;QQOOS;

LOCAL QOQ,OQO,CQOC,COCQ;

BEGIN

FOR(QOQ=0;QOQ<=17;QOQ++)OQQ.OQ[QOQ].QO[0]=2;OQQ.OQ[QOQ].QO[1]=2;
OQQ.OQ[QOQ].QO[2]=2;
OQQ.OQ[QOQ].QO[12]=2;
OQQ.OQ[QOQ].QO[13]=2;
OQQ.OQ[QOQ].QO[14]=2;
END;

FOR(OQO=0;OQO<=14;OQO++)OQQ.OQ[18].QO[OQO]=DOS;OQQ.OQ[19].QO[OQO]=2;
OQQ.OQ[20].QO[OQO]=2;END;
SET_FPS(QOCQ,0);WRITE(0,0,CQO,0,"OFUSTRIS (C)1998 100% !DEEMO");
WRITE(0,0,CQO+9,0,"www.geocities.com/SiliconValley/Campus/2439/");

As you can see, the author writes a strange and confusing program...

dom cook - 13-3-2017 at 06:20 AM

Wow that's horrible!
The map_put function is pretty fast
Here's some code showing it updating an entire grid every frame. The FPS is set to 60 and it's keeping up

Code:
/* * tits.PRG by dom cook * (c) 2017 sollia 3 */ PROGRAM tits; const grid_wide=10; grid_high=20; grid_x0=100; grid_y0=100; grid_size=grid_wide*grid_high; cell_size=10; global; struct cell_data[grid_size] x_pos; y_pos; x_coord; y_coord; state; end graph_cell[1]; private i; BEGIN set_fps(60,0); set_mode(m640x480); graph=new_map(120,240,0,0,20); x=grid_x0; y=grid_y0; graph_cell[0]=new_map(cell_size,cell_size,0,0,30); graph_cell[1]=new_map(cell_size,cell_size,0,0,40); for(i=0; i<grid_size; i+=1) cell_data[i].x_coord=i % grid_wide; cell_data[i].y_coord=i / grid_wide; cell_data[i].x_pos=cell_data[i].x_coord*cell_size; cell_data[i].y_pos=cell_data[i].y_coord*cell_size; cell_data[i].state=rand(0,1); map_put(0,graph,graph_cell[cell_data[i].state],cell_data[i].x_pos,cell_data[i].y_pos); end write(0,40,10,2,"fps: "); write_int(0,40,10,0,&fps); loop for(i=0; i<grid_size; i+=1) cell_data[i].state=rand(0,1); map_put(0,graph,graph_cell[cell_data[i].state],cell_data[i].x_pos,cell_data[i].y_pos); end frame; end END


dom cook - 14-3-2017 at 01:33 PM

Hi Dani,
How's the project going? Have you come up with a way to do the falling pieces? I've given it some thought so if you get stuck I think I can help.

Dani_Karmann - 14-3-2017 at 04:53 PM

I'm sorry, but I'm busy due to my job and I did not make any actual progress in the game.

Dani_Karmann - 14-3-2017 at 09:28 PM

Latest news:

-The process "next brick preview" is already done. Now you can see the next piece.
-Now there will be 5 different games: Tetris, Tetris special, Arkanoid, Grand Prix and Space duel.
-Created the title screen with the "9999 in 1" logo on screen (see screenshot).

Some examples (they're not captures of the actual games, they're only previews):

9999IN1.png - 302kB GPRIX.png - 902kB SDUEL.png - 302kB

Dani_Karmann - 14-3-2017 at 09:56 PM

For now, I have done this:

When you run the program, the logo "9999 in 1" appears flashing on screen until you press a key. Then the game selection showing the letters from "A" to "E" starts.

Now I need to make a preview for every game and the selection of the game you want to play.

GAME A: Normal Tetris.
GAME B: Special Tetris (It's just basic Tetris with more types of bricks).
GAME C: Arkanoid.
GAME D: Grand Prix.
GAME E: Space Duel.

The game will save the record for every game. I don't want to make more than these 5 games, at least for now.

Ah, I need the sound effects, of course, and a starting and "game over" melodies.

Dani_Karmann - 15-3-2017 at 08:18 PM

Before I make the two Tetris games, I will concentrate in the other three games: Arkanoid, Grand Prix and space Duel, and things like the lives indicator, game selection, etc. I will move this project to the "WIPS" section under the title "LCD brick game simulation".

MikeDX - 15-3-2017 at 08:45 PM

Wow Dani this is amazing

I haven't been online much lately (very busy at work and with home life)

Great to see this

You should take a look at my astro wars DIV game, which is an emulator of an LCD (actually VFD) display game which may give you an idea of how an LCD game could be done.