diff --git a/DungeonShooting_Godot/excel/ActivityBase.xlsx b/DungeonShooting_Godot/excel/ActivityBase.xlsx
index 9b52007..772a6d7 100644
--- a/DungeonShooting_Godot/excel/ActivityBase.xlsx
+++ b/DungeonShooting_Godot/excel/ActivityBase.xlsx
Binary files differ
diff --git a/DungeonShooting_Godot/excelTool/serialize/ActivityType.cs b/DungeonShooting_Godot/excelTool/serialize/ActivityType.cs
index d094992..acf51f0 100644
--- a/DungeonShooting_Godot/excelTool/serialize/ActivityType.cs
+++ b/DungeonShooting_Godot/excelTool/serialize/ActivityType.cs
@@ -49,6 +49,10 @@
///
Treasure,
///
+ /// Npc
+ ///
+ Npc,
+ ///
/// 其它类型
///
Other = 99,
diff --git a/DungeonShooting_Godot/excelTool/version b/DungeonShooting_Godot/excelTool/version
index c793025..301160a 100644
--- a/DungeonShooting_Godot/excelTool/version
+++ b/DungeonShooting_Godot/excelTool/version
@@ -1 +1 @@
-7
\ No newline at end of file
+8
\ No newline at end of file
diff --git a/DungeonShooting_Godot/prefab/role/enemy/Enemy0001.tscn b/DungeonShooting_Godot/prefab/role/enemy/Enemy0001.tscn
index 723e2f1..3e85288 100644
--- a/DungeonShooting_Godot/prefab/role/enemy/Enemy0001.tscn
+++ b/DungeonShooting_Godot/prefab/role/enemy/Enemy0001.tscn
@@ -9,7 +9,6 @@
[ext_resource type="Animation" uid="uid://16rxpnsgj5tl" path="res://resource/animation/enemy/Enemy_notify.res" id="6_x8gmo"]
[ext_resource type="Animation" uid="uid://cmje7jsgrhgmx" path="res://resource/animation/enemy/Enemy_query.res" id="7_e37p2"]
-
[sub_resource type="ShaderMaterial" id="ShaderMaterial_3nkur"]
resource_local_to_scene = true
shader = ExtResource("3_x8agd")
diff --git a/DungeonShooting_Godot/prefab/role/shopBoss/ShopBoss0001.tscn b/DungeonShooting_Godot/prefab/role/shopBoss/ShopBoss0001.tscn
index 8a18747..d0f6ea5 100644
--- a/DungeonShooting_Godot/prefab/role/shopBoss/ShopBoss0001.tscn
+++ b/DungeonShooting_Godot/prefab/role/shopBoss/ShopBoss0001.tscn
@@ -30,6 +30,7 @@
shader_parameter/grey = 0.0
[node name="ShopBoss0001" node_paths=PackedStringArray("ViewRay", "NavigationAgent2D", "NavigationPoint", "FirePoint", "HurtArea", "HurtCollision", "InteractiveArea", "InteractiveCollision", "TipRoot", "TipSprite", "AnimationPlayer", "MountPoint", "BackMountPoint", "MeleeAttackArea", "MeleeAttackCollision", "ShadowSprite", "AnimatedSprite", "Collision") instance=ExtResource("1_25fpq")]
+collision_layer = 1024
script = ExtResource("2_2ng7e")
ViewRay = NodePath("ViewRay")
NavigationAgent2D = NodePath("NavigationPoint/NavigationAgent2D")
@@ -56,3 +57,4 @@
[node name="AnimatedSprite" parent="." index="2"]
material = SubResource("ShaderMaterial_x86iq")
sprite_frames = ExtResource("3_b0a5c")
+animation = &"idle"
diff --git a/DungeonShooting_Godot/project.godot b/DungeonShooting_Godot/project.godot
index 7c6559c..9c42853 100644
--- a/DungeonShooting_Godot/project.godot
+++ b/DungeonShooting_Godot/project.godot
@@ -252,6 +252,7 @@
2d_physics/layer_8="debris"
2d_physics/layer_9="throwing"
2d_physics/layer_10="obstacle"
+2d_physics/layer_11="npc"
2d_physics/layer_14="ui_mouse"
[mono]
diff --git a/DungeonShooting_Godot/resource/config/ActivityBase.json b/DungeonShooting_Godot/resource/config/ActivityBase.json
index 8a65df5..6c4d2db 100644
--- a/DungeonShooting_Godot/resource/config/ActivityBase.json
+++ b/DungeonShooting_Godot/resource/config/ActivityBase.json
@@ -44,7 +44,7 @@
{
"Id": "shopBoss0001",
"Name": "\u5546\u5E97\u8001\u677F",
- "Type": 4,
+ "Type": 11,
"Quality": 0,
"Price": 0,
"Intro": "\u5546\u5E97\u8001\u677F",
diff --git a/DungeonShooting_Godot/resource/spriteFrames/role/ShopBoss0001.tres b/DungeonShooting_Godot/resource/spriteFrames/role/ShopBoss0001.tres
index 0b118c9..05b4873 100644
--- a/DungeonShooting_Godot/resource/spriteFrames/role/ShopBoss0001.tres
+++ b/DungeonShooting_Godot/resource/spriteFrames/role/ShopBoss0001.tres
@@ -11,4 +11,28 @@
"loop": true,
"name": &"default",
"speed": 5.0
+}, {
+"frames": [{
+"duration": 1.0,
+"texture": ExtResource("1_k2gly")
+}],
+"loop": true,
+"name": &"idle",
+"speed": 5.0
+}, {
+"frames": [{
+"duration": 1.0,
+"texture": ExtResource("1_k2gly")
+}],
+"loop": true,
+"name": &"reverseRun",
+"speed": 5.0
+}, {
+"frames": [{
+"duration": 1.0,
+"texture": ExtResource("1_k2gly")
+}],
+"loop": true,
+"name": &"run",
+"speed": 5.0
}]
diff --git a/DungeonShooting_Godot/src/config/ExcelConfig_ActivityBase.cs b/DungeonShooting_Godot/src/config/ExcelConfig_ActivityBase.cs
index 3e86482..f9af8d4 100644
--- a/DungeonShooting_Godot/src/config/ExcelConfig_ActivityBase.cs
+++ b/DungeonShooting_Godot/src/config/ExcelConfig_ActivityBase.cs
@@ -30,6 +30,7 @@
/// Effect(特效): 8
/// Prop(道具): 9
/// Treasure(宝箱): 10
+ /// Npc: 11
/// Other(其它类型): 99
///
[JsonInclude]
diff --git a/DungeonShooting_Godot/src/framework/activity/ActivityType.cs b/DungeonShooting_Godot/src/framework/activity/ActivityType.cs
index d094992..acf51f0 100644
--- a/DungeonShooting_Godot/src/framework/activity/ActivityType.cs
+++ b/DungeonShooting_Godot/src/framework/activity/ActivityType.cs
@@ -49,6 +49,10 @@
///
Treasure,
///
+ /// Npc
+ ///
+ Npc,
+ ///
/// 其它类型
///
Other = 99,
diff --git a/DungeonShooting_Godot/src/framework/map/preinstall/RoomPreinstall.cs b/DungeonShooting_Godot/src/framework/map/preinstall/RoomPreinstall.cs
index 97f2e5a..2a63757 100644
--- a/DungeonShooting_Godot/src/framework/map/preinstall/RoomPreinstall.cs
+++ b/DungeonShooting_Godot/src/framework/map/preinstall/RoomPreinstall.cs
@@ -226,12 +226,9 @@
private void HandlerShopBossMark(World world, MarkInfo markInfo, ActivityMark mark)
{
- mark.Id = ActivityObject.Ids.Id_treasure_box0001;
- mark.ActivityType = ActivityType.Treasure;
+ mark.Id = ActivityObject.Ids.Id_shopBoss0001;
+ mark.ActivityType = ActivityType.Npc;
mark.Altitude = 0;
-
- // mark.Id = ActivityObject.Ids.Id_shopBoss0001;
- // mark.ActivityType = ActivityType.Enemy;
}
private void HandlerTreasureMark(World world, MarkInfo markInfo, ActivityMark mark)
@@ -469,12 +466,16 @@
//获取物体默认所在层级
private RoomLayerEnum GetDefaultLayer(ActivityMark activityMark)
{
- if (activityMark.ActivityType == ActivityType.Player || activityMark.ActivityType == ActivityType.Enemy || activityMark.ActivityType == ActivityType.Treasure)
+ switch (activityMark.ActivityType)
{
- return RoomLayerEnum.YSortLayer;
+ case ActivityType.Player:
+ case ActivityType.Enemy:
+ case ActivityType.Npc:
+ case ActivityType.Treasure:
+ return RoomLayerEnum.YSortLayer;
+ default:
+ return RoomLayerEnum.NormalLayer;
}
-
- return RoomLayerEnum.NormalLayer;
}
///
diff --git a/DungeonShooting_Godot/src/game/activity/role/ai/AiRole.cs b/DungeonShooting_Godot/src/game/activity/role/ai/AiRole.cs
index 4eced81..2eba496 100644
--- a/DungeonShooting_Godot/src/game/activity/role/ai/AiRole.cs
+++ b/DungeonShooting_Godot/src/game/activity/role/ai/AiRole.cs
@@ -76,6 +76,11 @@
///
public float AttackInterval { get; set; } = 0;
+ ///
+ /// 当前Ai是否有攻击欲望
+ ///
+ public bool HasAttackDesire { get; private set; } = true;
+
public override void OnInit()
{
base.OnInit();
@@ -101,7 +106,7 @@
}
///
- /// 获取攻击的目标对象, 该函数不能返回 null
+ /// 获取攻击的目标对象, 当 HasAttackDesire 为 true 时才会调用
///
public virtual Role GetAttackTarget()
{
@@ -388,6 +393,18 @@
Destroy();
}
+ ///
+ /// 设置Ai是否有攻击欲望
+ ///
+ public void SetAttackDesire(bool v)
+ {
+ if (v != HasAttackDesire)
+ {
+ HasAttackDesire = v;
+ StateController.ChangeState(AIStateEnum.AiNormal);
+ }
+ }
+
// private void OnVelocityComputed(Vector2 velocity)
// {
// if (Mathf.Abs(velocity.X) >= 0.01f && Mathf.Abs(velocity.Y) >= 0.01f)
diff --git a/DungeonShooting_Godot/src/game/activity/role/ai/state/AiAstonishedState.cs b/DungeonShooting_Godot/src/game/activity/role/ai/state/AiAstonishedState.cs
index 0d7131b..7e8f382 100644
--- a/DungeonShooting_Godot/src/game/activity/role/ai/state/AiAstonishedState.cs
+++ b/DungeonShooting_Godot/src/game/activity/role/ai/state/AiAstonishedState.cs
@@ -34,7 +34,10 @@
_timer = 0.6f;
//播放惊讶表情
- Master.AnimationPlayer.Play(AnimatorNames.Astonished);
+ if (Master.AnimationPlayer.HasAnimation(AnimatorNames.Astonished))
+ {
+ Master.AnimationPlayer.Play(AnimatorNames.Astonished);
+ }
}
public override void Process(float delta)
diff --git a/DungeonShooting_Godot/src/game/activity/role/ai/state/AiFindAmmoState.cs b/DungeonShooting_Godot/src/game/activity/role/ai/state/AiFindAmmoState.cs
index 75f9e30..c776dc0 100644
--- a/DungeonShooting_Godot/src/game/activity/role/ai/state/AiFindAmmoState.cs
+++ b/DungeonShooting_Godot/src/game/activity/role/ai/state/AiFindAmmoState.cs
@@ -54,7 +54,10 @@
_playAnimFlag = prev == AIStateEnum.AiLeaveFor;
if (_playAnimFlag)
{
- Master.AnimationPlayer.Play(AnimatorNames.Query);
+ if (Master.AnimationPlayer.HasAnimation(AnimatorNames.Query))
+ {
+ Master.AnimationPlayer.Play(AnimatorNames.Query);
+ }
}
}
@@ -74,18 +77,21 @@
if (Master.LookTarget == null) //没有目标
{
- //临时处理
+ //攻击目标
var attackTarget = Master.GetAttackTarget();
- var targetPos = attackTarget.GetCenterPosition();
- if (Master.IsInViewRange(targetPos) && !Master.TestViewRayCast(targetPos)) //发现玩家
+ if (attackTarget != null)
{
- //关闭射线检测
- Master.TestViewRayCastOver();
- //发现玩家
- Master.LookTarget = attackTarget;
- //进入惊讶状态, 然后再进入通知状态
- ChangeState(AIStateEnum.AiAstonished, AIStateEnum.AiFindAmmo, TargetWeapon);
- return;
+ var targetPos = attackTarget.GetCenterPosition();
+ if (Master.IsInViewRange(targetPos) && !Master.TestViewRayCast(targetPos)) //发现玩家
+ {
+ //关闭射线检测
+ Master.TestViewRayCastOver();
+ //发现玩家
+ Master.LookTarget = attackTarget;
+ //进入惊讶状态, 然后再进入通知状态
+ ChangeState(AIStateEnum.AiAstonished, AIStateEnum.AiFindAmmo, TargetWeapon);
+ return;
+ }
}
}
diff --git a/DungeonShooting_Godot/src/game/activity/role/ai/state/AiLeaveForState.cs b/DungeonShooting_Godot/src/game/activity/role/ai/state/AiLeaveForState.cs
index 2352bd1..4f118db 100644
--- a/DungeonShooting_Godot/src/game/activity/role/ai/state/AiLeaveForState.cs
+++ b/DungeonShooting_Godot/src/game/activity/role/ai/state/AiLeaveForState.cs
@@ -53,7 +53,10 @@
_playAnimFlag = prev != AIStateEnum.AiFindAmmo;
if (_playAnimFlag)
{
- Master.AnimationPlayer.Play(AnimatorNames.Query);
+ if (Master.AnimationPlayer.HasAnimation(AnimatorNames.Query))
+ {
+ Master.AnimationPlayer.Play(AnimatorNames.Query);
+ }
}
//看向目标位置
@@ -101,27 +104,31 @@
//站立
Master.DoIdle();
}
-
+ //攻击目标
var attackTarget = Master.GetAttackTarget();
- var targetPos = attackTarget.GetCenterPosition();
- //检测玩家是否在视野内, 如果在, 则切换到 AiTargetInView 状态
- if (Master.IsInTailAfterViewRange(targetPos))
+ if (attackTarget != null)
{
- if (!Master.TestViewRayCast(targetPos)) //看到玩家
+ var targetPos = attackTarget.GetCenterPosition();
+ //检测玩家是否在视野内, 如果在, 则切换到 AiTargetInView 状态
+ if (Master.IsInTailAfterViewRange(targetPos))
{
- //关闭射线检测
- Master.TestViewRayCastOver();
- //切换成发现目标状态
- Master.LookTarget = attackTarget;
- ChangeState(AIStateEnum.AiAstonished, AIStateEnum.AiFollowUp);
- return;
- }
- else
- {
- //关闭射线检测
- Master.TestViewRayCastOver();
+ if (!Master.TestViewRayCast(targetPos)) //看到玩家
+ {
+ //关闭射线检测
+ Master.TestViewRayCastOver();
+ //切换成发现目标状态
+ Master.LookTarget = attackTarget;
+ ChangeState(AIStateEnum.AiAstonished, AIStateEnum.AiFollowUp);
+ return;
+ }
+ else
+ {
+ //关闭射线检测
+ Master.TestViewRayCastOver();
+ }
}
}
+
//移动到目标掉了, 还没发现目标
if (Master.NavigationAgent2D.IsNavigationFinished())
diff --git a/DungeonShooting_Godot/src/game/activity/role/ai/state/AiNormalState.cs b/DungeonShooting_Godot/src/game/activity/role/ai/state/AiNormalState.cs
index c526575..dfdc704 100644
--- a/DungeonShooting_Godot/src/game/activity/role/ai/state/AiNormalState.cs
+++ b/DungeonShooting_Godot/src/game/activity/role/ai/state/AiNormalState.cs
@@ -46,33 +46,40 @@
public override void Process(float delta)
{
- //获取攻击目标
- var attackTarget = Master.GetAttackTarget();
- //玩家中心点坐标
- var targetPos = attackTarget.GetCenterPosition();
-
- if (Master.IsInViewRange(targetPos) && !Master.TestViewRayCast(targetPos)) //发现目标
+ if (Master.HasAttackDesire) //有攻击欲望
{
- //关闭射线检测
- Master.TestViewRayCastOver();
- //发现玩家
- Master.LookTarget = attackTarget;
- //判断是否进入通知状态
- if (Master.World.Enemy_InstanceList.FindIndex(enemy =>
- enemy != Master && !enemy.IsDie && enemy.AffiliationArea == Master.AffiliationArea &&
- enemy.StateController.CurrState == AIStateEnum.AiNormal) != -1)
+ //获取攻击目标
+ var attackTarget = Master.GetAttackTarget();
+ if (attackTarget != null)
{
- //进入惊讶状态, 然后再进入通知状态
- ChangeState(AIStateEnum.AiAstonished, AIStateEnum.AiNotify);
+ //玩家中心点坐标
+ var targetPos = attackTarget.GetCenterPosition();
+
+ if (Master.IsInViewRange(targetPos) && !Master.TestViewRayCast(targetPos)) //发现目标
+ {
+ //关闭射线检测
+ Master.TestViewRayCastOver();
+ //发现玩家
+ Master.LookTarget = attackTarget;
+ //判断是否进入通知状态
+ if (Master.World.Enemy_InstanceList.FindIndex(enemy =>
+ enemy != Master && !enemy.IsDie && enemy.AffiliationArea == Master.AffiliationArea &&
+ enemy.StateController.CurrState == AIStateEnum.AiNormal) != -1)
+ {
+ //进入惊讶状态, 然后再进入通知状态
+ ChangeState(AIStateEnum.AiAstonished, AIStateEnum.AiNotify);
+ }
+ else
+ {
+ //进入惊讶状态, 然后再进入跟随状态
+ ChangeState(AIStateEnum.AiAstonished, AIStateEnum.AiTailAfter);
+ }
+ return;
+ }
}
- else
- {
- //进入惊讶状态, 然后再进入跟随状态
- ChangeState(AIStateEnum.AiAstonished, AIStateEnum.AiTailAfter);
- }
- return;
}
- else if (_pauseTimer >= 0)
+
+ if (_pauseTimer >= 0)
{
Master.AnimatedSprite.Play(AnimatorNames.Idle);
_pauseTimer -= delta;
diff --git a/DungeonShooting_Godot/src/game/activity/role/ai/state/AiNotifyState.cs b/DungeonShooting_Godot/src/game/activity/role/ai/state/AiNotifyState.cs
index 22726f1..b1e0b3f 100644
--- a/DungeonShooting_Godot/src/game/activity/role/ai/state/AiNotifyState.cs
+++ b/DungeonShooting_Godot/src/game/activity/role/ai/state/AiNotifyState.cs
@@ -22,7 +22,10 @@
_timer = 1.2f;
//通知其它角色
Master.World.NotifyEnemyTarget(Master, Master.LookTarget);
- Master.AnimationPlayer.Play(AnimatorNames.Notify);
+ if (Master.AnimationPlayer.HasAnimation(AnimatorNames.Notify))
+ {
+ Master.AnimationPlayer.Play(AnimatorNames.Notify);
+ }
}
public override void Process(float delta)
diff --git a/DungeonShooting_Godot/src/game/activity/role/shop/ShopBoss.cs b/DungeonShooting_Godot/src/game/activity/role/shop/ShopBoss.cs
index b6153c3..f481376 100644
--- a/DungeonShooting_Godot/src/game/activity/role/shop/ShopBoss.cs
+++ b/DungeonShooting_Godot/src/game/activity/role/shop/ShopBoss.cs
@@ -7,6 +7,19 @@
[Tool]
public partial class ShopBoss : AiRole
{
+ public override void OnInit()
+ {
+ base.OnInit();
+ SetAttackDesire(false);
+ }
+
+ protected override RoleState OnCreateRoleState()
+ {
+ var roleState = new RoleState();
+ roleState.MoveSpeed = 50;
+ return roleState;
+ }
+
public override void OnCreateWithMark(RoomPreinstall roomPreinstall, ActivityMark activityMark)
{
diff --git a/DungeonShooting_Godot/src/game/data/property/PhysicsLayer.cs b/DungeonShooting_Godot/src/game/data/property/PhysicsLayer.cs
index d1675e4..0194269 100644
--- a/DungeonShooting_Godot/src/game/data/property/PhysicsLayer.cs
+++ b/DungeonShooting_Godot/src/game/data/property/PhysicsLayer.cs
@@ -47,4 +47,8 @@
/// 障碍物
///
public const uint Obstacle = 0b1000000000;
+ ///
+ /// npc
+ ///
+ public const uint Npc = 0b10000000000;
}
\ No newline at end of file