PDA

View Full Version : newbie seeks help!!



yawbird
19-11-2002, 06:23 PM
Hi I've jus started using delphi having a little previous experience with pascal. I need some help with a task I have been set.

I'm required to design a simple game involving a target (shape) that is initialy displaed at a random position on the form it then moves smootly around the form. A single game consists of a number of targets. At any instant in time, there is only one target on the form. u get points for clicking on it an points deducted if missed. The skill level should be adjustable in means of the target size, the speed an the complexity of target movement. The game takes say 2 mins and the final score is displayed.
I do not have the foggiest idea on how i should start this.
suggestions + emails are more than
welcome.

The annoying thing is I do not seem to have ne of the help files with my version of delphi (vr 6) is there a place where I can download these?


Thanks in advance

Derek

Alimonster
19-11-2002, 09:47 PM
It depends a bit on what shape you want - do you want a simple thing like a square or something more complex, like a picture with transparent areas?

First of all, a simple square is easy enough to do. You only need one of them rather than a variable amount, so you can simply dump down a TShape from the "additional" component tab.

Note that the shape has an "OnMouseDown" event. This lets you know when the user hit the shape, regardless of where that shape is on the form (i.e., you can move it about). You could write some simple logic for this event that added a score and repositioned the shape if you clicked on it.

Also, note that the form itself has similar events. You're most interested in the "onclick" event, which gets fired when the user clicks on the form. Note that if the user clicks the shape, no OnClick happens. This means that you can write code in the OnClick which assumes the user missed, deducting points and/or insulting them with nasty messages.

Next up, you have to know how to randomly position the thing. There are two functions of interest, Randomize and Random. Call Randomize *once* in your program. It ensures that the "random" values generated are different - if you don't call it, your program will generate the same "random" values each time it's run (which you may, but probably don't, want).

The main form's OnCreate is a good place to chuck that *one* call to Randomize.

The random function generates a number from [0..number-1] inclusive if passed in a value - for example, Random(10) gives a value from 0 to 9 inclusive. If you want more, you can add an offset onto it - Random(6) + 1 would result in a number from 1 to 6, since it would be [0..5] + 1.

The trick for moving/positioning your object is to notice the *left* and *top* properties for your shape. Your shape will be moved if you change these. Therefore, you want to generate a random value for the left and the top, which will move your object somewhere around the form. You might want to ensure that the values are from [0..ClientWidth - Shape1.Width] and [0..ClientHeight - Shape1.Height] to keep it on the screen.

Next up, you need to decide the difficulty - you can let the user select this somehow (e.g. a TRadioGroupBox or buttons), or you could generate it somehow (a random number again?). You have to decide how this effects the difficultly, mind you. A simple way would be to make the shape smaller depending on the value - e.g. "Shape1.Width := DEFAULT_SIZE - (10 * skill)", or something like that, with the same for its height.

It would be easy enough to time your game. Dump down a TTimer from the "system" tab and give it some code for the OnTimer event. This gets called regularly, each time a given amount of time (in milliseconds) has passed. For example, the default interval is 1000 milliseconds, equal to a second. If you set it to 2 minutes (60 * 2 * 1000 = 120000) then your timer event will fire. At that point, your game has finished! You can do any code and disable the timer (Timer1.Enabled := False). Re-enable the timer at the start of a new game.

You can move the object using another timer. TTimer sucks for quick animation (interval < 55msecs), but if you're just learning then it will be fine [you can also investigate some other component sets with good timers if you want, more on that later]. You can dump some logic in there to move the object in a speed and direction.

One easy way to store the direction is to have two integer variables for the x and the y speed - negative values = left or up, positive values = right or down (for example, speed_x = -2 would move two pixels left every timer update. If you had speed_y = -1 then that would be two units left, one unit up). You can use these simply by adding the values to the left and top positions of the shape each update.

You can make your shape bounce off of the edges by negating the speeds. Some quick pseudocode:

procedure TForm1.MoveShape;
var
NewX, NewY: Integer;
begin
NewX := Shape1.Left + Speed_X;
NewY := Shape1.Top + Speed_Y;

if NewX < 0 then
begin
NewX := 0;
Speed_X := -Speed_X; // opposite direction
end;

if NewX > ClientWidth - Shape1.Width then
begin
NewX := ClientWidth - Shape1.Width;
Speed_x := -Speed_X;
end;

if NewY < 0 then
begin
NewY := 0;
Speed_Y := -Speed_Y;
end;

if NewY > ClientHeight - Shape1.Height then
begin
NewY := ClientHeight - Shape1.Height;
Speed_Y := -Speed_Y;
end;

Shape1.Left := NewX;
Shape1.Top := NewY;
end;

The above will 'bounce' your shapes. ClientWidth and ClientHeight return the available area of your form after stuff like borders, title bar are taken into account. The above code stops the shape from going off-screen. However, it will only move in lines - moving in fancy ways (circles, etc.) is a bit more difficult. You might want to consider adding a random value to the speed(s) when the shape hits the side of the form, to make things more interesting.

If you're wanting something more complicated than a square, it will take a bit more work. You can consider using a TImage (additional component tab) and giving it a bitmap using its Picture property (hit the three dots beside that property). You could then check its OnMouseDown property - it gives you access to the x and y values of where it was clicked. You could then check "if Image1.Canvas.Pixels[x,y] = transparent_colour" then missed_with_click else hit_target" (I think...)

If you want things to look better, you'd use one of the dozen component sets out there (DelphiX, PowerDraw, JDS Games' thing [gamevision? Can't remember, sorry :oops: ], Bobby's Omega Project]... You could consider using a high performance timer for your main game update (see other threads in this board about game loops, etc.).

If you don't have access to a component with an onclick then you have to check manually - draw the bitmap to screen, then check in the form's onmousedown "if (x >= your_bitmap_x) and (x < your_bitmap_x + your_bitmap_height) and (y >= your_bitmap_y) and (y < your_bitmap_y + your_bitmap_height) then hit_target else missed_target;".

If you want any more detail/code, just ask.

yawbird
21-11-2002, 04:06 PM
Thanks for the detailed reply!!
my lil programme works a treat.

regards

Derek :)

yawbird
06-01-2003, 07:47 PM
Hello again

Iv had to dig this out again for an assignment. I just need to make a few tweaks, wonder if any1 can help me.

Below is the code Im using at the moment to simply move a ball(shape) across a form bounicng of walls as it goes along. Now what i wish to do is to make the ball jerk, spasm like instead of moving in a straight direction as to speak.

procedure TForm1.Timer1Timer(Sender: TObject);
begin
if (Circle.Left > (Form1.ClientWidth - Circle.Width))
or (Circle.Left <0)
then

begin
JumpHoriz:= -JumpHoriz;

end;
if (Circle.Top > (Form1.ClientHeight - Circle.Height))
or (Circle.Top < 0)
then

begin
JumpVert:= -Jumpvert;

end;
Circle.Left:= Circle.Left+JumpHoriz;
Circle.Top:= Circle.Top+Jumpvert;

end;

I have used a timer so i can alter the speed in which the ball moves easily if you was wondering why.

Any help will be greatly appreciated

Derek

Diragor
07-01-2003, 04:01 PM
To make the ball "spasm" as it moves along, just add or subtract a random unit or two from the JumpHoriz and JumpVert. I'd use a const for the amount of jitter:

const
JITTER = 5; // use an odd number to properly center around zero

Then before you do the side collision checking:

Randomize;
Inc(JumpHoriz, Random(JITTER) - ((JITTER - 1) div 2));
Inc(JumpVert, Random(JITTER) - ((JITTER - 1) div 2));

This may not be the most optimized way to do it, but it should work.

yawbird
08-01-2003, 07:27 PM
Iv tried implementing this into my system but it does not seem to work.

e.g.

procedure TForm1.Timer1Timer(Sender: TObject);
const
JITTER = 5;
begin
Randomize;
Inc(JumpHoriz, Random(JITTER) - ((JITTER - 1) div 2));
Inc(JumpVert, Random(JITTER) - ((JITTER - 1) div 2));
// this i believe is before the collision detecting takes place
// its probably very obvious to the delphi orientated and iv probably put it in the wrong place, but im still a true newbie! sorry
if (Circle.Left > (Form1.ClientWidth - Circle.Width))
or (Circle.Left <0)
then

begin
JumpHoriz:= -JumpHoriz;

end;
if (Circle.Top > (Form1.ClientHeight - Circle.Height))
or (Circle.Top < 0)
then

begin
JumpVert:= -Jumpvert;

end;
Circle.Left:= Circle.Left+JumpHoriz;
Circle.Top:= Circle.Top+Jumpvert;

end;

Diragor
09-01-2003, 04:18 PM
Hmmm. Well, I have a couple suggestions. The const should probably go in the interface section. I generally put consts at the very top, just under the uses. I think you only need to call randomize once, so that could go in the form's OnCreate event or in whatever "initialize" function you may have. You could also make that jitter number a lot bigger, just to make sure it's obvious when it does work.