Initial Commit
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace FlappyBird.Ground
|
||||
{
|
||||
[CreateAssetMenu(fileName = "GroundSettings", menuName = "FlappyBird/Ground Settings")]
|
||||
public class GroundSettings : ScriptableObject
|
||||
{
|
||||
[Tooltip("World X position where the first ground segment starts.")]
|
||||
public float spawnX = -5f;
|
||||
|
||||
[Tooltip("World X position where ground segments are returned to the pool.")]
|
||||
public float despawnX = -15f;
|
||||
|
||||
[Tooltip("The exact width of the ground sprite/collider to ensure seamless looping.")]
|
||||
public float groundWidth = 10f;
|
||||
|
||||
[Tooltip("World Y position where the ground is placed.")]
|
||||
public float yPosition = -4f;
|
||||
|
||||
[Tooltip("Number of ground segments to create up front.")]
|
||||
public int initialPoolSize = 3;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2646352a67506b34181e2563502f05fb
|
||||
@@ -0,0 +1,127 @@
|
||||
using FlappyBird.Core;
|
||||
using FlappyBird.Ground;
|
||||
using FlappyBird.Pipes;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using Zenject;
|
||||
|
||||
namespace FlappyBird.Environment
|
||||
{
|
||||
public class GroundSpawner : IInitializable, ITickable, IDisposable
|
||||
{
|
||||
private readonly IObjectPoolManager _objectPoolManager;
|
||||
private readonly IGameManager _gameManager;
|
||||
private readonly PipeSettings _pipeSettings;
|
||||
private readonly GroundSettings _groundSettings;
|
||||
private readonly GameObject _groundPrefab;
|
||||
|
||||
private readonly List<GroundView> _activeGrounds = new List<GroundView>();
|
||||
|
||||
private bool _isRunning;
|
||||
|
||||
[Inject]
|
||||
public GroundSpawner(
|
||||
IObjectPoolManager objectPoolManager,
|
||||
IGameManager gameManager,
|
||||
PipeSettings pipeSettings,
|
||||
GroundSettings groundSettings,
|
||||
[Inject(Id = "GroundPrefab")] GameObject groundPrefab)
|
||||
{
|
||||
_objectPoolManager = objectPoolManager;
|
||||
_gameManager = gameManager;
|
||||
_pipeSettings = pipeSettings;
|
||||
_groundSettings = groundSettings;
|
||||
_groundPrefab = groundPrefab;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the ground system by registering the object pool and
|
||||
/// spawning initial segments. They will remain stationary until the game starts.
|
||||
/// </summary>
|
||||
public void Initialize()
|
||||
{
|
||||
_objectPoolManager.RegisterPool<GroundView>(_groundPrefab, _groundSettings.initialPoolSize);
|
||||
|
||||
_gameManager.OnGameStateChanged += HandleGameStateChanged;
|
||||
|
||||
// Pre-spawn segments so the floor is visible in the Menu state
|
||||
float currentX = _groundSettings.spawnX;
|
||||
for (int i = 0; i < Mathf.Max(1, _groundSettings.initialPoolSize); i++)
|
||||
{
|
||||
SpawnGround(currentX);
|
||||
currentX += _groundSettings.groundWidth;
|
||||
}
|
||||
|
||||
// Sets initial movement state based on current GameManager state (Menu = stopped)
|
||||
ApplyState(_gameManager.CurrentState);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_gameManager.OnGameStateChanged -= HandleGameStateChanged;
|
||||
}
|
||||
|
||||
public void Tick()
|
||||
{
|
||||
if (!_isRunning)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MoveActiveGrounds();
|
||||
}
|
||||
|
||||
private void HandleGameStateChanged(GameState state)
|
||||
{
|
||||
ApplyState(state);
|
||||
}
|
||||
|
||||
private void ApplyState(GameState state)
|
||||
{
|
||||
// Ground only moves during active gameplay
|
||||
_isRunning = state == GameState.Playing;
|
||||
}
|
||||
|
||||
private void MoveActiveGrounds()
|
||||
{
|
||||
float step = _pipeSettings.moveSpeed * Time.deltaTime;
|
||||
float rightmostX = GetRightmostGroundX();
|
||||
|
||||
for (int i = _activeGrounds.Count - 1; i >= 0; i--)
|
||||
{
|
||||
GroundView groundView = _activeGrounds[i];
|
||||
groundView.MoveLeft(step);
|
||||
|
||||
if (groundView.XPosition > _groundSettings.despawnX)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
_activeGrounds.RemoveAt(i);
|
||||
_objectPoolManager.Return(groundView);
|
||||
|
||||
// Re-spawn at the end of the chain
|
||||
SpawnGround(rightmostX + _groundSettings.groundWidth - step);
|
||||
rightmostX += _groundSettings.groundWidth;
|
||||
}
|
||||
}
|
||||
|
||||
private float GetRightmostGroundX()
|
||||
{
|
||||
float maxX = float.MinValue;
|
||||
foreach (var ground in _activeGrounds)
|
||||
{
|
||||
if (ground.XPosition > maxX) maxX = ground.XPosition;
|
||||
}
|
||||
return maxX == float.MinValue ? _groundSettings.spawnX : maxX;
|
||||
}
|
||||
|
||||
private void SpawnGround(float xPosition)
|
||||
{
|
||||
GroundView groundView = _objectPoolManager.Get<GroundView>();
|
||||
groundView.SetPosition(new Vector3(xPosition, _groundSettings.yPosition, 0f));
|
||||
_activeGrounds.Add(groundView);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9b7f0d695b68afb4bbc3556af67e7c7b
|
||||
@@ -0,0 +1,37 @@
|
||||
using FlappyBird.Core;
|
||||
using FlappyBird.Pipes;
|
||||
using UnityEngine;
|
||||
using Zenject;
|
||||
|
||||
namespace FlappyBird.Ground
|
||||
{
|
||||
public class GroundView : MonoBehaviour, Core.IPoolable
|
||||
{
|
||||
private Transform _cachedTransform;
|
||||
|
||||
public float XPosition => _cachedTransform.position.x;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
_cachedTransform = transform;
|
||||
}
|
||||
|
||||
public void SetPosition(Vector3 position)
|
||||
{
|
||||
_cachedTransform.position = position;
|
||||
}
|
||||
|
||||
public void MoveLeft(float distance)
|
||||
{
|
||||
_cachedTransform.position += Vector3.left * distance;
|
||||
}
|
||||
|
||||
public void OnSpawned()
|
||||
{
|
||||
}
|
||||
|
||||
public void OnDespawned()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0d496ba852926f14cb1a0cbbda11884f
|
||||
Reference in New Issue
Block a user