-1

So I'm creating a simple game in Delphi where timers are used to move images(the moving algorithm completed), but it would be better to move all images with a certain name (ie. they all start with "img") at the same time using 1 timer. Is this possible? The images all move in a straight line at them same speed and are created dynamically at random intervals, cant create a timer for each one. Here is the timers code:

if ((imgLandmine.Left + imgLandmine.Width) <= 0) then
  begin
    imgLandmine.Left := iFormWidth - imgLandmine.Width;
  end
  else
  begin
    imgLandmine.Left := imgLandmine.Left - iMineSpeed;
  end;

how to replace "imgLandmine" with an alternative that includes every landmine image currently in use.

this is the code for the dynamic image:

imgLandmine := TImage.Create(frmTank);
  imgLandmine.Parent := frmTank;

  imgLandmine.Picture.LoadFromFile('Landmine.png');
  imgLandmine.Visible := True;
  imgLandmine.BringToFront;
  imgLandmine.Stretch := True;
  imgLandmine.Width := 60;
  imgLandmine.Height := 30;
  imgLandmine.Left := iFormWidth - imgLandmine.Width;
  imgLandmine.Top := pnlGrass.Top - imgLandmine.Height;
Lucas
  • 7
  • 3
  • (1) Don't create animations by moving controls. Instead, draw your scene in code. (2) Use arrays. (3) It's your lucky day! You can find a complete example application demonstrating both points: https://stackoverflow.com/questions/7223678/delphi-moving-overlapping-tshapes – Andreas Rejbrand Feb 13 '22 at 14:07
  • How would i move the images without the timer? is there a way that i can include all images with a certain name in the ontimer event? Im still new to coding so this is super confusing to me XD (Also i need to keep it within limits of what weve done at school, so canvas isnt really an option for me) – Lucas Feb 13 '22 at 14:23
  • You definitely don't want to animate by moving controls and you definitely don't want to use timers. You need to start again and get the right approach for a game. But if this is a school project, ask your teachers for guidance. – David Heffernan Feb 13 '22 at 16:29
  • 2
    Although I didn't downvote, I think the downvoter realised that this is a less-than-optimal fit for SO. SO isn't really a place where you can ask for personalised tutorials or code reviews. It is a bit unlikely this Q will benefit any future programmer searching Google for advice on how to move multiple `TImage` controls using only a single `TTimer`. – Andreas Rejbrand Feb 14 '22 at 19:15

1 Answers1

3

Can you move multiple images with one timer? Of course you can. You just need a mechanism to iterate over them.

Since you are using components one bad way would be to iterate through all Controls of your frmTank and check if their name starts with img. But this is bad approach as you would be iterating through all controls that are on your form and doing lots of string comparisons.


The good way of doing this would be to create a list or an array that would contain references to your images so you can easily loop thought them.

Since you are new in coding i would recommend using List at this time so you don't have to deal with additional code that would be required to manage dynamic array allocation when adding items and resizing and reordering of items in an array when removing items.

So you should create yourself a List to store references to the mines

procedure TForm3.FormCreate(Sender: TObject);
begin
  //Create a list for storing references to your LandMine images
  LandMines := TList.Create;
end;

Then while you are creating the LandMines you also add them to the said list

  imgLandmine := TImage.Create(frmTank);
  //Add your LandMine image to the list
  LandMines.Add(imgLandMine);

And finally in your OnTimer event you can then loop through all the LandMines using

procedure TForm3.Timer1Timer(Sender: TObject);
var I: Integer;
    //Just local TImage variable to store reference to current landmine we will be
    //working with for easier code readability
    LandMine: TImage;
begin
  //Loop through the LandMines list
  //NOTE: Since list is 0 based you should pay attention that your loop does not
  //exceed list bounds. So always use List.Count-1 end loop position
  for I := 0 to LandMines.Count-1 do
  begin
    //Retrieve reference to specific landmine image from the list and set the
    //local LandMine variable to it for easier code readability
    LandMine := TImage(LandMines[I]);
    //Update the landmine position
    LandMine.Left := Landmine.Left - iMineSpeed;
    //Check to see if the LandMine is out of viewable area so it can be destroyed
    //
    //Checking mine position after moving it to new position saves the need to use
    //if..else if clause that you used in your code example which can improve in
    //code readability
    if (LandMine.Left + LandMine.Width) < 0 then //Destroy landmine
  end;
end;

NOTE: instead of destroying your mines after they leave the viewable area you might want to just move them back to the right side changing their height position to some random value.This way you avoid having to constantly create and destroy image components which does have some performance overhead. And to avoid the feeling of mines coming at constant rate just add some random value to their left position when you reallocate them which would mean that they would come with some random delay into viewable are from the right side.


Having all the LandMines in a list will also allow you later to easily loop thought them and check their collision with your tank.

You might also want to create a similar list for your and possibly enemy projectiles. I'm guessing your game would also have these.

PS: If you want your projectiles to have different speeds you could store speed for each projectile using TImage.Tag property which is an inherited property from TComponent and allows you to store simple Integer value. And then when you are updating the position of your projectiles you read speed of each projectile from the mentioned Tag property instead from some global constant.

Heck you could even update the projectile speed in each cycle to simulate air drag affecting them if you want. Would require some clever math so that speed would not slow down too fast since Tag property is just an integer and not a Floating point value (storing initial speed multiplied by lets us say 100 and then dividing this stored speed by 100 every time to get needed movement speed without the use of Floating point values).


Anyway lists are a good way of grouping objects together into some logical collections. And yes you can have one object in multiple lists if needed since lists don't really store the objects themselves but only references to the said objects.

Just don't forget to remove your objects from the list(s) before destroying them or you will end up with your list referencing the nonexistent objects and thus running into Access Violations when trying to access such objects.

You can remove objects from list by calling List.Delete

This is easy when you are looping through a list since you already have an Index of a current item. But what to do when you don't have an index of an item but only reference to the said item? Then you use List.IndexOf method to retrieve the index of specific object in the list.


Delphi also has a TObjectList which is similar to a TList except that it can also Own the objects that are added to it.

What does this means? This means that if TObjectList is set to own the object and you Delete an object from it it will automatically notify the said object that it needs to be destroyed. But the disadvantage is that only one list can own an object at the same time. So if you are adding your object to multiple list one list may Destroy a specific object without notifying other list that the said object has been destroyed so they would reference to a nonexistent object.

SilverWarior
  • 7,372
  • 2
  • 16
  • 22
  • I think the only final point this answer is missing is that what you call the "good way" is really just applying better programming techniques to a still-bad solution. The major takeaway here is that a VCL/WinForms environment is not the right place to make a game at all. There are other frameworks out there designed specifically for making real-time interactive graphics-based programs (ie: games) and any of those would be a more suitable place to start making a game. – J... Feb 14 '22 at 13:49
  • @J... Yes VCL is not best for making games. But OP wasn't asking about that. He was asking about solving a specific problem of moving multiple objects with same timer. So I wrote an answer about solving his specific problem not paying much attention of what framework he is using for making of this game. Why? That is because his problem is not really coupled with any visual framework. In fact he would face same problem and could use same proposed solution whether he is using VCL and moving entire components around, using FMX and moving shapes around or using any game engine. ... – SilverWarior Feb 14 '22 at 16:32
  • ... In all cases the problem is "How to get group of objects and move them at the same time". And best way of doing this is grouping such objects into lists first so you can easily iterate over them. Well if you would store your game entities within a database you could get specific group of entities by performing a filtered search on the database and then loop thought those results. – SilverWarior Feb 14 '22 at 16:36
  • Also as state in his comment OP is still new at programming so he has a lot ob basics to learn especially to become a good game developer. So why is he learning basics on making a game. That is because by doing so he is also creating something that might be interesting to use after he is done even thou it won't be of best quality. So there is more motivation to actually finish this. That is why many teachers encourage beginners to learn doing fun projects like games despite the fact that in order to make a good game you need pretty good programming knowledge and also so much more. – SilverWarior Feb 14 '22 at 16:45
  • Yes, agreed with all that. Just making the point because sometimes these teachers/professors don't actually make the point of stressing that their exercises are just exercises and that nobody in their right mind would actually write a game that way in the real world. This can leave students feeling confused and frustrated, blaming themselves when they can't get things to work like they feel they should. If that's OP, it's important that they understand that this exercise, if that's what it is, has already set them up to fail. – J... Feb 14 '22 at 18:41
  • In addition to all valid points above, I want to point out that it definitely is possible (and even convenient) to create simple or modestly complex games in a VCL application. For very simple 2D games, the 80s' GDI is enough. But you probably want to use Direct2D or OpenGL. In fact, you can even use DirectX or OpenGL to create quite sophisticated 3D animations. Delphi lets you create native Win32 apps, and a `TForm` is merely a Win32 top-level window which you can treat any way you like. But if your aim is to create a GTA-style game, then Delphi isn't a good choice at all. – Andreas Rejbrand Feb 14 '22 at 19:10
  • @AndreasRejbrand I wouldn't call a D2D or OGL application a "VCL" application. It's not really using the visual component library and would really be using token `TForms` simply to host a drawable surface. I mean making a game using VCL controls in place of sprites or game objects like OP is trying to do. – J... Feb 14 '22 at 21:21
  • @J...: OK, if so I completely agree with you, of course. – Andreas Rejbrand Feb 14 '22 at 21:24
  • @AndreasRejbrand Why do you think Delphi is not a good choice at all for making a GTA-style game? If you use a game engine like [Castle Game Engine](https://castle-engine.io/) what would be stopping you to do so? Castle Game Engine does offer access to moder rendering pipeline so with some work you could reach graphic level detail comparable to that of GTA. If you are very good in Delphi programming language and not so good in others then using Delphi+CGE might be better choice than using other game engines like Unity or Unreal where you would also have have to learn new programming language. – SilverWarior Feb 15 '22 at 07:04
  • If you are working on one of the largest game companies in the world, selling many millions of copies of your game, earning tens of billions of dollars in worldwide revenue, and produce games of never-before seen graphics, AI, and scope, then you won't choose Delphi. There are many reasons: (1) Tool support etc. is better in C++. (2) Compiler and RTL performance is better in C++ (no overhead). (3) More advanced libraries and tools. (4) Easier to find the world's best programmers. (5) You are not dependent on a single company (Embarcadero). (6) You know the language will exist even in 20 y. – Andreas Rejbrand Feb 15 '22 at 07:39
  • Maybe I was a bit vague when I wrote "GTA-style". I really did intend to imply the extreme nature of such a huge project. Although a single person certainly can create a game as large as GTA V himself/herself, it likely would take her a few decades. – Andreas Rejbrand Feb 15 '22 at 07:41
  • @AndreasRejbrand While C++ is amongst most common languages used in Game Development it is actually loosing its popularity in recent years to JAVA, .NET and C#. Also we could go and argue here in comments of possible benefits of C++ over Delphi and vice versa but that is not in line with SO guidelines – SilverWarior Feb 15 '22 at 09:40
  • thanks for the answer! i actually havent checked this Q in a while and i ended up using a dynamic array anyways XD. The goal was to create a game in delphi that i could implement into the end of year project, so the program was limited to highschool delphi code, whic is very limiting. – Lucas Feb 25 '22 at 18:59