mirror of
https://gitlab.com/MaddoScientisto/cirnogodot.git
synced 2026-06-01 11:15:33 +00:00
Shooting and big tank fix
This commit is contained in:
parent
cc00c8eaf0
commit
0a6e89faed
26 changed files with 797 additions and 9 deletions
55
Scripts/Actors/BulletSpawner3D.cs
Normal file
55
Scripts/Actors/BulletSpawner3D.cs
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
using Cirno.Scripts.Components;
|
||||
using Cirno.Scripts.Controllers;
|
||||
using Cirno.Scripts.Weapons;
|
||||
using Godot;
|
||||
|
||||
namespace Cirno.Scripts.Actors;
|
||||
|
||||
public partial class BulletSpawner3D : Node3D
|
||||
{
|
||||
[Export] public PackedScene BulletScene;
|
||||
|
||||
public void SpawnBullet(BulletInfo bulletInfo, Vector3 position)
|
||||
{
|
||||
var bulletScene = bulletInfo.BulletScene ?? BulletScene;
|
||||
Bullet3D bullet;
|
||||
int count = bulletInfo.BulletCount;
|
||||
float spreadRadians = Mathf.DegToRad(bulletInfo.Spread);
|
||||
float step = count > 1 ? spreadRadians / (count - 1) : 0;
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
|
||||
bullet = PoolingManager.Instance.SpawnBullet<Bullet3D>(bulletInfo.OriginalBulletResource);
|
||||
bullet.GlobalPosition = position;
|
||||
|
||||
if (bulletInfo.Modifier is not null)
|
||||
{
|
||||
bulletInfo = bulletInfo.Modifier.ModifyBullet(bulletInfo, i, count);
|
||||
}
|
||||
|
||||
bullet.Initialize(bulletInfo);
|
||||
|
||||
Vector2 baseDirection = bulletInfo.Direction == Vector2.Zero ? Vector2.Right : bulletInfo.Direction.Normalized();
|
||||
float baseAngle = Mathf.Atan2(baseDirection.Y, baseDirection.X);
|
||||
|
||||
// Spread centered: offset from center
|
||||
float offsetFromCenter = (i - (count - 1) / 2.0f) * step;
|
||||
float angle = baseAngle + Mathf.DegToRad(bulletInfo.RotationOffset) + offsetFromCenter;
|
||||
|
||||
Vector2 bulletDirection = new Vector2(Mathf.Cos(angle), Mathf.Sin(angle));
|
||||
bullet.SetDirection(bulletDirection);
|
||||
|
||||
// float offsetRadians = Mathf.DegToRad(bulletInfo.RotationOffset);
|
||||
// float spreadStep = Mathf.DegToRad(bulletInfo.Spread) / Mathf.Max(1, bulletInfo.BulletCount - 1); // Ensure proper spread spacing, also add 1 if 0
|
||||
// float angle = baseAngle + offsetRadians + (spreadStep * i);
|
||||
//
|
||||
//
|
||||
// Vector2 bulletDirection = new Vector2(Mathf.Cos(angle), Mathf.Sin(angle));
|
||||
//
|
||||
// bullet.SetDirection(bulletDirection);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
1
Scripts/Actors/BulletSpawner3D.cs.uid
Normal file
1
Scripts/Actors/BulletSpawner3D.cs.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://bf5f2phitdqw8
|
||||
97
Scripts/Actors/ScriptableBulletsEmitter3D.cs
Normal file
97
Scripts/Actors/ScriptableBulletsEmitter3D.cs
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
using Cirno.Scripts.AttackPatterns;
|
||||
using Cirno.Scripts.Resources;
|
||||
using Cirno.Scripts.Resources.BulletScripts;
|
||||
using Godot;
|
||||
|
||||
namespace Cirno.Scripts.Actors;
|
||||
|
||||
public partial class ScriptableBulletsEmitter3D : Node3D, IActivable, IScriptHost3D
|
||||
{
|
||||
public Node3D ParentObject => this;
|
||||
|
||||
[Export]
|
||||
public BulletScript3D Script { get; set; }
|
||||
|
||||
[Export]
|
||||
public bool InvertSignal { get; private set; } = false;
|
||||
|
||||
[Export]
|
||||
public bool EmitOnStart { get; set; } = false;
|
||||
|
||||
[Signal]
|
||||
public delegate void StateChangedEventHandler(bool isEmitting);
|
||||
|
||||
private bool _isActive = false;
|
||||
|
||||
//private BulletScript _scriptInstance;
|
||||
|
||||
protected BulletScript3D.BulletScriptMachine ScriptMachine;
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
//_scriptInstance = Script.Duplicate(true) as BulletScript;
|
||||
|
||||
ScriptMachine = Script.Make(this);
|
||||
|
||||
_homePosition = this.GlobalPosition;
|
||||
|
||||
if (EmitOnStart)
|
||||
{
|
||||
_isActive = true;
|
||||
ScriptMachine.Start();
|
||||
}
|
||||
EmitSignal(SignalName.StateChanged, _isActive);
|
||||
}
|
||||
|
||||
public bool Activate(ActivationType activationType = ActivationType.Toggle)
|
||||
{
|
||||
switch (activationType)
|
||||
{
|
||||
case ActivationType.Use:
|
||||
case ActivationType.Toggle:
|
||||
_isActive = !_isActive;
|
||||
break;
|
||||
case ActivationType.Open:
|
||||
case ActivationType.Enable:
|
||||
_isActive = !InvertSignal;
|
||||
break;
|
||||
case ActivationType.Close:
|
||||
case ActivationType.Disable:
|
||||
_isActive = InvertSignal;
|
||||
break;
|
||||
case ActivationType.Destroy:
|
||||
_isActive = InvertSignal;
|
||||
// TODO: Explode
|
||||
break;
|
||||
}
|
||||
|
||||
if (_isActive)
|
||||
{
|
||||
ScriptMachine.Start();
|
||||
}
|
||||
|
||||
EmitSignal(SignalName.StateChanged, _isActive);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Toggle()
|
||||
{
|
||||
this.Activate();
|
||||
}
|
||||
|
||||
public override void _Process(double delta)
|
||||
{
|
||||
if (!_isActive) return;
|
||||
|
||||
ScriptMachine.UpdatePhase(delta);
|
||||
}
|
||||
|
||||
private Vector3 _homePosition;
|
||||
public Vector3 HomePosition => _homePosition;
|
||||
|
||||
public void ChangeSpriteDirection(Vector2 direction)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
1
Scripts/Actors/ScriptableBulletsEmitter3D.cs.uid
Normal file
1
Scripts/Actors/ScriptableBulletsEmitter3D.cs.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://dpibtd73awwp7
|
||||
10
Scripts/AttackPatterns/IScriptHost3D.cs
Normal file
10
Scripts/AttackPatterns/IScriptHost3D.cs
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
using Godot;
|
||||
|
||||
namespace Cirno.Scripts.AttackPatterns;
|
||||
|
||||
public interface IScriptHost3D
|
||||
{
|
||||
public Node3D ParentObject { get; }
|
||||
public Vector3 HomePosition { get; }
|
||||
public void ChangeSpriteDirection(Vector2 direction);
|
||||
}
|
||||
1
Scripts/AttackPatterns/IScriptHost3D.cs.uid
Normal file
1
Scripts/AttackPatterns/IScriptHost3D.cs.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://c4mqs0ovhgk0x
|
||||
228
Scripts/AttackPatterns/ShootingPattern3D.cs
Normal file
228
Scripts/AttackPatterns/ShootingPattern3D.cs
Normal file
|
|
@ -0,0 +1,228 @@
|
|||
using Cirno.Scripts.Actors;
|
||||
using Cirno.Scripts.Components;
|
||||
using Cirno.Scripts.Resources;
|
||||
using Cirno.Scripts.Utils;
|
||||
using Godot;
|
||||
using Godot.Collections;
|
||||
|
||||
namespace Cirno.Scripts.AttackPatterns;
|
||||
|
||||
[GlobalClass]
|
||||
[Tool]
|
||||
public partial class ShootingPattern3D : AttackPattern
|
||||
{
|
||||
[Export] public BulletResource BulletResource { get; set; }
|
||||
|
||||
[Export] public Vector3 EmitterOffset { get; set; } = Vector3.Zero;
|
||||
|
||||
[Export] public int bulletCount = 16;
|
||||
[Export] public float rotationSpeed = 0f;
|
||||
[Export] public float _rotationOffset = 0f;
|
||||
[Export] public float duration = 5f;
|
||||
[Export] public float spread = 360f;
|
||||
[Export] public float burstInterval = 0.5f;
|
||||
|
||||
[ExportCategory("Burst")] [Export] public int ShotsPerBurst { get; private set; } = 100;
|
||||
|
||||
[Export] public float BurstRate { get; private set; } = 0f;
|
||||
|
||||
[ExportCategory("Other")] [Export] public bool _targetPlayer = false;
|
||||
[ExportCategory("Other")] [Export] public bool _predictPlayer = false;
|
||||
|
||||
[ExportCategory("Overrides")]
|
||||
[Export] public bool OverrideOwner { get; private set; } = false;
|
||||
[Export] public BulletOwner Owner { get; private set; } = BulletOwner.None;
|
||||
[Export] public bool OverrideDamageType { get; private set; } = false;
|
||||
[Export] public DamageType DamageType { get; private set; } = DamageType.Neutral;
|
||||
[Export] public bool OverrideControllable { get; private set; } = false;
|
||||
[Export] public bool Controllable { get; private set; } = false;
|
||||
|
||||
[ExportCategory("Extra Modifiers")]
|
||||
[Export]
|
||||
public bool OverrideCreationModifier { get; private set; } = false;
|
||||
|
||||
[Export] public BulletCreationModifier Modifier;
|
||||
[Export] public Array<TimeModifier> TimeModifiers = [];
|
||||
|
||||
protected virtual BulletInfo MakeBullet(Vector2 position, int count = 1, float spread = 0f, float rotationOffset = 0f)
|
||||
{
|
||||
var bullet = this.BulletResource.MakeBullet(position, count,
|
||||
spread, rotationOffset);
|
||||
|
||||
if (OverrideOwner)
|
||||
{
|
||||
bullet.Owner = this.Owner;
|
||||
}
|
||||
|
||||
if (OverrideDamageType)
|
||||
{
|
||||
bullet.DamageType = DamageType;
|
||||
}
|
||||
|
||||
if (OverrideControllable)
|
||||
{
|
||||
bullet.Controllabe = Controllable;
|
||||
}
|
||||
|
||||
if (OverrideCreationModifier)
|
||||
{
|
||||
bullet.Modifier = this.Modifier;
|
||||
}
|
||||
|
||||
if (TimeModifiers.Count != 0)
|
||||
{
|
||||
bullet.TimeModifiers.AddRange(TimeModifiers);
|
||||
}
|
||||
|
||||
return bullet;
|
||||
}
|
||||
|
||||
public override IPatternMachine MakeMachine(Node parent)
|
||||
{
|
||||
return new SpiralPatternMachine(this, parent);
|
||||
}
|
||||
|
||||
public class SpiralPatternMachine(ShootingPattern3D pattern, Node parent) : IPatternMachine
|
||||
{
|
||||
public Node Parent => parent;
|
||||
public IScriptHost3D ScriptHost { get; private set; }
|
||||
private double timer;
|
||||
private double burstTimer;
|
||||
//private double _burstRateTimer;
|
||||
private BulletSpawner3D spawner;
|
||||
|
||||
private ShootStatus _state = ShootStatus.Idle;
|
||||
|
||||
private int _burstBullets;
|
||||
|
||||
public void Start()
|
||||
{
|
||||
ScriptHost = Parent as IScriptHost3D;
|
||||
|
||||
timer = 0;
|
||||
_burstBullets = pattern.ShotsPerBurst;
|
||||
burstTimer = pattern.burstInterval; // start immediately
|
||||
|
||||
spawner = parent.GetNode<BulletSpawner3D>("BulletSpawner3D");
|
||||
|
||||
_state = ShootStatus.Shooting;
|
||||
}
|
||||
|
||||
private void WaitingBurstUpdate(double delta)
|
||||
{
|
||||
timer += delta;
|
||||
burstTimer += delta;
|
||||
|
||||
if (burstTimer >= pattern.burstInterval)
|
||||
{
|
||||
_state = ShootStatus.Shooting;
|
||||
}
|
||||
}
|
||||
|
||||
private void WaitingReloadUpdate(double delta)
|
||||
{
|
||||
timer += delta;
|
||||
burstTimer += delta;
|
||||
|
||||
if (burstTimer >= pattern.BurstRate)
|
||||
{
|
||||
_burstBullets = pattern.ShotsPerBurst;
|
||||
_state = ShootStatus.Shooting;
|
||||
}
|
||||
}
|
||||
|
||||
private void ShootingUpdate(double delta)
|
||||
{
|
||||
timer += delta;
|
||||
burstTimer = 0;
|
||||
Shoot();
|
||||
_burstBullets--;
|
||||
|
||||
if (_burstBullets <= 0)
|
||||
{
|
||||
_state = ShootStatus.WaitingReload;
|
||||
}
|
||||
else
|
||||
{
|
||||
_state = ShootStatus.WaitingBurst;
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdatePattern(double delta)
|
||||
{
|
||||
switch (_state)
|
||||
{
|
||||
case ShootStatus.Idle:
|
||||
case ShootStatus.Done:
|
||||
return;
|
||||
case ShootStatus.Shooting:
|
||||
ShootingUpdate(delta);
|
||||
break;
|
||||
case ShootStatus.WaitingBurst:
|
||||
WaitingBurstUpdate(delta);
|
||||
break;
|
||||
case ShootStatus.WaitingReload:
|
||||
WaitingReloadUpdate(delta);
|
||||
break;
|
||||
}
|
||||
|
||||
if (timer >= pattern.duration)
|
||||
{
|
||||
_state = ShootStatus.Done;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void Shoot()
|
||||
{
|
||||
float angleOffset = pattern._rotationOffset + (float)(pattern.rotationSpeed * timer);
|
||||
|
||||
Vector2 direction = pattern.BulletResource.Direction;
|
||||
|
||||
// TODO: Fix player aiming for 3D
|
||||
// if (pattern._targetPlayer && GameManager.Instance.PlayerPosition.HasValue)
|
||||
// {
|
||||
// if (pattern._predictPlayer && GameManager.Instance.PlayerVelocity.HasValue)
|
||||
// {
|
||||
// var predictedDirection = MathFunctions.PredictInterceptPosition(ScriptHost.ParentObject.GlobalPosition,
|
||||
// GameManager.Instance.PlayerPosition.Value, GameManager.Instance.PlayerVelocity.Value,
|
||||
// pattern.BulletResource.BulletSpeed);
|
||||
// if (predictedDirection.HasValue)
|
||||
// {
|
||||
// direction = (predictedDirection.Value - ScriptHost.ParentObject.GlobalPosition).Normalized();
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// direction = (GameManager.Instance.PlayerPosition.Value - ScriptHost.ParentObject.GlobalPosition).Normalized();
|
||||
// }
|
||||
// }
|
||||
|
||||
var spawnPosition = ScriptHost.ParentObject.GlobalPosition + pattern.EmitterOffset;
|
||||
|
||||
var bullet = pattern.MakeBullet(spawnPosition.ToVector2(), pattern.bulletCount,
|
||||
pattern.spread, angleOffset);
|
||||
|
||||
bullet.Direction = direction;
|
||||
|
||||
//spawner.SpawnBullet(MakeBullet(Boss.GlobalPosition, direction, angleOffset));
|
||||
spawner.SpawnBullet(bullet, spawnPosition);
|
||||
}
|
||||
|
||||
|
||||
public bool IsComplete()
|
||||
{
|
||||
//return timer >= pattern.duration;
|
||||
return _state is ShootStatus.Done;
|
||||
}
|
||||
|
||||
private enum ShootStatus
|
||||
{
|
||||
Idle,
|
||||
Shooting,
|
||||
WaitingBurst,
|
||||
WaitingReload,
|
||||
Done
|
||||
}
|
||||
}
|
||||
}
|
||||
1
Scripts/AttackPatterns/ShootingPattern3D.cs.uid
Normal file
1
Scripts/AttackPatterns/ShootingPattern3D.cs.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://bxiprx5nwmpnu
|
||||
52
Scripts/Resources/BulletScripts/BulletScript3D.cs
Normal file
52
Scripts/Resources/BulletScripts/BulletScript3D.cs
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
using Cirno.Scripts.AttackPatterns;
|
||||
using Godot;
|
||||
using Godot.Collections;
|
||||
|
||||
namespace Cirno.Scripts.Resources.BulletScripts;
|
||||
|
||||
[GlobalClass]
|
||||
[Tool]
|
||||
public partial class BulletScript3D : Resource
|
||||
{
|
||||
[Export]
|
||||
public Array<AttackPattern> Patterns { get; private set; }
|
||||
|
||||
public BulletScriptMachine Make(Node parent)
|
||||
{
|
||||
return new BulletScriptMachine(parent, Patterns);
|
||||
}
|
||||
|
||||
public class BulletScriptMachine(Node parent, Array<AttackPattern> patterns)
|
||||
{
|
||||
private int _currentPatternIndex = 0;
|
||||
//private double _patternTimer;
|
||||
|
||||
private AttackPattern CurrentPattern => patterns[_currentPatternIndex];
|
||||
|
||||
private IPatternMachine _currentPatternMachine;
|
||||
|
||||
public void Start()
|
||||
{
|
||||
if (patterns.Count == 0) return;
|
||||
_currentPatternIndex = 0;
|
||||
|
||||
_currentPatternMachine = CurrentPattern.MakeMachine(parent);
|
||||
_currentPatternMachine.Start();
|
||||
}
|
||||
|
||||
public void UpdatePhase(double delta)
|
||||
{
|
||||
//_patternTimer += delta;
|
||||
|
||||
_currentPatternMachine.UpdatePattern(delta);
|
||||
//CurrentPattern.UpdatePattern(delta);
|
||||
|
||||
if (!CurrentPattern.WaitForCompletion || _currentPatternMachine.IsComplete())
|
||||
{
|
||||
_currentPatternIndex = (_currentPatternIndex + 1) % patterns.Count;
|
||||
_currentPatternMachine = CurrentPattern.MakeMachine(parent);
|
||||
_currentPatternMachine.Start();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
1
Scripts/Resources/BulletScripts/BulletScript3D.cs.uid
Normal file
1
Scripts/Resources/BulletScripts/BulletScript3D.cs.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://w8hcpu68ssq
|
||||
|
|
@ -8,4 +8,9 @@ public static class VectorExtensions
|
|||
{
|
||||
return new Vector2(original.X, original.Z);
|
||||
}
|
||||
|
||||
public static Vector3 ToVector3(this Vector2 original, float height = 0)
|
||||
{
|
||||
return new Vector3(original.X, height, original.Y);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue