How to convert Raycast 3D to 2D in Unity [duplicate] - c#

I have this code below which could control a touched player among 3 players. I was able to implement it by like sort of "cheating" by way of adding a 3D cube behind a 2D sprite since my game should be in 2D and I am having hard time implementing it in 2D. I'm really confused on how to do it in 2D because I'm really confuse on the parameters.
Although I already implemented it by the way mentioned above, I still want to implement it in pure 2D. And because I have this problem when the selected player moves, the sprite moves faster.
public GameObject target = null;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update ()
{
if(Input.touchCount > 0 || Input.GetTouch(0).phase == TouchPhase.Began)
{
Ray ray = Camera.main.ScreenPointToRay(Input.GetTouch(0).position);
Debug.DrawRay(ray.origin,ray.direction * 20,Color.red);
RaycastHit hit;
if(Physics.Raycast(ray, out hit,Mathf.Infinity))
{
Debug.Log(hit.transform.gameObject.name);
if(this.target != null){
SelectMove sm = this.target.GetComponent<SelectMove>();
if(sm != null){ sm.enabled = false; }
}
target = hit.transform.gameObject;
//Destroy(hit.transform.gameObject);
selectedPlayer();
}
}
}
void selectedPlayer(){
SelectMove sm = this.target.GetComponent<SelectMove>();
if(sm == null){
target.AddComponent<SelectMove>();
}
sm.enabled = true;
}

use RaycastHit2D to do this instead of RaycastHit then change Physics.Raycast to Physics2D.Raycast. The parameters are different the code below should do it.You may also have to change && to || depending on your game logic.
Select the Sprite then add Box Colider 2D from the Editor. You can also use Circle Collider 2D for the Sprite if your Sprite is round. If you don't add any 2D collider to the Sprite, ray won't detect the object when clicked on.
FOR MOBILE DEVICES
if ((Input.touchCount > 0) && (Input.GetTouch(0).phase == TouchPhase.Began))
{
Vector2 cubeRay = Camera.main.ScreenToWorldPoint(Input.GetTouch(0).position);
RaycastHit2D cubeHit = Physics2D.Raycast(cubeRay, Vector2.zero);
if (cubeHit)
{
//We hit something
Debug.Log(cubeHit.transform.gameObject.name);
if (this.target != null)
{
SelectMove sm = this.target.GetComponent<SelectMove>();
if (sm != null) { sm.enabled = false; }
}
target = cubeHit.transform.gameObject;
//Destroy(cubeHit.transform.gameObject);
selectedPlayer();
}
}
FOR DESKTOPS / EDITOR
if (Input.GetMouseButtonDown(0))
{
Vector2 cubeRay = Camera.main.ScreenToWorldPoint(Input.mousePosition);
RaycastHit2D cubeHit = Physics2D.Raycast(cubeRay, Vector2.zero);
if (cubeHit)
{
//We hit something
Debug.Log(cubeHit.transform.gameObject.name);
if (this.target != null)
{
SelectMove sm = this.target.GetComponent<SelectMove>();
if (sm != null) { sm.enabled = false; }
}
target = cubeHit.transform.gameObject;
//Destroy(cubeHit.transform.gameObject);
selectedPlayer();
}
}

Related

why gameobject / raycast when dragged is not accurately following the touch position in unity

so I made a script for multitouch using raycast. when dragged faster, the gameobject will be released, but when moving the gameobject slowly it follows the touch. here the codes
Vector2[] startPos = new Vector2[5];
Touch[] touch = new Touch[5];// Update is called once per frame
void FixedUpdate()
{
Debug.Log(Input.touchCount);
if (Input.touchCount > 0)
{
touch[Input.touchCount-1] = Input.GetTouch(Input.touchCount-1);
Vector2 worldPoint = Camera.main.ScreenToWorldPoint(touch[Input.touchCount-1].position);
RaycastHit2D hit = Physics2D.Raycast(worldPoint, Vector2.zero, Mathf.Infinity);
if (hit.transform != null)
{
if (touch[Input.touchCount - 1].phase == TouchPhase.Moved)
{
hit.transform.position = worldPoint;]
}
else if (touch[Input.touchCount-1].phase == TouchPhase.Began)
{
startPos[touch[Input.touchCount-1].fingerId] = worldPoint;
}
else if (touch[Input.touchCount-1].phase == TouchPhase.Ended)
{
hit.transform.position = startPos[touch[Input.touchCount-1].fingerId];
}
}
}
}
what can i do for drag faster without gameobject will released? sorry for my bad english
one solution is to play with a bool variable and tag,
you keep in memory the gameobject you are dragging, you set a bool variable to true.. this is the idea , you try to use bool variable instead touchphase.ended/began...
this post could help you
i have just adapted to game2D
GameObject objet = null;
Plane plane;
float rayDistance;
Vector3 Offset;
bool mouseOver = false;
bool mousePressed = false;
void FixedUpdate()
{
if (Input.touchCount > 0)
{
mousePressed = true;
}
else
{
mousePressed = false;
objet = null;
}
Vector2 worldPoint = Camera.main.ScreenToWorldPoint(touch[Input.touchCount - 1].position);
RaycastHit2D hit = Physics2D.Raycast(worldPoint, Vector2.zero, Mathf.Infinity);
if (hit.transform != null && hit.collider.tag == "Draggable")
{
mouseOver = true;
if (Input.GetTouch(0).phase != TouchPhase.Moved)
objet = hit.collider.gameObject;
}
else
{
if (mousePressed == false)
mouseOver = false;
}
if (mouseOver)
{
if (mousePressed)
{
//to adapt following your game configuration
plane = new Plane(Camera.main.transform.forward * -1, objet.transform.position);
plane.Raycast(ray, out rayDistance);
objet.transform.position = ray.GetPoint(rayDistance);// + Offset; to see if offset is needed
}
}
} // end update

Rotating an object at which I am looking (ARFoundation)

2 items are placed in AR. i would like to rotate 1 of those items while its in the middle of the screen (using touch controls and Raycast).
I would like all the rotation part of the code to be executed when the camera is looking at the object.
this is the script i use on an object placed in the scene, the Move function works since that is only activated when you tap on the screen where the object is and drag it away (Raycast to a Collider). however my rotation works on all objects in the scene when i swipe anywhere because if i swipe on the collider i move the object, so for rotation i have to stay outside that collider.
public class MoveObject : MonoBehaviour
{
public bool holding;
private Component rotator;
int doubleTap = 0;
void Start()
{
holding = false;
}
void Update()
{
if (holding)
{
Move();
}
// One finger
if (Input.touchCount == 1)
{
// Tap on Object
if (Input.GetTouch(0).phase == TouchPhase.Began)
{
Ray ray = Camera.main.ScreenPointToRay(Input.GetTouch(0).position);
RaycastHit hitTouch;
if (Physics.Raycast(ray, out hitTouch, 100f))
{
if (hitTouch.transform == transform)
{
holding = true;
}
}
}
// Release
if (Input.GetTouch(0).phase == TouchPhase.Ended)
{
holding = false;
}
}
if (Input.touchCount == 1 && !holding) //THIS is the rotation part
{
// GET TOUCH 0
Touch touch0 = Input.GetTouch(0);
// APPLY ROTATION
if (touch0.phase == TouchPhase.Moved)
{
transform.Rotate(0f, touch0.deltaPosition.x * 0.5f, 0f);
}
}
}
void Move()
{
RaycastHit hit;
Ray ray = Camera.main.ScreenPointToRay(Input.GetTouch(0).position);
// The GameObject this script attached should be on layer "Surface"
if (Physics.Raycast(ray, out hit, 30.0f,
LayerMask.GetMask("Surface")))
{
transform.position = new Vector3(hit.point.x,
transform.position.y,
hit.point.z);
}
}
}
You'll probably want another flag similar to holding to make sure that you don't rotate an object the center of the screen passes over during a swipe, such as when the camera is moving and the object passes through the center of the screen.
You can use Camera.ViewportPointToRay with input of new Vector3(0.5f, 0.5f, 0) to create a ray coming from the center of the screen. From there, the process is similar to your holding code.
Also, with a little rearranging, you can re-use the raycast that is already used to check if this object was touched because it also checks if any object was touched. Only checking to start rotating when the first raycast touches nothing avoids rotating (and raycasting unnecessarily) in the situation where this object is in the center of the screen but another object was touched.
As a sidenote, it's recommended to cache the result of Camera.main because it does a FindGameObjectsWithTag internally every time you reference it and that can add up to extra computation time.
Altogether, it could look like this:
private bool rotating;
private Camera cam;
void Start()
{
holding = false;
rotating = false;
cam = Camera.main;
}
void Update()
{
// One finger
if (Input.touchCount == 1)
{
Touch touch0 = Input.GetTouch(0);
if (touch0.phase == TouchPhase.Began)
{
Ray ray;
RaycastHit hitTouch;
// test hold start
ray = cam.ScreenPointToRay(touch0.position);
if (Physics.Raycast(ray, out hitTouch, 100f))
{
if (hitTouch.transform == transform)
{
holding = true;
}
}
else // avoid rotating/raycasting again in situation
// where this object may be in center of screen
// but this or other object was touched.
{
// test rotate start
ray = cam.ViewportPointToRay(new Vector3(0.5f, 0.5f, 0));
if (Physics.Raycast(ray, out hitTouch, 100f)))
{
if (hitTouch.transform == transform)
{
rotating = true;
}
}
}
}
else if (touch0.phase == TouchPhase.Moved)
{
if (holding)
{
Move();
}
else if (rotating)
{
transform.Rotate(0f, touch0.deltaPosition.x * 0.5f, 0f);
}
}
// Release
else if (touch0.phase == TouchPhase.Ended)
{
holding = false;
rotating = false;
}
}
}

RaycastHit2D - touch for 2D game

I'm trying to build a 2D game for touch devices. Now I'm trying to cast a ray against colliders in the scene to do do something. For example, if hit the ray hit the left button the player move to the left.
I've searched everywhere in the google and youtube but haven't figured how to do this. I'm new to Unity and programming in general, but from what I searched it seems if I want to detect a touch on the screen for a 2D game is more complicated than a 3D game !!!
void Update ()
{
if (Input.touchCount > 0 )
{
for ( int i = 0; i < Input.touchCount; i++)
{
if ( Input.GetTouch(i).phase == TouchPhase.Began)
{
Ray2D ray = Camera.main.ScreenToWorldPoint (Input.GetTouch(i).position);
RaycastHit2D hit;
if ( Physics2D.Raycast ( ray, out hit) ) )
{
if (hit.transform.gameobject.name == "left")
{
// Do Something
}
}
}
}
}
Dunno if this help but this is how i do it:
//Get current worldspace position of mouse cursor
RaycastHit2D[] hits = Physics2D.LinecastAll(clickedPos,clickedPos,theLayer);
// Copy Linecast to HashSet (unique records), clean out the "Background" GameObject
foreach (RaycastHit2D arf2D in hits) {
//linecast_GameObject = GameObject.FindWithTag(arf2D.collider.tag);
linecast_GameObject = GameObject.Find(arf2D.collider.name);
//if (linecast_GameObject.name != "Background") {
if (linecast_GameObject.tag != "Background") {
linecast_GameObject_HashSet.Add(linecast_GameObject);
clickedOnTheBackground = false;
}
else if (hits.Length == 1) {
clickedOnTheBackground = true;
fingerSelection_GO = GameObject.FindWithTag("Dummy_GameObject");
//fingerSelection_GO = GameObject.Find("Dummy_GameObject");
}
}

Unity Input.Touches if hold touch do nothing?

Newbie...
Learning Unity to make mobile games and I have a small hex grid map that when touched the tiles change to a random color. I have a script for the camera to move it around with a finger press and zoom in an out with two fingers.
I want the tiles to only change color on a single touch, and not change when I pan or zoom the camera. I have been trying for two days and googled myself out and can't seem to figure it out. It seems pretty simple.
Here is the code that is called from Update() when a raycast hits an object. This just changes the hex's color but I want it to only do it when not panning or zooming the camera.
void Touch_Hex(GameObject ourHitObject)
{
Touch[] touches = Input.touches;
if (touches[0].phase == TouchPhase.Ended)
{
MeshRenderer mr = ourHitObject.GetComponentInChildren<MeshRenderer>();
mr.material.color = color[Random.Range(0, color.Length)];
}
}
I've tried all different combos of phases etc but just cannot get it to work as I want it. I'm thinking deltaTime or deltaPostion is the answer but I can't work it out.
Cheers
You need to use a combination of a boolean variable and touches[0].phase == TouchPhase.Moved. When touches[0].phase == TouchPhase.Moved is true then your input is now considered to be invalid. You can then set to boolean variable to true or false then use it later on to decide whether to change the color or not.
bool onlyTouched;
void Update()
{
if (Input.touchCount > 0)
{
Ray ray = Camera.main.ScreenPointToRay(Input.GetTouch(0).position);
RaycastHit hit;
if (Input.GetTouch(0).phase == TouchPhase.Began)
{
//Touched
onlyTouched = true;
}
if (Input.GetTouch(0).phase == TouchPhase.Moved)
{
//Moved Finger (Now Invalid!)
onlyTouched = false;
}
if (Input.GetTouch(0).phase == TouchPhase.Ended)
{
//Check if only touched then change color
if (onlyTouched)
{
Debug.Log("Only touched Finger");
//MeshRenderer mr = ourHitObject.GetComponentInChildren<MeshRenderer>();
//mr.material.color = color[Random.Range(0, color.Length)];
if (Physics.Raycast(ray, out hit))
{
if (hit.transform != null)
{
MeshRenderer mr = hit.transform.gameObject.GetComponentInChildren<MeshRenderer>();
mr.material.color = color[Random.Range(0, color.Length)];
//hit.transform.GetComponent<MeshRenderer>().material.color = Color.red;
}
}
}
else
{
Debug.Log("Finger was moved while touching");
}
//Reset onlyTouched for next read
onlyTouched = false;
}
}
}

Convert 3D Raycast to Raycast2D

I have this code below which could control a touched player among 3 players. I was able to implement it by like sort of "cheating" by way of adding a 3D cube behind a 2D sprite since my game should be in 2D and I am having hard time implementing it in 2D. I'm really confused on how to do it in 2D because I'm really confuse on the parameters.
Although I already implemented it by the way mentioned above, I still want to implement it in pure 2D. And because I have this problem when the selected player moves, the sprite moves faster.
public GameObject target = null;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update ()
{
if(Input.touchCount > 0 || Input.GetTouch(0).phase == TouchPhase.Began)
{
Ray ray = Camera.main.ScreenPointToRay(Input.GetTouch(0).position);
Debug.DrawRay(ray.origin,ray.direction * 20,Color.red);
RaycastHit hit;
if(Physics.Raycast(ray, out hit,Mathf.Infinity))
{
Debug.Log(hit.transform.gameObject.name);
if(this.target != null){
SelectMove sm = this.target.GetComponent<SelectMove>();
if(sm != null){ sm.enabled = false; }
}
target = hit.transform.gameObject;
//Destroy(hit.transform.gameObject);
selectedPlayer();
}
}
}
void selectedPlayer(){
SelectMove sm = this.target.GetComponent<SelectMove>();
if(sm == null){
target.AddComponent<SelectMove>();
}
sm.enabled = true;
}
use RaycastHit2D to do this instead of RaycastHit then change Physics.Raycast to Physics2D.Raycast. The parameters are different the code below should do it.You may also have to change && to || depending on your game logic.
Select the Sprite then add Box Colider 2D from the Editor. You can also use Circle Collider 2D for the Sprite if your Sprite is round. If you don't add any 2D collider to the Sprite, ray won't detect the object when clicked on.
FOR MOBILE DEVICES
if ((Input.touchCount > 0) && (Input.GetTouch(0).phase == TouchPhase.Began))
{
Vector2 cubeRay = Camera.main.ScreenToWorldPoint(Input.GetTouch(0).position);
RaycastHit2D cubeHit = Physics2D.Raycast(cubeRay, Vector2.zero);
if (cubeHit)
{
//We hit something
Debug.Log(cubeHit.transform.gameObject.name);
if (this.target != null)
{
SelectMove sm = this.target.GetComponent<SelectMove>();
if (sm != null) { sm.enabled = false; }
}
target = cubeHit.transform.gameObject;
//Destroy(cubeHit.transform.gameObject);
selectedPlayer();
}
}
FOR DESKTOPS / EDITOR
if (Input.GetMouseButtonDown(0))
{
Vector2 cubeRay = Camera.main.ScreenToWorldPoint(Input.mousePosition);
RaycastHit2D cubeHit = Physics2D.Raycast(cubeRay, Vector2.zero);
if (cubeHit)
{
//We hit something
Debug.Log(cubeHit.transform.gameObject.name);
if (this.target != null)
{
SelectMove sm = this.target.GetComponent<SelectMove>();
if (sm != null) { sm.enabled = false; }
}
target = cubeHit.transform.gameObject;
//Destroy(cubeHit.transform.gameObject);
selectedPlayer();
}
}

Categories