I'm looking to create a piece of terrain in unity using only a script (c# preferably) to do this rather than the menu options on the editor. So far I only have this code below, but I don't know what to do next to get it to appear on the scene, can anyone help?
Thank you
using UnityEngine;
using System.Collections;
public class terraintest : MonoBehaviour {
// Use this for initialization
void Start () {
GameObject terrain = new GameObject();
TerrainData _terraindata = new TerrainData();
terrain = Terrain.CreateTerrainGameObject(_terraindata);
}
// Update is called once per frame
void Update () {
}
}
Simply adding :
Vector3 position = ... //the ingame position you want your terrain at
GameObject ingameTerrainGameObject = Instantiate(terrain, position, Quaternion.identity);
should make the terrain appear ingame. The Instantiate method returns a reference to the gameobject spawned ingame, so if you later want to access it, you can use that reference.
Related
I am trying to make an [ExecuteInEditMode] script spawn game objects (linked to the same prefab) at specific positions right in the Editor so that I can quickly create different hexagon tile maps by just triggering booleans in the inspector. However, the Resources.Load() method cannot not find the prefab even though the path is correct and so I get the following error:
NullReferenceException: Object reference not set to an instance of an object.
Here is the code:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
[ExecuteInEditMode]
public class PositionChecker : MonoBehaviour
{
[SerializeField] float tileGap = 1.5f;
[SerializeField] GameObject tilePrefab; // alternatively tried dragging the prefab in the field in the inspector - it worked
[SerializeField] bool tileUpLeft;
GameObject tilesParent;
private void Awake()
{
tilesParent = GameObject.Find("All Tiles");
tilePrefab = Resources.Load("Assets/Prefabs/Tile.prefab") as GameObject;
}
// Update is called once per frame
void Update()
{
CheckForCreateTile();
}
private void CheckForCreateTile()
{
if (tileUpLeft)
{
tileUpLeft = false;
InstantiateTilePrefab(new Vector3(transform.position.x - 0.6f * tileGap, transform.position.y, transform.position.z - tileGap));
}
}
private void InstantiateTilePrefab(Vector3 vector3)
{
GameObject newTile = PrefabUtility.InstantiatePrefab(tilePrefab, tilesParent.transform) as GameObject;
Debug.Log(tilePrefab); // null
Debug.Log(tilesParent); // ok
Debug.Log(newTile); // Null
newTile.transform.position = vector3;
}
}
If I drag the prefab onto the serialized field of each created tile manually in the inspector instead of trying to load it, everything works fine.
The asset has to be in a "Resources" folder. So to solve your problem you can put "Tile.prefab" into the folder "Assets/Resources" and use the relative path: Resources.Load("Tile.prefab");
https://docs.unity3d.com/ScriptReference/Resources.Load.html
The file-path string automatically starts with "Resources/". So you shouldn't type that in. Also I don't think unity likes the file type in the string so don't type that in either. This works for me:
GameObject tilePrefab;
tilePrefab = Resources.Load<GameObject>("Prefabs/Tile");
GameObject tile = Instantiate(tilePrefab, Vector3.zero, Quaternion.identity);
I am trying to make a zombie wave game and current have a Prefab for my enemies. If I have the prefab be in the scene when I hit run, they are attached to the NavMesh and track the player perfectly. I want to achieve this but with the enemy being spawned from an empty GameObject so I can get the waves spawning in. I have achieved them Spawning but they have the error,
"SetDestination" can only be called on an active agent that has been placed on a NavMesh.
UnityEngine.AI.NavMeshAgent:SetDestination(Vector3)
EnemyAI:Update() (at Assets/Scripts/EnemyAI.cs:25)
Here is my EnemyAI Script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
public class EnemyAI : MonoBehaviour
{
public float lookRadius = 10f;
Transform target;
NavMeshAgent agent;
public GameObject Player;
void Start()
{
agent = GetComponent<NavMeshAgent>();
}
// Update is called once per frame
void Update()
{
float distance = Vector3.Distance(Player.transform.position, transform.position);
if (distance <= lookRadius)
{
agent.SetDestination(Player.transform.position);
}
}
}
And my spawning script, which is attached to an empty game object,
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Spawning : MonoBehaviour
{
public GameObject prefab;
public int CountofCubes;
private IEnumerator coroutine;
public float spawnRate;
IEnumerator Start()
{
while (true)
{
for (int i = 0; i < CountofCubes; i++)
{
Instantiate(prefab, new Vector3(Random.Range(-25.0f, 25.0f), 0.5f, Random.Range(-25.0f, 25.0f)), Quaternion.identity);
}
yield return new WaitForSeconds(spawnRate);
}
}
}
Any help would be great thanks!
I had the same issue and I don't have an explanation but only a workaround:
In the Start fucntion, I added:
navAgent = GetComponent<NavMeshAgent>();
navAgent.enabled = false;
// Invoke is used as a workaround for enabling NavMeshAgent on NavMeshSurface
Invoke("EnableNavMeshAgent", 0.025f);
And the EnableNavMeshAgent function is just :
private void EnableNavMeshAgent ()
{
navAgent.enabled = true;
}
If I set the invoke delay to a value less than 0.025 second the error keep going but for 0.025 I only have it twice and the behaviour is the one I wanted after that.
Some reasons this might happen:
The agent is not on level with any navmesh i.e. can be too far above or below. You want it to be "close to the NavMesh surface". Use raycasting on the floor to position the agent or add a rigidbody and drop it from above the floor. After you do this you might need to disable and enable the agent.
Moving the transform yourself rather than using Wrap function. There's property where you can check if the simulated and actual position are in sync.
Corrupted navmesh so you might need to re-bake it.
It is essentially trying to tell you your agent is not on the mesh so it cannot find a path. Try playing with where you're placing the agent.
I kind of remember running into a similar problem a while back and problem was I forgot to bake the NavMesh in Window > AI > Navigation. Just in case.
First of all I apologize that this texts looks so weird.
It's my first time to use stackoverflow
I start to learn about Unity and C#.
And today I learn about move cube in unity, gonna review the script and I think i failed.
I put script in cube1 at Hierarchy, click the solution build at C# and run at unity.
And didn't work.
public class TRAIN : MonoBehaviour
{
// return cube1 to cube. cube1 is name of cube object in unity
GameObject cube = GameObject.Find("cube1");
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
//move cube1 to z-axis at speed 1
cube.transform.position += new Vector3(0, 0, 1);
}
}
How can I move cube1?
You can't call GameObject.Find() directly there, you should be getting an error in the console.
UnityException: Find is not allowed to be called from a MonoBehaviour constructor (or instance field initializer), call it in Awake or Start instead
Do it in the Awake() or Start() instead.
public class TRAIN : MonoBehaviour
{
GameObject cube;
void Start()
{
cube = GameObject.Find("cube1");
}
kinda new to coding so help would be appreciated. I'm trying to duplicate this GameObject "cube" in unity and I'm having trouble with it. what im trying to do is duplicate the cube and get it to stack on top of each other over and over.
I know if i got this to work it would duplicte it in the same postion so you would only see it duplicate in the higharchy.
using System.Collections;
using UnityEngine;
public class cube : MonoBehaviour
{
public GameObject cube1;
public void update()
if(input.getKeyDown(KeyCode.Space))
{
instantiate cube1;
}
}
I assume you know the height of the cube, you are working with. In unity the default height is 1.0f(For the primitive cube).
Btw if your code is a pseudo code then its okey but if not, you need more training before writing such scripts, even tho this type of script is extremely easy to write.
(ps: i wrote this script in notepad++ hope it compiles :/)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
// We start classes with capital letters in c# its a convention :)
public class Cube : MonoBehaviour
{
// Same applies to public class fields & Properties
// Marking a MonoBehaviour field as public will allow you to directly assign values to it
// inside the editor
public GameObject OriginalCube;
// Same can be achieved with private fields using the serializefield attribute
[SerializeField]
private float cubeHeight = 1.0f;
// In case you would like to store the duplicated cubes
public List<GameObject> Cubes = new List<GameObject>();
private void Awake()
{
// Adding the first cube to the list, i assume your cube is already in the scene
Cubes.Add(OriginalCube);
}
private void Update()
{
if(Input.GetKeyDown(KeyCode.Space))
{
// We instantiate a new cube and add it to the list
Cubes.Add(Instantiate(Cubes[Cubes.Count - 1]);
// We ask the previous cube position (the one we copied)
Vector3 previousCubePosition = Cubes[Cubes.Count - 2].transform.position;
// then we assign a new position to our cube raised by "1 unit" on the y axis which is the up axis in unity
Cubes[Cubes.Count - 1].transform.position =
new Vector3(previousCubePosition.x, previousCubePosition.y + cubeHeight, previousCubePosition.z);
}
}
}
One way you can have your goal achieved, is to add to your newly instantiated object's y position a constant amount. This constant amount will be increased each time you create a new duplicate of your object.
public GameObject cube1;
private int instantiateCounter = 0;
public float PULL_UP_AMOUNT = 30f;
public void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
instantiateCounter++;
GameObject newCube = Instantiate(cube1);
newCube.transform.position = new Vector3(cube1.transform.position.x, cube1.transform.position.y + instantiateCounter * PULL_UP_AMOUNT, cube1.transform.position.z);
}
}
The constant amount we're talking about is PULL_UP_AMOUNT.
Keep in mind, you can access your new duplicate's properties by saving the result of Instantiate method inside a new GameObject, just like I did.
camera transform
I am trying to move my camera based on the players' movements on Y axis in Unity.
However, it does not work...
What did I do wrong? I have attached image of my script (C#) here.
and, Yes, I did attach this script with Main Camera.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CameraController : MonoBehaviour {
GameObject player;
// Use this for initialization
void Start () {
this.player = GameObject.Find("cat");
}
// Update is called once per frame
void Update () {
Vector3 playerPos = this.player.transform.position;
transform.position = new Vector3(
transform.position.x, playerPos.y, transform.position.z);
}
}
Make the player GameObject public and just drag and drop your player in the inspector in unity see if that works? Are you getting any exceptions? Also add Debug.Log (player.transform.position.ToString ()) to see if it is showing the right values. Are you sure you player object name is cat and not Cat, it is case sensitive. Check on those things and let me know if you figured it out!