PDA

View Full Version : Math-O-Spheres



sewing0109
08-05-2014, 09:19 PM
My game, Math-O-Spheres, is a Bejewled (https://www.youtube.com/watch?v=_nb4z-BpQA8)-type game where, instead of colored gemstones, you click on spheres with numbers on them. The numbers must add up to ten, and you get a higher score if you chain together more spheres (similar to Tetris Attack (https://www.youtube.com/watch?v=mALA_pYQCIw) or Roof Rats (https://www.youtube.com/watch?v=5zpJBcC-f2I)). You also get a higher score for finishing a level faster. Each level has a set time limit, and the time limit gets shorter and shorter as you go along. You have to get a certain number of ten's before the time runs out.

Right now, the spheres all add together (the feature I'm working on now), but I would eventually like to add subtraction and multiplication spheres, as well. I would also like to add a difficulty system with different grid sizes, but first I'll need a working game.

code_glitch
08-05-2014, 09:26 PM
Hi sewing and welcome to the PGD forums :)

It sounds like a cool game (as far as mechanics go, its more advanced than 2048 after all ;)). How far have you gotten on the code? Is there a demo to try or are you looking for help?

sewing0109
08-05-2014, 10:08 PM
I've designed the interface, loaded the images (via an imagelist), and setup the timer and lives system, but have no idea how to implement the click-then-add mechanics. "Looking for help" would definitely be what I'm doing. I know I want longer chains to generate higher scores, but I'm currently looking for a way to read the image in a cell, then assign the value based on which image it is. My thought is a switch statement with a case for each image, which would be stored in an array until the total value of the array became ten, but again have no idea how to "pick out" the images in the first place. Maybe create the image as part of a spheres class, and draw the object to the grid? I was actually writing a post asking for help in Start with the Basics (http://www.pascalgamedevelopment.com/forumdisplay.php?20-Start-with-The-Basics) when I saw your email.

As far as a demo goes, I could send you what I have.

code_glitch
09-05-2014, 03:03 PM
So, it looks like what you need is some 2d array that stores the value of each 'cell'. (reading a texture/image is slow and painful). Then I would write two functions: a FindContiguousBlockScore(X, Y) function that gives me the score for a block of like cells based on the XY co-oridnate of the cell that was clicked in the array. If the score is greater than whatever the minimum score is for a 1x3 or whatever, then I would increment the score by the returned amount before doing something like a EraseContiguousBlock(X, Y) to delete the cells that were just 'cashed in'.

Then all that remains is the comparatively simple matter of shifting the cells above it downwards and filling the rest with random values.

sewing0109
09-05-2014, 04:17 PM
I relied to your post, but hit the "Reply to Thread" button by mistake. The response is post #3.

sewing0109
12-05-2014, 03:36 PM
Would this be easier to do in a TStringGrid component? I just read up on the difference, and realized the stringGrid1.Cells[] property might be useful. I'm honestly not sure how to dsetermine the clicked cell. I know the computer knows already, but how do I associate a value with each image, and how do I tell it to store the information in the clicked cell?

I apologize for asking so many questions, I'm just feeling a little lost.

User137
12-05-2014, 04:01 PM
I don't know exactly what you are asking, but you can define 2-dimensional arrays that store any information. Dynamic or static arrays of records.


TSomeCell = record
someNumber: integer;
someText: string;
end;
...
grid: array[0..8, 0..8] of TSomeCell; // Defines a 9x9 grid
...
// Access it easily
grid[1, 2].someNumber:=1;

If you need dynamic array it's:


grid: array of array of TSomeCell;
...
setlength(grid, 9, 9); // Defines a 9x9 grid, and you can change it while program runs

SilverWarior
12-05-2014, 05:04 PM
I'm honestly not sure how to dsetermine the clicked cell.

Well that depends a bit on what components or library you use for drawing your game. So it would be nice if you could share some more information on this.
But based on the fact that in your posts you are mentioning ImageList and StringGrid I asume that you are using Visual components (VCL in delphi or LCL in Lazarus).
So I have written you a short example which will show you how to get mouse relative coordinates above TImage and how to caclulate which cell would be selected. I even add a bit of code to render the gridlines on TImage to make it easier for you to understand.
In order to make this example simply create a new project and put a TImage component on it.
Then you need to create an OnMouseMove event for TImage and copy the code below into it:

procedure TForm1.Image1MouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
var Line, Row: Integer;
begin
//Calculate over which row is mouse cursor positioned
//Row width is 20 pixels
Row := X div 20;
//Calculate ower which line is mouse cursor positioned
//Line height is 20 pixels
Line := Y div 20;
//Show output values instead of form caption
Form1.Caption := 'X:'+IntToStr(X)+' Y:'+IntToStr(Y)+' Line:'+IntToStr(Line)+' Row:'+IntToStr(Row);
end;
You also need to create an OnCreate even for main form in order to draw gridlines on TImage. Code for this is below:

procedure TForm1.FormCreate(Sender: TObject);
var X,Y: Integer;
begin
//Draw vertical lines
for X:=0 to 20 do
begin
Image1.Canvas.MoveTo(X*20,0);
Image1.Canvas.LineTo(X*20,400);
end;
//Drwa horizontal lines
for Y:=0 to 20 do
begin
Image1.Canvas.MoveTo(0,Y*20);
Image1.Canvas.LineTo(400,Y*20);
end;
end;
This example reads mouse relative coordinates above TImage component, calculates over which line/row is mouse cursor positioned and displays that instead of default Form caption.

sewing0109
12-05-2014, 06:31 PM
I'm using Delphi -- RAD Studio XE5. Would it help if I posted the folder with all the files -- the images, exe, dproj, dpr, etc?

UPDATE: An image of the game running.

1274

Each sphere is in a cell, and I want to add functionality so that any two spheres that get clicked are added up.

SilverWarior
12-05-2014, 09:45 PM
You can post your project since I do own Delphi XE5 and would therefore be able to check your code in action and then try to give you best suggestion based on your current design.

sewing0109
13-05-2014, 03:41 PM
Here's the link at MediaFire -- I couldn't upload the ZIP file using the "Manage Attachments" window...

https://www.mediafire.com/?l9lp8cersb44iki

SilverWarior
13-05-2014, 07:27 PM
I have just checked your code.
There is no easy way to say this but your code is a mess. That is why I won't simply just do some changes to your code in order to solve your problem as I would have to change lots of it and you probably wouldn't understand what I did and why.
So instead I will try to tell you which parts of your code are god and which are not god and should be changed.
1. It was quite clever of you to use TDrawGrid for Cell picking. I myself probably would have never used that but instead do my own math for that similar as in that example of mine I posted before.
2. Why do you have 128 Images in your ImageList? And most of all why do you have same images at multiple indexes? Don't tell me that you are trying to use that image list to store the position of different Spheres in the grid.
I only recomend your ImageList to contain only all posbile spheres available (+1, +2, +3, ...,+9, -1, -2, ...). Then you only need to define somewhere in your program which ImageList index is used for which sphere. Note image list index starts with 0 and not 1.
3. You should store spheres information in two dimensional array like so:

var SphereMap: Array [0..7, 0..15] of Integer;
4. Upond clicking on certain cell you could use the information from that same array to find out what to do like so:

case SphereMap[row, column] of
1: Sum := Sum + 1; // +1 Sphere
2: Sum := Sum + 2; // +2 Sphere
...
10: Sum := Sum - 1; // -1 Sphere
11: Sum := Sum - 2; // -2 Sphere
...
end;
5. In your code you say that you set the starting time to 15 seconds but you have your timer interval set to half a second. So the player actually doesent have 15 seconds as stated.
6. I advise you set the ProgressBar max value to the starting time. This way progressBar will start being full and not only partially full as it does now.
7. Infact using TProgressBar might not be the best idea. Why? On windows Vista and newer the ProgressBar will show that default Windows ProgressBar moving animation which might not be desirable. You can use TGauge instead. It's usage is quite similar to ProgressBar but its look is not afected by the operating system you are running your program on.

So these are my coments and suggestions on your project so far. I hope they will be helpfull.
And you can always ask for further advice if you need it.

sewing0109
13-05-2014, 08:18 PM
You're right about things being a mess, I was planning to clean them up after I had everything working.

1.) Thanks.

2.) That was a temporary measure; I actually wanted to iterate through a length: nine (0 through 8 ) list randomly 128 times, at which point the grid would be filled. I haven't done that mainly because I'm currently working on the "chain" functionality of the game.

3.) I have the code for that, but haven't finished implementing it.

4.) Thanks.

5.) I was planning to make the game time around one minute, but have it set to fifteen seconds from when I was testing to make sure the Game Over events were working. Waiting all that time just for the game to end seemed like a waste.

6.) I've already done that; the current length is only temporary. Once I've set the final length, the bar will start full.

7.) Didn't know that. Thanks.

You've been more than helpful. I really appreciate you taking time out of your day to do this.

SilverWarior
13-05-2014, 08:21 PM
No problem. If you will have any other questions don't be shy.

sewing0109
21-05-2014, 08:51 PM
I'm still not sure how to iterate over the imagelist.

The code I have is...

index := ARow * grdPlayField.ColCount + ACol;
grdPlayField.Canvas.Brush.Color := clMaroon;
grdPlayField.Canvas.FillRect(Rect);
imlSpheres.Draw(grdPlayField.Canvas,Rect.Left,Rect .Top,index, True);
if (gdFocused in State) then
begin
grdPlayField.Canvas.DrawFocusRect(Rect);
end;


...It works for simply displaying the nine items on the grid in the appropriate cells, but I can't figure out how to tell Delphi to keep assigning the elements until the grid is full.

User137
22-05-2014, 06:53 AM
You're only showing what you do with 1 element. Is there a for or while structure we can take a look at? Iterating 2D table is really easy


var i, j: integer;
...
for j:=0 to RowCount-1 do
for i:=0 to ColCount-1 do
begin
// Do something with element[i, j] ...

end;