I'm having an issue with the cameras in Unity. When the camera moves through any means it seems to cut my FPS in half if not more. It's not really noticeable on PC, unless I'm looking at the from from 800fps to about 150fps, however on mobile it'll cut the smooth 60fps I'm getting to 20fps on a Nexus 4. It's absolutely devastating.
Here's the properties for the camera I'm using & the script HOWEVER this issue still happens without ANY of these components and a completely reset camera component:
public class ViewDrag : MonoBehaviour
{
public Vector3 hit_position = Vector3.zero;
public Vector3 current_position = Vector3.zero;
public Vector3 camera_position = Vector3.zero;
public Vector2 min_position;
public Vector2 max_position;
float z = 0.0f;
MouseHolder holder;
hider sidebarHide;
GameObject gameStructure;
// Use this for initialization
void Start()
{
gameStructure = GameObject.FindGameObjectWithTag("GameStructure");
holder = gameStructure.GetComponent<MouseHolder>();
sidebarHide = GameObject.FindGameObjectWithTag("SidebarBG").GetComponent<hider>();
}
void Update()
{
if (Input.GetMouseButtonDown(0))
{
hit_position = Input.mousePosition;
camera_position = transform.position;
}
if (Input.GetMouseButton(0))
{
current_position = Input.mousePosition;
LeftMouseDrag();
}
if (!sidebarHide.isHidden)
{
//GetComponent<Camera2DFollow>().enabled = true;
}
if(gameStructure.GetComponent<ExecuteMovement2>().isExecuted)
{
//GetComponent<Camera2DFollow>().enabled = true;
}
}
void LeftMouseDrag()
{
// From the Unity3D docs: "The z position is in world units from the camera." In my case I'm using the y-axis as height
// with my camera facing back down the y-axis. You can ignore this when the camera is orthograhic.
//current_position.z = hit_position.z = camera_position.y;
// Get direction of movement. (Note: Don't normalize, the magnitude of change is going to be Vector3.Distance(current_position-hit_position)
// anyways.
Vector3 direction = Camera.main.ScreenToWorldPoint(current_position) - Camera.main.ScreenToWorldPoint(hit_position);
// Invert direction to that terrain appears to move with the mouse.
direction = direction * -1;
Vector3 position = camera_position + direction;
if (position.x < max_position.x && position.x > min_position.x && position.y < max_position.y && position.y > min_position.y)
{
if (!EventSystem.current.IsPointerOverGameObject() && holder.fromSlot == null )
{
if (sidebarHide.isHidden)
{
if (!gameStructure.GetComponent<ExecuteMovement2>().isExecuted)
{
//GetComponent<Camera2DFollow>().enabled = false;
transform.position = position;
}
}
}
}
}
}
Has anyone got an idea why this happens and how I can work around it if not fix it?
Through closer inspection I think it has something to do with the Canvas being screen space.. But it's kind of needed that way. Again, any workaround?
Check comments for profiler screenshot.
Problem Solved:
In the profiler I found that Canvas.SendWillRenderCanvases() was causing huge spikes. I solved the issue completely by turning off Pixel Perfect in the Canvas. Smooth as butter now.
Related
I've got a falling object, which i want to move back and forth horizontally while falling.
While i've manage to do this, i'm getting a jittery movement while this happens. When the object falls without horizontal movement, theres no jittery movement.This is also the case if the object just moves horizontally without falling.
I'm currently using rigidbody2d.velocity to move it horizontally and have tried using transform.position and translate but didn't see any difference in smoother movement.
Jittery Movement GIF
So clearly theres an issue with combine the two movements together, but i can't work out how to remedy this in order to make it a smooth movement.
Object Inspector Image
Here's the object code for it's movement:
public float verticalSpeed = 7f;
private Rigidbody2D object_RB;
private int moveHorizontal;
private int horizontalSpeed;
void Start()
{
object_RB = GetComponent<Rigidbody2D>();
moveHorizontal = Random.Range(1, 3);
horizontalSpeed = Random.Range(4, 7);
}
void Update()
{
if (transform.position.y <= -10f)
{
Destroy(gameObject);
}
if (transform.position.x < -1.7f)
{
moveHorizontal = 1;
}
else if (transform.position.x > 1.7f)
{
moveHorizontal = 2;
}
transform.position -= transform.up * Time.deltaTime * verticalSpeed;
}
void FixedUpdate()
{
if (moveHorizontal == 1)
{
object_RB.velocity = new Vector2(horizontalSpeed, 0);
}
else if (moveHorizontal == 2)
{
object_RB.velocity = new Vector2(-horizontalSpeed, 0);
}
}
I'm stuck with this and would appreciate some input to fix this movement.
EDIT - I've tried setting the Interpolate property of the rigidbody to Interpolate or Extrapolate and had no luck. If i set it to Interpolate, the horizontal movement slows down drastically, to a point where it doesn't seem like its moving horizontally at all. Changing it to Extrapolate actually increases the jittery effect.
Vector2 mousePos = Input.mousePosition;
// motion core
if (GameObject.Find("Camera").GetComponent<room>().playerNum == 1)
{
if (Input.GetMouseButtonDown(0))
{
// move script not working
}
}
So, I have mostly every possible solution I could find but none of them worked. I cannot get it to smoothly move with AddForce because I could not figure out a working algorithm to make the force move toward the MousePosition.
The position you're getting out of Input.mousePosition are the coordinates on the screen, not the position in the world. To transform between the two, you can use Camera.ScreenToWorldPoint().
if (Input.GetMouseButtonDown(0))
{
Vector3 mousePos = Input.mousePosition
mousePos = new Vector3(mousePos.x, mousePos.y, Camera.main.nearClipPlane)
Vector3 worldPos = Camera.main.ScreenToWorldPoint(new Vector3())
// move script
}
You might need to edit the z coordinate in the mousePos to the current transform.position.z of the object you're trying to move, or another value that makes most sense here. It acts as a kind of wall, where it'll create the point exactly that far from the camera on your mouse position. This should be a lot cheaper than raycasting, and still works if there's nothing to hit where you're clicking.
I have a script that did this same movement to the handle of a wrecking ball, but I don't have the code with me at the moment. I can't remember exactly how it worked, but I think the idea was that when the mouse was clicked, drag would be set to a very high number and gravity would be set to 0. Then an extremely strong force would be added to counter the drag so that the object would fly towards the mouse without orbiting. When the mouse was released, the drag and gravity would be set back to normal.
I can't test this at the moment because I'm on a chromebook and my PC with Unity on it is in another building, but this code should do the trick if I don't make any errors.
using UnityEngine;
public class ExampleClass : MonoBehaviour
{
float prevDrag, prevGrav;
bool mousedown;
Plane plane;
Rigidbody2D r;
void Start()
{
r = GetComponent<Rigidbody2D>(); // assuming this script is attached to the object being moved.
plane = new Plane(Vector3.up, Vector3.zero);
}
void Update()
{
if(mousedown)
{
float enter;
if (plane.Raycast(ray, out enter))
{
var hitPoint = ray.GetPoint(enter);
var mouseDir = hitPoint - gameObject.transform.position;
rb.AddForce(mouseDir * 9999999);
}
}
}
void OnMouseDown()
{
mousedown = true;
prevDrag = r.drag;
prevGrav = r.gravity;
r.drag = 99999;
r.gravity = 0;
}
void OnMouseUp()
{
mousedown = false;
r.drag = prevDrag;
r.gravity = prevGrav;
}
}
I want to rotate the bar based on my finger touch draw related to the pivot point. Following test structure implementation, I have created it for testing purposes.
Currently, I can able to write this code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TestRotateController : MonoBehaviour
{
float rotateSpeed = 10f;
Vector2 touchStartPos;
Transform touchItem;
//
[SerializeField] LayerMask touchItemsMask;
private void Update()
{
if (Input.GetMouseButtonDown(0))
{
Vector3 mousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
Vector2 mousePos2D = new Vector2(mousePos.x, mousePos.y);
RaycastHit2D hit = Physics2D.Raycast(mousePos2D, Vector2.zero, 0f, touchItemsMask);
if (hit.collider != null && hit.transform.CompareTag(GameConstants.TAG_RELEASE_ANGLE_BAR))
{
touchItem = hit.transform;
touchStartPos = mousePos2D;
}
}
else if (Input.GetMouseButton(0))
{
if (touchItem != null && touchItem.CompareTag(GameConstants.TAG_RELEASE_ANGLE_BAR))
{
Vector3 mousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
Vector2 mousePos2D = new Vector2(mousePos.x, mousePos.y);
RotateReleaseAngleBar(touchStartPos, mousePos2D);
}
}
else if (Input.GetMouseButtonUp(0))
{
touchItem = null;
}
}
// rotate pivot parent
public void RotateReleaseAngleBar(Vector2 touchStartPosition, Vector2 touchPosition)
{
if (touchStartPosition.x > touchPosition.x)
{
transform.parent.Rotate(Vector3.forward, rotateSpeed * Time.deltaTime);
}
else if (touchStartPosition.x < touchPosition.x)
{
transform.parent.Rotate(Vector3.forward, -rotateSpeed * Time.deltaTime);
}
}
}
Now with this code, I can't able to rotate the bar as my finger is moving.
Selected direction will remain proper because I have used X value to decide this but when I stop dragging my finger then also rotation remain continue in the same direction.
I want to stop this, I want to rotate the bar based on finger drag amount. It is a kind of experience, I want a person is rotating the bar with his finger.
I think you don't really want to rotate the bar by a certain amount each frame, but instead update its rotation at each frame with respect to the finger.
You are currently rotating the bar not considering the exact (x,y) mouse2D position of current frame, which is what you need.
This script works for me, assuming you assign it to the child of the pivot (as I assume you did from the screenshot)
public class TestRotateController : MonoBehaviour
{
//member variables
void Update() {
//[...] take the input as you did...
//else
if (Input.GetMouseButton(0)) {
//if(touchItem != null...) {
Vector3 mousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
Vector2 mousePos2D = new Vector2(mousePos.x, mousePos.y);
RotateFollowPoint(mousePos2D);
//}
}
//[else...]
}
//sets the angle of the bar to point in the direction of targetPoint2D
void RotateFollowPoint(Vector2 targetPoint2D) {
Vector2 position2D = new Vector2(transform.parent.position.x, transform.parent.position.y);
float angle = Vector2.Angle(Vector2.right, targetPoint2D - position2D);
if (targetPoint2D.y < position2D.y)
angle *= -1;
transform.parent.eulerAngles = new Vector3(0, 0, angle);
}
}
First you take the position 2D of the pivot point, then you compute the acute angle between the vector pointing from the pivot to the clicked point, which is targetPoint2D - position2D, and the Vector2.right vector (which is (1,0), so a vector pointing right), which means that the bar must be oriented to the right on its default position (when rotation on Z of the pivot = 0).
Then since Vector2.Angle gives the acute angle, set it negative if it should be more than 180°, and finally just update the angle accordingly
i'm trying to implement a simple orbit camea that can rotate and zoom in a scene. I followed some tutorials and i can run my program without any problems on windows if i build it as a PC Standalone. If i build it as WebGL my camera still correctly works with a single touch (rotation) , with multi touch i have a strange behaviour.. Difficult to explain but it zoomsin and out even if i do not move the fingers. Is king of "fuzzy". It happens with Firefox and Chrome, the browsers i have tested.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CameraOrbitTouch : MonoBehaviour {
protected Transform _XForm_Camera;
protected Transform _XForm_Parent;
protected Vector3 _LocalRotation;
protected float _CameraDistance = 10f;
// The rate of change of the field of view in perspective mode.
public float perspectiveZoomSpeed = 0.2f;
public float OrbitDampening = 30f;
public float ScrollDampening = 18f;
public bool CameraDisabled = false;
// Use this for initialization
void Start() {
this._XForm_Camera = this.transform;
this._XForm_Parent = this.transform.parent;
}
void LateUpdate() {
if (Input.GetKeyDown(KeyCode.LeftShift))
CameraDisabled = !CameraDisabled;
if (!CameraDisabled)
{
//Rotation of the Camera based on Mouse Coordinates
if (Input.touchCount == 1 && Input.GetTouch(0).phase == TouchPhase.Moved)
{
_LocalRotation.x += Input.touches[0].deltaPosition.x ;
_LocalRotation.y += Input.touches[0].deltaPosition.y;
//Clamp the y Rotation to horizon and not flipping over at the top
if (_LocalRotation.y < 0f)
_LocalRotation.y = 0f;
else if (_LocalRotation.y > 90f)
_LocalRotation.y = 90f;
}
//Zooming Input from our Mouse Scroll Wheel
if (Input.touchCount == 2 && Input.GetTouch(0).phase == TouchPhase.Moved && Input.GetTouch(1).phase == TouchPhase.Moved)
{
// Store both touches.
Touch touchZero = Input.GetTouch(0);
Touch touchOne = Input.GetTouch(1);
// Find the position in the previous frame of each touch.
Vector2 touchZeroPrevPos = touchZero.position - touchZero.deltaPosition;
Vector2 touchOnePrevPos = touchOne.position - touchOne.deltaPosition;
// Find the magnitude of the vector (the distance) between the touches in each frame.
float prevTouchDeltaMag = (touchZeroPrevPos - touchOnePrevPos).magnitude;
float touchDeltaMag = (touchZero.position - touchOne.position).magnitude;
// Find the difference in the distances between each frame.
float deltaMagnitudeDiff = (prevTouchDeltaMag - touchDeltaMag);
//this._CameraDistance += deltaMagnitudeDiff * -1f;
this._CameraDistance += deltaMagnitudeDiff * perspectiveZoomSpeed;
this._CameraDistance = Mathf.Clamp(this._CameraDistance, 1.5f, 100f);
}
}
//Actual Camera Rig Transformations
Quaternion QT = Quaternion.Euler(_LocalRotation.y, _LocalRotation.x, 0);
this._XForm_Parent.rotation = Quaternion.Lerp(this._XForm_Parent.rotation, QT, Time.deltaTime * OrbitDampening);
if ( this._XForm_Camera.localPosition.z != this._CameraDistance * -1f )
{
this._XForm_Camera.localPosition = new Vector3(0f, 0f, Mathf.Lerp(this._XForm_Camera.localPosition.z, this._CameraDistance * -1f, Time.deltaTime * ScrollDampening));
}
}
}
Can someone can tell me why this is happening? Have my code some errors? There is some kind of incompatibility with WebGL and multi touch? Thans for your time and answers
Ok i found the problem. The problem was Windows 7. I used the same code on another computer with windows 10 and it works as intended...
I'm making a simple project in Unity where there is a Ball attached to a SpringJoint2d component the ball is on an angled slope, like in the image below:
I simply want the user to be able to drag the ball backward along the edge of the slope only,in other words I don't want the user to be able to move the ball away from the slope or into it.
I'v been trying several ways I thought could do the job hers the script of the dragging with what I tried:
(This Is the updated version)
public class ball : MonoBehaviour
{
public Rigidbody2D rb;
public Transform spring;
public Transform calcpoint;
private Vector3 start;
private Vector3 end;
private bool isPressed = false;
RaycastHit2D[] hits = new RaycastHit2D[2];
RaycastHit2D[] hits2 = new RaycastHit2D[2];
float factor = 0;
private void OnMouseDown()
{
if (!isPressed)
{
isPressed = true;
rb.isKinematic = true;
}
}
private void OnMouseUp()
{
isPressed = false;
rb.isKinematic = false;
StartCoroutine(release());
}
/// <summary>
/// release the ball from the spring joint after a small amount of time
/// </summary>
/// <returns></returns>
IEnumerator release()
{
yield return new WaitForSeconds(0.1f);
rb.GetComponent<SpringJoint2D>().enabled = false;
}
// Update is called once per frame
void Update()
{
if (isPressed)
{
if (Vector3.Distance(spring.position, rb.position) > 3f || spring.position.x < (rb.position.x - 1)) return;//restrict the dragging of the ball to not go beyond the spring point and not too far back
float angle = 0;
if (checkGround() > 1)//if we hit the slope with the ray cast downward from the mouse/Tap position
{
angle = Mathf.Abs(Mathf.Atan2(hits[1].normal.x, hits[1].normal.y) * Mathf.Rad2Deg); //get angle
factor = (float)(((45 - angle) * 0.02) + 1) * (angle / 45);//an inaccurate formula to offset the ball to be on top of the slope that works just fine with some glitches
rb.position = hits[1].point + new Vector2(0, factor * 1f);//position the ball at the point were the ray cast downward from the mouse hit
//(that puts the ball center on the line of the slope) so I offset it usinf the formula above
}
}
}
private int checkGround()
{
int h = Physics2D.RaycastNonAlloc(Camera.main.ScreenToWorldPoint(Input.mousePosition), -Vector2.up, hits); //cast downwards
return h;
}
}
here are the settings on the ball:
and the slope setup:
The dragging of the ball works fine ,at one point the player could drag it in the air or into the slope, I managed to fix that with the new code so now the player could only drag it on the edge, though my calculations are still a bit flawed and when the slopes angle is changed the ball would dip a bit inside the slope and that causes some problems at release.
The method used to try to solve the problem is simple, when the player start dragging the ball I cast a ray from the mouse downward and pit the ball on the point of impact with the slope ,offsetting it to sit on top of it,right ow the problem is that the offsetting part is not accurate enough.
I hope I explained myself a bit better this time Thanks:)
After lots of trial and error I did manage to come up with a perfect solution to the problem so I thought I might as well share the answer maybe it will help someone.
here is the updated code I changed my method of restricting the movement completely now I use simple linear line equation as shown below:
private void OnMouseDown()
{
if (!isPressed)
{
//cast a ray on the slope
if (checkGround() > 1)
{
angle = Mathf.Abs(Mathf.Atan2(hits[1].normal.x, hits[1].normal.y) * Mathf.Rad2Deg); //get angle
slope = Mathf.Tan(angle * Mathf.Deg2Rad);//get the slope steepiness
}
isPressed = true;
rb.isKinematic = true;
}
}
private void OnMouseUp()
{
isPressed = false;
rb.isKinematic = false;
StartCoroutine(release());
}
void Update() {
if (isPressed)
{
xMove = Camera.main.ScreenToWorldPoint(Input.mousePosition).x - spring.position.x;//get how much the mouse moved backward or forward
if (xMove < -3f ) xMove = -3f; //restrict the drag range to 3 backward
if (xMove > 0.3f) xMove = 0.3f;//restrict the drag range to 0.3 forward
xpos = spring.position.x+xMove;//since the ball and the spring start at exactly the same position the new ball's x position would be the spring x + the x movement we calculated above
ypos = (xMove * slope)- spring.position.y; //the y posistion would be y=mx+b so the the x movement * the slop steepiness - the starting y position
rb.position = new Vector2(xpos, -ypos);//set the new position of the ball
}
}
private int checkGround()
{
int h = Physics2D.RaycastNonAlloc(Camera.main.ScreenToWorldPoint(Input.mousePosition), -Vector2.up, hits); //cast downwards
return h;
}