Initial Commit
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
using FlappyBird.Core;
|
||||
using UnityEngine;
|
||||
|
||||
namespace FlappyBird.Pipes
|
||||
{
|
||||
public class PipeScoreTrigger : MonoBehaviour
|
||||
{
|
||||
private IScoreManager _scoreManager;
|
||||
private bool _canScore;
|
||||
|
||||
public void Initialize(IScoreManager scoreManager)
|
||||
{
|
||||
_scoreManager = scoreManager;
|
||||
}
|
||||
|
||||
public void ResetTrigger()
|
||||
{
|
||||
_canScore = true;
|
||||
}
|
||||
|
||||
private void OnTriggerEnter2D(Collider2D other)
|
||||
{
|
||||
if (!_canScore || _scoreManager == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!other.CompareTag("Player"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_canScore = false;
|
||||
_scoreManager.AddScore(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5e53bfbf6adf1dd4b8b2b230469171a9
|
||||
@@ -0,0 +1,41 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace FlappyBird.Pipes
|
||||
{
|
||||
[CreateAssetMenu(fileName = "PipeSettings", menuName = "FlappyBird/Pipe Settings")]
|
||||
public class PipeSettings : ScriptableObject
|
||||
{
|
||||
[Header("Spawn")]
|
||||
[Tooltip("Seconds between pipe spawns.")]
|
||||
public float spawnInterval = 1.5f;
|
||||
|
||||
[Tooltip("World X position where new pipe pairs appear.")]
|
||||
public float spawnX = 10f;
|
||||
|
||||
[Tooltip("World X position where pipe pairs are returned to the pool.")]
|
||||
public float despawnX = -10f;
|
||||
|
||||
[Tooltip("Number of pipe pairs to create up front.")]
|
||||
public int initialPoolSize = 4;
|
||||
|
||||
[Tooltip("Spawn the first pipe immediately when gameplay starts.")]
|
||||
public bool spawnImmediately = false;
|
||||
|
||||
[Header("Movement")]
|
||||
[Tooltip("Horizontal speed for active pipe pairs.")]
|
||||
public float moveSpeed = 2.5f;
|
||||
|
||||
[Header("Gap")]
|
||||
[Tooltip("Distance between the top and bottom pipes.")]
|
||||
public float gapSize = 4f;
|
||||
|
||||
[Tooltip("Minimum vertical center position for the pipe gap.")]
|
||||
public float minGapCenterY = -1.5f;
|
||||
|
||||
[Tooltip("Maximum vertical center position for the pipe gap.")]
|
||||
public float maxGapCenterY = 2.5f;
|
||||
|
||||
[Tooltip("Width of the scoring trigger collider.")]
|
||||
public float scoreTriggerWidth = 1f;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c5ca25bedc7c8714b87c9d32fbc5946b
|
||||
@@ -0,0 +1,140 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using FlappyBird.Core;
|
||||
using UnityEngine;
|
||||
using Zenject;
|
||||
|
||||
namespace FlappyBird.Pipes
|
||||
{
|
||||
public class PipeSpawner : IInitializable, ITickable, IDisposable
|
||||
{
|
||||
private readonly IObjectPoolManager _objectPoolManager;
|
||||
private readonly IGameManager _gameManager;
|
||||
private readonly PipeSettings _settings;
|
||||
private readonly GameObject _pipePrefab;
|
||||
|
||||
private readonly List<PipeView> _activePipes = new List<PipeView>();
|
||||
|
||||
private bool _isRunning;
|
||||
private float _spawnTimer;
|
||||
|
||||
[Inject]
|
||||
public PipeSpawner(
|
||||
IObjectPoolManager objectPoolManager,
|
||||
IGameManager gameManager,
|
||||
PipeSettings settings,
|
||||
[Inject(Id = "PipePrefab")] GameObject pipePrefab)
|
||||
{
|
||||
_objectPoolManager = objectPoolManager;
|
||||
_gameManager = gameManager;
|
||||
_settings = settings;
|
||||
_pipePrefab = pipePrefab;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the spawner by registering the Pipe pool, subscribing to game state changes,
|
||||
/// and setting the initial spawn timer based on settings.
|
||||
/// </summary>
|
||||
public void Initialize()
|
||||
{
|
||||
// Register the pool with the new generic ObjectPoolManager
|
||||
_objectPoolManager.RegisterPool<PipeView>(_pipePrefab, _settings.initialPoolSize);
|
||||
|
||||
_gameManager.OnGameStateChanged += HandleGameStateChanged;
|
||||
ApplyState(_gameManager.CurrentState);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_gameManager.OnGameStateChanged -= HandleGameStateChanged;
|
||||
}
|
||||
|
||||
public void Tick()
|
||||
{
|
||||
if (!_isRunning)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MoveActivePipes();
|
||||
UpdateSpawnTimer();
|
||||
}
|
||||
|
||||
private void HandleGameStateChanged(GameState state)
|
||||
{
|
||||
ApplyState(state);
|
||||
}
|
||||
|
||||
private void ApplyState(GameState state)
|
||||
{
|
||||
if (state == GameState.Playing)
|
||||
{
|
||||
_isRunning = true;
|
||||
_spawnTimer = _settings.spawnImmediately ? 0f : _settings.spawnInterval;
|
||||
return;
|
||||
}
|
||||
|
||||
_isRunning = false;
|
||||
|
||||
if (state == GameState.Menu)
|
||||
{
|
||||
DespawnAllActivePipes();
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateSpawnTimer()
|
||||
{
|
||||
_spawnTimer -= Time.deltaTime;
|
||||
if (_spawnTimer > 0f)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SpawnPipe();
|
||||
_spawnTimer += Mathf.Max(0.01f, _settings.spawnInterval);
|
||||
}
|
||||
|
||||
private void SpawnPipe()
|
||||
{
|
||||
PipeView pipeView = _objectPoolManager.Get<PipeView>();
|
||||
|
||||
// Randomize the vertical position of the gap
|
||||
float gapCenterY = UnityEngine.Random.Range(_settings.minGapCenterY, _settings.maxGapCenterY);
|
||||
|
||||
pipeView.ConfigureGap(gapCenterY, _settings.gapSize, _settings.scoreTriggerWidth);
|
||||
pipeView.SetWorldPosition(new Vector3(_settings.spawnX, 0f, 0f));
|
||||
|
||||
_activePipes.Add(pipeView);
|
||||
}
|
||||
|
||||
private void MoveActivePipes()
|
||||
{
|
||||
float step = _settings.moveSpeed * Time.deltaTime;
|
||||
|
||||
for (int i = _activePipes.Count - 1; i >= 0; i--)
|
||||
{
|
||||
PipeView pipeView = _activePipes[i];
|
||||
pipeView.MoveLeft(step);
|
||||
|
||||
// Despawn if the pipe has moved past the despawn threshold
|
||||
if (pipeView.XPosition > _settings.despawnX)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
_activePipes.RemoveAt(i);
|
||||
_objectPoolManager.Return(pipeView);
|
||||
}
|
||||
}
|
||||
|
||||
private void DespawnAllActivePipes()
|
||||
{
|
||||
for (int i = _activePipes.Count - 1; i >= 0; i--)
|
||||
{
|
||||
_objectPoolManager.Return(_activePipes[i]);
|
||||
}
|
||||
|
||||
_activePipes.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 62dc8cef99ffb954b838a53c73cb8a0c
|
||||
@@ -0,0 +1,110 @@
|
||||
using FlappyBird.Core;
|
||||
using UnityEngine;
|
||||
using Zenject;
|
||||
|
||||
namespace FlappyBird.Pipes
|
||||
{
|
||||
public class PipeView : MonoBehaviour, global::FlappyBird.Core.IPoolable
|
||||
{
|
||||
private const string UpperPipeName = "Pipe_Upper";
|
||||
private const string LowerPipeName = "Pipe_Lower";
|
||||
private const string ScoreTriggerName = "ScoreTrigger";
|
||||
|
||||
private Transform _cachedTransform;
|
||||
private Transform _upperPipe;
|
||||
private Transform _lowerPipe;
|
||||
private Transform _scoreTrigger;
|
||||
private SpriteRenderer _upperRenderer;
|
||||
private SpriteRenderer _lowerRenderer;
|
||||
private BoxCollider2D _scoreTriggerCollider;
|
||||
private PipeScoreTrigger _pipeScoreTrigger;
|
||||
private FlappyBird.Core.IScoreManager _scoreManager;
|
||||
|
||||
public float XPosition => _cachedTransform.position.x;
|
||||
|
||||
[Inject]
|
||||
public void Construct(FlappyBird.Core.IScoreManager scoreManager)
|
||||
{
|
||||
_scoreManager = scoreManager;
|
||||
}
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
_cachedTransform = transform;
|
||||
_upperPipe = _cachedTransform.Find(UpperPipeName);
|
||||
_lowerPipe = _cachedTransform.Find(LowerPipeName);
|
||||
_scoreTrigger = _cachedTransform.Find(ScoreTriggerName);
|
||||
|
||||
if (_upperPipe != null)
|
||||
{
|
||||
_upperRenderer = _upperPipe.GetComponent<SpriteRenderer>();
|
||||
}
|
||||
|
||||
if (_lowerPipe != null)
|
||||
{
|
||||
_lowerRenderer = _lowerPipe.GetComponent<SpriteRenderer>();
|
||||
}
|
||||
|
||||
if (_scoreTrigger != null)
|
||||
{
|
||||
_scoreTriggerCollider = _scoreTrigger.GetComponent<BoxCollider2D>();
|
||||
_pipeScoreTrigger = _scoreTrigger.GetComponent<PipeScoreTrigger>();
|
||||
|
||||
if (_pipeScoreTrigger == null)
|
||||
{
|
||||
_pipeScoreTrigger = _scoreTrigger.gameObject.AddComponent<PipeScoreTrigger>();
|
||||
}
|
||||
|
||||
_pipeScoreTrigger.Initialize(_scoreManager);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetWorldPosition(Vector3 position)
|
||||
{
|
||||
_cachedTransform.position = position;
|
||||
}
|
||||
|
||||
public void MoveLeft(float distance)
|
||||
{
|
||||
_cachedTransform.position += Vector3.left * distance;
|
||||
}
|
||||
|
||||
public void ConfigureGap(float gapCenterY, float gapSize, float scoreTriggerWidth)
|
||||
{
|
||||
if (_upperPipe == null || _lowerPipe == null || _upperRenderer == null || _lowerRenderer == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
float upperHalfHeight = _upperRenderer.size.y * 0.5f;
|
||||
float lowerHalfHeight = _lowerRenderer.size.y * 0.5f;
|
||||
float gapHalf = gapSize * 0.5f;
|
||||
|
||||
_upperPipe.localPosition = new Vector3(0f, gapCenterY + gapHalf + upperHalfHeight, 0f);
|
||||
_lowerPipe.localPosition = new Vector3(0f, gapCenterY - gapHalf - lowerHalfHeight, 0f);
|
||||
|
||||
if (_scoreTrigger != null)
|
||||
{
|
||||
_scoreTrigger.localPosition = new Vector3(0f, gapCenterY, 0f);
|
||||
}
|
||||
|
||||
if (_scoreTriggerCollider != null)
|
||||
{
|
||||
_scoreTriggerCollider.size = new Vector2(scoreTriggerWidth, gapSize);
|
||||
_scoreTriggerCollider.offset = Vector2.zero;
|
||||
}
|
||||
}
|
||||
|
||||
public void OnSpawned()
|
||||
{
|
||||
if (_pipeScoreTrigger != null)
|
||||
{
|
||||
_pipeScoreTrigger.ResetTrigger();
|
||||
}
|
||||
}
|
||||
|
||||
public void OnDespawned()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 12677c2e66077cc4f89582de3982d3e7
|
||||
Reference in New Issue
Block a user