- Home /
Proper way to strew lots of dead in Napoleonic RTS?
Hi, I'm currently working on a napoleonic RTS game, and am trying to find a good way of painting groups of "dead body" textures on the field that persist for the entire length of the battle.
Just to be clear, my graphics involve impressionistic painted planes that represent individual battalions, so I'm not talking about Total War style level of detail.
From what I've read in other threads, there seems to be two ways of doing this:
Instantiating a gameobject with a plane right above the ground that has a "group of dead bodies" texture painted on. This seems like the simplest way to do it, but I'm afraid of the performance implications of having possibly thousands of gameobjects lying around for the entirety of a game.
The second would be to actually paint the landscape texture directly using the getpixel/setpixel functions. When I implemented this, however, the performance hit was very noticeable (a stutter every time a battalion received damage), even after segmenting the landscape into smaller tiles, though the upside was that there weren't any piles of gameobjects accumulating.
Do you all have any suggestions of how else I should go about doing this? Should I not worry so much about having thousands of gameobjects lying around, so long as I don't do anything foolish like routinely use the Gameobject.Find function?
Answer by Alehr · Jan 18, 2012 at 10:44 PM
In case this helps anybody in the future who is struggling with a similar problem, I think I figured it out. The solution was basically to keep an independent set of generic lists that could be sized dynamically, which are then swapped with the mesh's vertices, uv and triangles arrays as a arrays using the ".ToArray()" function. This completely solved the performance problems.
I could see this being useful for anybody who needed to dynamically draw lots of simple static meshes for whatever reason without wanting to deal with instantiating gameObjects (drawing grass procedurally, for example).
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
public class BodyPilerScript : MonoBehaviour
{
Mesh mesh;
//Create independent lists for mesh attributes (vertices, uvs and triangles)
List<Vector3> vertices;
List<Vector2> uvs;
List<int> triangles;
// Use this for initialization
void Start ()
{
mesh = gameObject.GetComponent<MeshFilter>().mesh;
//Populate the lists with the starting "template" mesh attributes
vertices = mesh.vertices.ToList();
uvs = mesh.uv.ToList();
triangles = mesh.triangles.ToList();
}
// Update is called once per frame
void Update ()
{
}
public void AddBodyPile(Vector3 pileLocation)
{
mesh = gameObject.GetComponent<MeshFilter>().mesh;
//Determine the positions of new bodyPile plane vertices
float offset = .5f;
Vector3 upperLeft = new Vector3(pileLocation.x + offset, pileLocation.y,pileLocation.z - offset);
Vector3 upperRight = new Vector3(pileLocation.x + offset, pileLocation.y,pileLocation.z + offset);
Vector3 lowerRight = new Vector3(pileLocation.x - offset, pileLocation.y,pileLocation.z + offset);
Vector3 lowerLeft = new Vector3(pileLocation.x - offset, pileLocation.y,pileLocation.z - offset);
//And add them to the independent vertex list
vertices.Add(upperLeft);
vertices.Add(upperRight);
vertices.Add(lowerRight);
vertices.Add(lowerLeft);
//Create corresponding uv coordinates (these particular ones just define the four corners of a plane)
//and add them to the independent uvs list
uvs.Add(new Vector2(0, 0));
uvs.Add(new Vector2(1f, 0));
uvs.Add(new Vector2(1f, 1f));
uvs.Add(new Vector2(0, 1f));
//create new triangles based on new vertices.
//and add them to the independent triangles list
triangles.Add(mesh.vertexCount);
triangles.Add(mesh.vertexCount + 1);
triangles.Add(mesh.vertexCount + 2);
triangles.Add(mesh.vertexCount + 2);
triangles.Add(mesh.vertexCount + 3);
triangles.Add(mesh.vertexCount);
mesh.Clear();
//assign the modified independent lists to the mesh arrays as arrays
mesh.vertices = vertices.ToArray();
mesh.uv = uvs.ToArray();
mesh.triangles = triangles.ToArray();
mesh.RecalculateNormals();
}
}
Thanks for the solution!
Would this be useful to place decals on the terrain? Are you using planes to represent battalions and moving those planes on a 3D terrain? How do you manage to deform the plane to adjust it to the terrain heights?
I'd like to ask you some more questions about your game, napoleonics is one of my hobbies. Could I contact you in any way?
Answer by Alehr · Jan 17, 2012 at 06:51 PM
I've made a working function now that manually adds new geometry to an existing mesh, so that now all of my body pile planes are combined into one mesh that adds a new body pile plane (four vertices, two triangles) every time a battalion receives damage. But there is still a problem:
public void AddBodyPile(Vector3 pileLocation)
{
Mesh mesh = gameObject.GetComponent<MeshFilter>().mesh;
//Create new arrays that will eventually replace current arrays of the mesh
//Add new indices for additional plane
Vector3[] vertices = new Vector3[mesh.vertexCount + 4];
Vector2[] uvs = new Vector2[vertices.Length];
int[] triangles = new int[mesh.triangles.Length + 6];
//Populate new vertex and triangle arrays with existing data
for (int i = 0; i < mesh.vertexCount; i++)
vertices[i] = mesh.vertices[i];
for (int i = 0; i < mesh.triangles.Length; i++)
triangles[i] = mesh.triangles[i];
//Determine the positions of new bodyPile plane vertices
float offset = .5f;
Vector3 upperLeft = new Vector3(pileLocation.x + offset, pileLocation.y,pileLocation.z - offset);
Vector3 upperRight = new Vector3(pileLocation.x + offset, pileLocation.y,pileLocation.z + offset);
Vector3 lowerRight = new Vector3(pileLocation.x - offset, pileLocation.y,pileLocation.z + offset);
Vector3 lowerLeft = new Vector3(pileLocation.x - offset, pileLocation.y,pileLocation.z - offset);
//And add them to the new vertex array
vertices[mesh.vertexCount] = upperLeft;
vertices[mesh.vertexCount + 1] = upperRight;
vertices[mesh.vertexCount + 2] = lowerRight;
vertices[mesh.vertexCount + 3] = lowerLeft;
//Populate new uv array
for (int i = 0; i < uvs.Length; i++)
uvs[i] = new Vector2(vertices[i].x, vertices[i].z);
//Populate new triangles based on new vertices.
triangles[mesh.triangles.Length] = mesh.vertexCount;
triangles[mesh.triangles.Length + 1] = mesh.vertexCount + 1;
triangles[mesh.triangles.Length + 2] = mesh.vertexCount + 2;
triangles[mesh.triangles.Length + 3] = mesh.vertexCount + 2;
triangles[mesh.triangles.Length + 4] = mesh.vertexCount + 3;
triangles[mesh.triangles.Length + 5] = mesh.vertexCount;
mesh.Clear();
//Swap the old mesh with the new one (which now has one more body pile plane)
mesh.vertices = vertices;
mesh.uv = uvs;
mesh.triangles = triangles;
mesh.RecalculateNormals();
}
While this gets the job done, and ultimately has very little effect on performance in the long run when no more bodies are being piled, the calculation to add each new body pile plane becomes extremely slow when the vertex count only reaches a couple hundred. I assume this is because I have it iterating through large arrays thrice every time the function is called.
Is there a more efficient way to do this? Can I add to built-in arrays without having to constantly re-populate it through iteration? Because ultimately all I want to do is (frequently) add four vertices to an existing mesh.
I would love to hear some input from somebody who's worked with procedural grass generation on terrain, as the concept seems very similar.
Any help is appreciated!
Answer by f.cherchi · Jan 30, 2012 at 10:00 PM
You could use a particle system. In the Particle Emitter you disable Emit and set Max Energy to Infinite, in the Particle Renderer you set Horizontal Billboard and maybe a Particle/VertexLit-Blended material. Finally, through scripting, you emit a particle where a battalion dies: particleEmitter.Emit(...);
Your answer
Follow this Question
Related Questions
SetPixel on a sprite texture without changing it globally 1 Answer
instantiate photon hitdecal 1 Answer
Use SetPixels, but dont set unvisible Pixels 1 Answer
decal moving with object 1 Answer
Object Pooling, have some question marks 0 Answers