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");
}
}
Related
Due to the power consuming GPS data, I would like to calculate the device speed with only the accelerometer x,y and z data. I have read a lot of questions about this topic and I tried many set-ups to find a satisfactory solution to calculate the speed when my device is in my car.
It seems so simple but nothing works, which drives me crazy.
Been trying the Sensor.TYPE_LINEAR_ACCELERATION and the Sensor.TYPE_ACCELEROMETER with removed gravity. Tried a Low Pass Filter on the Linear acceleration data. Unfortunately all with no succes.
Looks like the calculated speed is correct but testing in my car the calculated speed doesn't get higher then about 2 m/s.
below a code snip
mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION);
public void onSensorChanged(SensorEvent event) {
if (event.sensor == mAccelerometer) {
if (timestamp != 0) {
final float dT = (event.timestamp - timestamp) * NS2S;
lax = event.values[0];
lay = event.values[1];
laz = event.values[2];
vx = vxo + lax * dT ;
vy = vyo + lay * dT ;
vz = vzo + laz * dT ;
speed = (float) (Math.sqrt(vx*vx + vy*vy + vz*vz)) ;
if (speed < 0.01) {speed = 0 ; }
tv_speed.setText(String.valueOf(speed));
}
timestamp = event.timestamp;
}
}
Hope someone can help, thanks a lot.
It's possible to compute distance and speed using only accelerometer, but with three conditions:
1. Linear movement - trajectory must be straight.
2. Slope of the road must be constant.
3. You must perform calibration procedure before start.
Where can you use this method with such restrictions - it's up to you... Now, how to do it:
We need something, implementing SensorEventListener interface. For the future use, let's add following abstract class:
public abstract class Accelerometer implements SensorEventListener {
protected float lastX;
protected float lastY;
protected float lastZ;
public abstract Point getPoint();
public void onAccuracyChanged(Sensor arg0, int arg1) {
}
}
and this will be our SensorEventListener:
public class XYZAccelerometer extends Accelerometer {
private static final int BUFFER_SIZE = 500;
// calibration
private float dX = 0;
private float dY = 0;
private float dZ = 0;
// buffer variables
private float X;
private float Y;
private float Z;
private int cnt = 0;
// returns last SenorEvent parameters
public Point getLastPoint(){
return new Point(lastX, lastY, lastZ, 1);
}
// returrns parameters, using buffer: average acceleration
// since last call of getPoint().
public Point getPoint(){
if (cnt == 0){
return new Point(lastX, lastY, lastZ, 1);
}
Point p = new Point(X, Y, Z, cnt);
reset();
return p;
}
// resets buffer
public void reset(){
cnt = 0;
X = 0;
Y = 0;
Z = 0;
}
public void onSensorChanged(SensorEvent se) {
float x = se.values[SensorManager.DATA_X] + dX;
float y = se.values[SensorManager.DATA_Y] + dY;
float z = se.values[SensorManager.DATA_Z] + dZ;
lastX = x;
lastY = y;
lastZ = z;
X+= x;
Y+= y;
Z+= z;
if (cnt < BUFFER_SIZE-1) {
cnt++;
} else
{
reset();
}
}
public int getCnt(){
return cnt;
}
public void setdX(float dX) {
this.dX = dX;
}
public void setdY(float dY) {
this.dY = dY;
}
public void setdZ(float dZ) {
this.dZ = dZ;
}
}
Calibrating accelerometer must be called before each experiment. Phone orientation must not be changed while measuring.
To calibrate accelerometer, i use this class:
public class Calibrator {
final static int UPDATE_INTERVAL = 400;
final static int ITERATIONS = 5;
Handler hRefresh;
XYZAccelerometer acc;
int eventNumber;
private LinkedList calData;
public Calibrator(Handler hRefresh, XYZAccelerometer acc, int eventNumber) {
this.hRefresh = hRefresh;
this.acc = acc;
this.eventNumber = eventNumber;
}
public void calibrate() {
final Timer calTimer = new Timer();
calData = new LinkedList();
acc.setdX(0);
acc.setdY(0);
acc.setdZ(0);
calTimer.scheduleAtFixedRate(
new TimerTask() {
public void run() {
addCalData(calData);
if (calData.size() > ITERATIONS) {
calTimer.cancel();
try {
calSensor(calData);
} catch (Exception ex) {
try {
throw ex;
} catch (Exception ex1) {
hRefresh.sendEmptyMessage(5);
}
}
hRefresh.sendEmptyMessage(eventNumber);
}
}
},
0,
UPDATE_INTERVAL);
}
private void addCalData(LinkedList cD) {
Point p = acc.getPoint();
cD.add(p);
acc.reset();
}
private void calSensor(LinkedList cD) throws Exception {
if (cD.size() < ITERATIONS-1) {
throw new Exception("not enough data to calibrate");
}
float x = 0;
float y = 0;
float z = 0;
// Don't use first measure
for (int i = 1; i < cD.size(); ++i) {
x += cD.get(i).getX();
y += cD.get(i).getY();
z += cD.get(i).getZ();
}
x = x / (cD.size() - 1);
y = y / (cD.size() - 1);
z = z / (cD.size() - 1);
acc.setdX(-x);
acc.setdY(-y);
acc.setdZ(-z);
}
}
maintenance class to keep data of one measure
public class Point {
private float x = 0;
private float y = 0;
private float z = 0;
private int cnt = 1;
public float getX() {
return x/(float)cnt;
}
public float getY() {
return y/(float)cnt;
}
public float getZ() {
return z/(float)cnt;
}
public Point(float x, float y, float z, int cnt) {
this.x = x;
this.y = y;
this.z = z;
this.cnt = cnt;
}
public float getForce(){
return getX()*getX()+getY()*getY()+getZ()*getZ();
}
}
And class to process data of measure
public class MeasurePoint {
private float x;
private float y;
private float z;
private float speedBefore;
private float speedAfter;
private float distance;
private float acceleration;
private long interval;
private Point averagePoint;
public MeasurePoint(float x, float y, float z, float speedBefore, long interval, Point averagePoint) {
this.x = x;
this.y = y;
this.z = z;
this.speedBefore = speedBefore;
this.interval = interval;
this.averagePoint = averagePoint;
speedAfter = 0;
calc();
}
private void calc(){
//Acceleration as projection of current vector on average
acceleration = this.x*averagePoint.getX() +
this.y*averagePoint.getY() +
this.z*averagePoint.getZ();
acceleration = acceleration / ((float)Math.sqrt(averagePoint.getForce()));
float t = ((float)interval / 1000f);
speedAfter = speedBefore + acceleration * t;
distance = speedBefore*t + acceleration*t*t/2;
}
public String getStoreString(){
String s = "write here whatever you want";
return s;
}
// add getters
}
This one - to store and save data array
public class MeasureData {
// points from accelerometr
private LinkedList accData;
private LinkedList data;
// timer interval of generating points
private long interval;
public MeasureData(long interval) {
this.interval = interval;
accData = new LinkedList ();
data = new LinkedList ();
}
public void addPoint(Point p){
accData.add(p);
}
public void process(){
for(int i = 0; i < accData.size(); ++i){
Point p = accData.get(i);
float speed = 0;
if(i > 0){
speed = data.get(i-1).getSpeedAfter();
}
data.add(new MeasurePoint(p.getX(), p.getY(), p.getZ(), speed, interval, getAveragePoint()));
}
}
public boolean saveExt(Context con, String fname) throws Throwable {
try {
File file = new File(con.getExternalFilesDir(null), fname);
FileOutputStream os = new FileOutputStream(file);
OutputStreamWriter out = new OutputStreamWriter(os);
for (int i = 0; i < data.size(); ++i) {
MeasurePoint m = data.get(i);
out.write(m.getStoreString());
}
out.close();
} catch (Throwable t) {
throw (t);
}
return true;
}
private Point getAveragePoint() {
float x = 0;
float y = 0;
float z = 0;
for(int i = 0; i < accData.size(); ++i){
Point p = accData.get(i);
x += p.getX();
y += p.getY();
z += p.getZ();
}
return new Point(x, y, z, 1);
}
public float getLastSpeed(){
return data.getLast().getSpeedAfter();
}
public float getLastSpeedKm(){
float ms = getLastSpeed();
return ms*3.6f;
}
}
And, finally, how to use all this in your activity(I cleaned it up a lot, sorry if it will not complie - fill free to write it in comments:
public class TestActivity extends Activity {
static final int TIMER_DONE = 2;
static final int START = 3;
static final int CAL_TIMER_DONE = 4;
static final int ERROR = 5;
private StartCatcher mStartListener;
private XYZAccelerometer xyzAcc;
private SensorManager mSensorManager;
private static final long UPDATE_INTERVAL = 500;
private static final long MEASURE_TIMES = 20;
private Timer timer;
private TextView tv;
private Button testBtn;
int counter;
private MeasureData mdXYZ;
/** handler for async events*/
Handler hRefresh = new Handler() {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case TIMER_DONE:
onMeasureDone();
String es1 = Float.toString(Math.round(mdXYZ.getLastSpeedKm()*100)/100f);
tv.append(" END SPEED " + es1 + " " + es2 + " \n");
enableButtons();
break;
case START:
tv.append(" START");
timer = new Timer();
timer.scheduleAtFixedRate(
new TimerTask() {
public void run() {
dumpSensor();
}
},
0,
UPDATE_INTERVAL);
break;
case ERROR:
Toast.makeText(getApplicationContext(), "ERROR", Toast.LENGTH_SHORT).show();
break;
}
}
};
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
tv = (TextView) findViewById(R.id.txt);
testBtn = (Button) findViewById(R.id.btn);
}
#Override
protected void onResume() {
super.onResume();
tv.append("\n ..");
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
setAccelerometer();
setStartCatcher();
mSensorManager.registerListener(xyzAcc,
mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
SensorManager.SENSOR_DELAY_GAME);
}
#Override
protected void onPause() {
mSensorManager.unregisterListener(xyzAcc);
super.onPause();
}
public void onButtonTest(View v) {
disableButtons();
mdXYZ = new MeasureData(UPDATE_INTERVAL);
counter = 0;
tv.setText("");
tv.append("Calibrating");
Calibrator cal = new Calibrator(hRefresh, xyzAcc, START);
cal.calibrate();
}
void dumpSensor() {
++counter;
mdXYZ.addPoint(xyzAcc.getPoint());
hRefresh.sendEmptyMessage(TICK);
if (counter > MEASURE_TIMES) {
timer.cancel();
hRefresh.sendEmptyMessage(TIMER_DONE);
}
}
private void enableButtons() {
testBtn.setEnabled(true);
}
private void setAccelerometer() {
xyzAcc = new XYZAccelerometer();
mSensorManager.registerListener(xyzAcc,
mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
SensorManager.SENSOR_DELAY_UI);
}
private void disableButtons() {
testBtn.setEnabled(false);
}
private void onMeasureDone() {
try {
mdXYZ.process();
long now = System.currentTimeMillis();
mdXYZ.saveExt(this, Long.toString(now) + ".csv");
} catch (Throwable ex) {
Toast.makeText(this, ex.getMessage().toString(), Toast.LENGTH_SHORT);
}
}
}
<serviceLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<serviceButton
android:id="#+id/btn"
android:text="TEST"
android:layout_width="300px"
android:layout_height="200px"
android:onClick="onButtonTest" />
<serviceTextView
android:id = "#+id/txt"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text=":"
/>
<service/LinearLayout>
Although at the developer.android.com site it is stated clearly that
you could use the linear accelerometer to see how fast your car is going"
But I did not find anything (in testing or in examples or code) that showed this is really true.
Now, unfortunately, I am convinced that it is not possible to calculate the speed of a car with the linear accelerometer.
Please see the below code to get the velocity using accelerometer
public class SensorTestActivity extends Activity implements SensorEventListener {
double calibration = Double.NaN;
private SensorManager sensorManager;
private boolean color = false;
private TextView view;
private long lastUpdate;
float appliedAcceleration = 0;
float currentAcceleration = 0;
float velocity = 0;
Date lastUpdatedate;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
view = findViewById(R.id.textView);
// view.setBackgroundColor(Color.GREEN);
lastUpdatedate = new Date(System.currentTimeMillis());
sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
lastUpdate = System.currentTimeMillis();
}
#Override
public void onSensorChanged(SensorEvent event) {
// if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
// getAccelerometer(event);
// }
double x = event.values[0];
double y = event.values[1];
double z = event.values[2];
double a = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2) + Math.pow(z, 2));
if (calibration == Double.NaN)
calibration = a;
else {
updateVelocity();
currentAcceleration = (float)a;
}
}
private void getAccelerometer(SensorEvent event) {
float[] values = event.values;
// Movement
float x = values[0];
float y = values[1];
float z = values[2];
float accelationSquareRoot = (x * x + y * y + z * z)
/ (SensorManager.GRAVITY_EARTH * SensorManager.GRAVITY_EARTH);
long actualTime = event.timestamp;
if (accelationSquareRoot >= 2) //
{
if (actualTime - lastUpdate < 200) {
return;
}
lastUpdate = actualTime;
// Toast.makeText(this, "Device was shuffed", Toast.LENGTH_SHORT)
// .show();
if (color) {
view.setBackgroundColor(Color.GREEN);
} else {
view.setBackgroundColor(Color.RED);
}
color = !color;
view.setText("SPEEDDDDD=== "+accelationSquareRoot);
// Log.i("SensorTestActivity","SPEEDDDDD=== "+accelationSquareRoot+" ");
}
}
private void updateVelocity() {
// Calculate how long this acceleration has been applied.
Date timeNow = new Date(System.currentTimeMillis());
long timeDelta = timeNow.getTime()-lastUpdatedate.getTime();
lastUpdatedate.setTime(timeNow.getTime());
// Calculate the change in velocity at the
// current acceleration since the last update.
float deltaVelocity = appliedAcceleration * (timeDelta/1000);
appliedAcceleration = currentAcceleration;
// Add the velocity change to the current velocity.
velocity += deltaVelocity;
final double mph = (Math.round(100*velocity / 1.6 * 3.6))/100;
Log.i("SensorTestActivity","SPEEDDDDD=== "+mph+" "+velocity);
}
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
#Override
protected void onResume() {
super.onResume();
// register this class as a listener for the orientation and
// accelerometer sensors
sensorManager.registerListener(this,
sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
SensorManager.SENSOR_DELAY_NORMAL);
}
#Override
protected void onPause() {
// unregister listener
super.onPause();
sensorManager.unregisterListener(this);
}
}
I am having a WaveFormView on which I want to change the color of it while playing Audio file and as the Audio is paused it should be stopped coloring at that certain point and when resumed it should continue forward with coloring. I am not getting how to do it in my code..
This is the screen shot of my generated waveform. Now when I will click on Play button it should change the color of waveform gradually with red color (from start to end slowly).
Here is my code to draw waveform view.
WaveFormView.class
public class WaveformView extends View {
public interface WaveformListener {
public void waveformFling(float x);
public void waveformDraw();
}
;
// Colors
private Paint mGridPaint;
private Paint mSelectedLinePaint;
private Paint mUnselectedLinePaint;
private Paint mUnselectedBkgndLinePaint;
private Paint mBorderLinePaint;
private Paint mPlaybackLinePaint;
private Paint mTimecodePaint;
private SoundFile mSoundFile;
private int[] mLenByZoomLevel;
private double[][] mValuesByZoomLevel;
private double[] mZoomFactorByZoomLevel;
private int[] mHeightsAtThisZoomLevel;
private int mZoomLevel;
private int mNumZoomLevels;
private int mSampleRate;
private int mSamplesPerFrame;
private int mOffset;
private int mSelectionStart;
private int mSelectionEnd;
private int mPlaybackPos;
private float mDensity;
private float mInitialScaleSpan;
private WaveformListener mListener;
private GestureDetector mGestureDetector;
private ScaleGestureDetector mScaleGestureDetector;
private boolean mInitialized;
Color color;
public WaveformView(Context context, AttributeSet attrs) {
super(context, attrs);
// We don't want keys, the markers get these
setFocusable(false);
mGridPaint = new Paint();
mGridPaint.setAntiAlias(false);
mGridPaint.setColor(
getResources().getColor(R.color.grid_line));
mSelectedLinePaint = new Paint();
mSelectedLinePaint.setAntiAlias(false);
mSelectedLinePaint.setColor(
getResources().getColor(R.color.waveform_selected));
mUnselectedLinePaint = new Paint();
mUnselectedLinePaint.setAntiAlias(false);
mUnselectedLinePaint.setColor(
getResources().getColor(R.color.waveform_unselected));
mUnselectedBkgndLinePaint = new Paint();
mUnselectedBkgndLinePaint.setAntiAlias(false);
mUnselectedBkgndLinePaint.setColor(
getResources().getColor(
R.color.selection_border));
mBorderLinePaint = new Paint();
mBorderLinePaint.setAntiAlias(true);
mBorderLinePaint.setStrokeWidth(1.5f);
mBorderLinePaint.setPathEffect(
new DashPathEffect(new float[]{3.0f, 2.0f}, 0.0f));
mBorderLinePaint.setColor(
getResources().getColor(R.color.selection_border));
mPlaybackLinePaint = new Paint();
mPlaybackLinePaint.setAntiAlias(false);
mPlaybackLinePaint.setColor(
getResources().getColor(R.color.playback_indicator));
mTimecodePaint = new Paint();
mTimecodePaint.setTextSize(12);
mTimecodePaint.setAntiAlias(true);
mTimecodePaint.setColor(
getResources().getColor(R.color.timecode));
mTimecodePaint.setShadowLayer(
2, 1, 1,
getResources().getColor(R.color.timecode_shadow));
mGestureDetector = new GestureDetector(
context,
new GestureDetector.SimpleOnGestureListener() {
public boolean onFling(
MotionEvent e1, MotionEvent e2, float vx, float vy) {
mListener.waveformFling(vx);
return true;
}
});
mSoundFile = null;
mLenByZoomLevel = null;
mValuesByZoomLevel = null;
mHeightsAtThisZoomLevel = null;
mOffset = 0;
mPlaybackPos = -1;
mSelectionStart = 0;
mSelectionEnd = 0;
mDensity = 1.0f;
mInitialized = false;
}
public boolean hasSoundFile() {
return mSoundFile != null;
}
public void setSoundFile(SoundFile soundFile) {
mSoundFile = soundFile;
mSampleRate = mSoundFile.getSampleRate();
mSamplesPerFrame = mSoundFile.getSamplesPerFrame();
computeDoublesForAllZoomLevels();
mHeightsAtThisZoomLevel = null;
}
/**
* Called once when a new sound file is added
*/
private void computeDoublesForAllZoomLevels() {
int numFrames = mSoundFile.getNumFrames();
int[] frameGains = mSoundFile.getFrameGains();
double[] smoothedGains = new double[numFrames];
if (numFrames == 1) {
smoothedGains[0] = frameGains[0];
} else if (numFrames == 2) {
smoothedGains[0] = frameGains[0];
smoothedGains[1] = frameGains[1];
} else if (numFrames > 2) {
smoothedGains[0] = (double)(
(frameGains[0] / 2.0) +
(frameGains[1] / 2.0));
for (int i = 1; i < numFrames - 1; i++) {
smoothedGains[i] = (double)(
(frameGains[i - 1] / 3.0) +
(frameGains[i ] / 3.0) +
(frameGains[i + 1] / 3.0));
}
smoothedGains[numFrames - 1] = (double)(
(frameGains[numFrames - 2] / 2.0) +
(frameGains[numFrames - 1] / 2.0));
}
// Make sure the range is no more than 0 - 255
double maxGain = 1.0;
for (int i = 0; i < numFrames; i++) {
if (smoothedGains[i] > maxGain) {
maxGain = smoothedGains[i];
}
}
double scaleFactor = 1.0;
if (maxGain > 255.0) {
scaleFactor = 255 / maxGain;
}
// Build histogram of 256 bins and figure out the new scaled max
maxGain = 0;
int gainHist[] = new int[256];
for (int i = 0; i < numFrames; i++) {
int smoothedGain = (int)(smoothedGains[i] * scaleFactor);
if (smoothedGain < 0)
smoothedGain = 0;
if (smoothedGain > 255)
smoothedGain = 255;
if (smoothedGain > maxGain)
maxGain = smoothedGain;
gainHist[smoothedGain]++;
}
// Re-calibrate the min to be 5%
double minGain = 0;
int sum = 0;
while (minGain < 255 && sum < numFrames / 20) {
sum += gainHist[(int)minGain];
minGain++;
}
// Re-calibrate the max to be 99%
sum = 0;
while (maxGain > 2 && sum < numFrames / 100) {
sum += gainHist[(int)maxGain];
maxGain--;
}
// Compute the heights
double[] heights = new double[numFrames];
double range = maxGain - minGain;
for (int i = 0; i < numFrames; i++) {
double value = (smoothedGains[i] * scaleFactor - minGain) / range;
if (value < 0.0)
value = 0.0;
if (value > 1.0)
value = 1.0;
heights[i] = value * value;
}
mNumZoomLevels = 5;
mLenByZoomLevel = new int[5];
mZoomFactorByZoomLevel = new double[5];
mValuesByZoomLevel = new double[5][];
// Level 0 is doubled, with interpolated values
mLenByZoomLevel[0] = numFrames * 2;
mZoomFactorByZoomLevel[0] = 2.0;
mValuesByZoomLevel[0] = new double[mLenByZoomLevel[0]];
if (numFrames > 0) {
mValuesByZoomLevel[0][0] = 0.5 * heights[0];
mValuesByZoomLevel[0][1] = heights[0];
}
for (int i = 1; i < numFrames; i++) {
mValuesByZoomLevel[0][2 * i] = 0.5 * (heights[i - 1] + heights[i]);
mValuesByZoomLevel[0][2 * i + 1] = heights[i];
}
// Level 1 is normal
mLenByZoomLevel[1] = numFrames;
mValuesByZoomLevel[1] = new double[mLenByZoomLevel[1]];
mZoomFactorByZoomLevel[1] = 1.0;
for (int i = 0; i < mLenByZoomLevel[1]; i++) {
mValuesByZoomLevel[1][i] = heights[i];
}
// 3 more levels are each halved
for (int j = 2; j < 5; j++) {
mLenByZoomLevel[j] = mLenByZoomLevel[j - 1] / 2;
mValuesByZoomLevel[j] = new double[mLenByZoomLevel[j]];
mZoomFactorByZoomLevel[j] = mZoomFactorByZoomLevel[j - 1] / 2.0;
for (int i = 0; i < mLenByZoomLevel[j]; i++) {
mValuesByZoomLevel[j][i] =
0.5 * (mValuesByZoomLevel[j - 1][2 * i] +
mValuesByZoomLevel[j - 1][2 * i + 1]);
}
}
if (numFrames > 5000) {
mZoomLevel = 3;
} else if (numFrames > 1000) {
mZoomLevel = 2;
} else if (numFrames > 300) {
mZoomLevel = 1;
} else {
mZoomLevel = 0;
}
mInitialized = true;
}
public boolean canZoomIn() {
return (mZoomLevel > 0);
}
public void zoomIn() {
if (canZoomIn()) {
mZoomLevel--;
mSelectionStart *= 2;
mSelectionEnd *= 2;
mHeightsAtThisZoomLevel = null;
int offsetCenter = mOffset + getMeasuredWidth() / 2;
offsetCenter *= 2;
mOffset = offsetCenter - getMeasuredWidth() / 2;
if (mOffset < 0)
mOffset = 0;
invalidate();
}
}
public boolean canZoomOut() {
return (mZoomLevel < mNumZoomLevels - 1);
}
public void zoomOut() {
if (canZoomOut()) {
mZoomLevel++;
mSelectionStart /= 2;
mSelectionEnd /= 2;
int offsetCenter = mOffset + getMeasuredWidth() / 2;
offsetCenter /= 2;
mOffset = offsetCenter - getMeasuredWidth() / 2;
if (mOffset < 0)
mOffset = 0;
mHeightsAtThisZoomLevel = null;
invalidate();
}
}
public double pixelsToSeconds(int pixels) {
double z = mZoomFactorByZoomLevel[mZoomLevel];
return (pixels * (double)mSamplesPerFrame / (mSampleRate * z));
}
public void setListener(WaveformListener listener) {
mListener = listener;
}
public void recomputeHeights(float density) {
mHeightsAtThisZoomLevel = null;
mDensity = density;
mTimecodePaint.setTextSize((int)(12 * density));
invalidate();
}
protected void drawWaveformLine(Canvas canvas,
int x, int y0, int y1,
Paint paint) {
canvas.drawLine(x, y0, x, y1, paint);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (mSoundFile == null)
return;
if (mHeightsAtThisZoomLevel == null)
computeIntsForThisZoomLevel();
DisplayMetrics displaymetrics = getContext().getResources().getDisplayMetrics();
int height = displaymetrics.heightPixels;
int widths = displaymetrics.widthPixels;
// Draw waveform
int measuredWidth = getMeasuredWidth();
int measuredHeight = getMeasuredHeight();
int start = mOffset;
int width = mHeightsAtThisZoomLevel.length - start;
int ctr = measuredHeight / 2;
Log.e("wid",String.valueOf(width));
Log.e("widCal",String.valueOf(mHeightsAtThisZoomLevel.length));
Log.e("widstart",String.valueOf(start));
if (width > measuredWidth)
width = measuredWidth;
Log.e("measured",String.valueOf(measuredWidth));
// Draw grid
double onePixelInSecs = pixelsToSeconds(1);
boolean onlyEveryFiveSecs = (onePixelInSecs > 1.0 / 50.0);
double fractionalSecs = mOffset * onePixelInSecs;
int integerSecs = (int) fractionalSecs;
int i = 0;
while (i < width) {
i++;
fractionalSecs += onePixelInSecs;
int integerSecsNew = (int) fractionalSecs;
if (integerSecsNew != integerSecs) {
integerSecs = integerSecsNew;
if (!onlyEveryFiveSecs || 0 == (integerSecs % 5)) {
canvas.drawLine(i, 0, i, measuredHeight, mGridPaint);
}
}
}
// Draw waveform
for ( i = 0; i < width; i++) {
Paint paint;
if (i + start >= mSelectionStart &&
i + start < mSelectionEnd) {
paint = mSelectedLinePaint;
// paint.setColor(color);
} else {
drawWaveformLine(canvas, ((widths/width)*i), 0, measuredHeight,
mUnselectedBkgndLinePaint);
paint = mUnselectedLinePaint;
}
drawWaveformLine(
canvas, ((widths/width)*i),
ctr - mHeightsAtThisZoomLevel[start + i],
ctr + 1 + mHeightsAtThisZoomLevel[start + i],
paint);
if (i + start == mPlaybackPos) {
canvas.drawLine(i, 0, i, measuredHeight, mPlaybackLinePaint);
}
}
if (mListener != null) {
mListener.waveformDraw();
}
}
private void computeIntsForThisZoomLevel() {
int halfHeight = (getMeasuredHeight() / 2) - 1;
mHeightsAtThisZoomLevel = new int[mLenByZoomLevel[mZoomLevel]];
for (int i = 0; i < mLenByZoomLevel[mZoomLevel]; i++) {
mHeightsAtThisZoomLevel[i] =
(int)(mValuesByZoomLevel[mZoomLevel][i] * halfHeight);
}
}
}
MainActivity.class
public class MainActivity extends AppCompatActivity implements WaveformView.WaveformListener {
WaveformView mWaveformView;
SoundFile mSoundFile;
private float mDensity;
private File mFile;
private String mFilename;
private long mLoadingLastUpdateTime;
boolean mLoadingKeepGoing;
boolean mFinishActivity;
private ProgressDialog mProgressDialog;
String mTitle,mArtist;
private Thread mLoadSoundFileThread;
private Thread mRecordAudioThread;
private Thread mSaveSoundFileThread;
private boolean mIsPlaying;
private SamplePlayer mPlayer;
private String mInfoContent;
private int mWidth;
private int mMaxPos;
private int mStartPos;
private int mEndPos;
private boolean mStartVisible;
private boolean mEndVisible;
private int mLastDisplayedStartPos;
private int mLastDisplayedEndPos;
private int mOffset;
private int mOffsetGoal;
private int mFlingVelocity;
private int mPlayStartMsec;
private int mPlayEndMsec;
private Handler mHandler;
Button pla;
MediaPlayer mediaPlayer;
boolean ismIsPlaying;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
pla = (Button)findViewById(R.id.play);
mWaveformView = (WaveformView)findViewById(R.id.waveform);
mWaveformView.setListener(this);
mHandler = new Handler();
Uri uri = Uri.parse("/sdcard/audio_file.mp3");
mediaPlayer = new MediaPlayer();
mediaPlayer = MediaPlayer.create(getApplicationContext(),uri);
loadGui();
loadFromFile();
}
/**
* Called from both onCreate and onConfigurationChanged
* (if the user switched layouts)
*/
private void loadGui() {
// Inflate our UI from its XML layout description.
setContentView(R.layout.activity_main);
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
mDensity = metrics.density;
mWaveformView = (WaveformView)findViewById(R.id.waveform);
mWaveformView.setListener(this);
if (mSoundFile != null && !mWaveformView.hasSoundFile()) {
mWaveformView.setSoundFile(mSoundFile);
mWaveformView.recomputeHeights(mDensity);
}
}
private void loadFromFile() {
mFilename = "/sdcard/audio_file.mp3";
mFile = new File(mFilename);
SongMetadataReader metadataReader = new SongMetadataReader(
this, mFilename);
mTitle = metadataReader.mTitle;
mArtist = metadataReader.mArtist;
String titleLabel = mTitle;
if (mArtist != null && mArtist.length() > 0) {
titleLabel += " - " + mArtist;
}
setTitle(titleLabel);
mLoadingLastUpdateTime = getCurrentTime();
mLoadingKeepGoing = true;
mFinishActivity = false;
mProgressDialog = new ProgressDialog(MainActivity.this);
mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
mProgressDialog.setTitle("Loading...");
mProgressDialog.setCancelable(true);
mProgressDialog.setOnCancelListener(
new DialogInterface.OnCancelListener() {
public void onCancel(DialogInterface dialog) {
mLoadingKeepGoing = false;
mFinishActivity = true;
}
});
mProgressDialog.show();
final SoundFile.ProgressListener listener =
new SoundFile.ProgressListener() {
public boolean reportProgress(double fractionComplete) {
long now = getCurrentTime();
if (now - mLoadingLastUpdateTime > 100) {
mProgressDialog.setProgress(
(int) (mProgressDialog.getMax() * fractionComplete));
mLoadingLastUpdateTime = now;
}
return mLoadingKeepGoing;
}
};
// Load the sound file in a background thread
mLoadSoundFileThread = new Thread() {
public void run() {
try {
mSoundFile = SoundFile.create(mFile.getAbsolutePath(), listener);
if (mSoundFile == null) {
mProgressDialog.dismiss();
String name = mFile.getName().toLowerCase();
String[] components = name.split("\\.");
String err;
if (components.length < 2) {
err = getResources().getString(
R.string.no_extension_error);
} else {
err = getResources().getString(
R.string.bad_extension_error) + " " +
components[components.length - 1];
}
final String finalErr = err;
Runnable runnable = new Runnable() {
public void run() {
showFinalAlert(new Exception(), finalErr);
}
};
mHandler.post(runnable);
return;
}
mPlayer = new SamplePlayer(mSoundFile);
} catch (final Exception e) {
mProgressDialog.dismiss();
e.printStackTrace();
mInfoContent = e.toString();
runOnUiThread(new Runnable() {
public void run() {
}
});
Runnable runnable = new Runnable() {
public void run() {
showFinalAlert(e, getResources().getText(R.string.read_error));
}
};
mHandler.post(runnable);
return;
}
mProgressDialog.dismiss();
if (mLoadingKeepGoing) {
Runnable runnable = new Runnable() {
public void run() {
finishOpeningSoundFile();
}
};
mHandler.post(runnable);
} else if (mFinishActivity){
MainActivity.this.finish();
}
}
};
mLoadSoundFileThread.start();
}
private void finishOpeningSoundFile() {
mWaveformView.setSoundFile(mSoundFile);
mWaveformView.recomputeHeights(mDensity);
Log.e("sound file",mFilename);
Log.e("sound", String.valueOf(mSoundFile));
}
/**
* Show a "final" alert dialog that will exit the activity
* after the user clicks on the OK button. If an exception
* is passed, it's assumed to be an error condition, and the
* dialog is presented as an error, and the stack trace is
* logged. If there's no exception, it's a success message.
*/
private void showFinalAlert(Exception e, CharSequence message) {
CharSequence title;
if (e != null) {
Log.e("Ringdroid", "Error: " + message);
Log.e("Ringdroid", getStackTrace(e));
title = getResources().getText(R.string.alert_title_failure);
setResult(RESULT_CANCELED, new Intent());
} else {
Log.v("Ringdroid", "Success: " + message);
title = getResources().getText(R.string.alert_title_success);
}
new AlertDialog.Builder(MainActivity.this)
.setTitle(title)
.setMessage(message)
.setPositiveButton(
R.string.alert_ok_button,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,
int whichButton) {
finish();
}
})
.setCancelable(false)
.show();
}
private void showFinalAlert(Exception e, int messageResourceId) {
showFinalAlert(e, getResources().getText(messageResourceId));
}
#Override
public void waveformTouchStart(float x) {
}
#Override
public void waveformTouchMove(float x) {
}
#Override
public void waveformTouchEnd() {
}
#Override
public void waveformFling(float x) {
}
#Override
public void waveformDraw() {
mWidth = mWaveformView.getMeasuredWidth();
if (mOffsetGoal != mOffset) {
// updateDisplay();
}
else if (mIsPlaying) {
// updateDisplay();
} else if (mFlingVelocity != 0) {
// updateDisplay();
}
}
private long getCurrentTime() {
return System.nanoTime() / 1000000;
}
private String getStackTrace(Exception e) {
StringWriter writer = new StringWriter();
e.printStackTrace(new PrintWriter(writer));
return writer.toString();
}
public void buttonClick(View view) {
Toast.makeText(MainActivity.this, "test", Toast.LENGTH_SHORT).show();
mediaPlayer.start();
ismIsPlaying = true;
}
}
In your onDraw(Canvas canvas) add the following lines
if (i + start <= mPlaybackPos) {
Paint mPaint = new Paint(paint);
mPaint.setColor(Color.RED);
drawWaveformLine(
canvas, ((widths/width)*i),
ctr - mHeightsAtThisZoomLevel[start + i],
ctr + 1 + mHeightsAtThisZoomLevel[start + i],
mPaint);
}
add them above the line:
if (i + start == mPlaybackPos) {
And if this works, consider to allocate the Paint-object outside the onDraw() method.
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?
guys. I'm playing around with making my very first Android game, but stumbled into a problem. The framerate seems to have random lag spikes. If I comment the background(s) out the framerate gets much smoother. I've looked around SO and can't find anything to solve my problems. I have a feeling it has something to do with allocating a specific amount of time every time I draw, but I don't know how to properly implement such a feature. Any suggestions? Btw, tryed hardware ac, anti etc.
This is the class that starts the surfaceview :
package com.example.glassrunner;
Imports Here
public class Game extends Activity
{
MySurfaceView mySurfaceView;
public SoundPool spool;
private int soundID;
int length=0;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
this.setVolumeControlStream(AudioManager.STREAM_MUSIC);
mySurfaceView = new MySurfaceView(this);
setContentView(mySurfaceView);
}
#Override
protected void onResume()
{
// TODO Auto-generated method stub
super.onResume();
mySurfaceView.onResumeMySurfaceView();
}
#Override
protected void onPause()
{
// TODO Auto-generated method stub
super.onPause();
mySurfaceView.onPauseMySurfaceView();
}
#Override
protected void onDestroy()
{
super.onDestroy();
mySurfaceView = null;
}
}
This is the surfaceview class :
package com.example.glassrunner;
Imports here
public class MySurfaceView extends SurfaceView implements Runnable
{
public static boolean gameOver = false;
SurfaceHolder surfaceHolder;
Thread thread = null;
public Integer score=0;
public SoundPool spool;
private int soundID;
int length=0;
public static MediaPlayer mp;
volatile boolean running = false;
int Yposition = 450;
int Xposition = 50;
Paint textPaint;
long mLastTime;
Bitmap background;
Bitmap background2;
Bitmap lines;
Bitmap runSprite;
Bitmap box;
Paint bitmapPaint ;
Paint textPaint2;
Bitmap scaledBackground ;
Bitmap scaledBackground2 ;
Bitmap scaledLines ;
Bitmap scaledBox;
Canvas canvas;
Paint paint;
int SpX=0;
int SpY=0;
Bitmap[][] sprite;
/** Variables for the counter */
int frameSamplesCollected = 0;
int frameSampleTime = 0;
int fps = 0;
int speed = 5;
Toast GameOverToast;
Context context;
MediaPlayer mMediaPlayer;
public MySurfaceView(Context context)
{
super(context);
this.context = context;
// TODO Auto-generated constructor stub
surfaceHolder = getHolder();
surfaceHolder.setFormat(PixelFormat.RGB_565);
CharSequence text = "Game Over!";
int duration = Toast.LENGTH_SHORT;
GameOverToast = Toast.makeText(context, text, duration);
spool = new SoundPool(10, AudioManager.STREAM_MUSIC, 0);
soundID = spool.load(context, R.raw.jump, 1);
mp = MediaPlayer.create(context, R.raw.saturdaymorningfunk);
initialization();
}
public void initialization()
{
mp.setLooping(true);
mp.start();
Options options = new Options();
options.inSampleSize = 1/4;
options.inPreferredConfig = Bitmap.Config.RGB_565;
background=BitmapFactory.decodeResource(getResources(),R.drawable.background,options);
lines=BitmapFactory.decodeResource(getResources(),R.drawable.lines);// getting the png from drawable folder
background2=BitmapFactory.decodeResource(getResources(),R.drawable.background2,options);
runSprite=BitmapFactory.decodeResource(getResources(),R.drawable.runsprite);
box=BitmapFactory.decodeResource(getResources(),R.drawable.box);
bitmapPaint = new Paint(Paint.ANTI_ALIAS_FLAG); // tool for painting on the canvas
bitmapPaint.setAntiAlias(true);
bitmapPaint.setFilterBitmap(true);
textPaint = new Paint();
textPaint.setColor(Color.RED);
textPaint.setTextSize(32);
textPaint2 = new Paint();
textPaint2.setColor(Color.BLUE);
textPaint2.setTextSize(50);
scaledBackground = Bitmap.createScaledBitmap(background, 2560, 500, true);
scaledBackground2 = Bitmap.createScaledBitmap(background2, 2560, 400, true);
scaledLines = Bitmap.createScaledBitmap(lines, 2560, 30, true);
runSprite = Bitmap.createScaledBitmap(runSprite, 1400, 1000, true);
scaledBox = Bitmap.createScaledBitmap(box, 100, 100, true);
sprite = new Bitmap[4][7];
for(int row=0;row<=3;row++)
{
for(int col=0;col<=6;col++)
{
sprite[row][col] = Bitmap.createBitmap(runSprite, SpX, SpY, 200, 250);
SpX+=200;
}
SpX=0;
SpY+=250;
}
}
public void onResumeMySurfaceView()
{
mp.seekTo(length);
mp.start();
running = true;
thread = new Thread(this);
thread.start();
}
public void onPauseMySurfaceView()
{
mp.pause();
length=mp.getCurrentPosition();
boolean retry = true;
running = false;
while(retry){
try {
thread.join();
retry = false;
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public void onDestroyMySurfaceView()
{
mp.stop();
running = false;
thread = null;
thread.stop();
}
private void fps()
{
long now = System.currentTimeMillis();
if (mLastTime != 0)
{
//Time difference between now and last time we were here
int time = (int) (now - mLastTime);
frameSampleTime += time;
frameSamplesCollected++;
//After 10 frames
if (frameSamplesCollected == 10)
{
//Update the fps variable
fps = (int) (10000 / frameSampleTime);
//Reset the sampletime + frames collected
frameSampleTime = 0;
frameSamplesCollected = 0;
}
}
mLastTime = now;
}
public boolean pressDown = false;
public long pressTime;
public boolean onTouchEvent(MotionEvent event)
{
if (event != null)
{
if (event.getAction() == MotionEvent.ACTION_DOWN)
{ if(Yposition == orgPos)
{
spool.play(soundID, 15, 15, 1, 0, 1f);
pressDown = true;
pressTime = System.currentTimeMillis();
}
}else if (event.getAction() == MotionEvent.ACTION_UP)
{
pressDown = false;
}
}
return true;
}
int x=0;
int y=100;
int x2=0;
int y2=20;
int row=0;
int col=0;
int limit = 100;
int orgPos = 450;
int Xbox = 1280;
int Ybox = 580;
Random r = new Random();
int RBox;
public static String Fscore;
boolean onTop = false;
long now;
long start;
long stop;
long time ;
int spritePosition = 0 ;
int spriteSize;
#Override
public void run()
{
while(running)
{
canvas = null;
if(surfaceHolder.getSurface().isValid())
{
canvas = surfaceHolder.lockCanvas();
fps(); // fps
// Update screen parameters
update();
draw();
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
}
public void update()
{
if(score<500)
{
speed = 7;
}
else if(score%500 == 0)
{
speed = 7 + (score / 500);
}
if(col==6)
{
row++;
col=0;
}
if(row==4)
{
row=0;
}
score++;
Fscore = score.toString();
if(x>-1280)
{
x-=speed;
}else if(x<=-1280)
{
x=0;
}
if(x2>-1280)
{
x2-=5;
}else if(x2<=-1280)
{
x2=-0;
}
RBox = r.nextInt(999)+1280;
if(Xbox > -100)
{
Xbox-=speed;
}else if(Xbox<=-100)
{
Xbox=RBox;
}
if( (Xposition + 200 == Xbox +40 )&&(Yposition + 250 > Ybox+20)||( Xposition+200<=Xbox+70)&&( Xposition+200>=Xbox+20)&&(Yposition + 250 > Ybox+30) ) // collision
{
GameOverToast.show();
running = false;
spool.release();
mp.release();
Looper.prepare();
Intent database = new Intent(context, MainHighscore.class);
database.putExtra("score", Fscore);
context.startActivity(database);
onDestroyMySurfaceView();
}
now = System.currentTimeMillis();
if(( now - pressTime) <= 600)
{
if(Yposition > limit)
{
Yposition -= 10;
}
}
onTop = false;
if((now - pressTime) >= 600 && (now - pressTime) <= 1200)
{
if(!(Yposition == orgPos))
{
if(Yposition+250 >= Ybox && Xposition+200>=Xbox+70 && Xposition <= Xbox+40)
{
onTop=true;
Yposition = 340;
}else
{
Yposition += 10;
}
}
}
if((now - pressTime) >= 1200)
{
if(Yposition < 450) Yposition +=10;
else Yposition = 450;
}
}
public void draw()
{
canvas.drawColor(Color.WHITE);
//canvas.drawBitmap(scaledBackground, x2,y2, bitmapPaint);
canvas.drawBitmap(scaledBackground2, x,y, bitmapPaint);
canvas.drawBitmap(scaledLines, x,650, bitmapPaint);
canvas.drawText(Fscore, 1050, 50, textPaint2);
canvas.drawText(fps + " fps", getWidth() / 2, getHeight() / 2, textPaint);
canvas.drawBitmap(sprite[row][col],Xposition,Yposition,bitmapPaint );
canvas.drawBitmap(scaledBox,Xbox,Ybox,bitmapPaint);
col++;
}
}
I think your problem might be actually the moving part. Your just drawing too much stuff, and the surfaceView is not meant for that.