Improved the collision logic of bullets.

改进子弹的碰撞逻辑。
This commit is contained in:
Cold-Mint 2024-08-12 22:30:13 +08:00
parent ef58f3885b
commit 3b2ba7440c
Signed by: Cold-Mint
GPG Key ID: C5A9BF8A98E0CE99
8 changed files with 87 additions and 75 deletions

View File

@ -24,7 +24,9 @@ animations = [{
[node name="Player" type="CharacterBody2D"] [node name="Player" type="CharacterBody2D"]
collision_layer = 4 collision_layer = 4
collision_mask = 34 collision_mask = 162
platform_floor_layers = 4294967042
platform_wall_layers = 128
script = ExtResource("1_1dlls") script = ExtResource("1_1dlls")
MaxHp = 32 MaxHp = 32
CampId = "Default" CampId = "Default"

View File

@ -9,16 +9,20 @@
radius = 11.0 radius = 11.0
[node name="curseOfTheUndead" type="CharacterBody2D"] [node name="curseOfTheUndead" type="CharacterBody2D"]
collision_layer = 0 collision_layer = 16
collision_mask = 0 collision_mask = 102
slide_on_ceiling = false
platform_floor_layers = 4294967042
platform_wall_layers = 32
script = ExtResource("1_ib3qh") script = ExtResource("1_ib3qh")
Life = 5000 Life = 5000
Durability = 1.0 Durability = 3.0
MaxDamage = 3 MaxDamage = 3
MinDamage = 10 MinDamage = 10
DamageType = 2 DamageType = 2
KnockbackForce = Vector2(2, -3) KnockbackForce = Vector2(2, -3)
Speed = 500.0 Speed = 300.0
EnableBounce = true
[node name="CollisionShape2D" type="CollisionShape2D" parent="."] [node name="CollisionShape2D" type="CollisionShape2D" parent="."]
shape = SubResource("CircleShape2D_dgro2") shape = SubResource("CircleShape2D_dgro2")

View File

@ -28,7 +28,7 @@ shape = SubResource("CircleShape2D_dgro2")
[node name="CollisionDetectionArea" type="Area2D" parent="."] [node name="CollisionDetectionArea" type="Area2D" parent="."]
collision_layer = 16 collision_layer = 16
collision_mask = 78 collision_mask = 206
[node name="CollisionShape2D" type="CollisionShape2D" parent="CollisionDetectionArea"] [node name="CollisionShape2D" type="CollisionShape2D" parent="CollisionDetectionArea"]
shape = SubResource("CircleShape2D_8117d") shape = SubResource("CircleShape2D_8117d")

View File

@ -151,12 +151,13 @@ locale/translations=PackedStringArray("res://locals/DeathInfo.en.translation", "
[layer_names] [layer_names]
2d_physics/layer_1="RoomArea" 2d_physics/layer_1="RoomArea"
2d_physics/layer_2="Ground" 2d_physics/layer_2="Floor"
2d_physics/layer_3="Player" 2d_physics/layer_3="Player"
2d_physics/layer_4="PickAbleItem" 2d_physics/layer_4="PickAbleItem"
2d_physics/layer_5="Projectile" 2d_physics/layer_5="Projectile"
2d_physics/layer_6="Platform" 2d_physics/layer_6="Platform"
2d_physics/layer_7="Mob" 2d_physics/layer_7="Mob"
2d_physics/layer_8="Wall"
[physics] [physics]

View File

@ -425,12 +425,13 @@ public static class Config
public static class LayerNumber public static class LayerNumber
{ {
public const int RoomArea = 1; public const int RoomArea = 1;
public const int Ground = 2; public const int Floor = 2;
public const int Player = 3; public const int Player = 3;
public const int PickAbleItem = 4; public const int PickAbleItem = 4;
public const int Projectile = 5; public const int Projectile = 5;
public const int Platform = 6; public const int Platform = 6;
public const int Mob = 7; public const int Mob = 7;
public const int Wall = 8;
} }
/// <summary> /// <summary>

View File

@ -286,7 +286,6 @@ public partial class CharacterTemplate : CharacterBody2D
_healthBar.MaxValue = MaxHp; _healthBar.MaxValue = MaxHp;
} }
ItemMarker2D = GetNode<Marker2D>("ItemMarker2D"); ItemMarker2D = GetNode<Marker2D>("ItemMarker2D");
_itemMarkerOriginalX = ItemMarker2D.Position.X; _itemMarkerOriginalX = ItemMarker2D.Position.X;
_animatedSprite2D = GetNode<AnimatedSprite2D>("AnimatedSprite2D"); _animatedSprite2D = GetNode<AnimatedSprite2D>("AnimatedSprite2D");
@ -303,6 +302,11 @@ public partial class CharacterTemplate : CharacterBody2D
_pickingArea.BodyEntered += EnterThePickingRangeBody; _pickingArea.BodyEntered += EnterThePickingRangeBody;
_pickingArea.BodyExited += ExitThePickingRangeBody; _pickingArea.BodyExited += ExitThePickingRangeBody;
} }
//The character cannot pass through the wall and floor
//角色不能穿过墙壁和地板
SetCollisionMaskValue(Config.LayerNumber.Wall, true);
SetCollisionMaskValue(Config.LayerNumber.Floor, true);
} }
/// <summary> /// <summary>
@ -389,7 +393,8 @@ public partial class CharacterTemplate : CharacterBody2D
pickAbleTemplate.Owner = this; pickAbleTemplate.Owner = this;
pickAbleTemplate.Picked = true; pickAbleTemplate.Picked = true;
pickAbleTemplate.SetCollisionMaskValue(Config.LayerNumber.Platform, false); pickAbleTemplate.SetCollisionMaskValue(Config.LayerNumber.Platform, false);
pickAbleTemplate.SetCollisionMaskValue(Config.LayerNumber.Ground, false); pickAbleTemplate.SetCollisionMaskValue(Config.LayerNumber.Floor, false);
pickAbleTemplate.SetCollisionMaskValue(Config.LayerNumber.Wall, false);
LogCat.Log("item_pickup_disables_collision_damage", LogCat.LogLabel.ContactInjury); LogCat.Log("item_pickup_disables_collision_damage", LogCat.LogLabel.ContactInjury);
pickAbleTemplate.EnableContactInjury = false; pickAbleTemplate.EnableContactInjury = false;
pickAbleTemplate.Sleeping = true; pickAbleTemplate.Sleeping = true;
@ -759,7 +764,8 @@ public partial class CharacterTemplate : CharacterBody2D
//仍出武器时,我们不能立即恢复物理碰撞,立即恢复会导致武器更早的与地面和平台碰撞,阻止武器的飞行。 //仍出武器时,我们不能立即恢复物理碰撞,立即恢复会导致武器更早的与地面和平台碰撞,阻止武器的飞行。
pickAbleTemplate.EnableContactInjury = true; pickAbleTemplate.EnableContactInjury = true;
LogCat.Log("item_thrown_restore_collision_damage", LogCat.LogLabel.ContactInjury); LogCat.Log("item_thrown_restore_collision_damage", LogCat.LogLabel.ContactInjury);
pickAbleTemplate.SetCollisionMaskValue(Config.LayerNumber.Ground, true); pickAbleTemplate.SetCollisionMaskValue(Config.LayerNumber.Floor, true);
pickAbleTemplate.SetCollisionMaskValue(Config.LayerNumber.Wall, true);
pickAbleTemplate.SetCollisionMaskValue(Config.LayerNumber.Platform, true); pickAbleTemplate.SetCollisionMaskValue(Config.LayerNumber.Platform, true);
timer.QueueFree(); timer.QueueFree();
}; };

View File

@ -19,8 +19,7 @@ public partial class Projectile : CharacterBody2D
/// <para>life(ms)</para> /// <para>life(ms)</para>
/// <para>子弹的存在时间(毫秒)</para> /// <para>子弹的存在时间(毫秒)</para>
/// </summary> /// </summary>
[Export] [Export] public long Life;
public long Life;
//The durability of the projectile //The durability of the projectile
//抛射体的耐久度 //抛射体的耐久度
@ -38,13 +37,6 @@ public partial class Projectile : CharacterBody2D
/// </summary> /// </summary>
private DateTime? _destructionTime; private DateTime? _destructionTime;
/// <summary>
/// <para>The impact area of the bullet</para>
/// <para>子弹的碰撞区域</para>
/// </summary>
private Area2D? _area2D;
/// <summary> /// <summary>
/// <para>knockback</para> /// <para>knockback</para>
/// <para>击退</para> /// <para>击退</para>
@ -53,11 +45,22 @@ public partial class Projectile : CharacterBody2D
///<para>How much force does it have when hitting the character? Unit: Number of cellsThe X direction of the force is inferred automatically.</para> ///<para>How much force does it have when hitting the character? Unit: Number of cellsThe X direction of the force is inferred automatically.</para>
///<para>当击中角色时带有多大的力单位格数力的X方向是自动推断的。</para> ///<para>当击中角色时带有多大的力单位格数力的X方向是自动推断的。</para>
/// </remarks> /// </remarks>
[Export] [Export] public Vector2 KnockbackForce;
public Vector2 KnockbackForce;
[Export] public float Speed; [Export] public float Speed;
/// <summary>
/// <para>Whether it bounces back after hitting an enemy or a wall</para>
/// <para>是否撞到敌人或墙壁后反弹</para>
/// </summary>
[Export] public bool EnableBounce;
/// <summary>
/// <para>Can it penetrate the wall</para>
/// <para>是否可以穿透墙壁</para>
/// </summary>
[Export] public bool IgnoreWall;
private List<IProjectileDecorator>? _projectileDecorators; private List<IProjectileDecorator>? _projectileDecorators;
@ -69,12 +72,6 @@ public partial class Projectile : CharacterBody2D
public override void _Ready() public override void _Ready()
{ {
//The bullet's impact detection area
//子弹的碰撞检测区域
_area2D = GetNode<Area2D>("CollisionDetectionArea");
_area2D.Monitoring = true;
_area2D.BodyEntered += OnBodyEnter;
_area2D.BodyExited += OnBodyExited;
//If the existence time is less than or equal to 0, then it is set to exist for 10 seconds, and projectiles that exist indefinitely are prohibited //If the existence time is less than or equal to 0, then it is set to exist for 10 seconds, and projectiles that exist indefinitely are prohibited
//如果存在时间小于等于0那么设置为存在10秒禁止无限期存在的抛射体 //如果存在时间小于等于0那么设置为存在10秒禁止无限期存在的抛射体
if (Life <= 0) if (Life <= 0)
@ -83,6 +80,11 @@ public partial class Projectile : CharacterBody2D
} }
_destructionTime = DateTime.Now.AddMilliseconds(Life); _destructionTime = DateTime.Now.AddMilliseconds(Life);
SetCollisionMaskValue(Config.LayerNumber.Wall, !IgnoreWall);
SetCollisionMaskValue(Config.LayerNumber.Floor, !IgnoreWall);
//Platform collision layer is not allowed to collide
//平台碰撞层不可碰撞
SetCollisionMaskValue(Config.LayerNumber.Platform, false);
} }
/// <summary> /// <summary>
@ -247,45 +249,6 @@ public partial class Projectile : CharacterBody2D
} }
} }
/// <summary>
/// <para>When the bullet is in contact with the node</para>
/// <para>当子弹与节点接触时</para>
/// </summary>
/// <param name="node"></param>
protected virtual void OnBodyEnter(Node2D node)
{
//Here we test whether harm is allowed, notice that for TileMap, we directly allow harm.
//这里我们检测是否允许造成伤害注意对于TileMap我们直接允许造成伤害。
var canCauseHarm = CanCauseHarm(Owner, node);
if (!canCauseHarm)
{
return;
}
DoDamage(Owner, node);
//Please specify in the Mask who the bullet will collide with
//请在Mask内配置子弹会和谁碰撞
//When a bullet hits an object, its durability decreases
//子弹撞击到物体时,耐久度减少
Durability--;
if (Durability <= 0)
{
//When the durability is less than or equal to 0, destroy the bullet
//当耐久度小于等于0时销毁子弹
QueueFree();
}
}
/// <summary>
/// <para>When the bullet leaves the node</para>
/// <para>当子弹离开节点时</para>
/// </summary>
/// <param name="node"></param>
protected virtual void OnBodyExited(Node2D node)
{
}
/// <summary> /// <summary>
/// <para>When beyond the time of existence</para> /// <para>When beyond the time of existence</para>
/// <para>当超过存在时间</para> /// <para>当超过存在时间</para>
@ -307,6 +270,38 @@ public partial class Projectile : CharacterBody2D
public override void _PhysicsProcess(double delta) public override void _PhysicsProcess(double delta)
{ {
MoveAndSlide(); var collisionInfo = MoveAndCollide(Velocity * (float)delta);
if (collisionInfo != null)
{
//Bump into other objects.
//撞到其他对象。
if (EnableBounce)
{
Velocity = Velocity.Bounce(collisionInfo.GetNormal());
}
//Here we test whether harm is allowed, notice that for TileMap, we directly allow harm.
//这里我们检测是否允许造成伤害注意对于TileMap我们直接允许造成伤害。
var godotObject = collisionInfo.GetCollider();
var node = (Node2D)godotObject;
var canCauseHarm = CanCauseHarm(Owner, node);
if (!canCauseHarm)
{
return;
}
DoDamage(Owner, node);
//Please specify in the Mask who the bullet will collide with
//请在Mask内配置子弹会和谁碰撞
//When a bullet hits an object, its durability decreases
//子弹撞击到物体时,耐久度减少
Durability--;
if (Durability <= 0)
{
//When the durability is less than or equal to 0, destroy the bullet
//当耐久度小于等于0时销毁子弹
QueueFree();
}
}
} }
} }

View File

@ -6,14 +6,14 @@
texture = ExtResource("1_4c2am") texture = ExtResource("1_4c2am")
texture_region_size = Vector2i(32, 32) texture_region_size = Vector2i(32, 32)
0:0/0 = 0 0:0/0 = 0
0:0/0/physics_layer_0/polygon_0/points = PackedVector2Array(-16, -16, 16, -16, 16, 16, -16, 16) 0:0/0/physics_layer_2/polygon_0/points = PackedVector2Array(-16, -16, 16, -16, 16, 16, -16, 16)
1:0/0 = 0 1:0/0 = 0
1:0/0/physics_layer_0/polygon_0/points = PackedVector2Array(-16, -16, 16, -16, 16, 16, -16, 16) 1:0/0/physics_layer_0/polygon_0/points = PackedVector2Array(-16, -16, 16, -16, 16, 16, -16, 16)
1:1/0 = 0 1:1/0 = 0
2:1/0 = 0 2:1/0 = 0
2:1/0/physics_layer_0/polygon_0/points = PackedVector2Array(-16, -16, 16, -16, 16, 16, -16, 16) 2:1/0/physics_layer_2/polygon_0/points = PackedVector2Array(-16, -16, 16, -16, 16, 16, -16, 16)
2:2/0 = 0 2:2/0 = 0
2:2/0/physics_layer_0/polygon_0/points = PackedVector2Array(-16, -16, 16, -16, 16, 16, -16, 16) 2:2/0/physics_layer_2/polygon_0/points = PackedVector2Array(-16, -16, 16, -16, 16, 16, -16, 16)
3:2/0 = 0 3:2/0 = 0
3:4/0 = 0 3:4/0 = 0
3:4/0/physics_layer_1/polygon_0/points = PackedVector2Array(-16, -16, 16, -16, 16, -6.75, 8.25, -6, 7, -2.25, 1, -2, -16, 16) 3:4/0/physics_layer_1/polygon_0/points = PackedVector2Array(-16, -16, 16, -16, 16, -6.75, 8.25, -6, 7, -2.25, 1, -2, -16, 16)
@ -27,17 +27,18 @@ texture_region_size = Vector2i(32, 32)
1:3/0 = 0 1:3/0 = 0
1:3/0/physics_layer_0/polygon_0/points = PackedVector2Array(-16, -16, 16, -16, 16, 16, -16, 16) 1:3/0/physics_layer_0/polygon_0/points = PackedVector2Array(-16, -16, 16, -16, 16, 16, -16, 16)
1:2/0 = 0 1:2/0 = 0
1:2/0/physics_layer_0/polygon_0/points = PackedVector2Array(-16, -16, 16, -16, 16, 16, -16, 16) 1:2/0/physics_layer_2/polygon_0/points = PackedVector2Array(-16, -16, 16, -16, 16, 16, -16, 16)
0:2/0 = 0 0:2/0 = 0
0:2/0/physics_layer_0/polygon_0/points = PackedVector2Array(-16, -16, 16, -16, 16, 16, -16, 16) 0:2/0/physics_layer_0/polygon_0/points = PackedVector2Array(-16, -16, 16, -16, 16, 16, -16, 16)
0:2/0/physics_layer_2/polygon_0/points = PackedVector2Array(-16, -16, 16, -16, 16, 16, -16, 16)
0:1/0 = 0 0:1/0 = 0
0:1/0/physics_layer_0/polygon_0/points = PackedVector2Array(-16, -16, 16, -16, 16, 16, -16, 16) 0:1/0/physics_layer_2/polygon_0/points = PackedVector2Array(-16, -16, 16, -16, 16, 16, -16, 16)
2:3/0 = 0 2:3/0 = 0
2:3/0/physics_layer_0/polygon_0/points = PackedVector2Array(-16, -16, 16, -16, 16, 16, -16, 16) 2:3/0/physics_layer_0/polygon_0/points = PackedVector2Array(-16, -16, 16, -16, 16, 16, -16, 16)
3:1/0 = 0 3:1/0 = 0
3:0/0 = 0 3:0/0 = 0
2:0/0 = 0 2:0/0 = 0
2:0/0/physics_layer_0/polygon_0/points = PackedVector2Array(-16, -16, 16, -16, 16, 16, -16, 16) 2:0/0/physics_layer_2/polygon_0/points = PackedVector2Array(-16, -16, 16, -16, 16, 16, -16, 16)
4:0/0 = 0 4:0/0 = 0
4:1/0 = 0 4:1/0 = 0
5:0/0 = 0 5:0/0 = 0
@ -86,4 +87,6 @@ physics_layer_0/collision_layer = 2
physics_layer_0/collision_mask = 0 physics_layer_0/collision_mask = 0
physics_layer_1/collision_layer = 32 physics_layer_1/collision_layer = 32
physics_layer_1/collision_mask = 0 physics_layer_1/collision_mask = 0
physics_layer_2/collision_layer = 128
physics_layer_2/collision_mask = 0
sources/1 = SubResource("TileSetAtlasSource_abxy2") sources/1 = SubResource("TileSetAtlasSource_abxy2")