New Modifier

This commit is contained in:
Marco 2025-02-09 09:37:43 +01:00
commit 019f7d7ca0
18 changed files with 423 additions and 45 deletions

View file

@ -11,11 +11,13 @@ public partial class SpiralPattern : AttackPattern
[Export] public PackedScene BulletScene;
[Export] private float bulletSpeed = 5f;
[Export] private int bulletCount = 16;
[Export] private float rotationSpeed = 90f;
[Export] private float rotationSpeed = 0f;
[Export] private float _rotationOffset = 0f;
[Export] private float duration = 5f;
[Export] private float burstInterval = 0.5f;
[Export] private float spread = 360f;
[Export] private BulletOwner owner = BulletOwner.Enemy;
[Export] private Resource _modifier;
private double timer;
private double burstTimer;
@ -35,7 +37,22 @@ public partial class SpiralPattern : AttackPattern
burstTimer += delta;
if (timer < duration && burstTimer >= burstInterval)
{
spawner.SpawnSpiralPattern(Boss.GlobalPosition, bulletSpeed, owner, bulletCount, rotationSpeed, timer, spread, BulletScene);
float angleOffset = (float)(rotationSpeed * timer);
spawner.SpawnBullet(new BulletInfo()
{
Position = Boss.GlobalPosition,
Direction = Vector2.Right,
Speed = bulletSpeed,
Owner = owner,
BulletCount = bulletCount,
Spread = spread,
BulletScene = BulletScene,
RotationOffset = _rotationOffset,
Modifier = _modifier as IBulletModifier,
});
// spawner.SpawnSpiralPattern(Boss.GlobalPosition, bulletSpeed, owner, bulletCount, rotationSpeed, timer, spread, BulletScene);
burstTimer = 0;
}
}

View file

@ -1,4 +1,5 @@
using Cirno.Scripts.Resources;
using System;
using Cirno.Scripts.Resources;
using Godot;
namespace Cirno.Scripts.Components;
@ -12,6 +13,32 @@ public partial class BulletSpawner : Node2D
{
_gameManager = GetNode<GameManager>("/root/GameScene");
}
public void SpawnBullet(BulletInfo bulletInfo)
{
for (int i = 0; i < bulletInfo.BulletCount; i++)
{
var bullet = this.CreateChildOf<Bullet>(_gameManager.BulletsContainer, bulletInfo.BulletScene ?? BulletScene, bulletInfo.Position);
//var bullet = BulletScene.Instantiate<Bullet>();
bullet.Position = bulletInfo.Position;
bullet.Owner = bulletInfo.Owner;
//bullet.Speed = speed;
float modifiedSpeed = bulletInfo.Modifier?.ModifySpeed(bulletInfo.Speed, i, bulletInfo.BulletCount) ?? bulletInfo.Speed;
bullet.Speed = modifiedSpeed;
Vector2 baseDirection = bulletInfo.Direction == Vector2.Zero ? Vector2.Right : bulletInfo.Direction.Normalized();
float baseAngle = Mathf.Atan2(baseDirection.Y, baseDirection.X);
//float angle = angleOffset + (360 / count) * i;
float angle = baseAngle + Mathf.DegToRad(bulletInfo.RotationOffset + (bulletInfo.Spread / bulletInfo.BulletCount) * i);
Vector2 bulletDirection = new Vector2(Mathf.Cos(angle), Mathf.Sin(angle));
//Vector2 bulletDirection = new Vector2(Mathf.Cos(Mathf.DegToRad(angle)), Mathf.Sin(Mathf.DegToRad(angle)));
bullet.SetDirection(bulletDirection);
//GetParent().AddChild(bullet);
}
}
public void SpawnBullet(Vector2 position, Vector2 direction, float speed, BulletOwner owner, int count = 1, float angleOffset = 0, float spread = 0, PackedScene bulletScene = null, IBulletModifier modifier = null)
{
@ -24,7 +51,7 @@ public partial class BulletSpawner : Node2D
bullet.Owner = owner;
//bullet.Speed = speed;
float modifiedSpeed = modifier?.ModifySpeed(speed, i) ?? speed;
float modifiedSpeed = modifier?.ModifySpeed(speed, i, count) ?? speed;
bullet.Speed = modifiedSpeed;
Vector2 baseDirection = direction == Vector2.Zero ? Vector2.Right : direction.Normalized();
@ -44,10 +71,26 @@ public partial class BulletSpawner : Node2D
Vector2 direction = (target - position).Normalized();
SpawnBullet(position, direction, speed, owner, burstCount, spread: spread, bulletScene: bulletScene, modifier: modifier);
}
[Obsolete]
public void SpawnSpiralPattern(Vector2 position, float speed, BulletOwner owner, int bulletCount, float rotationSpeed, double time, float spread, PackedScene bulletScene = null)
{
float angleOffset = (float)(rotationSpeed * time);
SpawnBullet(position, Vector2.Right, speed, owner, bulletCount, angleOffset, spread, bulletScene: bulletScene);
}
}
public class BulletInfo
{
public Vector2 Position { get; set; }
public Vector2 Direction { get; set; }
public float Speed { get; set; }
public BulletOwner Owner { get; set; }
public int BulletCount { get; set; }
public float RotationSpeed { get; set; }
public float RotationOffset { get; set; }
//public double Time { get; set; }
public float Spread { get; set; }
public PackedScene BulletScene { get; set; }
public IBulletModifier Modifier { get; set; }
}

View file

@ -7,7 +7,7 @@ public partial class DecreasingSpeedModifier : Resource, IBulletModifier
{
[Export] private float decreaseRate = 0.1f;
public float ModifySpeed(float baseSpeed, int bulletIndex)
public float ModifySpeed(float baseSpeed, int bulletIndex, int totalBullets)
{
return Mathf.Max(0, baseSpeed - (decreaseRate * bulletIndex));
}

View file

@ -2,5 +2,5 @@
public interface IBulletModifier
{
float ModifySpeed(float baseSpeed, int bulletIndex);
float ModifySpeed(float baseSpeed, int bulletIndex, int totalBullets);
}

View file

@ -0,0 +1,152 @@
using Godot;
namespace Cirno.Scripts.Resources;
[GlobalClass]
public partial class SpeedModifier : Resource, IBulletModifier
{
[Export] public SpeedModifierType ModifierType;
[Export] public EasingType Easing;
[Export] public bool Invert = false;
[Export] public float MinimumSpeed = 10f;
[Export] public float ScalingFactor = 10.0f;
public float ModifySpeed(float baseSpeed, int bulletIndex, int totalBullets)
{
if (totalBullets <= 1)
return baseSpeed;
float t = (float)bulletIndex / (totalBullets - 1); // Normalize to [0,1]
t = ApplyEasing(t);
return Mathf.Lerp(MinimumSpeed, baseSpeed, t);
}
private float ApplyEasing(float t)
{
switch (ModifierType)
{
case SpeedModifierType.Linear:
return t;
case SpeedModifierType.Quad:
return Easing == EasingType.In ? t * t : Easing == EasingType.Out ? 1 - (1 - t) * (1 - t) : (t < 0.5f ? 2 * t * t : 1 - Mathf.Pow(-2 * t + 2, 2) / 2);
case SpeedModifierType.Sine:
return Easing == EasingType.In ? 1 - Mathf.Cos((t * Mathf.Pi) / 2) : Easing == EasingType.Out ? Mathf.Sin((t * Mathf.Pi) / 2) : -(Mathf.Cos(Mathf.Pi * t) - 1) / 2;
case SpeedModifierType.Exponential:
return Easing == EasingType.In ? Mathf.Pow(2, 10 * (t - 1)) : Easing == EasingType.Out ? 1 - Mathf.Pow(2, -10 * t) : (t < 0.5f ? Mathf.Pow(2, 10 * (2 * t - 1)) / 2 : (2 - Mathf.Pow(2, -10 * (2 * t - 1))) / 2);
case SpeedModifierType.Quint:
return Easing == EasingType.In ? t * t * t * t * t : Easing == EasingType.Out ? 1 - Mathf.Pow(1 - t, 5) : (t < 0.5f ? 16 * t * t * t * t * t : 1 - Mathf.Pow(-2 * t + 2, 5) / 2);
case SpeedModifierType.Circ:
return Easing == EasingType.In ? 1 - Mathf.Sqrt(1 - t * t) : Easing == EasingType.Out ? Mathf.Sqrt(1 - Mathf.Pow(t - 1, 2)) : (t < 0.5f ? (1 - Mathf.Sqrt(1 - 4 * t * t)) / 2 : (Mathf.Sqrt(1 - Mathf.Pow(-2 * t + 2, 2)) + 1) / 2);
case SpeedModifierType.Cubic:
return Easing == EasingType.In ? t * t * t : Easing == EasingType.Out ? 1 - Mathf.Pow(1 - t, 3) : (t < 0.5f ? 4 * t * t * t : 1 - Mathf.Pow(-2 * t + 2, 3) / 2);
case SpeedModifierType.Quart:
return Easing == EasingType.In ? t * t * t * t : Easing == EasingType.Out ? 1 - Mathf.Pow(1 - t, 4) : (t < 0.5f ? 8 * t * t * t * t : 1 - Mathf.Pow(-2 * t + 2, 4) / 2);
case SpeedModifierType.Elastic:
return Easing == EasingType.In ? (t == 0 ? 0 : t == 1 ? 1 : -Mathf.Pow(2, 10 * t - 10) * Mathf.Sin((t * 10 - 10.75f) * ((2 * Mathf.Pi) / 3))) : Easing == EasingType.Out ? (t == 0 ? 0 : t == 1 ? 1 : Mathf.Pow(2, -10 * t) * Mathf.Sin((t * 10 - 0.75f) * ((2 * Mathf.Pi) / 3)) + 1) : (t < 0.5f ? -(Mathf.Pow(2, 20 * t - 10) * Mathf.Sin((20 * t - 11.125f) * ((2 * Mathf.Pi) / 3))) / 2 : (Mathf.Pow(2, -20 * t + 10) * Mathf.Sin((20 * t - 11.125f) * ((2 * Mathf.Pi) / 3))) / 2 + 1);
case SpeedModifierType.Back:
float c1 = 1.70158f;
float c2 = c1 * 1.525f;
return Easing == EasingType.In ? (c1 + 1) * t * t * t - c1 * t * t : Easing == EasingType.Out ? 1 + (c1 + 1) * Mathf.Pow(t - 1, 3) + c1 * Mathf.Pow(t - 1, 2) : (t < 0.5f ? (Mathf.Pow(2 * t, 2) * ((c2 + 1) * 2 * t - c2)) / 2 : (Mathf.Pow(2 * t - 2, 2) * ((c2 + 1) * (t * 2 - 2) + c2) + 2) / 2);
case SpeedModifierType.Bounce:
return Easing == EasingType.In ? 1 - ApplyEasing(1 - t) : Easing == EasingType.Out ? BounceEaseOut(t) : (t < 0.5f ? (1 - BounceEaseOut(1 - 2 * t)) / 2 : (1 + BounceEaseOut(2 * t - 1)) / 2);
default:
return t;
}
}
private float BounceEaseOut(float t)
{
if (t < 1 / 2.75f) return 7.5625f * t * t;
else if (t < 2 / 2.75f) return 7.5625f * (t -= 1.5f / 2.75f) * t + 0.75f;
else if (t < 2.5f / 2.75f) return 7.5625f * (t -= 2.25f / 2.75f) * t + 0.9375f;
else return 7.5625f * (t -= 2.625f / 2.75f) * t + 0.984375f;
}
public float ApplyModifier(float baseSpeed, float factor)
{
float easedFactor = factor;
switch (Easing)
{
case EasingType.In:
easedFactor = factor * factor;
break;
case EasingType.Out:
easedFactor = 1 - Mathf.Pow(1 - factor, 2);
break;
case EasingType.InOut:
easedFactor = factor < 0.5f ? 2 * factor * factor : 1 - Mathf.Pow(-2 * factor + 2, 2) / 2;
break;
}
float speedRange = baseSpeed - MinimumSpeed;
float modifiedSpeed = MinimumSpeed + speedRange * easedFactor;
switch (ModifierType)
{
case SpeedModifierType.Sine:
modifiedSpeed *= Mathf.Sin(easedFactor * Mathf.Pi * 0.5f);
break;
case SpeedModifierType.Quad:
modifiedSpeed *= easedFactor * easedFactor;
break;
case SpeedModifierType.Exponential:
modifiedSpeed *= Mathf.Pow(2, easedFactor) - 1;
break;
case SpeedModifierType.Quint:
modifiedSpeed *= easedFactor * easedFactor * easedFactor * easedFactor * easedFactor;
break;
case SpeedModifierType.Circ:
modifiedSpeed *= 1 - Mathf.Sqrt(1 - easedFactor * easedFactor);
break;
case SpeedModifierType.Cubic:
modifiedSpeed *= easedFactor * easedFactor * easedFactor;
break;
case SpeedModifierType.Linear:
modifiedSpeed *= easedFactor;
break;
case SpeedModifierType.Quart:
modifiedSpeed *= easedFactor * easedFactor * easedFactor * easedFactor;
break;
case SpeedModifierType.Elastic:
modifiedSpeed *= Mathf.Sin(13 * easedFactor * Mathf.Pi) * Mathf.Pow(2, 10 * (easedFactor - 1));
break;
case SpeedModifierType.Back:
modifiedSpeed *= easedFactor * easedFactor * (2.70158f * easedFactor - 1.70158f);
break;
case SpeedModifierType.Bounce:
modifiedSpeed *= Mathf.Abs(Mathf.Sin(6.28f * (easedFactor + 1) * (easedFactor + 1)) * (1 - easedFactor));
break;
}
if (Invert)
{
modifiedSpeed = baseSpeed + (baseSpeed - modifiedSpeed);
}
return Mathf.Max(modifiedSpeed, MinimumSpeed);
}
}
public enum SpeedModifierType
{
Sine,
Quad,
Exponential,
Quint,
Circ,
Cubic,
Linear,
Quart,
Elastic,
Back,
Bounce
}
public enum EasingType
{
In,
Out,
InOut
}