I'm instancing a small UI canvas with text to appear above a pick up on contact:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PickUpCheck : MonoBehaviour {
public GameObject pickUp;
public GameObject textBox;
public GameObject particle;
private Vector3 pickUpPos;
// Use this for initialization
void Start () {
pickUpPos = pickUp.transform.position;
}
void OnTriggerEnter2D(Collider2D collider)
{
Instantiate(particle, pickUpPos, new Quaternion());
Instantiate(textBox, pickUpPos , new Quaternion());
Destroy(pickUp.gameObject);
}
}
The canvas and text appear somewhere else though. Specifically, at the position of the text object I originally reference in the editor.
I'm not sure why this is overriding the position set in the instance code. I've moved the referenced canvas object prefab around (including to the origin) and re-referenced it to the pick up object and it always will appear at this position instead of the pick up position.
Edit - Just to clarify, pickUp is the game object this script is attached to. The GameObject particle is a particle effect set to instance when the object is collided with. It is unrelated to the current problem.
You're setting the position on Start() which means that it'll get set once when you start running the game.
Have you tried setting it when you need the current position, like this?
void OnTriggerEnter2D(Collider2D collider)
{
pickUpPos = pickUp.transform.position;
Instantiate(particle, pickUpPos, new Quaternion());
Instantiate(textBox, pickUpPos , new Quaternion());
Destroy(pickUp.gameObject);
}
So I found a simple solution to the problem - I assigned the instance of the created object to a variable and then set the position of that variable to the position of the pick up object:
void OnTriggerEnter2D(Collider2D collider)
{
pickUpPos = pickUp.transform.position;
textBox = Instantiate(textBox, pickUpPos , new Quaternion());
textBox.transform.position = pickUpPos;
Destroy(pickUp.gameObject);
}
Works as intended now.
Related
I'm trying to get all tiles around the player in unity 2d tileset.
What I would like to happen when player presses U I Would like to get all tiles surrounding the player including the one underneath the player or simply the one 1 tile in front of them.
I'm trying to make a farming Game where when the player pulls out an item it will highlight on the tilemap where they are about to place it.
Please note I'm not asking for full code, I just want what ever solution allows me to get tiles near the players position
Edit, found a solution by editing someone elses code but im not sure if there's a better way, if not I would also like this to work based on player rotation currently it places a tile above the player. Code Source https://lukashermann.dev/writing/unity-highlight-tile-in-tilemap-on-mousever/
using System.Collections;
using System.Collections.Generic;
using Unity.Mathematics;
using UnityEngine;
using UnityEngine.Tilemaps;
public class PlayerGrid : MonoBehaviour
{
private Grid grid;
[SerializeField] private Tilemap interactiveMap = null;
[SerializeField] private Tilemap pathMap = null;
[SerializeField] private Tile hoverTile = null;
[SerializeField] private Tile pathTile = null;
public GameObject player;
private Vector3Int previousMousePos = new Vector3Int();
// Start is called before the first frame update
void Start()
{
grid = gameObject.GetComponent<Grid>();
}
// Update is called once per frame
void Update()
{
var px = Mathf.RoundToInt(player.transform.position.x);
var py = Mathf.RoundToInt(player.transform.position.y);
var tilePos = new Vector3Int(px, py, 0);
if (!tilePos.Equals(previousMousePos))
{
interactiveMap.SetTile(previousMousePos, null); // Remove old hoverTile
interactiveMap.SetTile(tilePos, hoverTile);
previousMousePos = tilePos;
}
// Left mouse click -> add path tile
if (Input.GetMouseButton(0))
{
pathMap.SetTile(tilePos, pathTile);
}
// Right mouse click -> remove path tile
if (Input.GetMouseButton(1))
{
pathMap.SetTile(tilePos, null);
}
}
}
try to use the layer field inside the inspector, you can create new Layers inside the Project Manager and there you can easily create Layers like "Background" "Scenery" "Player" "Foreground".. after this you can assign them individually to your Tiles also its important to have different grids otherwise you will not be able to assign different layers to it i hope it worked already
I am new to unity and working on collision detection.
I have a rigidbody cube and an empty object with a cube mesh. The rigidbody cube moves with arrow keys and the empty object is static. Both have a box collider.
How do I detect collision between this empty object and the rigidbody cube?
I am wondering whether it should be OnCollisionEnter or OnTriggerEnter and how to use the correct command.
Thank you for your help.
First you need to set the box collider component to the cube and to the empty object with cube mesh. Then you can use this code:
using UnityEngine;
public class PlayerCollision : MonoBehaviour
{
public PlayerMovement movement;
public GAME_MANAGER GameManager;
private void OnCollisionEnter(Collision collisionInfo)
{
if (collisionInfo.collider.tag == "Obstacle")
{
movement.enabled = false;
}
}
}
Make sure you have set the tag of the obstacle to “Obstacle” and add this script to the player or the cube. Here,
movement.enabled = false;
You can apply you own logic according to your need.
Thanks
Here is the code in which I was talking about. I can't figure out why my collider isn't working:
using System.Collections.Generic;
using UnityEngine;
public class SphereCollider : MonoBehaviour
{
GameObject obj;
void Awake ()
{
obj = GameObject.FindGameObjectWithTag("Player");
}
// Update is called once per frame
void Update()
{
void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.name == "Player")
{
obj.GetComponent<Health>().health -= 25;
}
}
}
}
Rather than using the code you have, make sure to change some code. This is what you should change: get rid of the obj variable and the awake function. Then instead of finding the object with that name, use tag. Also get rid of Update(){} and take the OnCollisionEnter(){} out of it.
A few more changes are shown in code:
void OnCollisionEnter(Collision collision){
var obj = collision.GameObject;
if (obj.Tag == “Player”){
obj.GetComponent<Health>().health -= 25;
}
}
This will work as long as: the script is called Health, the variable inside Health is called health, and it is set to a float, and the player’s tag is set to Player.
Not sure if the code pasted in the question is just copied over wrong, but OnCollisionEnter() is its own unique method and should not be nested in Update().
If the player will be colliding with this Sphere object often, it is good to cache a component rather than using GetComponent frequently. However I assume in your case this Sphere will be one of many obstacles, so calling the GetComponent in the collision is fine. The issue with your current code is the gameObject you are colliding with might not have the name exactly spelled as Player, which would make your collision check fail. Caching the object that has the tag of Player is a bit redundant when you can just check it inside of the collision check.
I will use your entire snippet of code so there is no confusion
using System.Collections.Generic;
using UnityEngine;
public class SphereCollider : MonoBehaviour
{
void OnCollisionEnter(Collision col)
{
// compare if the collider's gameObjects tag is equal to our target tag (Player)
if (col.gameObject.tag == "Player")
{
// get the component of Health on our gameObject that we collided with that has the tag of Player
obj.GetComponent<Health>().health -= 25;
}
}
}
I am following an Unity tutorial. I face a problem when trying to detect collision in the game. This is the error:
NullReferenceException: Object reference not set to an instance of an object
This is the script:
using UnityEngine;
public class Collide : MonoBehaviour
{
public Movement movement; // A reference to our PlayerMovement script
// This function runs when we hit another object.
// We get information about the collision and call it "collisionInfo".
void OnCollisionEnter(Collision collisionInfo)
{
// We check if the object we collided with has a tag called "Obstacle".
if (collisionInfo.collider.tag == "Obstacle")
{
movement.enabled = false; // Disable the players movement.
Debug.Log("Coollision occured");
}
}
}
As i saw in the second image you have not added the movement reference to the movement field. At the same in the script also you are not assigning the reference. Try to assign at editor or you can create object.
The reason is you have not set the movement field in your Collide component.
You can add it from the Unity Editor or add the following line in your Start function of Collide :
void Start()
{
movement = GetComponent<Movement>();
}
I try to create a VR scene in unity using google cardboard sdk. I add a cube and CardboardMain.prefab to scene. There is an example scene that detect focus on cube. Its hierarchy view is :
I don't know how to add GUIReticle object or prefab like as the image.
How can I detect focus on an object?
Actually you could make the script by your own and it is quite simple.
You could detect whether the user is looking at your object or not by using RayCast from the Main Camera. If the RayCast hit your object, then it is being focused on.
For example:
using UnityEngine;
using System;
[RequireComponent(typeof(Collider))]
public class LookableObject : MonoBehaviour {
[SerializeField]
Transform cam; // This is the main camera.
// You can alternately use Camera.main if you've tagged it as MainCamera
bool focus; // True if focused
Collider gazeArea; // Your object's collider
public void Start () {
gazeArea = GetComponent<Collider> ();
}
public void Update () {
RaycastHit hit;
if (Physics.Raycast (cam.position, cam.forward, out hit, 1000f)) {
focus = (hit.collider == gazeArea);
} else {
focus = false;
}
}
}
Edit: This is just an example. You probably would want to make a script to do the Raycast only just once instead of doing the Raycast on each of your object over and over again to make your project runs faster.