Unity, Spawn a prefab to "nearestTarget" gameObject's location - unity3d

I'm creating a game where objects are being created. These objects are moving left and the player has to press space bar before the object reaches the end of the screen. Every thing works fine with the exception of spawning a prefab on the moving objects.
The idea is to spawn a animation on the nearest target. But when instantiated, the prefab always instantiate at the prefab location (0,0,0). How do I make the instantiated prefab spawn at the correct place? (I've tested with print(nearestTarget.transform.position) and the print always gives me a different location depending on the "nearestTarget")
Trying to spawn the prefab in HandSlapAnimation() Method.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerInput : MonoBehaviour
{
// Reference to levelManager
[SerializeField] LevelManager levelManager;
// Array of all present entities
private GameObject[] targets;
// Nearest entity
private GameObject nearestTarget;
// Array of all x position of all present entities
private float[] locationOfTargets;
// Nearest x position (transform.position.x) in all entities
private float nearestLocation;
// Finds the index location of the float value
private int index;
// Hand prefab to be instantiate during Keypress
public GameObject handPrefab;
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
targets = GameObject.FindGameObjectsWithTag("Entities");
if (targets.Length > 0)
{
FindLocationOfEntities();
AssignNearestTarget();
HandSlapAnimation();
DestroyNearestTarget();
}
}
}
void FindLocationOfEntities()
{
locationOfTargets = new float[targets.Length];
for (int i = 0; i < targets.Length; i++)
{
locationOfTargets[i] = targets[i].transform.position.x;
}
}
void AssignNearestTarget()
{
nearestLocation = Mathf.Min(locationOfTargets);
index = System.Array.IndexOf(locationOfTargets, nearestLocation);
nearestTarget = targets[index];
}
void DestroyNearestTarget()
{
if (nearestTarget.GetComponent<CubeMovement>().isCat == true)
{
levelManager.LoadLevel("Game Over");
}
else
{
Destroy(nearestTarget);
}
}
void HandSlapAnimation()
{
// Instantiate prefab Hand GameObject at the nearest target to execute the Hand Slap animation
Instantiate(handPrefab, transform.position, Quaternion.identity);
handPrefab.transform.SetParent(nearestTarget.transform);
print(nearestTarget.transform.position);
}
}

The problem is that in:
Instantiate(handPrefab, transform.position, Quaternion.identity);
The transform.positionis the position of the actual object, your PlayerInput instance.
Then, you do: handPrefab.transform.SetParent(nearestTarget.transform) but that doesn't move the position, only sets the parent.
Instead of using transform.position in the Instantiate method, use nearestTarget.transform.position.
Instantiate(handPrefab, nearestTarget.transform.position, Quaternion.identity);

Related

Interacting with 3D object placed on Vuforia's ground plane using ray casting

Hello so I've been looking for a solution for my problem but looks like there is absolutely nothing about it.
I'm working on a scene where I have some 3D object renderred on a ground plane and my goal is making an animation on that 3D object start by tapping it. I'm using latest version of vuforia 10.4 with Unity 2020.3.9f1. I have a script for instantiating the 3d Model and making the plane finder disappear as long as it doesn't lose tracking.`using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class sceneManager : MonoBehaviour
{
private string level = "snake";
public GameObject[] renderredPrefab;
public GameObject ground;
public GameObject groundFinder;
private int levelChecker(string levelName)
{
if (levelName == "snake")
return 0;
else return 1;
}
public void spawnObject(int i)
{
Instantiate(renderredPrefab[levelChecker(level)], new Vector3(0, 0, 0), Quaternion.identity, ground.transform);
}
public void groundFinderOff()
{
groundFinder.SetActive(false);
}
public void groundFinderOn()
{
groundFinder.SetActive(true);
}
}
And another one to trigger the animation following the game object's tag hereusing System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class animationTriggerManager : MonoBehaviour
{
private Animator m_Animator;
private string objectName;
private GameObject[] eos;
private GameObject snake;
[SerializeField]
private Camera ARCamera;
// Start is called before the first frame update
void Start()
{
// Get the different eos present on the scene
for (int i = 0; i < eos.Length; i++)
{
eos[i] = GameObject.FindWithTag("myEolienne" + i);
}
// Get snake game objecct in the scene
snake = GameObject.FindWithTag("Snake");
}
// Update is called once per frame
void Update()
{
if (Input.touchCount > 0 && Input.touches[0].phase == TouchPhase.Began)
{
Ray ray = ARCamera.ScreenPointToRay(Input.GetTouch(0).position);
if (Physics.Raycast(ray, out RaycastHit hit))
{
objectName = hit.collider.name;
Debug.Log("raycast touched " + hit.transform.name);
switch (objectName) //Get the Animator depending on which gameObject been tapped on.
{
case "myEolienne1":
m_Animator = eos[0].GetComponent<Animator>();
// Launch the animation on the gameObject that's been tapped
m_Animator.SetTrigger("Helice_Rotate");
Debug.Log("rotate launched");
break;
case "myEolienne2":
m_Animator = eos[1].GetComponent<Animator>();
// Launch the animation on the gameObject that's been tapped
m_Animator.SetTrigger("Helice_Rotate");
Debug.Log("rotate launched");
break;
case "myEolienne3":
m_Animator = eos[2].GetComponent<Animator>();
// Launch the animation on the gameObject that's been tapped
m_Animator.SetTrigger("Helice_Rotate");
Debug.Log("rotate launched");
break;
case "Snake":
m_Animator = snake.GetComponent<Animator>();
m_Animator.SetTrigger("snakeMoving");
break;
}
}
}
}
}
`
Note that each 3D model has different parts grouped in one parent that has a mesh collider on the parent only.enter image description here
The rendering works perfectly but I can't figure out what's wrong with my raycasting script. Note that I first tried with 3D model on image target and it worked fine.
Thanks in advance !

Spawn in a fix position 2D Game

I am trying to do a multiplayer game and I have a problem with spawning prefabs. I want this prefabs to be spawn in 2 fix position but I don't understand why my script doesn't work because when I start the game the objects are spawn in one position. I created an empty game object( I named it Spawner and added the script) and added 2 game objects ( Position1 , Position2 ) as Childs. The prefab is spawn in the position of the Spawner and not position 1 and 2 .
Here is the script I used. Also do I have to add to it PhotonView and Photon Transform ? and something with PunRPC?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SpawnPosition : MonoBehaviour
{
public GameObject[] powersPrefab;
public Transform[] points;
public float beat= (60/130)*2;
private float timer;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
if (timer > beat)
{
GameObject powers = Instantiate(powersPrefab[Random.Range(0, 2)]);
powers.transform.localPosition = Vector2.zero;
timer -= beat;
}
timer += Time.deltaTime;
}
}
You always set
powers.transform.localPosition = Vector2.zero
The object is instantiated on root level without a parent this equals setting its absolute position .... you always set it to the Unity origin.
You probably wanted to spawn it at the position of on of the elements in points like e.g.:
var powers = Instantiate(
powersPrefab[Random.Range(0, powersPrefab.Length)],
points[Random.Range(0, points.Length)].position,
Quaternion.identity
);
see Instantiate for available overloads.
However as you also state this is for multiplayer so you shouldn't use Instantiate at all since this only spawns this object on this client but not on others. You should probably rather make sure that this spawner is only running on one of your clients and use PhotonNetwork.Instantiate instead.
Something like e.g.
public class SpawnPosition : MonoBehaviour
{
public GameObject[] powersPrefab;
public Transform[] points;
public float beat= (60/130)*2;
private float timer;
// Update is called once per frame
void Update()
{
// only run this if you are the master client
if(!PhotonNetwork.isMasterClient) return;
if (timer > beat)
{
// spawn the prefab object over network
// Note: This requires you to also reference the prefabs in Photon as spawnable object
Instantiate(
powersPrefab[Random.Range(0, 2)].name,
points[Random.Range(0, points.Length)].position,
Quaternion.identity,
0
);
timer -= beat;
}
timer += Time.deltaTime;
}
}
This should work
void Update() {
if (timer > beat) {
GameObject powers = Instantiate(powersPrefab[Random.Range(0, 2)]);
powers.transform.localPosition = points[Random.Range(0, points.Length)].position;
timer -= beat;
}
timer += Time.deltaTime;
}
}
You are not assigning right position, and since they are parentless power.transform.position = Vector2.zero means that power's global position would always 0,0,0. So you must assign it as I wrote above, and it's also randomized.

Create Primitive and then Move it Right After

I have a script that deletes a cube primitive and then creates a new sphere primitive. How would I then move that sphere primitive?
void OnCollisionEnter(Collision collision)
{
if (collision.collider.gameObject.tag != "Destroy")
{
GameObject sphere = GameObject.CreatePrimitive(PrimitiveType.Sphere);
sphere.transform.SetPositionAndRotation(gameObject.transform.position, gameObject.transform.rotation);
Destroy (gameObject);
}
}
Here is how I would do it.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Main : MonoBehaviour
{
public GameObject sphere;
private bool spawnSphere = false;
private GameObject sphereThatIWantToMove;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
if (spawnSphere)
{
sphereThatIWantToMove = Instantiate(sphere, new Vector3(0, 0, 0), Quaternion.identity);
spawnSphere = false;
}
//Code that moves the sphere
}
}
In my code I added a public GameObject, so that I could load a sphere prefab to it.
Then you instantiate that prefab, but store the instance in another GameObject variable, then you can just use GameObject.Transform.Position to move it around.
Some more detail on actually moving the sphere:
float x = sphereThatIWantToMove.transform.position.x;
float y = sphereThatIWantToMove.transform.position.y;
float z = sphereThatIWantToMove.transform.position.z;
if (Input.GetKeyDown(KeyCode.UpArrow))
{
y--;
}
if (Input.GetKeyDown(KeyCode.LeftArrow))
{
x--;
}
if (Input.GetKeyDown(KeyCode.DownArrow))
{
y++;
}
if (Input.GetKeyDown(KeyCode.RightArrow))
{
x++;
}
if (Input.GetKeyDown(KeyCode.PageUp))
{
z--;
}
if (Input.GetKeyDown(KeyCode.PageDown))
{
z++;
}
sphereThatIWantToMove.transform.position = new Vector3(x, y, z);
The GameObject's coordinates are stored as a Vector3 in Transform.Position. You cannot edit that value directly, instead you have to break the values out (they're floats) using GameObject.Transform.Position.x, GameObject.Transform.Position.y, and GameObject.Transform.Position.z. Then you change those values and load them back in with a "new Vector3"
I hope that helps!

Destroying Prefabs Object After Spawn Using collision

I currently have some objects spawning from a prefab and am attempting to destroy only one of the spawned items of that prefab. I was searching online and I found tons of different examples but I have been unable to get any of them to work. I tried setting up an instance of the Instantiate and destroying that instance but I am unable to get it to work. The spawn/collision script is attached to the main camera if that matters. Collision with other items in my game work and the prefab does have a box collider set to isTrigger. Again, I know there are plenty of examples explaining this etc, but I can't get it to work and maybe I am not understanding what I actually should be doing.
Spawner code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class bloodVialSpawner : MonoBehaviour
{
public GameObject vialOfBlood;
private GameObject vialss;
private int hunger =10;
public int numOfVials;
public int minSpawnRange, maxSpawnRange;
public int minSpawnRange2, maxSpawnRange2;
// Start is called before the first frame update
float timeSpawns = 2;
List<GameObject> vialsInstantiated = new List<GameObject>();
void Start()
{
StartCoroutine(becomeHungry());
InvokeRepeating("SpawnVials", timeSpawns, timeSpawns);
}
private void Update()
{
if (hunger == -1)
{
Debug.Log("sigh");
}
}
void SpawnVials()
{
for (int i = 0; i < numOfVials; i++)
{
vialsInstantiated.Add(Instantiate(vialOfBlood, SpawnPosition(), Quaternion.identity) as GameObject);
}
}
Vector3 SpawnPosition()
{
int x, y, z;
y = 59;
x= UnityEngine.Random.Range(minSpawnRange, maxSpawnRange);
z = UnityEngine.Random.Range(minSpawnRange2, maxSpawnRange2);
return new Vector3(x, y, z);
}
IEnumerator becomeHungry()
{
while (true)
{
hunger -= 1;
yield return new WaitForSeconds(1);
Debug.Log(hunger);
}
}
}
Spawner Script is on the Main Camera. Player used is the First Person Player Unity provides.
Code for destroying spawned object:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class destroyVial : MonoBehaviour
{
void OnTriggerEnter(Collider col)
{
if (col.gameObject.tag == "vials")
{
Destroy(col.gameObject);
Debug.Log("yell");
}
}
}
Destroy code is on prefab. Note prefab is not in hierarchy as it should not be.
Firstly,
I see that you're spawning things in a for-loop and overwriting the vialss variable every time:
for (int i = 0; i < numOfVials; i++)
{
vialss = Instantiate(vialOfBlood,
SpawnPosition(),
Quaternion.identity) as GameObject;
}
And then, on collision, you're Destroying vialss, which in this case will be the latest spawned object. And if you collide with anything after 1 collision, vialss will already be deleted and probably throw an exception. Maybe that's fine in your game, but the logic looks a bit flawed.
Also, I'm assuming you want to destroy the object you're colliding with? Does something like this not work?
void OnTriggerEnter(Collider col)
{
if (col.gameObject.tag == "vials")
{
Destroy(col.gameObject); // <== Remove colliding object
Debug.Log("yell");
}
}
If you, for some unrelated reason, need a list of all your spawned vials, maybe you'd like to convert that to a list instead:
List<GameObject> spawnedVials = new List<GameObject>();
void SpawnVials()
{
for (int i = 0; i < numOfVials; i++)
{
var vial = Instantiate<GameObject>(vialOfBlood,
SpawnPosition(),
Quaternion.identity)
spawnedVials.Add(vial);
}
}
Finally,
make sure that the collision detection is working. You're saying that the script is attached to your camera. please make sure you have a Collider on the camera. But you're saying that other colliders are working, so I'm guessing you have this under control.
I'd guess your issue lies in the flawed logic I initially described.
OnTriggerEnter needs to be on a script attached to the object it's colliding with, or the vial itself. It can't be on the main camera as OnTriggerEnter will never get called.
I would recommend you to keep scripts to one job, you should split that script into a Spawn script and a Collider script. And create a empty GameObject with the sole purpose of spawning prefabs.
Also there's some errors in your code:
void OnTriggerEnter(Collider col)
{
if (col.gameObject.tag == "vials")
{
Destroy(col.gameObject); // Destroy the gameObject you're colliding with
Debug.Log("yell");
}
}
Also the variable vialss isn't doing what you're expecting, vialss is only referencing to the last instantiated vial, so better save all vials in a List:
List<GameObject> vialsInstantiated = new List<GameObject>();
And then:
void SpawnVials()
{
for (int i = 0; i < numOfVials; i++)
{
vialsInstantiated.Add(Instantiate(vialOfBlood, SpawnPosition(), Quaternion.identity) as GameObject);
}
}

Object not destroying after reaching a certain point Unity

Okay so i'm making an infinite runner and the technique I've used is to keep the player static and move and instantiate the platform objects.
For that I've created an Array List of objects that are the platforms.
And then I'm adding them in and spawning them.
I am also translating them along the z-axis and i want to destroy the objects that go below 0 in the z axis and then add another object in replacement.
The problem is that it doesn't translate the objects unless I add another script just to do that and it doesn't destroy or add even if I add another script for translation.
My code is as follows. If you have trouble understanding my problem, please ask I would try to explain again.
I have two scripts.
1) PlatformManager: This one is applied on the empty GameObject and contains the ArrayList.
public class PlatformManager : MonoBehaviour
{
[HideInInspector]
public List<GameObject> platforms = new List<GameObject>(); // List of Platfroms.
public GameObject[] prefab; // Allow user to add as many prefabs through the inspactor.
public static float noOfPlatforms; // a variable to hold how many platoforms.
[HideInInspector]
public static float objectPosition; // Z position of the game object.
[HideInInspector]
public static float objectScale;
// Use this for initialization
void Start ()
{
noOfPlatforms = 6.0f;
objectPosition = 0.0f;
objectScale = 0.0f;
platforms.Add((GameObject)Instantiate(prefab[Random.Range(0,prefab.Length)], new Vector3(0,0,0) ,Quaternion.identity));
//platforms.Add((GameObject)Instantiate(prefab[Random.Range(0, prefab.Length)], new Vector3(0, 0, 40.40114f), Quaternion.identity));
for(int i = 0; i < noOfPlatforms; i++){
objectScale = platforms[platforms.Count-1].transform.localScale.z;
objectPosition = platforms[platforms.Count-1].transform.localPosition.z;
platforms.Add((GameObject)Instantiate(prefab[Random.Range(0,prefab.Length)], new Vector3(0,0,(objectPosition + objectScale)+277f) ,Quaternion.identity));
}
}
// Update is called once per frame
void Update ()
{
}
}
2) PlatformController: This one is supposed to instantiate and destroy and translate the objects.
public class PlatformController : MonoBehaviour {
//private bool canBeDestroy = true; // Flag to check whether the gameObject shoud be destroyed or not.
[HideInInspector]
public PlatformManager managePlateform; // Reference to plateformManager script.
[HideInInspector]
public float plateformSpeed = 10f;
[HideInInspector]
public GameObject allPlatforms;
[HideInInspector]
// Awake is called when the script instance is being loaded.
void Awake()
{
// Accessing the plateformManager script for the Plateform.
managePlateform = GameObject.FindGameObjectWithTag("Platform").GetComponent<PlatformManager>();
}
void Start()
{
}
// Update is called once per frame
void Update()
{
// Get the first platform object.
GameObject firstPlatform = managePlateform.platforms[0];
// Get the last platform object.
GameObject lastPlatform = managePlateform.platforms[managePlateform.platforms.Count - 1];
if (firstPlatform.transform.localPosition.z < 0f)
{
Destroy(firstPlatform.gameObject); // destroy the first plateform gameObject.
managePlateform.platforms.Remove(firstPlatform); // also remove the destroyed object from the list.
// When the game object is destroyed then instantiate one gameobject into list and add at the last point.
managePlateform.platforms.Add((GameObject)Instantiate(managePlateform.prefab[Random.Range(0, managePlateform.prefab.Length)], new Vector3(0, 0, (lastPlatform.transform.localPosition.z + lastPlatform.transform.localScale.z) + 277f), Quaternion.identity));
}
// Move the available platforms in the list along the z-axis
foreach (GameObject platform in managePlateform.platforms)
{
platform.transform.Translate(0, 0, -plateformSpeed * Time.deltaTime);
}
}
}