Projectiles can now track enemies.

抛射体可以跟踪敌人了。
This commit is contained in:
Cold-Mint 2024-08-18 16:09:31 +08:00
parent 8c02a0548c
commit 2a5629fc86
Signed by: Cold-Mint
GPG Key ID: C5A9BF8A98E0CE99
11 changed files with 116 additions and 15 deletions

View File

@ -98,3 +98,11 @@ collision_mask = 76
[node name="CollisionShape2D" type="CollisionShape2D" parent="ScoutArea2D"] [node name="CollisionShape2D" type="CollisionShape2D" parent="ScoutArea2D"]
shape = SubResource("CircleShape2D_fowd5") shape = SubResource("CircleShape2D_fowd5")
[node name="TipLabel" type="Label" parent="."]
offset_left = -20.0
offset_top = 46.0
offset_right = 15.0
offset_bottom = 71.0
text = "name"
horizontal_alignment = 1

View File

@ -99,3 +99,14 @@ collision_mask = 76
[node name="CollisionShape2D" type="CollisionShape2D" parent="ScoutArea2D"] [node name="CollisionShape2D" type="CollisionShape2D" parent="ScoutArea2D"]
shape = SubResource("CircleShape2D_fowd5") shape = SubResource("CircleShape2D_fowd5")
[node name="TipLabel" type="Label" parent="."]
anchors_preset = 5
anchor_left = 0.5
anchor_right = 0.5
offset_left = -57.0
offset_top = 57.0
offset_right = 61.0
offset_bottom = 82.0
grow_horizontal = 2
horizontal_alignment = 1

View File

@ -16,8 +16,6 @@ platform_floor_layers = 4294967042
platform_wall_layers = 32 platform_wall_layers = 32
script = ExtResource("1_ib3qh") script = ExtResource("1_ib3qh")
Speed = 300.0 Speed = 300.0
IgnoreWall = true
EnableTracking = true
[node name="CollisionShape2D" type="CollisionShape2D" parent="."] [node name="CollisionShape2D" type="CollisionShape2D" parent="."]
shape = SubResource("CircleShape2D_dgro2") shape = SubResource("CircleShape2D_dgro2")

View File

@ -14,8 +14,10 @@ _durability = 1.0
_maxDamage = 10 _maxDamage = 10
_minDamage = 1 _minDamage = 1
_damageType = 2 _damageType = 2
_knockbackForce = Vector2(60, 0) _knockBackForce = Vector2(0, 1)
Speed = 500.0 Speed = 500.0
_enableTracking = true
_targetDiesDestroyProjectile = true
[node name="CurseOfTheUndead" type="Sprite2D" parent="."] [node name="CurseOfTheUndead" type="Sprite2D" parent="."]
texture = ExtResource("1_k8el6") texture = ExtResource("1_k8el6")

View File

@ -12,8 +12,3 @@ texture_under = ExtResource("1_sc0v3")
texture_over = ExtResource("2_ay5vh") texture_over = ExtResource("2_ay5vh")
texture_progress = ExtResource("2_s0gle") texture_progress = ExtResource("2_s0gle")
script = ExtResource("4_84gre") script = ExtResource("4_84gre")
[node name="Label" type="Label" parent="."]
layout_mode = 0
offset_right = 40.0
offset_bottom = 23.0

View File

@ -21,6 +21,7 @@ anchor_right = 1.0
anchor_bottom = 1.0 anchor_bottom = 1.0
grow_horizontal = 2 grow_horizontal = 2
grow_vertical = 2 grow_vertical = 2
mouse_filter = 2
[node name="VBoxContainer" type="VBoxContainer" parent="CanvasLayer/Control"] [node name="VBoxContainer" type="VBoxContainer" parent="CanvasLayer/Control"]
layout_mode = 1 layout_mode = 1
@ -34,25 +35,31 @@ offset_right = -20.0
offset_bottom = -20.0 offset_bottom = -20.0
grow_horizontal = 2 grow_horizontal = 2
grow_vertical = 0 grow_vertical = 0
mouse_filter = 2
[node name="HealthBarUi" type="HBoxContainer" parent="CanvasLayer/Control/VBoxContainer"] [node name="HealthBarUi" type="HBoxContainer" parent="CanvasLayer/Control/VBoxContainer"]
layout_mode = 2 layout_mode = 2
mouse_filter = 2
script = ExtResource("2_xrm3v") script = ExtResource("2_xrm3v")
[node name="TextureRect3" type="TextureRect" parent="CanvasLayer/Control/VBoxContainer/HealthBarUi"] [node name="TextureRect3" type="TextureRect" parent="CanvasLayer/Control/VBoxContainer/HealthBarUi"]
layout_mode = 2 layout_mode = 2
mouse_filter = 2
texture = ExtResource("2_n1yht") texture = ExtResource("2_n1yht")
[node name="HotBar" type="HBoxContainer" parent="CanvasLayer/Control/VBoxContainer"] [node name="HotBar" type="HBoxContainer" parent="CanvasLayer/Control/VBoxContainer"]
layout_mode = 2 layout_mode = 2
mouse_filter = 2
script = ExtResource("2_owrhq") script = ExtResource("2_owrhq")
[node name="TextureRect3" type="TextureRect" parent="CanvasLayer/Control/VBoxContainer/HotBar"] [node name="TextureRect3" type="TextureRect" parent="CanvasLayer/Control/VBoxContainer/HotBar"]
layout_mode = 2 layout_mode = 2
mouse_filter = 2
texture = ExtResource("2_n1yht") texture = ExtResource("2_n1yht")
[node name="OperationTip" type="RichTextLabel" parent="CanvasLayer/Control/VBoxContainer"] [node name="OperationTip" type="RichTextLabel" parent="CanvasLayer/Control/VBoxContainer"]
layout_mode = 2 layout_mode = 2
mouse_filter = 2
bbcode_enabled = true bbcode_enabled = true
fit_content = true fit_content = true

View File

@ -9,6 +9,7 @@ anchor_right = 1.0
anchor_bottom = 1.0 anchor_bottom = 1.0
grow_horizontal = 2 grow_horizontal = 2
grow_vertical = 2 grow_vertical = 2
mouse_filter = 2
script = ExtResource("1_vj6du") script = ExtResource("1_vj6du")
[node name="ColorRect" type="ColorRect" parent="."] [node name="ColorRect" type="ColorRect" parent="."]
@ -18,6 +19,7 @@ anchor_right = 1.0
anchor_bottom = 1.0 anchor_bottom = 1.0
grow_horizontal = 2 grow_horizontal = 2
grow_vertical = 2 grow_vertical = 2
mouse_filter = 2
color = Color(0.941176, 0.243137, 0.243137, 0.258824) color = Color(0.941176, 0.243137, 0.243137, 0.258824)
[node name="CenterContainer" type="CenterContainer" parent="."] [node name="CenterContainer" type="CenterContainer" parent="."]
@ -27,12 +29,15 @@ anchor_right = 1.0
anchor_bottom = 1.0 anchor_bottom = 1.0
grow_horizontal = 2 grow_horizontal = 2
grow_vertical = 2 grow_vertical = 2
mouse_filter = 2
[node name="VBoxContainer" type="VBoxContainer" parent="CenterContainer"] [node name="VBoxContainer" type="VBoxContainer" parent="CenterContainer"]
layout_mode = 2 layout_mode = 2
mouse_filter = 2
[node name="CenterContainer" type="CenterContainer" parent="CenterContainer/VBoxContainer"] [node name="CenterContainer" type="CenterContainer" parent="CenterContainer/VBoxContainer"]
layout_mode = 2 layout_mode = 2
mouse_filter = 2
[node name="GameOverLabel" type="Label" parent="CenterContainer/VBoxContainer/CenterContainer"] [node name="GameOverLabel" type="Label" parent="CenterContainer/VBoxContainer/CenterContainer"]
layout_mode = 2 layout_mode = 2
@ -41,10 +46,12 @@ text = "ui_game_over_title"
[node name="MarginContainer" type="MarginContainer" parent="CenterContainer/VBoxContainer"] [node name="MarginContainer" type="MarginContainer" parent="CenterContainer/VBoxContainer"]
layout_mode = 2 layout_mode = 2
mouse_filter = 2
theme_override_constants/margin_top = 18 theme_override_constants/margin_top = 18
[node name="CenterContainer2" type="CenterContainer" parent="CenterContainer/VBoxContainer/MarginContainer"] [node name="CenterContainer2" type="CenterContainer" parent="CenterContainer/VBoxContainer/MarginContainer"]
layout_mode = 2 layout_mode = 2
mouse_filter = 2
[node name="DeathInfoLabel" type="Label" parent="CenterContainer/VBoxContainer/MarginContainer/CenterContainer2"] [node name="DeathInfoLabel" type="Label" parent="CenterContainer/VBoxContainer/MarginContainer/CenterContainer2"]
layout_mode = 2 layout_mode = 2
@ -52,6 +59,7 @@ text = "ui_death_info_describe"
[node name="MarginContainer2" type="MarginContainer" parent="CenterContainer/VBoxContainer"] [node name="MarginContainer2" type="MarginContainer" parent="CenterContainer/VBoxContainer"]
layout_mode = 2 layout_mode = 2
mouse_filter = 2
theme_override_constants/margin_top = 10 theme_override_constants/margin_top = 10
theme_override_constants/margin_bottom = 150 theme_override_constants/margin_bottom = 150

View File

@ -35,12 +35,18 @@ public static class GameSceneNodeHolder
} }
} }
/// <summary>
/// <para>When the mouse enters the scope of a character, it is considered a target</para>
/// <para>鼠标进入到某个角色的范围内时,会将其视作目标</para>
/// </summary>
public static Node2D? TemporaryTargetNode { get; set; }
/// <summary> /// <summary>
/// <para>ProjectileContainer</para> /// <para>ProjectileContainer</para>
/// <para>抛射体容器</para> /// <para>抛射体容器</para>
/// </summary> /// </summary>
public static Node2D? ProjectileContainer { get; set; } public static Node2D? ProjectileContainer { get; set; }
/// <summary> /// <summary>
/// <para>WeaponContainer</para> /// <para>WeaponContainer</para>
/// <para>武器容器</para> /// <para>武器容器</para>
@ -113,16 +119,14 @@ public static class GameSceneNodeHolder
NodeUtils.ForEachNode<PacksackUi>(BackpackUiContainer, node => NodeUtils.ForEachNode<PacksackUi>(BackpackUiContainer, node =>
{ {
//If the child node is not visible, the traversal continues. //If the child node is not visible, the traversal continues.
//如果子节点不可见,则继续遍历。 //如果子节点不可见,则继续遍历。
if (!node.Visible) if (!node.Visible)
return false; return false;
//Until you find a visible node, hide it, and return true, ending the loop. //Until you find a visible node, hide it, and return true, ending the loop.
//直到找到可见的节点隐藏该节点然后返回true结束遍历。 //直到找到可见的节点隐藏该节点然后返回true结束遍历。
node.Hide(); node.Hide();
return true; return true;
}); });
} }
} }

View File

@ -178,6 +178,7 @@ public partial class CharacterTemplate : CharacterBody2D
[Export] public string LootListId { get; private set; } = ""; [Export] public string LootListId { get; private set; } = "";
private HealthBar? _healthBar; private HealthBar? _healthBar;
private Label? _tipLabel;
private DateTime _lastDamageTime; private DateTime _lastDamageTime;
/// <summary> /// <summary>
@ -291,6 +292,7 @@ public partial class CharacterTemplate : CharacterBody2D
_animatedSprite2D = GetNode<AnimatedSprite2D>("AnimatedSprite2D"); _animatedSprite2D = GetNode<AnimatedSprite2D>("AnimatedSprite2D");
_pickingArea = GetNode<Area2D>("Area2DPickingArea"); _pickingArea = GetNode<Area2D>("Area2DPickingArea");
_damageNumber = GetNode<Marker2D>("DamageNumber") as DamageNumberNodeSpawn; _damageNumber = GetNode<Marker2D>("DamageNumber") as DamageNumberNodeSpawn;
_tipLabel = GetNodeOrNull<Label>("TipLabel");
if (_pickingArea != null) if (_pickingArea != null)
{ {
//If true, the zone will detect objects or areas entering and leaving the zone. //If true, the zone will detect objects or areas entering and leaving the zone.
@ -307,6 +309,52 @@ public partial class CharacterTemplate : CharacterBody2D
//角色不能穿过墙壁和地板 //角色不能穿过墙壁和地板
SetCollisionMaskValue(Config.LayerNumber.Wall, true); SetCollisionMaskValue(Config.LayerNumber.Wall, true);
SetCollisionMaskValue(Config.LayerNumber.Floor, true); SetCollisionMaskValue(Config.LayerNumber.Floor, true);
InputPickable = true;
}
public override void _ExitTree()
{
base._ExitTree();
if (GameSceneNodeHolder.TemporaryTargetNode == this)
{
GameSceneNodeHolder.TemporaryTargetNode = null;
}
}
private bool _mouseEntered;
public override void _InputEvent(Viewport viewport, InputEvent @event, int shapeIdx)
{
if (!_mouseEntered)
{
return;
}
}
public override void _MouseEnter()
{
_mouseEntered = true;
GameSceneNodeHolder.TemporaryTargetNode = this;
if (_tipLabel != null)
{
_tipLabel.Visible = true;
_tipLabel.Text = CharacterName;
//Vertical Centering Tip
//垂直居中提示
var oldPosition = _tipLabel.Position;
oldPosition.X = -_tipLabel.Size.X / 2;
_tipLabel.Position = oldPosition;
}
}
public override void _MouseExit()
{
_mouseEntered = false;
if (_tipLabel != null)
{
_tipLabel.Visible = false;
}
} }
/// <summary> /// <summary>

View File

@ -67,11 +67,17 @@ public partial class Projectile : CharacterBody2D
/// </summary> /// </summary>
[Export] private bool _enableTracking; [Export] private bool _enableTracking;
/// <summary>
/// <para>The target dies and destroys the projectile at the same time</para>
/// <para>在目标死亡后销毁抛射体</para>
/// </summary>
[Export]private bool _targetDiesDestroyProjectile;
/// <summary> /// <summary>
/// <para>The target</para> /// <para>The target</para>
/// <para>设置目标</para> /// <para>设置目标</para>
/// </summary> /// </summary>
private Node2D? Target { get; set; } public Node2D? TargetNode { get; set; }
private List<IProjectileDecorator>? _projectileDecorators; private List<IProjectileDecorator>? _projectileDecorators;
@ -100,6 +106,19 @@ public partial class Projectile : CharacterBody2D
//Platform collision layer is not allowed to collide //Platform collision layer is not allowed to collide
//平台碰撞层不可碰撞 //平台碰撞层不可碰撞
SetCollisionMaskValue(Config.LayerNumber.Platform, false); SetCollisionMaskValue(Config.LayerNumber.Platform, false);
if (TargetNode != null)
{
TargetNode.TreeExiting += () =>
{
//Clear the trace when the target is destroyed.
//在目标被销毁的时候清空跟踪。
TargetNode = null;
if (_targetDiesDestroyProjectile)
{
OnTimeOut();
}
};
}
} }
/// <summary> /// <summary>
@ -290,13 +309,13 @@ public partial class Projectile : CharacterBody2D
{ {
//No collision. //No collision.
//没有撞到任何东西。 //没有撞到任何东西。
if (_enableTracking && Target != null) if (_enableTracking && TargetNode != null)
{ {
//Track the target //Track the target
//追踪目标 //追踪目标
//Gets a vector of the projectile pointing at the enemy's position. //Gets a vector of the projectile pointing at the enemy's position.
//得到抛射体指向敌人位置的向量。 //得到抛射体指向敌人位置的向量。
var desiredVelocity = GlobalPosition.DirectionTo(Target.GlobalPosition) * Speed; var desiredVelocity = GlobalPosition.DirectionTo(TargetNode.GlobalPosition) * Speed;
//The weight is smaller, the circle is larger. //The weight is smaller, the circle is larger.
//weight越小子弹绕的圈越大。 //weight越小子弹绕的圈越大。
Velocity = Velocity.Lerp(desiredVelocity, 0.1f); Velocity = Velocity.Lerp(desiredVelocity, 0.1f);

View File

@ -169,6 +169,7 @@ public partial class ProjectileWeapon : WeaponTemplate
NodeUtils.CallDeferredAddChild(GameSceneNodeHolder.ProjectileContainer, projectile); NodeUtils.CallDeferredAddChild(GameSceneNodeHolder.ProjectileContainer, projectile);
projectile.Owner = owner; projectile.Owner = owner;
projectile.TargetNode = GameSceneNodeHolder.TemporaryTargetNode;
projectile.Velocity = projectile.Velocity =
(_marker2D.GlobalPosition.DirectionTo(enemyGlobalPosition) * projectile.Speed) (_marker2D.GlobalPosition.DirectionTo(enemyGlobalPosition) * projectile.Speed)
.Rotated(GetRandomAngle()); .Rotated(GetRandomAngle());