can i computing the velocity with the accelerations from the sensor which type is SENSOR_TYPE_ACCELEROMETER?
or can i get the orientation of the the accelerations from the sensor which type is SENSOR_TYPE_ACCELEROMETER?
i have seen some blogs about checking the value of the vector of accelerations to detect whether the android phone is filling down or not.
but ,the reson may be the android phone is shaking and is not filling.
my code is:
/**
* how often analysising the accelerometer?(Millisecond)
*/
private static final int ANALYSIS_ACCELERATION_INTERVAL = 500;
/**
* how often checking the accelerometer?(Millisecond)
*/
private static final int CHECK_TIME_INTERVAL = 5000;
/**
* when the sMinorMaxAccelerationInOneSecoud[0] is less than
* ACCELERATION_CRITICAL_VALUE[0],and the
* sMinorMaxAccelerationInOneSecoud[1] is more than
* ACCELERATION_CRITICAL_VALUE[1],i think the phone dropped to the
* ground.
*/
private static float ACCELERATION_CRITICAL_VALUE[] = {2, 40};
/**
* during{#link #ANALYSIS_ACCELERATION_INTERVAL},the min accelerometer
* of the phone is sMinorMaxAccelerationInOneSecoud[0],the max
* accelerometer of the phone is saved at
* sMinorMaxAccelerationInOneSecoud[1].
*/
private static float sMinorMaxAccelerationInOneSecoud[] = {0, 0};
/**
* the last time when checking the accelerometer
*/
private static long sLastCheckTime = 0;
/**
* the last time when analysising the accelerometer
*/
private static long sLastAnalysisTime = 0;
/**
* during {#link #CHECK_TIME_INTERVAL},is phone dropped to ground?
*/
private static boolean sIsFallDown = false;
private SensorManager mSensorManager;
public void receiveCondition() {
// a dialog
Intent intent = new Intent();
intent.setClass(GlobalHolder.getApplicationContext(), PhoneDroppedDialog.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
GlobalHolder.getApplicationContext().startActivity(intent);
}
public void start() {
mSensorManager = (SensorManager) getApplicationContext().getSystemService(Context.SENSOR_SERVICE);
mSensorManager.registerListener(this,
mSensorManager.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION),
SensorManager.SENSOR_DELAY_UI);
}
public void stop() {
mSensorManager.unregisterListener(this);
mSensorManager = null;
sMinorMaxAccelerationInOneSecoud = new float[]{0, 0};
sLastCheckTime = 0;
sLastAnalysisTime = 0;
}
#Override
public void onSensorChanged(SensorEvent event) {
int sensorType = event.sensor.getType();
if (sensorType != Sensor.TYPE_LINEAR_ACCELERATION) {
return;
}
// judge if the sMinorMaxAccelerationInOneSecoud[0] is less than
// ACCELERATION_CRITICAL_VALUE[0],and the
// sMinorMaxAccelerationInOneSecoud[1] is more than
// ACCELERATION_CRITICAL_VALUE[1]
analysisAcceleration(event.values);
long currentTime = System.currentTimeMillis();
long beta = currentTime - sLastCheckTime;
if (Math.abs(beta) < CHECK_TIME_INTERVAL) {
return;
}
// it have been more than one secound since the last check,so we need re-check if the phone have dropped to the ground.
checkIsFallDown();
// reset sLastCheckTime with the current time
sLastCheckTime = currentTime;
}
private void analysisAcceleration(float[] values) {
if (sIsFallDown) {
// if the phone have already dropped to the ground,we return directly.
return;
}
// whether the min sum vector of the accelerations on the x_axis,y_axis,zaxis is less than ACCELERATION_CRITICAL_VALUE[0]
// and the max sum vector of the accelerations on the x_axis,y_axis,zaxis is more than ACCELERATION_CRITICAL_VALUE[1]
if (sLastAnalysisTime == 0) {
sLastAnalysisTime = System.currentTimeMillis();
}
// the sum vector of the accelerations on the x_axis,y_axis,zaxis
float currentAcceleration = 0f;
for (int i = 0; i < values.length; i++) {
currentAcceleration += (values[i] * values[i]);
}
currentAcceleration = (float) Math.sqrt(currentAcceleration);
if (sMinorMaxAccelerationInOneSecoud[0] == 0 || sMinorMaxAccelerationInOneSecoud[0] > currentAcceleration) {
sMinorMaxAccelerationInOneSecoud[0] = currentAcceleration;
}
if (sMinorMaxAccelerationInOneSecoud[1] == 0 || sMinorMaxAccelerationInOneSecoud[1] < currentAcceleration) {
sMinorMaxAccelerationInOneSecoud[1] = currentAcceleration;
}
long currentTime = System.currentTimeMillis();
long delta = currentTime - sLastAnalysisTime;
if (delta < ANALYSIS_ACCELERATION_INTERVAL) {
return;
}
MLog.d(TAG, "during ANALYSIS_ACCELERATION_INTERVAL, the min value is " + sMinorMaxAccelerationInOneSecoud[0] + ", the max value is " + sMinorMaxAccelerationInOneSecoud[1]);
boolean isLessPre = sMinorMaxAccelerationInOneSecoud[0] < ACCELERATION_CRITICAL_VALUE[0];
boolean isMoreNext = sMinorMaxAccelerationInOneSecoud[1] > ACCELERATION_CRITICAL_VALUE[1];
sIsFallDown = isLessPre && isMoreNext;
sLastAnalysisTime = currentTime;
sMinorMaxAccelerationInOneSecoud = new float[]{0, 0};
}
private void checkIsFallDown() {
if (sIsFallDown) {
// the phone have dropped
receiveCondition();
MLog.d(TAG, "call the receiveCondition method.");
sMinorMaxAccelerationInOneSecoud = new float[]{0, 0};
sIsFallDown = false;
}
}
someone has a better idea?thanks!!
Related
I'm trying to detect a motion that you would get from bumping two phones with each other.
My question is, is an accelerometer the right sensor for this?
If so, how would I implement it?
Otherwise, what sensor should I use and in what way should I use it?
According to the guide at https://developer.android.com/guide/topics/sensors/sensors_overview, TYPE_LINEAR_ACCELERATION seems like the right one to use, however I can't figure out how to use it.
Here's how you could do it.
1- Initialize sensor object and register for sensor updates events callback like this
private void initSensorObject() {
SensorManager sensorMgr = (SensorManager) getSystemService(SENSOR_SERVICE);
Sensor _Sensor = sensorMgr.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
sensorMgr.registerListener(sensorEventListener, _Sensor,
SensorManager.SENSOR_DELAY_FASTEST);
}
2- Handle the sensor callback in the following way which detects linear acceleration exluding the effect of gravity and then an abrupt stop in motion (I wrote this for two tap motions like a tap then stop, again a tap then again stop. I'll explain the whole process for better understanding, you can easily modify it for only one tap detection.) I have added comments in the code to make it self-explanatory.
/*
* Following are the parameters for Tap detection Algorithm
*/
private static float SPEED_THRESHOLD_RISE1;
private static float SPEED_THRESHOLD_DROP1;
private static float SPEED_THRESHOLD_RISE2;
private static float SPEED_THRESHOLD_DROP2;
private static int DROP_DELTA;
private static int RISE2_DELTA;
private int SENSITIVITY_INDEX = TapParam.SEN_DEFAULT;
private static final int TAP_STATE_RISE1 = 0;
private static final int TAP_STATE_DROP1 = 1;
private static final int TAP_STATE_RISE2 = 2;
private static final int TAP_STATE_DROP2 = 3;
private int tappingState = TAP_STATE_RISE1;
private boolean tapLastStateOnce = false;
private long lastSensorUpdate;
private long tap1DroppedAt = 0;
private int mathMeanIndex = 0;
private float[] lastLinearAcc = new float[3];
private float[] acceleSet = new float[TapParam.AM_SIZE];
private int acceleIndex = 0;
private float[] gravity = new float[3];
private float lastAccele = -99; // an arbitrarily very small value
/**
* onSensorChanged is called when the Motion Sensor value
* is changed and then run the algorithm to detect your desired motion.
*
* #return void
*/
private SensorEventListener sensorEventListener = new SensorEventListener() {
#Override
public void onSensorChanged(SensorEvent event) {
long curSensorTime = System.currentTimeMillis();
if ((curSensorTime - lastSensorUpdate) < TapParam.SENSOR_RE_READ_TIME)
return;
lastSensorUpdate = curSensorTime;
acceleSet[acceleIndex] = getMotionAcceleration(event, curSensorTime);
acceleIndex = (acceleIndex + 1) % TapParam.AM_SIZE;
if (mathMeanIndex < TapParam.AM_SIZE)
mathMeanIndex++;
float accele = Util.getArithmeticMean(acceleSet);
switch (tappingState) {
case TAP_STATE_RISE1:
if (accele > SPEED_THRESHOLD_RISE1) {
tappingState = TAP_STATE_DROP1;
resetTapStateDropping();
mathMeanIndex = 0;
}
break;
case TAP_STATE_DROP1:
if (accele <= SPEED_THRESHOLD_DROP1) {
tappingState = TAP_STATE_RISE2;
resetTapStateRise2();
tap1DroppedAt = curSensorTime;
mathMeanIndex = 0;
}
break;
case TAP_STATE_RISE2:
if (curSensorTime - tap1DroppedAt >= TapParam.DELAY_BETWEEN_TAPS) {
if (accele > SPEED_THRESHOLD_RISE2) {
tappingState = TAP_STATE_DROP2;
resetTapStateDropping();
mathMeanIndex = 0;
}
}
break;
case TAP_STATE_DROP2:
if ((!tapLastStateOnce) && (accele <= SPEED_THRESHOLD_DROP2)) {
tapLastStateOnce = true;
resetTapStateRise2();
mathMeanIndex = 0;
onTapTapDetected();
}
break;
default:
tappingState = TAP_STATE_RISE1;
break;
}
}
/**
* onAccuracyChanged inter shall be called when hardware IMU
* (Inertial Measurement Unit a.k.a Motion Sensor) of the device change
* its accuracy value.
*
* #return void
*/
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
setThresholdValues();
}
};
/**
* It shall return the Linear Acceleration of the device. The force of
* gravity shall be filtered out.
*
* #return float - Linear acceleration
*/
private float getMotionAcceleration(SensorEvent event, long curSensorTime) {
// In this code, alpha is calculated as t / (t + dT),
// where t is the low-pass filter's time-constant and
// dT is the event delivery rate.
final float alpha = 0.8f;
float[] linearAcc = new float[3];
// Isolate the force of gravity with the low-pass filter.
gravity[0] = alpha * gravity[0] + (1 - alpha) * event.values[0];
gravity[1] = alpha * gravity[1] + (1 - alpha) * event.values[1];
gravity[2] = alpha * gravity[2] + (1 - alpha) * event.values[2];
// Remove the gravity contribution with the high-pass filter.
linearAcc[0] = event.values[0] - gravity[0];
linearAcc[1] = event.values[1] - gravity[1];
linearAcc[2] = event.values[2] - gravity[2];
float accele = (Math.abs(lastLinearAcc[0] - linearAcc[0])
+ Math.abs(lastLinearAcc[1] - linearAcc[1]) + Math
.abs(lastLinearAcc[2] - linearAcc[2])) / 3;
lastLinearAcc = linearAcc;
return accele;
}
/**
* resetTapStateRise2 shall reset the tapping state if
* second Tap is not detected within TAP_RISE2_TIME time.
*
* #return void
*/
private void resetTapStateRise2() {
handleResetTapState.removeCallbacks(runResetTapState);
handleResetTapState.postDelayed(runResetTapState, RISE2_DELTA);
}
private Handler handleResetTapState = new Handler();
private Runnable runResetTapState = new Runnable() {
#Override
public void run() {
tappingState = TAP_STATE_RISE1;
tapLastStateOnce = false;
}
};
/**
* resetTapStateDropping shall reset the tapping state if
* Tap Drop is not detected within TAP_DROP_TIME time.
*
* #return void
*/
private void resetTapStateDropping() {
handleResetTapState.removeCallbacks(runResetTapState);
handleResetTapState.postDelayed(runResetTapState, DROP_DELTA);
}
private Handler handleResetTapState = new Handler();
private Runnable runResetTapState = new Runnable() {
#Override
public void run() {
tappingState = TAP_STATE_RISE1;
tapLastStateOnce = false;
}
};
3- Here is a working parameters file to help you get started. thresholds array defines 10 levels of sensitivity of how hard or how soft you want to tap your phone to get detected as a valid motion
TapParam.java
final class TapParam {
static final int SEN_DEFAULT = 4;
static final int SEN_MIN = 0;
static final int SEN_MAX = 9;
static final int DELAY_BETWEEN_TAPS = 75;
static final int SENSOR_RE_READ_TIME = 1;
static final int AM_SIZE = 5;
// Columns: A B Y D T1 T2 T3
private static final double[][] thresholds = new double[][]{
{0.8483763, 0.33935052, 0.5655842, 0.33935052, 175, 300, 175},
{0.95167595, 0.38067037, 0.6344506, 0.38067037, 175, 300, 175},
{1.0836192, 0.4334477, 0.7224128, 0.4334477, 175, 300, 175},
{1.8552876, 0.742115, 1.2368584, 0.742115, 175, 300, 175},
{2.4327612, 0.9731045, 1.6218408, 0.9731045, 175, 300, 175},
{3.5321822, 1.4128729, 2.354788, 1.4128729, 175, 300, 175},
{6.4446864, 2.5778747, 4.296458, 2.5778747, 175, 300, 175},
{8.2, 3.5, 5.4, 2.6, 175, 300, 175},
{9.8, 4.0, 6.0, 2.9, 175, 300, 175},
{12, 6.0, 8.0, 3.1, 175, 300, 175}
};
private static int indexLimiting(int index) {
return (index > SEN_MAX) ? SEN_MAX : (index < SEN_MIN) ? SEN_MIN : index;
}
static float getRISE1(int index) {
index = indexLimiting(index);
return (float) thresholds[index][0];
}
static float getDROP1(int index) {
index = indexLimiting(index);
return (float) thresholds[index][1];
}
static float getRISE2(int index) {
index = indexLimiting(index);
return (float) thresholds[index][2];
}
static float getDROP2(int index) {
index = indexLimiting(index);
return (float) thresholds[index][3];
}
static float getDROP_DELTA1(int index) {
index = indexLimiting(index);
return (float) thresholds[index][4];
}
static float getRISE_DELTA2(int index) {
index = indexLimiting(index);
return (float) thresholds[index][5];
}
}
UPDATE:
/**
* setThresholdValues method shall calculate the Threshold values according
* to the accuracy value of the Motion Sensor.
*/
private void setThresholdValues() {
if (_Sensor == null)
return;
SPEED_THRESHOLD_RISE1 = TapParam.getRISE1(SENSITIVITY_INDEX);
SPEED_THRESHOLD_DROP1 = TapParam.getDROP1(SENSITIVITY_INDEX);
SPEED_THRESHOLD_RISE2 = TapParam.getRISE2(SENSITIVITY_INDEX);
SPEED_THRESHOLD_DROP2 = TapParam.getDROP2(SENSITIVITY_INDEX);
}
/**
* Method shall return the average (Arithmetic Mean) of the set of values
* passed as parameter.
*
* #param float[] set - the set of values
* #return float - arithmetic mean
*/
static float getArithmeticMean(float[] set) {
double sum = 0;
for (float aSet : set) {
sum += aSet;
}
return (float) sum / set.length;
}
UPDATE 2:
Call setTapTapSensitivity() in onCreate() of your activity
private void setTapTapSensitivity() {
setTapTapSensitivity(3); //You can try 0 to 9 for 10 levels of sensitivity defined in TapParam.java. I have tried 3 and it works for a moderate tap
}
private void setTapTapSensitivity(int sensitivityIndex) {
RISE2_DELTA = (int) TapParam.getRISE_DELTA2(sensitivityIndex);
DROP_DELTA = (int) TapParam.getDROP_DELTA1(sensitivityIndex);
SENSITIVITY_INDEX = sensitivityIndex;
}
I want to make an app,And I am new in android.
I have 10 pictures.
When I shake my phone I want to show each day one of these pictures in random method.
I write the shake code and show randomly this pictures,but I cant show one of them each day.
Can you help me how is the code of shared preference?
public class MainAccelerometer extends Activity implements AccelerometerListener{
ImageView favorit;
ImageView img;
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
favorit = (ImageView)findViewById(R.id.favorit);
img = (ImageView)findViewById(R.id.img);
// Check onResume Method to start accelerometer listener
}
public void onAccelerationChanged(float x, float y, float z) {
// TODO Auto-generated method stub
}
public void onShake(float force) {
Random rand = new Random();
int rndInt = rand.nextInt(10) + 1; // n = the number of images, that start at idx 1
String imgName = "img" + rndInt;
int id = getResources().getIdentifier(imgName, "drawable", getPackageName());
img.setImageResource(id);
// Do your stuff here
// Called when Motion Detected
Toast.makeText(getBaseContext(), "shake",
Toast.LENGTH_SHORT).show();
favorit.setBackgroundResource(R.drawable.img2);
}
#Override
public void onResume() {
super.onResume();
Toast.makeText(getBaseContext(), "onResume Accelerometer Started",
Toast.LENGTH_SHORT).show();
//Check device supported Accelerometer senssor or not
if (AccelerometerManager.isSupported(this)) {
//Start Accelerometer Listening
AccelerometerManager.startListening(this);
}
}
#Override
public void onStop() {
super.onStop();
//Check device supported Accelerometer senssor or not
if (AccelerometerManager.isListening()) {
//Start Accelerometer Listening
AccelerometerManager.stopListening();
Toast.makeText(getBaseContext(), "onStop Accelerometer Stoped",
Toast.LENGTH_SHORT).show();
}
}
#Override
public void onDestroy() {
super.onDestroy();
Log.i("Sensor", "Service distroy");
//Check device supported Accelerometer senssor or not
if (AccelerometerManager.isListening()) {
//Start Accelerometer Listening
AccelerometerManager.stopListening();
Toast.makeText(getBaseContext(), "onDestroy Accelerometer Stoped",
Toast.LENGTH_SHORT).show();
}
}}
and other class
public class AccelerometerManager {
private static Context aContext=null;
/** Accuracy configuration */
private static float threshold = 15.0f;
private static int interval = 200;
private static Sensor sensor;
private static SensorManager sensorManager;
// you could use an OrientationListener array instead
// if you plans to use more than one listener
private static AccelerometerListener listener;
/** indicates whether or not Accelerometer Sensor is supported */
private static Boolean supported;
/** indicates whether or not Accelerometer Sensor is running */
private static boolean running = false;
/**
* Returns true if the manager is listening to orientation changes
*/
public static boolean isListening() {
return running;
}
/**
* Unregisters listeners
*/
public static void stopListening() {
running = false;
try {
if (sensorManager != null && sensorEventListener != null) {
sensorManager.unregisterListener(sensorEventListener);
}
} catch (Exception e) {}
}
/**
* Returns true if at least one Accelerometer sensor is available
*/
public static boolean isSupported(Context context) {
aContext = context;
if (supported == null) {
if (aContext != null) {
sensorManager = (SensorManager) aContext.
getSystemService(Context.SENSOR_SERVICE);
// Get all sensors in device
List<Sensor> sensors = sensorManager.getSensorList(
Sensor.TYPE_ACCELEROMETER);
supported = new Boolean(sensors.size() > 0);
} else {
supported = Boolean.FALSE;
}
}
return supported;
}
/**
* Configure the listener for shaking
* #param threshold
* minimum acceleration variation for considering shaking
* #param interval
* minimum interval between to shake events
*/
public static void configure(int threshold, int interval) {
AccelerometerManager.threshold = threshold;
AccelerometerManager.interval = interval;
}
/**
* Registers a listener and start listening
* #param accelerometerListener
* callback for accelerometer events
*/
public static void startListening( AccelerometerListener accelerometerListener )
{
sensorManager = (SensorManager) aContext.
getSystemService(Context.SENSOR_SERVICE);
// Take all sensors in device
List<Sensor> sensors = sensorManager.getSensorList(
Sensor.TYPE_ACCELEROMETER);
if (sensors.size() > 0) {
sensor = sensors.get(0);
// Register Accelerometer Listener
running = sensorManager.registerListener(
sensorEventListener, sensor,
SensorManager.SENSOR_DELAY_GAME);
listener = accelerometerListener;
}
}
/**
* Configures threshold and interval
* And registers a listener and start listening
* #param accelerometerListener
* callback for accelerometer events
* #param threshold
* minimum acceleration variation for considering shaking
* #param interval
* minimum interval between to shake events
*/
public static void startListening(
AccelerometerListener accelerometerListener,
int threshold, int interval) {
configure(threshold, interval);
startListening(accelerometerListener);
}
/**
* The listener that listen to events from the accelerometer listener
*/
private static SensorEventListener sensorEventListener =
new SensorEventListener() {
private long now = 0;
private long timeDiff = 0;
private long lastUpdate = 0;
private long lastShake = 0;
private float x = 0;
private float y = 0;
private float z = 0;
private float lastX = 0;
private float lastY = 0;
private float lastZ = 0;
private float force = 0;
public void onAccuracyChanged(Sensor sensor, int accuracy) {}
public void onSensorChanged(SensorEvent event) {
// use the event timestamp as reference
// so the manager precision won't depends
// on the AccelerometerListener implementation
// processing time
now = event.timestamp;
x = event.values[0];
y = event.values[1];
z = event.values[2];
// if not interesting in shake events
// just remove the whole if then else block
if (lastUpdate == 0) {
lastUpdate = now;
lastShake = now;
lastX = x;
lastY = y;
lastZ = z;
Toast.makeText(aContext,"no",
Toast.LENGTH_SHORT).show();
} else {
timeDiff = now - lastUpdate;
if (timeDiff > 0) {
/*force = Math.abs(x + y + z - lastX - lastY - lastZ)
/ timeDiff;*/
force = Math.abs(x + y + z - lastX - lastY - lastZ);
if (Float.compare(force, threshold) >0 ) {
//Toast.makeText(Accelerometer.getContext(),
//(now-lastShake)+" >= "+interval, 1000).show();
if (now - lastShake >= interval) {
// trigger shake event
listener.onShake(force);
}
else
{
Toast.makeText(aContext,"No Motion detected",
Toast.LENGTH_SHORT).show();
}
lastShake = now;
}
lastX = x;
lastY = y;
lastZ = z;
lastUpdate = now;
}
else
{
Toast.makeText(aContext,"No Motion detected", Toast.LENGTH_SHORT).show();
}
}
// trigger change event
listener.onAccelerationChanged(x, y, z);
}
};}
Hey You can use this method to ge the current timeStamp and to claculate time difference.
/*
* This method is calling to get current date
*
* */
public static String getCurrentDateWitTime() {
Calendar c = Calendar.getInstance();
// SimpleDateFormat df = new SimpleDateFormat(" yyyy-MM-dd'T'HH:mm:ss'Z");
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String formattedDate = df.format(c.getTime());
return formattedDate;
}
public static long getDifference(String oldTime)
{
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date oldDate = null;
try {
oldDate = dateFormat.parse(oldTime);
} catch (ParseException e) {
e.printStackTrace();
}
Date cDate = new Date();
Long timeDiff = cDate.getTime() - oldDate.getTime();
enter code here
long diffInSec = TimeUnit.MILLISECONDS.toSeconds(timeDiff);
return diffInSec;
}
I am unable to create more circles which follows its own path with drawCircle .
I have used the code below which creates another circle but follows the path along the lines of 1st circle but not independent .How do I move both circles independent of each other?
I have added
c.drawCircle(ballX-100, ballY-100, 50, ballPaintyellow);
How do I make the above circle independent from the 1st circle?. I really appreciate any help.Thanks in Advance.
BouncingBallActivity.java
package com.stuffthathappens.games;
import static android.hardware.SensorManager.DATA_X;
import static android.hardware.SensorManager.DATA_Y;
import static android.hardware.SensorManager.SENSOR_ACCELEROMETER;
import static android.hardware.SensorManager.SENSOR_DELAY_GAME;
import java.util.concurrent.TimeUnit;
import android.app.Activity;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.hardware.SensorListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.os.Vibrator;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.SurfaceHolder.Callback;
/**
* This activity shows a ball that bounces around. The phone's
* accelerometer acts as gravity on the ball. When the ball hits
* the edge, it bounces back and triggers the phone vibrator.
*/
#SuppressWarnings("deprecation")
public class BouncingBallActivity extends Activity implements Callback, SensorListener {
private static final int BALL_RADIUS =20;
private SurfaceView surface;
private SurfaceHolder holder;
private final BouncingBallModel model = new BouncingBallModel(BALL_RADIUS);
private GameLoop gameLoop;
private Paint backgroundPaint;
private Paint ballPaint;
private SensorManager sensorMgr;
private long lastSensorUpdate = -1;
private Paint ballPaintyellow;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.bouncing_ball);
surface = (SurfaceView) findViewById(R.id.bouncing_ball_surface);
holder = surface.getHolder();
surface.getHolder().addCallback(this);
backgroundPaint = new Paint();
backgroundPaint.setColor(Color.WHITE);
ballPaint = new Paint();
ballPaint.setColor(Color.BLUE);
ballPaint.setAntiAlias(true);
ballPaintyellow = new Paint();
ballPaintyellow.setColor(Color.YELLOW);
ballPaintyellow.setAntiAlias(true);
}
#Override
protected void onPause() {
super.onPause();
model.setVibrator(null);
sensorMgr.unregisterListener(this, SENSOR_ACCELEROMETER);
sensorMgr = null;
model.setAccel(0, 0);
}
#Override
protected void onResume() {
super.onResume();
sensorMgr = (SensorManager) getSystemService(SENSOR_SERVICE);
boolean accelSupported = sensorMgr.registerListener(this,
SENSOR_ACCELEROMETER,
SENSOR_DELAY_GAME);
if (!accelSupported) {
// on accelerometer on this device
sensorMgr.unregisterListener(this, SENSOR_ACCELEROMETER);
// TODO show an error
}
// NOTE 1: you cannot get system services before onCreate()
// NOTE 2: AndroidManifest.xml must contain this line:
// <uses-permission android:name="android.permission.VIBRATE"/>
Vibrator vibrator = (Vibrator) getSystemService(Activity.VIBRATOR_SERVICE);
model.setVibrator(vibrator);
}
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
model.setSize(width, height);
}
public void surfaceCreated(SurfaceHolder holder) {
gameLoop = new GameLoop();
gameLoop.start();
}
private void draw() {
// thread safety - the SurfaceView could go away while we are drawing
Canvas c = null;
try {
// NOTE: in the LunarLander they don't have any synchronization here,
// so I guess this is OK. It will return null if the holder is not ready
c = holder.lockCanvas();
// this needs to synchronize on something
if (c != null) {
doDraw(c);
}
} finally {
if (c != null) {
holder.unlockCanvasAndPost(c);
}
}
}
private void doDraw(Canvas c) {
int width = c.getWidth();
int height = c.getHeight();
c.drawRect(0, 0, width, height, backgroundPaint);
float ballX, ballY;
synchronized (model.LOCK) {
ballX = model.ballPixelX;
ballY = model.ballPixelY;
}
c.drawCircle(ballX, ballY, BALL_RADIUS, ballPaint);
c.drawCircle(ballX-100, ballY-100, 50, ballPaintyellow);
}
public void surfaceDestroyed(SurfaceHolder holder) {
try {
model.setSize(0,0);
gameLoop.safeStop();
} finally {
gameLoop = null;
}
}
private class GameLoop extends Thread {
private volatile boolean running = true;
public void run() {
while (running) {
try {
// don't like this hardcoding
TimeUnit.MILLISECONDS.sleep(5);
draw();
model.updatePhysics();
} catch (InterruptedException ie) {
running = false;
}
}
}
public void safeStop() {
running = false;
interrupt();
}
}
public void onAccuracyChanged(int sensor, int accuracy) {
}
public void onSensorChanged(int sensor, float[] values) {
if (sensor == SENSOR_ACCELEROMETER) {
long curTime = System.currentTimeMillis();
// only allow one update every 50ms, otherwise updates
// come way too fast
if (lastSensorUpdate == -1 || (curTime - lastSensorUpdate) > 50) {
lastSensorUpdate = curTime;
model.setAccel(values[DATA_X], values[DATA_Y]);
}
}
}
}
Bouncingballmodel.java
package com.stuffthathappens.games;
import java.util.concurrent.atomic.AtomicReference;
import android.os.Vibrator;
/**
* This data model tracks the width and height of the playing field along
* with the current position of a ball.
*/
public class BouncingBallModel {
// the ball speed is meters / second. When we draw to the screen,
// 1 pixel represents 1 meter. That ends up too slow, so multiply
// by this number. Bigger numbers speeds things up.
private final float pixelsPerMeter = 10;
private final int ballRadius;
// these are public, so make sure you synchronize on LOCK
// when reading these. I made them public since you need to
// get both X and Y in pairs, and this is more efficient than
// getter methods. With two getters, you'd still need to
// synchronize.
public float ballPixelX, ballPixelY;
private int pixelWidth, pixelHeight;
// values are in meters/second
private float velocityX, velocityY;
// typical values range from -10...10, but could be higher or lower if
// the user moves the phone rapidly
private float accelX, accelY;
/**
* When the ball hits an edge, multiply the velocity by the rebound.
* A value of 1.0 means the ball bounces with 100% efficiency. Lower
* numbers simulate balls that don't bounce very much.
*/
private static final float rebound = 0.8f;
// if the ball bounces and the velocity is less than this constant,
// stop bouncing.
private static final float STOP_BOUNCING_VELOCITY = 2f;
private volatile long lastTimeMs = -1;
public final Object LOCK = new Object();
private AtomicReference<Vibrator> vibratorRef =
new AtomicReference<Vibrator>();
public BouncingBallModel(int ballRadius) {
this.ballRadius = ballRadius;
}
public void setAccel(float ax, float ay) {
synchronized (LOCK) {
this.accelX = ax;
this.accelY = ay;
}
}
public void setSize(int width, int height) {
synchronized (LOCK) {
this.pixelWidth = width;
this.pixelHeight = height;
}
}
public int getBallRadius() {
return ballRadius;
}
/**
* Call this to move the ball to a particular location on the screen. This
* resets the velocity to zero, but the acceleration doesn't change so
* the ball should start falling shortly.
*/
public void moveBall(int ballX, int ballY) {
synchronized (LOCK) {
this.ballPixelX = ballX;
this.ballPixelY = ballY;
velocityX = 0;
velocityY = 0;
}
}
public void updatePhysics() {
// copy everything to local vars (hence the 'l' prefix)
float lWidth, lHeight, lBallX, lBallY, lAx, lAy, lVx, lVy;
synchronized (LOCK) {
lWidth = pixelWidth;
lHeight = pixelHeight;
lBallX = ballPixelX;
lBallY = ballPixelY;
lVx = velocityX;
lVy = velocityY;
lAx = accelX;
lAy = -accelY;
}
if (lWidth <= 0 || lHeight <= 0) {
// invalid width and height, nothing to do until the GUI comes up
return;
}
long curTime = System.currentTimeMillis();
if (lastTimeMs < 0) {
lastTimeMs = curTime;
return;
}
long elapsedMs = curTime - lastTimeMs;
lastTimeMs = curTime;
// update the velocity
// (divide by 1000 to convert ms to seconds)
// end result is meters / second
lVx += ((elapsedMs * lAx) / 1000) * pixelsPerMeter;
lVy += ((elapsedMs * lAy) / 1000) * pixelsPerMeter;
// update the position
// (velocity is meters/sec, so divide by 1000 again)
lBallX += ((lVx * elapsedMs) / 1000) * pixelsPerMeter;
lBallY += ((lVy * elapsedMs) / 1000) * pixelsPerMeter;
boolean bouncedX = false;
boolean bouncedY = false;
if (lBallY - ballRadius < 0) {
lBallY = ballRadius;
lVy = -lVy * rebound;
bouncedY = true;
} else if (lBallY + ballRadius > lHeight) {
lBallY = lHeight - ballRadius;
lVy = -lVy * rebound;
bouncedY = true;
}
if (bouncedY && Math.abs(lVy) < STOP_BOUNCING_VELOCITY) {
lVy = 0;
bouncedY = false;
}
if (lBallX - ballRadius < 0) {
lBallX = ballRadius;
lVx = -lVx * rebound;
bouncedX = true;
} else if (lBallX + ballRadius > lWidth) {
lBallX = lWidth - ballRadius;
lVx = -lVx * rebound;
bouncedX = true;
}
if (bouncedX && Math.abs(lVx) < STOP_BOUNCING_VELOCITY) {
lVx = 0;
bouncedX = false;
}
// safely copy local vars back to object fields
synchronized (LOCK) {
ballPixelX = lBallX;
ballPixelY = lBallY;
velocityX = lVx;
velocityY = lVy;
}
if (bouncedX || bouncedY) {
Vibrator v = vibratorRef.get();
if (v != null) {
v.vibrate(20L);
}
}
}
public void setVibrator(Vibrator v) {
vibratorRef.set(v);
}
}
Which view you are using has nothing to do with it ....
At the moment you have only one BouncingBallModel
private final BouncingBallModel model = new BouncingBallModel(BALL_RADIUS);
This is the one you see when you draw something. Now if you want to draw multiple balls, you will need many BouncingBallModel. So either create a BouncingBallModel model2 or make it dynamic using an array.
Then iterate over the array and draw each ball.
I tried to make a single ball bouncing to dynamic ball bouncing . Eg: here the number of circles is 50.
But I am getting error while trying to make the circles dynamic (Model) .How do I make it work and make the model/circle dynamic.In this case 50 circles ? I really appreciate any help. Thanks in Advance.
package com.stuffthathappens.games;
import static android.hardware.SensorManager.DATA_X;
import static android.hardware.SensorManager.DATA_Y;
import static android.hardware.SensorManager.SENSOR_ACCELEROMETER;
import static android.hardware.SensorManager.SENSOR_DELAY_GAME;
import java.util.concurrent.TimeUnit;
import android.app.Activity;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.hardware.SensorListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.os.Vibrator;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.SurfaceHolder.Callback;
/**
* This activity shows a ball that bounces around. The phone's
* accelerometer acts as gravity on the ball. When the ball hits
* the edge, it bounces back and triggers the phone vibrator.
*/
#SuppressWarnings("deprecation")
public class BouncingBallActivity extends Activity implements Callback, SensorListener {
private static final int BALL_RADIUS =20;
private SurfaceView surface;
private SurfaceHolder holder;
private GameLoop gameLoop;
private Paint backgroundPaint;
private Paint ballPaint;
private SensorManager sensorMgr;
private long lastSensorUpdate = -1;
private Paint ballPaintyellow;
private BouncingBallModel[] model;
int Totalcircles=50;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.bouncing_ball);
for (int i = 0; i < Totalcircles; i++) {
model[i] = new BouncingBallModel(BALL_RADIUS);
}
surface = (SurfaceView) findViewById(R.id.bouncing_ball_surface);
holder = surface.getHolder();
surface.getHolder().addCallback(this);
backgroundPaint = new Paint();
backgroundPaint.setColor(Color.WHITE);
ballPaint = new Paint();
ballPaint.setColor(Color.BLUE);
ballPaint.setAntiAlias(true);
ballPaintyellow = new Paint();
ballPaintyellow.setColor(Color.YELLOW);
ballPaintyellow.setAntiAlias(true);
}
#Override
protected void onPause() {
super.onPause();
for (int i = 0; i < Totalcircles; i++) {
model[i].setVibrator(null);
}
sensorMgr.unregisterListener(this, SENSOR_ACCELEROMETER);
sensorMgr = null;
for (int i = 0; i < Totalcircles; i++) {
model[i].setAccel(0, 0);
}
}
#Override
protected void onResume() {
super.onResume();
sensorMgr = (SensorManager) getSystemService(SENSOR_SERVICE);
boolean accelSupported = sensorMgr.registerListener(this,
SENSOR_ACCELEROMETER,
SENSOR_DELAY_GAME);
if (!accelSupported) {
// on accelerometer on this device
sensorMgr.unregisterListener(this, SENSOR_ACCELEROMETER);
// TODO show an error
}
// NOTE 1: you cannot get system services before onCreate()
// NOTE 2: AndroidManifest.xml must contain this line:
// <uses-permission android:name="android.permission.VIBRATE"/>
Vibrator vibrator = (Vibrator) getSystemService(Activity.VIBRATOR_SERVICE);
for (int i = 0; i < Totalcircles; i++) {
model[i].setVibrator(vibrator);
}
}
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
for (int i = 0; i < Totalcircles; i++) {
model[i].setSize(width, height);
}
}
public void surfaceCreated(SurfaceHolder holder) {
gameLoop = new GameLoop();
gameLoop.start();
}
private void draw() {
// thread safety - the SurfaceView could go away while we are drawing
Canvas c = null;
try {
// NOTE: in the LunarLander they don't have any synchronization here,
// so I guess this is OK. It will return null if the holder is not ready
c = holder.lockCanvas();
// this needs to synchronize on something
if (c != null) {
doDraw(c);
}
} finally {
if (c != null) {
holder.unlockCanvasAndPost(c);
}
}
}
private void doDraw(Canvas c) {
int width = c.getWidth();
int height = c.getHeight();
c.drawRect(0, 0, width, height, backgroundPaint);
///
float ballX[]=new float[50], ballY[]=new float[50];
for (int i = 0; i < Totalcircles; i++) {
synchronized (model[i].LOCK) {
ballX[i] = model[i].ballPixelX;
ballY[i] = model[i].ballPixelY;
}
}
//
for (int i = 0; i < Totalcircles; i++) {
c.drawCircle(ballX[i], ballY[i], BALL_RADIUS, ballPaint);
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
try {
for (int i = 0; i < Totalcircles; i++) {
model[i].setSize(0,0);
}
gameLoop.safeStop();
} finally {
gameLoop = null;
}
}
private class GameLoop extends Thread {
private volatile boolean running = true;
public void run() {
while (running) {
try {
// don't like this hardcoding
TimeUnit.MILLISECONDS.sleep(5);
draw();
for (int i = 0; i < Totalcircles; i++) {
model[i].updatePhysics();
}
} catch (InterruptedException ie) {
running = false;
}
}
}
public void safeStop() {
running = false;
interrupt();
}
}
public void onAccuracyChanged(int sensor, int accuracy) {
}
public void onSensorChanged(int sensor, float[] values) {
if (sensor == SENSOR_ACCELEROMETER) {
long curTime = System.currentTimeMillis();
// only allow one update every 50ms, otherwise updates
// come way too fast
if (lastSensorUpdate == -1 || (curTime - lastSensorUpdate) > 50) {
lastSensorUpdate = curTime;
for (int i = 0; i < Totalcircles; i++) {
model[i].setAccel(values[DATA_X], values[DATA_Y]);
}
}
}
}
}
model.java
package com.stuffthathappens.games;
import java.util.concurrent.atomic.AtomicReference;
import android.os.Vibrator;
/**
* This data model tracks the width and height of the playing field along
* with the current position of a ball.
*/
public class BouncingBallModel {
// the ball speed is meters / second. When we draw to the screen,
// 1 pixel represents 1 meter. That ends up too slow, so multiply
// by this number. Bigger numbers speeds things up.
private final float pixelsPerMeter = 10;
private final int ballRadius;
// these are public, so make sure you synchronize on LOCK
// when reading these. I made them public since you need to
// get both X and Y in pairs, and this is more efficient than
// getter methods. With two getters, you'd still need to
// synchronize.
public float ballPixelX, ballPixelY;
private int pixelWidth, pixelHeight;
// values are in meters/second
private float velocityX, velocityY;
// typical values range from -10...10, but could be higher or lower if
// the user moves the phone rapidly
private float accelX, accelY;
/**
* When the ball hits an edge, multiply the velocity by the rebound.
* A value of 1.0 means the ball bounces with 100% efficiency. Lower
* numbers simulate balls that don't bounce very much.
*/
private static final float rebound = 0.8f;
// if the ball bounces and the velocity is less than this constant,
// stop bouncing.
private static final float STOP_BOUNCING_VELOCITY = 2f;
private volatile long lastTimeMs = -1;
public final Object LOCK = new Object();
private AtomicReference<Vibrator> vibratorRef =
new AtomicReference<Vibrator>();
public BouncingBallModel(int ballRadius) {
this.ballRadius = ballRadius;
}
public void setAccel(float ax, float ay) {
synchronized (LOCK) {
this.accelX = ax;
this.accelY = ay;
}
}
public void setSize(int width, int height) {
synchronized (LOCK) {
this.pixelWidth = width;
this.pixelHeight = height;
}
}
public int getBallRadius() {
return ballRadius;
}
/**
* Call this to move the ball to a particular location on the screen. This
* resets the velocity to zero, but the acceleration doesn't change so
* the ball should start falling shortly.
*/
public void moveBall(int ballX, int ballY) {
synchronized (LOCK) {
this.ballPixelX = ballX;
this.ballPixelY = ballY;
velocityX = 0;
velocityY = 0;
}
}
public void updatePhysics() {
// copy everything to local vars (hence the 'l' prefix)
float lWidth, lHeight, lBallX, lBallY, lAx, lAy, lVx, lVy;
synchronized (LOCK) {
lWidth = pixelWidth;
lHeight = pixelHeight;
lBallX = ballPixelX;
lBallY = ballPixelY;
lVx = velocityX;
lVy = velocityY;
lAx = accelX;
lAy = -accelY;
}
if (lWidth <= 0 || lHeight <= 0) {
// invalid width and height, nothing to do until the GUI comes up
return;
}
long curTime = System.currentTimeMillis();
if (lastTimeMs < 0) {
lastTimeMs = curTime;
return;
}
long elapsedMs = curTime - lastTimeMs;
lastTimeMs = curTime;
// update the velocity
// (divide by 1000 to convert ms to seconds)
// end result is meters / second
lVx += ((elapsedMs * lAx) / 1000) * pixelsPerMeter;
lVy += ((elapsedMs * lAy) / 1000) * pixelsPerMeter;
// update the position
// (velocity is meters/sec, so divide by 1000 again)
lBallX += ((lVx * elapsedMs) / 1000) * pixelsPerMeter;
lBallY += ((lVy * elapsedMs) / 1000) * pixelsPerMeter;
boolean bouncedX = false;
boolean bouncedY = false;
if (lBallY - ballRadius < 0) {
lBallY = ballRadius;
lVy = -lVy * rebound;
bouncedY = true;
} else if (lBallY + ballRadius > lHeight) {
lBallY = lHeight - ballRadius;
lVy = -lVy * rebound;
bouncedY = true;
}
if (bouncedY && Math.abs(lVy) < STOP_BOUNCING_VELOCITY) {
lVy = 0;
bouncedY = false;
}
if (lBallX - ballRadius < 0) {
lBallX = ballRadius;
lVx = -lVx * rebound;
bouncedX = true;
} else if (lBallX + ballRadius > lWidth) {
lBallX = lWidth - ballRadius;
lVx = -lVx * rebound;
bouncedX = true;
}
if (bouncedX && Math.abs(lVx) < STOP_BOUNCING_VELOCITY) {
lVx = 0;
bouncedX = false;
}
// safely copy local vars back to object fields
synchronized (LOCK) {
ballPixelX = lBallX;
ballPixelY = lBallY;
velocityX = lVx;
velocityY = lVy;
}
if (bouncedX || bouncedY) {
Vibrator v = vibratorRef.get();
if (v != null) {
v.vibrate(20L);
}
}
}
public void setVibrator(Vibrator v) {
vibratorRef.set(v);
}
}
Logcat error:
FATAL EXCEPTION: main
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.stuffthathappens.games/com.stuffthathappens.games.BouncingBallActivity}: java.lang.NullPointerException
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2194)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2229)
at android.app.ActivityThread.access$600(ActivityThread.java:139)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1261)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:4945)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.NullPointerException
at com.stuffthathappens.games.BouncingBallActivity.onCreate(BouncingBallActivity.java:52)
at android.app.Activity.performCreate(Activity.java:4531)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1071)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2150)
You can declare you array like this:
private BouncingBallModel[] model = new BouncingBallModel[50];
like the following
How do I declare and initialize an array in Java?
I'm developing a game which includes sprites.
currently I'm loading a bitmap and using Rectangle to get the right frame from the bitmap.
the problem is loading bitmaps takes too much memory and I wont be able to load several sprites at the same time.
what are my alternatives for doing sprite in Android?
Try this one:
import org.cocos2d.layers.CCLayer;
public class GameLayer extends CCLayer{
CCSprite mSprite;
protected GameLayer() {
super();
CGSize winSize = CCDirector.sharedDirector().winSize();
mSprite = new CCSprite("image.png");
mSprite.setPosition(CGPoint.ccp(mSprite.getContentSize().width/2.0f, mSprite.getContentSize().height/2.0f));
addChild(mSprite);
}
/* It is Sprite class */
import android.graphics.*;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
public class Sprite {
int x;
private int y;
private boolean visibility = true;
private Bitmap sprite;
private int verticalFrame,horizontalFrame;
private int frameWidth,frameHeight;
private int sequence[] = new int[1];
private int maxFrame = 0;
private int currentFrame;
private int color;
private Rect src;
private Rect dest;
private int frameCount;
private Paint p = new Paint();
private int spInitX,spInitY;
private int rotate = 0;
private float currentRotateAngle = 0;
//private Graphics g;
public float velocityY;
public float velocityX;
public int height;
public Sprite(Bitmap sprite){
this.sprite = sprite;
this.frameWidth = sprite.getWidth();
this.frameHeight = sprite.getHeight();
setFrameCount();
}
public Sprite(Bitmap sprite,int frameWidth,int frameHeight){
this.sprite = sprite;
this.frameWidth = frameWidth;
this.frameHeight = frameHeight;
setFrameCount();
}
public void rotate(float angle){
currentRotateAngle = angle;
}
public void setImage(Bitmap bm,int frameWidth,int frameHeight){
this.sprite = bm;
this.frameWidth = frameWidth;
this.frameHeight = frameHeight;
}
public Bitmap getBitmap(){
return sprite;
}
public void paint(Canvas canvas){
dest.offsetTo(getX(), getY());
// g.drawImage(sprite, x, y,src.left,src.top,frameWidth,frameHeight);
canvas.drawBitmap(sprite, src, dest, null);
}
public int getMaxFrame(){
return maxFrame;
}
public int getFrameSequenceLength(){
return sequence.length;
}
public void setFrameSequence(int seq[]){
sequence = seq;
}
public void previousFrame(){
if(sequence.length > 1){
if(frameCount > 0){
setFrame(sequence[frameCount]);
frameCount--;
}else{
frameCount = sequence.length - 1;
setFrame(sequence[frameCount]);
}
}else{
setFrame(frameCount);
if(frameCount > 0){
frameCount++;
}else{
frameCount = maxFrame - 1;
}
}
}
public void setPixel(int x,int y){
spInitX = x;
spInitY = y;
}
public void nextFrame(){
if(sequence.length > 1){
if(frameCount < sequence.length){
setFrame(sequence[frameCount]);
frameCount++;
}else{
frameCount = 0;
setFrame(sequence[frameCount]);
}
}else{
setFrame(frameCount);
if(frameCount < maxFrame){
frameCount++;
}else{
frameCount = 0;
}
}
}
public int getFrame(){
return currentFrame;
}
public void setPosition(int x,int y){
this.x = x;
this.y = y;
}
public void setFrameCount(){
verticalFrame = sprite.getHeight() / frameHeight;
horizontalFrame = sprite.getWidth() / frameWidth;
src = new Rect(0,0,frameWidth,frameHeight);
dest = new Rect(0,0,frameWidth,frameHeight);
maxFrame = verticalFrame * horizontalFrame;
}
public void setFrame(int frame){
if(frame < maxFrame){
currentFrame = frame;
}
int hf = currentFrame % horizontalFrame;
int vf = currentFrame / horizontalFrame;
src.left = hf * frameWidth;
src.right = src.left + frameWidth;
src.top = vf * frameHeight;
src.bottom = src.top + frameHeight;
}
public boolean collidesWith(Sprite sp,boolean cl){
int maxHGap = (getWidth() + sp.getWidth())/2;
int maxVGap = (getHeight() + sp.getHeight())/2;
int x = getX() + getWidth()/2;
int y = getY() + getHeight()/2;
int x1 = sp.getX() + sp.getWidth()/2;
int y1 = sp.getY() + sp.getHeight()/2;
if(Math.abs(x - x1) < maxHGap && Math.abs(y - y1) < maxVGap){
return true;
}
return false;
}
public void setVisible(boolean v){
visibility = v;
}
public final boolean isVisible(){
return visibility;
}
public int getX(){
return x;
}
public int getY(){
return y;
}
public void setX(int x) {
this.x = x;
}
public void setY(int y) {
this.y = y;
}
public void move(int moveX,int moveY){
setX(getX()+moveX);
setY(getY()+moveY);
//this.y+=y;
//this.x+=x;
}
public final int getWidth(){
return frameWidth;
}
public final int getHeight(){
return frameHeight;
}
public void setEventY(int i) {
// TODO Auto-generated method stub
}
public int getEventY() {
// TODO Auto-generated method stub
return 0;
}
}
/*Create Main Thread Class Also */
import java.text.DecimalFormat;
import android.graphics.Canvas;
import android.util.Log;
import android.view.SurfaceHolder;
public class MainThread extends Thread {
boolean isPaused;
private static final String TAG = MainThread.class.getSimpleName();
// desired fps
private final static int MAX_FPS = 50;
// maximum number of frames to be skipped
private final static int MAX_FRAME_SKIPS = 5;
// the frame period
private final static int FRAME_PERIOD = 1000 / MAX_FPS;
/* Stuff for stats */
private DecimalFormat df = new DecimalFormat("0.##"); // 2 dp
// we'll be reading the stats every second
private final static int STAT_INTERVAL = 1000; // ms
// the average will be calculated by storing
// the last n FPSs
private final static int FPS_HISTORY_NR = 10;
// last time the status was stored
private long lastStatusStore = 0;
// the status time counter
private long statusIntervalTimer = 0l;
// number of frames skipped since the game started
private long totalFramesSkipped = 0l;
// number of frames skipped in a store cycle (1 sec)
private long framesSkippedPerStatCycle = 0l;
// number of rendered frames in an interval
private int frameCountPerStatCycle = 0;
private long totalFrameCount = 0l;
// the last FPS values
private double fpsStore[];
// the number of times the stat has been read
private long statsCount = 0;
// the average FPS since the game started
private double averageFps = 0.0;
// Surface holder that can access the physical surface
private SurfaceHolder surfaceHolder;
// The actual view that handles inputs
// and draws to the surface
private GameView gv;
// flag to hold game state
private boolean running;
public void setRunning(boolean running) {
this.running = running;
}
public MainThread(SurfaceHolder surfaceHolder, GameView gv) {
super();
this.surfaceHolder = surfaceHolder;
this.gv = gv;
}
public MainThread(Setting setting) {
// TODO Auto-generated constructor stub
}
public void setPause(int i) {
synchronized (gv.getHolder()) {
if (i == 0) {
isPaused = false;
}
if (i == 1) {
isPaused = true;
}
}
}
#Override
public void run() {
Canvas canvas;
Log.d(TAG, "Starting game loop");
initTimingElements();
long beginTime; // the time when the cycle begun
long timeDiff; // the time it took for the cycle to execute
int sleepTime; // ms to sleep (<0 if we're behind)
int framesSkipped; // number of frames being skipped
sleepTime = 0;
while (running) {
canvas = null;
// try locking the canvas for exclusive pixel editing
// in the surface
try {
canvas = this.surfaceHolder.lockCanvas();
synchronized (surfaceHolder) {
beginTime = System.currentTimeMillis();
framesSkipped = 0; // resetting the frames skipped
// update game state
this.gv.update();
// render state to the screen
// draws the canvas on the panel
this.gv.render(canvas);
// calculate how long did the cycle take
timeDiff = System.currentTimeMillis() - beginTime;
// calculate sleep time
sleepTime = (int) (FRAME_PERIOD - timeDiff);
if (sleepTime > 0) {
// if sleepTime > 0 we're OK
try {
// send the thread to sleep for a short period
// very useful for battery saving
Thread.sleep(sleepTime);
} catch (InterruptedException e) {
}
}
while (sleepTime < 0 && framesSkipped < MAX_FRAME_SKIPS) {
// we need to catch up
this.gv.update(); // update without rendering
sleepTime += FRAME_PERIOD; // add frame period to check
// if in next frame
framesSkipped++;
}
if (framesSkipped > 0) {
Log.d(TAG, "Skipped:" + framesSkipped);
}
// for statistics
framesSkippedPerStatCycle += framesSkipped;
// calling the routine to store the gathered statistics
storeStats();
}
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} finally {
// in case of an exception the surface is not left in
// an inconsistent state
if (canvas != null) {
surfaceHolder.unlockCanvasAndPost(canvas);
}
} // end finally
}
}
private void storeStats() {
frameCountPerStatCycle++;
totalFrameCount++;
// assuming that the sleep works each call to storeStats
// happens at 1000/FPS so we just add it up
// statusIntervalTimer += FRAME_PERIOD;
// check the actual time
statusIntervalTimer += (System.currentTimeMillis() - statusIntervalTimer);
if (statusIntervalTimer >= lastStatusStore + STAT_INTERVAL) {
// calculate the actual frames pers status check interval
double actualFps = (double) (frameCountPerStatCycle / (STAT_INTERVAL / 1000));
// stores the latest fps in the array
fpsStore[(int) statsCount % FPS_HISTORY_NR] = actualFps;
// increase the number of times statistics was calculated
statsCount++;
double totalFps = 0.0;
// sum up the stored fps values
for (int i = 0; i < FPS_HISTORY_NR; i++) {
totalFps += fpsStore[i];
}
// obtain the average
if (statsCount < FPS_HISTORY_NR) {
// in case of the first 10 triggers
averageFps = totalFps / statsCount;
} else {
averageFps = totalFps / FPS_HISTORY_NR;
}
// saving the number of total frames skipped
totalFramesSkipped += framesSkippedPerStatCycle;
// resetting the counters after a status record (1 sec)
framesSkippedPerStatCycle = 0;
statusIntervalTimer = 0;
frameCountPerStatCycle = 0;
statusIntervalTimer = System.currentTimeMillis();
lastStatusStore = statusIntervalTimer;
// Log.d(TAG, "Average FPS:" + df.format(averageFps));
gv.setAvgFps("FPS: " + df.format(averageFps));
}
}
private void initTimingElements() {
// initialise timing elements
fpsStore = new double[FPS_HISTORY_NR];
for (int i = 0; i < FPS_HISTORY_NR; i++) {
fpsStore[i] = 0.0;
}
Log.d(TAG + ".initTimingElements()",
"Timing elements for stats initialised");
}
}