发表于: 4/18/2023
好了,我们已经有了一个系统来把输入指令传递给我们的舰队了,那么,我们的舰队又将如何执行命令呢?
更具体一点,进行攻击?
是以豪迈的气魄向敌人发起冲锋,胆怯的人将迎来粉身碎骨的命运!
既然我们都已经登上太空了,当然要避免这种原始低效的杀戮方式。真理部的工程师们给我们带来了更好的选择。
万物皆可发射的终极“火炮”
枪
先考虑一些基本参数
class Weapon : MonoBehaviour{
string Name { get; }
float BaseDamage { get; }
float BaseRange { get; }
// 攻击间隔,防止过热,需要冷却才能进行下次攻击
float BaseCooldown { get; }
// “热身”过程,而当我们停止攻击,又逐渐变得需要重新进行预热
float BasePrepareTime { get; }
}
改改参数就可以说自己推出了一款新武器
为了保护武器延长使用寿命,为其加上限制
class Weapon : MonoBehaviour{
// ...
public float IsCoolingDown() => cooldown;
float Cooldown()
{
return cooldown = Mathf.Clamp(cooldown - Time.dltaTime, 0, BaseCooldown);
}
float cooldown = 0;
bool Prepared()
{
prepared = true;
prepareTime = Mathf.Clamp(prepareTime + Time.deltaTime, 0, BasePrepareTime);
return prepareTime >= BasePrepareTime;
}
bool prepared = false;
float prepareTime = 0;
void Update()
{
Cooldown();
}
void LateUpdate()
{
if(prepared)
prepared = false;
else
if(IsCoolingDown() == 0)
prepareTime = Mathf.Clamp(prepareTime - Time.deltaTime*0.3f, 0, BasePrepareTime);
}
}
我们在“开火!”时检测Prepare和Cooldown (顺便进行了Prepare),当可以发射后就发射并设置Cooldown。
public void Fire(Fleet self, Fleet target)
{
if (!Prepared() || IsCoolingDown() > 0)
return;
LaunchProjectile(self, target);
cooldown = BaseCooldown;
}
void LaunchProjectile(Fleet self, Fleet target)
{
}
弹
枪已经准备好了,只需要子弹了,那这就简单了,我们实际上只需要两个要素:
- 移动路径
- 命中判定
public class LaserProjectile : Projectile // 继承自 MonoBehaviour
{
Vector2 from;
Vector2 to;
Action<Fleet> OnHit;
// Update is called once per frame
void LateUpdate()
{
var collider = GetComponent<Collider2D>();
var hitList = new Collider2D[1];
if (collider.OverlapCollider(new() { layerMask = LayerMask.GetMask("PlayerControls") }, hitList) > 0)
{
if (hitList[0].gameObject.GetComponent<Fleet>() is Fleet fleet && fleet != self && fleet.Team != self.Team/*friendly fire*/)
{
OnHit?.Invoke(fleet);
Destroy(gameObject);
}
}
}
void Update()
{
transform.position = Vector2.MoveTowards(transform.position, to, speed * Time.deltaTime);
}
public static LaserProjectile Create(Fleet self, Fleet target, Action<Fleet> onHit)
{
var r = Quaternion.LookRotation(Vector3.forward, target.transform.position - self.transform.position);
var projectile = Instantiate(LaserProjectilePrefab, self.transform.position, r).GetComponent<LaserProjectile>();
projectile.transform.position = self.transform.position;
projectile.self = self;
projectile.from = self.transform.position;
projectile.to = target.transform.position;
projectile.OnHit = onHit;
return projectile;
}
}
这里简单制作了一枚弹药:直线运动,不能追踪目标 在Update中进行移动,在LateUpdate中进行命中判定,在创建时设置目标等一系列参数。 命中时触发命中事件进行诸如造成伤害之类的行为。
外题
近来有对Shader进行一定了解,将投射物整体运动也交给Shader不知道是否可行? 使用一张覆盖整个地图的材质,在上面绘制弹道,对大量的,规则运动的 “弹幕” 应该是个很好的优化办法。
——由此延申,战争迷雾也可以直接在Shader中计算范围,而非是基于网格的循环遍历,不过遮挡的处理或许略有复杂。 这大概能挽回我丢失的200多帧吧,是的,之前的实现要消耗掉200多帧,甚至略有卡顿。