How to move gameObject to a random object with specific tag - c#

I am trying to figure out how to make an object move to the position of another object that has a specific tag. I currently have an object array that contains all of the "choices" the object has. Then I get a random number from 0 to the number of objects found. I tested this part and it seems to work well.
What I am stuck on is moving the object the script is on to the position of the object the script finds. What I think I need to do is to get the object associated with the index number and its position, but that isn't working. Thanks in advance! Sorry if this question isn't structured correctly, this is my first post!
public class objective : MonoBehaviour
{
GameObject moveTo;
public GameObject[] gameObjectChoices;
public float choiceNumber;
void Start()
{
//get objects with tag and apply it to object array
gameObjectChoices = GameObject.FindGameObjectsWithTag("RandomCheesePoint");
//choose one of the gameObjects in array
choiceNumber = Random.Range(0, gameObjectChoices.Length);
Debug.Log(choiceNumber);
//move object to random object found
transform.position = gameObjectChoices[choiceNumber].gameObject.transform.position;
//problem occurs at gameObjectChoices[choiceNumber]
//error message says "Cannot implicitly convert type 'float' to 'int' An explicit conversion exists (are you missing a cast?)"
}
}

Your problem is you are attempting to index an array using a float value instead of an int.
Random.Range() will return an the same type as it's input parameters (in your case int) but this value is getting implicitly cast to a float because you declared your variable as:
public float choiceNumber;
If you change this to:
public int choiceNumber;
Then your code should work perfectly.

Related

why when i try having my player teleport to the object it says this?

My error is
CS0029 Cannot implicitly convert type 'UnityEngine.GameObject' to 'UnityEngine.Vector3'
Code:
{
GameObject snowball = GameObject.Find("LaunchSlingshotProjectile").GetComponent<SnowballThrowable>().projectilePrefab;
GorillaLocomotion.Player.Instance.transform.position = snowball;
}
I tried adding it to a variable but it didn't do anything
GameObject snowball = GameObject.Find("LaunchSlingshotProjectile")
Now snowball is a GameObject;
SnowballThrowable sbthrowable = snowball.GetComponent<SnowballThrowable>();
sbthrowable is a Component.
GameObject tile = sbthrowable.projectilePrefab;
tile is a GameObject variable which defined by yourself.
Vector3 pos = tile.transform.position;
The pos variable's type is Vector3, Only variables of the same type can be assigned.
GorillaLocomotion.Player.Instance.transform.position = pos;
Try
GorillaLocomotion.Player.Instance.transform.position = GameObject.Find("LaunchSlingshotProjectile").GetComponent<SnowballThrowable>().projectilePrefab.transform.position;
Your error is that you are trying to set a position
GorillaLocomotion.Player.Instance.transform.position = ...
which is a Vector3, and you are passing a GameObject for it, so the compiler doesn't understand.
A tip would be storing whatever GameObject.Find("LaunchSlingshotProjectile") is in a variable so that you don't perform this operation all the time, since Find is slow.

Passing the cycle from the beginning to the end (Or vice versa)

Good afternoon guys, such a question, I'm doing an array with brute force. I can't understand why assigning a value from the last element of the FrezeTree array to the BufferObject works in the Start() method, but this does not happen in Update.
So.
At the start of the scene, there is a search for all objects with the Tree tag (This is a temporary and debag solution):
FrezeTree = GameObject.FindGameObjectsWithTag("Tree");
Then, this list is passed to the array:
public GameObject[] FrezeTree;
Next, I'm trying to pass one element from the array to another object (This happens in the Start() method):
foreach (GameObject gm in FrezeTree)
{
BufferObject = gm;
}
But it turns out that only the last element is transmitted (Because of My own crookedness, since I don't know how to fix it yet). Why do I need a Buffer Object? From it I get the X position of the object, which I use for other purposes. The idea is to transfer one element from the array to the object, and when the object ceases to exist (Gets the null status), it goes to the element above / below (No matter in what order). Yes, I know that in what I have given above and I do not feel that I am trying to make a transition or skip an element from the array. I found various solutions on the great Internet, but the result was always the same, gets the last element and does not choose another one. That's why I turned here.
As I understand you want to
set one closest target object
wait until it is destroyed
go to the next closest target object
You could do this by simply checking whether the BufferObject is already set and still alive like e.g.
using System.Linq;
...
public GameObject BufferObject;
private void Update ()
{
// This means BufferObject is either not assigned yet or was destroyed
if(!BufferObject)
{
BufferObject = FindClosestTarget();
}
}
private GameObject FindClosestTarget ()
{
// Get all currently existing trees
// since this happens only once in a while it should be okey to repeat this call
return GameObject.FindGameObjectsWithTag("Tree")
// order them by distance
.OrderBy(gm => (transform.position - gm.transform.position).sqrMagnitude)
// get the first one or null if there was none
.FirstOrDefault();
}
This way it would also take trees that are spawned later into account.
If you rather want to cache this array only once you can still do this like
private GameObject [] trees;
public GameObject BufferObject;
private void Start ()
{
trees = GameObject.FindGameObjectsWithTag("Tree");
}
private void Update ()
{
// This means BufferObject is either not assigned yet or was destroyed
if(!BufferObject)
{
BufferObject = FindClosestTarget();
}
}
private GameObject FindClosestTarget ()
{
// First filter out any null or destroyed objects
return trees.Where(t => t)
// Then order the rest by distance
.OrderBy(gm => (transform.position - gm.transform.position).sqrMagnitude)
// Then pick the first one or null if there isn't any
.FirstOrDefault();
}
See
Linq Where
Linq OrderBy
Linq FirstOrDefault
implicit UnityEngine.Object.bool operator
In general, I figured out how to implement everything myself. So, the code:
public GameObject[] FrezeTree; //Array of all objects in the scene
private void Start()
{
FrezeTree = GameObject.FindGameObjectsWithTag("Tree"); //Finding all objects with a tag (I do not recommend using tags due to the lack of code navigation)
}
private GameObject FindClosestTarget()
{
return False True.Where(t => t).FirstOrDefault(); //Assigning and sorting an array with objects from the scene, thanks #derHugo
}
void Update()
{
BufferObject = FindClosestTarget(); //will be Assigned the next element of the array, in case the current will become "null"
if (BufferObject == null)
{
Debug.Log("debug for (BufferObject == null)"); //arbitrary code in the case that any object on the stage left.
}
}
P.S. This code is perfect for creating a simple AI for NPCs in your game. It's not perfect, but at least something is better than nothing :) Thanks #derHugo

Downcasting an entire array

In Unity I am trying to detect all the components of type text on an object
this.GetComponents(typeof(Text))
but it returns an array of components.
Since I know every component must be of type text I should be able to downcast it.
I tried to explicit cast it
Text[] a = (Text[])this.GetComponents(typeof(Text));
but that didn't work.
Text is a derived class of component, but I don't know how to downcast the array so I can use the methods that are associated with type text. Can someone show me how I can convert the array to one of the type Text?
From the docs, you can use the generic method GetComponents without needing to type cast each.
using UnityEngine;
public class Example : MonoBehaviour
{
void Start()
{
HingeJoint[] hinges = GetComponents<HingeJoint>();
for (int i = 0; i < hinges.Length; i++)
{
hinges[i].useSpring = false;
}
}
}
You should use the generic syntax: this.GetComponents<Text>(). That returns a Text[] so no need to cast anymore.

Array.FindIndex Always Got Null in unity C#

I don't know why my script below in unity c# always got null ?
public class WeatherControl : MonoBehaviour {
public GameObject Rain;
public int[] RainTime = new int[]{6,7,8,9,10,18,19,20,21,22,16};
int day;
System.DateTime dates;
// Use this for initialization
void Start () {
dates = System.DateTime.UtcNow;
day = (int) dates.Day;
//day = 16;
Debug.Log ("DAY : " + day);
int posRain = System.Array.FindIndex (RainTime, x => x.Equals(16));
Debug.Log ("POS RAIN : " + posRain);
if (posRain >= 0) {
Rain.SetActive (true);
} else {
Rain.SetActive (false);
}
}
}
my variable int posRain always return -1 Even at array there is value contain it. the variable day contain 16. I put it manually and type 16 too. But always return -1.
I don't know why.
I have try this too :
int posRain = System.Array.IndexOf (RainTime, day);
That's always return -1 too.
I have tested it at online C# Tester here : https://csharppad.com/
It works at it return 10.
But in unity c# editor it is different always return -1.
Could someone explain what is going on ?
Thanks
Dennis
Your array is public, so it's serialized by Unity. Unity will set the array to the value you gave it in inspector, overriding the one you declared in the code. If you don't need to access the array from the inspector, you should use [NonSerialized] attribute. If you do need to access it from inspector, you should also edit it from there.
Finally Got The ANSWER....
And finally this is a little thing we should remember. Sometimes this can make us onfused.
Once you update the array value at script. Don't forget to resetting or reattach the script that contain array value in the inspector. When you resetting or reattach the script all the value array size will update.
For example :
in script you have an array :
public int[] RainTime = new int[]{6,7,8,9,10,18,19,20,21,22};
This is not include 16 in array. Now you run the code in editor.
In the inspector you will see that array size contain value of all RainTime array value.
Now back to the script update the array value at :
public int[] RainTime = new int[]{6,7,8,9,10,18,19,20,21,22,**16**};
You have put 16 at last array. Now Run the code in editor. And see in the inspector array size value, Value 16 is not contain at array in the inspector even you have update it via script.
What you should you is to Reset The value from inspector OR reattact the script from inspector. It will update the value and now array in the inspector now contain value 16 too.
Thanks

C# & Unity : Pass reference by value?

I'm new to C# and Unity, and here I am tweaking and creating my first minigame.
Here is the problem:
I've got a little cube, that moves. I've implemented a method that checks the next position before making a move.
The method receives as parameters the current cube position, and the direction:
public bool okToMove(Transform playerCurrentPosition , int directionIndex)
{
Transform playerNextPosition = playerCurrentPosition;
playerNextPosition.Translate(toDirection(directionIndex));
if (playerNextPosition.position.x > 1 ||
playerNextPosition.position.x < -1 ||
playerNextPosition.position.y > 1 ||
playerNextPosition.position.y < -1)
return false;
else
return true;
}
Then, I call the method
public void movePlayer(int directionIndex)
{
if ( okToMove(gameObject.transform, directionIndex) )
transform.Translate(toDirection(directionIndex));
}
The problem is that the cube makes 2 moves at once. This is because of
transform.Translate(toDirection(directionIndex));
and
playerNextPosition.Translate(toDirection(directionIndex));
that is called from okToMove method. Unity or C# sees playerNextPosition as the real cube, and not somekind of temporary copy that only exists inside the method.
So why is my gameObject.transform being passed as a reference and not by value? How can I make it work?
Thanks in advance and sorry for my noobiness.
You are passing reference to Transform and then moving it with translate in "okToMove", best way is to make a copy of Vector3, just change your "okToMove" like this.
public bool okToMove(Transform playerCurrentPosition , int directionIndex){
Vector3 playerNextPosition = playerCurrentPosition.position;
playerNextPosition += toDirection(directionIndex);
if (playerNextPosition.x > 1 ||
playerNextPosition.x < -1 ||
playerNextPosition..y > 1 ||
playerNextPosition.position.y < -1)
return false;
else
return true;
}
Transform is component attached to each gameObject and it holds values for position, rotation and scale, so your "playerCurrentPosition" is not copy of position but rather reference to Transform (not a copy).
Create a new GameObject that is a copy of yours original, and use its transform to make your calculations. (This answer is originally from the Unity forums). The official documentation tells me you can use Object.Instantiate to create a clone of a GameObject.
In C#, objects have always their reference passed as value, so simply reassign won't do it. See this related question.
Objects in C# are passed by reference. If you want to copy an object, implement the ICloneable interface which has the method Clone(). You will need to copy the object yourself and return it from this method.

Categories