diff --git a/DungeonShooting_Godot/Silver.ttf b/DungeonShooting_Godot/Silver.ttf
new file mode 100644
index 0000000..9d568c4
--- /dev/null
+++ b/DungeonShooting_Godot/Silver.ttf
Binary files differ
diff --git a/DungeonShooting_Godot/prefab/role/Enemy.tscn b/DungeonShooting_Godot/prefab/role/Enemy.tscn
index 335ac3f..0315428 100644
--- a/DungeonShooting_Godot/prefab/role/Enemy.tscn
+++ b/DungeonShooting_Godot/prefab/role/Enemy.tscn
@@ -1,4 +1,4 @@
-[gd_scene load_steps=5 format=2]
+[gd_scene load_steps=6 format=2]
[ext_resource path="res://prefab/role/Role.tscn" type="PackedScene" id=1]
[ext_resource path="res://resource/materlal/Blend.gdshader" type="Shader" id=2]
@@ -15,6 +15,9 @@
shader_param/blend = Color( 1, 1, 1, 1 )
shader_param/schedule = 0.0
+[sub_resource type="CircleShape2D" id=3]
+radius = 13.0
+
[node name="Enemy" instance=ExtResource( 1 )]
CollisionLayer = 16
@@ -23,7 +26,13 @@
[node name="AnimatedSprite" parent="." index="2"]
material = SubResource( 2 )
-frame = 1
[node name="ViewRay" type="RayCast2D" parent="." index="6"]
position = Vector2( 0, -8 )
+
+[node name="MarginArea" type="Area2D" parent="." index="8"]
+collision_layer = 0
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="MarginArea" index="0"]
+position = Vector2( 0, -8 )
+shape = SubResource( 3 )
diff --git a/DungeonShooting_Godot/project.godot b/DungeonShooting_Godot/project.godot
index e1ec7c8..c5ef034 100644
--- a/DungeonShooting_Godot/project.godot
+++ b/DungeonShooting_Godot/project.godot
@@ -39,7 +39,7 @@
[gui]
theme/custom="res://resource/theme/mainTheme.tres"
-theme/custom_font="res://resource/font/cn_font_18.tres"
+theme/custom_font="res://resource/font/cn_font_36.tres"
[importer_defaults]
@@ -173,6 +173,7 @@
2d_physics/layer_3="props"
2d_physics/layer_4="player"
2d_physics/layer_5="enemy"
+2d_physics/layer_6="view"
[mono]
diff --git a/DungeonShooting_Godot/resource/font/cn_font_12.tres b/DungeonShooting_Godot/resource/font/cn_font_12.tres
index dbd8053..fd3c470 100644
--- a/DungeonShooting_Godot/resource/font/cn_font_12.tres
+++ b/DungeonShooting_Godot/resource/font/cn_font_12.tres
@@ -1,6 +1,6 @@
[gd_resource type="DynamicFont" load_steps=2 format=2]
-[ext_resource path="res://SourceHanSerifCN-SemiBold.otf" type="DynamicFontData" id=1]
+[ext_resource path="res://Silver.ttf" type="DynamicFontData" id=1]
[resource]
size = 12
diff --git a/DungeonShooting_Godot/resource/font/cn_font_18.tres b/DungeonShooting_Godot/resource/font/cn_font_18.tres
index 032a49a..a1de47c 100644
--- a/DungeonShooting_Godot/resource/font/cn_font_18.tres
+++ b/DungeonShooting_Godot/resource/font/cn_font_18.tres
@@ -1,6 +1,6 @@
[gd_resource type="DynamicFont" load_steps=2 format=2]
-[ext_resource path="res://SourceHanSerifCN-SemiBold.otf" type="DynamicFontData" id=1]
+[ext_resource path="res://Silver.ttf" type="DynamicFontData" id=1]
[resource]
size = 18
diff --git a/DungeonShooting_Godot/resource/font/cn_font_35.tres b/DungeonShooting_Godot/resource/font/cn_font_35.tres
deleted file mode 100644
index f4e81ad..0000000
--- a/DungeonShooting_Godot/resource/font/cn_font_35.tres
+++ /dev/null
@@ -1,8 +0,0 @@
-[gd_resource type="DynamicFont" load_steps=2 format=2]
-
-[ext_resource path="res://SourceHanSerifCN-SemiBold.otf" type="DynamicFontData" id=1]
-
-[resource]
-size = 35
-extra_spacing_char = 1
-font_data = ExtResource( 1 )
diff --git a/DungeonShooting_Godot/resource/font/cn_font_36.tres b/DungeonShooting_Godot/resource/font/cn_font_36.tres
new file mode 100644
index 0000000..b3ea792
--- /dev/null
+++ b/DungeonShooting_Godot/resource/font/cn_font_36.tres
@@ -0,0 +1,7 @@
+[gd_resource type="DynamicFont" load_steps=2 format=2]
+
+[ext_resource path="res://Silver.ttf" type="DynamicFontData" id=1]
+
+[resource]
+size = 36
+font_data = ExtResource( 1 )
diff --git a/DungeonShooting_Godot/scene/test/TestNavigation.tscn b/DungeonShooting_Godot/scene/test/TestNavigation.tscn
index d310e7d..baf5acf 100644
--- a/DungeonShooting_Godot/scene/test/TestNavigation.tscn
+++ b/DungeonShooting_Godot/scene/test/TestNavigation.tscn
@@ -4,7 +4,6 @@
[ext_resource path="res://icon.png" type="Texture" id=2]
[ext_resource path="res://resource/sprite/environment/craftpix-net-248911/16x16.png" type="Texture" id=3]
-
[sub_resource type="NavigationPolygon" id=2]
vertices = PoolVector2Array( 0, 0, 16, 0, 16, 16, 0, 16 )
polygons = [ PoolIntArray( 0, 1, 2, 3 ) ]
@@ -48,6 +47,7 @@
0/z_index = 0
[node name="TestNavigation" type="Node2D"]
+scale = Vector2( 4, 4 )
script = ExtResource( 1 )
[node name="Position2D" type="Position2D" parent="."]
diff --git a/DungeonShooting_Godot/src/game/PhysicsLayer.cs b/DungeonShooting_Godot/src/game/PhysicsLayer.cs
index 36a31e5..1d4bb83 100644
--- a/DungeonShooting_Godot/src/game/PhysicsLayer.cs
+++ b/DungeonShooting_Godot/src/game/PhysicsLayer.cs
@@ -23,4 +23,8 @@
/// 敌人
///
public const uint Enemy = 16;
+ ///
+ /// 视野遮挡
+ ///
+ public const uint View = 32;
}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/game/role/PathSign.cs b/DungeonShooting_Godot/src/game/role/PathSign.cs
index cec2ea9..a3487ed 100644
--- a/DungeonShooting_Godot/src/game/role/PathSign.cs
+++ b/DungeonShooting_Godot/src/game/role/PathSign.cs
@@ -58,6 +58,15 @@
}
}
+ ///
+ /// 目标出现过的位置
+ ///
+ public Vector2 TargetPosition
+ {
+ get => _targetPos;
+ set => _targetPos = value;
+ }
+
//是否发现过目标
private bool _isDiscoverTarget = false;
//目标在视野范围内出现过的位置
@@ -133,6 +142,7 @@
var distance = Mathf.Sqrt(distanceSquared);
Next = new PathSign(GameApplication.Instance.Room.GetRoot(false), _targetPos, ViewRadius - distance, Target, Index + 1);
Next._targetPos = nowTargetPos;
+ Next.Enable = true;
}
}
else //没有碰到墙
diff --git a/DungeonShooting_Godot/src/game/role/enemy/Enemy.cs b/DungeonShooting_Godot/src/game/role/enemy/Enemy.cs
index 626896f..7eb9c12 100644
--- a/DungeonShooting_Godot/src/game/role/enemy/Enemy.cs
+++ b/DungeonShooting_Godot/src/game/role/enemy/Enemy.cs
@@ -44,7 +44,7 @@
///
/// 移动目标标记
///
- public PathSign TargetSign { get; }
+ public PathSign PathSign { get; }
///
/// 寻路标记线段总长度
@@ -52,6 +52,8 @@
public float PathSignLength { get; set; } = 500;
//-------------------------------------------------------
+
+ private Area2D _marginArea;
public Enemy() : base(ResourcePath.prefab_role_Enemy_tscn)
{
@@ -65,21 +67,40 @@
//视野射线
ViewRay = GetNode("ViewRay");
+ _marginArea = GetNode("MarginArea");
+
+ PathSign = new PathSign(this, PathSignLength, GameApplication.Instance.Room.Player);
//注册Ai状态机
StateController.Register(new AINormalState());
+ StateController.Register(new AIProbeState());
StateController.Register(new AITailAfterState());
+ }
+
+ public override void _Ready()
+ {
+ base._Ready();
//默认状态
StateController.ChangeState(AIStateEnum.AINormal);
- TargetSign = new PathSign(this, PathSignLength, GameApplication.Instance.Room.Player);
+ _marginArea.Connect("body_shape_entered", this, nameof(OnObjectEnter));
}
+ public void OnObjectEnter(RID id, Node node, int shapeIndex, int localShapeIndex)
+ {
+ if (node is TileMap tileMap)
+ {
+ // var tileGetShape = tileMap.TileSet.TileGetShapeTransform(shapeIndex, localShapeIndex).;
+ // GD.Print("enter: ", tileGetShape.GetType().FullName);
+ }
+ }
+
public override void _Process(float delta)
{
base._Process(delta);
if (GameApplication.Instance.Debug)
{
+ PathSign.Scale = new Vector2((int)Face, 1);
Update();
}
}
@@ -88,52 +109,52 @@
{
base._PhysicsProcess(delta);
- var player = GameApplication.Instance.Room.Player;
- //玩家中心点坐标
- var playerPos = player.MountPoint.GlobalPosition;
-
- //玩家是否在前方
- var isForward = IsPositionInForward(playerPos);
-
- if (isForward) //脸朝向玩家
- {
- // if (GlobalPosition.DistanceSquaredTo(playerPos) <= ViewRange * ViewRange) //没有超出视野半径
- // {
- // //射线检测墙体
- // ViewRay.Enabled = true;
- // var localPos = ViewRay.ToLocal(playerPos);
- // ViewRay.CastTo = localPos;
- // ViewRay.ForceRaycastUpdate();
- //
- // if (ViewRay.IsColliding()) //在视野范围内, 但是碰到墙壁
- // {
- // LookTarget = null;
- // StateController.ChangeState(StateEnum.Idle);
- // }
- // else //视野无阻
- // {
- // LookTarget = player;
- // StateController.ChangeState(StateEnum.Run);
- // }
- //
- // ViewRay.Enabled = false;
- // }
- // else //超出视野半径
- // {
- // LookTarget = null;
- // StateController.ChangeState(StateEnum.Idle);
- // }
- // //_prevPlayerPos = playerPos;
- }
+ // var player = GameApplication.Instance.Room.Player;
+ // //玩家中心点坐标
+ // var playerPos = player.MountPoint.GlobalPosition;
+ //
+ // //玩家是否在前方
+ // var isForward = IsPositionInForward(playerPos);
+ //
+ // if (isForward) //脸朝向玩家
+ // {
+ // // if (GlobalPosition.DistanceSquaredTo(playerPos) <= ViewRange * ViewRange) //没有超出视野半径
+ // // {
+ // // //射线检测墙体
+ // // ViewRay.Enabled = true;
+ // // var localPos = ViewRay.ToLocal(playerPos);
+ // // ViewRay.CastTo = localPos;
+ // // ViewRay.ForceRaycastUpdate();
+ // //
+ // // if (ViewRay.IsColliding()) //在视野范围内, 但是碰到墙壁
+ // // {
+ // // LookTarget = null;
+ // // StateController.ChangeState(StateEnum.Idle);
+ // // }
+ // // else //视野无阻
+ // // {
+ // // LookTarget = player;
+ // // StateController.ChangeState(StateEnum.Run);
+ // // }
+ // //
+ // // ViewRay.Enabled = false;
+ // // }
+ // // else //超出视野半径
+ // // {
+ // // LookTarget = null;
+ // // StateController.ChangeState(StateEnum.Idle);
+ // // }
+ // // //_prevPlayerPos = playerPos;
+ // }
}
public override void _Draw()
{
if (GameApplication.Instance.Debug)
{
- if (TargetSign != null)
+ if (PathSign != null)
{
- DrawLine(Vector2.Zero,ToLocal(TargetSign.GlobalPosition), Colors.Red);
+ DrawLine(Vector2.Zero,ToLocal(PathSign.GlobalPosition), Colors.Red);
}
}
}
diff --git a/DungeonShooting_Godot/src/game/role/enemy/state/AINormalState.cs b/DungeonShooting_Godot/src/game/role/enemy/state/AINormalState.cs
index 664b8d6..5733bec 100644
--- a/DungeonShooting_Godot/src/game/role/enemy/state/AINormalState.cs
+++ b/DungeonShooting_Godot/src/game/role/enemy/state/AINormalState.cs
@@ -9,11 +9,38 @@
public StateController StateController { get; set; }
public void Enter(AIStateEnum prev, params object[] args)
{
-
+ Master.PathSign.Enable = false;
}
public void PhysicsProcess(float delta)
{
+ //检测玩家
+ var player = GameApplication.Instance.Room.Player;
+ //玩家中心点坐标
+ var playerPos = player.MountPoint.GlobalPosition;
+
+ //玩家是否在前方
+ var isForward = Master.IsPositionInForward(playerPos);
+
+ if (isForward) //脸朝向玩家
+ {
+ if (Master.GlobalPosition.DistanceSquaredTo(playerPos) <= Master.ViewRange * Master.ViewRange) //没有超出视野半径
+ {
+ //射线检测墙体
+ Master.ViewRay.Enabled = true;
+ var localPos = Master.ViewRay.ToLocal(playerPos);
+ Master.ViewRay.CastTo = localPos;
+ Master.ViewRay.ForceRaycastUpdate();
+
+ if (!Master.ViewRay.IsColliding()) //视野无阻
+ {
+ //发现玩家, 切换状态
+ StateController.ChangeStateLate(AIStateEnum.AITailAfter);
+ }
+
+ Master.ViewRay.Enabled = false;
+ }
+ }
}
diff --git a/DungeonShooting_Godot/src/game/role/enemy/state/AITailAfterState.cs b/DungeonShooting_Godot/src/game/role/enemy/state/AITailAfterState.cs
index 1a84a2d..170cb24 100644
--- a/DungeonShooting_Godot/src/game/role/enemy/state/AITailAfterState.cs
+++ b/DungeonShooting_Godot/src/game/role/enemy/state/AITailAfterState.cs
@@ -9,17 +9,62 @@
public StateController StateController { get; set; }
public void Enter(AIStateEnum prev, params object[] args)
{
-
+ Master.PathSign.Enable = true;
}
public void PhysicsProcess(float delta)
{
var master = Master;
- if (master.LookTarget != null)
+ var targetSign = master.PathSign;
+ var enemyPos = master.GlobalPosition;
+ if (targetSign.Next == null)
{
- master.AnimatedSprite.Animation = AnimatorNames.ReverseRun;
- master.Velocity = (master.LookTarget.GlobalPosition - master.GlobalPosition).Normalized() * master.MoveSpeed;
- master.CalcMove(delta);
+ var targetPosition = targetSign.TargetPosition;
+
+ if (enemyPos.DistanceSquaredTo(targetPosition) <= master.Velocity.LengthSquared() * delta) //移动到下一个节点了, 还是没有找到目标, 变为第二状态
+ {
+ StateController.ChangeStateLate(AIStateEnum.AINormal);
+ }
+ else //继续移动
+ {
+ master.LookTargetPosition(targetPosition);
+ master.AnimatedSprite.Animation = AnimatorNames.Run;
+ master.Velocity = (targetPosition - enemyPos).Normalized() * master.MoveSpeed;
+ master.CalcMove(delta);
+ }
+ }
+ else
+ {
+ var nextPos = targetSign.Next.GlobalPosition;
+
+ if (enemyPos.DistanceSquaredTo(nextPos) <= master.Velocity.LengthSquared() * delta) //已经移动到下一个节点了, 删除下一个节点, 后面的接上
+ {
+ var nextNext = targetSign.Next.Next;
+ var tempPos = targetSign.Next.TargetPosition;
+ targetSign.Next.Next = null;
+ targetSign.Next.Destroy();
+ targetSign.Next = nextNext;
+
+ if (nextNext != null) //下一个点继续移动
+ {
+ nextPos = nextNext.GlobalPosition;
+ master.LookTargetPosition(nextPos);
+ master.AnimatedSprite.Animation = AnimatorNames.Run;
+ master.Velocity = (nextPos - enemyPos).Normalized() * master.MoveSpeed;
+ master.CalcMove(delta);
+ }
+ else
+ {
+ targetSign.TargetPosition = tempPos;
+ }
+ }
+ else //继续移动
+ {
+ master.LookTargetPosition(nextPos);
+ master.AnimatedSprite.Animation = AnimatorNames.Run;
+ master.Velocity = (nextPos - enemyPos).Normalized() * master.MoveSpeed;
+ master.CalcMove(delta);
+ }
}
}