Here is my problem , i have a camera that i move right , left , down and up with Touch in android device , and i have a gui button who shows me a text when i double tap on it. The problem that when i touch the gui button , the camera move. I want when i touch the gui button , the camera stops moving and when i touch anywhere else in the screen the camera moves.
Here is my code:
public float tapSpeed = 0.5f;
private float lastTapTime = 0;
public Touch touch;
public Vector2 startPos;
public Vector2 endPos;
public bool fingerHold = false;
private float CameraYLimitUp;
private float CameraYLimitDown;
private float CameraXLimitRight;
private float CameraXLimitLeft;
public GUIText guiTextTap;
void Awake()
{
CameraYLimitUp = 0;
CameraYLimitDown = 27;
CameraXLimitRight = -15;
CameraXLimitLeft = 22;
}
void Update()
{
// Camera moves left right up down with touch
if (Input.touchCount > 0)
{
touch = Input.GetTouch(0);
if (touch.phase == TouchPhase.Began)
{
startPos = touch.position;
fingerHold = true;
print("touch began");
}
else if (touch.phase == TouchPhase.Moved)
{
endPos = touch.position;
}
else if (touch.phase == TouchPhase.Ended)
{
fingerHold = false;
print("touch end");
}
}
if (fingerHold)
{
float deltaX = endPos.x - startPos.x;
float deltaY = endPos.y - startPos.y;
bool horizontal = false;
if (Mathf.Abs(deltaX) > Mathf.Abs(deltaY))
horizontal = true;
if (horizontal)
{
if (deltaX < 0 && transform.position.x < CameraXLimitLeft)
transform.Translate(Vector3.left * Time.deltaTime * 20);
else if (deltaX > 0 && transform.position.x > CameraXLimitRight)
transform.Translate(Vector3.right * Time.deltaTime * 20);
}
else
{
if (deltaY < 0 && transform.position.y < CameraYLimitDown)
transform.Translate(Vector3.down * Time.deltaTime * 20);
else if (deltaY > 0 && transform.position.y > CameraYLimitUp)
transform.Translate(Vector3.up * Time.deltaTime * 20);
}
}
}
void OnGUI()
{
if (GUI.Button(new Rect(480 , 289.5f , 100, 100), "GUI Test"))
{
if ((Time.time - lastTapTime) < tapSpeed)
{
Debug.Log("Gui Button Taped");
guiTextTap.text = "Gui Button Taped";
}
lastTapTime = Time.time;
}
}
I Uploaded my project , you can find it here : https://mega.co.nz/#!0EkHQRDI!yDcUfJR_B5poXokku7fExOc-NtlDyYDeTCaBiAePzMs
Thanks a lot for your help
Checking the GUI hot control id would solve that issue, i.e. if the value of GUIUtility.hotControl is greater than 0, it means that the user holds down a button. Hence, you could simply modify your if statement as below to bypass the camera movement when the user presses down the button:
void Update()
{
...
...
// Check additionally if the GUI button is currently free
if (GUIUtility.hotControl == 0 && fingerHold)
{
...
...
}
}
Related
here are some parts of the code that I used for the drag and zoom of the camera. First I zoom out using two fingers, then release one of the finger. But when I drag the remaining finger, the camera jumps into the last finger position.
void Update()
{
if (Input.touchCount == 1)
{
Touch currentTouch = Input.GetTouch(0);
if (currentTouch.phase == TouchPhase.Began)
{
hit_position = currentTouch.position;
camera_position = Camera.main.transform.position;
}
if (currentTouch.phase == TouchPhase.Moved)
{
current_position = currentTouch.position;
LeftMouseDrag()
}
}
// if two fingers are touching the screen at the same time ...
else if (Input.touchCount == 2)
{
isDragging = false;
Touch touch1 = Input.touches[0];
Touch touch2 = Input.touches[1];
etc...
void LeftMouseDrag()
{
Vector3 direction = Camera.main.ScreenToWorldPoint(current_position) - Camera.main.ScreenToWorldPoint(hit_position);
direction = direction * -1;
Vector3 position = camera_position + direction * panSpeed;
Camera.main.transform.position = new Vector3(position.x, initialCameraHeight, position.z);
}
One solution would be to set a bool to true once a second finger has been placed (pinching has begun). You can then prevent the drag method from happening until pinching has ended, or the number of touches has reset back to 0 (the bool is false).
void Update()
{
if (Input.touchCount == 0)
{
isPinching = false;
}
if (Input.touchCount == 1 && isPinching == false)
{
Touch currentTouch = Input.GetTouch(0);
if (currentTouch.phase == TouchPhase.Began)
{
hit_position = currentTouch.position;
camera_position = Camera.main.transform.position;
}
if (currentTouch.phase == TouchPhase.Moved)
{
current_position = currentTouch.position;
LeftMouseDrag()
}
}
else if (Input.touchCount == 2)
{
isPinching = true;
isDragging = false;
Touch touch1 = Input.touches[0];
Touch touch2 = Input.touches[1];
//etc...
}
}
I am creating an application. If the custom View goes off the screen, a method is called. Here is my code for the custom View.
public class CustomView extends View {
private boolean bubbleOver;
private static final int BITMAP_SIZE = 64;
private static final int REFRESH_RATE = 40;
private final Paint mPainter = new Paint();
private ScheduledFuture<?> mMoverFuture;
private int mScaledBitmapWidth;
private Bitmap mScaledBitmap;
// location, speed and direction of the bubble
private float mXPos, mYPos, mDx, mDy, mRadius, mRadiusSquared;
private long mRotate, mDRotate;
CustomView (Context context, float x, float y) {
super (context);
// Create a new random number generator to randomize size, rotation, speed and direction
Random r = new Random ();
// Creates the bubble bitmap for this BubbleView
createScaledBitmap (r);
// Radius of the Bitmap
mRadius = mScaledBitmapWidth / 2;
mRadiusSquared = mRadius * mRadius;
// Adjust position to center the bubble under user's finger
mXPos = x - mRadius;
mYPos = y - mRadius;
// Set the BubbleView's speed and direction
setSpeedAndDirection(r);
// Set the BubbleView's rotation
setRotation(r);
mPainter.setAntiAlias(true);
}
private void setRotation(Random r) {
if (speedMode == RANDOM) {
// TODO - set rotation in range [1..3]
mDRotate = r.nextInt (3) + 1;
} else {
mDRotate = 0;
}
}
private void setSpeedAndDirection(Random r) {
// Used by test cases
switch (speedMode) {
case SINGLE:
mDx = 20;
mDy = 20;
break;
case STILL:
// No speed
mDx = 0;
mDy = 0;
break;
default:
// Limit movement speed in the x and y direction to [-3..3] pixels per movement.
mDx = r.nextFloat() * 6.0f - 3.0f;
mDy = r.nextFloat() * 6.0f - 3.0f;
}
}
private void createScaledBitmap (Random r) {
if (speedMode != RANDOM) {
mScaledBitmapWidth = BITMAP_SIZE * 3;
} else {
mScaledBitmapWidth = (r.nextInt(3) + 1) * BITMAP_SIZE;
}
mScaledBitmap = Bitmap.createScaledBitmap(mBitmap, mScaledBitmapWidth, mScaledBitmapWidth, true);
}
// Start moving the BubbleView & updating the display
private void start () {
// Creates a WorkerThread
ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
// Execute the run() in Worker Thread every REFRESH_RATE milliseconds. Save reference to this job in mMoverFuture
mMoverFuture = executor.scheduleWithFixedDelay(new Runnable() {
#Override
public void run() {
if (moveWhileOnScreen()) {
stop (false);
} else {
BubbleView.this.postInvalidate();
}
}
}, 0, REFRESH_RATE, TimeUnit.MILLISECONDS);
}
// Returns true if the BubbleView intersects position (x,y)
private synchronized boolean intersects(float x, float y) {
// TODO - Return true if the BubbleView intersects position (x,y)
if ((mXPos <= x) && (x <= mXPos + mScaledBitmapWidth) && (mYPos <= y) && (y <= mYPos + mScaledBitmapWidth)) {
return true;
}
return false;
}
// Cancel the Bubble's movement. Remove Bubble from mFrame.
// Play pop sound if the BubbleView was popped
private void stop (final boolean wasPopped) {
if (null != mMoverFuture && !mMoverFuture.isDone()) {
mMoverFuture.cancel(true);
}
// This work will be performed on the UI Thread
mFrame.post(new Runnable() {
#Override
public void run() {
mFrame.removeView(BubbleView.this);
if (wasPopped) {
mSoundPool.play(mSoundID, mStreamVolume, mStreamVolume, 1, 0, 1f);
}
}
});
}
// Change the Bubble's speed and direction
private synchronized void deflect(float velocityX, float velocityY) {
mDx = velocityX / REFRESH_RATE;
mDy = velocityY / REFRESH_RATE;
}
// Draw the Bubble at its current location
#Override
protected synchronized void onDraw(Canvas canvas) {
canvas.save();
mRotate += mDRotate;
canvas.rotate(mRotate, mXPos + (mScaledBitmapWidth / 2), mYPos + (mScaledBitmapWidth / 2));
canvas.drawBitmap(mScaledBitmap, mXPos, mYPos, mPainter);
canvas.restore();
}
// Returns true if the BubbleView is still on the screen after the move operation
private synchronized boolean moveWhileOnScreen() {
mXPos += mDx;
mYPos += mDy;
return isOutOfView();
}
// Return true if the BubbleView is off the screen after the move operation
private boolean isOutOfView() {
if ((mXPos + mDisplayWidth < 0) || (mYPos + mDisplayHeight < 0) || (mXPos> mDisplayWidth) || (mYPos > mDisplayHeight)) {
loseGame();
return true;
}
return false;
}
}
When the View goes off the screen, loseGame() is not called. Only if another CustomView is created, loseGame() is called.
You have wrong sum to check, try with mScaledBitmapWidth not the mDisplayWidth.
if ((mXPos + mScaledBitmapWidth < 0)
|| (mYPos + mScaledBitmapWidth < 0)
|| (mXPos> mDisplayWidth)
|| (mYPos > mDisplayHeight)
{
loseGame();
return true;
}
I am working on 2D infinite runner. I have below code to take input from screen swipe to jump, slide and run fast. I am providing jumpHeight from editor and value is 500 with frame rate of 30. Code works fine generally but sometimes player jumps too high for up swipe. Similar code works as expected if input is from Keyboard. Why this is happening is beyond my understanding of unity. Any help is greatly appreciated.
using UnityEngine;
public class PlayerControl : MonoBehaviour
{
public float ForwardSpeed = 3.7f; //moves player in forward direction
public float speedOffset = 0.0f; //offset speed of player
public float JumpHeight = 250; //moves player in verticle direction
bool grounded = false; //checks if player is grounded or not
public Transform groundCheck;
float groundCheckRadius = 0.3f; //radius of groundcheck circle to check grounded bool
public LayerMask groundLayer;
Vector2 fingerStart;
Vector2 fingerEnd;
void Update()
{
foreach (Touch touch in Input.touches)
{
if (touch.phase == TouchPhase.Began)
{
fingerStart = touch.position;
fingerEnd = touch.position;
}
if (touch.phase == TouchPhase.Moved)
{
fingerEnd = touch.position;
if (Mathf.Abs(fingerEnd.y - fingerStart.y) > 50)//Vertical swipe
{
if (fingerEnd.y - fingerStart.y > 50)//up swipe
{
Jump();
}
else if (fingerEnd.y - fingerStart.y < -50)//Down swipe
{
//Slide();
}
fingerStart = touch.position;
}
}
if (touch.phase == TouchPhase.Stationary)
{
RunFast();
}
if (touch.phase == TouchPhase.Ended)
{
fingerEnd = touch.position;
if (Mathf.Abs(fingerEnd.y - fingerStart.y) > 50)//Vertical swipe
{
if (fingerEnd.y - fingerStart.y > 50)//up swipe
{
Jump();
}
else if (fingerEnd.y - fingerStart.y < -50)//Down swipe
{
//Slide();
}
}
}
}
if (Input.GetButton("Fire1"))
{
speedOffset = 2.5f;
}
else
{
speedOffset = 0.0f;
}
if (grounded && Input.GetKeyDown(KeyCode.UpArrow))
{
grounded = false;
GetComponent<Rigidbody2D>().AddForce(new Vector2(0, JumpHeight));
}
//check if circle overlaps with ground layer
grounded = Physics2D.OverlapCircle(groundCheck.position, groundCheckRadius, groundLayer);
//Debug.Log(grounded);
}
void FixedUpdate()
{
//set players forward velocityto forward speed variable
Vector2 PlayerForwardvelocity = GetComponent<Rigidbody2D>().velocity;
// Vector2 PlayerJumpHeight = GetComponent<Rigidbody2D>().AddForce()
PlayerForwardvelocity.x = ForwardSpeed + speedOffset;
GetComponent<Rigidbody2D>().velocity = PlayerForwardvelocity;
}
void Jump()
{
if (grounded)
{
GetComponent<Rigidbody2D>().AddForce(new Vector2(0, JumpHeight));
speedOffset = 0.0f;
}
}
void RunFast()
{
if (Input.GetButton("Fire1"))
{
speedOffset = 2.5f;
}
else
{
speedOffset = 0.0f;
}
}
}
You have 2 problems with your code.
Your first problem lies in this line of code:
grounded = Physics2D.OverlapCircle(groundCheck.position, groundCheckRadius, groundLayer);
This line of code is failing. grounded is always true. Because of this, jump is called too many times while player is not grounded.
Replace this line of code with
Collider2D playerCollider = gameObject.GetComponent<Collider2D>();
grounded = Physics2D.OverlapCircle(playerCollider.transform.position, 1, groundLayer);
OR
Collider2D playerCollider = gameObject.GetComponent<Collider2D>();
grounded = playerCollider.IsTouchingLayers(groundLayer.value);
Another problem with your code is a false report.Sometimes, collider overlapping returns true even if it is false. I tried moving that part of code to LateUpdate function but that didn't fix it.
You can fix it by implementing a timer. The timer resets to 0 and starts counting to 0.5 whenever player jumps. Don't jump when timer has not reached the value it is counting to. .5 to 1 is a perfect value for this. Increment the timer with Time.deltaTime. Below is your whole code with timer and fixes.
public class PlayerControl : MonoBehaviour
{
public float ForwardSpeed = 3.7f; //moves player in forward direction
public float speedOffset = 0.0f; //offset speed of player
public float JumpHeight = 250; //moves player in verticle direction
bool grounded = false; //checks if player is grounded or not
public Transform groundCheck;
float groundCheckRadius = 0.3f; //radius of groundcheck circle to check grounded bool
public LayerMask groundLayer;
Vector2 fingerStart;
Vector2 fingerEnd;
public float resetTimer = 0.5f; //.5 second
float timerCounter = 0;
Collider2D playerCollider = null;
Rigidbody2D playerRigidBody;
void Start()
{
playerRigidBody = GetComponent<Rigidbody2D>();
playerCollider = gameObject.GetComponent<Collider2D>();
}
void Update()
{
foreach (Touch touch in Input.touches)
{
if (touch.phase == TouchPhase.Began)
{
fingerStart = touch.position;
fingerEnd = touch.position;
}
if (touch.phase == TouchPhase.Moved)
{
fingerEnd = touch.position;
if (Mathf.Abs(fingerEnd.y - fingerStart.y) > 50)//Vertical swipe
{
if (fingerEnd.y - fingerStart.y > 50)//up swipe
{
Jump();
}
else if (fingerEnd.y - fingerStart.y < -50)//Down swipe
{
//Slide();
}
fingerStart = touch.position;
}
}
if (touch.phase == TouchPhase.Stationary)
{
RunFast();
}
if (touch.phase == TouchPhase.Ended)
{
fingerEnd = touch.position;
if (Mathf.Abs(fingerEnd.y - fingerStart.y) > 50)//Vertical swipe
{
if (fingerEnd.y - fingerStart.y > 50)//up swipe
{
Jump();
}
else if (fingerEnd.y - fingerStart.y < -50)//Down swipe
{
//Slide();
}
}
}
}
if (Input.GetButton("Fire1"))
{
speedOffset = 2.5f;
}
else
{
speedOffset = 0.0f;
}
if (grounded && Input.GetKeyDown(KeyCode.UpArrow))
{
grounded = false;
playerRigidBody.AddForce(new Vector2(0, JumpHeight));
}
//check if circle overlaps with ground layer
grounded = Physics2D.OverlapCircle(playerCollider.transform.position, 1, groundLayer);
//OR Use grounded = playerCollider.IsTouchingLayers(groundLayer.value);
//Increment Timer if it is still less than resetTimer
if (timerCounter < resetTimer)
{
timerCounter += Time.deltaTime;
}
}
void FixedUpdate()
{
//set players forward velocityto forward speed variable
Vector2 PlayerForwardvelocity = playerRigidBody.velocity;
// Vector2 PlayerJumpHeight = playerRigidBody.AddForce()
PlayerForwardvelocity.x = ForwardSpeed + speedOffset;
playerRigidBody.velocity = PlayerForwardvelocity;
}
void Jump()
{
if (grounded)
{
//Exit if timer has not reached the required value to jump again
if (timerCounter < resetTimer)
{
Debug.Log("Failed To Jump because timer has not yet reached");
return; //Exit
}
timerCounter = 0; //Reset Timer
playerRigidBody.AddForce(new Vector2(0, JumpHeight));
speedOffset = 0.0f;
Debug.Log("Jumped");
}
else
{
Debug.Log("Not on the Ground");
}
}
void RunFast()
{
if (Input.GetButton("Fire1"))
{
speedOffset = 2.5f;
}
else
{
speedOffset = 0.0f;
}
}
}
In one of my Android applications (Made with Unity), I would like to move the camera by scrolling with finger on the screen and simultaneously not detect hit, when I touch on any object during scrolling. My problem is that when I want to scroll down the camera with my finger, it firstly also detects hits with the objects. I have one script which is attached to Main Camera.
Here's the code for better understanding.
//Update function for scrolling and detecting touch.
//Do not want to detect touch on objects when scrolling.
void Update () {
if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Began) {
checkTouch(Input.GetTouch(0).position);
}
if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Moved) {
Vector2 touchDeltaPosition = Input.GetTouch(0).deltaPosition;
transform.Translate(0, -touchDeltaPosition.y * Time.deltaTime, 0);
transform.position = new Vector3(0, Mathf.Clamp(transform.position.y, -30, 0), -10);
}
}
void checkTouch(Vector3 pos){
Vector3 wp = Camera.main.ScreenToWorldPoint (pos);
Vector2 touchpos = new Vector2 (wp.x, wp.y);
hit = Physics2D.OverlapPoint (touchpos);
if (hit) {
//Debug.Log (hit.transform.gameObject.name);
//hit.transform.gameObject.SendMessage ("Clicked", null, SendMessageOptions.DontRequireReceiver);
if (hit.transform.gameObject.tag == "item"){
//do something
}
}
}
I think you can try use something like this
void Update()
{
if (Input.touchCount <= 0)
return;
bool lMove = false;
if (Input.GetTouch(0).phase == TouchPhase.Moved)
{
Debug.Log("Touch phase = Moved");
lMove = true;
Vector2 touchDeltaPosition = Input.GetTouch(0).deltaPosition;
transform.Translate(0, -touchDeltaPosition.y * Time.deltaTime, 0);
transform.position = new Vector3(0, Mathf.Clamp(transform.position.y, -30, 0), -10);
}
if (Input.GetTouch(0).phase == TouchPhase.Ended)
{
Debug.Log("Touch phase = Ended");
if (!lMove)
{
//onClick
checkTouch(Input.GetTouch(0).position);
}
}
}
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class LineDirDetector: MonoBehaviour {
public Text texto01;
//inside class
Vector2 firstPressPos;
Vector2 secondPressPos;
Vector2 currentSwipe;
void Update()
{
Swipe();
}
public void Swipe() {
if (Input.touches.Length > 0) {
Touch t = Input.GetTouch(0);
if (t.phase == TouchPhase.Began) {
//save began touch 2d point
firstPressPos = new Vector2(t.position.x, t.position.y);
}
if (t.phase == TouchPhase.Ended) {
//save ended touch 2d point
secondPressPos = new Vector2(t.position.x, t.position.y);
//create vector from the two points
currentSwipe = new Vector3(secondPressPos.x - firstPressPos.x, secondPressPos.y - firstPressPos.y);
//normalize the 2d vector
currentSwipe.Normalize();
//swipe upwards
if (currentSwipe.y > 0 && currentSwipe.x > -0.5 f && currentSwipe.x < 0.5 f) {
Debug.Log("up swipe");
texto01.text = "ARRIBA";
}
//swipe down
if (currentSwipe.y < 0 && currentSwipe.x > -0.5 f && currentSwipe.x < 0.5 f) {
Debug.Log("down swipe");
texto01.text = "ABAJO";
}
//swipe left
if (currentSwipe.x < 0 && currentSwipe.y > -0.5 f && currentSwipe.y < 0.5 f) {
Debug.Log("left swipe");
texto01.text = "IZQUIERDA";
}
//swipe right
if (currentSwipe.x > 0 && currentSwipe.y > -0.5 f && currentSwipe.y < 0.5 f) {
Debug.Log("right swipe");
texto01.text = "DERECHA";
}
}
}
}
}
I am trying to rotate floor using Input.acceleration. I want to rotate floor around the point where player is standing and to limit my rotations at certain angles also stop at 0 if Input.acceleration is close to zero. considering that i'm newbie at game programming I've came up with this code:
using UnityEngine;
using System.Collections;
public class Tilt : MonoBehaviour {
public float maxRotationAngle = 350; // max rotation right
public float minRotationAngle = 10; // max rotation left
public float rotationSpeed = 20; //rotation speed
public Transform rotateAround; //rotation point
private bool stopRotation = false; //if this is true rotation stops
private int stopDir; //direction where rotation stops -1 equals left 0 center 1 right
void Update () {
int tiltDir = 0; //input tilt direction
float accel = Input.acceleration.x; //input tilt value
float currentRotation = transform.eulerAngles.z; //current rotation
//set rotation direction
if (accel > 0) {
tiltDir = 1;
}else if (accel < 0){
tiltDir = -1;
}
//stop rotation left
if (!stopRotation && (currentRotation < maxRotationAngle && currentRotation > 270)) {
stopRotation = true;
stopDir = -1;
}
//stop rotation right
if (!stopRotation && (currentRotation > minRotationAngle && currentRotation < 270)) {
stopRotation = true;
stopDir = 1;
}
//allow rotation right
if (stopRotation && stopDir < 0 && Input.acceleration.x > 0) {
stopRotation = false;
}
//allow rotation left
if (stopRotation && stopDir > 0 && Input.acceleration.x < 0) {
stopRotation = false;
}
//stop rotation center
if(!stopRotation && currentRotation < 0.2 || (currentRotation > 359.8 && currentRotation < 360)){
if(accel > -0.1 && accel < 0.1){
stopRotation = true;
stopDir = 0;
}
}
//allow rotation from center
if(stopRotation && stopDir == 0 && (accel < -0.1 || accel > 0.1)){
stopRotation = false;
}
//apply rotation
if(!stopRotation){
transform.RotateAround(rotateAround.position, new Vector3(0, 0, tiltDir), rotationSpeed * Mathf.Abs(accel) * Time.deltaTime);
}
}
}
This is working but this approach is not exact and i think there are cheaper ways of doing this. So Is there a better way?
I came up with this, which I think accomplishes what you wanted, although I may have misread your code. I've removed your magic number, changed the angles to map between -180 and 180 and renamed your variables to have full names for better maintainability.
public float maxRotationAngle = 170;
public float minRotationAngle = -170;
public float minimumAcceleration = 0.1f;
public float rotationSpeed = 20;
public Transform rotateAroundTransform;
void Update ()
{
float deltaAcceleration = Mathf.Abs(Input.acceleration.x);
float currentRotation = transform.eulerAngles.z;
//stop rotation outside of angle range and motion range
if (currentRotation > minRotationAngle &&
currentRotation < maxRotationAngle &&
deltaAcceleration < minimumAcceleration)
{
//set rotation direction
int tiltDirection = Input.acceleration.x > 0 ? 1 : -1;
transform.RotateAround(rotateAroundTransform.position, new Vector3(0, 0, tiltDirection), rotationSpeed * deltaAcceleration * Time.deltaTime);
}
}
Hope that helps!