I wanted to make a little game with touch inputs and this is the code I made for it: (This is inside the Update method)
//Check if Input has registered more than zero touches
if(Input.touchCount > 0){
//Store the first touch detected.
Touch myTouch = Input.touches[0];
//Check if the phase of that touch equals Began
if (myTouch.phase == TouchPhase.Began)
{
//If so, set touchOrigin to the position of that touch
touchOrigin = myTouch.position;
if(touchOrigin.x < -2){
horizontalInput = -1;
} else if(touchOrigin.x > 2){
horizontalInput = 1;
}
if(touchOrigin.x > -2 && touchOrigin.x < 2 && touchOrigin.y < 0){
verticalInput = 1;
}
} else if(myTouch.phase == TouchPhase.Ended){
horizontalInput = 0;
verticalInput = 0;
}
}
This is my scene: http://i.stack.imgur.com/PGbd3.jpg
When I tried it on my android phone it only moved to the right and I don't know why.
(My camera's position is: x: -6,6; y:-2,6) And I'm using an orthographic camera
This is becase you're using Touch.position, which returns values based on SCREEN space, rather than WORLD space.
What you need to do is convert the point from Screen to World space before applying your conditions. You can do that by using Camera.ScreenToWorldPoint.
Related
I'm creating an Android game with Unity. There are only three ways to control the movement of the character:
Tap in the right half of the screen: jump to the right
Tap in the left half of the screen: jump to the left
Swipe upwards: character dashes forward
In theory, I know that I can differentiate the touches with the TouchPhases (began, moved, stationary and ended). When only detecting the taps without caring for swipes, I just checked if the phase of the touch began and made the player jump. That felt fast on my device.
However, because I have to consider that a swipe may follow, I can not initiate the jump action until I detected ThouchPhase.Ended. This leads to a very slow responding character, which doesnt jump until the user rises his finger of the screen.
I tried to use ThouchPhase.Moved and ThouchPhase.Stationary instead to simulate a immediate response but my solution is pretty bad in terms of detecting the difference between a tap and a swipe:
Vector2 startTouchPosition;
Vector2 endTouchPosition;
Vector2 currentSwipe;
void Update()
{
if (Input.touches.Length > 0)
{
for (int i = 0; i < Input.touchCount; i++)
{
Touch touch = Input.GetTouch(i);
if (touch.phase == TouchPhase.Began)
{
//save began touch 2d point
startTouchPosition = new Vector2(touch.position.x, touch.position.y);
}
if (touch.phase == TouchPhase.Moved || touch.phase == TouchPhase.Stationary)
{
//save ended touch 2d point
endTouchPosition = new Vector2(touch.position.x, touch.position.y);
if (endTouchPosition.y - startTouchPosition.y < 5)
{
if (touch.position.x > (Screen.width / 2))
{
JumpToRight();
}
else if (touch.position.x < (Screen.width / 2))
{
JumpToLeft();
}
}
else
{
//create vector from the two points
currentSwipe = new Vector2(endTouchPosition.x - startTouchPosition.x, endTouchPosition.y - startTouchPosition.y);
//normalize the 2d vector
currentSwipe.Normalize();
//swipe upwards
if (currentSwipe.y > 0 && currentSwipe.x > -0.5f && currentSwipe.x < 0.5f)
{
DashForward();
}
}
}
}
}
}
Here is the code I used. I tested and it works but sometimes, I noted a delay. Let me know if it is good enough for you. Basically you dont need to go through all touches if you dont need multi-touch. And you just need Begin and End touch phases.
using System.Collections;
using System.Collections.Generic;
using UnityEngine.UI;
using UnityEngine;
public class touch : MonoBehaviour {
private Vector2 startTouchPosition;
private Vector2 endTouchPosition;
private Vector2 currentSwipe;
public Text textbox;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
if (Input.touches.Length > 0)
{
Touch touch = Input.GetTouch(0);
if (touch.phase == TouchPhase.Began)
{
//save began touch 2d point
startTouchPosition = new Vector2(touch.position.x, touch.position.y);
}
if (touch.phase == TouchPhase.Ended)
{
//save ended touch 2d point
endTouchPosition = new Vector2(touch.position.x, touch.position.y);
//create vector from the two points
currentSwipe = new Vector2(endTouchPosition.x - startTouchPosition.x, endTouchPosition.y - startTouchPosition.y);
//normalize the 2d vector
currentSwipe.Normalize();
if(Mathf.Abs(currentSwipe.y) < 0.1f && Mathf.Abs(currentSwipe.x) < 0.1f)
{
if (touch.position.x > (Screen.width / 2))
{
textbox.text= "jump right";
}
else if (touch.position.x < (Screen.width / 2))
{
textbox.text= "jump left";
}
}
if (currentSwipe.y > 0 && currentSwipe.x > -0.5f && currentSwipe.x < 0.5f)
{
textbox.text= "Dash forward";
}
}
}
}
}
Right now I've been developing a game which will make the character move up or down if either swipe up or down on the left side of the screen. Then, he can also, shoot projectiles if I tap the right side of the screen. I've succeeded on making it work but the problem is that the swipe function do not works while I tap the the right screen. Both only works if I do one of them. I cannot move the character if I am firing projectiles. Any suggestions? Appreciate it in advanced.
Here's the code:
For the swipe movement function:
void Swipe() {
if (Input.touchCount > 0) {
Touch t = Input.GetTouch(0);
if (t.phase == TouchPhase.Began)
{
lp = t.position;
fp = t.position;
text.text = fp.x.ToString();
}
else if (t.phase == TouchPhase.Ended)
{
lp = t.position;
//Swipe Up
if (fp.y < lp.y && fp.x < 400)
{
currentLane += 1;
}
//Swipe Down
else if (fp.y > lp.y && fp.x < 400)
{
currentLane -= 1;
}
}
}
}
And here's the code for the tap or firing projectiles function:
void FireBullets() {
interval += 2 * Time.deltaTime;
anim.SetBool("Attacking", firing);
if (Input.touchCount > 0 && interval > .75f) {
Vector3 bulletTouchPos;
Touch bulletT = Input.GetTouch(0);
bulletTouchPos = bulletT.position;
if (bulletT.phase == TouchPhase.Began) {
if (bulletTouchPos.x > 400)
{
interval = 0;
firing = true;
//Fire Bullets
Instantiate(bullets, new Vector3(transform.position.x + 1.2f, transform.position.y + .3f, transform.position.z), Quaternion.identity);
}
}
}else
{
firing = false;
}
}
Your lp and fp values don't care which finger is being checked.
If you want to detect multiple touch gestures at once, you need to discriminate your detection based on which finger that is.
You can do this by looking at the Touch.fingerId value, which is unique for each finger. Fingers are just an ID assigned to a given touching point as it moves across the screen in order to identify it from other touching points currently also on the screen.
You'll need to adjust your code to handle how to store the information you need in order to do what you need, but this should get you started.
I'm doing a game to android with Unity and I don't know how to do to jump more or less depending how much time you press the screen, I tried it but I don't know how to do it, I used deltatime but it doesn't work, at least no at least not in the way I did it, so I would like to know how to do that. The character jumps but just a little bit, it doesn't matter how much time I press the screen, it jumps so low.
This is how I've tried to accomplish that:
void Update () {
movimiento ();
if (transform.position.x <= 4.65f) {
SceneManager.LoadScene ("Game Over");
}
if (Input.touchCount > 0) {
GetComponent<Animator> ().Play ("Andar 2");
print (Input.GetTouch (0).deltaTime);
if (Input.GetTouch (0).deltaTime >= 2) {
GetComponent<Rigidbody2D> ().AddForce (Vector3.up * Time.deltaTime * 20000);
GetComponent<Animator> ().Play ("Andar 2");
} else if (Input.GetTouch (0).deltaTime >= 1) {
GetComponent<Rigidbody2D> ().AddForce (Vector3.up * Time.deltaTime * 2000);
} else if (Input.GetTouch (0).deltaTime < 1) {
GetComponent<Rigidbody2D> ().AddForce (Vector3.up * Time.deltaTime * 200);
}
}
}
I like to work with velocities directly when doing jumps as i feel like i can be more precise with it, But regardless, here is my solution for variable height jumps.
void Update ()
{
// set jump controls
if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Began)
jump = true;
if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Ended && !grounded)
jumpCancel = true;
}
void FixedUpdate()
{
// if player presses jump
if (jump)
{
rigidbody.velocity = new Vector3(rigidbody.velocity.x, jumpVelocity, rigidbody.velocity.z);
jump = false;
}
// if player performes a jump cancel
if (jumpCancel)
{
if (rigidbody.velocity.y > shortJumpVelocity)
rigidbody.velocity = new Vector3(rigidbody.velocity.x, shortJumpVelocity, rigidbody.velocity.z);
controller.jumpCancel = false;
}
}
This works by altering the player's velocity if the finger is lifted before the shortJumpVelocity is reached. As you can see you will have to have a grounded state of some kind for this to work properly.
I love this method as it avoids timers and gives the player a lot of control.
I am trying to move and object by touching it and dragging. I am testing it on my Samsung Galaxy SIII. I have used the following code. For some reason it moves faster than my finger. It should always be beneath my finger. What is wrong? (note: I haven't done the "move object only if you touch onto it" part, so right now it moves where ever I touch).
#pragma strict
var speed : float = 1;
function Start () {
}
function Update () {
if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Moved) {
// Get movement of the finger since last frame
var touchDeltaPosition:Vector2 = Input.GetTouch(0).deltaPosition;
// Move object across XY plane
transform.position = Vector2.Lerp(transform.position,
touchDeltaPosition,
Time.deltaTime*speed);
}
}
this is what i use, it may be a better option for you, it is based on the camera, the reason that your Vector2.Lerp is not working correctly i think is because of your time variable in it you could refer to this Lerp and tweak your 't' variable until it is good for you, or you can try this, this is what i use, also i subtract from x and add to y so my finger isnt over the graphic, best of luck :)
#pragma strict
var speed : float = 1;
var distance : float = 5;
function Start () {
}
function Update () {
if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Moved) {
// Get movement of the finger since last frame
var touchDeltaPosition:Vector2 = Input.GetTouch(0).deltaPosition;
var touchmove : Vector3 = Vector3(touchDeltaPosition.x, touchDeltaPosition.y, distance);
// Move object across XY plane
transform.position = Camera.main.ScreenToWorldPoint(touchmove);
}
}
I'm working on a simple platformer and I've been through a couple of collision systems before finally finding the solution that has thus far been as stable as I could hope for. That is until the player collides with a block whose CENTER position in the y axis equals 0. It's very wierd although I suspect it's only in the y axis because I check the x movement/collision first. I have no idea.
I do a simple AABB type collision check/response where I apply the x velocity first then if overlap, reposition player so that right player bound = left block bound bringing them out of overlap. I then go through the same with the y axis taking the player vertical direction to work out whether player has hit bottom side or top side of block. The only controls are jump as the player has an acceleration force in positive x hence the player will never travel left.
The problem is that the player moves off the blue dotted block but when it hits the red dotted one a collision is detected in the Y axis thus the player gets moved up out of overlap but then when the next frame executes the player's velocity in x is added as usual but a collision gets registered and it then positions the player to the left of the red block. The next frame detects a collision with the blue block and thus it positions the player on top of it as shown below.
The setup up below makes the player loop this sequence over
Info:
player.centerPosition = (2, 2)
player.width = 0.5f
player.height = 0.8f
blueBlock.centerPosition = (1, 1)
redBlock.centerPosition = (4, 0)
block.width = 3
block.height = 1
private void checkBlockCollision(float deltaTime) {
List<GameObject> colliders = grid.getPotentialColliders(player);
int len = colliders.size();
for (int axis=0;axis<2;axis++) { // 0 = X-axis, 1 = Y-axis
if (axis == 0) {
player.position.add(player.velocity.x*deltaTime, 0);
player.updateBounds();
} else {
player.position.add(0, player.velocity.y*deltaTime);
player.updateBounds();
}
for (int i=0;i<len;i++) { // Cycle through all blocks found in broad phase
GameObject collider = colliders.get(i);
if (OverlapTester.overlapRectangles(player.bounds, collider.bounds)) {
if (axis == 0) {
player.position.x = collider.position.x - (Player.PLAYER_WIDTH + collider.bounds.width)/2;
player.velocity.x = 0f;
Log.d("TAG", "Move player LEFT");
} else {
if (player.velocity.y > 0) {
player.position.y = collider.position.y - (Player.PLAYER_HEIGHT + collider.bounds.height)/2;
player.velocity.y = -player.velocity.y*0.333f;
Log.d("TAG", "Move player DOWN");
} else {
player.position.y = collider.position.y + (Player.PLAYER_HEIGHT + collider.bounds.height)/2;
player.velocity.y = 0;
player.state = Player.PLAYER_STATE_GROUNDED;
Log.d("TAG", "Move player UP");
}
}
}
} // end for loop colliders
} // end for loop axis
} // END METHOD
If anyone can shed some light on what the truck is going on here that would be amazing.
Thanks for reading and I can provide any further info or source to anyone interested.
Marios Kalogerou
SOLUTION:
I found a quick and dirty fix to the my problem. I just simply moved the player up an extra 0.001 units and this actually seperated the objects. Strange that since other blocks worked fine. Thanks again if you read through that and I hope my solution helps anyone with similar issues.