Source dependent immunity frames / Check each child in an object array

Greetings,

I have a bit of a complex issue to share this time around.

Terraria 1.4 added a new immunity frame system, which ensures that each enemy can be hit by each projectile no matter what, to increase the effectiveness of many piercing weapons. For more information, look here, and read up on Local Immunity: Invincibility frame - Official Terraria Wiki

Anyways, I’m trying to replicate this in my game with uhhhh, not ideal results… It shouldn’t be doing that much damage.
issue

So basically, my thought process:

  • Every single attack is given a UID.
  • If an enemy is hit by an attack, the attack’s UID is stored temporarily in an array that the enemy has (immuneQueue in this case).
  • The enemy CANNOT be harmed by the attack if it has the attack’s UID stored in it’s array.
  • However, after a very brief amount of time passes (1/6th of a second), that UID is cleared out, and the enemy can be hit by that same projectile again.
  • This is done for each child.

So I got to work and made this code, which of course, didn’t really work (Resulting in the GIF above):

After some debugging, I found out that EVERY child is cleaned out at once when the timer expires. So I tried to look for a solution to this. Maybe if I made the code check for every child in the array! That’s gotta work!

…oh…

It’s for global and scene variables only…

I tried using a structure variable instead, but sadly, the actions to remove the oldest child didn’t work out for me…

So uh… I’m kinda stuck here

If I could get the code to check for each child in the array individually, then maybe I could get it working. The only issue is HOW do I check for each child in an object array when the option to do so for object variables doesn’t seem to be present?

These links might help.

I helped someone do something similar
https://forum.gdevelop.io/t/projectile-piercing-not-working/54443/2?u=keith_1357

If I’m remembering correctly and understand your project, I think I used reversed logic. I had the projectile store the IDs. So, the bullet only hit each object once. The bullet would eventually be deleted, so the array didn’t have to be reset.

I also request that for each child would work with objects. I inuded a few workarounds on the bottom.
https://forum.gdevelop.io/t/use-for-each-child-event-with-object-variables/60680

Hmmmm, while the first suggestion certainly does work, it’s not quite what I’m looking for.

See, I want each child to remove itself from the array after a short time passes, which gives the enemy a chance to be hurt by the same projectile a multiple times.

In Terraria, things like minions count as projectiles, and rely on being able to hit multiple times. If they only hit once, they’re largely ineffective. While this may work for fast moving bullets, the scope of what I’m planning needs each bullet to be able to hit multiple times after a delay.

Adding an enemy ID to the bullet is an interesting idea, but if I do that, I would need to do the same thing to clear the ENEMY’S UID out of the bullet’s array, and I’m right back where I started.

Oh yeah, additionally, this is the player’s attack:
image

The player’s attack also counts as a projectile. It’s thrown at enemies, but when it hits a wall, it’s recalled to the player to be thrown again.

If the enemies add the player attack’s UID to their list and it’s never cleared out, then the enemies become fully immune to the attack after being hit just once.

I know it’s probably an easy fix for the player attack specifically, but I would like to try and iron this out for all projectiles so I don’t have to worry about it later for other attacks.


Anyways, I’ve noticed that in your workarounds, you added your array into a scene variable so code for each child can be checked individually.

It’s a clever solution, although, I don’t know how a scene array would be able to check the array for each individual object.

Is there nothing I can do to properly run code for each child of an object variable to determine it’s invulnerability? Or will I have to think outside the box more?

Currently, I’m thinking that maybe, just maybe, if I give each enemy a UID too, when the enemy is hit, I can add their UID to the scene array, and their UID can also be arrays that hold the UIDs of the bullets they were just hit by. An array of arrays, basically. Would that be viable? Or do you have a better idea?

EDIT: I tried to test this idea, but I’ve run into another issue
image
See, I’m trying to add the enemy’s UID to a scene variable as an array (Which will hold the UIDs of the bullets it was hit by), but there’s no option to add a value to an array AS an array…

Is there any way I can do this? Or am I just gonna have to hope for an update that adds child checking for object variables?

You reference array indexes with brackets.

ArrayName[number] = 10

The number can be a number, variable (including object variable) or any expression that returns a number.

You can create multidimensional arrays just like children in a structure by adding another set of brackets.

Variable [0] [0] = 123
Variable [0] [0] [1] = 123

You don’t need all of the spaces, I just wanted it to be clearer.

Here’s a couple of screenshots

Just remember it will create indexes if you try to read one so if in doubt use the count the number of children condition first.

I think I came up with an easier approach. I’m not sure on how to make it fit your project. This uses an object structure instead of array. The structure is in the Player, it might make more sense to be in the bullet. You can check the post history for my previous reply.

It saves the time and only checks the time when there’s a collision. So, there’s no constant updating. It’s a bit like separate timers.

Try me. Click the button to fire.
https://gd.games/instant-builds/b8d6ec29-5047-4db5-ac8f-128d47a7b183


(I guess the first and condition isn’t need. It needs the condition inside it just not the and. The child either doesn’t exit or (exists and a certain amount of time has passed)

Instead of an array, it uses a structure. It checks if the ID is in the structure exists. (Since structure child names need to be strings, it uses a ID that is a string) , it sets the child’s value to the time since the start. If the child exists it compares the child value to the current time. If a second has passed or the child doesn’t exit it sets the child to the current time since start. Now, that I think about it. The child should probabl|y be set to the time +. How many other seconds instead of adding the time later.

When the bullet is deleted, it removed the child. This part is a bit fuzzy because I don’t understand the whole range of your project. You may want this on the bullet instead of the character. Or maybe as a scene variable.| That’s up to you.

1 Like

I’m not quite understanding the index process. Do I need to add a bunch of indexes for each bullet that could theoretically hit the enemy like this?
image
Or maybe I’m just stupid, since you provided an example of how it’s used in your improved example below. Speaking of…


I tried out the simpler solution, and so far, it seems to work just like the previous code did, and…
…it works! It works perfectly! The damage is being distributed just like it does in Terraria!
I can’t exactly wrap my head around what TimeFromStart() is doing to make this work, especially when it compares itself to the child variable (Considering it compares the time from the beginning of the scene), so if you could briefly provide an explanation of what part TimeFromStart() is truly playing here, I’d greatly appreciate it.

Anyways, here’s the new code:

I’d still like for the children to remove themselves from the structure if it can be helped, as I’m afraid this may allegedly have an impact on performance?

I noticed how you mentioned that the children get deleted when the attack is deleted, I may try that out if there’s no better solution I could find.

Anyways, it works exactly like I want it to now, but is there still another way to remove each child from the structure individually after a certain amount of time? Or is it nothing I need to worry about and can just leave as is?

Thanks for the suggestion too!!

EDIT: Alright, so all these variables being added DOES have an impact on performance, so I added code that deletes the child when the attack “dies.”

It appears to be working quite well. Thanks again!

TimeFromStart() is used like a timer but unlike a regular timer it only gets checked when a collision happens. It’s used to track how much time has passed compared to time stored in the structure.

It sets the time the collision happens. The next time it collides it checks if the TimeFromStart() is greater than that time + a delay. It might be better to set the time for the variable to TimeFromStart()+delay instead of TimeFromStart() then it wouldn’t have to add the delay time in the compare condition. It could use if TimeFromStart() >= the Structure variable.

Anyways.
If the collision happens at a time of 100 then it stores 100
The next time it collides it checks if TimeFromStart() >= 100+the delay amount. So say, 102. If it was a 2 second delay. Is the time > the previous time plus the delay amount.

I would take the Boolean check and collision out of the for each object. Maybe that whole first section.

Check the Boolean and then check the collision and then only use the for each object on those objects instead of all of the objects.

You might want to check if it’s dead first and then the Boolean checks and then the collision. IDK. I would profile it both ways and see if it changes the time the event uses.

Collision check uses more resources. So, it can help if you can narrow down the objects that get checked.

As to whether my concept is the most efficient way? I have no idea. I don’t know how many objects you’re using. I don’t know how efficient variable structures are. It might be a simpler approach. I honestly don’t know.

1 Like