components used: TImage TPaintBox

this tutorial will partially work with borland kylix

Part 1Part 2 coming soon download source code (coming soon)

In this tutorial we'll be covering the use of the mouse in your games. This isn't the be all and end all in mouse use, but it should provide enough information to get you on pretty well. In addition, you may want to also look at the DelphiX tutorial on using the mouse, which will show you how to make use of what you've learnt here, with DelphiX too. So, we'll start by covering each of the events open to you that use the mouse.

OnClick
You've probably used this event countless times before already, as whenever you set up what happens when you click on a button on your form, this is the event that's created. As far as mouse operations go, an OnClick event is only called when the user clicks AND releases the mouse on a particular area of the form, such as a button.

It should be pointed out that an OnClick event can also be called by the keyboard if, say a button is focused on, and the return key is pushed.

The OnClick event is not likely to be used very often in your games other than for selecting options, as it does not tell your program the location of the click, ie the X and Y coordinates. For that we need the OnMouseDown event.

OnMouseDown
The OnMouseDown event differs from the OnClick event in a number of major ways. Firstly and most importantly, it will give your program the X and Y coordinates of a click, and so allowing you to tell exactly where on the form, a user has clicked. This is of course, extremely useful when trying to move a character around the screen by clicking on a location on the map. We'll come back to how to make use of this after we've gone through the other mouse events.

The second major way in which the OnMouseDown event differs from the OnClick event is that it can check for left, middle and right clicks, as well as if the Shift, Control or Alt buttons are pressed at the time of the click. This allows for a greater range of functions which you can provide to the user of the mouse.

The final major difference is that a 'click' of the mouse is now broken up into the pushing of the mouse button down, and the release of the mouse button. As the name suggests, for this event we're only dealing with the holding down of the mouse button. We'll deal with the release of the mouse button next.

OnMouseUp
The OnMouseUp event is exactly the same as the OnMouseDown event except for one obvious point: the event only occurs when the mouse button is released. Everything else works the same way. You can get the X and Y coordinates of the location where the mouse button was released (so if you were to push the mouse button down and then release it after moving the mouse a little you can find both the starting and ending coordinates), you can detect whether there are Shift, Control or Alt buttons pressed, and you can detect whether it is the left, middle or right mouse button being used. Simple.

OnMouseMove
This last event occurs at any time when the mouse is moving while your program is running and is selected. Usually you wouldn't want to be carrying out anything continuously while the mouse is moving, but it is often desirable to have certain actions occurring as a mouse button is being pressed and moved across the screen. For example, if we want to drag and select a group of player models on the screen we may want a rectangle to appear as we drag, to see who we are currently selecting. When used in conjunction with the OnMouseDown and OnMouseUp events, the OnMouseMove event becomes very useful and we'll use this event in our mouse example application next.

A Practical Example...
Now that you've heard a little about each mouse event, let's put all this knowledge together and make a few little programs. The first thing we'll try and do is get our fly from a previous tutorial, to move to the position on the form that we click on. After you've added the image onto the form, enter the following code in the OnMouseDown property of the actual form (not the TImage):

procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
 CurrentX := FlyImg.Left;
 CurrentY := FlyImg.Top;
 MouseX := X;
 MouseY := Y;

 while (CurrentX <> MouseX) do begin
  if
MouseX > CurrentX then CurrentX := CurrentX + 1
  else if MouseX < CurrentX then CurrentX := CurrentX - 1;
  FlyImg.Left := CurrentX;
 end;

 while
(CurrentY <> MouseY) do begin
  if
MouseY > CurrentY then CurrentY := CurrentY + 1
  else if MouseY < CurrentY then CurrentY:= CurrentY - 1;
  FlyImg.Top := CurrentY;
 end;
end;

Remember also to set up our four variables with the following code in the var section of the code:

CurrentX: integer;
CurrentY: integer;
MouseX: integer;
MouseY: integer;

Let's go through this code then. The first thing we're doing when you click on the form is setting the CurrentX and CurrentY variables to the location on the form where the fly lies at present on our form. Then we're setting our MouseX and MouseY coordinates to that of where we've just clicked.

Next we start actually carrying out the process of moving our fly to the correct location. What we're doing is first examining the location of our image and the location where we want to go and if they are not equal, we carry out the actual movement. We do this for the X coordinate and Y coordinate separately, and we check to see if the location where we've clicked is 'ahead' or 'behind' where the fly image is at that time. If we have to increase the X or Y coordinate to get closer to the clicked location, we increase our fly's coordinate by one, or if we have to decrease the coordinate, we take one off our fly's coordinate. Simple really, and these actions will repeat until the fly's location is exactly the same as the place where you've clicked.

This isn't however particularly useful on its own as we can't see the fly moving to its location. Instead we just see the fly suddenly at its new location, which we could have just as easily done by simply setting the Fly's coordinates immediately to that of the MouseDown's coordinates.

To solve this we need to make use of a delay between each movement. We can use our delay from the TTimer component tutorial for this, but we'll need to change our code a little first to allow a better movement. The way things are just now, the program will first move the fly along the X coordinate, and then after, move along the Y coordinate, causing it to move in a strange way. We can luckily sort this easily enough by getting the program to alternate between the X and Y coordinate until we reach our destination. The diagram below demonstrates this. Here the red dot represents our fly's starting position and the green dot represents the finishing position, with the orange line representing the movement of our fly.

Diagram 1
Movement before alteration in code

Diagram 2
Movement after alteration in code

This solution works well enough for the moment, although often you may find that one coordinate is reached before the other making the route taken a lot less perfect than that shown above.

procedure Delay(Num: longint);
var
 tc: longint;
begin
 tc :=GetTickCount;
 repeat
  Application.ProcessMessages;
 until ((GetTickCount-tc) >= Num);
end;

procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
 CurrentX := FlyImg.Left;
 CurrentY := FlyImg.Top;
 MouseX := X;
 MouseY := Y;

 while (CurrentX <> MouseX) or (CurrentY <> MouseY)
 do begin
  Delay(10);
  if (CurrentX <> MouseX) then begin
   if
MouseX > CurrentX then CurrentX := CurrentX+1
   else if MouseX < CurrentX then CurrentX := CurrentX-1;
   FlyImg.Left := CurrentX;
  end;

  if (CurrentY <> MouseY) then begin
   if
MouseY > CurrentY then CurrentY := CurrentY+1
   else if MouseY < CurrentY then CurrentY := CurrentY-1;
   FlyImg.Top := CurrentY;
  end;
 end;
end;

The difference here is that as well as adding the delay procedure, we've also placed our old code inside a new while..do..begin loop, as well as getting rid of our old two 'whiles' and swapping them with if..then..begin loops. This new while loop checks if either the current X-coordinate or the current Y-coordinate of the fly are not equal to the destination coordinates, and performs the relevant movement to both the X and Y coordinates at the same time. That's it.

You'll now find that the fly 'flies' all the way to its new destination. Okay, so it flickers a lot, but as a practical learning exercise for you, you should try making it flicker-free based on the techniques demonstrated in tutorial 11. If you get stuck, the downloadable code for this tutorial includes just such an example.

But that's not all...
We're not done with this tutorial though as I want to cover the ability to select multiple characters on a screen and move them, in a similar way as that seen in games such as 'Command & Conquer'. If you don't know what I mean then let me explain. Basically, when there are multiple characters on the screen and we want to select them all and get them to walk to a given location, we might want to 'drag' a box around the characters with one mouse button to select them, and then click with the other button to tell them where to move to. I think this calls for a second page, which will be available soon.

Part 1Part 2 coming soon download source code (coming soon)

Subscribe to the feed delphigamedev.com NEWS Feed
archived news | mailing list

[ all tutorials found at delphigamedev.com are Copyright © 2008 Ben Watt ]