My current problem is that I want to move an object over another object with the curser. But these objects overlap each other.
In my example it is a cube (ignores Raycast), which I move with the curser (Worldsace) over the ground (Other cube).
I have already searched for a solution but nothing realy works.
My only solution would be that I just take an empty object and take that as the deepest point of it... but I am sure that it dont work on walls...
I look forward to answers and your solutions.
Thanks in advance.
The 1. script handels my Mouse movement.
The second script moves my Objects (Cube)
using UnityEngine;
public class Mouse3D : MonoBehaviour
{
public static Mouse3D Instance { get; private set; }
[SerializeField] private LayerMask mouseColliderLayerMask = new LayerMask();
[SerializeField] private Transform debugVisual; public bool lockMouse;
public bool showDebugInformations;
[Header("Debug Only")] public Vector3 mousePosition = Vector3.zero;
public string objectName;
public string layerMask;
public static int x;
public static int y;
public static int z;
private void Awake()
{
Instance = this;
}
private void Update()
{
if (lockMouse)
{
Cursor.lockState = CursorLockMode.Locked;
Cursor.visible = false;
}
else
{
Cursor.lockState = CursorLockMode.None;
Cursor.visible = true;
}
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out RaycastHit raycastHit, 999f, mouseColliderLayerMask))
{
transform.position = raycastHit.point;
}
if (showDebugInformations)
{
debugVisual.position = GetMouseWorldPosition();
mousePosition = GetMouseWorldPosition();
//objectName = raycastHit.transform.parent.name;
//layerMask = raycastHit.ToString();
}
}
public static Vector3 GetMouseWorldPosition() => Instance.GetMouseWorldPosition_Instance();
private Vector3 GetMouseWorldPosition_Instance()
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out RaycastHit raycastHit, 999f, mouseColliderLayerMask))
{
x = (int)raycastHit.point.x; y = (int)raycastHit.point.y; z = (int)raycastHit.point.z;
return raycastHit.point;
}
else
{
return Vector3.zero;
}
}
}
using UnityEngine;
public class BuildAssetMovement : MonoBehaviour
{
void Update()
{
// moving by 1 unit
this.transform.SetPositionAndRotation(new Vector3(
Mathf.RoundToInt(Mouse3D.x),
Mathf.RoundToInt(Mouse3D.y),
Mathf.RoundToInt(Mouse3D.z)),
this.transform.rotation);
}
}
Easy solution will be to set world on a grid and each shape knows how much space it occupied.
I would not work if you have free rotation of object allowed.
As I can understand from your code the problem could be that you hitting dragged object. You need to make this object transparent for a Raycast.
Hey Guys I found an trick.
In my case, I set the Position hard so i only need the coliders to use the ray,
so I ajust the collder size a bit greather than I wanted it, but if now the values bekommes rounded. they will be always "correctly".
(dont round to the objects position, where you rayed against.)
That was my solution, if you guys have more ideas... let me know them ;)
Thanks four your support.
Related
I'm trying to do RTS style movement with single selection only and without navmeshagent. When I click while another unit is already moving, its getting stopped and new one moving to same the point. Is there any way to seperate their hit points? Like I click to unit and order it to the point and then I click another unit and order him to another point.
Here is the video: demo
private Camera mycam;
private RaycastHit hit;
public Vector3 tf;
public LayerMask ground;
private bool move;
public static UnitMove instance;
private void Awake()
{
instance = this;
}
private void Start()
{
mycam = Camera.main;
}
private void Update()
{
if (Input.GetMouseButtonDown(1) && haveSelected())
{
if (UnitClick.Instance.selectChanged)
{
getMouseRay();
}
}
if (move)
{
SetDestination(UnitClick.Instance.selectedUnit.transform.position, hit);
}
}
private void SetDestination(Vector3 unitPos, RaycastHit hit)
{
move = true;
if (Vector3.Distance(UnitClick.Instance.selectedUnit.transform.position, hit.point) > 0.5f)
{
UnitClick.Instance.selectedUnit.transform.position = Vector3.MoveTowards(UnitClick.Instance.selectedUnit.transform.position,
new Vector3(hit.point.x, UnitClick.Instance.selectedUnit.transform.position.y, hit.point.z), 1f * Time.deltaTime);
}
}
public void getMouseRay()
{
Ray ray = mycam.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out hit, Mathf.Infinity, ground))
{
move = true;
}
}
private bool haveSelected()
{
if (UnitSelection.Instance.unitSelected.Count > 0)
{
return true;
}
else
{
return false;
}
}
}
Looks to me like rather than just setting a destination, the SetDestination() function actually moves UnitClick.Instance.selectedUnit every frame. Once you click another unit, UnitClick.Instance.selectedUnit presumably changes to the newly selected unit, meaning every object’s SetDestination() code is always moving the same single object.
You’ll want to do something like save the destination in an instance variable when SetDestination() is first called and then have the move code change either:
change transform.position if the script is attached to the object you want to move
or if not: save the current UnitClick.Instance.selectedUnit in an instance variable when SetDestination() is first called and then change its position in the move code.
Edit: Here’s an attempt to show what I mean but note that this assumes the script is attached to the GameObject you want to move. It also preserves your existing system of setting the destination every frame while the unit is selected (it may be more desirable to update it only when the mouse is clicked?)
private Camera mycam;
private RaycastHit hit;
public Vector3 tf;
public LayerMask ground;
private bool move;
private Vector3 destination;
public static UnitMove instance;
private void Awake()
{
instance = this;
}
private void Start()
{
mycam = Camera.main;
}
private void Update()
{
if (Input.GetMouseButtonDown(1) && haveSelected())
{
if (UnitClick.Instance.selectChanged)
{
getMouseRay();
}
}
if (move)
{
if( transform == UnitClick.Instance.selectedUnit.transform ) // If we are currently selected
SetDestination(/*UnitClick.Instance.selectedUnit.transform.position,*/ hit); // Update our destination
// If ‘move’ is true, move towards our destination whether or not we are currently selected
if (Vector3.Distance(transform.position, destination) > 0.5f)
transform.position = Vector3.MoveTowards(transform.position, destination, 1f * Time.deltaTime);
else
move = false; // This part is a guess at what you want — remove if it causes problems.
}
}
private void SetDestination(/*Vector3 unitPos,*/ RaycastHit hit)
{
move = true;
destination = new Vector3(hit.point.x, transform.position.y, hit.point.z);
}
public void getMouseRay()
{
Ray ray = mycam.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out hit, Mathf.Infinity, ground))
{
move = true;
}
}
private bool haveSelected()
{
if (UnitSelection.Instance.unitSelected.Count > 0)
{
return true;
}
else
{
return false;
}
}
Hey guys I have a made two scripts to handle door opening.
Script 1 - Raycast
Script 2 - The door opening script
I have the raycast on the player camera and I have script 2 on the door.
But there is a problem.
In script 2, I have code that makes UI active and inactive and code that does the door animation
SCRIPT 1 -
using System.Collections.Generic;
using UnityEngine;
public class PlayerCasting : MonoBehaviour
{
public Camera FPScam;
public float range = 6;
public static float ToTarget;
void Update()
{
RaycastHit Hit;
if (Physics.Raycast(FPScam.transform.position, FPScam.transform.forward, out Hit, range))
{
ToTarget = Hit.distance;
}
}
}
SCRIPT 2 -
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class DoorOpen : MonoBehaviour
{
public float Distance;
public GameObject key;
public GameObject reason;
public GameObject Hinge;
public AudioSource DoorCreak;
// Update is called once per frame
void Update()
{
Distance = PlayerCasting.ToTarget;
}
private void OnMouseOver()
{
if (Distance <= 3.5f)
{
key.SetActive(true);
reason.SetActive(true);
}
if (Input.GetButtonDown("Action"))
{
if (Distance <= 3.5f)
{
key.SetActive(false);
reason.SetActive(false);
this.GetComponent<BoxCollider>().enabled = false;
Hinge.GetComponent<Animation>().Play("DoorOpenAnim");
DoorCreak.Play();
}
}
}
private void OnMouseExit()
{
key.SetActive(false);
reason.SetActive(false);
}
}
But, the UI doesn't activate nor does the animation plays when I click 'E' and when the Raycast distance <= 3.5.
I have the raycast on the player camera
Since you're using OnMouseOver() and OnMouseExit() your methods will only work when the player's mouse is on the thing you want to raycast.
Make sure that the raycast is actually pointing the same direction the mouse cursor is. You use use Debug.Raycast() to visually see where the raycast is going.
If the raycast is going in the direction you want it to and it's still not working try a different way of communicating through the scripts and avoid using OnMouseOver().
For example you could try something like this:
public class PlayerCasting : MonoBehaviour
{
public Camera FPScam;
public float range = 6;
public static float ToTarget = 0f;
public static GameObject HoveredObject = null; // <----
void Update()
{
RaycastHit Hit;
if (Physics.Raycast(FPScam.transform.position, FPScam.transform.forward, out Hit, range))
{
ToTarget = Hit.distance;
HoveredObject = Hit.collider.gameObject; // <----
}
}
}
public class DoorOpen : MonoBehaviour
{
public float Distance;
public GameObject key;
public GameObject reason;
public GameObject Hinge;
public AudioSource DoorCreak;
// Update is called once per frame
void Update()
{
if (PlayerCasting.HoveredObject == gameObject)
{
Distance = PlayerCasting.ToTarget;
CheckDistance();
}
}
private void CheckDistance()
{
if (Distance <= 3.5f)
{
key.SetActive(true);
reason.SetActive(true);
if (Input.GetButtonDown("Action"))
{
key.SetActive(false);
reason.SetActive(false);
this.GetComponent<BoxCollider>().enabled = false;
Hinge.GetComponent<Animation>().Play("DoorOpenAnim");
DoorCreak.Play();
}
}
else
{
key.SetActive(false);
reason.SetActive(false);
}
}
private void OnMouseExit()
{
key.SetActive(false);
reason.SetActive(false);
}
}
this is my code for raycast in my school project game. If I put script on object everything is working just fine. But if I close Unity and reopen my project, the value of "jakDaleko" = distance stays locked on 1129.395 instead of changing every frame.
What should I change so it will work everytime and not just the first time ipress play button.
Here's my code.
script 1 = raycast
public class SmerDivani : MonoBehaviour {
public static float VzdalenostOdCile;
public float VzdalenostOdCileInterni;
// Update is called once per frame
void Update() {
RaycastHit Hit;
if (Physics.Raycast(transform.position, transform.TransformDirection(Vector3.forward), out Hit)) {
VzdalenostOdCileInterni = Hit.distance;
VzdalenostOdCile = VzdalenostOdCileInterni;
}
}
}
Second script
public class TabuleMesto1 : MonoBehaviour
{
public float JakDaleko;
public GameObject AkceTlacitko;
public GameObject AkceText;
public GameObject UIQuest;
public GameObject ThePlayer;
public GameObject NoticeCam;
void Update() {
JakDaleko = SmerDivani.VzdalenostOdCile;
}
void OnMouseOver() {
if (JakDaleko <= 5) {
AkceTlacitko.SetActive(true);
AkceText.SetActive(true);
}
if (JakDaleko > 5)
{
AkceTlacitko.SetActive(false);
AkceText.SetActive(false);
}
if (Input.GetButtonDown("Akce")) {
if (JakDaleko <= 5) {
AkceTlacitko.SetActive(false);
AkceText.SetActive(false);
UIQuest.SetActive(true);
NoticeCam.SetActive(true);
ThePlayer.SetActive(false);
}
}
}
void OnMouseExit() {
AkceTlacitko.SetActive(false);
AkceText.SetActive(false);
}
}
I'm not quite sure what you're trying to achieve? Maybe this should "fix" your problem, you're not clearing the distance if the raycast don't hits....
void Update() {
RaycastHit Hit;
if (Physics.Raycast(transform.position, transform.forward, out Hit)) {
VzdalenostOdCileInterni = Hit.distance;
}
else {
VzdalenostOdCileInterni = 0.0f;
}
VzdalenostOdCile = VzdalenostOdCileInterni;
}
Additionally I think you should use transform.forward instead of transform.TransformDirection(Vector3.forward)
I think that the biggest problem was the name of the file. For some reason, my stupidity included, the solution was to rename the script from table1 to table_1
I am trying to create a 2D game where the user throws a bomb at an arch from point A(which is a fixed point) to point B(which will change constantly). My trouble comes in when I am trying to make the bomb move towards the target location, I cannot seem to get it to go where I touch. I also cannot get it to go there in an arch. Is there anyone that can assist me in solving this problem. Other help that I have researched is for a 3D situation and I have trouble converting it into a 2D model.
Below are the two scripts that are being used together.
public class PlayerController : MonoBehaviour {
public int[] distanceToThrow;
public int[] bombToThrow;
public GameObject bomb;
public Transform throwOrigin;
public Vector2 throwSpeed;
public float gravity;
//public Transform throwPointPos;
public Vector2 throwDestination;
public float flightSpeed;
public float throwTimer;
public float throwResetTimer;
public float landingTime;
public Vector2 touchPos;
private BombController theBomb;
private Rigidbody2D bombRB;
//private Camera theCamera;
// Use this for initialization
void Start () {
//theCamera = FindObjectOfType<Camera>();
theBomb = FindObjectOfType<BombController>();
bombRB = theBomb.GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void Update()
{
if (throwTimer > 0)
{
throwTimer -= Time.deltaTime;
// Using a single touch as control - Letholor
}
else if (Input.touchCount > 0)
{
Touch touch = Input.GetTouch(0);
touchPos = new Vector2(touch.position.x, touch.position.y);
Debug.Log("You are touching at position: " + touchPos);
/* Ray ray = Camera.main.ScreenPointToRay(touchPos);
RaycastHit hitResult;
Physics.Raycast(ray, out hitResult);*/
Vector2 throwDestination = touchPos;
Debug.Log("Throw destination is " + throwDestination);
SendBomb(throwDestination);
}
}
public void SendBomb(Vector2 throwDestination) {
if (throwTimer > 0)
{
Debug.Log("Cooling down.");
return;
}
throwTimer = throwResetTimer;
Debug.Log("Throwing bomb to " + throwDestination);
//Instantiate(bomb, throwOrigin.position, throwOrigin.rotation);
GameObject newBomb = Instantiate(bomb, throwOrigin.position, throwOrigin.rotation);
newBomb.GetComponent<BombController>().SetThrowDestination(touchPos - throwDestination);
}
}
public class BombController : MonoBehaviour {
public int bombTimer;
public float explosionRadius;
public int resetTimer;
public bool exploded;
public Animation anim;
private Rigidbody2D bombRigidbody;
public float bombSpeed;
public float gravity;
private PlayerController thePlayer;
// Use this for initialization
void Start () {
bombRigidbody = GetComponent<Rigidbody2D>();
thePlayer = FindObjectOfType<PlayerController>();
}
// Update is called once per frame
void Update () {
}
private void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.tag == "Ground" || collision.gameObject.tag == "Bomb")
{
bombRigidbody.velocity = new Vector2(0, 0);
}
}
public void Detonate()
{
anim.Play("explode");
exploded = true;
}
public void SetThrowDestination(Vector2 throwDestination)
{
bombRigidbody.velocity = throwDestination * bombSpeed;
}
}
Things to check:
Make sure your Rigidbody2D has its Gravity Scale property set to 1 and the Body Type to Dynamic.
Check you give a value to Edit -> Project Settings -> Physics 2D -> Gravity -> Y (it's in Newtons, so -9.8 sounds about right).
Since velocity should not be edited, use AddForce to make it move in the direction you want.
Make sure the direction vector is calculated as destination - origin (delta position), or in your case throwDestination - throwOrigin. Any multipliers should be applied to the direction vector (e.g. bombSpeed).
Remove any direct manipulation to velocity and let the physics engine do its thing.
All of that should make the object move in the direction you want. If it doesn't, then there's probably a problem with one of the vectors or maybe the bombSpeed is too low ("Add zeroes until it breaks"). Try setting the vector values manually and make sure they're not being modified by any other section of the code.
Not sure why, I've done this sort of this a bunch of times, but this is giving me some issues. Making a project for Game AI, I have a whole bunch of stuff already done, now just making some turrets that if the player is in a certain range it will fire, which I have already. The turret fires the bullet and then for some reason they just start destroying themselves and they don't go towards my player. Wondering if anyone on here can help, thanks in advance!
Some details you may need to know:
I have a Base, a Gun nose and a Gun for my turret. My Gun has a GunLook.cs script that makes it look at the player (so when they shoot it should go towards them), I'm not sure if that has anything to do with why I'm having these issues, but I'll post that code as well just incase
How my Hierchy for my turret is
Turret_AI (Base)
Gun (child of Turret_AI)
bulletSpawn (child of Gun)
Gun_Nose (child of turret_AI)
bulletSpawn is an empty GameObject I created in hopes to solve my problem. I set it just off the Gun so that it wouldn't just collide with gun and destroy itself (what I thought it might be doing, but not correct).
That should be all the info needed, if anyone needs more I will be checking this every 2 seconds so let me know and I will get back to you with quick response.
TurretScript.cs
(I did set the GameObject to Player in Unity, before anyone asks)
using UnityEngine;
using System.Collections;
public class TurretScript : MonoBehaviour {
[SerializeField]
public GameObject Bullet;
public float distance = 3.0f;
public float secondsBetweenShots = 0.75f;
public GameObject followThis;
private Transform target;
private float timeStamp = 0.0f;
void Start () {
target = followThis.transform;
}
void Fire() {
Instantiate(Bullet, transform.position , transform.rotation);
Debug.Log ("FIRE");
}
void Update () {
if (Time.time >= timeStamp && (target.position - target.position).magnitude < distance) {
Fire();
timeStamp = Time.time + secondsBetweenShots;
}
}
}
GunLook.cs
// C#
using System;
using UnityEngine;
public class GunLook : MonoBehaviour
{
public Transform target;
void Update()
{
if(target != null)
{
transform.LookAt(target);
}
}
}
BulletBehavior.cs
using UnityEngine;
using System.Collections;
public class BulletBehavior : MonoBehaviour {
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
if (rigidbody.velocity.magnitude <= 0.5)
Destroy (gameObject);
}
void OnCollisionEnter(Collision collision)
{
if (collision.collider)
{
if(collision.gameObject.tag == "Enemy" || collision.gameObject.tag == "EnemyProjectile")
{
Physics.IgnoreCollision(rigidbody.collider,collision.collider);
//Debug.Log ("Enemy");
}
if(collision.gameObject.tag == "SolidObject")
{
Destroy(gameObject);
}
if(collision.gameObject.tag == "Player")
{
Destroy(gameObject);
}
}
}
}
You're never moving your bullet.
public class BulletBehavior : MonoBehaviour
{
private const float DefaultSpeed = 1.0f;
private float startTime;
public Vector3 destination;
public Vector3 origin;
public float? speed;
public void Start()
{
speed = speed ?? DefaultSpeed;
startTime = Time.time;
}
public void Update()
{
float fracJourney = (Time.time - startTime) * speed.GetValueOrDefault();
this.transform.position = Vector3.Lerp (origin, destination, fracJourney);
}
}
Then call it like so:
void Fire()
{
GameObject bullet = (GameObject)Instantiate(Bullet, transform.position , transform.rotation);
BulletBehavior behavior = bullet.GetComponent<BulletBehavior>();
behavior.origin = this.transform.position;
behavior.destination = target.transform.position;
Debug.Log ("FIRE");
}
Note: If you're trying to mix this approach with trying to use physics to move the bullet you may end up with strange results.