I am developing a game where objects fall from the top of the screen, and you try to and tap on them before they reach the bottom of the screen. The code works fine when I played the game in the editor (with the touch controls swapped to mouse controls), except when I run the game on a phone, the game only seems to register a successful hit if you tap slightly in front of the object in the direction that it is traveling, and does not register a hit if you tap towards the back end or center of the object. I have built and ran the game over 10 times now, each time trying to fix this issue but nothing seems to help. My theory at the moment is that my code for the touch controls have too much going on and/ or have redundancies and by the time it checks whether or not an object is at the position of the touch, the object has moved to a different location. Any thoughts on why the hit boxes are off, and is there a better way to do hit detection with touch screen?
void FixedUpdate()
{
if (IsTouch())
{
CheckTouch(GetTouchPosition());
}
}
// Returns true if the screen is touched
public static bool IsTouch()
{
if (Input.touchCount > 0)
{
if (Input.GetTouch(0).phase == TouchPhase.Began)
{
return true;
}
}
return false;
}
// Gets the position the touch
private Vector2 GetTouchPosition()
{
Vector2 touchPos = new Vector2(0f, 0f);
Touch touch = Input.GetTouch(0);
if (Input.GetTouch(0).phase == TouchPhase.Began)
{
touchPos = touch.position;
}
return touchPos;
}
// Checks the position of the touch and destroys the ball if the
ball is touched
private void CheckTouch(Vector2 touchPos)
{
RaycastHit2D hit =
Physics2D.Raycast(Camera.main.ScreenToWorldPoint(
(Input.GetTouch(0).position)), Vector2.zero);
if (hit.collider != null)
{
destroy(hit.collider.gameObject);
}
}
Related
I am trying to give force to a rigidbody object by touch and dragging away from it and then releasing the touch. But the Touchphase.End just doesn't run. I can't find the answer to this problem. I get input from one touch until the touch releases, on releasing the touch the distance between the starting and final position is calculated and a similar force is applied on the rigidbody to make it move. The object on which the code is attached is the same object which needs to move.
// Update is called once per frame
void Update()
{
//Update the Text on the screen depending on current TouchPhase, and the current direction vector
// Track a single touch as a direction control.
if (Input.GetMouseButton(0))
{
Touch touch = Input.GetTouch(0);
_touchPosWorld =
Camera.main.ScreenToWorldPoint(touch.position); //get the position where the screen was touched
RaycastHit2D hitInformation = Physics2D.Raycast(_touchPosWorld, Vector2.zero);
FirstTouch = (hitInformation.collider.CompareTag("ball"));
if (FirstTouch || IsInTouch)
{
// Handle finger movements based on TouchPhase
switch (touch.phase)
{
//When a touch has first been detected, change the message and record the starting position
case TouchPhase.Began:
// Record initial touch position.
IsInTouch = true;
_startPos = touch.position;
GameManager.GetInstance().ChangeAccordinglyText.text = "clicked Inside";//test text
//Movement started
break;
//Determine if the touch is a moving touch
case TouchPhase.Moved:
// Determine direction by comparing the current touch position with the initial one
_direction = touch.position - _startPos;
GameManager.GetInstance().ChangeAccordinglyText.text = "MovingTouch to " + touch.position; //test text
//moving
break;
case TouchPhase.Ended:
// Report that the touch has ended when it ends
//end of movement of touch
GameManager.GetInstance().EndedText.text = "EndOfTouch";
float force = 0;
force = _direction.x > _direction.y ? _direction.x : _direction.y;
_rigidbody.AddForce(_direction * force);
FirstTouch = false;
IsInTouch = false;
break;
}
}
}
}
Your TouchPhase.End will never be reached since in the moment you release the touch also GetMouseButton(0) will be false and thus the entire block skipped!
To avoid the errors you are talking about before trying to access a certain touch, first check if there is any touch to access using Input.touchCount
if(Input.touchCount > 0)
{
var touch = Input.GetTouch(0);
// ...
}
In general for development you should rather check for e.g. Input.touchSupported and implement an alternative mouse system for simulating the touches
if(Input.touchSupported)
{
/* Implement touches */
if(Input.touchCount > 0)
{
var touch = Input.GetTouch(0);
// ...
}
}
// Optional
else
{
/* alternative mouse implementation for development */
if(Input.GetMouseButtonDown(0))
{
// simulates touch begin
}
else if(Input.GetMouseButton(0))
{
// simulates touch moved
}
// I've seen in strange occasions that down and up might get called within one frame
if(Input.GetMouseButtonUp(0))
{
// simulates touch end
}
}
I'm making a mobile game based on android. When I was making a transfer code for my player object, I wrote code like this.
void Update() {
if(Input.touchcount == 1)
{
Touch touch = Input.GetTouch(0);
if(touch.phase == TouchPhase.Began)
{
//Move
}
else if(touch.phase == TouchPhase.Stationary)
{
//Move
}
}
}
It's moving at right direction and speed that I wanted. But when I touch quicker, these codes are don't working smoothly. I mean the player object is not moving smoothly.
Is there any solution for this problem?
P.S. I cant use AddForce in rigidbody
I am trying to get touch controls to work for iOS, the result i want is drag left to move left, drag right to move right and tap to jump. At the moment the functions do work but what happens is if i don't want to jump and just want to drag the character will jump first as soon as touch the screen. Is there a way i can get the result i want i have added my code below. I want the first touch to just register for the drag and when the player lifts and then taps or maybe double taps the character will jump. Thanks in advance.
//Mobile Touch Drag Controls
{
if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Moved)
{
// Get movement of the finger since last frame
Vector2 touchDeltaPosition = Input.GetTouch(0).deltaPosition;
// Move object across X plane
transform.Translate(touchDeltaPosition.x * speed, 0, 0);
}
}
////Mobile Touch To Jump
{
if (Input.GetMouseButtonDown(0))
{
transform.Translate(Vector3.up * jumpForce * Time.deltaTime, Space.World);
}
When the button goes down, there is no way to know what the player wants to do. You should jump when the finger goes up instead.
An easy solution is to use a boolean to know if the player has moved before the finger was released. If yes, you don't want to jump
public class PlayerController // Or whatever name your class has
{
private bool _moved;
private void Update()
{
//Mobile Touch Drag Controls
if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Moved)
{
// Get movement of the finger since last frame
Vector2 touchDeltaPosition = Input.GetTouch(0).deltaPosition;
// Move object across X plane
transform.Translate(touchDeltaPosition.x * speed, 0, 0);
_moved = true; // Remember that the player moved
}
////Mobile Touch To Jump
if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Ended)
{
if(!_moved) // Only jump if we didnt move
{
transform.Translate(Vector3.up * jumpForce * Time.deltaTime, Space.World);
}
_moved = false;
}
}
}
I assume this code goes in your update function. This will work fine but here is a more elegant solution in case you want to try it:
Your class can implement IDragHandler and IEndDragHandler (among others, look for all possibilities that extend IEventSystemHandler)
When you implement these, you can override functions that get called when the user touches the screen, such as public void OnDrag(PointerEventData eventData)
With this you don't have to use the Update function anymore
I am making a game where an object follows my finger. But I do not want the object to jump to my finger if I tap anywhere on the screen. I am using a raycast to do this. It works perfectly except if I move my finger too fast the object freezes.
My theory is that because of it being in Update() that once I move my finger off the object it detects that I can no longer drag it. I have no idea how to fix this.
public GameObject Bigball;
public GameObject Smallball;
// Update is called once per frame
private void Update ()
{
// lets ball follow finger
if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Moved || Input.GetTouch(0).phase == TouchPhase.Stationary)
{
var touch = Input.GetTouch(0);
Vector3 fingerPos = touch.position;
RaycastHit hit;
Ray ray = Camera.main.ScreenPointToRay(fingerPos);
if (Physics.Raycast(ray, out hit) && (hit.collider.tag == "ball"))
{
Smallball.SetActive(false);
Bigball.SetActive(true);
Vector3 pos = new Vector3((Camera.main.ScreenToWorldPoint(Input.GetTouch(0).position)).x,
(Camera.main.ScreenToWorldPoint(Input.GetTouch(0).position)).y, 0);
Bigball.transform.position = pos;
}
}
else
{
Bigball.SetActive(false);
Smallball.SetActive(true);
Smallball.transform.position = new Vector3(Bigball.transform.position.x, Bigball.transform.position.y, 0);
}
}
It might make more sense to only Raycast once when the finger touches the screen. If that Raycast finds an object to drag, simply store that object and move it to follow the finger every Update(), as long as the finger continues to touch the screen.
Once the finger is released, just forget about the object until the next touch finds a new object to drag.
An alternative would be to use no Raycasts at all but build on IBeginDragHandler, IDragHandler and IEndDragHandler, as Bijan already mentioned.
I am making a 2D platform game in Untiy for android and i am having some issues with a section of code i have. When i jump onto a platform the first time i can land onto the platform but when i jump again i fall through the platform. i have it so the box collider is inactive if the player is less then the height of the platform and active when the player is higher then the platform. I thought the box collider was to small and it was just missing the collider so i have tried different sizes of colliders and i have tried adjusting different heights at which it activates. Also when i set the height to low the player does a double jump. So what am i doing wrong?
public class Rock : MonoBehaviour
{
private BoxCollider2D platform;
private PlayerScript player;
public float height;
void Awake() {
player = GameObject.Find("Player").GetComponent<PlayerScript>();
platform = GetComponent<BoxCollider2D>();
}
void Start () {
platform.enabled = false;
}
// Update is called once per frame
void Update () {
if(player.transform.position.y > height){
platform.enabled = true;
} else if(player.transform.position.y < height){
platform.enabled = false;
}
}
}
Could it be that you're not covering the case where player.transform.position.y == height?
I can see that you're checking for greater / smaller than height but not equality. This could lead to unwanted behavior like the one you're describing.
Let me know if this was the problem.
This code actually worked. The issue ended up being in my playerscript where I had added a chunk of code where I was having a bug if you held the jump button down the player would get stuck in the jump animation.
void OnCollisionStay2D(Collision2D target) {
if (target.gameObject.tag == "Ground") {
grounded = true;
anim.SetBool("Jump",false);
}
}
public void Jump () {
if(grounded){
grounded = false;
anim.SetBool("Jump",true);
myBody.velocity = new Vector2(myBody.velocity.x, 0);
myBody.AddForce( new Vector2(0, jumpForce));
}
}
After some troubleshooting and going and removing pieces of code trying to see why I doubled jump I finally came across this piece then when I was trying with the touch controls instead of with the keyboard I noticed I am not actually able to hold the jump button down like you can with a keyboard so I didn't really need this piece of code. So I was my own worst enemy this time.