Files
badeend-go/Assets/CollectableDuckManager.cs

235 lines
7.2 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using DefaultNamespace;
using Mapbox.CheapRulerCs;
using Mapbox.Unity.Map;
using Mapbox.Utils;
using UnityEngine;
using Random = UnityEngine.Random;
public class CollectableDuckManager : MonoBehaviour
{
private class SimpleDuckData
{
public Vector2d location;
public DateTime spawnTime;
public DateTime despawnTime;
}
public List<CollectableDuckData> collectableDucks;
private readonly HashSet<CollectableDuckData> _collectedDucks = new HashSet<CollectableDuckData>();
private readonly Dictionary<CollectableDuckData, CollectableDuck> _spawnedDucks = new Dictionary<CollectableDuckData, CollectableDuck>();
private List<SimpleDuckData> existingSimpleDucks = new List<SimpleDuckData>();
private readonly Dictionary<SimpleDuckData, CollectableDuck> _spawnedSimpleDucks = new Dictionary<SimpleDuckData,CollectableDuck>();
public AbstractMap map;
public Transform player;
public Transform collectableDuckParent;
public float spawnStandardDuckTimeout = 1f;
public float spawnStandardDuckProbability = 0.1f;
public float standardDuckTimeout = 15 * 60;
public GameObject simpleDuckPrefab;
private float timeSinceStandardDuckSpawn = 0f;
public event EventHandler<CollectableDuckData> DuckClicked;
/// <summary>
/// Spawn distance in meters (i.e. how close should the player be to a duck before it spawns on the map
/// </summary>
public float spawnDistance = 50;
public CollectableDuck duckSpawnPrefab;
private static CollectableDuckManager _instance;
public static CollectableDuckManager Instance
{
get { return _instance; }
private set { _instance = value; }
}
public CollectableDuckManager()
{
Instance = this;
}
private void Awake()
{
CheckCollectableDuckIds();
_collectedDucks.Clear();
foreach (var duck in collectableDucks.Where(duck => PlayerPrefs.GetInt("duck." + duck.Id) > 0))
{
_collectedDucks.Add(duck);
}
}
private void CheckCollectableDuckIds()
{
var duckIds = new HashSet<string>();
foreach (var duck in collectableDucks)
{
if (duckIds.Contains(duck.Id))
{
Debug.LogError("Duplicate duck ID: '" + duck.Id + "' for duck '" + duck.name + "'");
}
duckIds.Add(duck.Id);
}
}
private void Update()
{
var ruler = new CheapRuler(map.CenterLatitudeLongitude.x, CheapRulerUnits.Meters);
var playerPosition = map.WorldToGeoPosition(player.position).ToArray();
for (int i = 0; i < collectableDucks.Count; i++)
{
var duck = collectableDucks[i];
var duckCoord = duck.LatitudeLongitude;
var dist = ruler.Distance(duckCoord.ToArray(), playerPosition);
// Debug.Log("Distance to " + duck.name + ": " + dist);
if (dist < spawnDistance && !_collectedDucks.Contains(duck))
{
SpawnDuck(duck);
}
else
{
RemoveDuck(duck);
}
}
timeSinceStandardDuckSpawn += Time.deltaTime;
if (timeSinceStandardDuckSpawn > spawnStandardDuckTimeout)
{
timeSinceStandardDuckSpawn = 0;
if (Random.value < spawnStandardDuckProbability)
{
// Time to spawn a duck somewhere close to the player
double[] max = ruler.Destination(playerPosition, 100, 45);
double[] min = ruler.Destination(playerPosition, 100, 225);
var latDiff = max[0] - min[0];
var lonDiff = max[1] - min[1];
var duckCoord = new Vector2d(min[0] + (latDiff * Random.value), min[1] + (lonDiff * Random.value));
existingSimpleDucks.Add(new SimpleDuckData()
{
location = duckCoord,
despawnTime = DateTime.Now.AddSeconds(standardDuckTimeout),
spawnTime = DateTime.Now
});
}
}
for (int i = 0; i < existingSimpleDucks.Count; i++)
{
var duck = existingSimpleDucks[i];
if (duck.despawnTime < DateTime.Now)
{
existingSimpleDucks.RemoveAt(i);
i--;
HideSimpleDuck(duck);
}
else
{
var duckCoord = duck.location;
var dist = ruler.Distance(duckCoord.ToArray(), playerPosition);
// Debug.Log("Distance to " + duck.name + ": " + dist);
if (dist < spawnDistance)
{
SpawnSimpleDuck(duck);
}
else
{
HideSimpleDuck(duck);
}
}
}
}
private void SpawnDuck(CollectableDuckData duck)
{
if (!_spawnedDucks.ContainsKey(duck))
{
// Spawn the duck
var duckSpawn = Instantiate(duckSpawnPrefab, map.GeoToWorldPosition(duck.LatitudeLongitude),
Quaternion.identity, collectableDuckParent);
duckSpawn.CollectableDuckData = duck;
var duckModel = Instantiate(duck.ModelPrefab, duckSpawn.transform);
duckModel.transform.localPosition = Vector3.zero;
_spawnedDucks[duck] = duckSpawn;
}
else
{
if (!_spawnedDucks[duck].gameObject.activeSelf)
{
_spawnedDucks[duck].gameObject.SetActive(true);
}
}
}
private void SpawnSimpleDuck(SimpleDuckData duck)
{
if (!_spawnedSimpleDucks.ContainsKey(duck))
{
// Spawn the duck
var duckSpawn = Instantiate(duckSpawnPrefab, map.GeoToWorldPosition(duck.location),
Quaternion.identity, collectableDuckParent);
var duckModel = Instantiate(simpleDuckPrefab, duckSpawn.transform);
duckModel.transform.localPosition = Vector3.zero;
_spawnedSimpleDucks[duck] = duckSpawn;
}
else
{
if (!_spawnedSimpleDucks[duck].gameObject.activeSelf)
{
_spawnedSimpleDucks[duck].gameObject.SetActive(true);
}
}
}
private void RemoveDuck(CollectableDuckData duck)
{
if (_spawnedDucks.ContainsKey(duck))
{
if (_spawnedDucks[duck].gameObject.activeSelf)
{
_spawnedDucks[duck].gameObject.SetActive(false);
}
}
}
private void HideSimpleDuck(SimpleDuckData duck)
{
if (_spawnedSimpleDucks.ContainsKey(duck))
{
if (_spawnedSimpleDucks[duck].gameObject.activeSelf)
{
_spawnedSimpleDucks[duck].gameObject.SetActive(false);
}
}
}
public void OnDuckClicked(CollectableDuckData duck)
{
if (DuckClicked != null)
{
DuckClicked.Invoke(this, duck);
}
}
public void OnDuckCollected(CollectableDuckData duck)
{
_collectedDucks.Add(duck);
PlayerPrefs.SetInt("duck." + duck.Id, 1);
RemoveDuck(duck);
}
}