Turret fire

Hi there,

I have an object group Turrets. In it I have Turret1 and Turret2 type, each with its own defined variables to object (range, fire speed, etc).

I want to make a universal “Turret fire” code for each turret instance of any type (I would add type 3, 4, etc in the future). This is my current code (ctrl + scroll to zoom in):

Note: Create object turretplacement part is only a visual debug tool, not a part of the regular/intended code so I can see which object got selected. If there are 2 turrets of same type placed, only the first seems to be selected.

The first part works (turrets are aimed at enemy objects) but the second part doesn’t work. Even when I remove the “Turrents distance to…” it doesn’t work properly. It works for 1 turret instance of any type (turret 1 or turret 2), but if you place more than one, only one turret will shoot if e.g. 2 are placed.

Any suggestions what I’m doing wrong and a proper code that makes each turret object instance from group “Turrets” fire a bullet targeting the closest enemy (enemy object instance from group Enemy)?

P.S. Resetting the timer on “for each” is definitely not right. In standard code I used variable count, and a condition if variable count = count(Turrets) then reset timer. Since it didn’t work right, I moved it here for testing.

Thank you.

Yeah, there are some errors, but easy to fix :slight_smile:

1 - The event 6 picks the nearest Enemy to the Turret, but wich Turret?, a random one?
Then you iterate through every Turret, and check the distance against the Enemy previously selected, but that Enemy can be the nearest to another Turrent if there are more than one (because there is only one Enemy selected for every sub-event, the one selected by the parent event 6), that is way the game fails with more than one Turret.
You can fix it setting the “for each Turret” as the parent event, this way all the conditions and actions will be related to a single Turret at a time, each Turret will pick the nearest Enemy, check the distance, the timer, and shoot.

2 - About the timer, I have written about it a couple of times. The timer is a global counter, if you reset this timer because a Turret is firing, the timer will be reset for all the Turrets, because there is only one timer.
To fix it you have to add a counter variable, but it has to be an object variable, so every Turret will have its counter variable, then you have to do:

Conditions: No conditions Actions: Do + TimeDelta() to the variable counter of Turret
every frame to increase the counter, if no Turret is selected in parent events, or if this event is a parent event, it will update the counter of every Turrent, so no need to use a “for each Turret” here.
To reset the counter when firing, just set the counter variable of the shooting Turret = 0.

The fixed code should look like this (pseudo-code):

[code]Do + TimeDelta() to the variable counter of Turret

For each Turret:
Conditions: Pick the nearest Enemy to Turret.X(); Turret.Y()
Distance between Turret and Enemy is < Turret.Variable(Range)
Variable counter of Turret is > Turret.Variable(fireSpeedTimer)
Actions: Fire process
Do = 0 to the variable counter of Turret[/code]

Hope it helps, let me know if something doesn’t work as expected :slight_smile:

Thanks a bunch for the tips. I will try them out for sure. :slight_smile: You’re right regarding the timer, I previously used a global counter (before adding a reset to each step) so all turrets would fire at the same time when other things are set properly (although this wasn’t a huge issue), but each turret instance having their counter is definitely a better idea.

Just replacing the order of things seemed to resolve some of the issues, but then I got stuck a bit at Enemy instance to Turrets is below Turrets.Variable(Range). I typed a manual value instead (e.g. 500) and then it started working.

So, I went to write the value of Turrets.Variable(Range) as a text value on-screen for debugging, and found that distance for Turret1 type was 300 ,and Turret2 0 (should be 500 for both). Of course the distance can’t be smaller than 0, so Turret2 type will never shoot.

These are the defaults defined in Gdevelop editor, however, I also define the actual desired values in “At the beginning of the scene” in the External event for TurretControl attached to each level. (this handles all turret related stuff). The reason for this is so that when I make new levels (e.g. Scene2,Scene3, etc. for maps) I won’t have to recopy the objects each time some of their variables are changed (e.g. if I changed turret1range in map editor in scene1, I would also have to manually change it in scene2 and scene3, or however many scenes exist at that moment). I’m sure external layouts can also be used so that I only have one object of each type which is called (and I will consider this), but this seemed like a simple enough method, and I wanted to have the ability to manually place some objects for each map in the visual editor.

I tried assigning values like this:

(Okay, the insane amount of repetitions on Event #3 is just for testing purposes to make sure it’s not something related to timing of execution).

But to my surprise, the value of Range is still written out as 300, which is the “initial value” set in Gdevelop object variables editor. Turret2’s Range was declared but set to 0 by default (I didn’t add a custom initial value), since I expected the event to change that to the desired value, but since it was still reading 0 as range, it would never shoot, obviously.

If I remove the “at the beginning of the scene” condition, and just leave “Do =500 to variable Range of Turret2” then it does work, but of course, I don’t want this value to constantly be assigned, instead it should be once on scene beginning.

I’ve considered that maybe I cannot have multiple external events all having “At the beginning of the scene”, or multiple conditions “at the beginning of the scene” in the same scene. if you know of such an issue, please let me know. However, “Pause the current animation” and “do… to animation frame” work properly, and they are in the same condition.

I’m fairly certain that I don’t have additional code which modifies the variable Range later on and causes this issue (I have not yet implemented any saving/loading of stats and upgrade functionality, that comes later).

Do you have any idea what might cause this? It might be something very obvious which I’m missing.

To ensure that the “At the beginning of the scene” condition is the problem (it’s false), add an action like “Change scene background color”, of course if the background color is changed the problem is not the condition.

How do you link this external event?, always >> link, at the beginning of the scene >> link, or some conditions >> link?
Link an external event is the same as copying the external event code and pasting it instead the link event, so if you do:

Conditions: Time from start is > 10 seconds Link to "Turrets logic"
If the “Turrets logic” external event has some event with conditions “At the beginning of the scene”, this event will never run, because the condition “At the beginning of the scene” will never be true as the game has started 10 seconds ago.

If the other actions work (pause animation, set frame), maybe there is a typing error in the variable name, an extra whitespace, upper/lowercase, etc. and instead modifying or reading the Range variable, you are creating a new variable Range’ :confused:

I try to give options because GD failing in such basic things is not common, but it can happen I think :neutral_face:

Thanks a lot for the further help. I will definitely experiment and let you know, I think I might have some clues about potential causes, but the latest project version (and backup file) is now corrupted for some reason, so I have to redo some of the work first from an older backup. It can all be done within a day, but I need to get back to this point first.

Okay, I think I figured out the issue, and want to post about it in case anyone else experiences a similar problem.

This is my understanding only without looking at source code, it could be wrong.

In my game, I have this kind of standard mechanism:

Player selects a spot, purchases a turret, and a turret is placed on the selected position (where to place the turret is guided by ID of the selected turret placement spot, ID is written manually as a local variable to each turret placement spot instance).

The purchased turret instance uses local object variables to store information, such as firing range (when to start/stop shooting at enemy), firing speed, etc. Currently not all parts are implemented correctly.

Anyway, you can’t change the initial object variable programatically, unless you do it in the scene editor or gdg file manually. You need to set the variables for each instance after the instance gets created.

The way I solved it for now is something like this:

Where TurretVariables event looks like:

(Turret1 is the Turret type 1, but all turret types will get grouped into a group called Turrets, so I will use this group instead of accessing each type once I recreate my code, just like in the previous posts).

Hopefully, this can help a bit.

True, I thought the turrets were already in scene before the actions to change the Range at the beginning of the scene. But the turrets are created after that, good to know you have catched it :smiley:

Yes, create the instance and then modify its variables is the common way. Of course you can set the turrets initial values in the scene editor too :slight_smile: