You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

158 lines
3.6 KiB

// HACK:
// This will work out of the box, but it's intended to be an example of how to approach
// procedural decoration like this.
// A better approach would be to operate on the geometry itself.
namespace Mapbox.Unity.MeshGeneration.Modifiers
{
using Mapbox.Unity.MeshGeneration.Data;
using Mapbox.Unity.MeshGeneration.Components;
using UnityEngine;
using System.Collections.Generic;
using System;
[CreateAssetMenu(menuName = "Mapbox/Modifiers/Spawn Inside Modifier")]
public class SpawnInsideModifier : GameObjectModifier
{
[SerializeField]
int _spawnRateInSquareMeters;
[SerializeField]
int _maxSpawn = 1000;
[SerializeField]
GameObject[] _prefabs;
[SerializeField]
LayerMask _layerMask;
[SerializeField]
bool _scaleDownWithWorld;
[SerializeField]
bool _randomizeScale;
[SerializeField]
bool _randomizeRotation;
int _spawnedCount;
private Dictionary<GameObject, List<GameObject>> _objects;
private Queue<GameObject> _pool;
public override void Initialize()
{
if (_objects == null || _pool == null)
{
_objects = new Dictionary<GameObject, List<GameObject>>();
_pool = new Queue<GameObject>();
}
}
public override void Run(VectorEntity ve, UnityTile tile)
{
_spawnedCount = 0;
var bounds = ve.Mesh.bounds;
var center = ve.Transform.position + bounds.center;
center.y = 0;
var area = (int)(bounds.size.x * bounds.size.z);
int spawnCount = Mathf.Min(area / _spawnRateInSquareMeters, _maxSpawn);
while (_spawnedCount < spawnCount)
{
var x = UnityEngine.Random.Range(-bounds.extents.x, bounds.extents.x);
var z = UnityEngine.Random.Range(-bounds.extents.z, bounds.extents.z);
var ray = new Ray(center + new Vector3(x, 100, z), Vector3.down * 2000);
RaycastHit hit;
if (Physics.Raycast(ray, out hit, 150, _layerMask))
{
var index = UnityEngine.Random.Range(0, _prefabs.Length);
var transform = GetObject(index, ve.GameObject).transform;
transform.position = hit.point;
if (_randomizeRotation)
{
transform.localEulerAngles = new Vector3(0, UnityEngine.Random.Range(-180f, 180f), 0);
}
if (!_scaleDownWithWorld)
{
transform.localScale = Vector3.one / tile.TileScale;
}
if (_randomizeScale)
{
var scale = transform.localScale;
var y = UnityEngine.Random.Range(scale.y * .7f, scale.y * 1.3f);
scale.y = y;
transform.localScale = scale;
}
}
_spawnedCount++;
}
}
public override void OnPoolItem(VectorEntity vectorEntity)
{
if(_objects.ContainsKey(vectorEntity.GameObject))
{
foreach (var item in _objects[vectorEntity.GameObject])
{
item.SetActive(false);
_pool.Enqueue(item);
}
_objects[vectorEntity.GameObject].Clear();
_objects.Remove(vectorEntity.GameObject);
}
}
public override void Clear()
{
foreach (var go in _pool)
{
go.Destroy();
}
_pool.Clear();
foreach (var tileObject in _objects)
{
foreach (var go in tileObject.Value)
{
if (Application.isEditor && !Application.isPlaying)
{
DestroyImmediate(go);
}
else
{
Destroy(go);
}
}
}
_objects.Clear();
}
private GameObject GetObject(int index, GameObject go)
{
GameObject ob;
if (_pool.Count > 0)
{
ob = _pool.Dequeue();
ob.SetActive(true);
ob.transform.SetParent(go.transform);
}
else
{
ob = ((GameObject)Instantiate(_prefabs[index], go.transform, false));
}
if (_objects.ContainsKey(go))
{
_objects[go].Add(ob);
}
else
{
_objects.Add(go, new List<GameObject>() { ob });
}
return ob;
}
}
}