I'm trying to get a unity C# script working that will rotate the camera around the X axis in a 3D environment. Currently, it flips the screen making my terrain look like it is hanging upside down. I'm just trying to get the camera to rotate on the X axis instead. Below is what I currently have.
using UnityEngine;
public class TouchCamera : MonoBehaviour {
Vector2?[] oldTouchPositions = {
null,
null
};
Vector2 oldTouchVector;
float oldTouchDistance;
void Update() {
if (Input.touchCount == 0) {
oldTouchPositions[0] = null;
oldTouchPositions[1] = null;
}
else if (Input.touchCount == 1) {
if (oldTouchPositions[0] == null || oldTouchPositions[1] != null) {
oldTouchPositions[0] = Input.GetTouch(0).position;
oldTouchPositions[1] = null;
}
else {
Vector2 newTouchPosition = Input.GetTouch(0).position;
transform.position += transform.TransformDirection((Vector3)((oldTouchPositions[0] - newTouchPosition) * camera.orthographicSize / camera.pixelHeight * 2f));
oldTouchPositions[0] = newTouchPosition;
}
}
else {
if (oldTouchPositions[1] == null) {
oldTouchPositions[0] = Input.GetTouch(0).position;
oldTouchPositions[1] = Input.GetTouch(1).position;
oldTouchVector = (Vector2)(oldTouchPositions[0] - oldTouchPositions[1]);
oldTouchDistance = oldTouchVector.magnitude;
}
else {
Vector2 screen = new Vector2(camera.pixelWidth, camera.pixelHeight);
Vector2[] newTouchPositions = {
Input.GetTouch(0).position,
Input.GetTouch(1).position
};
Vector2 newTouchVector = newTouchPositions[0] - newTouchPositions[1];
float newTouchDistance = newTouchVector.magnitude;
transform.position += transform.TransformDirection((Vector3)((oldTouchPositions[0] + oldTouchPositions[1] - screen) * camera.orthographicSize / screen.y));
transform.localRotation *= Quaternion.Euler(new Vector3(0, 0, Mathf.Asin(Mathf.Clamp((oldTouchVector.y * newTouchVector.x - oldTouchVector.x * newTouchVector.y) / oldTouchDistance / newTouchDistance, -1f, 1f)) / 0.0174532924f));
camera.orthographicSize *= oldTouchDistance / newTouchDistance;
transform.position -= transform.TransformDirection((newTouchPositions[0] + newTouchPositions[1] - screen) * camera.orthographicSize / screen.y);
oldTouchPositions[0] = newTouchPositions[0];
oldTouchPositions[1] = newTouchPositions[1];
oldTouchVector = newTouchVector;
oldTouchDistance = newTouchDistance;
}
}
}
}
If you wanted to rotate it around (like a character turning its head), in the x-z plain, then you wanted to rotate it around the y axis, not the x.
In the end, I had to make a raycast shoot out the center of the camera and when it collided with something, set that as the pivot point. Then I rotated the camera around said pivot point. Example below...
RaycastHit hit;
if (Physics.Raycast(transform.position, transform.forward, out hit, 300)){}
float distanceToGround = hit.distance;
var pivotPoint = hit.point;
// -------- Rotation ---------
transform.RotateAround(pivotPoint, Vector3.up,Mathf.Asin(Mathf.Clamp((oldTouchVector.y * newTouchVector.x - oldTouchVector.x * newTouchVector.y) / oldTouchDistance / newTouchDistance, -1f, 1f)) / 0.0174532924f);
//---------------------------------------------------------
Related
I'm writing some code to create a Minecraft Quake like game but I have an issue with the jump mecanic. When I'm stuck to a wall the player jump to high (see the video).
I use a Rigidbody for the physics and I modify that velocity to move the player. There is a Physic Material on the player's Collider with no consideration for friction or bouncing.
If you have ideas to fix the bug or an alternative to work around the problem, I'm interested.
How it looks like
Here is my code
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public enum PlayerMovementState {
Sneak,
Walk,
Run
}
public class PlayerControls : MonoBehaviour
{
Rigidbody rb;
Vector3 velocity, desiredVelocity;
PlayerMovementState moveState;
float groundDistance;
[SerializeField]
bool forwardAir, backAir, rightAir, leftAir;
[SerializeField]
LayerMask groundLayer;
[SerializeField]
bool onGround;
bool desiredJump;
float jumpHeight = 1.0f;
private void Awake() {
rb = GetComponent<Rigidbody>();
moveState = PlayerMovementState.Walk;
groundDistance = GetComponentInChildren<Collider>().bounds.extents.y;
}
private void Update() {
Vector2 playerInputs = Vector2.ClampMagnitude(
new Vector2(
Input.GetAxis("Horizontal"),
Input.GetAxis("Vertical")
), 1.0f
);
if (Input.GetKey(KeyCode.LeftShift)) moveState = PlayerMovementState.Sneak;
else if (Input.GetKey(KeyCode.LeftControl)) moveState = PlayerMovementState.Run;
else moveState = PlayerMovementState.Walk;
float speed = moveState == PlayerMovementState.Run ? 10f : (
moveState == PlayerMovementState.Sneak ? 2f : 5f
);
RaycastGround();
onGround = !forwardAir && !backAir && !rightAir && !leftAir;
if (Input.GetButtonDown("Jump")) desiredJump = true;
if (moveState == PlayerMovementState.Sneak)
{
if (forwardAir && playerInputs.y > 0) playerInputs.y = 0f;
if (backAir && playerInputs.y < 0) playerInputs.y = 0f;
if (rightAir && playerInputs.x > 0) playerInputs.x = 0f;
if (leftAir && playerInputs.x < 0) playerInputs.x = 0f;
}
desiredVelocity =
(transform.forward * playerInputs.y + transform.right * playerInputs.x) * speed;
}
private void FixedUpdate() {
velocity = rb.velocity;
float acceleration = 10;
velocity.x = Mathf.MoveTowards(velocity.x, desiredVelocity.x, acceleration);
velocity.z = Mathf.MoveTowards(velocity.z, desiredVelocity.z, acceleration);
if (desiredJump && onGround)
{
desiredJump = false;
float jumpSpeed = Mathf.Sqrt(-2f * Physics.gravity.y * jumpHeight);
velocity.y += jumpSpeed;
}
rb.velocity = velocity;
desiredJump = false;
}
void RaycastGround()
{
forwardAir = !(Physics.Raycast(
transform.position + Vector3.forward * 0.1f,
-Vector3.up,
groundDistance + 0.1f,
groundLayer
));
backAir = !(Physics.Raycast(
transform.position - Vector3.forward * 0.1f,
-Vector3.up,
groundDistance + 0.1f,
groundLayer
));
rightAir = !(Physics.Raycast(
transform.position + Vector3.right * 0.1f,
-Vector3.up,
groundDistance + 0.1f,
groundLayer
));
leftAir = !(Physics.Raycast(
transform.position - Vector3.right * 0.1f,
-Vector3.up,
groundDistance + 0.1f,
groundLayer
));
}
}
Very likely the problem is that the script thinks it's still grounded while it is jumping upwards along the wall.
Depending on what feeling you want, either fix the raycasts such that they only trigger when you are standing directly on top of an object, or you check if the y part of your velocity is <= 0 for your onGround variable.
I did not find a solution to my problem but I found a workaround anyway.
By detecting the walls around the player, I prevent him from moving in the direction of the wall which prevents him from being stuck on it and having this bug when he jumps.
(It means that my problem is not resolved and that I am still looking for a solution)
Video
...
float wallDistance;
...
[SerializeField]
bool forwardWall, backWall, rightWall, leftWall;
...
SpherecastWall();
...
if (forwardWall && playerInputs.y > 0) playerInputs.y = 0f;
if (backWall && playerInputs.y < 0) playerInputs.y = 0f;
if (rightWall && playerInputs.x > 0) playerInputs.x = 0f;
if (leftWall && playerInputs.x < 0) playerInputs.x = 0f;
void SpherecastWall() {
forwardWall = (Physics.SphereCast(
new Ray(transform.position, Vector3.forward),
wallDistance,
.2f,
groundLayer
));
backWall = (Physics.SphereCast(
new Ray(transform.position, -Vector3.forward),
wallDistance,
.2f,
groundLayer
));
rightWall = (Physics.SphereCast(
new Ray(transform.position, Vector3.right),
wallDistance,
.2f,
groundLayer
));
leftWall = (Physics.SphereCast(
new Ray(transform.position, -Vector3.right),
wallDistance,
.2f,
groundLayer
));
}
I think that's because the spheres center gets over the corner of the wall. So when you apply a force the sphere will be pushed over it.
Maybe you could replace the sphere collider of your player with a capsule or a square collider.
How do I limit the touch space to the right side of the screen so that it only registers the right side touches. Left side touch nothing will happen. How am I able to do it with this script? Been trying out for the past 2 days still cannot figure anything out. Any experts able to help me out?
public class look2 : MonoBehaviour
{
private Vector3 firstpoint; //change type on Vector3
private Vector3 secondpoint;
private float xAngle = 0.0f; //angle for axes x for rotation
private float yAngle = 0.0f;
private float xAngTemp = 0.0f; //temp variable for angle
private float yAngTemp = 0.0f;
public GameObject character;
void Start()
{
//Initialization our angles of camera
xAngle = 0.0f;
yAngle = 0.0f;
this.transform.rotation = Quaternion.Euler(yAngle, xAngle, 0.0f);
character.transform.rotation = Quaternion.Euler(yAngle, xAngle, 0.0f);
}
void Update()
{
//Check count touches
if (Input.touchCount > 0)
{
//Touch began, save position
if (Input.GetTouch(0).phase == TouchPhase.Began)
{
firstpoint = Input.GetTouch(0).position;
xAngTemp = xAngle;
yAngTemp = yAngle;
}
//Move finger by screen
if (Input.GetTouch(0).phase == TouchPhase.Moved)
{
secondpoint = Input.GetTouch(0).position;
//Mainly, about rotate camera. For example, for Screen.width rotate on 180 degree
xAngle = xAngTemp + (secondpoint.x - firstpoint.x) * 180.0f / Screen.width;
yAngle = yAngTemp - (secondpoint.y - firstpoint.y) * 90.0f / Screen.height;
//Rotate camera
this.transform.rotation = Quaternion.Euler(yAngle, xAngle, 0.0f);
character.transform.rotation = Quaternion.Euler(yAngle, xAngle, 0.0f);
}
}
}
}
You can use Screen.width to get exactly that: The width of the device's screen in pixels.
Since the Touch.position is also in screen pixel space the right half of the screen is as simple as any touch having
touch.position.x > Screen.width / 2f
you could also use >= depending whether you want one pixel more or less ;)
And then you could simply filter the touches on that condition before accessing them e.g. using Linq Where
var validTouches = Input.touches.Where(touch => touch.position.x > Screen.width / 2f).ToArray();
This is basically short for doing something like
var touches = new List<Touch>();
foreach(var touch in Input.touches)
{
if(touch.position.x > Screen.width / 2f)
{
touches.Add(touch);
}
}
var validTouches = touches.ToArray();
So your code could look like
using System.Linq;
...
void Update()
{
//Check count touches
if (Input.touchCount > 0)
{
// Now collect only touches being on the left half of the screen
var validTouches = Input.touches.Where(touch => touch.position.x > Screen.width / 2f).ToArray();
if(validTouches.Length > 0)
{
var firstTouch = validTouches[0];
// Better use switch here
switch(firstTouch.phase)
{
case TouchPhase.Began:
firstpoint = firstTouch.position;
xAngTemp = xAngle;
yAngTemp = yAngle;
break;
case TouchPhase.Moved:
secondpoint = firstTouch.position;
//Mainly, about rotate camera. For example, for Screen.width rotate on 180 degree
xAngle = xAngTemp + (secondpoint.x - firstpoint.x) * 180.0f / Screen.width;
yAngle = yAngTemp - (secondpoint.y - firstpoint.y) * 90.0f / Screen.height;
//Rotate camera
this.transform.rotation = Quaternion.Euler(yAngle, xAngle, 0.0f);
character.transform.rotation = Quaternion.Euler(yAngle, xAngle, 0.0f);
break;
}
}
}
}
I am working on a project in unity and I have a small circle that shows how much power will be applied to a ball and an arrow that shows the direction.
The circle and arrow are meant to scale up to a max distance; the arrow scales but it is too big (takes up half the screen) and doesn't rotate properly; the circle does not scale at all. I have tried to change the local scale of the arrow and messed around with the various values but I am not sure what to really do. The arrow tends to only face the correct direction when the cursor is in the top left and the arrow is in the bottom right.
The two points, point A and B are two empty objects; point B is attached to the ball and pointA follows the mouse. When the ball is clicked on and the cursor is dragged away pointB moves in the opposite direction; I am trying to get the arrow to face pointB at all times or point at pointB from the opposite side of the ball.
Everything except for the arrow and circle rotating and scaling works. I'm fairly new to code and don't understand Mathf.Log. The arrow rotate and scale code is commented out as I am currently trying to get the circle to work.
If you can point me in the right direction or help with just one of these issues I'd greatly appreciate it.
public class PlayerBallHit : MonoBehaviour
{
private GameObject mousePointA;
private GameObject mousePointB;
private GameObject arrow;
private GameObject circle;
// calc distance
private float currDistance;
public float maxDistance = 3f;
private float spaceLimit;
private float shootPower;
public float shootPowervar;
public Vector2 shootDirection;
void Start()
{
}
void Awake()
{
mousePointA = GameObject.FindGameObjectWithTag("PointA");
mousePointB = GameObject.FindGameObjectWithTag("PointB");
arrow = GameObject.FindGameObjectWithTag("Stick");
circle = GameObject.FindGameObjectWithTag("Circle");
}
private void OnMouseDrag()
{
currDistance = Vector2.Distance(mousePointA.transform.position, transform.position);
if (currDistance <= 3f)
{
spaceLimit = currDistance;
}
else
{
spaceLimit = maxDistance;
}
// Direction of Hit and Circle
StrDirMarkers();
// calc Power & Direction
shootPower = Mathf.Abs(spaceLimit) * shootPowervar;
Vector3 dimxy = mousePointA.transform.position - transform.position;
float difference = dimxy.magnitude;
mousePointB.transform.position = (Vector3)transform.position + ((dimxy / difference) * currDistance * -1);
mousePointB.transform.position = new UnityEngine.Vector3(mousePointB.transform.position.x, mousePointB.transform.position.y);
shootDirection = (Vector2)Vector3.Normalize(mousePointA.transform.position - transform.position);
}
void OnMouseUp()
{
//arrow.GetComponent<SpriteRenderer>().enabled =false;
circle.GetComponent<SpriteRenderer>().enabled = false;
Vector2 push = shootDirection * shootPower *-1;
GetComponent<Rigidbody2D>().AddForce(push, ForceMode2D.Impulse);
}
private void StrDirMarkers()
{
//arrow.GetComponent<SpriteRenderer>().enabled = true;
circle.GetComponent<SpriteRenderer>().enabled = true;
// calc position
/*
if (currDistance <= maxDistance)
{
arrow.transform.position = new Vector2((2f * transform.position.x) - mousePointA.transform.position.x, (2f * transform.position.y) - mousePointA.transform.position.y);
}
else
{
Vector2 dimxy = mousePointA.transform.position - transform.position;
float difference = dimxy.magnitude;
arrow.transform.position = (Vector2)transform.position + ((dimxy / difference) * maxDistance * -1);
arrow.transform.position = new UnityEngine.Vector2(arrow.transform.position.x, arrow.transform.position.y);
}
*/
circle.transform.position = transform.position + new Vector3(0, 0, 0.04f);
Vector3 dir = mousePointA.transform.position - transform.position;
float rot;
if(Vector3.Angle(dir, transform.forward)> 90)
{
rot = Vector3.Angle(dir, transform.right);
}else
{
rot = Vector3.Angle(dir, transform.right) * -1;
}
//arrow.transform.eulerAngles = new Vector3(0, 0, rot);
// scale arrow
float scaleX = Mathf.Log(1 + spaceLimit / 10000f, 2f) * 0.05f;
float scaleY = Mathf.Log(1 + spaceLimit / 10000f, 2f) * 0.05f;
//arrow.transform.localScale = new Vector3(1 + scaleX, 1 + scaleY, 0.001f);
circle.transform.localScale = new Vector3(1 + scaleX, 1 + scaleY, 0.001f);
}
}
try to use this code for scaling and rotate the arrow
Vector3 dir = mousePointA.transform.position - transform.position;
float rot;
if (mousePointA.transform.position.y >= transform.position.y)
{
rot = Vector3.Angle(dir, transform.position) * -1;
}
else
{
rot = Vector3.Angle(dir, transform.position);
}
arrow.transform.eulerAngles = new Vector3(0, 0, rot);
// scale arrow
float scaleValue = Vector3.Distance(mousePointA.transform.position,
transform.position);
arrow.transform.localScale = new Vector3(1 + scaleValue,
arrow.transform.localScale.y, 1);
circle.transform.localScale = new Vector3(1 + scaleValue * 0.05f, 1 + scaleValue *
0.05f, 0.001f);
Trying to build an AR app where I can have a number of input touch like drag, rotate, scale, double tap to event, hold on object to event etc.
Everything works fine in a test scene I have built [not AR].
Once included the code in my AR placedOnPlane prefab [template scene - place on plane], once I touch the object, it disappears, and I cannot figure out what I am doing wrong!
Finally, I took advantage of LeanTouch and everything works fine (why? because it's a badass asset), but I usually hate using assets when I have my code that is working equally good and I spent days on it! Some help please.
I tried commenting out the built in drag function in the PlacedOnPlane code that comes with the scene of ARfoundation but it didn't work.
using UnityEngine;
using System.Collections;
using UnityEngine.iOS;
public class InputTouchUnity : MonoBehaviour
{
private Vector3 position;
private float width;
private float height;
public float speedDrag= 0.1f;
float initialFingersDistance;
float speedTwist = -4000f;
private float baseAngle = 0.0f;
Vector3 initialScale;
// scale clamp
//public float scalingSpeed = 0.03f;
public Vector3 min = new Vector3(292f, 292f, 292f);
public Vector3 max = new Vector3(800f, 800f, 800f);
// int tapCount;
// float doubleTapTimer;
void Awake()
{
width = (float)Screen.width / 2.0f;
height = (float)Screen.height / 2.0f;
//Position used for the cube.
position = this.transform.position;
}
void OnGUI() // TO OBSERVE MOTION
{
// Compute a fontSize based on the size of the screen width.
GUI.skin.label.fontSize = (int)(Screen.width / 25.0f);
GUI.Label(new Rect(20, 20, width, height * 0.25f),
"x = " + position.x.ToString("f2") +
", y = " + position.z.ToString("f2"));
}
void Update()
{
// Handle screen touches.
if (Input.touchCount > 0)
{
RaycastHit hit;
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out hit))
initialScale = transform.localScale;
{
{
{
//DRAG - got rid of it because conflicting the AR drag
Touch touch = Input.GetTouch(0);
Move the cube if the screen has the finger moving.
if (Input.touchCount == 2)
{
if (touch.phase == TouchPhase.Moved)
{
Vector2 pos = touch.position;
pos.x = (pos.x - width) / width;
pos.y = (pos.y - height) / height;
position = new Vector3(transform.position.x + pos.x * speedDrag, 0, transform.position.y + pos.y * speedDrag);
// Position the cube.
transform.position = position;
}
}
//SCALE
if (Input.touchCount == 2)
{
Touch touch1 = Input.GetTouch(0);
if (touch1.phase == TouchPhase.Began)
{
initialFingersDistance = Vector2.Distance(Input.touches[0].position , Input.touches[1].position);
initialScale = transform.localScale;
}
else
{
var currentFingersDistance = Vector2.Distance(Input.touches[0].position, Input.touches[1].position);
var scaleFactor = (currentFingersDistance / initialFingersDistance );
transform.localScale = initialScale * scaleFactor;
Debug.Log(transform.localScale);
GameObject[] models = GameObject.FindGameObjectsWithTag ("ARobject");
newScale.x = Mathf.Clamp(model.localScale.x - scaleFactor, min.x, max.x);
newScale.y = Mathf.Clamp(model.localScale.y - scaleFactor, min.y, max.y);
newScale.z = Mathf.Clamp(model.localScale.z - scaleFactor, min.z, max.z);
model.localScale = newScale;
}
}
//TWIST
if (Input.touchCount == 2)
{
Touch touch2 = Input.GetTouch(0);
if (touch2.phase == TouchPhase.Began)
{
Vector3 pos = Camera.main.WorldToScreenPoint(transform.position);
pos = Input.mousePosition - pos;
baseAngle = Mathf.Atan2(pos.y, pos.x) * Mathf.Deg2Rad;
baseAngle -= Mathf.Atan2(transform.right.y, transform.right.x) * Mathf.Rad2Deg;
}
if (touch2.phase == TouchPhase.Moved)
{
Vector3 pos = Camera.main.WorldToScreenPoint(transform.position);
pos = Input.mousePosition - pos;
float ang = Mathf.Atan2(pos.y, pos.x) * Mathf.Deg2Rad - baseAngle;
transform.rotation = Quaternion.AngleAxis(ang * speedTwist, Vector3.up);
}
}
}
}
}
}
}
}
//}
This is because you are using Physics.Raycast which does't work on AR trackables(Planes) because they don't have any specific geometry associated with them.
So to interact with trackable data unity has provided separate Raycast method that is available in ARRaycastManager in ARFoundation.
In previous version of ARFoundation it was available in ARSessionOrigin. So check which version you are using of Ar Foundation.
You can use it like this
enter code here
`
[SerializeField] ARRaycast​Manager raycastManager;
void Update()
{
if (Input.touchCount == 0)
return;
Touch touch = Input.GetTouch(0);
if (raycastManager.Raycast(touch.position,s_Hits,TrackableType.PlaneWithinPolygon))
{
// Raycast hits are sorted by distance, so the first one
// will be the closest hit.
var hitPose = s_Hits[0].pose;
if (spawnedObject == null)
{
spawnedObject = Instantiate(cube, hitPose.position, hitPose.rotation);
}
else
{
spawnedObject.transform.position = hitPose.position;
}
}
}
`
You can also refer to SimpleAR scene from Ar Foundation sample scenes available here: https://github.com/Unity-Technologies/arfoundation-samples
I am working on a script to move an object back anf forth based on swipe similarly to a game called Sky Rusher on the iOS App Store. The movement in the original game lets you swipe in any direction and an object moves in the same direction. However, the object also "bounces" for lack of a better term. For example, if you swipe to the left, the object will tilt to the left and then tilt back to its original position. For the best example I can give, please take a look at this video for a demonstartion of the game:
Sky Rusher Gameplay
This is the code I currently have (the object also doesn't move back and forth when swiping, not sure what==y that is but have an idea on how to fix it):
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MovePlayer : MonoBehaviour
{
private Vector3 currentPos;
private Vector3 touchPos;
private float screenWidth;
private float screenHeight;
private float touchX;
private float touchY;
private float objectX;
private float objectY;
// Start is called before the first frame update
void Start()
{
touchX = 0;
touchY = 0;
screenWidth = (float)Screen.width / 2.0f;
screenHeight = (float)Screen.height / 2.0f;
currentPos = new Vector3(0.0f, 1.0f, 0.0f);
}
// Update is called once per frame
void Update()
{
if(Input.touchCount > 0)
{
Touch touch = Input.GetTouch(0);
if(touch.phase == TouchPhase.Moved)
{
//touchPos = new Vector3((touch.position.x - screenWidth)/screenWidth, (touch.position.y - screenHeight)/screenHeight + 1, 0.0f);
touchPos = new Vector3(touch.position.x, touch.position.y, 0.0f);
touchX = (touchPos.x - screenWidth)/screenHeight - 1f;
touchY = (touchPos.y - screenHeight)/screenHeight + 1f;
//objectX = ((currentPos.x * screenWidth) - screenWidth)/screenWidth;
//objectY = ((currentPos.y * screenHeight) - screenHeight)/screenHeight;
objectX = currentPos.x;
objectY = currentPos.y;
objectX += (touchX - objectX) * 1.5f;
//objectY += (touchY - objectY) * 1.5f;
if(touchX >= 0.9f)
{
objectX+=0.05f;
}
else if(touchX <= -0.9f)
{
objectX-=0.05f;
}
currentPos = new Vector3(objectX, objectY, 0.0f);
transform.position = currentPos;
}
}
}
void OnGUI()
{
/*
// Compute a fontSize based on the size of the screen width.
GUI.skin.label.fontSize = (int)(Screen.width / 40.0f);
GUI.Label(new Rect(20, 20, screenWidth, screenHeight * 0.25f),
"Pos: x = " + (objectX.ToString("f2")) +
", y = " + objectY.ToString("f2"));
GUI.Label(new Rect(20, 50, screenWidth, screenHeight * 0.25f),
"Touch: x = " + (touchX.ToString("f2")) +
", y = " + (touchY.ToString("f2")));
*/
}
}
I need my object to tilt when moved similarly to how it is done in sky rusher. My game is played in a landscape orientation on an iOS Device using Unity Remote 5 and Unity 2018.3.
Quick way to achieve this effect, if I understood correctly what you mean:
1) Each time touchX >= .9f (you are moving right) apply localRotation along Z axis with some angle.
2) Each time touchX <= -.9f (you are moving left) apply localRotation along Z axis with some negative angle.
To make this look smooth and not jumpy, apply rotation along several frames, first calculating target rotation, then using RotateTowards with some given speed. Here is yourr code slightly modified:
public float tiltEffectAngle = 20;
public float tiltEffectSpeed = 90f;
void Update() {
var targetRotation = Quaternion.identity;
if (Input.touchCount > 0) {
Touch touch = Input.GetTouch(0);
if (touch.phase == TouchPhase.Moved) {
//touchPos = new Vector3((touch.position.x - screenWidth)/screenWidth, (touch.position.y - screenHeight)/screenHeight + 1, 0.0f);
touchPos = new Vector3(touch.position.x, touch.position.y, 0.0f);
touchX = (touchPos.x - screenWidth) / screenHeight - 1f;
touchY = (touchPos.y - screenHeight) / screenHeight + 1f;
//objectX = ((currentPos.x * screenWidth) - screenWidth)/screenWidth;
//objectY = ((currentPos.y * screenHeight) - screenHeight)/screenHeight;
objectX = currentPos.x;
objectY = currentPos.y;
objectX += (touchX - objectX) * 1.5f;
//objectY += (touchY - objectY) * 1.5f;
if (touchX >= 0.9f) {
objectX += 0.05f;
targetRotation = Quaternion.Euler(
transform.localEulerAngles.x,
transform.localEulerAngles.y,
tiltEffectAngle);
} else if (touchX <= -0.9f) {
objectX -= 0.05f;
targetRotation = Quaternion.Euler(
transform.localEulerAngles.x,
transform.localEulerAngles.y,
-tiltEffectAngle);
}
currentPos = new Vector3(objectX, objectY, 0.0f);
transform.position = currentPos;
}
}
transform.localRotation = Quaternion.RotateTowards(transform.localRotation, targetRotation, tiltEffectSpeed * Time.deltaTime);
}