I've created a simple scene and I'm now trying to make a rabbit move to the mouse-click position on a Plane.
So I've added a Rigidbody, a Nav Mesh Agent and a simple "Pathfinding" script to the rabbit.
The planes Mesh Renderer is set to "Navigation Static", "Generate OffMeshLinks" and "Walkable"
Now as soon as the rabbit gets close to the given destination, it will not stop but rather is "running around" in a very small circle around the destination.
Here is my script
using UnityEngine;
using UnityEngine.AI;
public class Pathfinding : MonoBehaviour {
private NavMeshAgent agent;
private Animator animator;
// Use this for initialization
void Start() {
agent = GetComponent<NavMeshAgent>();
animator = GetComponent<Animator>();
}
// Update is called once per frame
void Update() {
RaycastHit hit;
if(Input.GetMouseButtonDown(0)) {
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if(Physics.Raycast(ray, out hit)) {
agent.SetDestination(hit.point);
animator.SetInteger("AnimIndex", 1);
animator.SetBool("Next", true);
}
}
}
}
and a picture of my rabbit object ;)
Stopping Distance should be > 0
Actually I was wrong, updating Unity didn't fix the problem, but I recognized that the problem was that the animations "Root Transformation Position (XZ)"/ Bake Into Pose was deactivated.
I also changed my script to
using UnityEngine;
using UnityEngine.AI;
public class Pathfinding : MonoBehaviour {
private NavMeshAgent agent;
private Animator animator;
private bool run = false;
// Use this for initialization
void Start() {
agent = GetComponent<NavMeshAgent>();
animator = GetComponent<Animator>();
}
// Update is called once per frame
void Update() {
RaycastHit hit;
if(Input.GetMouseButtonDown(0)) {
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if(Physics.Raycast(ray, out hit)) {
Debug.Log("start");
agent.SetDestination(hit.point);
animator.SetInteger("AnimIndex", 1);
animator.SetBool("Next", true);
run = true;
}
}else if(agent.remainingDistance <= agent.stoppingDistance && run) {
Debug.Log("stop");
animator.SetInteger("AnimIndex", 0);
animator.SetBool("Next", true);
run = false;
}
}
}
Related
NullReferenceException: Object reference not set to an instance of an object
DragBlock.Update () (at Assets/Script/DragBlock.cs:13)
using UnityEngine;
public class DragBlock : MonoBehaviour
{
private bool isBeingHeld = false;
private Vector3 startPos;
private Transform heldObject;
private void Update()
{
if (Input.GetMouseButton(0))
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if (Physics.Raycast(ray, out hit))
{
if (hit.transform.CompareTag("Blocks"))
{
isBeingHeld = true;
startPos = hit.transform.position;
heldObject = hit.transform;
}
}
}
if (isBeingHeld)
{
Vector3 currentMousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
currentMousePos.z = heldObject.position.z;
heldObject.position = currentMousePos;
}
if (Input.GetMouseButtonUp(0))
{
isBeingHeld = false;
}
}
}
I tried to change the group of the object tried to check the position and so on in this code it should check the position of the mouse and drag the object with the Blocks tag
If line 13 is this one...
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
... then the only part of the code that could realistically be null is the Camera.main property. Camera.main is returned by Unity when Unity looks for, and finds, a Camera in your scene that's tagged "MainCamera".
I suggest that you might have removed or changed that tag of the Camera, or a parent of the camera, and now Unity can't find an appropriate camera.
This is echoed in the online documentation https://docs.unity3d.com/ScriptReference/Camera-main.html
I'm trying to make a 3D Isometric game with a wizard shooting fireballs. I managed to make it shoot the fireball but they go in the direction which the wizard is facing: if I rotate the wizard the fireballs change direction. What can I do? Thanks for helping me.
This is the script I made (attached to the player):
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class WizardController : Characters
{
[SerializeField]
public Transform spawnMagic;
private GameObject magicShot;
public List<GameObject> magicBullets = new List<GameObject>();
private void Start()
{
maxHP = 150.0f;
magicShot = magicBullets[0];
}
void Update()
{
GetInputs();
Attack();
Defend();
cameraFollow();
}
private void FixedUpdate()
{
LookAt();
Move();
}
public override void Attack()
{
if (Input.GetButtonDown("Fire1"))
{
GameObject magicBullet;
isAttacking = true;
GetComponent<Animator>().SetBool("hit1", true);
if (spawnMagic != null)
{
magicBullet = Instantiate(magicShot, spawnMagic.transform.position, Quaternion.identity);
}
}
else
{
GetComponent<Animator>().SetBool("hit1", false);
}
}
}
The movement script for the bullet is a simple "transform.position" line:
transform.position += spawnMagic.forward * (speed * Time.deltaTime);
And this is what happen when the player shoot:
https://youtu.be/TYwWDr8W4Q4
To solve this problem, you must make the bullet movement independent of the any objects that are Child of wizard or depend on it transfrom.
If you are careful, the spawnMagic rotates as the wizard moves, and the bullet is referenced by spawnMagic.forward.
First you need to place bullet rotation same as spawn spawnMagic rotation during production.
magicBullet = Instantiate(magicShot, spawnMagic.transform.position, spawnMagic.transform.rotation)
Then replace spawnMagic.forward with local bullet forward at movement part, it will make bullet movement indepent of spawnMagic direction during move phase:
transform.position += transform.forward * (speed * Time.deltaTime)
When dragging an object slowly with a raycast the object moves with a bit of lag.
When dragging the object fast the mouse pointer gets out of the field of layer raycasting so the object is no more moving.
The main project is dragging a cube on a plane.
But in order to make the project more simpler, I opened a new 2D project and made a circle and assigned to it the following script, and attached to it a sphere collider (the main target is in 3D space).
// If some one wrote:
private Vector2 deltaPos;
void Update () {
Vector2 touchPos;
if (Input.GetMouseButtonDown (0)) { // Clicking the Target
RaycastHit hit;
var ray = Camera.main.ScreenPointToRay (Input.mousePosition);
if (Physics.Raycast (ray, out hit, Mathf.Infinity)) {
touchPos = new Vector3 (hit.point.x, hit.point.y);
deltaPos.x = touchPos.x - transform.position.x;
deltaPos.y = touchPos.y - transform.position.y;
Debug.Log ("You Clicked Me");
}
}
if (Input.GetMouseButton (0)) {
RaycastHit hit;
var ray = Camera.main.ScreenPointToRay (Input.mousePosition);
if (Physics.Raycast (ray, out hit, Mathf.Infinity)) {
transform.position = new Vector2 (hit.point.x - deltaPos.x, hit.point.y - deltaPos.y);
}
}
}
I expected to drag the sphere regularly, but what happens is that the pointer goes outside the sphere collider when moving fast, therefore the circle stops moving.
I found this article, then I changed the void from Update() to FixedUpdate() but same result.
Try putting your physics code in FixedUpdate() function which is built for physics calculation. then if it's laggy, you can changeFixed Timestep in physics settings.
Fixed Timestep: A framerate-independent interval that dictates when physics calculations and FixedUpdate() events are performed.
https://docs.unity3d.com/Manual/class-TimeManager.html
EDIT
this code:
if (Physics.Raycast (ray, out hit, Mathf.Infinity))
checks if the raycast has hit something, therefore when the pointer goes out of the sphere there is nothing else to hit, so the if condition returns false and you cannot move it, to solve the problem add a big quad or plane as child to your camera and make sure it fills the camera view perfectly, and it's behind all your other scene elements.
you also can make a script that sets this plane for you.
EDIT 2
As another approach to solve the issue, you can use flags.
Add this to your camera, or edit it to your needs.
public class DragObjects : MonoBehaviour
{
Camera thisCamera;
private Transform DraggingObject;
bool DraggingFlag = false;
RaycastHit raycast;
Ray ray;
Vector3 deltaPosition;
void Start()
{
thisCamera = GetComponent<Camera>();
}
void Update()
{
if (Input.GetMouseButtonDown(0))
{
ray = thisCamera.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out raycast, Mathf.Infinity))
{
DraggingObject = raycast.collider.transform;
DraggingFlag = true;
deltaPosition = thisCamera.ScreenToWorldPoint (Input.mousePosition) - DraggingObject.position;
}
}
else if (Input.GetMouseButton(0))
{
if (DraggingFlag)
{
DraggingObject.position = new Vector3 (thisCamera.ScreenToWorldPoint (Input.mousePosition).x - deltaPosition.x, thisCamera.ScreenToWorldPoint (Input.mousePosition).y - deltaPosition.y, DraggingObject.position.z);
}
}
else if (Input.GetMouseButtonUp(0))
{
DraggingFlag = false;
}
}
}
Remember to cash your Camera.main in a variable at the start, because it is not performant and does this in the background:
GameObject.FindGameObjectsWithTag("MainCamera").GetComponent<Camera>();
I'm making a building mechanic in my game and I want to be able to clear out certain objects around the map (trees, other decor) so I have room to build. I've tried using a ray cast to find what object is being clicked on and destroy it but that doesn't work.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ObjectDestroy : MonoBehaviour {
// Start is called before the first frame update
void Start () {
}
// Update is called once per frame
void Update () {
if (Input.GetMouseButtonDown (0)) {
Ray ray = Camera.main.ScreenPointToRay (Input.mousePosition);
RaycastHit hit;
Debug.Log (Input.mousePosition);
if (Physics.Raycast (ray, out hit)) {
if (hit.collider.gameObject == gameObject) Destroy (gameObject);
}
}
}
}
Here is a little example script:
public class Destroyable : MonoBehaviour
{
private void OnMouseDown()
{
Destroy(gameObject);
}
}
You can attach this script to the GameObject you want to destroy and then during Play-Mode you can click on it to destroy it. It is modifiable if you just need it in your In-Game-Editor.
Note: You need an active Collider on the same Gameobject.
Edit:
The following script shows an example for changing the color of the object:
public class Destroyable : MonoBehaviour
{
public Color mouseHoverColor = Color.green;
private Color previousColor;
private MeshRenderer meshRenderer;
private void Start()
{
meshRenderer = GetComponent<MeshRenderer>();
previousColor = meshRenderer.material.color;
}
private void OnMouseDown()
{
Destroy(gameObject);
}
private void OnMouseOver()
{
meshRenderer.material.color = mouseHoverColor;
}
private void OnMouseExit()
{
meshRenderer.material.color = previousColor;
}
}
You don't need to add this script on every object, just add it to a manager and also I think you are missing Raycast parameters.
To see where you ray is going you can use Debug.Ray()
Also, I would prefer you use #MSauer way since is much cleaner for what you want, just be sure the object contains a collider, I think they can be a trigger and the click will still happen.
I am new to unity. I am working on cake maker like game for android device. I am facing a difficulty in dragging objects from cabinet to table. On table i want to mix them in a jar. These are Many items. So, I cannot do it by separating them using unity Tags. How to make a generic way to drag them on table?
I am using this code but its not working for me.
using UnityEngine;
using System.Collections;
public class DragObjects : MonoBehaviour {
Ray ray;
RaycastHit hit;
// Use this for initialization
void Start ()
{
}
// Update is called once per frame
void Update ()
{
if (Input.GetMouseButtonDown(0))
{
ray = Camera.main.ScreenPointToRay (Input.mousePosition);
if (Physics.Raycast (ray, out hit))
{
if (hit.collider.tag == "oil")
{
OnMouseDrag();
}
}
}
}
void OnMouseDrag()
{
Vector3 point = Camera.main.ScreenToWorldPoint(Input.mousePosition);
point.x = gameObject.transform.position.x;
gameObject.transform.position = point;
}
}
The Unity way of doing this would be to have a Draggable behaviour which you attach to each object you wish to drag.
If you are using 2D colliders you can use something like this:
Vector3 pos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
bool isOver = collider2D.OverlapPoint(pos);
With 3D colliders you can get a ray from the camera and see if that intersects with a draggable.
Then you can use other colliders to detect when they are placed on the jar.