diff --git a/DungeonShooting_Godot/prefab/role/Enemy0001.tscn b/DungeonShooting_Godot/prefab/role/Enemy0001.tscn index 6f76541..f00e445 100644 --- a/DungeonShooting_Godot/prefab/role/Enemy0001.tscn +++ b/DungeonShooting_Godot/prefab/role/Enemy0001.tscn @@ -272,11 +272,12 @@ "query": SubResource("Animation_usfrh") } -[node name="Enemy0001" node_paths=PackedStringArray("ViewRay", "NavigationAgent2D", "NavigationPoint", "HurtArea", "HurtCollision", "InteractiveArea", "InteractiveCollision", "TipRoot", "TipSprite", "AnimationPlayer", "MountPoint", "BackMountPoint", "MeleeAttackArea", "MeleeAttackCollision", "ShadowSprite", "AnimatedSprite", "Collision") instance=ExtResource("1_2vqwe")] +[node name="Enemy0001" node_paths=PackedStringArray("ViewRay", "NavigationAgent2D", "NavigationPoint", "FirePoint", "HurtArea", "HurtCollision", "InteractiveArea", "InteractiveCollision", "TipRoot", "TipSprite", "AnimationPlayer", "MountPoint", "BackMountPoint", "MeleeAttackArea", "MeleeAttackCollision", "ShadowSprite", "AnimatedSprite", "Collision") instance=ExtResource("1_2vqwe")] script = ExtResource("2_0pcq3") ViewRay = NodePath("ViewRay") NavigationAgent2D = NodePath("NavigationPoint/NavigationAgent2D") NavigationPoint = NodePath("NavigationPoint") +FirePoint = NodePath("FirePoint") HurtArea = NodePath("HurtArea") HurtCollision = NodePath("HurtArea/HurtCollision") InteractiveArea = NodePath("InteractiveArea") @@ -302,7 +303,10 @@ [node name="HurtCollision" parent="HurtArea" index="0"] shape = SubResource("RectangleShape2D_rkrey") -[node name="AnimationPlayer" parent="." index="10"] +[node name="FirePoint" parent="." index="8"] +position = Vector2(2, -9) + +[node name="AnimationPlayer" parent="." index="11"] libraries = { "": SubResource("AnimationLibrary_ur1ug") } diff --git a/DungeonShooting_Godot/prefab/role/Enemy0002.tscn b/DungeonShooting_Godot/prefab/role/Enemy0002.tscn index 1e08932..e869f0e 100644 --- a/DungeonShooting_Godot/prefab/role/Enemy0002.tscn +++ b/DungeonShooting_Godot/prefab/role/Enemy0002.tscn @@ -1,11 +1,11 @@ -[gd_scene load_steps=7 format=3 uid="uid://qqktspyolb34"] +[gd_scene load_steps=10 format=3 uid="uid://daqsdld5gnwwr"] -[ext_resource type="PackedScene" uid="uid://cyrcv2jdgr8cf" path="res://prefab/role/template/RoleTemplate.tscn" id="1_coayb"] +[ext_resource type="PackedScene" uid="uid://dbrig6dq441wo" path="res://prefab/role/template/EnemyTemplate.tscn" id="1_fanet"] [ext_resource type="Script" path="res://src/game/activity/role/enemy/NoWeaponEnemy.cs" id="2_3an4s"] [ext_resource type="Shader" path="res://resource/material/Blend.gdshader" id="2_yunbp"] [ext_resource type="SpriteFrames" uid="uid://ctpkpxgcwb583" path="res://resource/spriteFrames/role/Enemy0002.tres" id="3_hbsqi"] -[sub_resource type="ShaderMaterial" id="ShaderMaterial_8vxx6"] +[sub_resource type="ShaderMaterial" id="ShaderMaterial_5rnql"] resource_local_to_scene = true shader = ExtResource("2_yunbp") shader_parameter/blend = Color(0, 0, 0, 0.470588) @@ -16,7 +16,7 @@ shader_parameter/outline_rainbow = false shader_parameter/outline_use_blend = true -[sub_resource type="ShaderMaterial" id="ShaderMaterial_k8mt5"] +[sub_resource type="ShaderMaterial" id="ShaderMaterial_4qvs8"] resource_local_to_scene = true shader = ExtResource("2_yunbp") shader_parameter/blend = Color(1, 1, 1, 1) @@ -27,14 +27,76 @@ shader_parameter/outline_rainbow = false shader_parameter/outline_use_blend = true -[node name="Enemy0002" node_paths=PackedStringArray("ViewRay", "NavigationAgent2D", "NavigationPoint", "HurtArea", "HurtCollision", "InteractiveArea", "InteractiveCollision", "TipRoot", "TipSprite", "AnimationPlayer", "MountPoint", "BackMountPoint", "MeleeAttackArea", "MeleeAttackCollision", "ShadowSprite", "AnimatedSprite", "Collision") instance=ExtResource("1_coayb")] -collision_layer = 16 -collision_mask = 25 +[sub_resource type="Animation" id="Animation_343jg"] +length = 0.001 +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath("AnimatedSprite:frame") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 1, +"values": [0] +} + +[sub_resource type="Animation" id="Animation_bn678"] +resource_name = "attack" +length = 0.6 +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath("AnimatedSprite:animation") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 1, +"values": [&"attack"] +} +tracks/1/type = "value" +tracks/1/imported = false +tracks/1/enabled = true +tracks/1/path = NodePath("AnimatedSprite:frame") +tracks/1/interp = 1 +tracks/1/loop_wrap = true +tracks/1/keys = { +"times": PackedFloat32Array(0, 0.5), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [0, 7] +} +tracks/2/type = "method" +tracks/2/imported = false +tracks/2/enabled = true +tracks/2/path = NodePath(".") +tracks/2/interp = 1 +tracks/2/loop_wrap = true +tracks/2/keys = { +"times": PackedFloat32Array(0.3), +"transitions": PackedFloat32Array(1), +"values": [{ +"args": [], +"method": &"ShootBullet" +}] +} + +[sub_resource type="AnimationLibrary" id="AnimationLibrary_3ge8m"] +_data = { +"RESET": SubResource("Animation_343jg"), +"attack": SubResource("Animation_bn678") +} + +[node name="Enemy0002" node_paths=PackedStringArray("ViewRay", "NavigationAgent2D", "NavigationPoint", "FirePoint", "HurtArea", "HurtCollision", "InteractiveArea", "InteractiveCollision", "TipRoot", "TipSprite", "AnimationPlayer", "MountPoint", "BackMountPoint", "MeleeAttackArea", "MeleeAttackCollision", "ShadowSprite", "AnimatedSprite", "Collision") instance=ExtResource("1_fanet")] script = ExtResource("2_3an4s") CanPickUpWeapon = false ViewRay = NodePath("ViewRay") NavigationAgent2D = NodePath("NavigationPoint/NavigationAgent2D") NavigationPoint = NodePath("NavigationPoint") +FirePoint = NodePath("FirePoint") HurtArea = NodePath("HurtArea") HurtCollision = NodePath("HurtArea/HurtCollision") InteractiveArea = NodePath("InteractiveArea") @@ -51,30 +113,24 @@ Collision = NodePath("Collision") [node name="ShadowSprite" parent="." index="0"] -material = SubResource("ShaderMaterial_8vxx6") - -[node name="BackMountPoint" parent="." index="1"] -position = Vector2(-2, -7) +material = SubResource("ShaderMaterial_5rnql") [node name="AnimatedSprite" parent="." index="2"] -material = SubResource("ShaderMaterial_k8mt5") +material = SubResource("ShaderMaterial_4qvs8") sprite_frames = ExtResource("3_hbsqi") +animation = &"attack" offset = Vector2(0, -10) [node name="HurtCollision" parent="HurtArea" index="0"] -position = Vector2(-0.5, -7) - -[node name="ViewRay" type="RayCast2D" parent="." index="6"] -position = Vector2(0, -8) -enabled = false +position = Vector2(0, -7) [node name="MountPoint" parent="." index="7"] -position = Vector2(6, -8) +position = Vector2(4, -9) -[node name="NavigationPoint" type="Marker2D" parent="." index="8"] -position = Vector2(0, -5) +[node name="FirePoint" parent="." index="8"] +position = Vector2(7, -6) -[node name="NavigationAgent2D" type="NavigationAgent2D" parent="NavigationPoint" index="0"] -path_desired_distance = 3.0 -target_desired_distance = 3.0 -radius = 20.0 +[node name="AnimationPlayer" parent="." index="11"] +libraries = { +"": SubResource("AnimationLibrary_3ge8m") +} diff --git a/DungeonShooting_Godot/prefab/role/template/EnemyTemplate.tscn b/DungeonShooting_Godot/prefab/role/template/EnemyTemplate.tscn index 272b97a..28fcf5f 100644 --- a/DungeonShooting_Godot/prefab/role/template/EnemyTemplate.tscn +++ b/DungeonShooting_Godot/prefab/role/template/EnemyTemplate.tscn @@ -25,7 +25,7 @@ shader_parameter/outline_rainbow = false shader_parameter/outline_use_blend = true -[node name="AdvancedEnemyTemplate" instance=ExtResource("1_5po38")] +[node name="EnemyTemplate" instance=ExtResource("1_5po38")] collision_layer = 16 collision_mask = 25 @@ -39,7 +39,9 @@ position = Vector2(0, -8) enabled = false -[node name="NavigationPoint" type="Marker2D" parent="." index="8"] +[node name="FirePoint" type="Marker2D" parent="." index="8"] + +[node name="NavigationPoint" type="Marker2D" parent="." index="9"] position = Vector2(0, -5) [node name="NavigationAgent2D" type="NavigationAgent2D" parent="NavigationPoint" index="0"] diff --git a/DungeonShooting_Godot/prefab/role/template/RoleTemplate.tscn b/DungeonShooting_Godot/prefab/role/template/RoleTemplate.tscn index 7b79ea0..edd302e 100644 --- a/DungeonShooting_Godot/prefab/role/template/RoleTemplate.tscn +++ b/DungeonShooting_Godot/prefab/role/template/RoleTemplate.tscn @@ -35,7 +35,7 @@ [sub_resource type="RectangleShape2D" id="RectangleShape2D_n68nu"] size = Vector2(10, 16.5) -[node name="AdvancedRoleTemplate" type="CharacterBody2D"] +[node name="RoleTemplate" type="CharacterBody2D"] collision_layer = 0 [node name="ShadowSprite" type="Sprite2D" parent="."] diff --git a/DungeonShooting_Godot/src/game/AnimatorNames.cs b/DungeonShooting_Godot/src/game/AnimatorNames.cs index 56e3289..bf3d97d 100644 --- a/DungeonShooting_Godot/src/game/AnimatorNames.cs +++ b/DungeonShooting_Godot/src/game/AnimatorNames.cs @@ -9,85 +9,85 @@ /// /// 默认动画 /// - public const string Default = "default"; + public static readonly StringName Default = "default"; /// /// 静止不动 /// - public const string Idle = "idle"; + public static readonly StringName Idle = "idle"; /// /// 奔跑 /// - public const string Run = "run"; + public static readonly StringName Run = "run"; /// /// 倒退奔跑 /// - public const string ReverseRun = "reverseRun"; + public static readonly StringName ReverseRun = "reverseRun"; /// /// 翻滚 /// - public const string Roll = "roll"; + public static readonly StringName Roll = "roll"; /// /// 武器泛光动画 /// - public const string Floodlight = "floodlight"; + public static readonly StringName Floodlight = "floodlight"; /// /// 开门动画 /// - public const string OpenDoor = "openDoor"; + public static readonly StringName OpenDoor = "openDoor"; /// /// 关门动画 /// - public const string CloseDoor = "closeDoor"; + public static readonly StringName CloseDoor = "closeDoor"; /// /// 开火 /// - public const string Fire = "fire"; + public static readonly StringName Fire = "fire"; /// /// 换弹 /// - public const string Reloading = "reloading"; + public static readonly StringName Reloading = "reloading"; /// /// 子弹上膛 /// - public const string BeLoaded = "beLoaded"; + public static readonly StringName BeLoaded = "beLoaded"; /// /// ui入场 /// - public const string In = "in"; + public static readonly StringName In = "in"; /// /// ui出场 /// - public const string Out = "out"; + public static readonly StringName Out = "out"; /// /// 显示动画 /// - public const string Show = "show"; + public static readonly StringName Show = "show"; /// /// 播放特效 /// - public const string Play = "play"; + public static readonly StringName Play = "play"; /// /// 物体移动 /// - public const string Move = "move"; + public static readonly StringName Move = "move"; /// /// 攻击 /// - public const string Attack = "attack"; + public static readonly StringName Attack = "attack"; /// /// 惊讶动作 /// - public const string Astonished = "astonished"; + public static readonly StringName Astonished = "astonished"; /// /// 通知动作 /// - public const string Notify = "notify"; + public static readonly StringName Notify = "notify"; /// /// 疑惑动作 /// - public const string Query = "query"; + public static readonly StringName Query = "query"; /// /// 重置动画 /// - public const string Reset = "RESET"; + public static readonly StringName Reset = "RESET"; } \ No newline at end of file diff --git a/DungeonShooting_Godot/src/game/activity/role/Role.cs b/DungeonShooting_Godot/src/game/activity/role/Role.cs index 3a4e483..15541ef 100644 --- a/DungeonShooting_Godot/src/game/activity/role/Role.cs +++ b/DungeonShooting_Godot/src/game/activity/role/Role.cs @@ -139,12 +139,32 @@ /// /// 是否处于攻击中, 近战攻击远程攻击都算 /// - public bool IsAttack => AttackTimer > 0; + public bool IsAttack + { + get + { + if (AttackTimer > 0 || MeleeAttackTimer > 0) + { + return true; + } + var weapon = WeaponPack.ActiveItem; + if (weapon != null) + { + return weapon.GetAttackTimer() > 0 || weapon.GetContinuousCount() > 0; + } + return false; + } + } /// /// 攻击计时器 /// public float AttackTimer { get; set; } + + /// + /// 近战计时器 + /// + public float MeleeAttackTimer { get; set; } /// /// 是否死亡 @@ -464,6 +484,11 @@ { AttackTimer -= delta; } + + if (MeleeAttackTimer > 0) + { + MeleeAttackTimer -= delta; + } //检查可互动的物体 bool findFlag = false; @@ -1157,7 +1182,7 @@ /// public virtual void Attack() { - if (!IsAttack && WeaponPack.ActiveItem != null) + if (MeleeAttackTimer <= 0 && WeaponPack.ActiveItem != null) { WeaponPack.ActiveItem.Trigger(this); } @@ -1168,14 +1193,14 @@ /// public virtual void MeleeAttack() { - if (IsAttack || AttackTimer > 0) + if (IsAttack) { return; } if (WeaponPack.ActiveItem != null && WeaponPack.ActiveItem.Attribute.CanMeleeAttack) { - AttackTimer = RoleState.MeleeAttackTime; + MeleeAttackTimer = RoleState.MeleeAttackTime; MountLookTarget = false; //播放近战动画 diff --git a/DungeonShooting_Godot/src/game/activity/role/enemy/Enemy.cs b/DungeonShooting_Godot/src/game/activity/role/enemy/Enemy.cs index 4876e62..90c89dd 100644 --- a/DungeonShooting_Godot/src/game/activity/role/enemy/Enemy.cs +++ b/DungeonShooting_Godot/src/game/activity/role/enemy/Enemy.cs @@ -68,6 +68,12 @@ /// [Export, ExportFillNode] public Marker2D NavigationPoint { get; set; } + + /// + /// 不通过武发射子弹的开火点 + /// + [Export, ExportFillNode] + public Marker2D FirePoint { get; set; } /// /// 当前敌人所看向的对象, 也就是枪口指向的对象 diff --git a/DungeonShooting_Godot/src/game/activity/role/enemy/NoWeaponEnemy.cs b/DungeonShooting_Godot/src/game/activity/role/enemy/NoWeaponEnemy.cs index b66c3ab..406dc9f 100644 --- a/DungeonShooting_Godot/src/game/activity/role/enemy/NoWeaponEnemy.cs +++ b/DungeonShooting_Godot/src/game/activity/role/enemy/NoWeaponEnemy.cs @@ -1,4 +1,5 @@  +using Config; using Godot; /// @@ -7,8 +8,32 @@ [Tool] public partial class NoWeaponEnemy : Enemy { + public override void OnInit() + { + base.OnInit(); + AnimationPlayer.AnimationFinished += OnAnimationFinished; + } + public override void Attack() { - Debug.Log("attack..."); + if (AnimatedSprite.Animation != AnimatorNames.Attack) + { + Debug.Log("attack..."); + AnimatedSprite.Play(AnimatorNames.Attack); + } + } + + public void ShootBullet() + { + var bulletData = FireManager.GetBulletData(this, FirePoint.GlobalPosition.AngleTo(LookTarget.Position), ExcelConfig.BulletBase_Map["0006"]); + FireManager.ShootBullet(bulletData, AttackLayer); + } + + private void OnAnimationFinished(StringName name) + { + if (name == AnimatorNames.Attack) + { + AttackTimer = 2f; + } } } \ No newline at end of file diff --git a/DungeonShooting_Godot/src/game/activity/role/enemy/state/AiAttackState.cs b/DungeonShooting_Godot/src/game/activity/role/enemy/state/AiAttackState.cs index 128ec1a..6b70f5e 100644 --- a/DungeonShooting_Godot/src/game/activity/role/enemy/state/AiAttackState.cs +++ b/DungeonShooting_Godot/src/game/activity/role/enemy/state/AiAttackState.cs @@ -14,7 +14,7 @@ public AIStateEnum PrevState; /// - /// 攻击状态 + /// 武器攻击状态 /// public AiAttackEnum AttackState; @@ -219,9 +219,9 @@ //找到武器了, 攻击结束 ChangeState(PrevState); } - else if (AttackState == AiAttackEnum.AttackInterval) //攻击结束 + else if (Master.AttackTimer > 0 || Master.MeleeAttackTimer > 0) //攻击结束 { - + ChangeState(PrevState); } else //攻击状态 { diff --git a/DungeonShooting_Godot/src/game/manager/FireManager.cs b/DungeonShooting_Godot/src/game/manager/FireManager.cs index 3f02409..b7c50db 100644 --- a/DungeonShooting_Godot/src/game/manager/FireManager.cs +++ b/DungeonShooting_Godot/src/game/manager/FireManager.cs @@ -218,8 +218,15 @@ Penetration = Utils.Random.RandomConfigRange(bullet.Penetration), }; - data.Position = role.MountPoint.GlobalPosition; - + if (role is Enemy enemy) + { + data.Position = enemy.FirePoint.GlobalPosition; + } + else + { + data.Position = role.MountPoint.GlobalPosition; + } + var deviationAngle = Utils.Random.RandomConfigRange(bullet.DeviationAngleRange); data.Altitude = role.GetFirePointAltitude(); var roleState = role.RoleState;