How to update line renderer's start and end positions at runtime? - c#

I'm trying to connect two GameObject (sphereObject0 and sphereObject2) with a line renderer lineRenderer0_2 in a Unity3D project.
The line shows up fine at first. My problem is that I need the line renderer to update its start and end positions to match the positions of sphereObject0 and sphereObject2.
For some reasons, my line renderer is absolutely static, and I can't find the way to make it adjust its start and end positions together with the spheres GameObjects eventually move around.
Here's my C# script, any idea about what I am doing wrong? Any help is greatly appreciated!
using UnityEngine;
using System.Collections;
public class autoCreateNetwork : MonoBehaviour {
public bool sphereHasGravity = false;
private Collider coll;
private Renderer rend;
private SpringJoint springJoint;
public Material lines;
GameObject sphereObject0;
GameObject sphereObject2;
LineRenderer lineRenderer0_2 ;
void Start () {
// Spawn a sphere and set it up
sphereObject0 = GameObject.CreatePrimitive(PrimitiveType.Sphere);
sphereObject0.transform.position = new Vector3(-10.2571400951f, 98.8977277884f, -19.9870244083f);
Rigidbody sphereBody0 = sphereObject0.AddComponent<Rigidbody>();
sphereBody0.mass = 1f;
// Physics model
coll = sphereBody0.GetComponent<Collider> ();
PhysicMaterial material0 = new PhysicMaterial();
material0.dynamicFriction = 1;
coll.material = material0;
coll.material.bounciness = .8f;
// Render (color, smoothness, etc.)
rend = sphereBody0.GetComponent<Renderer>();
rend.material.color = new Color32(171,166,164,255);
rend.material.SetFloat("_Metallic", 0.0f);
rend.material.SetFloat("_Glossiness", 0.0f);
sphereBody0.useGravity = sphereHasGravity;
sphereBody0.transform.localScale = new Vector3(0.5f,0.5f,0.5f);
// Spawn a sphere and set it up
sphereObject2 = GameObject.CreatePrimitive(PrimitiveType.Sphere);
sphereObject2.transform.position = new Vector3(-28.1943570987f, 89.5665878403f, 5.43686642264f);
Rigidbody sphereBody2 = sphereObject2.AddComponent<Rigidbody>();
sphereBody2.mass = 1f;
// Physics model
coll = sphereBody2.GetComponent<Collider> ();
PhysicMaterial material2 = new PhysicMaterial();
material2.dynamicFriction = 1;
coll.material = material2;
coll.material.bounciness = .8f;
// Render (color, smoothness, etc.)
rend = sphereBody2.GetComponent<Renderer>();
rend.material.color = new Color32(105,150,187,255);
rend.material.SetFloat("_Metallic", 0.0f);
rend.material.SetFloat("_Glossiness", 0.0f);
sphereBody2.useGravity = sphereHasGravity;
sphereBody2.transform.localScale = new Vector3(0.5f,0.5f,0.5f);
// Spawn a line and set it up
GameObject line0_2 = new GameObject();
LineRenderer lineRenderer0_2 = line0_2.AddComponent<LineRenderer>();
lineRenderer0_2.material = lines;
lineRenderer0_2.widthMultiplier = 0.0482773661501f;
lineRenderer0_2.SetPosition(0, sphereObject0.transform.position);
lineRenderer0_2.SetPosition(1, sphereObject2.transform.position);
float alpha0_2 = .9f;
Gradient gradient0_2 = new Gradient();
gradient0_2.SetKeys(
new GradientColorKey[] { new GradientColorKey(new Color32(171,166,164,255), 0.0f), new GradientColorKey(new Color32(105,150,187,255), 1.0f) },
new GradientAlphaKey[] { new GradientAlphaKey(alpha0_2, 0.0f), new GradientAlphaKey(alpha0_2, 1.0f) }
);
lineRenderer0_2.colorGradient = gradient0_2;
lineRenderer0_2.useWorldSpace = true;
}
void Update () {
lineRenderer0_2.SetPosition(0, sphereObject0.transform.position);
lineRenderer0_2.SetPosition(1, sphereObject2.transform.position);
}
}

Your issue is how you're assigning the LineRenderer with AddComponent to a new variable instead of your member variable. The line here:
LineRenderer lineRenderer0_2 = line0_2.AddComponent<LineRenderer>();
creates a new variable named lineRenderer0_2 within the scope of Start() and hides the member variable when referenced elsewhere in that function. Change the line to:
lineRenderer0_2 = line0_2.AddComponent<LineRenderer>();
and it should work fine. As a side-node, it's common to name member variables with an "m_" prefix so you don't run into these issues.

Related

Text mesh pro moving issue

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);
}

Why is my line renderer not showing up in Unity 2D

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);
}
}

Move and Rotate LineRenderer with Transform property

You can rotate any visual Object in Unity with the Transform property. One exception is the LineRenderer. You can't move or rotate it with the transform property.
LineRenderer is moved with the SetPosition or SetPositions function so I managed to make it movable by the transform position property but I can't make make it rotate too.
Below is the code I am using to make it movable.
public Vector3 beginPos = new Vector3(-1.0f, -1.0f, 0);
public Vector3 endPos = new Vector3(1.0f, 1.0f, 0);
Vector3 beginPosOffset;
Vector3 endPosOffset;
LineRenderer diagLine;
void Start()
{
diagLine = gameObject.AddComponent<LineRenderer>();
diagLine.material = new Material(Shader.Find("Sprites/Default"));
diagLine.startColor = diagLine.endColor = Color.green;
diagLine.startWidth = diagLine.endWidth = 0.15f;
diagLine.SetPosition(0, beginPos);
diagLine.SetPosition(1, endPos);
//Get offset
beginPosOffset = transform.position - diagLine.GetPosition(0);
endPosOffset = transform.position - diagLine.GetPosition(1);
}
void Update()
{
//Calculate new postion with offset
Vector3 newBeginPos = transform.position + beginPosOffset;
Vector3 newEndPos = transform.position + endPosOffset;
//Apply new position with offset
diagLine.SetPosition(0, newBeginPos);
diagLine.SetPosition(1, newEndPos);
}
I tried to use the-same method I used to make it able to rotate but I am stuck in the first step of getting the offset because there is no way to access the rotation variable for LineRenderer but there is one for accessing the position GetPosition.
How can I get the LineRenderer rotation or how can I also make LineRenderer be rotated from the Transform property?
Below is an image that shows the behavior of LineRenderer with and without the script above. Position is now working with the script above enabled but rotation is not.
You can use the transform's localToWorldMatrix:
void Start()
{
diagLine = gameObject.AddComponent<LineRenderer>();
diagLine.material = new Material(Shader.Find("Sprites/Default"));
diagLine.startColor = diagLine.endColor = Color.green;
diagLine.startWidth = diagLine.endWidth = 0.15f;
diagLine.SetPosition(0, beginPos);
diagLine.SetPosition(1, endPos);
}
void Update()
{
//Calculate new postion
Vector3 newBeginPos = transform.localToWorldMatrix * new Vector4(beginPos.x, beginPos.y, beginPos.z, 1);
Vector3 newEndPos = transform.localToWorldMatrix * new Vector4(endPos.x, endPos.y, endPos.z, 1);
//Apply new position
diagLine.SetPosition(0, newBeginPos);
diagLine.SetPosition(1, newEndPos);
}
You can set useWorldSpace attribute of LineRenderer to false, Then LineRenderer can be controlled using its transform component.
https://answers.unity.com/questions/39391/line-renderer-position.html

How to instantiate object class that contains GameObject? [duplicate]

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.

Wont allow me to create more than 1 LineRenderer

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.

Categories

Resources