I want to add an upgradeable skill to fired bullets: Penetration Attack.
I plan to use the bullet’s HP to represent the number of penetration instances. When penetration is no longer possible, HP is set to 1; each additional possible penetration increases HP by 1. (When penetration occurs, HP decreases by 1.)
In AGM version 1.2.3, a new feature was added: “Deal damage to the same object only once.” Using this feature effectively solves the issue where, when a bullet collides with an enemy, that enemy takes damage only once. If the bullet does not disappear afterward, it can continue to damage the next enemy.
However, this feature does not address the detection of attack collisions. For example, if a bullet can penetrate twice, it deals damage on the first penetration, then again on the second, after which it should disappear. But without a similar feature such as “Collide with the same object only once,” when the bullet hits the first enemy, although it only deals damage once, the collision detection with that enemy continues to occur repeatedly.
As a result, it is impossible to implement the functionality of limiting the bullet to exactly X penetrations using the bullet’s HP. While damage to the enemy is correctly limited to once per hit, the continuous collision causes the bullet’s HP to decrease repeatedly, rather than only once per attack.
Therefore, the previous feature only solved “Deal damage to the same object only once,” but did not truly solve “Collide with the same object only once.”
Feature Request:
Please consider adding a new feature in the official AGM: “Trigger attack collision with the same object only once,” to complement the existing “Deal damage only once” feature.
If this feature cannot be added immediately, could you please provide a method to implement this functionality?
After some thought, I implemented this feature using signals and GDScript, and I’m sharing it first.
(1) Core technology: Godot’s native signal detection — area_entered. (Have the attack box send a signal directly to a GDScript.)
This signal triggers when an Area2D enters its detection range.
Advantage: Once an area enters the range, the signal is sent only once. So, in the weapon’s attack range, if Enemy A enters and doesn’t leave, the signal triggers only once. When Enemy B enters, it can trigger the signal again. Two enemies entering the detection zone do not conflict with each other. This naturally avoids continuous attack detection.
Add a condition in this signal so it triggers only when an “Enemy” group member enters.
(2) You can use a variable to track the number of penetration hits. Here, I directly bound it to the object’s HP value, so that in AGM’s object property settings, the object can disappear automatically once its stamina (HP) is depleted. (More convenient.)
(3) After the signal triggers, simply decrement the penetration value by 1. When it reaches 0, the weapon is destroyed.
Core code: (Note: This assumes penetration is bound to the object’s HP so it can be accessed. If you don’t use HP, you can declare any variable.)
func _on_攻击盒_area_entered(area: Area2D) → void:
var penetration = variable.get_value(“hp”)
if area.is_in_group(“Enemy”):
penetration -= 1
variable.set_value(“hp”, penetration)
Using the area_entered signal to detect hits isn’t perfect. Occasionally, when a bullet just grazes an enemy, the hitbox correctly registers the enemy as hit, but the bullet using area_entered fails to detect the collision. So, in actual game development, this approach has a small bug. We’re still hoping the official team will provide a dedicated feature for this. For now, the only workaround is to make the bullet briefly invulnerable so it doesn’t keep taking damage. (This is a conservative fix.)