I followed tutorial from this link-> http://android-er.blogspot.com/2015/02/create-audio-visualizer-for-mediaplayer.html
where graphics is done by extending view class.Now i am trying to do the same with surface view .Here`s the code:
MainActivity:
public class MainActivity extends Activity {
VisualizerView mVisualizerView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mVisualizerView= new VisualizerView(this);
setContentView(mVisualizerView);
}
#Override
protected void onPause(){
super.onPause();
if(isFinishing()){
mVisualizerView.clean();
}
}}
Sufaceview class:
public class VisualizerView extends SurfaceView implements SurfaceHolder.Callback {
private byte[] mBytes;
private float[] mPoints;
private Rect mRect = new Rect();
private Paint mForePaint = new Paint();
SurfaceThread _thread;
private MediaPlayer player;
private Visualizer visualizer;
private Context context;
public VisualizerView(Context context) {
super(context);
init();
getHolder().addCallback(this);
_thread = new SurfaceThread(getHolder(), this);
this.context=context;
}
private void init(){
mBytes = null;
mForePaint.setStrokeWidth(1f);
mForePaint.setAntiAlias(true);
mForePaint.setColor(Color.rgb(0,0, 255));
}
public void updateVisualizer(byte[] bytes) {
mBytes = bytes;
// invalidate();
}
private void initAudio(){
player= MediaPlayer.create(context, R.raw.duck);
setupVisualizerFxAndUI();
visualizer.setEnabled(true);
player.setOnCompletionListener(new MediaPlayer.OnCompletionListener(){
public void onCompletion(MediaPlayer mediaPlayer){
visualizer.setEnabled(false);
}
}
);
player.start();
}
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (mBytes == null) {
return;
}
if (mPoints == null || mPoints.length < mBytes.length * 4) {
mPoints = new float[mBytes.length * 4];
}
mRect.set(0, 0, getWidth(), getHeight());
for (int i = 0; i < mBytes.length - 1; i++) {
mPoints[i * 4] = mRect.width() * i / (mBytes.length - 1);
mPoints[i * 4 + 1] = mRect.height() / 2
+ ((byte) (mBytes[i] + 128)) * (mRect.height() / 2) / 128;
mPoints[i * 4 + 2] = mRect.width() * (i + 1) / (mBytes.length - 1);
mPoints[i * 4 + 3] = mRect.height() / 2
+ ((byte) (mBytes[i + 1] + 128)) * (mRect.height() / 2)
/ 128;
}
canvas.drawColor(Color.WHITE);
canvas.drawLines(mPoints, mForePaint);
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
// TODO Auto-generated method stub
_thread.setRunning(true);
_thread.start();
initAudio();
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
// TODO Auto-generated method stub
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
boolean retry = true;
_thread.setRunning(false);
while (retry) {
try {
_thread.join();
retry = false;
} catch (InterruptedException e) {
// we will try it again and again...
}
}
}
public void clean(){
if(player!=null){
visualizer.release();
player.release();
player= null;
}
}
private void setupVisualizerFxAndUI(){
Equalizer mEqualizer = new Equalizer(0, player.getAudioSessionId());
mEqualizer.setEnabled(false);
visualizer =new Visualizer(player.getAudioSessionId());
visualizer.setCaptureSize(Visualizer.getCaptureSizeRange()[1]);
visualizer.setDataCaptureListener(new Visualizer.OnDataCaptureListener() {
#Override
public void onWaveFormDataCapture(Visualizer visualizer, byte[] waveform,
int samplingRate) {
// TODO Auto-generated method stub
updateVisualizer(waveform);
}
#Override
public void onFftDataCapture(Visualizer visualizer, byte[] fft,
int samplingRate) {
// TODO Auto-generated method stub
}
},Visualizer.getMaxCaptureRate()/2,true,false) ;
// Log.d(Tag,String.valueOf(Visualizer.getMaxCaptureRate()));
}}
Thread class:
public class SurfaceThread extends Thread {
private SurfaceHolder surfaceHolder;
private VisualizerView panel;
private boolean run = false;
public SurfaceThread(SurfaceHolder surfaceHolder, VisualizerView panel) {
this. surfaceHolder = surfaceHolder;
this. panel = panel;
}
public void setRunning(boolean run) {
this.run = run;
}
#Override
public void run() {
Canvas c;
while (run) {
c = null;
try {
c = surfaceHolder.lockCanvas(null);
synchronized (surfaceHolder) {
panel.onDraw(c);
}
} finally {
// do this in a finally so that if an exception is thrown
// during the above, we don't leave the Surface in an
// inconsistent state
if (c != null) {
surfaceHolder.unlockCanvasAndPost(c);
}
}
}
}}
Now problem is that app will crash after running it twice.I know that i am
not passing data correctly from:
public void onWaveFormDataCapture(Visualizer visualizer, byte[] waveform,
int samplingRate) {
// TODO Auto-generated method stub
updateVisualizer(waveform);
}
So, how do i manage it ?
Also i am confused in which thread visualizer/mediaplayer is running and where should it go?
Related
I use MediaPlayer to play videos with GPUImage effects apply to it. On certain devices, after a short while - a few seconds or more (seems random), the video stops playing (the image remains stuck), but audio keeps playing (most of the time). I target the MediaPlayer to a GLSurfaceView, in order to be able to use GPUImage effects on top of it.
Here is the custom view:
public class FilteredVideoView extends GLSurfaceView {
private MediaPlayer mMediaPlayer = null;
private long time = 0;
private MyCustomRenderer renderer;
private boolean mediaPlayerInitialized = false;
private String videoPath;
public FilteredVideoView(Context context) {
super(context);
setWillNotDraw(false);
init();
//startFilterChangeThread();
}
public void setFilter(MyGPUImageFilter filter) {
renderer.setFilter(filter);
}
public void stopVideo() {
mMediaPlayer.stop();
}
public void prepareVideo() {
try {
mMediaPlayer.prepare();
} catch (Exception e) {
}
}
public void playVideo() {
initMediaPlayer();
mMediaPlayer.seekTo(0);
mMediaPlayer.start();
}
private void init() {
setEGLContextClientVersion(2);
getHolder().setFormat(PixelFormat.TRANSLUCENT);
setEGLConfigChooser(8, 8, 8, 8, 16, 0);
mMediaPlayer = new MediaPlayer();
//initMediaPlayer();
renderer = new MyCustomRenderer(new MyNoFilterFilter(), mMediaPlayer);
setRenderer(renderer);
}
private void initMediaPlayer() {
if (mediaPlayerInitialized) {
return;
}
mediaPlayerInitialized = true;
try {
FileInputStream fi = new FileInputStream(new File(videoPath));
mMediaPlayer.setDataSource(fi.getFD());
mMediaPlayer.prepare();
mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
onVideoPlaybackFinished();
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
void onVideoPlaybackFinished() {
}
#Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
if (mMediaPlayer != null) {
mMediaPlayer.stop();
mMediaPlayer.release();
}
}
And here is the renderer.
public class MyCustomRenderer implements Renderer, SurfaceTexture.OnFrameAvailableListener {
public static final int NO_IMAGE = -1;
public static final float CUBE[] = {
-1.0f, -1.0f,
1.0f, -1.0f,
-1.0f, 1.0f,
1.0f, 1.0f,
};
private MyGPUImageFilter mFilter;
public final Object mSurfaceChangedWaiter = new Object();
private int mTextureID = NO_IMAGE;
private SurfaceTexture mSurfaceTexture = null;
private final FloatBuffer mGLCubeBuffer;
private final FloatBuffer mGLTextureBuffer;
private IntBuffer mGLRgbBuffer;
private int mOutputWidth;
private int mOutputHeight;
private int mImageWidth;
private int mImageHeight;
private int mAddedPadding;
private final Queue<Runnable> mRunOnDraw;
private final Queue<Runnable> mRunOnDrawEnd;
private Rotation mRotation;
private boolean mFlipHorizontal;
private boolean mFlipVertical;
private GPUImage.ScaleType mScaleType = GPUImage.ScaleType.CENTER_CROP;
public SurfaceTexture mSurface;
public boolean updateSurface = false;
private MediaPlayer mMediaPlayer;
private int GL_TEXTURE_EXTERNAL_OES = 0x8D65;
private float[] mSTMatrix = new float[16];
public MyCustomRenderer(final MyGPUImageFilter filter, MediaPlayer mediaPlayer) {
mMediaPlayer = mediaPlayer;
mFilter = filter;
mRunOnDraw = new LinkedList<Runnable>();
mRunOnDrawEnd = new LinkedList<Runnable>();
mGLCubeBuffer = ByteBuffer.allocateDirect(CUBE.length * 4)
.order(ByteOrder.nativeOrder())
.asFloatBuffer();
mGLCubeBuffer.put(CUBE).position(0);
mGLTextureBuffer = ByteBuffer.allocateDirect(TEXTURE_NO_ROTATION.length * 4)
.order(ByteOrder.nativeOrder())
.asFloatBuffer();
setRotation(Rotation.NORMAL, false, false);
Matrix.setIdentityM(mSTMatrix, 0);
}
#Override
public void onSurfaceCreated(final GL10 unused, final EGLConfig config) {
int[] textures = new int[1];
GLES20.glGenTextures(1, textures, 0);
mTextureID = textures[0];
GLES20.glBindTexture(GL_TEXTURE_EXTERNAL_OES, mTextureID);
mSurface = new SurfaceTexture(mTextureID);
mSurface.setOnFrameAvailableListener(this);
Surface surface = new Surface(mSurface);
mMediaPlayer.setSurface(surface);
surface.release();
synchronized (this) {
updateSurface = false;
}
GLES20.glClearColor(0, 0, 0, 1);
GLES20.glDisable(GLES20.GL_DEPTH_TEST);
mFilter.init();
//mMediaPlayer.start();
}
#Override
public void onSurfaceChanged(final GL10 gl, final int width, final int height) {
mOutputWidth = width;
mOutputHeight = height;
GLES20.glViewport(0, 0, width, height);
GLES20.glUseProgram(mFilter.getProgram());
mFilter.onOutputSizeChanged(width, height);
adjustImageScaling();
synchronized (mSurfaceChangedWaiter) {
mSurfaceChangedWaiter.notifyAll();
}
}
#Override
public void onDrawFrame(final GL10 gl) {
synchronized (this) {
if (updateSurface) {
mSurface.updateTexImage();
mSurface.getTransformMatrix(mSTMatrix);
updateSurface = false;
} else {
//return;
}
}
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
runAll(mRunOnDraw);
mFilter.onDraw(mTextureID, mGLCubeBuffer, mGLTextureBuffer);
runAll(mRunOnDrawEnd);
/*if (mSurfaceTexture != null) {
mSurfaceTexture.updateTexImage();
}*/
}
private void runAll(Queue<Runnable> queue) {
synchronized (queue) {
while (!queue.isEmpty()) {
queue.poll().run();
}
}
}
public void setFilter(final MyGPUImageFilter filter) {
runOnDraw(new Runnable() {
#Override
public void run() {
final MyGPUImageFilter oldFilter = mFilter;
mFilter = filter;
if (oldFilter != null) {
oldFilter.destroy();
}
mFilter.init();
GLES20.glUseProgram(mFilter.getProgram());
mFilter.onOutputSizeChanged(mOutputWidth, mOutputHeight);
}
});
}
public void deleteImage() {
runOnDraw(new Runnable() {
#Override
public void run() {
GLES20.glDeleteTextures(1, new int[]{
mTextureID
}, 0);
mTextureID = NO_IMAGE;
}
});
}
public void setScaleType(GPUImage.ScaleType scaleType) {
mScaleType = scaleType;
}
protected int getFrameWidth() {
return mOutputWidth;
}
protected int getFrameHeight() {
return mOutputHeight;
}
private void adjustImageScaling() {
float outputWidth = mOutputWidth;
float outputHeight = mOutputHeight;
if (mRotation == Rotation.ROTATION_270 || mRotation == Rotation.ROTATION_90) {
outputWidth = mOutputHeight;
outputHeight = mOutputWidth;
}
mImageWidth = App.screenW();
mImageHeight = App.screenH();
outputWidth = App.screenW();
outputHeight = App.screenH();
float ratio1 = outputWidth / mImageWidth;
float ratio2 = outputHeight / mImageHeight;
float ratioMax = Math.max(ratio1, ratio2);
int imageWidthNew = Math.round(mImageWidth * ratioMax);
int imageHeightNew = Math.round(mImageHeight * ratioMax);
float ratioWidth = imageWidthNew / outputWidth;
float ratioHeight = imageHeightNew / outputHeight;
float[] cube = CUBE;
float[] textureCords = TextureRotationUtil.getRotation(mRotation, mFlipHorizontal, mFlipVertical);
if (mScaleType == GPUImage.ScaleType.CENTER_CROP) {
float distHorizontal = (1 - 1 / ratioWidth) / 2;
float distVertical = (1 - 1 / ratioHeight) / 2;
textureCords = new float[]{
addDistance(textureCords[0], distHorizontal), addDistance(textureCords[1], distVertical),
addDistance(textureCords[2], distHorizontal), addDistance(textureCords[3], distVertical),
addDistance(textureCords[4], distHorizontal), addDistance(textureCords[5], distVertical),
addDistance(textureCords[6], distHorizontal), addDistance(textureCords[7], distVertical),
};
} else {
cube = new float[]{
CUBE[0] / ratioHeight, CUBE[1] / ratioWidth,
CUBE[2] / ratioHeight, CUBE[3] / ratioWidth,
CUBE[4] / ratioHeight, CUBE[5] / ratioWidth,
CUBE[6] / ratioHeight, CUBE[7] / ratioWidth,
};
}
mGLCubeBuffer.clear();
mGLCubeBuffer.put(cube).position(0);
mGLTextureBuffer.clear();
mGLTextureBuffer.put(textureCords).position(0);
}
private float addDistance(float coordinate, float distance) {
return coordinate == 0.0f ? distance : 1 - distance;
}
public void setRotationCamera(final Rotation rotation, final boolean flipHorizontal,
final boolean flipVertical) {
setRotation(rotation, flipVertical, flipHorizontal);
}
public void setRotation(final Rotation rotation) {
mRotation = rotation;
adjustImageScaling();
}
public void setRotation(final Rotation rotation,
final boolean flipHorizontal, final boolean flipVertical) {
mFlipHorizontal = flipHorizontal;
mFlipVertical = flipVertical;
setRotation(rotation);
}
public Rotation getRotation() {
return mRotation;
}
public boolean isFlippedHorizontally() {
return mFlipHorizontal;
}
public boolean isFlippedVertically() {
return mFlipVertical;
}
protected void runOnDraw(final Runnable runnable) {
synchronized (mRunOnDraw) {
mRunOnDraw.add(runnable);
}
}
protected void runOnDrawEnd(final Runnable runnable) {
synchronized (mRunOnDrawEnd) {
mRunOnDrawEnd.add(runnable);
}
}
#Override
public void onFrameAvailable(SurfaceTexture surfaceTexture) {
updateSurface = true;
}
}
Any ideas what could be causing the issue? Maybe a memory-leak?
Thank you for your help!
So basically I have created a page with a visualiser and a button for recording the audio. I want the visualiser to run for the audio that I am recording. I guess I need to get the MaxAmplitude for the recording and then dynamically plot a visualiser graph for every small period. Can someone please help me with that ? or if there is a better way to do it. Currently the code i pasted, the visualiser runs for the recording after recording it.
public class MainActivity extends Activity {
private static final float VISUALIZER_HEIGHT_DIP = 200f;
MediaPlayer mp;
private Visualizer mVisualizer;
private LinearLayout mLinearLayout;
private VisualizerView mVisualizerView;
private TextView mStatusTextView;
private File metapath;
private static String[] META_PATH;
private Button play;
private boolean mStartRecording;
private static final String LOG_TAG = "AudioRecordTest";
private static String mFileName = null;
private MediaRecorder mRecorder = null;
private MediaPlayer mPlayer = null;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mStatusTextView = (TextView)findViewById(R.id.recording);
if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)
|| Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED_READ_ONLY))
metapath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC);
META_PATH = metapath.list(new WavFilter());
mLinearLayout = (LinearLayout)findViewById(R.id.subscreen);
play = (Button)findViewById(R.id.startandstop);
mStartRecording=true;
play.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
onRecord(mStartRecording);
if (mStartRecording) {
play.setText("Stop recording");
} else {
play.setText("Start recording");
}
mStartRecording = !mStartRecording;
}
});
setupVisualizerFxAndUI();
mVisualizer.setEnabled(true);
mStatusTextView.setText("Playing audio...");
}
private void onRecord(boolean start) {
if (start) {
startRecording();
} else {
stopRecording();
}
}
private void startRecording() {
mRecorder = new MediaRecorder();
mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
mRecorder.setOutputFile(metapath.getPath()+"/myfile.3gp");
mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
try {
mRecorder.prepare();
} catch (IOException e) {
Log.e(LOG_TAG, "prepare() failed");
}
mRecorder.start();
}
private void stopRecording() {
mRecorder.stop();
mRecorder.release();
mRecorder = null;
mPlayer = new MediaPlayer();
try {
mPlayer.setDataSource(metapath.getPath()+"/myfile.3gp");
mPlayer.prepare();
mPlayer.start();
} catch (IOException e) {
Log.e(LOG_TAG, "prepare() failed");
}
}
class WavFilter implements FilenameFilter {
public boolean accept(File dir, String name) {
return (name.endsWith(".wav"));
}
}
private void setupVisualizerFxAndUI() {
mVisualizerView = new VisualizerView(this);
mVisualizerView.setLayoutParams(new ViewGroup.LayoutParams(
600,
(int)(VISUALIZER_HEIGHT_DIP * getResources().getDisplayMetrics().density)));
mLinearLayout.addView(mVisualizerView);
mLinearLayout.setGravity(Gravity.CENTER_HORIZONTAL);
mVisualizer = new Visualizer(0);
mVisualizer.setCaptureSize(Visualizer.getCaptureSizeRange()[1]);
mVisualizer.setDataCaptureListener(new Visualizer.OnDataCaptureListener() {
public void onWaveFormDataCapture(Visualizer visualizer, byte[] bytes,
int samplingRate) {
for(int i=0;i<bytes.length;i++)
bytes[i]+=2;
mVisualizerView.updateVisualizer(bytes);
}
public void onFftDataCapture(Visualizer visualizer, byte[] bytes, int samplingRate) {}
}, Visualizer.getMaxCaptureRate() / 2, true, false);
}
#Override
protected void onPause() {
super.onPause();
if (isFinishing() && mp != null) {
mVisualizer.release();
mp.release();
mp = null;
}
}
class VisualizerView extends View {
private byte[] mBytes;
private float[] mPoints;
private Rect mRect = new Rect();
private Paint mForePaint = new Paint();
public VisualizerView(Context context) {
super(context);
init();
}
private void init() {
mBytes = null;
mForePaint.setStrokeWidth(6f);//set width of the moving wave
mForePaint.setAntiAlias(true);
mForePaint.setColor(Color.RED);//color of the moving wavd\e
}
public void updateVisualizer(byte[] bytes) {
mBytes = bytes;
invalidate();
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (mBytes == null) {
return;
}
if (mPoints == null || mPoints.length < mBytes.length * 4) {
mPoints = new float[mBytes.length * 4];
}
mRect.set(0, 0, getWidth(), getHeight());
for (int i = 0; i < mBytes.length - 1; i++) {
mPoints[i * 4] = mRect.width() * i / (mBytes.length - 1);
mPoints[i * 4 + 1] = mRect.height() / 2
+ ((byte) (mBytes[i] + 128)) * (mRect.height() / 2) / 128;
mPoints[i * 4 + 2] = mRect.width() * (i + 1) / (mBytes.length - 1);
mPoints[i * 4 + 3] = mRect.height() / 2
+ ((byte) (mBytes[i + 1] + 128)) * (mRect.height() / 2) / 128;
}
canvas.drawColor(Color.BLACK);
canvas.drawLines(mPoints, mForePaint);
}
}
}
I'm trying to make a basic AndEngine game but the sprite doesn't appear. I don't get any errors.
I can't find the issue and neither can the guy who's helping me with this so any help is greatly appreciated.
public class Game extends BaseGameActivity implements SensorEventListener {
Scene scene;
protected static final int CAMERA_WIDTH = 800;
protected static final int CAMERA_HEIGHT = 480;
private BuildableBitmapTextureAtlas playerTexture;
private TextureRegion regionCell;
private Sprite sprCell;
private SensorManager sensorManager;
private float accellSpeedX, accellSpeedY;
private float sprX, sprY;
#Override
public EngineOptions onCreateEngineOptions() {
// TODO Auto-generated method stub
Camera mCamera = new Camera(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT);
EngineOptions options = new EngineOptions(true,
ScreenOrientation.LANDSCAPE_FIXED, new RatioResolutionPolicy(
CAMERA_WIDTH, CAMERA_HEIGHT), mCamera);
return options;
}
#Override
public void onCreateResources(
OnCreateResourcesCallback pOnCreateResourcesCallback)
throws Exception {
// TODO Auto-generated method stub
BitmapTextureAtlasTextureRegionFactory.setAssetBasePath("gfx/");
// BitmapTextureAtlas must be power of 2 for width and height.
playerTexture = new BuildableBitmapTextureAtlas(
this.getTextureManager(), 256, 64);
regionCell = BitmapTextureAtlasTextureRegionFactory.createFromAsset(
playerTexture, this.getAssets(), "player.png");
playerTexture.load();
pOnCreateResourcesCallback.onCreateResourcesFinished();
}
#SuppressWarnings("static-access")
#Override
public void onCreateScene(OnCreateSceneCallback pOnCreateSceneCallback)
throws Exception {
// TODO Auto-generated method stub
sensorManager = (SensorManager) getSystemService(this.SENSOR_SERVICE);
sensorManager.registerListener(this,
sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
sensorManager.SENSOR_DELAY_GAME);
this.mEngine.registerUpdateHandler(new FPSLogger());
this.mEngine.registerUpdateHandler(new IUpdateHandler() {
#Override
public void reset() {
// TODO Auto-generated method stub
}
#Override
public void onUpdate(float pSecondsElapsed) {
// TODO Auto-generated method stub
updateSpritePosistion();
}
private void updateSpritePosistion() {
// TODO Auto-generated method stub
if (accellSpeedX != 0 || accellSpeedY != 0) {
int tL = 0;
int iL = 0;
int rL = CAMERA_WIDTH - (int) sprCell.getWidth();
int bL = CAMERA_HEIGHT - (int) sprCell.getHeight();
if (sprX >= iL) {
sprX += accellSpeedX;
} else {
sprX = iL;
}
if (sprX <= rL) {
sprX += accellSpeedX;
} else {
sprX = rL;
}
if (sprY >= tL) {
sprY += accellSpeedY;
} else {
sprY = tL;
}
if (sprY <= bL) {
sprY += accellSpeedY;
} else {
sprY = bL;
}
if (sprX < iL) {
sprX = iL;
} else if (sprX > rL) {
sprX = rL;
}
if (sprY < tL) {
sprY = tL;
} else if (sprY > bL) {
sprY = bL;
}
sprCell.setPosition(sprX, sprY);
}
}
});
this.scene = new Scene();
this.scene.setBackground(new Background(0, 122, 222));
sprX = (CAMERA_WIDTH - this.regionCell.getWidth()) / 2;
sprY = (CAMERA_HEIGHT - this.regionCell.getHeight()) / 2;
sprCell = new Sprite(sprX, sprY, regionCell,
getVertexBufferObjectManager());
scene.attachChild(sprCell);
pOnCreateSceneCallback.onCreateSceneFinished(this.scene);
}
#Override
public void onPopulateScene(Scene pScene,
OnPopulateSceneCallback pOnPopulateSceneCallback) throws Exception {
// TODO Auto-generated method stub
pOnPopulateSceneCallback.onPopulateSceneFinished();
}
#Override
public void onAccuracyChanged(Sensor arg0, int arg1) {
// TODO Auto-generated method stub
}
#Override
public void onSensorChanged(SensorEvent event) {
// TODO Auto-generated method stub
synchronized (this) {
switch (event.sensor.getType()) {
case Sensor.TYPE_ACCELEROMETER:
accellSpeedX = (int) event.values[1];
accellSpeedY = (int) event.values[0];
break;
}
}
}
}
Try this..I have tried it and solved the problem... Just set & change the size of your image in mBitmapTextureAtlas and name of your image in mTextureRegion under onCreateResources...
public class MainActivity extends BaseGameActivity implements
SensorEventListener {
Scene scene;
private ITextureRegion mTextureRegion;
private BuildableBitmapTextureAtlas mBitmapTextureAtlas;
protected static final int CAMERA_WIDTH = 800;
protected static final int CAMERA_HEIGHT = 480;
private BuildableBitmapTextureAtlas playerTexture;
private Sprite sprCell;
private SensorManager sensorManager;
private float accellSpeedX, accellSpeedY;
private float sprX, sprY;
Rectangle rect;
#Override
public EngineOptions onCreateEngineOptions()
{
// TODO Auto-generated method stub
Camera mCamera = new Camera(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT);
EngineOptions options = new EngineOptions(true,
ScreenOrientation.LANDSCAPE_FIXED, new RatioResolutionPolicy(
CAMERA_WIDTH, CAMERA_HEIGHT), mCamera);
return options;
}
#Override
public void onCreateResources(
OnCreateResourcesCallback pOnCreateResourcesCallback)
throws Exception {
// TODO Auto-generated method stub
BitmapTextureAtlasTextureRegionFactory.setAssetBasePath("gfx/");
this.mBitmapTextureAtlas = new BuildableBitmapTextureAtlas(this.getTextureManager(), 100, 100);
this.mTextureRegion = BitmapTextureAtlasTextureRegionFactory
.createFromAsset(this.mBitmapTextureAtlas, this, "mo.png");
try
{
this.mBitmapTextureAtlas
.build(new BlackPawnTextureAtlasBuilder<IBitmapTextureAtlasSource, BitmapTextureAtlas>(
0, 0, 0));
this.mBitmapTextureAtlas.load();
}
catch (TextureAtlasBuilderException e)
{
Debug.e(e);
}
pOnCreateResourcesCallback.onCreateResourcesFinished();
}
#SuppressWarnings("static-access")
#Override
public void onCreateScene(OnCreateSceneCallback pOnCreateSceneCallback)
throws Exception {
// TODO Auto-generated method stub
this.scene = new Scene();
this.scene.setBackground(new Background(0, 122, 222));
sprX = (CAMERA_WIDTH - this.mTextureRegion.getWidth()) / 2;
sprY = (CAMERA_HEIGHT - this.mTextureRegion.getHeight()) / 2;
sprCell = new Sprite(sprX, sprY, mTextureRegion, getVertexBufferObjectManager());
scene.attachChild(sprCell);
sensorManager = (SensorManager) getSystemService(this.SENSOR_SERVICE);
sensorManager.registerListener(this,
sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
sensorManager.SENSOR_DELAY_GAME);
this.mEngine.registerUpdateHandler(new FPSLogger());
this.mEngine.registerUpdateHandler(new IUpdateHandler() {
#Override
public void reset() {
// TODO Auto-generated method stub
}
#Override
public void onUpdate(float pSecondsElapsed) {
// TODO Auto-generated method stub
updateSpritePosistion();
}
private void updateSpritePosistion() {
// TODO Auto-generated method stub
if (accellSpeedX != 0 || accellSpeedY != 0) {
int tL = 0;
int iL = 0;
int rL = CAMERA_WIDTH - (int) sprCell.getWidth();
int bL = CAMERA_HEIGHT - (int) sprCell.getHeight();
if (sprX >= iL) {
sprX += accellSpeedX;
} else {
sprX = iL;
}
if (sprX <= rL) {
sprX += accellSpeedX;
} else {
sprX = rL;
}
if (sprY >= tL) {
sprY += accellSpeedY;
} else {
sprY = tL;
}
if (sprY <= bL) {
sprY += accellSpeedY;
} else {
sprY = bL;
}
if (sprX < iL) {
sprX = iL;
} else if (sprX > rL) {
sprX = rL;
}
if (sprY < tL) {
sprY = tL;
} else if (sprY > bL) {
sprY = bL;
}
sprCell.setPosition(sprX, sprY);
}
}
});
pOnCreateSceneCallback.onCreateSceneFinished(this.scene);
}
#Override
public void onPopulateScene(Scene pScene,
OnPopulateSceneCallback pOnPopulateSceneCallback) throws Exception {
// TODO Auto-generated method stub
pOnPopulateSceneCallback.onPopulateSceneFinished();
}
#Override
public void onAccuracyChanged(Sensor arg0, int arg1) {
// TODO Auto-generated method stub
}
#Override
public void onSensorChanged(SensorEvent event) {
// TODO Auto-generated method stub
synchronized (this) {
switch (event.sensor.getType()) {
case Sensor.TYPE_ACCELEROMETER:
accellSpeedX = (int) event.values[1];
accellSpeedY = (int) event.values[0];
break;
}
}
}
}
You should load your textures before you create texture region from them.
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.
It looks like this both in the emulator and on the phone. It's always a random square that is broken.
And here is the code from the SurfaceView class, the most relevant part is in prepareBackground() :
Code begins:
public class MenuBackgroundView extends SurfaceView implements SurfaceHolder.Callback
{
private Paint mPaint;
private Bitmap blocks12x12;
private boolean draw = false;
private Context ctx;
//private int begOffX;
private int offX;
private int offY;
private int mWidth = 1;
private int mHeight = 1;
private ViewThread mThread;
private int calcSizeXY;
public MenuBackgroundView(Context context, AttributeSet attrs) {
super(context, attrs);
getHolder().addCallback(this);
mThread = new ViewThread(this);
mPaint = new Paint();
mPaint.setColor(Color.RED);
ctx = context;
}
public void doDraw(long elapsed, Canvas canvas) {
canvas.drawColor(Color.BLUE);
if(draw)
{
canvas.drawBitmap(blocks12x12, offX, offY, mPaint);
}
canvas.drawText("FPS: " + Math.round(1000f / elapsed) + " Elements: ", 10, 10, mPaint);
}
public void animate(long elapsed)
{
/*
//elapsed = elapsed/10;
offX = (offX+2);
if(offX >= 0)
{
offX -= 2*calcSizeXY;
}
offY = (offY+3);
if(offY >= 0)
{
offY -= 2*calcSizeXY;
}
//offY = (offY + (int)(elapsed/10f)) % calcSizeXY*2;//
*
*///
}
public void prepareBackground()
{
if(mWidth <= 1 || mHeight <= 1 )
return;
Log.d("Menu", "prepareBackground");
if(mHeight > mWidth)
{
calcSizeXY = mHeight/10;
}
else
{
calcSizeXY = mWidth/10;
}
offX = -2*calcSizeXY;
Bitmap block = BitmapFactory.decodeResource(ctx.getResources(), R.drawable.block);
block = Bitmap.createScaledBitmap(block, calcSizeXY, calcSizeXY, false);
// Group together
int sizeX = 12*calcSizeXY;
int sizeY = 12*calcSizeXY;
blocks12x12 = Bitmap.createBitmap(sizeX, sizeY, Bitmap.Config.ARGB_8888);
Canvas blocks12x12Canvas = new Canvas(blocks12x12);
for(int i = 0; i < 14; i+=2)
{
for(int j = 0; j < 14; j+=2)
{
blocks12x12Canvas.drawBitmap(block, (j*calcSizeXY), (i*calcSizeXY), mPaint);
}
}
// "Memory leak"
block.recycle();
draw = true;
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
mWidth = width;
mHeight = height;
prepareBackground();
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
prepareBackground();
if (!mThread.isAlive()) {
mThread = new ViewThread(this);
mThread.setRunning(true);
mThread.start();
}
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
if (mThread.isAlive()) {
mThread.setRunning(false);
freeMem();
}
}
public void freeMem() {
// TODO Auto-generated method stub
draw = false;
blocks12x12.recycle(); // "Memory leak"
}
}
Ok I figured it out, simply make the thread sleep for 1ms:
blocks12x12 = Bitmap.createBitmap(sizeX, sizeY, Bitmap.Config.ARGB_8888);
Canvas blocks12x12Canvas = new Canvas(blocks12x12);
for(int i = 0; i < 14; i+=2)
{
for(int j = 0; j < 14; j+=2)
{
try {
Thread.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
blocks12x12Canvas.drawBitmap(block, (j*calcSizeXY), (i*calcSizeXY), mPaint);
}
}