- Home /
Please help. Attempting touch controls but I cant figure out what I'm doing wrong
Hi. I am trying to make a game for smartphones and have found several touch screen tutorials online such as this one https://www.youtube.com/watch?v=uUIXFL2ic7k which is the one I have been attempting to emulate. I have some code but cannot understand why it isn't working.
I have managed to get Unity and the Android SDK working in tandem so I can install the app on my phone. Although it loads fine nothing happens when I touch the GUI texture/s. Any help is greatly appreciated. Here is my code.
using UnityEngine; using System.Collections;
public class __upArrow : MonoBehaviour {
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
for (int i = 0; i < Input.touchCount; i++) {
if (this.guiTexture.HitTest (Input.GetTouch (i).position)) {
if(Input.GetTouch(i).phase == TouchPhase.Began){
Player2.Player.Translate (Vector3.up * Player2.playerSpeed * Time.deltaTime);
}
}
}
}
}
The best way to debug is to throw in a bunch of Debug.Log() statements in there to see exactly what's going on.
Put one inside of the for loop to make sure touches are being recognized, put one inside the HitTest to see if the guiTexture is recognizing it in the hit area, etc... until you get more information.
What is guiTexture? What is it that you're trying to accomplish (I mean what action and what response)?
Thank you both for your replies. I am simply trying to move a cube I'm using to represent the player. The GUI textures I have are all arrows to represent a D-pad this code is used on all the arrows and the direction of movement is changed as needed for each arrow. I will try debugging now
Thinking about this again, you are using TouchPhase.Began which means the player will only move up once when the user first puts their finger down onto the up arrow ins$$anonymous$$d of constantly as it's held down. It may be your desired effect, but if it's not then you have to use TouchPhase.$$anonymous$$oved and/or TouchPhase.Stationary.
Tried using Debug and still nothing happens. Nothing comes up in the console.
and here is my code using UnityEngine; using System.Collections;
public class __upArrow : $$anonymous$$onoBehaviour {
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
for (int i = 0; i < Input.touchCount; i++) {
Debug.Log(Input.touchCount);
if (this.guiTexture.HitTest (Input.GetTouch (i).position)) {
if(Input.GetTouch(i).phase == TouchPhase.Began){
Debug.Log (TouchPhase.Began);
Player2.Player.Translate (Vector3.up * Player2.playerSpeed * Time.deltaTime);
}
}
}
}
}
The image is just to show the set up I have showing the game running on my phone
Answer by Leuthil · Mar 27, 2014 at 06:36 PM
I'm not sure exactly why the error is happening but it's probably happening because of your way of accessing Player2's variables by making them static. This is not really proper functionality. Really Player2 should all have non-static variables that are public. You can then access them the proper way in your upArrow script as seen below:
// directly set this in the Editor by dragging your Player2 GameObject in the scene here
public GameObject player2GameObject;
private Player2 player2;
void Start () {
// if not set directly in the Editor then find it by GameObject name which is not as efficient
player2GameObject = FindByName("Player2");
player2 = player2GameObject.GetComponent<Player2>();
}
And then continue to reference the Player2 variables as player2.variable instead of Player2.variable.
O$$anonymous$$ again THAN$$anonymous$$ YOU SO $$anonymous$$UCH FOR HELPING :)
I have tried using the editor and code and I get the same error as above
using UnityEngine; using System.Collections;
public class __upArrow : $$anonymous$$onoBehaviour { public GameObject player2Gameobject; private Player2 player2;
// Use this for initialization
void Start () {
/*player2GameObject = FindByName("Player2");
player2 = player2GameObject.GetComponent<Player2>();*/
}
// Update is called once per frame
void Update () {
for (int i = 0; i < Input.touchCount; i++) {
if (this.guiTexture.HitTest (Input.GetTouch (i).position)) {
if(Input.GetTouch(i).phase == TouchPhase.Began){
player2.transform.Translate (Vector3.up * 5.0f * Time.deltaTime);
}
}
}
}
}
Is this how you wanted me to test your code?
Sorry I didn't clarify enough on the code in Start(). Just the first line should be commented out if you are setting the Player2 game object in the Editor. So change it to be like this:
using UnityEngine;
using System.Collections;
public class __upArrow : $$anonymous$$onoBehaviour {
public GameObject player2Gameobject;
private Player2 player2;
// Use this for initialization
void Start () {
/*player2GameObject = FindByName("Player2");*/
player2 = player2GameObject.GetComponent<Player2>();
}
// Update is called once per frame
void Update () {
for (int i = 0; i < Input.touchCount; i++) {
if (this.guiTexture.HitTest (Input.GetTouch (i).position)) {
if(Input.GetTouch(i).phase == TouchPhase.Began){
player2.transform.Translate (Vector3.up * 5.0f * Time.deltaTime);
}
}
}
}
}
Answer by supernat · Mar 27, 2014 at 04:37 PM
If you get any errors while running your code, you need to find and fix those first. When a script gets an error, it stops processing the rest of the code in the function. It means you may not be running other code unrelated potentially to the error.
I would recommend moving away from using the touch phases and touch input stuff manually unless you have a specific need. Unity maps the OnMouseDown, OnMouseUp, and OnMouseDrag (maybe) methods to the touch methods for you, saving you a lot of pain for simple things like clicks of buttons.
In other words, if you put an OnMouseDown() method in a script on your down arrow button, if you touch the button on the device, that method will be called. In your case, you don't care if the mouse (finger) is being dragged, but you might be able to use OnMouseDrag() for that as well (I can't say 100%, haven't tried it, but it stands to reason it is the same as the others).
So, in OnMouseDown, set a flag indicating the object is down. In OnMouseUp, change the flag to indicate it is not down. In Update(), check if the flag is down, and move the cube accordingly (is one solution).
If you want support for multi touch, i.e. to detect when two arrows are pressed by two fingers, then you'll likely need to use the Touch Input classes, I can't say for sure.
supernat is correct. If you are getting errors then the rest is pretty pointless. Please post the errors that you are getting exactly and the code lines that it is referencing.
Thank you both for still replying. I have tried using the mouseDown which supernat is right - it does work. However my cube still doesn't move and this is my error and I have no idea how to fix it...
NullReferenceException: Object reference not set to an instance of an object __upArrow.Update () (at Assets/Scripts/Touch/touchScreenControlScripts/__upArrow.cs:15)
So here is my player script first...
using UnityEngine; using System.Collections;
public class Player2 : $$anonymous$$onoBehaviour {
public static Transform Player;
public static float playerSpeed;
public static float playerStrength;
public static bool hasDied = false;
public Vector3 respawnPoint;
// Use this for initialization
void Start () {
Player = transform;
Player.transform.position = new Vector3 (0, 1, 0);
playerSpeed = 5.0f;
playerStrength = 2.5f;
}
// Update is called once per frame
void Update () {
Player.Translate(Vector3.right * playerSpeed * Input.GetAxis ("Horizontal") * Time.deltaTime);
Player.Translate(Vector3.up * playerSpeed * Input.GetAxis ("Vertical") * Time.deltaTime);
if (newLift$$anonymous$$echanic.inContact) {//used to check if the player is touching an object that can be lifted
playerSpeed = 0.0f;
} else {
playerSpeed = 5.0f;
}
}
}
and this is my __upArrow script...
using UnityEngine; using System.Collections;
public class __upArrow : $$anonymous$$onoBehaviour {
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
for (int i = 0; i < Input.touchCount; i++) {
if (this.guiTexture.HitTest (Input.GetTouch (i).position)) {
if(Input.GetTouch(i).phase == TouchPhase.Began){
Player2.Player.Translate (Vector3.up * Player2.playerSpeed * Time.deltaTime);
}
}
}
}
}
Answer by Kebabs · Mar 27, 2014 at 06:55 PM
ITS FINALLY WORKING THANK YOU SO MUCH LEUTHIL!!!
using UnityEngine; using System.Collections;
public class __upArrow : MonoBehaviour { public GameObject player2Gameobject; private Player2 player2;
// Use this for initialization
void Start () {
/*player2GameObject = FindByName("Player2");
player2 = player2GameObject.GetComponent<Player2>();*/
}
// Update is called once per frame
void Update () {
for (int i = 0; i < Input.touchCount; i++) {
if (this.guiTexture.HitTest (Input.GetTouch (i).position)) {
if(Input.GetTouch(i).phase == TouchPhase.Began){
player2Gameobject.transform.Translate (Vector3.up * 5.0f * Time.deltaTime);
}
}
}
}
}
I had to change the player2 reference to be the player2Gameobject being used from the editor.
If I ever meet you in real life, I owe you!! THANK YOU :)
I didn't even realize you could do that (reference directly to a Component in the Editor) but I guess that makes sense. In that case you don't even need the player2GameObject variable.
Glad you got it sorted out :).