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