I have some 2D objects in same transform position. How can I find out how many objects are in one same position and which objects are they?
EDIT:
Here is my code:
I want save all object on transform.position - new Vector3(speed, 0, 0)
GameObject go = GetObjectAt(transform.position - new Vector3(speed, 0, 0));
public GameObject GetObjectAt(Vector3 position)
{
string pos = position.x + "_" + position.y + "_";
if (obstacleDictionary.ContainsKey(pos + "BigRed"))
{
return obstacleDictionary[pos + "BigRed"];
}
else if (obstacleDictionary.ContainsKey(pos + "SmallRed"))
{
return obstacleDictionary[pos + "SmallRed"];
}
else return null;
}
I think you can use List<SomeModel> for keep object and postion.
Add your object to list when the object created
then find same postion object used by LINQ
CodeSample
Public class ObjectListener
{
public string ObjectName {get; set;}
public Vector2 ObjectVector {get; set;}
}
public class CreateObject : MonoBehaviour
{
List<ObjectListener> _gameObjectListener = new List<ObjectListener>();
void Update()
{
private GameObject _gameObject ; // you must create _gameObject
// and set tranform.Postion maybe you
// can use a method returned gameObject
Instantiate(_gameObject, _gameObject.transform.position, Quaternion.identity);
_gameObjectListener.Add(new ObjectListener
{
ObjectName = _gameObject.Name,
ObjectVector = _gameObject.transform.postion
});
}
}
I'm not sure that's the right way, but you can keep all created object name and postion in list object. So you can find how many object are in same object or not
Assuming all of the objects have a Collider2D on them, you just need to call Physics2D.BoxCastAll( and it will return a array of RaycastHit2D which you can call hitItems[i].collider.gameObject on to get the object.
RaycastHit2D[] hitItems = Physics2D.BoxCastAll(origin, size, angle, direction);
for(int i = 0; i < hitItems.Length; i++)
{
GameObject hitObject = hitItems[i].collider.gameObject;
//Do something with the hit object.
}
One method is mentioned in the below article
http://answers.unity3d.com/questions/638319/getting-a-list-of-colliders-inside-a-trigger.html
The basics of the above article
Make sure everything has a collider
Make sure at least one thing has a trigger
User "TriggerList" to get all items with a collider within the trigger.
This article is a second option
http://answers.unity3d.com/questions/532746/finding-gameobjects-within-a-radius.html
The basics
Get a position/transform
Get all colliders within a sphere
iterate through the list.
Related
I'm stuck with this one for quite some time now. I am trying to create spheres via script and update their position based on the position of points. Their position is updating on the Debug.Log() but they are not moving in Game View.
Here is my code:
void createSpheres(int objCount, float xPointsPos, float yPointsPos){
var sphereCreator = GameObject.CreatePrimitive(PrimitiveType.Sphere);
sphereCreator.transform.localScale = new Vector3(0.1f, 0.1f, 0.1f);
sphereCreator.transform.position = new Vector3(xPointsPos, yPointsPos, 0);
sphereCreator.AddComponent<Rigidbody>();
sphereCreator.GetComponent<Rigidbody>().useGravity = false;
sphereCreator.AddComponent<SphereCollider>();
//ADD THE SPHERES TO THE SPHERELIST
sphereList = new List<Sphere>();
for(int loop = 0; loop < objCount-1; loop++){
Sphere temp = new Sphere();
temp.sphereName = "sphere"+sphereNameCount;
temp.sphereObj = sphereCreator;
temp.sphereXPos = xPointsPos;
temp.sphereYPos = yPointsPos;
sphereList.Add(temp);
}
sphereNameCount++;
}
void UpdateSpheres()
{
for(int i = 0; i < sphereList.Count - 1; i++){
sphereList[i].sphereXPos = points[i].position.x;
sphereList[i].sphereYPos = points[i].position.y;
Debug.Log($"{sphereList[i].sphereXPos}" + " -- " + $"{points[i].position.x}");
}
}
public class Sphere{
public string sphereName;
public float sphereXPos;
public float sphereYPos;
public GameObject sphereObj;
}
The createSpheres() method is called inside a loop containing how many points are spawned to match it.
I also tried checking if the ArrayList is empty or not using Debug.Log() and it returned all the Sphere gameObjects that I added.
Any help or hint will be highly appreciated. Thanks!
You do not create a number of spheres according to the code. You create just a single sphere and assign it to all your Sphere instances. To create and move your spheres:
create GameObject object for every object instead of assigning the same object for each Sphere class instance
use .transform.position of the created object, assigned to Sphere class instance to move the corresponding GameObject instance
im kind of newbie to unity and object oriented programming. Recently im trying to clone Cube Surfer mobile game. Basic idea from my view is this ;
-When we triggered to collactable cubes which consist script will be duplicated and it will be belong the main cube parent as child object then triggered cube will be destroyed.(After positioning)
-Later this duplicate child objects(cubes) will do the same when they enter trigger area of other collectable cubes(those will be the same prefab but did not yet create a prefab)
Im trying to collect(create a clone of it position and destroy the object) cubes. For first cube, I added some code to my movement script which is below.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Movement : MonoBehaviour
{
public GameObject addup;
Rigidbody rb;
float controlSpeed = 1.25f;
float forwardMovementSpeed = 10f;
private Vector3 axisGet;
float deathTime;
public int collected;
// Start is called before the first frame update
void Start()
{
rb = gameObject.GetComponent<Rigidbody>();
collected = 0;
}
// Update is called once per frame
void FixedUpdate()
{
axisGet = new Vector3(0, 0, Input.GetAxis("Horizontal"));
rb.MovePosition(transform.position + Vector3.left * forwardMovementSpeed * Time.deltaTime + axisGet * controlSpeed * Time.deltaTime);
}
private void OnTriggerEnter(Collider other)
{
if(other.tag=="add up")
{
gameObject.transform.position += Vector3.up;
var newObject = Instantiate(addup.gameObject, Vector3.zero, Quaternion.identity);
newObject.transform.parent = transform;
newObject.transform.position = gameObject.transform.position + Vector3.down;
Destroy(other.gameObject);
newObject.GetComponent<BoxCollider>().isTrigger = false;
collected++;
}
}
}
WORKED WITHOUT ERROR BUT THEN, I applied the same method to collectable cubes scripts.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class UpNdown : MonoBehaviour
{
void Start()
{
}
// Update is called once per frame
void Update()
{
}
private void OnTriggerEnter(Collider other)
{
if (other.tag == "add up")
{
GameObject parentTransform;//?????????
parentTransform = gameObject.GetComponentInParent<GameObject>(); //get first cube component
parentTransform.transform.position += Vector3.up; //first cube one unit up
GameObject newObject; // ?????????
newObject = Instantiate(other.gameObject, Vector3.zero, Quaternion.identity) as GameObject; //???????????
Debug.Log(newObject);
var collect = parentTransform.GetComponent<Movement>().collected;
if (other != null)
{
Destroy(other.gameObject); //destroy triggered collactable
}
newObject.transform.parent = parentTransform.transform; //setting parent to new cube
newObject.transform.position = parentTransform.transform.position + Vector3.down * (collect + 1); //setting position of new cube
newObject.GetComponent<BoxCollider>().isTrigger = false; //prepare the below cubes(new cubes) for trigger with other collactable cubes
collect++;
}
}
}
And, I had nullexception error in every line in ontriggerenter method then, I changed(added) the lines with question marks. So, I get
ArgumentException: GetComponent requires that the requested component 'GameObject' derives from MonoBehaviour or Component or is an interface.
UnityEngine.GameObject.GetComponentInParent[T] (System.Boolean includeInactive) (at :0)
UnityEngine.GameObject.GetComponentInParent[T] () (at :0)
UpNdown.OnTriggerEnter (UnityEngine.Collider other)
I thought, I understood the OOP instance idea which objects in the scenes are instances scripts has their own value... but i dont understand that while I was operating on a instance why it is null in the memory :((((((((((((( if PC can't access how instantiates the object ?
SORRY I WRITE THIS LONG BUT IM ABOUT THE EDGE AGAIN I DON'T WANT TO QUIT BECAUSE OF FACING THIS PROBLEM AGAIN
TY FOR YOUR ANSWERS, ALREADY APPRECIATED :)
GameObject is no component (it is rather a container of all components attached to it!)
=> you can't get it using GetComponent or GetComponentInParent at all. (Btw Note that GetComponentInParent starts the search on this object itself first before bubling up the hierarchy so either way this isn't what you want to use).
What you want is simply transform.parent to get the Transform component of the parent object of the object this script is attached to (assuming the rest of your code does what it should)
private void OnTriggerEnter(Collider other)
{
// Rather use CompareTag instead of string ==
// The latter silently fails in case of typos making your debugging life miserabel
// it is also slightly less efficient
if (!other.CompareTag("add up")) return;
// Get the parent of this object
var parentTransform = transform.parent;
// Cache this you will need it later see below
var parentMovement = parentTransform.GetComponent<Movement>();
var collect = parentMovement.collected;
parentTransform.position += Vector3.up;
// By using the correct type you want later you can skip GetComponent
var newObjectCollider = Instantiate(other, Vector3.zero, Quaternion.identity);
Debug.Log(newObjectCollider);
Destroy(other.gameObject);
newObjectCollider.transform.parent = parentTransform;
newObjectCollider.transform.position = parentTransform.position + Vector3.down * (collect + 1);
newObjectCollider.isTrigger = false;
// This does absolutely nothing. Numeric values are passed by value and there is no connection
// between your local variable and the component you got it from
//collect++;
// you probably rather want to increase
parentMovement.collected++;
}
Or alternatively since you anyway have a specific component on your parent object you could also do
// Instead directly get this component
var parentMovement = GetComponentInParent<Movement>();
// Then wherever needed access the transform through it
var parentTransform = parentMovement.transform;
...
I'm quite sure though that the other way round it is more efficient since you already know exactly which parent you are searching the component on.
Or - and this would probably be the best option - cache that parent information once right away:
// If possible already reference this vis the Inspector
[SerializeField] private Movement parentMovement;
private Transform parentTransform;
private void Awake ()
{
if(! parentMovement) parentMovement = GetComponentInParent<Movement>();
parentTransform = parentMovement.transform;
}
Ty sir my first code was nearly the same of your first answer but didn't work again at least for error.
private Transform parentTransform;
private void Awake ()
{
if(! parentMovement) parentMovement = GetComponentInParent<Movement>();
parentTransform = parentMovement.transform;
}
But this worked, I guess the problem I need to define instances to class so they don't disappear instantly on the trigger function or direct I need to define them to class.
Anyway, thank you derHugo now need to solve different problems :D
This is a follow-up for a different question I posted earlier. The solution found there led to a new problem I will describe here.
Having objects spawn, with random size within set range, with equal distance between them regardless of framerate
I am trying to create the effect of several buildings in different sizes moving from left to right at a constant speed regardless of framerate. I want the spacing between the buildings to be the same no matter the size, and each building's size is randomized within a range.
I solved this by comparing the size of the last building with the current and dividing it by their speed, which worked initially, but was very heavy on performance due to Instantiating prefabs constantly. This is the original code from my ScrollingCity script.
if(Time.time > nextBuilding)
{
spawningRatio = ((randomSize / 2) + (buildingPrefab.transform.localScale.x / 2) + distanceBetween) / (speed);
nextBuilding = Time.time + spawningRatio;
buildingPrefab.transform.localScale = new Vector3(randomSize, randomSize, randomSize);
Instantiate(buildingPrefab, spawnPoint.transform.position, Quaternion.identity);
randomSize = Random.Range(ranMin, ranMax);
}
In the linked thread I was advised to use pooling for my objects, to reduce the load, and I was able to make it work with the use of some tutorials. However, I now don't know how to compare the sizes of the last to objects pulled from the pool, to ensure that they all have the same spacing between them.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ObjectPooler : MonoBehaviour
{
[System.Serializable]
public class Pool
{
public string tag;
public GameObject prefab;
public int size;
}
#region Singleton
public static ObjectPooler Instance;
private void Awake()
{
Instance = this;
}
#endregion
public List<Pool> pools;
public Dictionary<string, Queue<GameObject>> poolDictionary;
private void Start()
{
poolDictionary = new Dictionary<string, Queue<GameObject>>();
foreach (Pool pool in pools)
{
Queue<GameObject> objectPool = new Queue<GameObject>();
for (int i = 0; i < pool.size; i++)
{
GameObject obj = Instantiate(pool.prefab);
obj.SetActive(false);
objectPool.Enqueue(obj);
}
poolDictionary.Add(pool.tag, objectPool);
}
}
public GameObject SpawnFromPool (string tag, Vector3 position, Quaternion rotation)
{
if (!poolDictionary.ContainsKey(tag))
{
Debug.LogWarning("Tag doesn't exist");
return null;
}
GameObject objectToSpawn = poolDictionary[tag].Dequeue();
objectToSpawn.SetActive(true);
objectToSpawn.transform.position = position;
objectToSpawn.transform.rotation = rotation;
poolDictionary[tag].Enqueue(objectToSpawn);
return objectToSpawn;
}
}
This is the script for my Object Pooler, learned from a tutorial.
I then call the function in my ScrollingCity Script, where I try to get the transform value of the latest object created so I can compare them with the current object, but I can only get the transform of the first object pulled, until it reaches the end of the Queue.
if(Time.time > nextBuilding)
{
nextBuilding = Time.time + spawningRatio;
objectPooler.SpawnFromPool("Build", transform.position, Quaternion.identity);
lastBuilding = objectPooler.SpawnFromPool("Build", transform.position, Quaternion.identity);
Debug.Log(lastBuilding.transform.localScale);
}
And it only returns the transform of the first object in the log:
So my Question is how can I access the scale of the last object in the Queue, and compare it with the current to control the frequency with which they are created, and effectively keep the distance between each object the same regardless of scale?
In my project I have a window that contains an input field. The script for the window then spawns a prefab named whatever I input. The script that I have running in the prefab that is instantiated has a function that should change the text mesh into this new name. However, when i run this script the name changes for the first instantiated prefab and all further prefabs have a the default name I typed into the text mesh component.
My prefab has a child canvas that contains the child text mesh pro UGUI
This is the Code I use for the window
public Toggle EnableSwitch;
public TMP_InputField inputField;
public GameObject Entity;
public GameObject Panel;
public string nameText;
public void OpenPanel()
{
if(Panel != null)
{
bool isActive = Panel.activeSelf;
Panel.SetActive(!isActive);
if(isActive == true && EnableSwitch.isOn)
{
Produce();
}
}
}
public void NameAssign(string newName)
{
nameText = newName;
}
public void Produce()
{
float h = 2f * Camera.main.orthographicSize;
float w = h * Camera.main.aspect;
float x0 = 0 - w / 2;
float y0 = 0 - h / 2;
float x1 = x0 + w;
float y1 = y0 + h;
Vector3 position = new Vector3(Random.Range(x0, x1), Random.Range(y0, y1), 0);
print(nameText); //this is to make sure the name is being taken in
Entity.name = nameText; //this is to assure the entity is renamed
Instantiate(Entity, position, Quaternion.identity);
Debug.Log(Entity.name); // this is a second check
}
This is the code that I run within my prefab
public Color fillColor = Color.blue;
public Slider radiusAdjuster;
private MeshFilter _meshFilter;
private LineRenderer _lineRenderer;
private CircleCollider2D _circleCollider2D;
public float radius;
public void Awake()
{
_meshFilter = GetComponent<MeshFilter>();
_lineRenderer = GetComponent<LineRenderer>();
_circleCollider2D = GetComponent<CircleCollider2D>();
}
private void Update()
{
Create();
print(this.gameObject.name);
GameObject.Find("Canvas/Test").GetComponent<TextMeshProUGUI>().SetText(this.gameObject.name);
}
because GameObject.Find("Canvas/Test") always returns the same object.
It goes through the entire Hierarchy top to bottom and returns the first encountered object matching the search pattern -> Unless you reorder htem later, this will always be the first prefab you spawned.
They even give you a hint in the API for GameObject.Find:
Note: If you wish to find a child GameObject, it is often easier to use Transform.Find.
In your case it is not only easier but would be the only option since they will all have the same name in the Hierarchy. So if you rather want to Find an object below your own hierarchy you would want to use Transform.Find instead
transform.Find("Canvas/Test")
but you will have to provide the exact full valid path starting below that prefab object.
Note: Find does not perform a recursive descend down a Transform hierarchy.
Even better would actually be to simply referenced it via the Inspector and not use Find at all (see below)!
And still: Do NOT use it in Update .. rather store the references ONCE at the beginning. Currently it doesn't seem like you would need to do it in Update at all actually.
// Best would actually be to reference this here via the Inspector
// by drag and drop and not get it on runtime AT ALL
[SerializeField] private TextMeshProUGUI _testText;
private void Awake()
{
// Only as fallback store it only ONCE
if(!_testText)
{
_testText = transform.Find("Canvas/Test").GetComponent<TextMeshProUGUI>();
}
Create();
// this.name equals gameObject.name btw ;)
print(name);
_testText.SetText(name);
}
then later re-use _testText wherever needed.
This may seem like a stupid question but I'm stuck with it. I have GameObjects in a list (List<GameObject>) and I want to add them on the scene runtime, prefarbly on predefined places (like placeholders or something). What would be a good way to do it? I've been searching the net but can't really find anything that would solve this. This is my code so far:
public static List<GameObject> imglist = new List<GameObject>();
private Vector3 newposition;
public static GameObject firstGO;
public GameObject frame1;//added line
void Start (){
newposition = transform.position;
firstGO = GameObject.Find ("pic1");
frame1 = GameObject.Find ("Placeholder1");//added line
//this happens when a button is pressed
imglist.Add(firstGO);
foreach(GameObject gos in imglist ){
if(gos != null){
print("List: " + gos.name);
try{
//Vector3 temp = new Vector3 (0f, 0f, -5f);
Vector3 temp = new Vector3( frame1.transform.position.x, frame1.transform.position.y, -1f);//added line
newposition = temp;
gos.transform.position += newposition;
print ("position: " + gos.transform.position);
}catch(System.NullReferenceException e){}
}
}
}
How can I place the pics (5) on the predefined spots?
//----------------
EDIT: Now I can place 1 image to a placeholder (transparent png). For some reason z-value goes all over the place so it needs to be forced to -1f but that's OK. I add the images to the list from other scenes and there can be 1-5 of them. Do I need to put the placeholders in another list or array? I'm a bit lost here.
If you've already created 5 new objects you can just do like they do here:
http://unity3d.com/learn/tutorials/modules/beginner/scripting/invoke under the InvokeScript
foreach(GameObject gos in imglist)
{
Instantiate(gos, new Vector3(0, 2, 0), Quaternion.identity);
}
I don't really understand what you're trying to do, but if I'm correct and you have a list of objects, and you know where you want to move them at runtime, just make two lists,
one containing the objects and
one containing transforms of empty game-objects in the scene placed at those predefined positions, and match them at runtime.
Populate both lists from the inspector.
public List<GameObject> imglist = new List<GameObject>();
public List<Transform> imgPositions = new List<Transform>();
void Start()
{
for(var i = 0 i < imglist.Count; ++i)
{
imglist[i].transform.position = imgPositions[i].position
}
}
The general best way is to create prefabs for your objects, passing them as a parameter and instantiate when needed (Start in your case). That's the common case, but maybe yours is slightly different.
This is an example of passing a prefabs array and to instantiate one object for each one in the array:
public GameObject prefabs[];
List<GameObject> objects = new List<GameObject>();
void Start() {
for(GameObject prefab in prefabs) {
GameObject go = Instantiate(prefab, Vector3.zero, Quaternion.identity) as GameObject; // Replace Vector3.zero by actual position
objects.Add(go); // Store objects to access them later: total enemies count, restart game, etc.
}
}
In case you need several instances for the same prefab (multiple enemies or items, for instance) just adapt code above.