I am attempting to create LineRenderers at runtime(when the user presses a button).
My Problem: I can never create more than one LineRenderer. When I go to created the 2nd one, the LineRenderer object is always NULL.
What am I doing wrong? Can you provide advice on what I need to do to create more than one LineRenderer?
public class AppInit : MonoBehaviour {
public Vector3[] TEST_VERTICES;
public const int SPEED = 5;
public List<LineRenderer> lines;
// Use this for initialization
void Start () {
TEST_VERTICES = new Vector3[10] {new Vector3(0,0,0), new Vector3(10,10,10), new Vector3(30,10,50), new Vector3(30,40,50),
new Vector3(10,30,90), new Vector3(10,20,40), new Vector3(50,20,40), new Vector3(70,80,90),
new Vector3(10,70,20), new Vector3(60,10,0)};
lines = new List<LineRenderer>();
}
// Update is called once per frame
void Update () {
float x = Input.GetAxis ("Horizontal") * Time.deltaTime * SPEED;
float z = 0;
float y = Input.GetAxis ("Vertical") * Time.deltaTime * SPEED;
gameObject.transform.Translate (new Vector3(x,y,z));
}
void OnGUI() {
if (GUI.Button (new Rect(10,10,100,20), "Create"))
createString(TEST_VERTICES);
}
public bool createString( Vector3[] vertices ) {
LineRenderer lRend = gameObject.AddComponent ("LineRenderer") as LineRenderer;
//LineRenderer lRend = new LineRenderer();
lines.Add(lRend);
Debug.Log ("IS NULL"+(lRend == null).ToString ());
lRend.SetColors (new Color(100,0,0,100), new Color(0,0,100,100));
lRend.SetWidth(10, 1);
lRend.SetVertexCount(vertices.Length);
for (int i=0; i<vertices.Length; i++)
lRend.SetPosition(i, vertices[i]);
return true;
}
}
As Iridium points out, you can only add one component of each type to a gameobject. So you want to create a new game object for each new linerenderer. The simple way to do this here is to change:
LineRenderer lRend = gameObject.AddComponent("LineRenderer") as LineRenderer;
to:
LineRenderer lRend = new GameObject().AddComponent("LineRenderer") as LineRenderer;
Then if you need to access the linerenderer's gameobject later you can do so by lRend.gameObject. Or lines[index].gameObject.
A quick Google brings up this page: http://answers.unity3d.com/questions/47575/create-a-linerender-in-c.html which suggests that you cannot add multiple instances of the same type to a single GameObject, and suggests that multiple GameObject instances should be used instead.
Related
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
public class spawningunits : MonoBehaviour
{
public static int amount1 = 100;
public static int amount2 = 200;
public GameObject ShadowWolf;
public GameObject Cannibal;
//public GameObject numberofunits1;
//public GameObject numberofunits2;
[SerializeField] private GameObject numberofunits1;
[SerializeField] private TMP_Text numberofunits2;
GameObject someObj;
private void Start(){
//numberofunits1.text = "200";
numberofunits2.text = "600";
Instantiate(numberofunits1, new Vector3(50, -1, -5), Quaternion.identity);
Instantiate(numberofunits2, new Vector3(45, -1, -5), Quaternion.identity);
Instantiate(ShadowWolf, new Vector3(56, -1, -5), Quaternion.identity);
ShadowWolf.SetActive(true);
Instantiate(Cannibal, new Vector3(-56, -1, -5), Quaternion.identity);
Cannibal.SetActive(true);
someObj = new GameObject("SomeObj");
numberofunits1.transform.parent = someObj.transform;
//GameObject someObj = new GameObject("SomeObj");
//someObj.AddComponent(numberofunits1);
//Vector3 pozycjacannibala = Cannibal.transform.position;
//Vector3 pozycjashadowwolfa = ShadowWolf.transform.position;
//numberofunits1.text = "200";
numberofunits2.text = "100";
}
void Update() {
//GameObject someObj = new GameObject("SomeObj");
//numberofunits1.transform.parent = someObj;
//Gameobject numberofunits1g = Gameobject.Find("numberofunits1g").GetComponent<GameObject>();
//Vector3 pozycjacannibala = Cannibal.transform.position;
//Vector3 pozycjashadowwolfa = ShadowWolf.transform.position;
//numberofunits1.transform.position = new Vector3(20,-1,-5);
numberofunits2.transform.position = new Vector3(Cannibal.transform.position.x,Cannibal.transform.position.y,Cannibal.transform.position.z);
numberofunits2.GetComponent<RectTransform>().localPosition += new Vector3(20,-1,-5);
//numberofunits1.GetComponent<RectTransform>().localPosition = new Vector3(-56,-1,-5);
//Vector3 poz = numberofunits1.transform.position;
//print(poz);
someObj.transform.position = new Vector3(Cannibal.transform.position.x,Cannibal.transform.position.y,Cannibal.transform.position.z);
//numberofunits1.transform.position = new Vector3(40, 12, -5);
//numberofunits1.anchoredPosition = new Vector2(20,-1);
//Vector3 poz = numberofunits1.transform.position;
//print(poz);
}
}
What I want to do is move text to a certain position (the text is a prefab, I'm using text mesh pro). The problem I get is that instantiation works correctly setting up the text in a desired position, however I cant seem to be able to move it later on. The code doesn't throw any errors and I even set a print function to see what position does the code display and the position is correct, but on the screen the text is still in the same place. The project is being created in 2d.
When moving UI elements you will need to use the RectTransform instead of the regular transform (however the regular transform will still work for world space ui).
For example you could use:
numberofunits1.GetComponent().anchoredPosition = new Vector2(20,-1);
if you really need the z position you can use:
numberofunits1.GetComponent().anchoredPosition3D = new Vector3(20,-1,-5);
You can find the documentation on RectTransform here:
https://docs.unity3d.com/ScriptReference/RectTransform.html
I also recommend using the TextMeshPro variable for the UI element you are trying to use. So in this case: TMP_Text.
So your variable declaration would become:
[SerializeField] private TMP_Text numberofunits1;
[SerializeField] private TMP_Text numberofunits2;
If you're trying to move the full set of UI it might be useful if you move the regular transform on the Canvas. However in that case the canvas needs to be World Space.
TextMeshPro doesn't contain transform component but rect transform so you need to chanage rect trasnform Or you can either create a gameObject like
[SerializeField] private GameObject numberofunits1;
[SerializeField] private GameObject numberofunits2;
GameObject someObj;
void Start(){
someObj = new GameObject("SomeObj");
numberofunits1.transform.parent = someObj;
}
void Update()
{
numberofunits1.text = "200";
numberofunits2.text = "100";
//Gameobject numberofunits1g = Gameobject.Find("numberofunits1g").GetComponent<GameObject>();
//Vector3 pozycjacannibala = Cannibal.transform.position;
//Vector3 pozycjashadowwolfa = ShadowWolf.transform.position;
numberofunits2.GetComponent<RectTransform>().localPosition += new Vector3(20,-1,-5) * Time.deltTime;
someObj.transform.position += new Vector3(Cannibal.transform.position.x,Cannibal.transform.position.y,Cannibal.transform.position.z) * Time.deltaTime;
Vector3 poz = numberofunits1.GetComponent<RectTransform>().localPosition.transform.position;
print(poz);
}
I am Using Unity 2019.2.14f.
Here is my code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Unity.Entities;
using Unity.Transforms;
using Unity.Collections;
public class GameSystem : MonoBehaviour
{
public GameObject player;
public int spawnNumber;
public bool useECS;
private EntityManager manager;
// Start is called before the first frame update
void Start()
{
manager = World.Active.EntityManager;
if (useECS)
{
SpawnECS(player);
}
else
{
for (int i = 0; i <= spawnNumber; i++)
{
Spawn(player);
}
}
}
// Update is called once per frame
void Update()
{
}
private void Spawn(GameObject unit)
{
float x = Random.Range(5, 249);
float y = 0f;
float z = Random.Range(5, 249);
float rx = 0f;
float ry = Random.Range(1, 180);
float rz = 0f;
Instantiate(unit, new Vector3(x, y, z), Quaternion.Euler(rx,ry,rz));
}
private void SpawnECS(GameObject unit)
{
float x = Random.Range(5, 249);
float y = 0f;
float z = Random.Range(5, 249);
float rx = 0f;
float ry = Random.Range(1, 180);
float rz = 0f;
NativeArray<Entity> players = new NativeArray<Entity>(spawnNumber, Allocator.Temp);
manager.Instantiate(unit, players);
players.Dispose();
}
}
This is the prefab which I am instantiating:
When I select on my GameSystem component useECS to be true I can see it is creating enteties into my entity debugger. Take a look:
So as you can see Entities are created. However when I inspect one Entity here is what I see:
As you can see Components are not converted. Where is my mistake?
How can I create visible entity out of GameObhject Prefab or use the so-called Hybrid ECS method?
NativeArray<Entity> players = new NativeArray<Entity>( 3 , Allocator.Temp );
Is equivalent to writing :
var players = new GameObject[]{ new GameObject() , new GameObject() , new GameObject() };
It's a list of prefab entities, that are completely empty. This is why spawning that list will give N amount of default entities.
What to should do instead is to convert that player GameObject to an entity prefab and instantiate that entity prefab N times (or populate that NativeArray with set of entity prefabs)
Entity entityPrefab = GameObjectConversionUtility.ConvertGameObjectHierarchy( gameObjectPrefab );
I am trying to create a Fruit Ninja style game on Unity 2D and I want to create a trail that follows where the player has "cut". I've tried to instantiate a "cut" object that contains the line renderer every time a user drags. However, the line renderer is not showing up. Can anyone correct any errors or suggest a new method?
public class CreateCuts : MonoBehaviour
{
public GameObject cut;
public float cutDestroyTime;
private bool dragging = false;
private Vector2 swipeStart;
// Update is called once per frame
void Update()
{
if (Input.GetMouseButtonDown(0))
{
dragging = true;
swipeStart = Camera.main.ScreenToWorldPoint(Input.mousePosition);
}
else if (Input.GetMouseButtonUp(0) && dragging)
{
createCut();
}
}
private void createCut()
{
this.dragging = false;
Vector2 swipeEnd = Camera.main.ScreenToWorldPoint(Input.mousePosition);
GameObject cut = Instantiate(this.cut, this.swipeStart, Quaternion.identity) as GameObject;
cut.GetComponent<LineRenderer>().positionCount = 1 ;
cut.GetComponent<LineRenderer>().enabled = true;
cut.GetComponent<LineRenderer>().SetPosition(0, this.swipeStart);
cut.GetComponent<LineRenderer>().SetPosition(1, swipeEnd);
Vector2[] colliderPoints = new Vector2[2];
colliderPoints[0] = new Vector2(0.0f, 0.0f);
colliderPoints[1] = swipeEnd - swipeStart;
cut.GetComponent<EdgeCollider2D>().points = colliderPoints;
Destroy(cut.gameObject, this.cutDestroyTime);
}
}
I expect there to be a line, but nothing shows up. There is also a warning stating that the SetPosition(1, swipeEnd) is out of bounds.
EDIT: Here are the settings of my cut object
1st part of cut object settings
2nd part of cut object settings
Positions tab of line renderer
I want to create a trail that follows where the player has "cut".
The word "trail" indicates that you should rather use a trail renderer!
Manual: https://docs.unity3d.com/Manual/class-TrailRenderer.html
API reference: https://docs.unity3d.com/ScriptReference/TrailRenderer.html
Back to your original question:
Your linerenderer probably is rendered but at a random position, because of Vector2 to Vector3 conversion, i dunno your project structure but this can be the case.
Please post a picture with one of your cut gameobject, that holds your linerenderer, and also extend the positions tab on the linerenderer so we can see your points xyz coordinates
Also apply the changes mentioned by commenters, because you really need 2 verticies for a line :P
Update:
public class CreateCuts : MonoBehaviour
{
public GameObject cut;
public float cutDestroyTime;
private bool dragging = false;
private Vector3 swipeStart;
// Update is called once per frame
void Update()
{
if (Input.GetMouseButtonDown(0))
{
dragging = true;
swipeStart = Camera.main.ScreenToWorldPoint(Input.mousePosition);
Debug.Log("Swipe Start: " + swipeStart);
}
else if (Input.GetMouseButtonUp(0) && dragging)
{
createCut();
}
}
private void createCut()
{
this.dragging = false;
Vector3 swipeEnd = Camera.main.ScreenToWorldPoint(Input.mousePosition);
Debug.Log("SwipeEnd: " + swipeEnd);
GameObject cut = Instantiate(this.cut, swipeStart, Quaternion.identity);
cut.GetComponent<LineRenderer>().positionCount = 2;
// why is it not enabled by default if you just instantiate the gameobject O.o?
cut.GetComponent<LineRenderer>().enabled = true;
cut.GetComponent<LineRenderer>().SetPositions(new Vector3[]{
new Vector3(swipeStart.x, swipeStart.y, 10),
new Vector3(swipeEnd.x, swipeEnd.y, 10)
// z is zero cos we are in 2d in unity up axis is Y we set it to 10 for visibility reasons tho}
});
// Commented out cos atm we are "debugging" your linerenderer
// Vector2[] colliderPoints = new Vector2[2];
// colliderPoints[0] = new Vector2(0.0f, 0.0f);
// colliderPoints[1] = swipeEnd - swipeStart;
// cut.GetComponent<EdgeCollider2D>().points = colliderPoints;
//Destroy(cut.gameObject, this.cutDestroyTime);
}
}
I writing simple runner game.
I have game object (quad).
I want it to generate.
I wrote spawnscript:
using UnityEngine;
using System.Collections;
public class SpawnScript : MonoBehaviour {
public GameObject[] obj;
//public GameObject obj;
public float spawnMin = 1f;
public float spawnMax = 2f;
// Use this for initialization
void Start () {
Spawn();
}
void Spawn()
{
//for (int i = 0; i < 10; i++)
// Instantiate(obj, new Vector3(i * 2.0f, 0, 0), Quaternion.identity);
Instantiate(obj[Random.Range(0, obj.GetLength(0))], transform.position, Quaternion.identity);
Invoke("Spawn", Random.Range(spawnMin, spawnMax));
}
}
But my quad spawning one time.I need it to spawn multiple times.
Where is my problem?
Use InvokeRepeating instead of Invoke in start event:
// Invokes the method methodName in time seconds, then repeatedly every repeatRate seconds.
InvokeRepeating("Spawn", 3, 3);
If you do InvokeRepeating("Function", 1.0f, 1.0f), it will call Function one second after the InvokeRepeating call and then every one second thereafter.
Hence, you can control the spawn timings.
Update
As asked in comments:
You can also cancel InvokeRepeating any time by calling below code. More information here.
CancelInvoke("Spawn");
There is no problem with code. All GameObjects instantiated same position so you can use code below:
public float spawnDistanceFactor = 2f; //Value is your choice. You can change it.
void Spawn()
{
float startPosX = 0f; // I assume your camera look at 0,0,0 point.
for (int i = 0; i < 10; i++){
Vector3 spawnPos = new Vector3(startPosX,0f,0f);
Instantiate(obj, spawnPos, Quaternion.identity);
startPosX+=spawnDistanceFactor;
}
}
It is only moves positions on X axis you can move it x,y,z.
Also
You can use Random function for moving spawn position
public float randomMin = 2f;
public float randomMax = 4f;
void Spawn()
{
float startPosX = 0f; // I assume your camera look at 0,0,0 point.
for (int i = 0; i < 10; i++){
Vector3 spawnPos = new Vector3(startPosX,0f,0f);
Instantiate(obj, spawnPos, Quaternion.identity);
float randomX = Random.Range(randomMin,randomMax);
startPosX+=randomX;
}
}
You can do a lot of things.
For destroying prefabs you can add Destroy script to object (You should create prefab with script) Like:
void DestroyObject(){
Destroy(this.gameObject);
}
or use list to hold pointers to the GameObjects. Like:
using System.Collections.Generic; // For list
private List<GameObject> objectList;
public float randomMin = 2f;
public float randomMax = 4f;
void Start(){
objectList = new List<GameObject>();
Spawn();
}
void Spawn()
{
objectList.Clear(); ///For multiple spawn purpose dont dublicate items.
float startPosX = 0f; // I assume your camera look at 0,0,0 point.
for (int i = 0; i < 10; i++){
Vector3 spawnPos = new Vector3(startPosX,0f,0f);
GameObject newObject = Instantiate(obj, spawnPos, Quaternion.identity) as GameObject;
objectList.Add(newObject);
float randomX = Random.Range(randomMin,randomMax);
startPosX+=randomX;
}
}
void DestroyObject(){
for(int i=0;i<objectList.Count;i++){
Destroy(objectList[i]);
}
}
This question already has answers here:
Declaring a new instance of a class in C#
(2 answers)
Closed 2 years ago.
I am attempting to instantiate a large number of "particles" using a C# script in Unity. I have created a particle class that contains the creation of a corresponding GameObject. The GameObject within each particle instance is a sphere. When attempting to instantiate a new particle (Particle p = new Particle(...)) I get a Unity warning that the 'new' keyword should not be used.
"You are trying to create a MonoBehaviour using the 'new' keyword. This is not allowed. MonoBehaviours can only be added using AddComponent(). Alternatively, your script can inherit from ScriptableObject or no base class at all
UnityEngine.MonoBehaviour:.ctor()"
What is the proper way to instantiate a number of instances of my particle class (each containing a singular sphere GameObject)?
Particle Class:
public class Particle : MonoBehaviour {
Vector3 position = new Vector3();
Vector3 velocity = new Vector3();
Vector3 force = new Vector3();
Vector3 gravity = new Vector3(0,-9.81f,0);
int age;
int maxAge;
int mass;
GameObject gameObj = new GameObject();
public Particle(Vector3 position, Vector3 velocity)
{
this.position = position;
this.velocity = velocity;
this.force = Vector3.zero;
age = 0;
maxAge = 250;
}
// Use this for initialization
void Start () {
gameObj = GameObject.CreatePrimitive (PrimitiveType.Sphere);
//gameObj.transform.localScale (1, 1, 1);
gameObj.transform.position = position;
}
// FixedUopdate is called at a fixed rate - 50fps
void FixedUpdate () {
}
// Update is called once per frame
public void Update () {
velocity += gravity * Time.deltaTime;
//transform.position += velocity * Time.deltaTime;
gameObj.transform.position = velocity * Time.deltaTime;
Debug.Log ("Velocity: " + velocity);
//this.position = this.position + (this.velocity * Time.deltaTime);
//gameObj.transform.position
}
}
CustomParticleSystem Class:
public class CustomParticleSystem : MonoBehaviour {
Vector3 initPos = new Vector3(0, 15, 0);
Vector3 initVel = Vector3.zero;
private Particle p;
ArrayList Particles = new ArrayList();
// Use this for initialization
void Start () {
Particle p = new Particle (initPos, initVel);
Particles.Add (p);
}
// Update is called once per frame
void Update () {
}
}
Any help is greatly appreciated!
Your code looks fine other than you may have accidentally typed the declaration wrong for gameObj
Change GameObject gameObj = new GameObject(); to just GameObject gameObj = null; in your Particle class.
The error specifically mentions that you cannot do what you did and in your Start() you are setting it like it mentioned.
EDIT: Looking at Particle, it inherits MonoBehaviour. You need to have gameObject create the instance for you using gameObject.AddComponent<Particle>();
http://docs.unity3d.com/ScriptReference/GameObject.AddComponent.html
gameObject is defined on MonoBehaviour so you should have access to it already.