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 !
Related
I started coding with unity and C# a week ago so forgive me if this is a dumb question.
I have made a trampoline in unity, the player jumps on it and it bounces the player up, higher each time using simple if statements and a counting integer.
My playerController script is set in the unity inspector. The trampoline acts as intended, it's working fine.
However, I would like it if the player would reset their momentum after leaving the trampoline and touching the ground.
Currently, after leaving the trampoline and getting back on it, they are bouncing as high as they were when they left it. So the counting integer needs to be reset.
I thought to do this with a simple check of the players "isgrounded" function and if true reset the trampolines jumpCount to 0.
But this isn't working. I have no idea why. To me, it seems like it should. The isgrounded is evaluating to true but the "else if (playerFP.groundCheck == true)" isnt activating.
Heres my code:
public class Trampoline : MonoBehaviour
{
public PlayerMovement1stPerson playerFP;
[SerializeField] int jumpCount = 0;
private void OnTriggerEnter(Collider collision)
{
if (jumpCount == 0 && collision.gameObject.tag == "Player" )
{
Debug.Log("Bounce 1 activated");
playerFP.velocity.y = 5;
jumpCount ++;
}
else if (jumpCount == 1 && collision.gameObject.tag == "Player")
{
playerFP.velocity.y = 10;
jumpCount ++;
}
else if (jumpCount == 2 && collision.gameObject.tag == "Player")
{
playerFP.velocity.y = 15;
jumpCount ++;
}
else if (jumpCount >= 3 && collision.gameObject.tag == "Player")
{
Debug.Log("Max Bounce");
playerFP.velocity.y = 15;
}
else if (playerFP.groundCheck == true)
{
Debug.Log("Bounces reset");
jumpCount = 0;
}
}
}
I'd really appreciate any tips.
Your bouncing (and ground check code) is being ran inside the Trampoline's OnTriggerEnter method. This means that the check will ONLY happen when the player enters the trampoline's trigger, not when the player lands on any ground.
Move the if check outside of the OnTriggerEnter method. The Update() method inside the Trampoline script would work, but the cleanest implementation would be to store the bouncing information within the player, rather than each trampoline instance. (That also allows a player to bounce on multiple trampolines without losing the height between them)
Using Unity3D 2018.2
Trying to get Single tap, Double tap, and Hold tap.
Problems having:
Single Tap: Sometimes won't register my single tap
Double Tap: Gets called 8 times every time I double Tap my device
Triple Tap: Double Tap gets called 10 times then Triple gets called 9 times
Here is my code, please your help would be appreciated on such a simple task I can not get right, new to C# and Unity
private void handleTouchTypes()
{
foreach (Touch touch in Input.touches)
{
float tapBeginTime = 0;
float tapEndedTime = 0;
// Touches Began
if (touch.phase == TouchPhase.Began)
{
tapBeginTime = Time.time;
}
// Touches Ended
if (touch.phase == TouchPhase.Ended)
{
tapEndedTime = Time.time;
// Single Touch: for 0.022f of a Second
if (touch.tapCount == 1 && ((tapEndedTime - tapBeginTime) < 0.03f))
{
Debug.Log("Single Touch");
}
// Hold Touch: within half a second .5f to 1f
if (touch.phase == TouchPhase.Moved && touch.deltaPosition.magnitude < 0.02f && (tapEndedTime - tapBeginTime) >= 0.5f && (tapEndedTime - tapBeginTime) <= 1f)
{
Debug.Log("Holding Touch");
}
}
if (touch.tapCount == 2)
{
// Double Tap
Debug.Log("Double Tap");
}
if (touch.tapCount >= 3)
{
// Triple Tap
Debug.Log("3 Touches and/or more");
}
}
}
There's a few different things amiss here.
1) You're calling
float tapBeginTime = 0;
float tapEndedTime = 0;
at the start of each Touch element. Meaning your check for
(tapEndedTime - tapBeginTime) < 0.03f
will never pass, because tapBeginTime will have been reset to 0 by the point you set tapEndedTime = Time.time;.
If you want to track these times on a per-touch basis, I'd suggest creating a dictionary that maps the touches' fingerIds to their starting times. You don't need to record the tapEndedTime per touch, as it should suffice as a local variable calculated as needed.
2) I'm not a 100% sure on this, but you may also need to check if (touch.phase == TouchPhase.Ended) in addition to the if (touch.tapCount == 2) check, for accurate results. I know I've personally had issues not explicitly checking so in the past.
3) You're also doing a if (touch.phase == TouchPhase.Moved) check inside an if (touch.phase == TouchPhase.Ended) block. I'll let you figure this one out :)
I hope these points help you figure some of the immediate issues out. Once you've solved these surface issues, I suggest you explore ways to optimise your resulting code even further.
Good luck!
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/
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.
Need help, i googled and converted my project file to xbox 360, but i do not know the buttons and stuff.. to make it work on the game pad.
here is what i done so far
if (isAI)
{
Ball b = Game1.ball; //this is AI
if (b.Y > padMiddle)
moveDown();
else if ((b.Y + height) < padMiddle)
moveUp();
}
else
{
GamePadState currentState = GamePad.GetState(PlayerIndex.One);
if (mouse.Y < padMiddle) // I need to replace mouse with xbox360 stuff
moveUp();
else if (mouse.Y > padMiddle)
moveDown();
mouse.y was declared as MouseState mouse = MouseState.GetState();
i need to replace that with xbox 360 buttons can someone help?
You were using a click on the paddle's upper region and lower region to determine if it should be moved up and down. That's going to be a fairly difficult thing to translate exactly on the 360.
If you really want to do it the exact same way, please clarify but if you want to translate it into something that makes more sense you're going to want to use the Thumbsticks for determining whether something should move up or down.
if (isAI) {
Ball b = Game1.ball; //this is AI
if (b.Y > padMiddle)
moveDown();
else if ((b.Y + height) < padMiddle)
moveUp();
}
else
{
GamePadState currentState = GamePad.GetState(PlayerIndex.One);
if (currentState.IsButtonDown(Buttons.LeftThumbstickUp)
{
moveUp();
}
else if (currentState.IsButtonDown(Buttons.LeftThumbstickDown)
{
moveDown();
}
}
In the above code, it's detecting if the player is pushing up or pushing down on the left thumbstick of the Xbox360 controller and then moves the paddle up and down appropriately