Initial Commit

This commit is contained in:
2026-03-16 14:38:46 +02:00
commit b8f7327a21
2327 changed files with 253610 additions and 0 deletions
@@ -0,0 +1,137 @@
using System;
using UnityEngine;
using Random = UnityEngine.Random;
namespace Zenject.SpaceFighter
{
public class EnemyStateAttack : IEnemyState
{
readonly EnemyRotationHandler _rotationHandler;
readonly EnemyCommonSettings _commonSettings;
readonly AudioPlayer _audioPlayer;
readonly EnemyTunables _tunables;
readonly EnemyStateManager _stateManager;
readonly PlayerFacade _player;
readonly Settings _settings;
readonly EnemyView _view;
readonly Bullet.Factory _bulletFactory;
float _lastShootTime;
bool _strafeRight;
float _lastStrafeChangeTime;
public EnemyStateAttack(
Bullet.Factory bulletFactory,
EnemyView view,
Settings settings,
PlayerFacade player,
EnemyStateManager stateManager,
EnemyTunables tunables,
AudioPlayer audioPlayer,
EnemyCommonSettings commonSettings,
EnemyRotationHandler rotationHandler)
{
_rotationHandler = rotationHandler;
_commonSettings = commonSettings;
_audioPlayer = audioPlayer;
_tunables = tunables;
_stateManager = stateManager;
_player = player;
_settings = settings;
_view = view;
_bulletFactory = bulletFactory;
_strafeRight = Random.Range(0.0f, 1.0f) < 0.5f;
}
public void EnterState()
{
}
public void ExitState()
{
}
public void Update()
{
if (_player.IsDead)
{
_stateManager.ChangeState(EnemyStates.Idle);
return;
}
_rotationHandler.DesiredLookDir = (_player.Position - _view.Position).normalized;
// Strafe back and forth over the given interval
if (Time.realtimeSinceStartup - _lastStrafeChangeTime > _settings.StrafeChangeInterval)
{
_lastStrafeChangeTime = Time.realtimeSinceStartup;
_strafeRight = !_strafeRight;
}
// Shoot every X seconds
if (Time.realtimeSinceStartup - _lastShootTime > _settings.ShootInterval)
{
_lastShootTime = Time.realtimeSinceStartup;
Fire();
}
// If the player runs away then chase them
if ((_player.Position - _view.Position).magnitude > _commonSettings.AttackDistance + _settings.AttackRangeBuffer)
{
_stateManager.ChangeState(EnemyStates.Follow);
}
}
public void FixedUpdate()
{
// Strafe to avoid getting hit too easily
if (_strafeRight)
{
_view.AddForce(_view.RightDir * _settings.StrafeMultiplier * _tunables.Speed);
}
else
{
_view.AddForce(-_view.RightDir * _settings.StrafeMultiplier * _tunables.Speed);
}
}
void Fire()
{
var bullet = _bulletFactory.Create(
_settings.BulletSpeed, _settings.BulletLifetime, BulletTypes.FromEnemy);
// Randomize our aim a bit
var accuracy = Mathf.Clamp(_tunables.Accuracy, 0, 1);
var maxError = 1.0f - accuracy;
var error = Random.Range(0, maxError);
if (Random.Range(0.0f, 1.0f) < 0.5f)
{
error *= -1;
}
var thetaError = error * _settings.ErrorRangeTheta;
bullet.transform.position = _view.Position + _view.LookDir * _settings.BulletOffsetDistance;
bullet.transform.rotation = Quaternion.AngleAxis(thetaError, Vector3.forward) * _view.Rotation;
_audioPlayer.Play(_settings.ShootSound, _settings.ShootSoundVolume);
}
[Serializable]
public class Settings
{
public AudioClip ShootSound;
public float ShootSoundVolume = 1.0f;
public float BulletLifetime;
public float BulletSpeed;
public float BulletOffsetDistance;
public float ShootInterval;
public float ErrorRangeTheta;
public float AttackRangeBuffer;
public float StrafeMultiplier;
public float StrafeChangeInterval;
}
}
}
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 3d2bd141d86c3fb40a0a616c19e6de0c
timeCreated: 1456620041
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,110 @@
using System;
using UnityEngine;
using Random = UnityEngine.Random;
namespace Zenject.SpaceFighter
{
public class EnemyStateFollow : IEnemyState
{
readonly EnemyRotationHandler _rotationHandler;
readonly EnemyCommonSettings _commonSettings;
readonly Settings _settings;
readonly EnemyTunables _tunables;
readonly EnemyStateManager _stateManager;
readonly EnemyView _view;
readonly PlayerFacade _player;
bool _strafeRight;
float _lastStrafeChangeTime;
public EnemyStateFollow(
PlayerFacade player,
EnemyView view,
EnemyStateManager stateManager,
EnemyTunables tunables,
Settings settings,
EnemyCommonSettings commonSettings,
EnemyRotationHandler rotationHandler)
{
_rotationHandler = rotationHandler;
_commonSettings = commonSettings;
_settings = settings;
_tunables = tunables;
_stateManager = stateManager;
_view = view;
_player = player;
}
public void EnterState()
{
_strafeRight = Random.Range(0, 1) == 0;
_lastStrafeChangeTime = Time.realtimeSinceStartup;
}
public void ExitState()
{
}
public void Update()
{
if (_player.IsDead)
{
_stateManager.ChangeState(EnemyStates.Idle);
return;
}
var distanceToPlayer = (_player.Position - _view.Position).magnitude;
// Always look towards the player
_rotationHandler.DesiredLookDir = (_player.Position - _view.Position).normalized;
// Strafe back and forth over the given interval
// This helps avoiding being too easy a target
if (Time.realtimeSinceStartup - _lastStrafeChangeTime > _settings.StrafeChangeInterval)
{
_lastStrafeChangeTime = Time.realtimeSinceStartup;
_strafeRight = !_strafeRight;
}
if (distanceToPlayer < _commonSettings.AttackDistance)
{
_stateManager.ChangeState(EnemyStates.Attack);
}
}
public void FixedUpdate()
{
MoveTowardsPlayer();
Strafe();
}
void Strafe()
{
// Strafe to avoid getting hit too easily
if (_strafeRight)
{
_view.AddForce(_view.RightDir * _settings.StrafeMultiplier * _tunables.Speed);
}
else
{
_view.AddForce(-_view.RightDir * _settings.StrafeMultiplier * _tunables.Speed);
}
}
void MoveTowardsPlayer()
{
var playerDir = (_player.Position - _view.Position).normalized;
_view.AddForce(playerDir * _tunables.Speed);
}
[Serializable]
public class Settings
{
public float StrafeMultiplier;
public float StrafeChangeInterval;
public float TeleportNewDistance;
}
}
}
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: f6b8435c02df92747b53470f32656b93
timeCreated: 1456620041
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,58 @@
using System;
using UnityEngine;
using Random = UnityEngine.Random;
namespace Zenject.SpaceFighter
{
public class EnemyStateIdle : IEnemyState
{
readonly EnemyRotationHandler _rotationHandler;
readonly Settings _settings;
readonly EnemyView _view;
Vector3 _startPos;
float _theta;
Vector3 _startLookDir;
public EnemyStateIdle(
EnemyView view, Settings settings,
EnemyRotationHandler rotationHandler)
{
_rotationHandler = rotationHandler;
_settings = settings;
_view = view;
}
public void EnterState()
{
_startPos = _view.Position;
_theta = Random.Range(0, 2.0f * Mathf.PI);
_startLookDir = _view.LookDir;
}
public void ExitState()
{
}
// Just add a bit of subtle movement
public void Update()
{
_theta += Time.deltaTime * _settings.Frequency;
_view.Position = _startPos + _view.RightDir * _settings.Amplitude * Mathf.Sin(_theta);
_rotationHandler.DesiredLookDir = _startLookDir;
}
public void FixedUpdate()
{
}
[Serializable]
public class Settings
{
public float Amplitude;
public float Frequency;
}
}
}
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 7a99ffa8c241c8a4e97392c7903712f0
timeCreated: 1456618194
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: