加入阵营系统, 目前子弹敌我判定还有点问题

This commit is contained in:
小李xl 2024-04-03 23:57:00 +08:00
parent be8dd86b29
commit 83089eb80f
23 changed files with 131 additions and 106 deletions

View File

@ -24,7 +24,7 @@ size = Vector2(12, 18)
[sub_resource type="AnimationLibrary" id="AnimationLibrary_ka171"] [sub_resource type="AnimationLibrary" id="AnimationLibrary_ka171"]
[node name="Role0001" node_paths=PackedStringArray("HurtArea", "HurtCollision", "InteractiveArea", "InteractiveCollision", "TipRoot", "TipSprite", "AnimationPlayer", "MountPoint", "BackMountPoint", "MeleeAttackArea", "MeleeAttackCollision", "ShadowSprite", "AnimatedSprite", "Collision") instance=ExtResource("1_10c2n")] [node name="Role0001" node_paths=PackedStringArray("HurtArea", "HurtCollision", "InteractiveArea", "InteractiveCollision", "TipRoot", "TipSprite", "AnimationPlayer", "MountPoint", "BackMountPoint", "MeleeAttackArea", "MeleeAttackCollision", "ShadowSprite", "AnimatedSprite", "Collision") instance=ExtResource("1_10c2n")]
collision_layer = 8 collision_layer = 24
script = ExtResource("2_6xwnt") script = ExtResource("2_6xwnt")
HurtArea = NodePath("HurtArea") HurtArea = NodePath("HurtArea")
HurtCollision = NodePath("HurtArea/HurtCollision") HurtCollision = NodePath("HurtArea/HurtCollision")

View File

@ -46,7 +46,7 @@ position = Vector2(0, -2)
shape = SubResource("CircleShape2D_5pj80") shape = SubResource("CircleShape2D_5pj80")
[node name="HurtArea" type="Area2D" parent="."] [node name="HurtArea" type="Area2D" parent="."]
collision_layer = 0 collision_layer = 1024
collision_mask = 0 collision_mask = 0
monitoring = false monitoring = false
script = ExtResource("2_2eey0") script = ExtResource("2_2eey0")

View File

@ -246,13 +246,13 @@ roulette={
2d_physics/layer_2="bullet" 2d_physics/layer_2="bullet"
2d_physics/layer_3="prop" 2d_physics/layer_3="prop"
2d_physics/layer_4="player" 2d_physics/layer_4="player"
2d_physics/layer_5="enemy" 2d_physics/layer_5="role"
2d_physics/layer_6="affiliation" 2d_physics/layer_6="affiliation"
2d_physics/layer_7="onHand" 2d_physics/layer_7="onHand"
2d_physics/layer_8="debris" 2d_physics/layer_8="debris"
2d_physics/layer_9="throwing" 2d_physics/layer_9="throwing"
2d_physics/layer_10="obstacle" 2d_physics/layer_10="obstacle"
2d_physics/layer_11="npc" 2d_physics/layer_11="hurtArea"
2d_physics/layer_14="ui_mouse" 2d_physics/layer_14="ui_mouse"
[mono] [mono]

View File

@ -1,17 +1,19 @@
using Godot; using Godot;
/// <summary>
/// 可被子弹击中的区域
/// </summary>
[Tool] [Tool]
public partial class HurtArea : Area2D, IHurt public partial class HurtArea : Area2D, IHurt
{ {
public delegate void HurtDelegate(ActivityObject target, int damage, float angle); /// <summary>
/// 所属角色
/// </summary>
public Role Master { get; private set; }
public event HurtDelegate OnHurtEvent; public void InitRole(Role role)
public ActivityObject ActivityObject { get; private set; }
public void InitActivityObject(ActivityObject activityObject)
{ {
ActivityObject = activityObject; Master = role;
} }
public override void _Ready() public override void _Ready()
@ -19,11 +21,23 @@ public partial class HurtArea : Area2D, IHurt
Monitoring = false; Monitoring = false;
} }
public bool CanHurt(ActivityObject target)
{
//无敌状态
if (Master.Invincible)
{
return true;
}
if (target is Role role)
{
return Master.IsEnemy(role);
}
return true;
}
public void Hurt(ActivityObject target, int damage, float angle) public void Hurt(ActivityObject target, int damage, float angle)
{ {
if (OnHurtEvent != null) Master.CallDeferred(nameof(Master.HurtHandler), target, damage, angle);
{
OnHurtEvent(target, damage, angle);
}
} }
} }

View File

@ -3,6 +3,12 @@ using Godot;
public interface IHurt public interface IHurt
{ {
/// <summary>
/// 返回是否可以造成伤害
/// </summary>
/// <param name="target">触发伤害的对象, 为 null 表示不存在对象或者对象已经被销毁</param>
bool CanHurt(ActivityObject target);
/// <summary> /// <summary>
/// 受到伤害 /// 受到伤害
/// </summary> /// </summary>

View File

@ -21,7 +21,7 @@ public static class NodeExtend
if (hurt is HurtArea hurtArea) if (hurt is HurtArea hurtArea)
{ {
return hurtArea.ActivityObject; return hurtArea.Master;
} }
return null; return null;

View File

@ -64,7 +64,7 @@ public partial class AffiliationArea : Area2D, IDestroy
Monitoring = true; Monitoring = true;
Monitorable = false; Monitorable = false;
CollisionLayer = PhysicsLayer.None; CollisionLayer = PhysicsLayer.None;
CollisionMask = PhysicsLayer.Prop | PhysicsLayer.Player | PhysicsLayer.Enemy | PhysicsLayer.Debris | PhysicsLayer.Throwing; CollisionMask = PhysicsLayer.Prop | PhysicsLayer.Role | PhysicsLayer.Debris | PhysicsLayer.Throwing | PhysicsLayer.Obstacle;
BodyEntered += OnBodyEntered; BodyEntered += OnBodyEntered;
BodyExited += OnBodyExited; BodyExited += OnBodyExited;

View File

@ -317,7 +317,7 @@ public class RoomPreinstall : IDestroy
foreach (var preloadData in _readyList) foreach (var preloadData in _readyList)
{ {
//有敌人 //有敌人
if (!hasEnemy && preloadData.ActivityObject.CollisionWithMask(PhysicsLayer.Enemy)) if (!hasEnemy && preloadData.ActivityObject is Role role && role.IsEnemyWithPlayer())
{ {
hasEnemy = true; hasEnemy = true;
} }
@ -332,7 +332,7 @@ public class RoomPreinstall : IDestroy
if (!hasEnemy) if (!hasEnemy)
{ {
hasEnemy = RoomInfo.AffiliationArea.ExistIncludeItem( hasEnemy = RoomInfo.AffiliationArea.ExistIncludeItem(
activityObject => activityObject.CollisionWithMask(PhysicsLayer.Enemy) activityObject => activityObject is Role role && role.IsEnemyWithPlayer()
); );
} }

View File

@ -474,7 +474,7 @@ public class RoomInfo : IDestroy
//房间内有敌人, 或者会刷新敌人才会关门 //房间内有敌人, 或者会刷新敌人才会关门
var hasEnemy = false; var hasEnemy = false;
if (AffiliationArea.ExistEnterItem(activityObject => activityObject.CollisionWithMask(PhysicsLayer.Enemy))) //先判断房间里面是否有敌人 if (AffiliationArea.ExistEnterItem(activityObject => activityObject is Role role && role.IsEnemyWithPlayer())) //先判断房间里面是否有敌人
{ {
hasEnemy = true; hasEnemy = true;
} }

View File

@ -164,7 +164,11 @@ public partial class Explode : Area2D, IPoolItem
if (len <= _hitRadius) //在伤害半径内 if (len <= _hitRadius) //在伤害半径内
{ {
hurt.Hurt(BulletData.TriggerRole.IsDestroyed ? null : BulletData.TriggerRole, _harm, angle); var target = BulletData.TriggerRole.IsDestroyed ? null : BulletData.TriggerRole;
if (hurt.CanHurt(target))
{
hurt.Hurt(target, _harm, angle);
}
} }
if (len <= _repelledRadius) //击退半径内 if (len <= _repelledRadius) //击退半径内

View File

@ -224,7 +224,11 @@ public partial class Laser : Area2D, IBullet
} }
//造成伤害 //造成伤害
hurt.Hurt(BulletData.TriggerRole.IsDestroyed ? null : BulletData.TriggerRole, BulletData.Harm, Rotation); var target = BulletData.TriggerRole.IsDestroyed ? null : BulletData.TriggerRole;
if (hurt.CanHurt(target))
{
hurt.Hurt(target, BulletData.Harm, Rotation);
}
} }
public long StartCoroutine(IEnumerator able) public long StartCoroutine(IEnumerator able)

View File

@ -204,7 +204,11 @@ public partial class Bullet : ActivityObject, IBullet
} }
//造成伤害 //造成伤害
hurt.Hurt(BulletData.TriggerRole.IsDestroyed ? null : BulletData.TriggerRole, BulletData.Harm, Rotation); var target = BulletData.TriggerRole.IsDestroyed ? null : BulletData.TriggerRole;
if (hurt.CanHurt(target))
{
hurt.Hurt(target, BulletData.Harm, Rotation);
}
//穿透次数 //穿透次数
CurrentPenetration++; CurrentPenetration++;

View File

@ -7,6 +7,11 @@ using Godot;
[Tool] [Tool]
public partial class ObstacleObject : ActivityObject, IHurt public partial class ObstacleObject : ActivityObject, IHurt
{ {
public virtual bool CanHurt(ActivityObject target)
{
return true;
}
public virtual void Hurt(ActivityObject target, int damage, float angle) public virtual void Hurt(ActivityObject target, int damage, float angle)
{ {
} }

View File

@ -1,10 +1,28 @@
public enum CampEnum public enum CampEnum
{ {
// 阵营1, 玩家 /// <summary>
/// 无阵营, 所有角色都视为敌人
/// </summary>
None,
/// <summary>
/// 和平阵营, 不会被攻击
/// </summary>
Peace,
/// <summary>
/// 阵营1, 玩家
/// </summary>
Camp1, Camp1,
// 阵营2, 敌人 /// <summary>
/// 阵营2, 敌人
/// </summary>
Camp2, Camp2,
// 阵营3, 中立单位 /// <summary>
Camp3 /// 阵营3, 敌人2
/// </summary>
Camp3,
/// <summary>
/// 阵营4, 敌人3
/// </summary>
Camp4,
} }

View File

@ -10,6 +10,11 @@ using Godot;
/// </summary> /// </summary>
public abstract partial class Role : ActivityObject public abstract partial class Role : ActivityObject
{ {
/// <summary>
/// 攻击目标的碰撞器所属层级, 数据源自于: <see cref="PhysicsLayer"/>
/// </summary>
public const uint AttackLayer = PhysicsLayer.Wall | PhysicsLayer.Obstacle | PhysicsLayer.HurtArea;
/// <summary> /// <summary>
/// 当前角色对其他角色造成伤害时对回调 /// 当前角色对其他角色造成伤害时对回调
/// 参数1为目标角色 /// 参数1为目标角色
@ -27,11 +32,6 @@ public abstract partial class Role : ActivityObject
/// </summary> /// </summary>
public RoleState RoleState { get; private set; } public RoleState RoleState { get; private set; }
/// <summary>
/// 默认攻击对象层级
/// </summary>
public const uint DefaultAttackLayer = PhysicsLayer.Player | PhysicsLayer.Enemy | PhysicsLayer.Obstacle;
/// <summary> /// <summary>
/// 伤害区域 /// 伤害区域
/// </summary> /// </summary>
@ -47,17 +47,7 @@ public abstract partial class Role : ActivityObject
/// <summary> /// <summary>
/// 所属阵营 /// 所属阵营
/// </summary> /// </summary>
public CampEnum Camp; public CampEnum Camp { get; set; }
/// <summary>
/// 攻击目标的碰撞器所属层级, 数据源自于: <see cref="PhysicsLayer"/>
/// </summary>
public uint AttackLayer { get; set; } = PhysicsLayer.Wall | PhysicsLayer.Obstacle;
/// <summary>
/// 该角色敌对目标的碰撞器所属层级, 数据源自于: <see cref="PhysicsLayer"/>
/// </summary>
public uint EnemyLayer { get; set; } = PhysicsLayer.Enemy;
/// <summary> /// <summary>
/// 携带的被动道具列表 /// 携带的被动道具列表
@ -282,20 +272,11 @@ public abstract partial class Role : ActivityObject
{ {
if (value) //无敌状态 if (value) //无敌状态
{ {
if (HurtArea != null)
{
HurtArea.CollisionLayer = _currentLayer;
}
_flashingInvincibleTimer = -1; _flashingInvincibleTimer = -1;
_flashingInvincibleFlag = false; _flashingInvincibleFlag = false;
} }
else //正常状态 else //正常状态
{ {
if (HurtArea != null)
{
HurtArea.CollisionLayer = _currentLayer;
}
SetBlendModulate(new Color(1, 1, 1, 1)); SetBlendModulate(new Color(1, 1, 1, 1));
} }
} }
@ -335,7 +316,6 @@ public abstract partial class Role : ActivityObject
private Vector2 _startScale; private Vector2 _startScale;
//当前可互动的物体 //当前可互动的物体
private CheckInteractiveResult _currentResultData; private CheckInteractiveResult _currentResultData;
private uint _currentLayer;
//闪烁计时器 //闪烁计时器
private float _flashingInvincibleTimer = -1; private float _flashingInvincibleTimer = -1;
//闪烁状态 //闪烁状态
@ -479,15 +459,7 @@ public abstract partial class Role : ActivityObject
_startScale = Scale; _startScale = Scale;
HurtArea.InitActivityObject(this); HurtArea.InitRole(this);
HurtArea.CollisionLayer = CollisionLayer;
HurtArea.CollisionMask = PhysicsLayer.None;
_currentLayer = HurtArea.CollisionLayer;
//CollisionLayer = PhysicsLayer.None;
HurtArea.OnHurtEvent += (target, damage, angle) =>
{
CallDeferred(nameof(HurtHandler), target, damage, angle);
};
Face = FaceDirection.Right; Face = FaceDirection.Right;
@ -857,7 +829,7 @@ public abstract partial class Role : ActivityObject
/// <param name="target">触发伤害的对象, 为 null 表示不存在对象或者对象已经被销毁</param> /// <param name="target">触发伤害的对象, 为 null 表示不存在对象或者对象已经被销毁</param>
/// <param name="damage">伤害的量</param> /// <param name="damage">伤害的量</param>
/// <param name="angle">伤害角度(弧度制)</param> /// <param name="angle">伤害角度(弧度制)</param>
protected virtual void HurtHandler(ActivityObject target, int damage, float angle) public virtual void HurtHandler(ActivityObject target, int damage, float angle)
{ {
//受伤闪烁, 无敌状态 //受伤闪烁, 无敌状态
if (Invincible) if (Invincible)
@ -1016,6 +988,20 @@ public abstract partial class Role : ActivityObject
return this == World.Player; return this == World.Player;
} }
/// <summary>
/// 返回指定角色是否是敌人
/// </summary>
public bool IsEnemy(Role other)
{
if (other.Camp == Camp || other.Camp == CampEnum.Peace || Camp == CampEnum.Peace)
{
return false;
}
return true;
}
/// <summary> /// <summary>
/// 是否是玩家的敌人 /// 是否是玩家的敌人
/// </summary> /// </summary>
@ -1025,7 +1011,7 @@ public abstract partial class Role : ActivityObject
{ {
return false; return false;
} }
return CollisionWithMask(World.Player.EnemyLayer); return IsEnemy(World.Player);
} }
/// <summary> /// <summary>
@ -1437,8 +1423,11 @@ public abstract partial class Role : ActivityObject
var v2 = position.Normalized() * repel; var v2 = position.Normalized() * repel;
o.AddRepelForce(v2); o.AddRepelForce(v2);
} }
hurt.Hurt(this, damage, (pos - GlobalPosition).Angle()); if (hurt.CanHurt(this))
{
hurt.Hurt(this, damage, (pos - GlobalPosition).Angle());
}
} }
protected override void OnDestroy() protected override void OnDestroy()

View File

@ -63,9 +63,6 @@ public partial class Enemy : AiRole
public override void OnInit() public override void OnInit()
{ {
base.OnInit(); base.OnInit();
AttackLayer = PhysicsLayer.Obstacle | PhysicsLayer.Player;
EnemyLayer = PhysicsLayer.Player;
Camp = CampEnum.Camp2; Camp = CampEnum.Camp2;
RoleState.MoveSpeed = 20; RoleState.MoveSpeed = 20;

View File

@ -37,8 +37,6 @@ public partial class Player : Role
IsAi = false; IsAi = false;
StateController = AddComponent<StateController<Player, PlayerStateEnum>>(); StateController = AddComponent<StateController<Player, PlayerStateEnum>>();
AttackLayer = PhysicsLayer.Obstacle | PhysicsLayer.Enemy;
EnemyLayer = EnemyLayer = PhysicsLayer.Enemy;
Camp = CampEnum.Camp1; Camp = CampEnum.Camp1;
MaxHp = 6; MaxHp = 6;
@ -223,10 +221,14 @@ public partial class Player : Role
} }
else if (Input.IsKeyPressed(Key.O)) //测试用, 消灭房间内所有敌人 else if (Input.IsKeyPressed(Key.O)) //测试用, 消灭房间内所有敌人
{ {
var enemyList = AffiliationArea.FindIncludeItems(o => o.CollisionWithMask(PhysicsLayer.Enemy)); var enemyList = AffiliationArea.FindIncludeItems(o => o is Role role && role.IsEnemyWithPlayer());
foreach (var enemy in enemyList) foreach (var enemy in enemyList)
{ {
((Enemy)enemy).HurtArea.Hurt(this, 1000, 0); var hurt = ((Enemy)enemy).HurtArea;
if (hurt.CanHurt(this))
{
hurt.Hurt(this, 1000, 0);
}
} }
} }
// //测试用 // //测试用

View File

@ -28,9 +28,9 @@ public abstract partial class Weapon : ActivityObject, IPackageItem<Role>
private ExcelConfig.WeaponBase _aiWeaponAttribute; private ExcelConfig.WeaponBase _aiWeaponAttribute;
/// <summary> /// <summary>
/// 武器攻击的目标阵营 /// 攻击目标层级
/// </summary> /// </summary>
public CampEnum TargetCamp { get; set; } public uint AttackLayer => Role.AttackLayer;
public Role Master { get; set; } public Role Master { get; set; }
@ -149,11 +149,6 @@ public abstract partial class Weapon : ActivityObject, IPackageItem<Role>
/// </summary> /// </summary>
public Role TriggerRole { get; private set; } public Role TriggerRole { get; private set; }
/// <summary>
/// 上一次触发改武器开火的触发开火攻击的层级, 数据源自于: <see cref="PhysicsLayer"/>
/// </summary>
public long TriggerRoleAttackLayer { get; private set; }
/// <summary> /// <summary>
/// 武器当前射速 /// 武器当前射速
/// </summary> /// </summary>
@ -850,13 +845,11 @@ public abstract partial class Weapon : ActivityObject, IPackageItem<Role>
if (triggerRole != null) if (triggerRole != null)
{ {
TriggerRole = triggerRole; TriggerRole = triggerRole;
TriggerRoleAttackLayer = triggerRole.AttackLayer;
SetCurrentWeaponAttribute(triggerRole.IsAi ? _aiWeaponAttribute : _playerWeaponAttribute); SetCurrentWeaponAttribute(triggerRole.IsAi ? _aiWeaponAttribute : _playerWeaponAttribute);
} }
else if (Master != null) else if (Master != null)
{ {
TriggerRole = Master; TriggerRole = Master;
TriggerRoleAttackLayer = Master.AttackLayer;
SetCurrentWeaponAttribute(Master.IsAi ? _aiWeaponAttribute : _playerWeaponAttribute); SetCurrentWeaponAttribute(Master.IsAi ? _aiWeaponAttribute : _playerWeaponAttribute);
} }
@ -1275,19 +1268,6 @@ public abstract partial class Weapon : ActivityObject, IPackageItem<Role>
return AiUseAttribute; return AiUseAttribute;
} }
/// <summary>
/// 获取武器攻击的目标层级
/// </summary>
/// <returns></returns>
public uint GetAttackLayer()
{
if (TriggerRoleAttackLayer > 0)
{
return (uint)TriggerRoleAttackLayer;
}
return Master != null ? Master.AttackLayer : Role.DefaultAttackLayer;
}
/// <summary> /// <summary>
/// 返回弹药是否到达上限 /// 返回弹药是否到达上限
/// </summary> /// </summary>

View File

@ -75,7 +75,7 @@ public partial class Knife : Weapon
{ {
Debug.Log("近战武器攻击! 蓄力时长: " + GetTriggerChargeTime() + ", 扳机按下时长: " + GetTriggerDownTime()); Debug.Log("近战武器攻击! 蓄力时长: " + GetTriggerChargeTime() + ", 扳机按下时长: " + GetTriggerDownTime());
//更新碰撞层级 //更新碰撞层级
_hitArea.CollisionMask = GetAttackLayer() | PhysicsLayer.Bullet; _hitArea.CollisionMask = AttackLayer | PhysicsLayer.Bullet;
//启用碰撞 //启用碰撞
_hitArea.Monitoring = true; _hitArea.Monitoring = true;
_attackIndex = 0; _attackIndex = 0;
@ -143,7 +143,6 @@ public partial class Knife : Weapon
} }
bullet.MoveController.ScaleAllVelocity(scale); bullet.MoveController.ScaleAllVelocity(scale);
bullet.Rotation += Mathf.Pi; bullet.Rotation += Mathf.Pi;
bullet.AttackLayer = TriggerRole.AttackLayer;
bullet.RefreshBulletColor(false); bullet.RefreshBulletColor(false);
} }
} }
@ -195,6 +194,9 @@ public partial class Knife : Weapon
} }
//造成伤害 //造成伤害
hurt.Hurt(TriggerRole, damage, (hurt.GetPosition() - globalPosition).Angle()); if (hurt.CanHurt(TriggerRole))
{
hurt.Hurt(TriggerRole, damage, (hurt.GetPosition() - globalPosition).Angle());
}
} }
} }

View File

@ -24,9 +24,9 @@ public class PhysicsLayer
/// </summary> /// </summary>
public const uint Player = 0b1000; public const uint Player = 0b1000;
/// <summary> /// <summary>
/// 敌人 /// 角色基类
/// </summary> /// </summary>
public const uint Enemy = 0b10000; public const uint Role = 0b10000;
/// <summary> /// <summary>
/// 归属区域判断层级 /// 归属区域判断层级
/// </summary> /// </summary>
@ -48,7 +48,7 @@ public class PhysicsLayer
/// </summary> /// </summary>
public const uint Obstacle = 0b1000000000; public const uint Obstacle = 0b1000000000;
/// <summary> /// <summary>
/// npc /// 可被子弹击中的区域
/// </summary> /// </summary>
public const uint Npc = 0b10000000000; public const uint HurtArea = 0b10000000000;
} }

View File

@ -97,11 +97,11 @@ public static class FireManager
{ {
if (bullet.Type == 1) //实体子弹 if (bullet.Type == 1) //实体子弹
{ {
return ShootSolidBullet(CreateSolidBulletData(weapon, fireRotation, bullet), weapon.GetAttackLayer()); return ShootSolidBullet(CreateSolidBulletData(weapon, fireRotation, bullet), weapon.AttackLayer);
} }
else if (bullet.Type == 2) //激光子弹 else if (bullet.Type == 2) //激光子弹
{ {
return ShootLaser(CreateLaserData(weapon, fireRotation, bullet), weapon.GetAttackLayer()); return ShootLaser(CreateLaserData(weapon, fireRotation, bullet), weapon.AttackLayer);
} }
else else
{ {
@ -118,7 +118,7 @@ public static class FireManager
{ {
if (bullet.Type == 1) //实体子弹 if (bullet.Type == 1) //实体子弹
{ {
return ShootSolidBullet(CreateSolidBulletData(trigger, fireRotation, bullet), trigger.AttackLayer); return ShootSolidBullet(CreateSolidBulletData(trigger, fireRotation, bullet), Role.AttackLayer);
} }
return null; return null;

View File

@ -904,7 +904,7 @@ public partial class DungeonManager : Node2D
{ {
//房间内是否有存活的敌人 //房间内是否有存活的敌人
var flag = ActiveAffiliationArea.ExistEnterItem( var flag = ActiveAffiliationArea.ExistEnterItem(
activityObject => activityObject.CollisionWithMask(PhysicsLayer.Enemy) activityObject => activityObject is Role role && role.IsEnemyWithPlayer()
); );
//Debug.Log("当前房间存活数量: " + count); //Debug.Log("当前房间存活数量: " + count);
if (!flag) if (!flag)