Android sensors to control game - android

I'm trying to setup my android game to use android sensors for controlling the game.
When the phone is tilted forwards slightly, I want the thrusters to fire.
And tilting the phone left or right rotates it in the rescpetive direction.
At the moment, I'm using TYPE_ORIENTATION as follows:
public void onSensorChanged(SensorEvent event) {
if(mMode == STATE_RUNNING) {
synchronized (mSurfaceHolder) {
//rotation
float pitch = event.values[2]; // pitch
if(pitch <= 15 & pitch >= -15) {
mRotating = 0;
} else if(pitch < -15) {
mRotating += 1;
} else if(pitch > 15) {
mRotating -= 1;
}
//thrust by tilting forward!
if(event.values[0] > 0) {
thrusterFiring = true;
} else {
thrusterFiring = false;
}
}
}
}
But I'm not sure if this is quite right? Additionally, you have to filt the phone quite a bit forwards in order for the thrusters to fire - I'd like it so you only need to tilt a little!
Any help appreciated!

Related

Detect swipe without losing immediate response of tap

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";
}
}
}
}
}

Multi-touch bug on my first Android game

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.

Using accelerometer and magnetic sensor to detect the directions

I am working on an android project where I need to detect the exact directions when user turns (i.e. left or right or bottom or top). I have found the directions too by using accelerometer with magnetic sensor, but I couldn't fix the maximum values to be turned.
The problem I face is this:
I am unable to make it detect the center point/position.
When a user turns the phone left from the central position, it detects it as a left turn.
However, when I return the position to the central position, the phone detects it as two movements: both left. My understanding is this: If the sensor had got the central position (point of origin) correctly fixed, the movements would be correctly detected. But, because the central position is not fixed, this is not happening.
Kindly guide me in fixing it. Do let me know if you need further clarifications.
My code is as below
public void onSensorChanged(SensorEvent event) {
azimuth = event.values[0]; // azimuth
pitch = event.values[1]; // pitch
roll = event.values[2]; // roll
if (pitch < -45 && pitch > -135) {
// top
currentSide = Side.TOP;
} else if (pitch > 45 && pitch < 135) {
// bottom
currentSide = Side.BOTTOM;
} else if (roll > 45) {
// right
currentSide = Side.RIGHT;
} else if (roll < -45) {
// left
currentSide = Side.LEFT;
}
if (currentSide != null && !currentSide.equals(oldSide)) {
switch (currentSide) {
case TOP :
listener.onTopUp();
break;
case BOTTOM :
listener.onBottomUp();
break;
case LEFT:
listener.onLeftUp();
break;
case RIGHT:
listener.onRightUp();
break;
}
oldSide = currentSide;
}
// forwards orientation to the OrientationListener
listener.onOrientationChanged(azimuth, pitch, roll);
}
Thanks for helping!

how to calculate exact foot step count using accelerometer in android?

I am developing some application like Runtastic Pedometer using the algorithm but I am not getting any similarity between the results.
my code is as follows:
public void onSensorChanged(SensorEvent event)
{
Sensor sensor = event.sensor;
synchronized (this)
{
if (sensor.getType() == Sensor.TYPE_ORIENTATION) {}
else {
int j = (sensor.getType() == Sensor.TYPE_ACCELEROMETER) ? 1 : 0;
if (j == 1) {
float vSum = 0;
for (int i=0 ; i<3 ; i++) {
final float v = mYOffset + event.values[i] * mScale[j];
vSum += v;
}
int k = 0;
float v = vSum / 3;
//Log.e("data", "data"+v);
float direction = (v > mLastValues[k] ? 1 : (v < mLastValues[k] ? -1 : 0));
if (direction == - mLastDirections[k]) {
// Direction changed
int extType = (direction > 0 ? 0 : 1); // minumum or maximum?
mLastExtremes[extType][k] = mLastValues[k];
float diff = Math.abs(mLastExtremes[extType][k] - mLastExtremes[1 - extType][k]);
if (diff > mLimit) {
boolean isAlmostAsLargeAsPrevious = diff > (mLastDiff[k]*2/3);
boolean isPreviousLargeEnough = mLastDiff[k] > (diff/3);
boolean isNotContra = (mLastMatch != 1 - extType);
if (isAlmostAsLargeAsPrevious && isPreviousLargeEnough && isNotContra) {
for (StepListener stepListener : mStepListeners) {
stepListener.onStep();
}
mLastMatch = extType;
}
else {
Log.i(TAG, "no step");
mLastMatch = -1;
}
}
mLastDiff[k] = diff;
}
mLastDirections[k] = direction;
mLastValues[k] = v;
}
}
}
}
for registering sensors:
mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
mSensor = mSensorManager.getDefaultSensor(
Sensor.TYPE_ACCELEROMETER);
mSensorManager.registerListener(mStepDetector,mSensor,SensorManager.SENSOR_DELAY_NORMAL);
in the algorithm i have different levels for sensitivity as public void
setSensitivity(float sensitivity) {
mLimit = sensitivity; // 1.97 2.96 4.44 6.66 10.00 15.00 22.50 33.75 50.62
}
on various sensitivity level my result is:
sensitivity rantastic pedometer my app
10.00 3870 5500
11.00 3000 4000
11.15 3765 4576
13.00 2000 890
11.30 754 986
I am not getting any proper pattern to match with the requirement.
As per my analysis this application is using Sensor.TYPE_MAGNETIC_FIELD for steps calculation please let me know some algorithm so that I can meet with the requirement.
The first thing you need to do is decide on an algorithm. As far as I know there are roughly speaking three ways to detect steps using accelerometers that are described in the literature:
Use the Pythagorean theorem to calculate the magnitude of the acceleration vector of each sample from the accelerometer. Low-pass filter the magnitude signal to remove high frequency noise and then look for peaks and valleys in the filtered signal. You may need to add additional requirements to remove false positives. This is by far the simplest way to detect steps, it is also the way that most if not all ordinary pedometers of the sort that you can buy from a sports store work.
Use Pythagoras' like in (1), then run the signal through an FFT and compare the output from the FFT to known outputs of walking. This requires you to have access to a fairly large amount of training data.
Feed the accelerometer data into an algorithm that uses some suitable machine learning technique, for example a neural network or a digital wavelet transform. You can of course include other sensors in this approach. This also requires you to have access to a fairly large amount of training data.
Once you have decided on an algorithm you will probably want to use something like Matlab or SciPy to test your algorithm on your computer using recordings that you have made on Android phones. Dump accelerometer data to a cvs file on your phone, make a record of how many steps the file represents, copy the file to your computer and run your algorithm on the data to see if it gets the step count right. That way you can detect problems with the algorithm and correct them.
If this sounds difficult, then the best way to get access to good step detection is probably to wait until more phones come with the built-in step counter that KitKat enables.
https://github.com/bagilevi/android-pedometer
i hope this might be helpfull
I am using step detection in my walking instrument.
I get nice results of step detection.
I use achartengine to plot accelerometer data.
Take a look here.
What I do:
Analysis of magnitude vector for accelerometer sensor.
Setting a changeable threshold level. When signal from accelerometer is above it I count it as a step.
Setting the time of inactive state (for step detection) after first crossing of the threshold.
Point 3. is calculated:
arbitrary setting the maximum tempo of our walking (e.g. 120bpm)
if 60bpm - 1000msec per step, then 120bpm - 500msec per step
accelerometer passes data with certain desired frequency (SENSOR_DELAY_NORMAL, SENSOR_DELAY_GAME, etc.). When DELAY_GAME: T ~= 20ms (this is included in Android documentation)
n - samples to omit (after passing the threshold)
n = 500msec / T
n = 500 / 20 = 25 (plenty of them. You can adjust this value).
after that, the threshold becomes active.
Take a look at this picture:
This is my realization. It was written about 1.5-2 years ago. And I really don't remember all this stuff that I wrote. But it worked. And it worked good for my needs.
I know that this is really big class (some methods are deleted), but may be it will be helpful. If not, I'll just remove this answer...
public class StepDetector implements SensorEventListener
{
public static final int MAX_BUFFER_SIZE = 5;
private static final int Y_DATA_COUNT = 4;
private static final double MIN_GRAVITY = 2;
private static final double MAX_GRAVITY = 1200;
public void onSensorChanged(final SensorEvent sensorEvent)
{
final float[] values = sensorEvent.values;
final Sensor sensor = sensorEvent.sensor;
if (sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD)
{
magneticDetector(values, sensorEvent.timestamp / (500 * 10 ^ 6l));
}
if (sensor.getType() == Sensor.TYPE_ACCELEROMETER)
{
accelDetector(values, sensorEvent.timestamp / (500 * 10 ^ 6l));
}
}
private ArrayList<float[]> mAccelDataBuffer = new ArrayList<float[]>();
private ArrayList<Long> mMagneticFireData = new ArrayList<Long>();
private Long mLastStepTime = null;
private ArrayList<Pair> mAccelFireData = new ArrayList<Pair>();
private void accelDetector(float[] detectedValues, long timeStamp)
{
float[] currentValues = new float[3];
for (int i = 0; i < currentValues.length; ++i)
{
currentValues[i] = detectedValues[i];
}
mAccelDataBuffer.add(currentValues);
if (mAccelDataBuffer.size() > StepDetector.MAX_BUFFER_SIZE)
{
double avgGravity = 0;
for (float[] values : mAccelDataBuffer)
{
avgGravity += Math.abs(Math.sqrt(
values[0] * values[0] + values[1] * values[1] + values[2] * values[2]) - SensorManager.STANDARD_GRAVITY);
}
avgGravity /= mAccelDataBuffer.size();
if (avgGravity >= MIN_GRAVITY && avgGravity < MAX_GRAVITY)
{
mAccelFireData.add(new Pair(timeStamp, true));
}
else
{
mAccelFireData.add(new Pair(timeStamp, false));
}
if (mAccelFireData.size() >= Y_DATA_COUNT)
{
checkData(mAccelFireData, timeStamp);
mAccelFireData.remove(0);
}
mAccelDataBuffer.clear();
}
}
private void checkData(ArrayList<Pair> accelFireData, long timeStamp)
{
boolean stepAlreadyDetected = false;
Iterator<Pair> iterator = accelFireData.iterator();
while (iterator.hasNext() && !stepAlreadyDetected)
{
stepAlreadyDetected = iterator.next().first.equals(mLastStepTime);
}
if (!stepAlreadyDetected)
{
int firstPosition = Collections.binarySearch(mMagneticFireData, accelFireData.get(0).first);
int secondPosition = Collections
.binarySearch(mMagneticFireData, accelFireData.get(accelFireData.size() - 1).first - 1);
if (firstPosition > 0 || secondPosition > 0 || firstPosition != secondPosition)
{
if (firstPosition < 0)
{
firstPosition = -firstPosition - 1;
}
if (firstPosition < mMagneticFireData.size() && firstPosition > 0)
{
mMagneticFireData = new ArrayList<Long>(
mMagneticFireData.subList(firstPosition - 1, mMagneticFireData.size()));
}
iterator = accelFireData.iterator();
while (iterator.hasNext())
{
if (iterator.next().second)
{
mLastStepTime = timeStamp;
accelFireData.remove(accelFireData.size() - 1);
accelFireData.add(new Pair(timeStamp, false));
onStep();
break;
}
}
}
}
}
private float mLastDirections;
private float mLastValues;
private float mLastExtremes[] = new float[2];
private Integer mLastType;
private ArrayList<Float> mMagneticDataBuffer = new ArrayList<Float>();
private void magneticDetector(float[] values, long timeStamp)
{
mMagneticDataBuffer.add(values[2]);
if (mMagneticDataBuffer.size() > StepDetector.MAX_BUFFER_SIZE)
{
float avg = 0;
for (int i = 0; i < mMagneticDataBuffer.size(); ++i)
{
avg += mMagneticDataBuffer.get(i);
}
avg /= mMagneticDataBuffer.size();
float direction = (avg > mLastValues ? 1 : (avg < mLastValues ? -1 : 0));
if (direction == -mLastDirections)
{
// Direction changed
int extType = (direction > 0 ? 0 : 1); // minumum or maximum?
mLastExtremes[extType] = mLastValues;
float diff = Math.abs(mLastExtremes[extType] - mLastExtremes[1 - extType]);
if (diff > 8 && (null == mLastType || mLastType != extType))
{
mLastType = extType;
mMagneticFireData.add(timeStamp);
}
}
mLastDirections = direction;
mLastValues = avg;
mMagneticDataBuffer.clear();
}
}
public static class Pair implements Serializable
{
Long first;
boolean second;
public Pair(long first, boolean second)
{
this.first = first;
this.second = second;
}
#Override
public boolean equals(Object o)
{
if (o instanceof Pair)
{
return first.equals(((Pair) o).first);
}
return false;
}
}
}
One main difference I spotted between your implementation and the code in the grepcode project is the way you register the listener.
Your code:
mSensorManager.registerListener(mStepDetector,
mSensor,
SensorManager.SENSOR_DELAY_NORMAL);
Their code:
mSensorManager.registerListener(mStepDetector,
mSensor,
SensorManager.SENSOR_DELAY_FASTEST);
This is a big difference. SENSOR_DELAY_NORMAL is intended for orientation changes, and is therefor not that fast (ever noticed that it takes some time between you rotating the device, and the device actually rotating? That's because this is some functionality that does not need to be super fast (that would probably be pretty annoying even). The rate at which you get updates is not that high).
On the other hand, SENSOR_DELAY_FASTEST is intended for things like pedometers: you want the sensor data as fast and often as possible, so your calculations of steps will be as accurate as possible.
Try to switch to the SENSOR_DELAY_FASTEST rate, and test again! It should make a big difference.
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType()==Sensor.TYPE_ACCELEROMETER ){
float x = event.values[0];
float y = event.values[1];
float z = event.values[2];
currentvectorSum = (x*x + y*y + z*z);
if(currentvectorSum < 100 && inStep==false){
inStep = true;
}
if(currentvectorSum > 125 && inStep==true){
inStep = false;
numSteps++;
Log.d("TAG_ACCELEROMETER", "\t" + numSteps);
}
}
}

Android how to detect if phone is turned around

This is my code for detecting if phone is turned around or not
private SensorManager sensorManager;
private int orientationLim = 165;
#Override
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_ORIENTATION) {
// If shake to stop is enabled
boolean turnAroundToStop = Utils.getBooleanFromProperties(this, Properties.SP_CB_TURN_AROUND_TO_STOP);
if (turnAroundToStop) {
float value = Math.abs(event.values[1]);
if (value > orientationLim && !stopped) {
// Down
stopped = true;
} else {
// Up
stopped = false;
}
}
}
}
but problem is that stopped variable is set to true even phone is not completely turned around but just a little.
How can i modify this code that will be executed only when phone is relay turned around.
float pitch = values[2];
if (pitch <= 45 && pitch >= -45) {
// mostly vertical
} else if (pitch < -45) {
// mostly right side up
} else if (pitch > 45) {
// mostly left side up
}
Take a look here on this topic:
http://www.workingfromhere.com/blog/2009/03/30/orientation-sensor-tips-in-android/

Categories

Resources