Initial Commit
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: be4d1f9900f1746418149a1b3ab2c2b0
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
userData:
|
||||
+115
@@ -0,0 +1,115 @@
|
||||
using System;
|
||||
using ModestTree;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Zenject.Asteroids
|
||||
{
|
||||
public class Asteroid : MonoBehaviour
|
||||
{
|
||||
LevelHelper _level;
|
||||
Rigidbody _rigidBody;
|
||||
Settings _settings;
|
||||
|
||||
// We could just add [Inject] to the field declarations but
|
||||
// it's often better practice to use PostInject methods
|
||||
// Note that we can't use Constructors here because this is
|
||||
// a MonoBehaviour
|
||||
[Inject]
|
||||
public void Construct(LevelHelper level, Settings settings)
|
||||
{
|
||||
_level = level;
|
||||
_settings = settings;
|
||||
_rigidBody = GetComponent<Rigidbody>();
|
||||
}
|
||||
|
||||
public Vector3 Position
|
||||
{
|
||||
get { return transform.position; }
|
||||
set { transform.position = value; }
|
||||
}
|
||||
|
||||
public float Mass
|
||||
{
|
||||
get { return _rigidBody.mass; }
|
||||
set { _rigidBody.mass = value; }
|
||||
}
|
||||
|
||||
public float Scale
|
||||
{
|
||||
get
|
||||
{
|
||||
var scale = transform.localScale;
|
||||
// We assume scale is uniform
|
||||
Assert.That(scale[0] == scale[1] && scale[1] == scale[2]);
|
||||
|
||||
return scale[0];
|
||||
}
|
||||
set
|
||||
{
|
||||
transform.localScale = new Vector3(value, value, value);
|
||||
_rigidBody.mass = value;
|
||||
}
|
||||
}
|
||||
|
||||
public Vector3 Velocity
|
||||
{
|
||||
get { return _rigidBody.linearVelocity; }
|
||||
set { _rigidBody.linearVelocity = value; }
|
||||
}
|
||||
|
||||
public void FixedTick()
|
||||
{
|
||||
// Limit speed to a maximum
|
||||
var speed = _rigidBody.linearVelocity.magnitude;
|
||||
|
||||
if (speed > _settings.maxSpeed)
|
||||
{
|
||||
var dir = _rigidBody.linearVelocity / speed;
|
||||
_rigidBody.linearVelocity = dir * _settings.maxSpeed;
|
||||
}
|
||||
}
|
||||
|
||||
public void Tick()
|
||||
{
|
||||
CheckForTeleport();
|
||||
}
|
||||
|
||||
void CheckForTeleport()
|
||||
{
|
||||
if (Position.x > _level.Right + Scale && IsMovingInDirection(Vector3.right))
|
||||
{
|
||||
transform.SetX(_level.Left - Scale);
|
||||
}
|
||||
else if (Position.x < _level.Left - Scale && IsMovingInDirection(-Vector3.right))
|
||||
{
|
||||
transform.SetX(_level.Right + Scale);
|
||||
}
|
||||
else if (Position.y < _level.Bottom - Scale && IsMovingInDirection(-Vector3.up))
|
||||
{
|
||||
transform.SetY(_level.Top + Scale);
|
||||
}
|
||||
else if (Position.y > _level.Top + Scale && IsMovingInDirection(Vector3.up))
|
||||
{
|
||||
transform.SetY(_level.Bottom - Scale);
|
||||
}
|
||||
|
||||
transform.RotateAround(transform.position, Vector3.up, 30 * Time.deltaTime);
|
||||
}
|
||||
|
||||
bool IsMovingInDirection(Vector3 dir)
|
||||
{
|
||||
return Vector3.Dot(dir, _rigidBody.linearVelocity) > 0;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class Settings
|
||||
{
|
||||
public float massScaleFactor;
|
||||
public float maxSpeed;
|
||||
}
|
||||
|
||||
public class Factory : PlaceholderFactory<Asteroid>
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5608cae0fd6ebbd46b5ad3c03b150682
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
+223
@@ -0,0 +1,223 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using ModestTree;
|
||||
using UnityEngine;
|
||||
using Random = UnityEngine.Random;
|
||||
|
||||
namespace Zenject.Asteroids
|
||||
{
|
||||
public class AsteroidManager : ITickable, IFixedTickable
|
||||
{
|
||||
readonly List<Asteroid> _asteroids = new List<Asteroid>();
|
||||
readonly Queue<AsteroidAttributes> _cachedAttributes = new Queue<AsteroidAttributes>();
|
||||
readonly Settings _settings;
|
||||
readonly Asteroid.Factory _asteroidFactory;
|
||||
readonly LevelHelper _level;
|
||||
|
||||
float _timeToNextSpawn;
|
||||
float _timeIntervalBetweenSpawns;
|
||||
bool _started;
|
||||
|
||||
[InjectOptional]
|
||||
bool _autoSpawn = true;
|
||||
|
||||
public AsteroidManager(
|
||||
Settings settings, Asteroid.Factory asteroidFactory, LevelHelper level)
|
||||
{
|
||||
_settings = settings;
|
||||
_timeIntervalBetweenSpawns = _settings.maxSpawnTime / (_settings.maxSpawns - _settings.startingSpawns);
|
||||
_timeToNextSpawn = _timeIntervalBetweenSpawns;
|
||||
_asteroidFactory = asteroidFactory;
|
||||
_level = level;
|
||||
}
|
||||
|
||||
public IEnumerable<Asteroid> Asteroids
|
||||
{
|
||||
get { return _asteroids; }
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
Assert.That(!_started);
|
||||
_started = true;
|
||||
|
||||
ResetAll();
|
||||
GenerateRandomAttributes();
|
||||
|
||||
for (int i = 0; i < _settings.startingSpawns; i++)
|
||||
{
|
||||
SpawnNext();
|
||||
}
|
||||
}
|
||||
|
||||
// Generate the full list of size and speeds so that we can maintain an approximate average
|
||||
// this way we don't get wildly different difficulties each time the game is run
|
||||
// For example, if we just chose speed randomly each time we spawned an asteroid, in some
|
||||
// cases that might result in the first set of asteroids all going at max speed, or min speed
|
||||
void GenerateRandomAttributes()
|
||||
{
|
||||
Assert.That(_cachedAttributes.Count == 0);
|
||||
|
||||
var speedTotal = 0.0f;
|
||||
var sizeTotal = 0.0f;
|
||||
|
||||
for (int i = 0; i < _settings.maxSpawns; i++)
|
||||
{
|
||||
var sizePx = Random.Range(0.0f, 1.0f);
|
||||
var speed = Random.Range(_settings.minSpeed, _settings.maxSpeed);
|
||||
|
||||
_cachedAttributes.Enqueue(new AsteroidAttributes {
|
||||
SizePx = sizePx,
|
||||
InitialSpeed = speed
|
||||
});
|
||||
|
||||
speedTotal += speed;
|
||||
sizeTotal += sizePx;
|
||||
}
|
||||
|
||||
var desiredAverageSpeed = (_settings.minSpeed + _settings.maxSpeed) * 0.5f;
|
||||
var desiredAverageSize = 0.5f;
|
||||
|
||||
var averageSize = sizeTotal / _settings.maxSpawns;
|
||||
var averageSpeed = speedTotal / _settings.maxSpawns;
|
||||
|
||||
var speedScaleFactor = desiredAverageSpeed / averageSpeed;
|
||||
var sizeScaleFactor = desiredAverageSize / averageSize;
|
||||
|
||||
foreach (var attributes in _cachedAttributes)
|
||||
{
|
||||
attributes.SizePx *= sizeScaleFactor;
|
||||
attributes.InitialSpeed *= speedScaleFactor;
|
||||
}
|
||||
|
||||
Assert.That(Mathf.Approximately(_cachedAttributes.Average(x => x.InitialSpeed), desiredAverageSpeed));
|
||||
Assert.That(Mathf.Approximately(_cachedAttributes.Average(x => x.SizePx), desiredAverageSize));
|
||||
}
|
||||
|
||||
void ResetAll()
|
||||
{
|
||||
foreach (var asteroid in _asteroids)
|
||||
{
|
||||
GameObject.Destroy(asteroid.gameObject);
|
||||
}
|
||||
|
||||
_asteroids.Clear();
|
||||
_cachedAttributes.Clear();
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
Assert.That(_started);
|
||||
_started = false;
|
||||
}
|
||||
|
||||
public void FixedTick()
|
||||
{
|
||||
for (int i = 0; i < _asteroids.Count; i++)
|
||||
{
|
||||
_asteroids[i].FixedTick();
|
||||
}
|
||||
}
|
||||
|
||||
public void Tick()
|
||||
{
|
||||
for (int i = 0; i < _asteroids.Count; i++)
|
||||
{
|
||||
_asteroids[i].Tick();
|
||||
}
|
||||
|
||||
if (_started && _autoSpawn)
|
||||
{
|
||||
_timeToNextSpawn -= Time.deltaTime;
|
||||
|
||||
if (_timeToNextSpawn < 0 && _asteroids.Count < _settings.maxSpawns)
|
||||
{
|
||||
_timeToNextSpawn = _timeIntervalBetweenSpawns;
|
||||
SpawnNext();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SpawnNext()
|
||||
{
|
||||
var asteroid = _asteroidFactory.Create();
|
||||
|
||||
var attributes = _cachedAttributes.Dequeue();
|
||||
|
||||
asteroid.Scale = Mathf.Lerp(_settings.minScale, _settings.maxScale, attributes.SizePx);
|
||||
asteroid.Mass = Mathf.Lerp(_settings.minMass, _settings.maxMass, attributes.SizePx);
|
||||
asteroid.Position = GetRandomStartPosition(asteroid.Scale);
|
||||
asteroid.Velocity = GetRandomDirection() * attributes.InitialSpeed;
|
||||
|
||||
_asteroids.Add(asteroid);
|
||||
}
|
||||
|
||||
Vector3 GetRandomDirection()
|
||||
{
|
||||
var theta = Random.Range(0, Mathf.PI * 2.0f);
|
||||
return new Vector3(Mathf.Cos(theta), Mathf.Sin(theta), 0);
|
||||
}
|
||||
|
||||
Vector3 GetRandomStartPosition(float scale)
|
||||
{
|
||||
var side = (Side)Random.Range(0, (int)Side.Count);
|
||||
var rand = Random.Range(0.0f, 1.0f);
|
||||
|
||||
switch (side)
|
||||
{
|
||||
case Side.Top:
|
||||
{
|
||||
return new Vector3(_level.Left + rand * _level.Width, _level.Top + scale, 0);
|
||||
}
|
||||
case Side.Bottom:
|
||||
{
|
||||
return new Vector3(_level.Left + rand * _level.Width, _level.Bottom - scale, 0);
|
||||
}
|
||||
case Side.Right:
|
||||
{
|
||||
return new Vector3(_level.Right + scale, _level.Bottom + rand * _level.Height, 0);
|
||||
}
|
||||
case Side.Left:
|
||||
{
|
||||
return new Vector3(_level.Left - scale, _level.Bottom + rand * _level.Height, 0);
|
||||
}
|
||||
}
|
||||
|
||||
throw Assert.CreateException();
|
||||
}
|
||||
|
||||
enum Side
|
||||
{
|
||||
Top,
|
||||
Bottom,
|
||||
Left,
|
||||
Right,
|
||||
Count
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class Settings
|
||||
{
|
||||
public float minSpeed;
|
||||
public float maxSpeed;
|
||||
|
||||
public float minScale;
|
||||
public float maxScale;
|
||||
|
||||
public int startingSpawns;
|
||||
public int maxSpawns;
|
||||
|
||||
public float maxSpawnTime;
|
||||
|
||||
public float maxMass;
|
||||
public float minMass;
|
||||
}
|
||||
|
||||
class AsteroidAttributes
|
||||
{
|
||||
public float SizePx;
|
||||
public float InitialSpeed;
|
||||
}
|
||||
}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a9a361be236d95c48a1de52c435fcc9a
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
@@ -0,0 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a1b545d343661c54bbb60bc94fe13453
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
userData:
|
||||
+129
@@ -0,0 +1,129 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Zenject.Asteroids
|
||||
{
|
||||
public class GameInstaller : MonoInstaller
|
||||
{
|
||||
[Inject]
|
||||
Settings _settings = null;
|
||||
|
||||
public override void InstallBindings()
|
||||
{
|
||||
// In this example there is only one 'installer' but in larger projects you
|
||||
// will likely end up with many different re-usable installers
|
||||
// that you'll want to use in several different scenes
|
||||
//
|
||||
// There are several ways to do this. You can store your installer as a prefab,
|
||||
// a scriptable object, a component within the scene, etc. Or, if you don't
|
||||
// need your installer to be a MonoBehaviour then you can just simply call
|
||||
// Container.Install
|
||||
//
|
||||
// See here for more details:
|
||||
// https://github.com/modesttree/zenject#installers
|
||||
//
|
||||
//Container.Install<MyOtherInstaller>();
|
||||
|
||||
// Install the main game
|
||||
InstallAsteroids();
|
||||
InstallShip();
|
||||
InstallMisc();
|
||||
InstallSignals();
|
||||
InstallExecutionOrder();
|
||||
}
|
||||
|
||||
void InstallAsteroids()
|
||||
{
|
||||
// ITickable, IFixedTickable, IInitializable and IDisposable are special Zenject interfaces.
|
||||
// Binding a class to any of these interfaces creates an instance of the class at startup.
|
||||
// Binding to any of these interfaces is also necessary to have the method defined in that interface be
|
||||
// called on the implementing class as follows:
|
||||
// Binding to ITickable or IFixedTickable will result in Tick() or FixedTick() being called like Update() or FixedUpdate().
|
||||
// Binding to IInitializable means that Initialize() will be called on startup during Unity's Start event.
|
||||
// Binding to IDisposable means that Dispose() will be called when the app closes or the scene changes
|
||||
|
||||
// Any time you use To<Foo>().AsSingle, what that means is that the DiContainer will only ever instantiate
|
||||
// one instance of the type given inside the To<> (in this example, Foo). So in this case, any classes that take ITickable,
|
||||
// IFixedTickable, or AsteroidManager as inputs will receive the same instance of AsteroidManager.
|
||||
// We create multiple bindings for ITickable, so any dependencies that reference this type must be lists of ITickable.
|
||||
Container.BindInterfacesAndSelfTo<AsteroidManager>().AsSingle();
|
||||
|
||||
// Note that the above binding is equivalent to the following:
|
||||
//Container.Bind(typeof(ITickable), typeof(IFixedTickable), typeof(AsteroidManager)).To<AsteroidManager>.AsSingle();
|
||||
|
||||
// Here, we're defining a generic factory to create asteroid objects using the given prefab
|
||||
// So any classes that want to create new asteroid objects can simply include an injected field
|
||||
// or constructor parameter of type Asteroid.Factory, then call Create() on that
|
||||
Container.BindFactory<Asteroid, Asteroid.Factory>()
|
||||
// This means that any time Asteroid.Factory.Create is called, it will instantiate
|
||||
// this prefab and then search it for the Asteroid component
|
||||
.FromComponentInNewPrefab(_settings.AsteroidPrefab)
|
||||
// We can also tell Zenject what to name the new gameobject here
|
||||
.WithGameObjectName("Asteroid")
|
||||
// GameObjectGroup's are just game objects used for organization
|
||||
// This is nice so that it doesn't clutter up our scene hierarchy
|
||||
.UnderTransformGroup("Asteroids");
|
||||
}
|
||||
|
||||
void InstallMisc()
|
||||
{
|
||||
Container.BindInterfacesAndSelfTo<GameController>().AsSingle();
|
||||
Container.Bind<LevelHelper>().AsSingle();
|
||||
|
||||
Container.BindInterfacesTo<AudioHandler>().AsSingle();
|
||||
|
||||
// FromComponentInNewPrefab matches the first transform only just like GetComponentsInChildren
|
||||
// So can be useful in cases where we don't need a custom MonoBehaviour attached
|
||||
Container.BindFactory<Transform, ExplosionFactory>()
|
||||
.FromComponentInNewPrefab(_settings.ExplosionPrefab);
|
||||
|
||||
Container.BindFactory<Transform, BrokenShipFactory>()
|
||||
.FromComponentInNewPrefab(_settings.BrokenShipPrefab);
|
||||
}
|
||||
|
||||
void InstallSignals()
|
||||
{
|
||||
// Every scene that uses signals needs to install the built-in installer SignalBusInstaller
|
||||
// Or alternatively it can be installed at the project context level (see docs for details)
|
||||
SignalBusInstaller.Install(Container);
|
||||
|
||||
// Signals can be useful for game-wide events that could have many interested parties
|
||||
Container.DeclareSignal<ShipCrashedSignal>();
|
||||
}
|
||||
|
||||
void InstallShip()
|
||||
{
|
||||
Container.Bind<ShipStateFactory>().AsSingle();
|
||||
|
||||
// Note that the ship itself is bound using a ZenjectBinding component (see Ship
|
||||
// game object in scene heirarchy)
|
||||
|
||||
Container.BindFactory<ShipStateWaitingToStart, ShipStateWaitingToStart.Factory>().WhenInjectedInto<ShipStateFactory>();
|
||||
Container.BindFactory<ShipStateDead, ShipStateDead.Factory>().WhenInjectedInto<ShipStateFactory>();
|
||||
Container.BindFactory<ShipStateMoving, ShipStateMoving.Factory>().WhenInjectedInto<ShipStateFactory>();
|
||||
}
|
||||
|
||||
void InstallExecutionOrder()
|
||||
{
|
||||
// In many cases you don't need to worry about execution order,
|
||||
// however sometimes it can be important
|
||||
// If for example we wanted to ensure that AsteroidManager.Initialize
|
||||
// always gets called before GameController.Initialize (and similarly for Tick)
|
||||
// Then we could do the following:
|
||||
Container.BindExecutionOrder<AsteroidManager>(-20);
|
||||
Container.BindExecutionOrder<GameController>(-10);
|
||||
|
||||
// Note that they will be disposed of in the reverse order given here
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class Settings
|
||||
{
|
||||
public GameObject ExplosionPrefab;
|
||||
public GameObject BrokenShipPrefab;
|
||||
public GameObject AsteroidPrefab;
|
||||
public GameObject ShipPrefab;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ac59283f2813c5643a2495056b74c1c0
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
using System;
|
||||
|
||||
namespace Zenject.Asteroids
|
||||
{
|
||||
// We prefer to use ScriptableObjectInstaller for installers that contain game settings
|
||||
// There's no reason why you couldn't use a MonoInstaller here instead, however
|
||||
// using ScriptableObjectInstaller has advantages here that make it nice for settings:
|
||||
//
|
||||
// 1) You can change these values at runtime and have those changes persist across play
|
||||
// sessions. If it was a MonoInstaller then any changes would be lost when you hit stop
|
||||
// 2) You can easily create multiple ScriptableObject instances of this installer to test
|
||||
// different customizations to settings. For example, you might have different instances
|
||||
// for each difficulty mode of your game, such as "Easy", "Hard", etc.
|
||||
// 3) If your settings are associated with a game object composition root, then using
|
||||
// ScriptableObjectInstaller can be easier since there will only ever be one definitive
|
||||
// instance for each setting. Otherwise, you'd have to change the settings for each game
|
||||
// object composition root separately at runtime
|
||||
//
|
||||
// Uncomment if you want to add alternative game settings
|
||||
//[CreateAssetMenu(menuName = "Asteroids/Game Settings")]
|
||||
public class GameSettingsInstaller : ScriptableObjectInstaller<GameSettingsInstaller>
|
||||
{
|
||||
public ShipSettings Ship;
|
||||
public AsteroidSettings Asteroid;
|
||||
public AudioHandler.Settings AudioHandler;
|
||||
public GameInstaller.Settings GameInstaller;
|
||||
|
||||
// We use nested classes here to group related settings together
|
||||
[Serializable]
|
||||
public class ShipSettings
|
||||
{
|
||||
public ShipStateMoving.Settings StateMoving;
|
||||
public ShipStateDead.Settings StateDead;
|
||||
public ShipStateWaitingToStart.Settings StateStarting;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class AsteroidSettings
|
||||
{
|
||||
public AsteroidManager.Settings Spawner;
|
||||
public Asteroid.Settings General;
|
||||
}
|
||||
|
||||
public override void InstallBindings()
|
||||
{
|
||||
Container.BindInstance(Ship.StateMoving);
|
||||
Container.BindInstance(Ship.StateDead);
|
||||
Container.BindInstance(Ship.StateStarting);
|
||||
Container.BindInstance(Asteroid.Spawner);
|
||||
Container.BindInstance(Asteroid.General);
|
||||
Container.BindInstance(AudioHandler);
|
||||
Container.BindInstance(GameInstaller);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ed9935f795c01cc498910bae6d24d10a
|
||||
timeCreated: 1461785453
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 400be1c46a6fb414f856927bc0910da7
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
userData:
|
||||
+127
@@ -0,0 +1,127 @@
|
||||
using System;
|
||||
using ModestTree;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Zenject.Asteroids
|
||||
{
|
||||
public enum GameStates
|
||||
{
|
||||
WaitingToStart,
|
||||
Playing,
|
||||
GameOver
|
||||
}
|
||||
|
||||
public class GameController : IInitializable, ITickable, IDisposable
|
||||
{
|
||||
readonly SignalBus _signalBus;
|
||||
readonly Ship _ship;
|
||||
readonly AsteroidManager _asteroidSpawner;
|
||||
|
||||
GameStates _state = GameStates.WaitingToStart;
|
||||
float _elapsedTime;
|
||||
|
||||
public GameController(
|
||||
Ship ship, AsteroidManager asteroidSpawner,
|
||||
SignalBus signalBus)
|
||||
{
|
||||
_signalBus = signalBus;
|
||||
_asteroidSpawner = asteroidSpawner;
|
||||
_ship = ship;
|
||||
}
|
||||
|
||||
public float ElapsedTime
|
||||
{
|
||||
get { return _elapsedTime; }
|
||||
}
|
||||
|
||||
public GameStates State
|
||||
{
|
||||
get { return _state; }
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
Physics.gravity = Vector3.zero;
|
||||
|
||||
Cursor.visible = false;
|
||||
|
||||
_signalBus.Subscribe<ShipCrashedSignal>(OnShipCrashed);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_signalBus.Unsubscribe<ShipCrashedSignal>(OnShipCrashed);
|
||||
}
|
||||
|
||||
public void Tick()
|
||||
{
|
||||
switch (_state)
|
||||
{
|
||||
case GameStates.WaitingToStart:
|
||||
{
|
||||
UpdateStarting();
|
||||
break;
|
||||
}
|
||||
case GameStates.Playing:
|
||||
{
|
||||
UpdatePlaying();
|
||||
break;
|
||||
}
|
||||
case GameStates.GameOver:
|
||||
{
|
||||
UpdateGameOver();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
Assert.That(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateGameOver()
|
||||
{
|
||||
Assert.That(_state == GameStates.GameOver);
|
||||
|
||||
if (Input.GetMouseButtonDown(0))
|
||||
{
|
||||
StartGame();
|
||||
}
|
||||
}
|
||||
|
||||
void OnShipCrashed()
|
||||
{
|
||||
Assert.That(_state == GameStates.Playing);
|
||||
_state = GameStates.GameOver;
|
||||
_asteroidSpawner.Stop();
|
||||
}
|
||||
|
||||
void UpdatePlaying()
|
||||
{
|
||||
Assert.That(_state == GameStates.Playing);
|
||||
_elapsedTime += Time.deltaTime;
|
||||
}
|
||||
|
||||
void UpdateStarting()
|
||||
{
|
||||
Assert.That(_state == GameStates.WaitingToStart);
|
||||
|
||||
if (Input.GetMouseButtonDown(0))
|
||||
{
|
||||
StartGame();
|
||||
}
|
||||
}
|
||||
|
||||
void StartGame()
|
||||
{
|
||||
Assert.That(_state == GameStates.WaitingToStart || _state == GameStates.GameOver);
|
||||
|
||||
_ship.Position = Vector3.zero;
|
||||
_elapsedTime = 0;
|
||||
_asteroidSpawner.Start();
|
||||
_ship.ChangeState(ShipStates.Moving);
|
||||
_state = GameStates.Playing;
|
||||
}
|
||||
}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d1fe837eefbc3fa4ab06a9081d26caf9
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
@@ -0,0 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f289e0dd7cbe36b408dcfd072332f8b6
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
userData:
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Zenject.Asteroids
|
||||
{
|
||||
public class AudioHandler : IInitializable, IDisposable
|
||||
{
|
||||
readonly SignalBus _signalBus;
|
||||
readonly Settings _settings;
|
||||
readonly AudioSource _audioSource;
|
||||
|
||||
public AudioHandler(
|
||||
AudioSource audioSource,
|
||||
Settings settings,
|
||||
SignalBus signalBus)
|
||||
{
|
||||
_signalBus = signalBus;
|
||||
_settings = settings;
|
||||
_audioSource = audioSource;
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
_signalBus.Subscribe<ShipCrashedSignal>(OnShipCrashed);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_signalBus.Unsubscribe<ShipCrashedSignal>(OnShipCrashed);
|
||||
}
|
||||
|
||||
void OnShipCrashed()
|
||||
{
|
||||
_audioSource.PlayOneShot(_settings.CrashSound);
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class Settings
|
||||
{
|
||||
public AudioClip CrashSound;
|
||||
}
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 24cbab5eaeb84b44481d817f66ea7b27
|
||||
timeCreated: 1461797898
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+218
@@ -0,0 +1,218 @@
|
||||
using System;
|
||||
using ModestTree;
|
||||
using UnityEngine;
|
||||
|
||||
#pragma warning disable 649
|
||||
|
||||
namespace Zenject.Asteroids
|
||||
{
|
||||
public class GuiHandler : MonoBehaviour, IDisposable, IInitializable
|
||||
{
|
||||
GameController _gameController;
|
||||
|
||||
[SerializeField]
|
||||
GUIStyle _titleStyle;
|
||||
|
||||
[SerializeField]
|
||||
GUIStyle _instructionsStyle;
|
||||
|
||||
[SerializeField]
|
||||
GUIStyle _timeStyle;
|
||||
|
||||
[SerializeField]
|
||||
float _gameOverFadeInTime;
|
||||
|
||||
[SerializeField]
|
||||
float _gameOverStartFadeTime;
|
||||
|
||||
[SerializeField]
|
||||
float _restartTextStartFadeTime;
|
||||
|
||||
[SerializeField]
|
||||
float _restartTextFadeInTime;
|
||||
|
||||
float _gameOverElapsed;
|
||||
SignalBus _signalBus;
|
||||
|
||||
[Inject]
|
||||
public void Construct(
|
||||
GameController gameController, SignalBus signalBus)
|
||||
{
|
||||
_gameController = gameController;
|
||||
_signalBus = signalBus;
|
||||
}
|
||||
|
||||
void OnGUI()
|
||||
{
|
||||
GUILayout.BeginArea(new Rect(0, 0, Screen.width, Screen.height));
|
||||
{
|
||||
switch (_gameController.State)
|
||||
{
|
||||
case GameStates.WaitingToStart:
|
||||
{
|
||||
StartGui();
|
||||
break;
|
||||
}
|
||||
case GameStates.Playing:
|
||||
{
|
||||
PlayingGui();
|
||||
break;
|
||||
}
|
||||
case GameStates.GameOver:
|
||||
{
|
||||
PlayingGui();
|
||||
GameOverGui();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
Assert.That(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
GUILayout.EndArea();
|
||||
}
|
||||
|
||||
void GameOverGui()
|
||||
{
|
||||
_gameOverElapsed += Time.deltaTime;
|
||||
|
||||
if (_gameOverElapsed > _gameOverStartFadeTime)
|
||||
{
|
||||
var px = Mathf.Min(1.0f, (_gameOverElapsed - _gameOverStartFadeTime) / _gameOverFadeInTime);
|
||||
_titleStyle.normal.textColor = new Color(1, 1, 1, px);
|
||||
}
|
||||
else
|
||||
{
|
||||
_titleStyle.normal.textColor = new Color(1, 1, 1, 0);
|
||||
}
|
||||
|
||||
if (_gameOverElapsed > _restartTextStartFadeTime)
|
||||
{
|
||||
var px = Mathf.Min(1.0f, (_gameOverElapsed - _restartTextStartFadeTime) / _restartTextFadeInTime);
|
||||
_instructionsStyle.normal.textColor = new Color(1, 1, 1, px);
|
||||
}
|
||||
else
|
||||
{
|
||||
_instructionsStyle.normal.textColor = new Color(1, 1, 1, 0);
|
||||
}
|
||||
|
||||
GUILayout.BeginHorizontal();
|
||||
{
|
||||
GUILayout.FlexibleSpace();
|
||||
GUILayout.BeginVertical();
|
||||
{
|
||||
GUILayout.FlexibleSpace();
|
||||
GUILayout.BeginVertical();
|
||||
{
|
||||
GUILayout.FlexibleSpace();
|
||||
|
||||
GUILayout.BeginHorizontal();
|
||||
{
|
||||
GUILayout.FlexibleSpace();
|
||||
GUILayout.Label("GAME OVER", _titleStyle);
|
||||
GUILayout.FlexibleSpace();
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUILayout.Space(60);
|
||||
|
||||
GUILayout.BeginHorizontal();
|
||||
{
|
||||
GUILayout.FlexibleSpace();
|
||||
|
||||
GUILayout.Label("Click to restart", _instructionsStyle);
|
||||
|
||||
GUILayout.FlexibleSpace();
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
GUILayout.EndVertical();
|
||||
|
||||
GUILayout.FlexibleSpace();
|
||||
}
|
||||
|
||||
GUILayout.EndVertical();
|
||||
GUILayout.FlexibleSpace();
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
void PlayingGui()
|
||||
{
|
||||
GUILayout.BeginVertical();
|
||||
{
|
||||
GUILayout.Space(30);
|
||||
GUILayout.BeginHorizontal();
|
||||
{
|
||||
GUILayout.Space(30);
|
||||
GUILayout.Label("Time: " + _gameController.ElapsedTime.ToString("0.##"), _timeStyle);
|
||||
GUILayout.FlexibleSpace();
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
GUILayout.EndVertical();
|
||||
}
|
||||
|
||||
void StartGui()
|
||||
{
|
||||
GUILayout.BeginHorizontal();
|
||||
{
|
||||
GUILayout.FlexibleSpace();
|
||||
GUILayout.BeginVertical();
|
||||
{
|
||||
GUILayout.Space(100);
|
||||
GUILayout.FlexibleSpace();
|
||||
GUILayout.BeginVertical();
|
||||
{
|
||||
GUILayout.FlexibleSpace();
|
||||
|
||||
GUILayout.BeginHorizontal();
|
||||
{
|
||||
GUILayout.FlexibleSpace();
|
||||
GUILayout.Label("ASTEROIDS", _titleStyle);
|
||||
GUILayout.FlexibleSpace();
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUILayout.Space(60);
|
||||
|
||||
GUILayout.BeginHorizontal();
|
||||
{
|
||||
GUILayout.FlexibleSpace();
|
||||
|
||||
GUILayout.Label("Click to start", _instructionsStyle);
|
||||
|
||||
GUILayout.FlexibleSpace();
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
GUILayout.EndVertical();
|
||||
|
||||
GUILayout.FlexibleSpace();
|
||||
}
|
||||
|
||||
GUILayout.EndVertical();
|
||||
GUILayout.FlexibleSpace();
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
_signalBus.Subscribe<ShipCrashedSignal>(OnShipCrashed);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_signalBus.Unsubscribe<ShipCrashedSignal>(OnShipCrashed);
|
||||
}
|
||||
|
||||
void OnShipCrashed()
|
||||
{
|
||||
_gameOverElapsed = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 79984cb687438fd469b84d7e916d0574
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Zenject.Asteroids
|
||||
{
|
||||
public class LevelHelper
|
||||
{
|
||||
readonly Camera _camera;
|
||||
|
||||
public LevelHelper(
|
||||
[Inject(Id = "Main")]
|
||||
Camera camera)
|
||||
{
|
||||
_camera = camera;
|
||||
}
|
||||
|
||||
public float Bottom
|
||||
{
|
||||
get { return -ExtentHeight; }
|
||||
}
|
||||
|
||||
public float Top
|
||||
{
|
||||
get { return ExtentHeight; }
|
||||
}
|
||||
|
||||
public float Left
|
||||
{
|
||||
get { return -ExtentWidth; }
|
||||
}
|
||||
|
||||
public float Right
|
||||
{
|
||||
get { return ExtentWidth; }
|
||||
}
|
||||
|
||||
public float ExtentHeight
|
||||
{
|
||||
get { return _camera.orthographicSize; }
|
||||
}
|
||||
|
||||
public float Height
|
||||
{
|
||||
get { return ExtentHeight * 2.0f; }
|
||||
}
|
||||
|
||||
public float ExtentWidth
|
||||
{
|
||||
get { return _camera.aspect * _camera.orthographicSize; }
|
||||
}
|
||||
|
||||
public float Width
|
||||
{
|
||||
get { return ExtentWidth * 2.0f; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 439c34e98ba09b546be28d2b13fda970
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
using UnityEngine;
|
||||
|
||||
#pragma warning disable 649
|
||||
|
||||
namespace Zenject.Asteroids
|
||||
{
|
||||
public class TilingBackground : MonoBehaviour
|
||||
{
|
||||
[SerializeField]
|
||||
float _speed;
|
||||
|
||||
Vector2 _offset;
|
||||
Renderer _renderer;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
_renderer = GetComponent<Renderer>();
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
_offset.y += _speed * Time.deltaTime;
|
||||
_renderer.material.mainTextureOffset = _offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d72ecc6be0485ff4f96c39e24aea61f3
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
@@ -0,0 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bb012d11f2128404dbc27a5b0ed3e26a
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
userData:
|
||||
@@ -0,0 +1,87 @@
|
||||
using UnityEngine;
|
||||
|
||||
#pragma warning disable 649
|
||||
#pragma warning disable 618
|
||||
|
||||
namespace Zenject.Asteroids
|
||||
{
|
||||
public class Ship : MonoBehaviour
|
||||
{
|
||||
[SerializeField]
|
||||
MeshRenderer _meshRenderer;
|
||||
|
||||
#if UNITY_2018_1_OR_NEWER
|
||||
[SerializeField]
|
||||
ParticleSystem _particleSystem;
|
||||
#else
|
||||
[SerializeField]
|
||||
ParticleEmitter _particleEmitter;
|
||||
#endif
|
||||
|
||||
ShipStateFactory _stateFactory;
|
||||
ShipState _state;
|
||||
|
||||
[Inject]
|
||||
public void Construct(ShipStateFactory stateFactory)
|
||||
{
|
||||
_stateFactory = stateFactory;
|
||||
}
|
||||
|
||||
public MeshRenderer MeshRenderer
|
||||
{
|
||||
get { return _meshRenderer; }
|
||||
}
|
||||
|
||||
#if UNITY_2018_1_OR_NEWER
|
||||
public ParticleSystem ParticleEmitter
|
||||
{
|
||||
get { return _particleSystem; }
|
||||
}
|
||||
#else
|
||||
public ParticleEmitter ParticleEmitter
|
||||
{
|
||||
get { return _particleEmitter; }
|
||||
}
|
||||
#endif
|
||||
|
||||
public Vector3 Position
|
||||
{
|
||||
get { return transform.position; }
|
||||
set { transform.position = value; }
|
||||
}
|
||||
|
||||
public Quaternion Rotation
|
||||
{
|
||||
get { return transform.rotation; }
|
||||
set { transform.rotation = value; }
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
ChangeState(ShipStates.WaitingToStart);
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
_state.Update();
|
||||
}
|
||||
|
||||
public void OnTriggerEnter(Collider other)
|
||||
{
|
||||
_state.OnTriggerEnter(other);
|
||||
}
|
||||
|
||||
public void ChangeState(ShipStates state)
|
||||
{
|
||||
if (_state != null)
|
||||
{
|
||||
_state.Dispose();
|
||||
_state = null;
|
||||
}
|
||||
|
||||
_state = _stateFactory.CreateState(state);
|
||||
_state.Start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: aab42c7e45a13404daf7de27c7366efc
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
using ModestTree;
|
||||
|
||||
namespace Zenject.Asteroids
|
||||
{
|
||||
public enum ShipStates
|
||||
{
|
||||
Moving,
|
||||
Dead,
|
||||
WaitingToStart,
|
||||
Count
|
||||
}
|
||||
|
||||
public class ShipStateFactory
|
||||
{
|
||||
readonly ShipStateWaitingToStart.Factory _waitingFactory;
|
||||
readonly ShipStateMoving.Factory _movingFactory;
|
||||
readonly ShipStateDead.Factory _deadFactory;
|
||||
|
||||
public ShipStateFactory(
|
||||
ShipStateDead.Factory deadFactory,
|
||||
ShipStateMoving.Factory movingFactory,
|
||||
ShipStateWaitingToStart.Factory waitingFactory)
|
||||
{
|
||||
_waitingFactory = waitingFactory;
|
||||
_movingFactory = movingFactory;
|
||||
_deadFactory = deadFactory;
|
||||
}
|
||||
|
||||
public ShipState CreateState(ShipStates state)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case ShipStates.Dead:
|
||||
{
|
||||
return _deadFactory.Create();
|
||||
}
|
||||
case ShipStates.WaitingToStart:
|
||||
{
|
||||
return _waitingFactory.Create();
|
||||
}
|
||||
case ShipStates.Moving:
|
||||
{
|
||||
return _movingFactory.Create();
|
||||
}
|
||||
}
|
||||
|
||||
throw Assert.CreateException();
|
||||
}
|
||||
}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 732d3e232d9f7084ca4f03e6129bcbb6
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 35ea476df49732c408f30d07debaf227
|
||||
folderAsset: yes
|
||||
timeCreated: 1461796083
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Zenject.Asteroids
|
||||
{
|
||||
public class BrokenShipFactory : PlaceholderFactory<Transform>
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b9b5eb959c3c75149a4153c9c7d7a7d4
|
||||
timeCreated: 1528645987
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Zenject.Asteroids
|
||||
{
|
||||
public class ExplosionFactory : PlaceholderFactory<Transform>
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: aa6c7bf121e4f8343b05c7d09eb12ec6
|
||||
timeCreated: 1528645987
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Zenject.Asteroids
|
||||
{
|
||||
public abstract class ShipState : IDisposable
|
||||
{
|
||||
public abstract void Update();
|
||||
|
||||
public virtual void Start()
|
||||
{
|
||||
// optionally overridden
|
||||
}
|
||||
|
||||
public virtual void Dispose()
|
||||
{
|
||||
// optionally overridden
|
||||
}
|
||||
|
||||
public virtual void OnTriggerEnter(Collider other)
|
||||
{
|
||||
// optionally overridden
|
||||
}
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a68789b75fb09ef43b854fd3c59241b0
|
||||
timeCreated: 1461796083
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using Random = UnityEngine.Random;
|
||||
|
||||
namespace Zenject.Asteroids
|
||||
{
|
||||
public class ShipStateDead : ShipState
|
||||
{
|
||||
readonly SignalBus _signalBus;
|
||||
readonly BrokenShipFactory _brokenShipFactory;
|
||||
readonly ExplosionFactory _explosionFactory;
|
||||
readonly Settings _settings;
|
||||
readonly Ship _ship;
|
||||
|
||||
GameObject _shipBroken;
|
||||
GameObject _explosion;
|
||||
|
||||
public ShipStateDead(
|
||||
Settings settings, Ship ship,
|
||||
ExplosionFactory explosionFactory,
|
||||
BrokenShipFactory brokenShipFactory,
|
||||
SignalBus signalBus)
|
||||
{
|
||||
_signalBus = signalBus;
|
||||
_brokenShipFactory = brokenShipFactory;
|
||||
_explosionFactory = explosionFactory;
|
||||
_settings = settings;
|
||||
_ship = ship;
|
||||
}
|
||||
|
||||
public override void Start()
|
||||
{
|
||||
_ship.MeshRenderer.enabled = false;
|
||||
|
||||
_ship.ParticleEmitter.gameObject.SetActive(false);
|
||||
|
||||
_explosion = _explosionFactory.Create().gameObject;
|
||||
_explosion.transform.position = _ship.Position;
|
||||
|
||||
_shipBroken = _brokenShipFactory.Create().gameObject;
|
||||
_shipBroken.transform.position = _ship.Position;
|
||||
_shipBroken.transform.rotation = _ship.Rotation;
|
||||
|
||||
foreach (var rigidBody in _shipBroken.GetComponentsInChildren<Rigidbody>())
|
||||
{
|
||||
var randomTheta = Random.Range(0, Mathf.PI * 2.0f);
|
||||
var randomDir = new Vector3(Mathf.Cos(randomTheta), Mathf.Sin(randomTheta), 0);
|
||||
rigidBody.AddForce(randomDir * _settings.explosionForce);
|
||||
}
|
||||
|
||||
_signalBus.Fire<ShipCrashedSignal>();
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
_ship.MeshRenderer.enabled = true;
|
||||
|
||||
_ship.ParticleEmitter.gameObject.SetActive(true);
|
||||
|
||||
GameObject.Destroy(_explosion);
|
||||
GameObject.Destroy(_shipBroken);
|
||||
}
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class Settings
|
||||
{
|
||||
public float explosionForce;
|
||||
}
|
||||
|
||||
public class Factory : PlaceholderFactory<ShipStateDead>
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 379e1c748b9152a449b52cd01e25a642
|
||||
timeCreated: 1461796083
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+112
@@ -0,0 +1,112 @@
|
||||
using System;
|
||||
using ModestTree;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Zenject.Asteroids
|
||||
{
|
||||
public class ShipStateMoving : ShipState
|
||||
{
|
||||
readonly Settings _settings;
|
||||
readonly Camera _mainCamera;
|
||||
readonly Ship _ship;
|
||||
|
||||
Vector3 _lastPosition;
|
||||
float _oscillationTheta;
|
||||
|
||||
public ShipStateMoving(
|
||||
Settings settings, Ship ship,
|
||||
[Inject(Id = "Main")]
|
||||
Camera mainCamera)
|
||||
{
|
||||
_ship = ship;
|
||||
_settings = settings;
|
||||
_mainCamera = mainCamera;
|
||||
}
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
UpdateThruster();
|
||||
Move();
|
||||
ApplyOscillation();
|
||||
}
|
||||
|
||||
void ApplyOscillation()
|
||||
{
|
||||
var obj = _ship.MeshRenderer.gameObject;
|
||||
|
||||
var cycleInterval = 1.0f / _settings.oscillationFrequency;
|
||||
var thetaMoveSpeed = 2 * Mathf.PI / cycleInterval;
|
||||
|
||||
_oscillationTheta += thetaMoveSpeed * Time.deltaTime;
|
||||
|
||||
obj.transform.position = obj.transform.parent.position + new Vector3(0, _settings.oscillationAmplitude * Mathf.Sin(_oscillationTheta), 0);
|
||||
}
|
||||
|
||||
void UpdateThruster()
|
||||
{
|
||||
var speed = (_ship.Position - _lastPosition).magnitude / Time.deltaTime;
|
||||
var speedPx = Mathf.Clamp(speed / _settings.speedForMaxEmisssion, 0.0f, 1.0f);
|
||||
|
||||
#if UNITY_2018_1_OR_NEWER
|
||||
var emission = _ship.ParticleEmitter.emission;
|
||||
emission.rateOverTime = _settings.maxEmission * speedPx;
|
||||
#else
|
||||
_ship.ParticleEmitter.maxEmission = _settings.maxEmission * speedPx;
|
||||
#endif
|
||||
}
|
||||
|
||||
void Move()
|
||||
{
|
||||
var mouseRay = _mainCamera.ScreenPointToRay(Input.mousePosition);
|
||||
var mousePos = mouseRay.origin;
|
||||
mousePos.z = 0;
|
||||
|
||||
_lastPosition = _ship.Position;
|
||||
_ship.Position = Vector3.Lerp(_ship.Position, mousePos, Mathf.Min(1.0f, _settings.moveSpeed * Time.deltaTime));
|
||||
|
||||
var moveDelta = _ship.Position - _lastPosition;
|
||||
var moveDistance = moveDelta.magnitude;
|
||||
|
||||
if (moveDistance > 0.01f)
|
||||
{
|
||||
var moveDir = moveDelta / moveDistance;
|
||||
_ship.Rotation = Quaternion.LookRotation(-moveDir);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Start()
|
||||
{
|
||||
_lastPosition = _ship.Position;
|
||||
|
||||
_ship.ParticleEmitter.gameObject.SetActive(true);
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
_ship.ParticleEmitter.gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
public override void OnTriggerEnter(Collider other)
|
||||
{
|
||||
Assert.That(other.GetComponent<Asteroid>() != null);
|
||||
_ship.ChangeState(ShipStates.Dead);
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class Settings
|
||||
{
|
||||
public float moveSpeed;
|
||||
public float rotateSpeed;
|
||||
|
||||
public float speedForMaxEmisssion;
|
||||
public float maxEmission;
|
||||
|
||||
public float oscillationFrequency;
|
||||
public float oscillationAmplitude;
|
||||
}
|
||||
|
||||
public class Factory : PlaceholderFactory<ShipStateMoving>
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6519cef92721b644c9e0b46f2f92430a
|
||||
timeCreated: 1461796083
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Zenject.Asteroids
|
||||
{
|
||||
public class ShipStateWaitingToStart : ShipState
|
||||
{
|
||||
readonly Settings _settings;
|
||||
readonly Ship _ship;
|
||||
|
||||
float _theta;
|
||||
|
||||
public ShipStateWaitingToStart(
|
||||
Ship ship,
|
||||
Settings settings)
|
||||
{
|
||||
_settings = settings;
|
||||
_ship = ship;
|
||||
}
|
||||
|
||||
public override void Start()
|
||||
{
|
||||
_ship.Position = _settings.StartOffset;
|
||||
_ship.Rotation = Quaternion.AngleAxis(90.0f, Vector3.up) * Quaternion.AngleAxis(90.0f, Vector3.right);
|
||||
}
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
_ship.Position = _settings.StartOffset + Vector3.up * _settings.Amplitude * Mathf.Sin(_theta);
|
||||
_theta += Time.deltaTime * _settings.Frequency;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class Settings
|
||||
{
|
||||
public Vector3 StartOffset;
|
||||
public float Amplitude;
|
||||
public float Frequency;
|
||||
}
|
||||
|
||||
public class Factory : PlaceholderFactory<ShipStateWaitingToStart>
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ce3520353cbeb084691b14a57a7bec93
|
||||
timeCreated: 1461796083
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ca259dfabfd45a54eba7128747f28149
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
userData:
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
namespace Zenject.Asteroids
|
||||
{
|
||||
public class ShipCrashedSignal
|
||||
{
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 44a6c869bd4f68c479f02155b98fbeca
|
||||
timeCreated: 1483817409
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Zenject.Asteroids
|
||||
{
|
||||
public static class UnityExtensionMethods
|
||||
{
|
||||
// Since transforms return their position as a property,
|
||||
// you can't set the x/y/z values directly, so you have to
|
||||
// store a temporary Vector3
|
||||
// Or you can use these methods instead
|
||||
public static void SetX(this Transform transform, float x)
|
||||
{
|
||||
var pos = transform.position;
|
||||
pos.x = x;
|
||||
transform.position = pos;
|
||||
}
|
||||
|
||||
public static void SetY(this Transform transform, float y)
|
||||
{
|
||||
var pos = transform.position;
|
||||
pos.y = y;
|
||||
transform.position = pos;
|
||||
}
|
||||
|
||||
public static void SetZ(this Transform transform, float z)
|
||||
{
|
||||
var pos = transform.position;
|
||||
pos.z = z;
|
||||
transform.position = pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1018c66230d7f7b408485a0d8c28147d
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
Reference in New Issue
Block a user