diff --git a/DungeonShooting_Godot/prefab/effect/weapon/BulletDisappear.tscn b/DungeonShooting_Godot/prefab/effect/weapon/BulletDisappear.tscn index 54549a1..6572e0c 100644 --- a/DungeonShooting_Godot/prefab/effect/weapon/BulletDisappear.tscn +++ b/DungeonShooting_Godot/prefab/effect/weapon/BulletDisappear.tscn @@ -1,8 +1,8 @@ -[gd_scene load_steps=15 format=3] +[gd_scene load_steps=13 format=3 uid="uid://c6mmikwchwt"] [ext_resource type="Texture2D" uid="uid://d8ot2wrdoe4j" path="res://resource/sprite/effects/Explosion.png" id="1_qqm6c"] -[ext_resource type="Texture2D" uid="uid://h7hkgbwj1li" path="res://resource/sprite/effects/Smoke.png" id="1_ybsvf"] - +[ext_resource type="Texture2D" uid="uid://h7hkgbwj1li" path="res://resource/sprite/effects/common/Smoke.png" id="1_ybsvf"] +[ext_resource type="Script" path="res://src/game/effects/AutoDestroySprite.cs" id="2_l2qlq"] [sub_resource type="AtlasTexture" id="AtlasTexture_tscb3"] atlas = ExtResource("1_qqm6c") @@ -69,63 +69,15 @@ color = Color(0.909804, 0.909804, 0.909804, 0.380392) anim_offset_max = 1.0 -[sub_resource type="Animation" id="Animation_jnfgg"] -resource_name = "Start" -length = 0.3 -tracks/0/type = "value" -tracks/0/imported = false -tracks/0/enabled = true -tracks/0/path = NodePath(".:emitting") -tracks/0/interp = 1 -tracks/0/loop_wrap = true -tracks/0/keys = { -"times": PackedFloat32Array(0), -"transitions": PackedFloat32Array(1), -"update": 1, -"values": [true] -} -tracks/1/type = "method" -tracks/1/imported = false -tracks/1/enabled = true -tracks/1/path = NodePath("..") -tracks/1/interp = 1 -tracks/1/loop_wrap = true -tracks/1/keys = { -"times": PackedFloat32Array(0.3), -"transitions": PackedFloat32Array(1), -"values": [{ -"args": [], -"method": &"queue_free" -}] -} - -[sub_resource type="Animation" id="Animation_yr61b"] -length = 0.001 -tracks/0/type = "value" -tracks/0/imported = false -tracks/0/enabled = true -tracks/0/path = NodePath(".:emitting") -tracks/0/interp = 1 -tracks/0/loop_wrap = true -tracks/0/keys = { -"times": PackedFloat32Array(0), -"transitions": PackedFloat32Array(1), -"update": 1, -"values": [false] -} - -[sub_resource type="AnimationLibrary" id="AnimationLibrary_1spnw"] -_data = { -"RESET": SubResource("Animation_yr61b"), -"Start": SubResource("Animation_jnfgg") -} - -[node name="BulletDisappear" type="AnimatedSprite2D"] +[node name="BulletDisappear" type="AnimatedSprite2D" node_paths=PackedStringArray("Particles2D")] modulate = Color(1, 1, 1, 0.784314) z_index = -4 scale = Vector2(0.5, 0.5) sprite_frames = SubResource("SpriteFrames_ub3cw") autoplay = "default" +script = ExtResource("2_l2qlq") +DelayTime = 0.3 +Particles2D = [NodePath("GPUParticles2D")] [node name="GPUParticles2D" type="GPUParticles2D" parent="."] material = SubResource("CanvasItemMaterial_4bd3q") @@ -136,10 +88,3 @@ one_shot = true explosiveness = 0.9 fixed_fps = 20 - -[node name="AnimationPlayer" type="AnimationPlayer" parent="."] -root_node = NodePath("../GPUParticles2D") -autoplay = "Start" -libraries = { -"": SubResource("AnimationLibrary_1spnw") -} diff --git a/DungeonShooting_Godot/src/game/activity/bullet/Bullet.cs b/DungeonShooting_Godot/src/game/activity/bullet/Bullet.cs index 0794389..b57041b 100644 --- a/DungeonShooting_Godot/src/game/activity/bullet/Bullet.cs +++ b/DungeonShooting_Godot/src/game/activity/bullet/Bullet.cs @@ -13,6 +13,15 @@ public Area2D CollisionArea { get; set; } /// + /// 攻击的层级 + /// + public uint AttackLayer + { + get => CollisionArea.CollisionMask; + set => CollisionArea.CollisionMask = value; + } + + /// /// 发射该子弹的武器 /// public Weapon Weapon { get; private set; } @@ -55,7 +64,7 @@ { Weapon = weapon; Role = weapon.Master; - CollisionArea.CollisionMask = targetLayer; + AttackLayer = targetLayer; CollisionArea.AreaEntered += OnArea2dEntered; //只有玩家使用该武器才能获得正常速度的子弹 @@ -81,6 +90,17 @@ // } } + /// + /// 播放子弹消失的特效 + /// + public virtual void PlayDisappearEffect() + { + var packedScene = ResourceManager.Load(ResourcePath.prefab_effect_weapon_BulletDisappear_tscn); + var node = packedScene.Instantiate(); + node.GlobalPosition = GlobalPosition; + node.AddToActivityRoot(RoomLayerEnum.YSortLayer); + } + protected override void PhysicsProcessOver(float delta) { //移动 @@ -102,15 +122,11 @@ CurrFlyDistance += FlySpeed * delta; if (CurrFlyDistance >= MaxDistance) { - var packedScene = ResourceManager.Load(ResourcePath.prefab_effect_weapon_BulletDisappear_tscn); - var node = packedScene.Instantiate(); - node.GlobalPosition = GlobalPosition; - node.AddToActivityRoot(RoomLayerEnum.YSortLayer); - + PlayDisappearEffect(); Destroy(); } } - + private void OnArea2dEntered(Area2D other) { var role = other.AsActivityObject(); diff --git a/DungeonShooting_Godot/src/game/activity/role/Role.cs b/DungeonShooting_Godot/src/game/activity/role/Role.cs index c37cd51..0f52874 100644 --- a/DungeonShooting_Godot/src/game/activity/role/Role.cs +++ b/DungeonShooting_Godot/src/game/activity/role/Role.cs @@ -1117,7 +1117,7 @@ MeleeAttackAngle, 6 ); - MeleeAttackArea.CollisionMask = AttackLayer; + MeleeAttackArea.CollisionMask = AttackLayer | PhysicsLayer.Bullet; } } @@ -1134,12 +1134,21 @@ var activityObject = body.AsActivityObject(); if (activityObject != null) { - if (activityObject is Role role) + if (activityObject is Role role) //攻击角色 { var damage = Utils.Random.RandomConfigRange(activeWeapon.Attribute.MeleeAttackHarmRange); damage = RoleState.CallCalcDamageEvent(damage); role.CallDeferred(nameof(Hurt), damage, (role.GetCenterPosition() - GlobalPosition).Angle()); } + else if (activityObject is Bullet bullet) //攻击子弹 + { + var attackLayer = bullet.AttackLayer; + if (CollisionWithMask(attackLayer)) //是攻击玩家的子弹 + { + bullet.PlayDisappearEffect(); + bullet.Destroy(); + } + } } } diff --git a/DungeonShooting_Godot/src/game/activity/role/Role_Animation.cs b/DungeonShooting_Godot/src/game/activity/role/Role_Animation.cs index 977c5ef..8de62e5 100644 --- a/DungeonShooting_Godot/src/game/activity/role/Role_Animation.cs +++ b/DungeonShooting_Godot/src/game/activity/role/Role_Animation.cs @@ -19,9 +19,9 @@ var tween = CreateTween(); tween.SetParallel(); - tween.TweenProperty(MountPoint, "rotation_degrees", r - MeleeAttackAngle / 2f, 0.12); - tween.TweenProperty(MountPoint, "position", p2, 0.12); - tween.TweenProperty(MountPoint, "position", p2, 0.12); + tween.TweenProperty(MountPoint, "rotation_degrees", r - MeleeAttackAngle / 2f, 0.1); + tween.TweenProperty(MountPoint, "position", p2, 0.1); + tween.TweenProperty(MountPoint, "position", p2, 0.1); tween.Chain(); tween.TweenCallback(Callable.From(() => diff --git a/DungeonShooting_Godot/src/game/activity/weapon/Weapon.cs b/DungeonShooting_Godot/src/game/activity/weapon/Weapon.cs index 0cc4c41..abc4a4d 100644 --- a/DungeonShooting_Godot/src/game/activity/weapon/Weapon.cs +++ b/DungeonShooting_Godot/src/game/activity/weapon/Weapon.cs @@ -135,6 +135,11 @@ /// public bool IsAutoPlaySpriteFrames { get; set; } = true; + /// + /// 在没有所属 Master 的时候是否可以触发扳机 + /// + public bool NoMasterCanTrigger { get; set; } = true; + //-------------------------------------------------------------------------------------------- //触发按下扳机的角色 @@ -663,6 +668,9 @@ /// 按下扳机的角色, 如果传 null, 则视为走火 public void Trigger(Role trigger) { + //不能触发扳机 + if (!NoMasterCanTrigger && Master == null) return; + //这一帧已经按过了, 不需要再按下 if (_triggerFlag) return; diff --git a/DungeonShooting_Godot/src/game/activity/weapon/knife/Knife.cs b/DungeonShooting_Godot/src/game/activity/weapon/knife/Knife.cs index 5c6f5ed..f8d56f1 100644 --- a/DungeonShooting_Godot/src/game/activity/weapon/knife/Knife.cs +++ b/DungeonShooting_Godot/src/game/activity/weapon/knife/Knife.cs @@ -26,7 +26,9 @@ public override void OnInit() { base.OnInit(); - + + //没有Master时不能触发开火 + NoMasterCanTrigger = false; _hitArea = GetNode("HitArea"); _collisionPolygon = new CollisionPolygon2D(); var a = Mathf.Abs(-BeginChargeAngle + Attribute.UpliftAngle); @@ -72,7 +74,7 @@ { GD.Print("近战武器攻击! 蓄力时长: " + GetTriggerChargeTime() + ", 扳机按下时长: " + GetTriggerDownTime()); //更新碰撞层级 - _hitArea.CollisionMask = GetAttackLayer(); + _hitArea.CollisionMask = GetAttackLayer() | PhysicsLayer.Bullet; //启用碰撞 _hitArea.Monitoring = true; _attackIndex = 0; @@ -125,7 +127,7 @@ var activityObject = body.AsActivityObject(); if (activityObject != null) { - if (activityObject is Role role) + if (activityObject is Role role) //碰到角色 { var damage = Utils.Random.RandomConfigRange(Attribute.HarmRange); if (Master != null) @@ -135,6 +137,17 @@ role.CallDeferred(nameof(Role.Hurt), damage, (role.GetCenterPosition() - GlobalPosition).Angle()); } + else if (activityObject is Bullet bullet) //攻击子弹 + { + var attackLayer = bullet.AttackLayer; + if (Master.CollisionWithMask(attackLayer)) //是攻击玩家的子弹 + { + bullet.PlayDisappearEffect(); + bullet.BasisVelocity = bullet.BasisVelocity.Rotated(Mathf.Pi); + bullet.Rotation += Mathf.Pi; + bullet.AttackLayer = Master.AttackLayer; + } + } } } } diff --git a/DungeonShooting_Godot/src/game/effects/AutoDestroySprite.cs b/DungeonShooting_Godot/src/game/effects/AutoDestroySprite.cs index 857819d..a24db0c 100644 --- a/DungeonShooting_Godot/src/game/effects/AutoDestroySprite.cs +++ b/DungeonShooting_Godot/src/game/effects/AutoDestroySprite.cs @@ -1,4 +1,5 @@ using Godot; +using Godot.Collections; /// /// 到期自动销毁的帧动画 @@ -11,9 +12,22 @@ [Export] public float DelayTime { get; set; } = 1f; + /// + /// 子节点包含的例子特效, 在创建完成后自动播放 + /// + [Export] + public Array Particles2D { get; set; } + public override async void _Ready() { var sceneTreeTimer = GetTree().CreateTimer(DelayTime); + if (Particles2D != null) + { + foreach (var gpuParticles2D in Particles2D) + { + gpuParticles2D.Emitting = true; + } + } await ToSignal(sceneTreeTimer, Timer.SignalName.Timeout); QueueFree(); }