- Home /
tree creator tree chopping question
So I am coming into Unity from Unreal 4. In unreal i had a tree chopping system that I was curious of how to do here. Unreal had a terrain editor where I could put my tree model in and it would paint it to the terrain as a static mesh. The blueprint i made was when I did a line trace (raycast for unity) , i could get close to the tree, left click and it would remove the static tree mesh and simulateansly add the physics enabled tree in its place and fall over. I assumed that the static mesh would be better in large volumes than hundreds of physics enabled meshes as far as performance. From what I can see in unity, the terrain tool also paints via a static mesh type of model with collision. Is this better on performance than putting hundreds of rigidbody tree meshes in by hand? If so, how can I script it so that the tree model I have painted via the terrain tools, can disappear on left click and be replaced at the same time with a rigid body tree?
Answer by dan_wipf · Feb 18, 2019 at 09:32 AM
Basically you need to Setup Colliders for a Raycast => if I'm right UnityTerrainCollider will merge all TreeColliders in to one(TerrainCollider), so you won't be able to get quite a specific Information for your Ray. So you have to setup Colliders for each Tree.
fyi => UnityTerrain stores Instances of all the Tree's in an Array TreeInstances[] which hold's some Information (PrototypeIndex(Prefab Information)) Position, Rotation) but you have to do some work to Use TreeInstance / PrototypeIndex.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using System.Linq;
public class choptree : MonoBehaviour
{
Terrain ter;
TerrainData ted;
List<GameObject> Colliders;
void OnEnable(){
ter = Terrain.activeTerrain;
ted = ter.terrainData;
Colliders = new List<GameObject>();
int TerrainMultiplier = ted.heightmapWidth * ted.heightmapHeight;
// Checkthrough all Instances
for (int i = 0; i<ted.treeInstances.Length;i++){
GameObject tree = ted.treePrototypes[ted.treeInstances[i].prototypeIndex].prefab;
CapsuleCollider tempCol;
//Get Collider from Original prefab (right now just Capsule Collider)
if(tree.GetComponent<CapsuleCollider>() != null){
tempCol = tree.GetComponent<CapsuleCollider>();
}if(tree.GetComponentInChildren<CapsuleCollider>() != null){
tempCol = tree.GetComponentInChildren<CapsuleCollider>();
}else{
tempCol = new CapsuleCollider();
}
//Spawn Collider GameObject
GameObject tempGo = new GameObject();
tempGo.name = i.ToString();
//Get Position of WorldPos
Vector3 worldPos = ted.treeInstances[i].position - ter.transform.position;
worldPos.x /= ted.size.x;
worldPos.y /= ted.size.y;
worldPos.z /= ted.size.z;
worldPos *= TerrainMultiplier;
tempGo.transform.position = worldPos;
//Add a Collider to the right Position.
tempGo.AddComponent<CapsuleCollider>();
tempGo.GetComponent<CapsuleCollider>().height = tempCol.height;
tempGo.GetComponent<CapsuleCollider>().radius = tempCol.radius;
tempGo.GetComponent<CapsuleCollider>().center = tempCol.center;
//CleanUp Hirarchy
tempGo.transform.parent = ter.transform;
tempGo.hideFlags = HideFlags.HideInHierarchy;
Colliders.Add(tempGo);
}
}
void Update()
{
RaycastHit hit;
if(Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition),out hit)){
//Check for Input and if hit is a valid target in CollidersList
if(Input.GetMouseButtonUp(0) && Colliders.Any(x => x.name == hit.transform.name)){
int i = Int32.Parse(hit.transform.name);
Debug.Log(i);
var instances = ted.treeInstances.ToList();
//Get treeIndex for Spawning sameTree.
var index = ted.treeInstances[i].prototypeIndex;
GameObject FallenTree = Instantiate(ted.treePrototypes[index].prefab,Colliders[i].transform.position,Quaternion.identity,ter.transform);
//Remove TreeInstance from Terrain and CollidersList
instances.RemoveAt(i);
Colliders.RemoveAt(i);
//update treeInstance Array from Terrain
ted.treeInstances = instances.ToArray();
}
}
}
}