I am new to Unity, and was following the tutorials of roll a ball.
I was to create it for both mobile and desktop and it is working but the only problem I have is that I am unable to create touch keys arrows(left,right,up,down) to control the player on the touch screen devices.
Please check my code below of controlling the player:
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
public class PlayerController : MonoBehaviour {
public float speed;
public Text countText;
public Texture2D button1; //button 1
public Texture2D button2; //button2
public Texture texture;
private Rigidbody rb;
private int count;
// Use this for initialization
void Start () {
Screen.orientation = ScreenOrientation.LandscapeLeft;
//GUITexture.texture = button1;
rb = GetComponent<Rigidbody> ();
count = 0;
SetCountText ();
}
// Update is called once per frame
void FixedUpdate () {
Screen.orientation = ScreenOrientation.LandscapeLeft;
Screen.sleepTimeout = SleepTimeout.NeverSleep;
if (SystemInfo.deviceType == DeviceType.Desktop) {
float moveHorizontal = Input.GetAxis ("Horizontal");
float moveVertical = Input.GetAxis ("Vertical");
Vector3 movement = new Vector3 (moveHorizontal, 0.0f, moveVertical);
GetComponent<Rigidbody>().AddForce (movement * speed * Time.deltaTime);
if (Input.GetKey("escape"))
{
Application.Quit();
}
}//END Desktop
else
{
float moveHorizontal = Input.acceleration.x;
float moveVertical = Input.acceleration.y;
Vector3 movement = new Vector3 (moveHorizontal, 0.0f, moveVertical);
GetComponent<Rigidbody>().AddForce (movement * speed * Time.deltaTime);
if (Input.GetKeyDown(KeyCode.Escape))
{
Application.Quit();
}
foreach(Touch touch in Input.touches)
{
//Always getting error here
if (GUITexture.HitTest(touch.position) && touch.phase !=TouchPhase.Ended)
{
GUITexture.texture = button2;
transform.Translate(Vector3.right*30*Time.smoothDeltaTime);
}else if(GUITexture.HitTest(touch.position) && touch.phase !=TouchPhase.Ended)
{
GUITexture.texture = button1;
}
}
}
// Building of force vector
}
void OnTriggerEnter(Collider other)
{
if (other.gameObject.CompareTag ("Pick Up"))
{
other.gameObject.SetActive(false);
count = count + 1;
SetCountText();
}
}
void SetCountText()
{
countText.text = "Count:" + count.ToString ();
}
}
Your trying to call HitTest directly from GUITexture like a static function but HitTest isn't a static function, you need to create a variable from GUITexture class and then call HitTest function from that object like this:
public GUITexture guiT;
if (guiT.HitTest(touch.position) && touch.phase !=TouchPhase.Ended)
{
guiT.texture = button2;
transform.Translate(Vector3.right*30*Time.smoothDeltaTime);
}
else if(guiT.HitTest(touch.position) && touch.phase !=TouchPhase.Ended)
{
guiT.texture = button1;
}
don't forget to assign guiT variable to something from the Editor.
Related
How to detect touches and long touches on buttons in unity for android?
I have already tried this function but it returns true if i touch any place on screen:
bool checkTouch()
{
for(int i = 0; i < Input.touchCount; i++)
{
TouchPhase tp = Input.GetTouch(i).phase;
if(tp == TouchPhase.Began || tp == TouchPhase.Ended || tp == TouchPhase.Stationary)
return true;
}
return false;
}
One way to achieve Buttons that allow that, is to create your own button, implementing the necessary interfaces like IPointerDownHandler, IPointerUpHandler.
That way you could manage how will the button act, here is an example:
using UnityEngine;
using UnityEngine.EventSystems;
public class LongClickButton : MonoBehaviour, IPointerDownHandler, IPointerUpHandler
{
private bool pointerDown;
private float pointerDownTimer;
[SerializeField]
private float requiredHoldTime;
public void OnPointerDown(PointerEventData eventData)
{
pointerDown = true;
Debug.Log("OnPointerDown");
}
public void OnPointerUp(PointerEventData eventData)
{
Reset();
Debug.Log("OnPointerUp");
}
private void Update()
{
if (pointerDown)
{
pointerDownTimer += Time.deltaTime;
if (pointerDownTimer >= requiredHoldTime)
{
//do your LongClick stuff
Debug.Log("LongClick");
Reset();
}
}
}
private void Reset()
{
pointerDown = false;
pointerDownTimer = 0;
}
}
Remember to attach the script to a GameObject that can be interactable, like an Image.
I'm using Unity 2D for my game and I'm facing a weird problem. I have a GameObject (an image) in my scene with a button attached to it. When the player is out of the screen, the image that works as a GameOver panel appears and in case of enough coins, you can resume the game. Everything works fine but when the image appears and I click on button to resume, the image doesn't disappear while the function for decreasing number of coins still works.
Here is my script in which di() is for die and but() for button:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using CodeStage.AntiCheat.ObscuredTypes;
using CodeStage.AntiCheat.Detectors;
public class UIManager2 : MonoBehaviour {
public static ObscuredInt coin_score = 0;
public Text coin_text;
public Slider slider;
public Slider slider1;
public Slider slider2;
public GameObject bul;
public bool reverse;
public float timer;
public int delay = 1;
public float speed=0.5f;
public GameObject pause;
public AudioSource[] aud=new AudioSource[3];
void Start () {
coin_score = ObscuredPrefs.GetInt ("Score");
StartCoroutine (elapsed ());
slider1.minValue = 0;
slider1.maxValue = 20;
bul = GameObject.FindGameObjectWithTag ("Player").GetComponent<Plane19> ().bullet;
}
void Update () {
timer += Time.deltaTime;
if (timer >= delay && reverse == false) {
timer = 0f;
slider2.value++;
}
if (timer >= delay && reverse == true) {
timer = 0f;
slider2.value -= speed;
}
coin_text.text = coin_score.ToString ();
ObscuredPrefs.SetInt ("Score", coin_score);
if (slider2.value == 10) {
bul.SetActive (false);
reverse = true;
}
if (slider2.value == 0) {
bul.SetActive (true);
reverse = false;
}
}
public void di(){
pause.SetActive(true);
GetComponent<AudioSource>().Pause();
Time.timeScale = 0;
aud[0].Play();
aud[1].Pause();
aud[2].Pause();
}
public void but(){
pause.SetActive(false);
Time.timeScale=1;
aud[0].Pause();
aud[1].UnPause();
aud[2].UnPause();
GetComponent<AudioSource>().UnPause();
UIManager2.coin_score-=2;
}
IEnumerator elapsed () {
yield return new WaitForSeconds (2f);
slider.value++;
StartCoroutine (elapsed ());
}
}
I am trying to draw bullets on the screen when the player presses, but
after a few bullets I get the following error: FATAL EXCEPTION: Thread-2
Here is the classes of the bullet and of the gameView
public class Bullet {
private int x;
private int y;
private int speed;
private Bitmap bitmap;
public Bullet(Context context,int PositionX,int PositionY) {
Log.v("i am in bullet"," come on!!!");
speed = 10;
x = PositionX;
y = PositionY;
bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.flash);
}
public void update() {
//Log.v("i am in update bullet"," come on!!!");
//animating the star horizontally right side
//by increasing x coordinate with player speed
x += 20;
}
public Bitmap getBitmap(){return bitmap;}
public int getX() {
return x;
}
public int getY() {
return y;
}
}
returns
public class GameView extends SurfaceView implements Runnable {
private long fps;
private long timeThisFrame;
volatile boolean playing;
private Thread gameThread = null;
private Player player;
//a screenX holder
int screenX;
int i=0;
//context to be used in onTouchEvent to cause the activity transition from GameAvtivity to MainActivity.
Context context;
//the score holder
int score;
//the high Scores Holder
int highScore[] = new int[4];
//Shared Prefernces to store the High Scores
SharedPreferences sharedPreferences;
//to count the number of Misses
int countMisses;
//indicator that the enemy has just entered the game screen
boolean flag ;
//an indicator if the game is Over
private boolean isGameOver ;
private Paint paint;
private Canvas canvas;
private SurfaceHolder surfaceHolder;
private Enemy enemies;
//created a reference of the class Friend
private Friend friend;
//private Bullet bullet;
private ArrayList<Star> stars = new
ArrayList<Star>();
private ArrayList<Bullet> bullet = new
ArrayList<Bullet>();
//defining a boom object to display blast
private Boom boom;
//the mediaplayer objects to configure the background music
static MediaPlayer gameOnsound;
final MediaPlayer killedEnemysound;
final MediaPlayer gameOversound;
public GameView(Context context, int screenX, int screenY) {
super(context);
player = new Player(context, screenX, screenY);
surfaceHolder = getHolder();
paint = new Paint();
//initializing context
this.context = context;
int starNums = 20;
for (int i = 0; i < starNums; i++) {
Star s = new Star(context,screenX, screenY);
stars.add(s);
}
enemies = new Enemy(context,screenX,screenY);
//initializing boom object
boom = new Boom(context);
//initializing the Friend class object
friend = new Friend(context, screenX, screenY);
//setting the score to 0 initially
score = 0;
//setting the countMisses to 0 initially
countMisses = 0;
this.screenX = screenX;
isGameOver = false;
//initializing shared Preferences
sharedPreferences = context.getSharedPreferences("SHAR_PREF_NAME",Context.MODE_PRIVATE);
//initializing the array high scores with the previous values
highScore[0] = sharedPreferences.getInt("score1",0);
highScore[1] = sharedPreferences.getInt("score2",0);
highScore[2] = sharedPreferences.getInt("score3",0);
highScore[3] = sharedPreferences.getInt("score4",0);
//initializing the media players for the game sounds
gameOnsound = MediaPlayer.create(context,R.raw.gameon);
killedEnemysound = MediaPlayer.create(context,R.raw.killedenemy);
gameOversound = MediaPlayer.create(context,R.raw.gameover);
//starting the music to be played across the game
gameOnsound.start();
}
#Override
public void run() {
while (playing) {
long startFrameTime = System.currentTimeMillis();
synchronized (surfaceHolder) {
update();
draw();
control();
}
timeThisFrame = System.currentTimeMillis() - startFrameTime;
if (timeThisFrame >= 1) {
fps = 1000 / timeThisFrame;
}
}
}
private void update() {
//incrementing score as time passes
score++;
player.update();
//setting boom outside the screen
boom.setX(-250);
boom.setY(-250);
for (Star s : stars) {
s.update(player.getSpeed());
}
for (Bullet b : bullet) {
b.update();
}
//setting the flag true when the enemy just enters the screen
if(enemies.getX()==screenX){
flag = true;
}
enemies.update(player.getSpeed(),getFps());
}
private void draw() {
if (surfaceHolder.getSurface().isValid()) {
canvas = surfaceHolder.lockCanvas();
canvas.drawColor(Color.argb(500,135,206,250));
paint.setColor(Color.WHITE);
paint.setTextSize(20);
for (Star s : stars) {
canvas.drawBitmap(
s.getBitmap(),
s.getX(),
s.getY(),
paint);
}
for (Bullet b : bullet) {
canvas.drawBitmap(
b.getBitmap(),
b.getX(),
b.getY(),
paint);
}
canvas.drawBitmap(
player.getBitmap(),
player.getX(),
player.getY(),
paint);
canvas.drawBitmap( enemies.getBitmap(), enemies.getframeToDraw(), enemies.getwhereToDraw(), null);
//drawing the score on the game screen
paint.setTextSize(30);
canvas.drawText("Score:"+score,100,50,paint);
//drawing boom image
canvas.drawBitmap(
boom.getBitmap(),
boom.getX(),
boom.getY(),
paint
);
//draw game Over when the game is over
if(isGameOver){
paint.setTextSize(150);
paint.setTextAlign(Paint.Align.CENTER);
int yPos=(int) ((canvas.getHeight() / 2) - ((paint.descent() + paint.ascent()) / 2));
canvas.drawText("Game Over",canvas.getWidth()/2,yPos,paint);
}
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
private void control() {
try {
gameThread.sleep(17);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void pause() {
playing = false;
try {
gameThread.join();
} catch (InterruptedException e) {
gameThread.interrupt();
}
}
public void resume() {
playing = true;
gameThread = new Thread(this);
gameThread.start();
}
//stop the music on exit
public static void stopMusic(){
gameOnsound.stop();
}
#Override
public boolean onTouchEvent(MotionEvent motionEvent) {
switch (motionEvent.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_UP:
player.stopBoosting();
break;
case MotionEvent.ACTION_DOWN:
player.setBoosting();
break;
}
//if touch the player
if (player.getDetectCollision().contains((int)motionEvent.getX(), (int)motionEvent.getY())) {
Bullet b = new Bullet(context,player.getX()+player.getDetectCollision().width()
,player.getY()-(player.getDetectCollision().height()/2));
bullet.add(b);
Log.d("test", "touch not inside myEditText");
}
//if the game's over, tappin on game Over screen sends you to MainActivity
if(isGameOver){
if(motionEvent.getAction()==MotionEvent.ACTION_DOWN){
context.startActivity(new Intent(context,MainActivity.class));
}
}
return true;
}
public long getFps(){
return fps;
}
}
i'm using the vision API for face detection, now i want to implement eye blink but still vision api detect eye blinking in image(photo) of a person(not live).
In addition, I am using a Tracker to keep track of the eye state over time, to detect the sequence of events that indicate a blink of left eye:
left eyes open -> left eyes closed -> left eyes open
The GraphicFaceTracker class is defined as below :
private class GraphicFaceTracker extends Tracker<Face> {
private GraphicOverlay mOverlay;
private FaceGraphic mFaceGraphic;
private Context context ;
GraphicFaceTracker(Context context, GraphicOverlay overlay) {
mOverlay = overlay;
this.context= context;
mFaceGraphic = new FaceGraphic(overlay);
}
private final float OPEN_THRESHOLD = 0.85f;
private final float CLOSE_THRESHOLD = 0.4f;
private int state = 0;
void blink(float value, final int eyeNo, String whichEye) {
switch (state) {
case 0:
if (value > OPEN_THRESHOLD) {
// Both eyes are initially open
state = 1;
}
break;
case 1:
if (value < CLOSE_THRESHOLD ) {
// Both eyes become closed
state = 2;
}
break;
case 2:
if (value > OPEN_THRESHOLD) {
// Both eyes are open again
Log.i("BlinkTracker", "blink occurred!");
mCameraSource.takePicture(null, new CameraSource.PictureCallback() {
#Override
public void onPictureTaken(byte[] bytes) {
Bitmap bmp = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
Log.d("BITMAP", bmp.getWidth() + "x" + bmp.getHeight());
System.out.println(bmp.getWidth() + "x" + bmp.getHeight());
}
});
state = 0;
}
break;
}
}
/**
* Start tracking the detected face instance within the face overlay.
*/
#Override
public void onNewItem(int faceId, Face item) {
mFaceGraphic.setId(faceId);
}
/**
* Update the position/characteristics of the face within the overlay.
*/
#Override
public void onUpdate(FaceDetector.Detections<Face> detectionResults, Face face) {
mOverlay.add(mFaceGraphic);
mFaceGraphic.updateFace(face);
float left = face.getIsLeftEyeOpenProbability();
float right = face.getIsRightEyeOpenProbability();
if (left == Face.UNCOMPUTED_PROBABILITY) {
// At least one of the eyes was not detected.
return;
}
blink(left,0,"left");
if(right == Face.UNCOMPUTED_PROBABILITY ){
return ;
}
}
}
I have enabled "classifications" in order to have the detector indicate if eyes are open/closed :
FaceDetector detector = new FaceDetector.Builder(context)
.setProminentFaceOnly(true) // optimize for single, relatively large face
.setTrackingEnabled(true) // enable face tracking
.setClassificationType(/* eyes open and smile */ FaceDetector.ALL_CLASSIFICATIONS)
.setMode(FaceDetector.FAST_MODE) // for one face this is OK
.build();
The tracker is then added as a processor for receiving face updates over time from the detector. For example, this configuration would be used to track whether the largest face in view has blinked:
Tracker<Face> tracker = new GraphicFaceTracker(this,mGraphicOverlay);
detector.setProcessor(new LargestFaceFocusingProcessor.Builder(detector, tracker).build());
But the above code detects blink in image of a person . But the image of a person cannot blink . How can I detect blink by camera ?
From Face object you can get below probability.
float leftOpenScore = face.getIsLeftEyeOpenProbability();
if (leftOpenScore == Face.UNCOMPUTED_PROBABILITY) {//left eye is open }else{//left eye closed }
float leftOpenScore = face.getIsRightEyeOpenProbability();
if (leftOpenScore == Face.UNCOMPUTED_PROBABILITY) {//Right eye is open }else{//Right eye closed }
Now you can pass this value where you want to use.
You can pass your detector to camera source and process blink detection from the surface view.
public class LivelinessScanFragment extends Fragment {
SurfaceView cameraView;
CameraSource cameraSource;
final int RequestCameraPermissionID = 1001;
FaceDetector detector;
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
switch (requestCode) {
case RequestCameraPermissionID: {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
return;
}
try {
cameraSource.start(cameraView.getHolder());
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
public LivelinessScanFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View rootView = inflater.inflate(R.layout.fragment_liveliness_scan, container, false);
cameraView = (SurfaceView)rootView.findViewById(R.id.surface_view);
detector = new FaceDetector.Builder(getActivity())
.setProminentFaceOnly(true) // optimize for single, relatively large face
.setTrackingEnabled(true) // enable face tracking
.setClassificationType(/* eyes open and smile */ FaceDetector.ALL_CLASSIFICATIONS)
.setMode(FaceDetector.FAST_MODE) // for one face this is OK
.build();
if (!detector.isOperational()) {
Log.w("MainActivity", "Detector Dependencies are not yet available");
} else {
cameraSource = new CameraSource.Builder(Application.getContext(), detector)
.setFacing(CameraSource.CAMERA_FACING_FRONT)
.setRequestedFps(2.0f)
.setRequestedPreviewSize(1280, 1024)
.setAutoFocusEnabled(true)
.build();
cameraView.getHolder().addCallback(new SurfaceHolder.Callback() {
#Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
try {
if (ActivityCompat.checkSelfPermission(Application.getContext(), Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(getActivity(),
new String[]{Manifest.permission.CAMERA}, RequestCameraPermissionID);
return;
}
cameraSource.start(cameraView.getHolder());
detector.setProcessor(
new LargestFaceFocusingProcessor(detector, new GraphicFaceTracker()));
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
}
#Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
cameraSource.stop();
}
});
}
return rootView;
}
private class GraphicFaceTracker extends Tracker<Face> {
private final float OPEN_THRESHOLD = 0.85f;
private final float CLOSE_THRESHOLD = 0.4f;
private int state = 0;
void blink(float value) {
switch (state) {
case 0:
if (value > OPEN_THRESHOLD) {
// Both eyes are initially open
state = 1;
}
break;
case 1:
if (value < CLOSE_THRESHOLD ) {
// Both eyes become closed
state = 2;
}
break;
case 2:
if (value > OPEN_THRESHOLD) {
// Both eyes are open again
Log.i("BlinkTracker", "blink occurred!");
state = 0;
}
break;
}
}
/**
* Update the position/characteristics of the face within the overlay.
*/
#Override
public void onUpdate(FaceDetector.Detections<Face> detectionResults, Face face) {
float left = face.getIsLeftEyeOpenProbability();
float right = face.getIsRightEyeOpenProbability();
if ((left == Face.UNCOMPUTED_PROBABILITY) ||
(right == Face.UNCOMPUTED_PROBABILITY)) {
// One of the eyes was not detected.
return;
}
float value = Math.min(left, right);
blink(value);
}
}
}
Here is a Github project open source eye blink detector for Android that detects eye blinks in real time in Android which is implemented on top of FaceDetectorApi
I think that looks about right. If you associate the detector with a running CameraSource instance, like in this example:
https://developers.google.com/vision/android/face-tracker-tutorial
that would track the eye motion from the video camera. I also think you might change the onUpdate code a little to better decide the blink threshold:
#Override
public void onUpdate(FaceDetector.Detections<Face> detectionResults, Face face) {
mOverlay.add(mFaceGraphic);
mFaceGraphic.updateFace(face);
float left = face.getIsLeftEyeOpenProbability();
float right = face.getIsRightEyeOpenProbability();
if ((left == Face.UNCOMPUTED_PROBABILITY) ||
(right == Face.UNCOMPUTED_PROBABILITY)) {
// One of the eyes was not detected.
return;
}
float value = Math.min(left, right);
blink(value);
}
I try to make a game for android where you have press and hold buttons to move and lift to stop. However, I couldn't make it work on android, because the OnMouseDown and OnMouseUp only works for PC. Is there any way to do it in android? Here is my code:
using UnityEngine;
using System.Collections;
public class buttonRight : MonoBehaviour {
public Rigidbody player;
public float speed;
private bool clicking;
void OnMouseDown()
{
Debug.Log("click");
clicking = true;
Vector3 movement = new Vector3(1.0f, 0.0f, 0.0f);
if (clicking == true)
player.velocity = movement * speed;
}
void OnMouseUp()
{
Debug.Log("stop click");
clicking = false;
Vector3 movement = new Vector3(0.0f, 0.0f, 0.0f);
player.velocity = movement * 0;
}
}
A thousand times question. Well, answer is OnMouseDown and OnMouseUp execute only once and you are trying to use them as OnMouseDown executes per frame.
You can do something like,
Vector3 movement = new Vector3 (1.0f, 0.0f, 0.0f);
bool clicking = false;
void Update ()
{
if (clicking == true)
_rb.velocity = movement * 5;
else
_rb.velocity = movement * 0;
}
void OnMouseDown ()
{
Debug.Log ("click");
clicking = true;
}
void OnMouseUp ()
{
Debug.Log ("stop click");
clicking = false;
}