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);
}
Related
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 want the player to draw a line through the mouse, and this line has a collider, but this collider appears in the wrong place.
I have tried these methods with ScreenToWorldPoint, ScreenToViewportPoint and ScreenPointToRay, but these results are not what I want.
public class DrawLine : MonoBehaviour
{
public GameObject linePrefab;
public GameObject currentLine;
public LineRenderer lineRenderer;
public EdgeCollider2D edgeCollider;
public List<Vector2> fingerPositions;
public List<Vector2> fingerWorldPositions;
// Use this for initialization
void Start()
{
}
// Update is called once per frame
void Update()
{
if (Input.GetMouseButtonDown(0))
{
CreateLine();
}
if (Input.GetMouseButton(0))
{
Vector2 tempFingerPos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
if (Vector2.Distance(tempFingerPos, fingerPositions[fingerPositions.Count - 1]) > .1f)
{
UpdateLine(tempFingerPos);
}
}
}
void CreateLine()
{
currentLine = Instantiate(linePrefab, Vector2.zero, Quaternion.identity);
lineRenderer = currentLine.GetComponent<LineRenderer>();
edgeCollider = currentLine.GetComponent<EdgeCollider2D>();
fingerPositions.Clear();
Vector3 tempMousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
fingerPositions.Add(tempMousePosition);
fingerPositions.Add(tempMousePosition);
lineRenderer.SetPosition(0, fingerPositions[0]);
lineRenderer.SetPosition(1, fingerPositions[1]);
edgeCollider.points = fingerPositions.ToArray();
}
void UpdateLine(Vector2 newFingerPos)
{
fingerPositions.Add(newFingerPos);
lineRenderer.positionCount++;
lineRenderer.SetPosition(lineRenderer.positionCount - 1, newFingerPos);
edgeCollider.points = fingerPositions.ToArray();
}
}
The black line is drawn with a mouse and the green line is Edge collider 2D.
I had your exact same problem some time ago in a project of mine. I fixed it by adjusting the transform.position of the linerenderer object to the location of the next point. And after setting the points, i would reset the position of the gameobject to zero (last line of code). This worked for me, because my gameobject should always be at absolute zero. But if yours doesn't, then just change it to use relative position and child it to an gameobject if it isnt already.
Here is my code, I hope it helps you.
public GameObject LineDrawPrefab;
private LineRenderer lineRenderer;
private EdgeCollider2D edgeCollider;
private List<Vector2> edgePoints;
private GameObject activeLineGameObject;
private List<GameObject> lineGameObjects;
private void StartLine(Vector3 start, Color color)
{
var targetPos = new Vector3 { x = start.x, y = start.y, z = 0.1f };
drawing = true;
activeLineGameObject = Instantiate(LineDrawPrefab, Vector3.zero, Quaternion.identity);
lineGameObjects.Add(activeLineGameObject);
lineRenderer = activeLineGameObject.GetComponent<LineRenderer>();
edgeCollider = activeLineGameObject.GetComponent<EdgeCollider2D>();
lineRenderer.sortingOrder = 1;
lineRenderer.material = LineRendererMaterial;
lineRenderer.startColor = color;
lineRenderer.endColor = color;
lineRenderer.startWidth = 0.3f;
lineRenderer.endWidth = 0.3f;
lineRenderer.SetPosition(0, targetPos);
lineRenderer.SetPosition(1, targetPos);
edgePoints.Clear();
edgePoints.Add(targetPos);
edgeCollider.points = edgePoints.ToArray();
}
private void ExtendLine(Vector3 nextpoint)
{
if (lineRenderer == null))
{
StartLine(Camera.main.ScreenToWorldPoint(Input.mousePosition), color);
return;
}
var targetPos = new Vector3 { x = nextpoint.x, y = nextpoint.y, z = 0.1f };
lineRenderer.positionCount += 1;
lineRenderer.SetPosition(lineRenderer.positionCount - 1, lineRenderer.transform.position = targetPos); // manipulate position to avoid the collider from spawning out of the object.
edgePoints.Add(nextpoint);
edgeCollider.points = edgePoints.ToArray();
activeLineGameObject.transform.position = Vector3.zero; // reset position
}
Edit: An additional tip. I (and you) used Camera.main here. This is not performant because it does an expensive lookup every time it is called.
(GameObject.FindGameObjectWithTag("MainCamera").GetComponent<Camera>())
I suggest to cache it in start or awake and then reuse that variable. This can potentially be a huge performance gain.
private Camera mainCamera;
private void Start()
{
mainCamera = Camera.main;
}
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.
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.
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.