Modifies the return value of the damage Api to whether fatal damage has been inflicted. Add the projectile decorator.
修改伤害Api的返回值为是否造成了致命伤害。加入抛射体装饰器。
This commit is contained in:
parent
e54b62cb82
commit
bac2ae1992
|
@ -502,8 +502,8 @@ public partial class CharacterTemplate : CharacterBody2D
|
||||||
///<para>伤害模板</para>
|
///<para>伤害模板</para>
|
||||||
/// </param>
|
/// </param>
|
||||||
/// <returns>
|
/// <returns>
|
||||||
///<para>Return whether the damage was done successfully</para>
|
///<para>Return whether the character is dead</para>
|
||||||
///<para>返回是否成功造成了伤害</para>
|
///<para>返回本次伤害是否导致角色死亡。</para>
|
||||||
/// </returns>
|
/// </returns>
|
||||||
public bool Damage(DamageTemplate damageTemplate)
|
public bool Damage(DamageTemplate damageTemplate)
|
||||||
{
|
{
|
||||||
|
@ -517,12 +517,10 @@ public partial class CharacterTemplate : CharacterBody2D
|
||||||
//角色死亡
|
//角色死亡
|
||||||
OnDie(damageTemplate);
|
OnDie(damageTemplate);
|
||||||
ThrowAllItemOnDie();
|
ThrowAllItemOnDie();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
UpDataHealthBar();
|
UpDataHealthBar();
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
using ColdMint.scripts.utils;
|
using ColdMint.scripts.utils;
|
||||||
|
|
||||||
namespace ColdMint.scripts.loot;
|
namespace ColdMint.scripts.loot;
|
||||||
|
@ -9,7 +8,7 @@ namespace ColdMint.scripts.loot;
|
||||||
/// <para>Loot entry</para>
|
/// <para>Loot entry</para>
|
||||||
/// <para>战利品条目</para>
|
/// <para>战利品条目</para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly struct LootEntry(string itemId,int minQuantity=1,int maxQuantity = 1,int weight = 1)
|
public readonly struct LootEntry(string itemId, int minQuantity = 1, int maxQuantity = 1, int weight = 1)
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <para>ID of item</para>
|
/// <para>ID of item</para>
|
||||||
|
@ -40,8 +39,14 @@ public readonly struct LootEntry(string itemId,int minQuantity=1,int maxQuantity
|
||||||
/// <para>Loot Group</para>
|
/// <para>Loot Group</para>
|
||||||
/// <para>战利品分组</para>
|
/// <para>战利品分组</para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="Chance"></param>
|
/// <param name="Chance">
|
||||||
/// <param name="Entries"></param>
|
///<para>Chance</para>
|
||||||
|
///<para>概率</para>
|
||||||
|
/// </param>
|
||||||
|
/// <param name="Entries">
|
||||||
|
///<para>Entries</para>
|
||||||
|
///<para>条目列表</para>
|
||||||
|
/// </param>
|
||||||
public readonly record struct LootGroup(double Chance, IEnumerable<LootEntry> Entries)
|
public readonly record struct LootGroup(double Chance, IEnumerable<LootEntry> Entries)
|
||||||
{
|
{
|
||||||
private int WeightSum { get; } = Entries.Sum(entry => entry.Weight);
|
private int WeightSum { get; } = Entries.Sum(entry => entry.Weight);
|
||||||
|
@ -61,6 +66,6 @@ public readonly record struct LootGroup(double Chance, IEnumerable<LootEntry> En
|
||||||
|
|
||||||
var quantity = random.Next(entry.MinQuantity, entry.MaxQuantity + 1);
|
var quantity = random.Next(entry.MinQuantity, entry.MaxQuantity + 1);
|
||||||
|
|
||||||
return new(entry.ItemId, quantity);
|
return new LootDatum(entry.ItemId, quantity);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -10,19 +10,17 @@ public static class LootRegister
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static void StaticRegister()
|
public static void StaticRegister()
|
||||||
{
|
{
|
||||||
|
//Register the test using the loot table
|
||||||
//注册测试使用的战利品表
|
//注册测试使用的战利品表
|
||||||
if (Config.IsDebug())
|
if (Config.IsDebug())
|
||||||
{
|
{
|
||||||
IList<LootGroup> lootGroups = [];
|
List<LootGroup> lootGroups =
|
||||||
lootGroups.Add(new LootGroup(0.8,
|
|
||||||
[
|
[
|
||||||
new LootEntry("degraded_staff_of_the_undead", weight: 2), new LootEntry("staff_of_the_undead")
|
new LootGroup(0.8,
|
||||||
]));
|
|
||||||
lootGroups.Add(new LootGroup(1,
|
|
||||||
[
|
[
|
||||||
new LootEntry("packsack", minQuantity: 2, maxQuantity: 4)
|
new LootEntry("staff_necromancy"),
|
||||||
]));
|
])
|
||||||
|
];
|
||||||
var testLootList = new LootList(Config.LootListId.Test, lootGroups);
|
var testLootList = new LootList(Config.LootListId.Test, lootGroups);
|
||||||
LootListManager.RegisterLootList(testLootList);
|
LootListManager.RegisterLootList(testLootList);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,317 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using ColdMint.scripts.camp;
|
||||||
|
using ColdMint.scripts.character;
|
||||||
|
using ColdMint.scripts.damage;
|
||||||
|
using ColdMint.scripts.inventory;
|
||||||
|
using ColdMint.scripts.pickable;
|
||||||
|
using ColdMint.scripts.projectile.decorator;
|
||||||
|
using Godot;
|
||||||
|
|
||||||
namespace ColdMint.scripts.projectile;
|
namespace ColdMint.scripts.projectile;
|
||||||
|
|
||||||
public partial class Projectile : ProjectileTemplate;
|
/// <summary>
|
||||||
|
/// <para>Projectile</para>
|
||||||
|
/// <para>抛射体</para>
|
||||||
|
/// </summary>
|
||||||
|
public partial class Projectile : CharacterBody2D
|
||||||
|
{
|
||||||
|
private long _life;
|
||||||
|
|
||||||
|
//The durability of the projectile
|
||||||
|
//抛射体的耐久度
|
||||||
|
//When the projectile hits the object, the durability will be reduced, and when the durability is less than or equal to 0, the projectile will be destroyed
|
||||||
|
//当抛射体撞击到物体时,会减少耐久度,当耐久度小于等于0时,销毁抛射体
|
||||||
|
private double _durability;
|
||||||
|
|
||||||
|
private int _maxDamage;
|
||||||
|
private int _minDamage;
|
||||||
|
private int _damageType;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <para>After this time destroy the projectile</para>
|
||||||
|
/// <para>超过此时刻销毁抛射体</para>
|
||||||
|
/// </summary>
|
||||||
|
private DateTime? _destructionTime;
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <para>The impact area of the bullet</para>
|
||||||
|
/// <para>子弹的碰撞区域</para>
|
||||||
|
/// </summary>
|
||||||
|
private Area2D? _area2D;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <para>knockback</para>
|
||||||
|
/// <para>击退</para>
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
///<para>How much force does it have when hitting the character? Unit: Number of cells,The X direction of the force is inferred automatically.</para>
|
||||||
|
///<para>当击中角色时带有多大的力?单位:格数,力的X方向是自动推断的。</para>
|
||||||
|
/// </remarks>
|
||||||
|
private Vector2 _knockbackForce;
|
||||||
|
|
||||||
|
public float Speed => GetMeta("Speed", "15").AsSingle();
|
||||||
|
|
||||||
|
private List<IProjectileDecorator>? _projectileDecorators;
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <para>The master of the weapon</para>
|
||||||
|
/// <para>武器的主人</para>
|
||||||
|
/// </summary>
|
||||||
|
public new Node2D? Owner { get; set; }
|
||||||
|
|
||||||
|
public override void _Ready()
|
||||||
|
{
|
||||||
|
//The bullet's impact detection area
|
||||||
|
//子弹的碰撞检测区域
|
||||||
|
_area2D = GetNode<Area2D>("CollisionDetectionArea");
|
||||||
|
_area2D.Monitoring = true;
|
||||||
|
_area2D.BodyEntered += OnBodyEnter;
|
||||||
|
_area2D.BodyExited += OnBodyExited;
|
||||||
|
_durability = GetMeta("Durability", "1").AsDouble();
|
||||||
|
_maxDamage = GetMeta("MaxDamage", "7").AsInt32();
|
||||||
|
_minDamage = GetMeta("MinDamage", "5").AsInt32();
|
||||||
|
_damageType = GetMeta("DamageType", Config.DamageType.Physical).AsInt32();
|
||||||
|
_knockbackForce = GetMeta("Knockback", Vector2.Zero).AsVector2();
|
||||||
|
//life(ms)
|
||||||
|
//子弹的存在时间(毫秒)
|
||||||
|
_life = GetMeta("Life", "10000").AsInt64();
|
||||||
|
//If the existence time is less than or equal to 0, then it is set to exist for 10 seconds, and projectiles that exist indefinitely are prohibited
|
||||||
|
//如果存在时间小于等于0,那么设置为存在10秒,禁止无限期存在的抛射体
|
||||||
|
if (_life <= 0)
|
||||||
|
{
|
||||||
|
_life = 10000;
|
||||||
|
}
|
||||||
|
|
||||||
|
_destructionTime = DateTime.Now.AddMilliseconds(_life);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <para>Add decorator</para>
|
||||||
|
/// <para>添加装饰器</para>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="decorator">
|
||||||
|
///<para>decorator</para>
|
||||||
|
///<para>装饰器</para>
|
||||||
|
/// </param>
|
||||||
|
public void AddProjectileDecorator(IProjectileDecorator decorator)
|
||||||
|
{
|
||||||
|
_projectileDecorators ??= [];
|
||||||
|
_projectileDecorators.Add(decorator);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <para>Remove decorator</para>
|
||||||
|
/// <para>移除装饰器</para>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="decorator">
|
||||||
|
///<para>decorator</para>
|
||||||
|
///<para>装饰器</para>
|
||||||
|
/// </param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public bool RemoveProjectileDecorator(IProjectileDecorator decorator)
|
||||||
|
{
|
||||||
|
return _projectileDecorators?.Remove(decorator) ?? false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <para>Detect whether harm is allowed</para>
|
||||||
|
/// <para>检测是否允许造成伤害</para>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="owner"></param>
|
||||||
|
/// <param name="target"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private bool CanCauseHarm(Node2D? owner, Node2D target)
|
||||||
|
{
|
||||||
|
//We must know who the owner of the bullet is in order to determine whether it should cause damage or not
|
||||||
|
//我们必须知道子弹的主人是谁,才能判断是否应该造成伤害
|
||||||
|
if (owner == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (owner is not CharacterTemplate ownerCharacterTemplate)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target is TileMapLayer)
|
||||||
|
{
|
||||||
|
//When we hit the tile, we return true to prevent the bullet from penetrating the tile.
|
||||||
|
//撞击到瓦片时,我们返回true,是为了防止子弹穿透瓦片。
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Match any item now
|
||||||
|
//现在使它识别任何物品
|
||||||
|
if (target is IItem)
|
||||||
|
{
|
||||||
|
//Bullets are allowed to strike objects.
|
||||||
|
//允许子弹撞击物品。
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target is not CharacterTemplate characterTemplate)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//First get the owner's camp and compare it with the target camp
|
||||||
|
//先获取主人的阵营与目标阵营进行比较
|
||||||
|
var canCauseHarm = CampManager.CanCauseHarm(CampManager.GetCamp(ownerCharacterTemplate.CampId),
|
||||||
|
CampManager.GetCamp(characterTemplate.CampId));
|
||||||
|
return canCauseHarm;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <para>Executive injury treatment</para>
|
||||||
|
/// <para>执行伤害处理</para>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="owner"></param>
|
||||||
|
/// <param name="target"></param>
|
||||||
|
private void DoDamage(Node2D? owner, Node2D target)
|
||||||
|
{
|
||||||
|
if (target is CharacterTemplate characterTemplate)
|
||||||
|
{
|
||||||
|
//Allow damage to be caused
|
||||||
|
//允许造成伤害
|
||||||
|
var damage = new Damage
|
||||||
|
{
|
||||||
|
Attacker = owner,
|
||||||
|
MaxDamage = _maxDamage,
|
||||||
|
MinDamage = _minDamage
|
||||||
|
};
|
||||||
|
damage.CreateDamage();
|
||||||
|
damage.MoveLeft = Velocity.X < 0;
|
||||||
|
damage.Type = _damageType;
|
||||||
|
var dead = characterTemplate.Damage(damage);
|
||||||
|
if (dead)
|
||||||
|
{
|
||||||
|
//If the character is dead, then call OnKillCharacter
|
||||||
|
//如果角色死亡了,那么调用OnKillCharacter
|
||||||
|
InvokeDecorators(decorator => { decorator.OnKillCharacter(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_knockbackForce != Vector2.Zero)
|
||||||
|
{
|
||||||
|
//If we set the attack force, then apply the force to the object
|
||||||
|
//如果我们设置了攻退力,那么将力应用到对象上
|
||||||
|
var force = new Vector2();
|
||||||
|
var forceX = Math.Abs(_knockbackForce.X);
|
||||||
|
if (Velocity.X < 0)
|
||||||
|
{
|
||||||
|
//Beat back to port
|
||||||
|
//向左击退
|
||||||
|
forceX = -forceX;
|
||||||
|
}
|
||||||
|
|
||||||
|
force.X = forceX * Config.CellSize;
|
||||||
|
force.Y = _knockbackForce.Y * Config.CellSize;
|
||||||
|
characterTemplate.AddForce(force);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (target is PickAbleTemplate pickAbleTemplate)
|
||||||
|
{
|
||||||
|
if (_knockbackForce != Vector2.Zero)
|
||||||
|
{
|
||||||
|
//If we set the attack force, then apply the force to the object
|
||||||
|
//如果我们设置了攻退力,那么将力应用到对象上
|
||||||
|
var force = new Vector2();
|
||||||
|
var forceX = Math.Abs(_knockbackForce.X);
|
||||||
|
if (Velocity.X < 0)
|
||||||
|
{
|
||||||
|
//Beat back to port
|
||||||
|
//向左击退
|
||||||
|
forceX = -forceX;
|
||||||
|
}
|
||||||
|
|
||||||
|
force.X = forceX * Config.CellSize;
|
||||||
|
force.Y = _knockbackForce.Y * Config.CellSize;
|
||||||
|
pickAbleTemplate.ApplyImpulse(force);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <para>Call the method of the decorator</para>
|
||||||
|
/// <para>调用装饰器的方法</para>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="projectileDecoratorAction"></param>
|
||||||
|
private void InvokeDecorators(Action<IProjectileDecorator> projectileDecoratorAction)
|
||||||
|
{
|
||||||
|
if (_projectileDecorators == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var decorator in _projectileDecorators)
|
||||||
|
{
|
||||||
|
projectileDecoratorAction(decorator);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <para>When the bullet is in contact with the node</para>
|
||||||
|
/// <para>当子弹与节点接触时</para>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="node"></param>
|
||||||
|
protected virtual void OnBodyEnter(Node2D node)
|
||||||
|
{
|
||||||
|
//Here we test whether harm is allowed, notice that for TileMap, we directly allow harm.
|
||||||
|
//这里我们检测是否允许造成伤害,注意对于TileMap,我们直接允许造成伤害。
|
||||||
|
var canCauseHarm = CanCauseHarm(Owner, node);
|
||||||
|
if (!canCauseHarm)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DoDamage(Owner, node);
|
||||||
|
//Please specify in the Mask who the bullet will collide with
|
||||||
|
//请在Mask内配置子弹会和谁碰撞
|
||||||
|
//When a bullet hits an object, its durability decreases
|
||||||
|
//子弹撞击到物体时,耐久度减少
|
||||||
|
_durability--;
|
||||||
|
if (_durability <= 0)
|
||||||
|
{
|
||||||
|
//When the durability is less than or equal to 0, destroy the bullet
|
||||||
|
//当耐久度小于等于0时,销毁子弹
|
||||||
|
QueueFree();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <para>When the bullet leaves the node</para>
|
||||||
|
/// <para>当子弹离开节点时</para>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="node"></param>
|
||||||
|
protected virtual void OnBodyExited(Node2D node)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <para>When beyond the time of existence</para>
|
||||||
|
/// <para>当超过存在时间</para>
|
||||||
|
/// </summary>
|
||||||
|
private void OnTimeOut()
|
||||||
|
{
|
||||||
|
QueueFree();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void _Process(double delta)
|
||||||
|
{
|
||||||
|
//If the existence time is exceeded, the projectile is destroyed
|
||||||
|
//如果超过了存在时间,那么销毁抛射体
|
||||||
|
if (DateTime.Now >= _destructionTime)
|
||||||
|
{
|
||||||
|
OnTimeOut();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void _PhysicsProcess(double delta)
|
||||||
|
{
|
||||||
|
MoveAndSlide();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,260 +0,0 @@
|
||||||
using System;
|
|
||||||
using ColdMint.scripts.camp;
|
|
||||||
using ColdMint.scripts.character;
|
|
||||||
using ColdMint.scripts.damage;
|
|
||||||
using ColdMint.scripts.inventory;
|
|
||||||
using ColdMint.scripts.pickable;
|
|
||||||
using Godot;
|
|
||||||
|
|
||||||
namespace ColdMint.scripts.projectile;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// <para>Projectile template</para>
|
|
||||||
/// <para>抛射体模板</para>
|
|
||||||
/// </summary>
|
|
||||||
public partial class ProjectileTemplate : CharacterBody2D
|
|
||||||
{
|
|
||||||
private long _life;
|
|
||||||
|
|
||||||
//The durability of the projectile
|
|
||||||
//抛射体的耐久度
|
|
||||||
//When the projectile hits the object, the durability will be reduced, and when the durability is less than or equal to 0, the projectile will be destroyed
|
|
||||||
//当抛射体撞击到物体时,会减少耐久度,当耐久度小于等于0时,销毁抛射体
|
|
||||||
private double _durability;
|
|
||||||
|
|
||||||
private int _maxDamage;
|
|
||||||
private int _minDamage;
|
|
||||||
private int _damageType;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// <para>After this time destroy the projectile</para>
|
|
||||||
/// <para>超过此时刻销毁抛射体</para>
|
|
||||||
/// </summary>
|
|
||||||
private DateTime? _destructionTime;
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// <para>The impact area of the bullet</para>
|
|
||||||
/// <para>子弹的碰撞区域</para>
|
|
||||||
/// </summary>
|
|
||||||
private Area2D? _area2D;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// <para>knockback</para>
|
|
||||||
/// <para>击退</para>
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
///<para>How much force does it have when hitting the character? Unit: Number of cells,The X direction of the force is inferred automatically.</para>
|
|
||||||
///<para>当击中角色时带有多大的力?单位:格数,力的X方向是自动推断的。</para>
|
|
||||||
/// </remarks>
|
|
||||||
private Vector2 _knockbackForce;
|
|
||||||
|
|
||||||
public float Speed => GetMeta("Speed", "15").AsSingle();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// <para>The master of the weapon</para>
|
|
||||||
/// <para>武器的主人</para>
|
|
||||||
/// </summary>
|
|
||||||
public new Node2D? Owner { get; set; }
|
|
||||||
|
|
||||||
public override void _Ready()
|
|
||||||
{
|
|
||||||
//The bullet's impact detection area
|
|
||||||
//子弹的碰撞检测区域
|
|
||||||
_area2D = GetNode<Area2D>("CollisionDetectionArea");
|
|
||||||
_area2D.Monitoring = true;
|
|
||||||
_area2D.BodyEntered += OnBodyEnter;
|
|
||||||
_area2D.BodyExited += OnBodyExited;
|
|
||||||
_durability = GetMeta("Durability", "1").AsDouble();
|
|
||||||
_maxDamage = GetMeta("MaxDamage", "7").AsInt32();
|
|
||||||
_minDamage = GetMeta("MinDamage", "5").AsInt32();
|
|
||||||
_damageType = GetMeta("DamageType", Config.DamageType.Physical).AsInt32();
|
|
||||||
_knockbackForce = GetMeta("Knockback", Vector2.Zero).AsVector2();
|
|
||||||
//life(ms)
|
|
||||||
//子弹的存在时间(毫秒)
|
|
||||||
_life = GetMeta("Life", "10000").AsInt64();
|
|
||||||
//If the existence time is less than or equal to 0, then it is set to exist for 10 seconds, and projectiles that exist indefinitely are prohibited
|
|
||||||
//如果存在时间小于等于0,那么设置为存在10秒,禁止无限期存在的抛射体
|
|
||||||
if (_life <= 0)
|
|
||||||
{
|
|
||||||
_life = 10000;
|
|
||||||
}
|
|
||||||
|
|
||||||
_destructionTime = DateTime.Now.AddMilliseconds(_life);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// <para>Detect whether harm is allowed</para>
|
|
||||||
/// <para>检测是否允许造成伤害</para>
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="owner"></param>
|
|
||||||
/// <param name="target"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
private bool CanCauseHarm(Node2D? owner, Node2D target)
|
|
||||||
{
|
|
||||||
//We must know who the owner of the bullet is in order to determine whether it should cause damage or not
|
|
||||||
//我们必须知道子弹的主人是谁,才能判断是否应该造成伤害
|
|
||||||
if (owner == null)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (owner is not CharacterTemplate ownerCharacterTemplate)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (target is TileMapLayer)
|
|
||||||
{
|
|
||||||
//When we hit the tile, we return true to prevent the bullet from penetrating the tile.
|
|
||||||
//撞击到瓦片时,我们返回true,是为了防止子弹穿透瓦片。
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Match any item now
|
|
||||||
//现在使它识别任何物品
|
|
||||||
if (target is IItem)
|
|
||||||
{
|
|
||||||
//Bullets are allowed to strike objects.
|
|
||||||
//允许子弹撞击物品。
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (target is not CharacterTemplate characterTemplate)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//First get the owner's camp and compare it with the target camp
|
|
||||||
//先获取主人的阵营与目标阵营进行比较
|
|
||||||
var canCauseHarm = CampManager.CanCauseHarm(CampManager.GetCamp(ownerCharacterTemplate.CampId),
|
|
||||||
CampManager.GetCamp(characterTemplate.CampId));
|
|
||||||
return canCauseHarm;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// <para>Executive injury treatment</para>
|
|
||||||
/// <para>执行伤害处理</para>
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="owner"></param>
|
|
||||||
/// <param name="target"></param>
|
|
||||||
private void DoDamage(Node2D? owner, Node2D target)
|
|
||||||
{
|
|
||||||
if (target is CharacterTemplate characterTemplate)
|
|
||||||
{
|
|
||||||
//Allow damage to be caused
|
|
||||||
//允许造成伤害
|
|
||||||
var damage = new Damage
|
|
||||||
{
|
|
||||||
Attacker = owner,
|
|
||||||
MaxDamage = _maxDamage,
|
|
||||||
MinDamage = _minDamage
|
|
||||||
};
|
|
||||||
damage.CreateDamage();
|
|
||||||
damage.MoveLeft = Velocity.X < 0;
|
|
||||||
damage.Type = _damageType;
|
|
||||||
characterTemplate.Damage(damage);
|
|
||||||
if (_knockbackForce != Vector2.Zero)
|
|
||||||
{
|
|
||||||
//If we set the attack force, then apply the force to the object
|
|
||||||
//如果我们设置了攻退力,那么将力应用到对象上
|
|
||||||
var force = new Vector2();
|
|
||||||
var forceX = Math.Abs(_knockbackForce.X);
|
|
||||||
if (Velocity.X < 0)
|
|
||||||
{
|
|
||||||
//Beat back to port
|
|
||||||
//向左击退
|
|
||||||
forceX = -forceX;
|
|
||||||
}
|
|
||||||
|
|
||||||
force.X = forceX * Config.CellSize;
|
|
||||||
force.Y = _knockbackForce.Y * Config.CellSize;
|
|
||||||
characterTemplate.AddForce(force);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (target is PickAbleTemplate pickAbleTemplate)
|
|
||||||
{
|
|
||||||
if (_knockbackForce != Vector2.Zero)
|
|
||||||
{
|
|
||||||
//If we set the attack force, then apply the force to the object
|
|
||||||
//如果我们设置了攻退力,那么将力应用到对象上
|
|
||||||
var force = new Vector2();
|
|
||||||
var forceX = Math.Abs(_knockbackForce.X);
|
|
||||||
if (Velocity.X < 0)
|
|
||||||
{
|
|
||||||
//Beat back to port
|
|
||||||
//向左击退
|
|
||||||
forceX = -forceX;
|
|
||||||
}
|
|
||||||
|
|
||||||
force.X = forceX * Config.CellSize;
|
|
||||||
force.Y = _knockbackForce.Y * Config.CellSize;
|
|
||||||
pickAbleTemplate.ApplyImpulse(force);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// <para>When the bullet is in contact with the node</para>
|
|
||||||
/// <para>当子弹与节点接触时</para>
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="node"></param>
|
|
||||||
protected virtual void OnBodyEnter(Node2D node)
|
|
||||||
{
|
|
||||||
//Here we test whether harm is allowed, notice that for TileMap, we directly allow harm.
|
|
||||||
//这里我们检测是否允许造成伤害,注意对于TileMap,我们直接允许造成伤害。
|
|
||||||
var canCauseHarm = CanCauseHarm(Owner, node);
|
|
||||||
if (!canCauseHarm)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
DoDamage(Owner, node);
|
|
||||||
//Please specify in the Mask who the bullet will collide with
|
|
||||||
//请在Mask内配置子弹会和谁碰撞
|
|
||||||
//When a bullet hits an object, its durability decreases
|
|
||||||
//子弹撞击到物体时,耐久度减少
|
|
||||||
_durability--;
|
|
||||||
if (_durability <= 0)
|
|
||||||
{
|
|
||||||
//When the durability is less than or equal to 0, destroy the bullet
|
|
||||||
//当耐久度小于等于0时,销毁子弹
|
|
||||||
QueueFree();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// <para>When the bullet leaves the node</para>
|
|
||||||
/// <para>当子弹离开节点时</para>
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="node"></param>
|
|
||||||
protected virtual void OnBodyExited(Node2D node)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// <para>When beyond the time of existence</para>
|
|
||||||
/// <para>当超过存在时间</para>
|
|
||||||
/// </summary>
|
|
||||||
private void OnTimeOut()
|
|
||||||
{
|
|
||||||
QueueFree();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void _Process(double delta)
|
|
||||||
{
|
|
||||||
//If the existence time is exceeded, the projectile is destroyed
|
|
||||||
//如果超过了存在时间,那么销毁抛射体
|
|
||||||
if (DateTime.Now >= _destructionTime)
|
|
||||||
{
|
|
||||||
OnTimeOut();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void _PhysicsProcess(double delta)
|
|
||||||
{
|
|
||||||
MoveAndSlide();
|
|
||||||
}
|
|
||||||
}
|
|
18
scripts/projectile/decorator/IProjectileDecorator.cs
Normal file
18
scripts/projectile/decorator/IProjectileDecorator.cs
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
namespace ColdMint.scripts.projectile.decorator;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <para>Projectile decorator</para>
|
||||||
|
/// <para>抛射体装饰</para>
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
///<para>Decorator mode is a structural mode, which can add special features to the projectile.</para>
|
||||||
|
///<para>装饰模式是一种结构性模式,可以将一种抛射体的特殊功能添加到抛射体上。</para>
|
||||||
|
/// </remarks>
|
||||||
|
public interface IProjectileDecorator
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// <para>When the character is killed by this projectile</para>
|
||||||
|
/// <para>当角色被此抛射体击杀时</para>
|
||||||
|
/// </summary>
|
||||||
|
void OnKillCharacter();
|
||||||
|
}
|
|
@ -61,7 +61,7 @@ public partial class ProjectileWeapon : WeaponTemplate
|
||||||
//获取第一个抛射体
|
//获取第一个抛射体
|
||||||
var projectileScene = ProjectileScenes[0];
|
var projectileScene = ProjectileScenes[0];
|
||||||
// var projectileScene = _projectileCache[_projectiles[0]];
|
// var projectileScene = _projectileCache[_projectiles[0]];
|
||||||
var projectile = NodeUtils.InstantiatePackedScene<ProjectileTemplate>(projectileScene);
|
var projectile = NodeUtils.InstantiatePackedScene<Projectile>(projectileScene);
|
||||||
if (projectile == null) return;
|
if (projectile == null) return;
|
||||||
NodeUtils.CallDeferredAddChild(GameSceneNodeHolder.ProjectileContainer, projectile);
|
NodeUtils.CallDeferredAddChild(GameSceneNodeHolder.ProjectileContainer, projectile);
|
||||||
projectile.Owner = owner;
|
projectile.Owner = owner;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user