Am trying to figure out how to get Vuforia AR camera compass direction, i.e. North/South/East/West. Can someone guide me on the same?
Tried to use below, but CameraDevice.Instance does not have any attribute to get compass direction.
Tried below, from a different Vuforia post, to see what attributes but this does not have any as well.
// Get the fields
IEnumerable cameraFields = CameraDevice.Instance.GetCameraFields();
// Print fields to device logs
foreach (CameraDevice.CameraField field in cameraFields) {
Debug.Log("Key: " + field.Key + "; Type: " + field.Type);
}
Tried something like below.
GameObject cam;
cam = GameObject.Find("ARCamera");
and tried to print cam.transform.forward, but it gives me something like (0.0,0.0,1.0). If this is the right approach, can you help me understand how to get the direction from this?
Update:
I had tried a solution using Vector3.forward, right etc. But it always prints North as the direction, irrespective of the direction in which am holding my phone. Can you pls guide me on what is wrong here? I need to find the direction in which the user is holding his phone, to show some points of interest in that direction.
I attachd this script to the ARCamera (vuforia) object itself and added the statements in the start method of the script. I tried placing them in update method also, but still the same behavior.
Pls let me know if you need more details.
GameObject cam;
cam = GameObject.Find ("ARCamera");
var dir = cam.transform.forward;
dir.y = 0;
dir.Normalize ();
if (Vector3.Angle(dir, Vector3.forward) <= 45.0) {
Debug.Log("In Start method.. North");
} else if (Vector3.Angle(dir, Vector3.right) <= 45.0) {
Debug.Log("In Start method.. East");
} else if (Vector3.Angle(dir, Vector3.back) <= 45.0) {
Debug.Log("In Start method.. South");
} else {
Debug.Log("In Start method.. West");
}
If you want to achieve an In Game Compass you could buy one from the AssetStore here. But If you want to make it yourself for free you can start here with a pretty basic one
EDIT1
Here is a script that could help
GameObject cam;
cam = GameObject.Find ("ARCamera");
if (cam.transform.eulerAngles.y >= 0 && cam.transform.eulerAngles.y <= 90)
{
print("Looking at NORTH");
}
else if (cam.transform.eulerAngles.y >= 91 && cam.transform.eulerAngles.y <= 180)
{
print("Looking at EAST");
}
else if (cam.transform.eulerAngles.y >= 181 && cam.transform.eulerAngles.y <= 270)
{
print("Looking at SOUTH");
}
else if (cam.transform.eulerAngles.y >= 271 && cam.transform.eulerAngles.y <= 360)
{
print("Looking at WEST");
}
}
Looks like Unity has something called 'Input.compass'.. so, if I set 'Input.compass.enabled=true, before starting to track location and use Input.compass.trueHeading, it gives me the direction (in terms of eulerangle, I believe) of the phone camera.. found from another blog post - https://blog.falafel.com/displaying-device-compass-unity/
Related
I have written this code for my controller in Unity. The problem is that the jump in Y axis has different height than the jump for X and Y axis simultaneously.
// Update is called once per frame
void FixedUpdate()
{
Debug.Log(rigidbody.velocity);
float inputX = Input.GetAxis("Horizontal");
//Movement X
if(inputX != 0 && isGrounded)
{
animator.SetBool("isWalking", true);
rigidbody.velocity = new Vector2(inputX*speed, 0);
//Turn left & right
if(inputX > 0)
{
spriteRenderer.flipX = false;
} else if (inputX < 0)
{
spriteRenderer.flipX = true;
}
} else
{
animator.SetBool("isWalking", false);
}
//Jump
if(Input.GetAxis("Jump") > 0 && isGrounded)
{
rigidbody.AddForce(Vector2.up * jumpImpulse, ForceMode2D.Impulse);
}
}
if i understand your code right, you only gives force to X when you are in ground, so i suggest to remove isgrounded variable and use it just for jump for example in your update method
if(isGround){
if(keypress == y){
addforce in Y
}
}
actually im a bit oxided in unity but i hope to be usefull about logical
I am pretty bad myself when it comes to the jumping physics, but i found these links maybe these will help you.
Unity 2d jumping script
https://answers.unity.com/questions/710765/2d-c-jump-script-addforce-1.html
I also want to know which jump is higher. You stated that there is a height difference when you jump without moving vs when you are moving. Which of the two jumps higher? Are you actually sure that one jumps higher than the other or does it just look like one jumps higher? You can test this by placing a platform an test if you can make it.
Sorry I can't me of more help and can only speculate of what might cause the problem. I would recommend however that when you do movement that you multiply it by Time.DeltaTime. This makes the movement time based instead of frame based. This will make the movement feel smoother.
I'm still working on "perfect" ladder movement, and what I was able to come up with is a way to calculate the exact, specific distance the character needs to move while it is on the ladder to reach the point with which it will collide perfectly with the ground above the ladder.
I know this value is exactly specific because I allow my character to land on the ladder landing when the game starts (position.y = 3.6235), and when I print the movement value in the console I get exactly 3.6235.
I'm not sure that I'm implementing this correctly in code, though, as I've noticed that this value is still barely above "0" in the console once my character is all the way up the ladder. Is Mathf.Clamp() not the correct function to limit movement, or maybe I'm using it incorrectly?
public void ClimbUpLadder(ref Vector3 deltaMovement)
{
float rayLength = raycastOrigins.centerRayLength * 2;
RaycastHit2D[] hits = Physics2D.RaycastAll(new Vector2(raycastOrigins.center.x + deltaMovement.x,
(raycastOrigins.center.y - raycastOrigins.centerRayLength + skinWidth) + deltaMovement.y), Vector2.up,
rayLength, climbMask);
Debug.DrawRay(new Vector2(raycastOrigins.center.x + deltaMovement.x,
(raycastOrigins.center.y - raycastOrigins.centerRayLength + skinWidth) + deltaMovement.y), Vector2.up * rayLength, Color.green);
for (int i = 0; i < hits.Length; i++)
{
if (hits[i])
{
if (hits[i].collider.tag == "Ladder")
{
IsClimbingLadder = true;
}
if (i >= 1 && hits[i].collider.tag == "platformOneWay")
{
//This gives us the exact distance needed to finish climbing
GameObject platform = hits[i].collider.gameObject;
Transform platformTransform = platform.GetComponent<Transform>();
float finalMoveDistance = (platformTransform.position.y - characterTransform.position.y) + platformTransform.position.y;
deltaMovement.y = Mathf.Clamp(deltaMovement.y, 0, finalMoveDistance);
print(finalMoveDistance);
}
}
}
}
Unfortunately, after I set deltaMovement.y to this value it says that finalMoveDistance is around .9 or 1.0, so I still move slightly too far up the ladder. Do you think setting the character's transform.position.y directly is the best way to smooth out the movement? My goal is to eliminate any bounce when transitioning from climbing the ladder to walking on the ground again.
I think you're making a mistake here:
float finalMoveDistance = (platformTransform.position.y - characterTransform.position.y) + platformTransform.position.y;
Why do you add the platformTransform twice?
Try this:
float finalMoveDistance = (platformTransform.position.y - characterTransform.position.y);
I have some issues with my Android/iOS game.
The concept is pretty simple (Portrait mode) :
If you tap on the left part of the screen, it bumps the ball to the right.
If you tap on the right part of the screen, it bumps the ball to the left.
The problem is, I've put this code in my controller script :
void TouchManagement()
{
for(int i = 0; i< Input.touchCount; ++i)
{
Touch touch = Input.GetTouch(i);
if(touch.phase == TouchPhase.Began)
{
Debug.Log(touch.position);
if(touch.position.x > Screen.width/2f && timer == 0f)
{
BumpLeft();
}
else if (touch.position.x <= Screen.width / 2f && timer == 0f)
{
BumpRight();
}
timer = cooldown;
}
}
}
And no matter where I tap when playing my build on my phone, the ball goes to the right. I can't even debug.log touch position with Unity remote since my phone isn't recognized for some reason.
According to other forum posts and questions, this code should work (And works with other inputs in the Editor), so I've no idea what to do.
Thanks for your help !
I'm trying to make it possible to drag an object. This object can only rotate so much. (Similair to a door).
Here is the code abit edited that rotates an object which works.
I have 2 vectors for maxrotation and minrotation.
This code will be called whenever the user is dragging the interactible object. (like update but only when dragged)
if (GestureManager.Instance.IsNavigating &&
HandsManager.Instance.FocusedGameObject == gameObject)
{
//speed and navigiation of rotation
float rotationFactor;
rotationFactor = ManipulationManager.Instance.ManipulationPosition.y * RotationSensitivity;
totransform.Rotate(new Vector3(rotationFactor, 0, 0));
}
It would be great if I could use an if statement here. And I tried quite some things but it's still not working.
As stated the code paste here works. The object should be dragable but only up to a certain points.
totransform is the transform that will be rotated
Any ideas would be great and most appreciated.
Kind regards.
I think you want to look at eulerAngles. Check the values you're getting then set an if-statement before doing the rotation. This is a sample code for you to find the values you want:
if (GestureManager.Instance.IsNavigating &&
HandsManager.Instance.FocusedGameObject == gameObject)
{
//speed and navigiation of rotation
float rotationFactor = ManipulationManager.Instance.ManipulationPosition.y * RotationSensitivity;
Debug.Log(totransform.eulerAngles);
if (totransform.eulerAngles.x < 100) {
totransform.Rotate(new Vector3(rotationFactor, 0, 0));
}
}
So here is the solution that worked for me. First I declare the movement variable (not seen down below, which is 2 in this case). Then I track the distance covered and put a limit on that.
Of course there are some improvements to this code like use movement instead of 2. But because of time constraints I didn't do it.
if (GestureManager.Instance.IsNavigating &&
HandsManager.Instance.FocusedGameObject == gameObject)
{
//here we get the movement direction and set it in movement.
if (GestureManager.Instance.NavigationPosition.y > 0)
{
movement = 2;
}
else if (GestureManager.Instance.NavigationPosition.y < 0)
{
movement = -2;
}
//the first part is false if we reach higher then maxdistance and the movement is going up
//the second part is false if we reach the lower distance and the movement is going down.
if ((!(distance > maxdistance.x) || movement < 0) && ((!(distance < mindistance.x) || movement > 0)))
{
//here we add the movement to the distance so we know if it gets closer or further
distance += movement;
//here we rotate
totransform.Rotate(new Vector3(movement, 0, 0));
}
}
Currently I am struggling to work out how to create a simple bit of code that will tell me if a tap has happened, allowing me to get the position of taps. Having looked through many different articles I am rather stumped as Touch.tapCount that is often suggested only works for ios. Also, i have tried to use Touch.deltaTime and/or Touch.deltaPosition to detect a tap but have failed.
I define a tap as having
A very short period between the finger initially touching and finally exiting the phone
Little or no movement
Thanks for reading this, I hope its clear and precise and if any detail or assistance is required on my behalf in order for your to answer feel free to ask. Any assistance is gratefully received. Thanks.
Note - I work in C#
First you have to find out if your Android device indeed can register several touches. If you have a newer device, this shouldn't be a problem. I'm going to assume that your device can, and if it can not - you'll soon find out soon enough.
let's start with the update method.
void Update() {
// Nothing at the moment
}
What we first want to do is register touches. We can do this by putting a foreach inside, checking for touches in Input.touches. Like this:
void Update() {
foreach (Touch touch in Input.touches) {
}
}
By doing this, we are always checking how many touches there are currently on the screen. What we can now do is check by fingerId, and if fingerId == 0, 1, 2... run some code. Here's what we got now:
void Update() {
foreach (Touch touch in Input.touches) {
if (touch.fingerId == 0) {
// Finger 1 is touching! (remember, we count from 0)
}
if (touch.fingerId == 1) {
// finger 2 is touching! Huzzah!
}
}
}
We're great so far! What we now want to do is detect the motion we want. In our case, we wanted taps, right? That should work perfectly with TouchPhase Began, and Ended. There's also TouchPhase.Moved, but we don't need that now.
if (touch.fingerId == 0) {
if (Input.GetTouch(0).phase == TouchPhase.Began) {
Debug.Log("First finger entered!");
}
if (Input.GetTouch(0).phase == TouchPhase.Ended) {
Debug.Log("First finger left.");
}
}
Here we are checking the phase of the corresponding finger. If you run that now, you should be able to see the messages in the console whenever your first touch enters, as well as leaves the screen. This can be done with several touches, so here's the 'whole' script:
void Update() {
foreach (Touch touch in Input.touches) {
if (touch.fingerId == 0) {
if (Input.GetTouch(0).phase == TouchPhase.Began) {
Debug.Log("First finger entered!");
}
if (Input.GetTouch(0).phase == TouchPhase.Ended) {
Debug.Log("First finger left.");
}
}
if (touch.fingerId == 1) {
if (Input.GetTouch(1).phase == TouchPhase.Began) {
Debug.Log("Second finger entered!");
}
if (Input.GetTouch(1).phase == TouchPhase.Ended) {
Debug.Log("Second finger left.");
}
}
}
}
I'm hoping this will help you. I'm fairly new at this myself, so if we're lucky - someone with more experience can come and help. I'm confident that this could be written a lot cleaner. Just remember that if you build it, you can't see the console messages. Check out Unity Remote if you haven't already. Good luck! :)
After doing some searching (Googling "unity mobile detect tap"), I found this as the top search result. #Mothil's answer gets us very close to the solution and OP's answer solves the question. However, OP's answer does not account for multiple taps. Also tracking the count of started touches, ended touches, and moved touches (e.g. int SCount, MCount, ECount) is not necessary.
Instead we can directly loop through each touch and track each individual touch by its fingerId as #mothil did. For this we'll need two arrays to track a tap's characteristics: 1) short time delay, and 2) no movement. In the arrays below, the array index is the fingerId.
private float[] timeTouchBegan;
private bool[] touchDidMove;
We'll also need one more variable to store our desired tap time threshold. In my tests, I found that a threshold of 0.2f works pretty well.
private float tapTimeThreshold = 0.2f;
In the Start() function, we'll initialize this to hold 10 elements for 10 touches. This can be modified to however many touches desired.
In the Update() function, we loop through each touch. If in TouchPhase.Began then we set the timeTouchBegan[fingerIndex] to the current time; we also set touchDidMove[fingerIndex] to false.
If in TouchPhase.Moved, we set touchDidMove[fingerIndex] to true.
Finally, in TouchPhase.Ended, we can calculate the tap time.
float tapTime = Time.time - timeTouchBegan[fingerIndex];
If the tap time is less than the threshold and the touch did not move then we have a verified tap.
if (tapTime <= tapTimeThreshold && touchDidMove[fingerIndex] == false)
{
// Tap detected at touch.position
}
Complete Script
Here's the full class:
public class TapManager : MonoBehaviour
{
private float[] timeTouchBegan;
private bool[] touchDidMove;
private float tapTimeThreshold = 0.2f;
void Start()
{
timeTouchBegan = new float[10];
touchDidMove = new bool[10];
}
private void Update()
{
// Touches
foreach (Touch touch in Input.touches)
{
int fingerIndex = touch.fingerId;
if (touch.phase == TouchPhase.Began)
{
Debug.Log("Finger #" + fingerIndex.ToString() + " entered!");
timeTouchBegan[fingerIndex] = Time.time;
touchDidMove[fingerIndex] = false;
}
if (touch.phase == TouchPhase.Moved)
{
Debug.Log("Finger #" + fingerIndex.ToString() + " moved!");
touchDidMove[fingerIndex] = true;
}
if (touch.phase == TouchPhase.Ended)
{
float tapTime = Time.time - timeTouchBegan[fingerIndex];
Debug.Log("Finger #" + fingerIndex.ToString() + " left. Tap time: " + tapTime.ToString());
if (tapTime <= tapTimeThreshold && touchDidMove[fingerIndex] == false)
{
Debug.Log("Finger #" + fingerIndex.ToString() + " TAP DETECTED at: " + touch.position.ToString());
}
}
}
}
}
Unity Tests
I tested this in my game using Unity Remote. In the screenshot below, you can see my debug console logs. I did a four finger tap. You can see that fingers 0 through 3 entered and left without any movement detected. A tap was detected for each finger and each tap's location was printed to the console.
simple yet effective, jsut add the engine at top UI and add code in update dune
enter image description here
I am pretty sure that tapCount will work on Android.
In my scenario, what handles input is not deriving from a MonoBehaviour. Instead its just an object I pass around. I wont supply the full class, but just what handles phone touches/taps.
if (Input.touchCount > i)
{
if (Input.GetTouch(i).phase == TouchPhase.Began)
{
}
if (Input.GetTouch(i).phase == TouchPhase.Canceled)
{
}
if (Input.GetTouch(i).phase == TouchPhase.Ended)
{
}
if (Input.GetTouch(i).phase == TouchPhase.Moved)
{
}
if (Input.GetTouch(i).phase == TouchPhase.Stationary)
{
}
}
The i is because I want to know how many touches the user has, but this should get you going at least.
Edit: I forgot to mention, you might want this if statement chunk inside a coroutine.
https://docs.unity3d.com/Manual/Coroutines.html
Hope this helps.