Rotating an object at which I am looking (ARFoundation) - c#

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;
}
}
}

Related

How can I position a GameObject with the help of a Ray?

For my grid-based game I want the enemies to have a line of sight that is visible to the player. The enemies can only look in one direction (up, down, left or right) and they won't change that direction once set.
The enemies cannot look through Obstacles or other Enemies, which is why I have set up a Raycast. This Raycast detects if the Player is in a direct line to the direction of the Enemy.
This is my EnemySight Scrip:
PathFollower pathFollower;
public GameObject sightline;
public GameObject player;
float rayLength = 20f;
bool onSameZAxis = false;
Ray myRay;
RaycastHit hit;
void Start()
{
GameObject g = GameObject.Find("Path");
pathFollower = g.GetComponent<PathFollower>();
}
void Update()
{
DrawRay();
if (player.transform.position.z.Equals(transform.position.z) && pathFollower.hasCheckedAxis == false)
{
onSameZAxis = true;
}
else { onSameZAxis = false; }
//checks only when enemy stands still if the player is in sight and on same axis
if (onSameZAxis == true && pathFollower.standsStill == true && PlayerInSight() == true)
{
Debug.Log("spotted");
pathFollower.sawPlayer = true;
pathFollower.hasCheckedAxis = true;
//onSameZAxis = false;
//Debug.Log("In the If-Loop");
}
}
//checks if there is a wall between the player and the enemy
bool PlayerInSight()
{
myRay = new Ray(transform.position + new Vector3(0, 0.15f, 0), -transform.right);
Debug.DrawRay(myRay.origin, myRay.direction, Color.red);
if (Physics.Raycast(myRay, out hit, rayLength))
{
if (hit.collider.tag == "Player")
{
return true;
}
}
return false;
}
void DrawRay()
{
//Moves the Sightline Object.
}
}
I have made the Sightline GameObject a Child of the respective enemy, so it moves with the enemy. The problem is that it will move through Obstacles and Enemies, altough the player won't be detected then.
I was thinking about moving the pivot point of my Sightline GameObject to the Vector 3 hit of the Raycast but I don't know how that could work.
I'm happy about any suggestions or solutions, thank you in advance!

Moving objects independently of each other, with the ability to move at the same time in Unity 2D

I have two objects. The point is that I need to move the object up and down (hold and drag), and at the same time I need to move the other object up and down (hold and drag) independently. Something like this:
Example
After searching the Internet, I found a small script, but it only works for one touch at a time, and dragging only one object. Plus, if I touch with second finger the object changes his position to second finger position:
public class Move : MonoBehaviour {
private Vector3 offset;
void OnMouseDown() {
offset = gameObject.transform.position - Camera.main.ScreenToWorldPoint(new Vector3(-2.527f, Input.mousePosition.y));
}
void OnMouseDrag() {
Vector3 curScreenPoint = new Vector3(-2.527f, Input.mousePosition.y);
Vector3 curPosition = Camera.main.ScreenToWorldPoint(curScreenPoint) + offset;
transform.position = curPosition;
}
}
I just can’t understand how I can make two objects drag and drop at the same time. I am new to unity and honestly i have problems with controllers
For touch screens I suggest you use Touch instead of mouse events. Touch class supports multiple touches at the same time and some useful information such as Touch.phase (Began, moving, stationary etc). I've written a script which you can attach to multiple objects with tag "Draggable", that makes objects move independently. Drag and drop the other object that should move when you use one finger to field otherObj and it should work. It only works for 2 obj in this version.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Serialization;
public class PlayerActionHandler : MonoBehaviour
{
private Camera _cam;
public bool beingDragged;
public Vector3 offset;
public Vector3 currPos;
public int fingerIndex;
public GameObject otherObj;
// Start is called before the first frame update
void Start()
{
_cam = Camera.main;
}
// Update is called once per frame
void Update()
{
//ONLY WORKS FOR 2 OBJECTS
if (Input.touchCount == 1 && Input.GetTouch(0).phase == TouchPhase.Began)
{
var raycast = _cam.ScreenPointToRay(Input.GetTouch(0).position);
RaycastHit hit;
if (Physics.Raycast(raycast, out hit))
{
//use this tag if you want only chosen objects to be draggable
if (hit.transform.CompareTag("Draggable"))
{
if(hit.transform.name == name)
{
//set being dragged and finger index so we can move the object
beingDragged = true;
offset = gameObject.transform.position - _cam.ScreenToWorldPoint(Input.GetTouch(0).position);
offset = new Vector3(offset.x, offset.y, 0);
fingerIndex = 0;
}
}
}
}else if (Input.touchCount == 1 && beingDragged)
{
otherObj.transform.SetParent(transform);
if (Input.GetTouch(fingerIndex).phase == TouchPhase.Moved ){
Vector3 pos = _cam.ScreenToWorldPoint(Input.GetTouch(fingerIndex).position);
currPos = new Vector3(pos.x, pos.y,0) + offset;
transform.position = currPos;
}
}
//ONLY WORKS FOR 2 OBJECTS_END
else if (beingDragged && Input.touchCount > 1)
{
//We tie each finger to an object so the object only moves when tied finger moves
if (Input.GetTouch(fingerIndex).phase == TouchPhase.Moved ){
Vector3 pos = _cam.ScreenToWorldPoint(Input.GetTouch(fingerIndex).position);
currPos = new Vector3(pos.x, pos.y,0) + offset;
transform.position = currPos;
}
}else if (Input.touchCount > 0)
{
for (var i = 0; i < Input.touchCount; i++)
{
//We find the fingers which just touched the screen
if(Input.GetTouch(i).phase == TouchPhase.Began)
{
var raycast = _cam.ScreenPointToRay(Input.GetTouch(i).position);
RaycastHit hit;
if (Physics.Raycast(raycast, out hit))
{
//use this tag if you want only chosen objects to be draggable
if (hit.transform.CompareTag("Draggable"))
{
if(hit.transform.name == name)
{
//set being dragged and finger index so we can move the object
beingDragged = true;
offset = gameObject.transform.position - _cam.ScreenToWorldPoint(Input.GetTouch(i).position);
offset = new Vector3(offset.x, offset.y, 0);
fingerIndex = i;
}
}
}
}
}
}else if (Input.touchCount == 0)
{
//if all fingers are lifted no object is being dragged
beingDragged = false;
}
}
}

Why isn't my 2D bullet's collider colliding with anything?

I'm trying to make a platformer game that uses 2D sprites in 3D space. For some reason, though the bullet the player shoots fires correctly from the GO that's a child of the player, it won't collide with anything (enemies, other objects, etc.) in either 2D or 3D. I have a 3D character controller on the parent player GO, but that doesn't affect the bullet object I'm firing, does it?
Colliders on everything appropriately.
Tried with IsTrigger both on and off in various combinations.
Objects are on the same layer and the same Z axis position.
//BULLET FIRING SCRIPT
void Update()
{
if (Input.GetButtonDown("Fire2") && !Input.GetButton("Fire3") &&
Time.time > nextFireTime)
{
Rigidbody2D cloneRb = Instantiate(bullet,
bulletSpawn.position, Quaternion.identity) as Rigidbody2D;
cloneRb.AddForce(bulletPrefab.transform.right *
projectileForce);
nextFireTime = Time.time + fireRate;
}
}
//____________________________________________________________
//BULLET OBJECT SCRIPT
private void Start()
{
direction = Input.GetAxisRaw("Horizontal");
if (direction == -1)
{
facingLeft = true;
}
else if (direction == 1)
{
facingLeft = false;
}
else if (direction == 0)
{
facingLeft = false;
}
if (facingLeft == false)
{
rb.velocity = transform.right * speed;
Debug.Log("Fired Bullet");
}
else
{
bulletPrefab.transform.Rotate(0, 180, 0);
firePoint.transform.Rotate(0, 180, 0);
Debug.Log("Rotated Bullet");
Debug.Log("Fired Bullet Left");
rb.velocity = transform.right * speed;
}
}
// Update is called once per frame
void Update()
{
}
public void OnTriggerEnter2D(Collider2D collider)
{
Debug.Log("Bullet Hit:");
Debug.Log(collider.name);
Enemy enemy = collider.GetComponent<Enemy>();
if (enemy != null)
{
enemy.TakeDamage(damage);
}
Destroy(gameObject);
}
Expected Result: Bullet object collides with other objects, prints Debug.Log output and gets destroyed.
Actual Result: Bullet object fires through, in front of, or behind other objects that also have colliders and there is no Debug.Log output. Bullet does not get destroyed and so instantiates clones infinitely when assigned input is entered.
Fixed issue by checking Default/Default in the Layer Collision Matrix under Edit-->Project Settings-->Physics. Not sure if it's supposed to be checked by default and somehow got unchecked but checking it solved the problem.

Rotation with the limit in unity 3D?

I am building an application in unity.
when User click on an GameObject the model position is changed.
Now I need is on change of the position, Rotation is also changed with the limit axis/Co-ordination point.
Here is my code change of the position on input click of the gameObject.
using UnityEngine;
using System.Collections;
public class centertheroombox : MonoBehaviour
{
public GameObject box345;
public int speed = 1;
// Update is called once per frame
void Update ()
{
foreach (Touch touch in Input.touches)
{
if (touch.phase == TouchPhase.Began || touch.phase == TouchPhase.Ended)
{
Ray ray = Camera.main.ScreenPointToRay(touch.position);
RaycastHit hit;
if (Physics.Raycast(ray, out hit, 1000.0f))
{
if (hit.collider.gameObject.name == "Box345")
{
Debug.Log("yupiee pressed");
box345.transform.position = new Vector3(3, 0, -9);
//box345.transform.Rotate(Vector3.right, Time.deltaTime);
//box345.transform.Rotate = new Vector3(353,0,0);
}
}
}
}
}
}

rigidbody.AddForce affects all game objects with the same script component

on scene I have 3 balls with Ball.cs script attached to each of them. And when I push ball with mouse all balls start moving, but I need that only one that I touch moves.
Here is my FixedUpdate:
void FixedUpdate() {
if(!isMoving) {
if (Input.GetMouseButtonDown (0)) {
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if (Physics.Raycast(ray, out hit, 100)) {
if(hit.collider.tag == "Ball") {
startPos = hit.point;
}
}
}
if (startPos != Vector3.zero && Input.GetMouseButtonUp(0)) {
endPos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
Vector3 direction = endPos - startPos;
direction.Normalize();
float distance = Vector3.Distance(endPos, startPos);
rigidbody.AddForce(direction * distance * force * Time.deltaTime, ForceMode.Impulse);
isMoving = true;
}
} else {
if(rigidbody.velocity.sqrMagnitude == 0) {
isMoving = false;
startPos = endPos = Vector3.zero;
}
}
}
Like Nick Udell already mentioned, your comparison of the tag is the source of your problem. All three balls are executing the same script at nearly the same time. So if you click on of the balls, all three scripts will cast a ray at your mouse position and check if they hit a ball. Guess what? All of them hit a ball but not the ball they belong to.
You need to check if they are hitting the collider attached to their GameObject
if (hit.collider == collider) {
// do stuff
}

Categories