I'm a beginner in Android programming, and I'm working on a small bubble shooter game. However, I face a weird problem which I cannot figure out. I have a piece of code which handles the launcher of the app, if I program the whole code in class, the app runs smooth. However, if I 'cut' the code into different classes there a noticeable lag in the movement of the launcher.
My main question is: what can cause this lag, and what is the best approach to avoid this (now and in the future).
Thanks in advance,
Kind regards,
This is my code when I program everything in one class.
package com.example.bubbleshootergame;
// imports are delete to shorten the post
public class GameThree extends Activity implements OnTouchListener {
OurView v;
Bitmap launcher;
float x, y, rotationAngle;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
v = new OurView(this);
v.setOnTouchListener(this);
launcher = BitmapFactory.decodeResource(getResources(),
R.drawable.launcher);
setContentView(v);
}
#Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
v.pause();
}
#Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
v.resume();
}
public class OurView extends SurfaceView implements Runnable {
Thread t = null;
SurfaceHolder holder;
boolean bool = false;
public OurView(Context context) {
super(context);
// TODO Auto-generated constructor stub
holder = getHolder();
}
#Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
View content = getWindow().findViewById(Window.ID_ANDROID_CONTENT);
// x & y are the width and height of the usable screen size
x = content.getWidth();
y = content.getHeight();
}
#Override
public void run() {
// TODO Auto-generated method stub
while (bool == true) {
if (!holder.getSurface().isValid()) {
continue;
}
Canvas c = holder.lockCanvas();
Paint Blackline = new Paint();
Blackline.setColor(Color.rgb(0, 0, 0));
Blackline.setStrokeWidth(10);
// background color of canvas
c.drawARGB(255, 255, 255, 255);
c.drawRect(0, (float) 0.85*y, x, (float) 0.84*y, Blackline);
// rotate by angle 'rotationAngle' around point x/2 and y
// this corresponds the middle of the launcher
c.rotate(rotationAngle, x / 2, y - (launcher.getHeight() / 2));
// draw the bitmap (this case the launcher) around the center of
// the width of the launcher and bottom of the launcher
c.drawBitmap(launcher, x / 2 - (launcher.getWidth() / 2), y
- (launcher.getHeight()), null);
holder.unlockCanvasAndPost(c);
}
}
public void pause() {
// TODO Auto-generated method stub
bool = false;
while (true) {
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
break;
}
t = null;
}
public void resume() {
// TODO Auto-generated method stub
bool = true;
t = new Thread(this);
t.start();
}
}
#Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
float currentX = event.getX();
float currentY = event.getY();
if (currentY >= 0.85*y ){
}
else
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE: {
double rotationAngleRadians = Math.atan2(currentX - x / 2, y
- currentY);
rotationAngle = (int) Math.toDegrees(rotationAngleRadians);
return true;
}
}
return true;
}
}
Here are the code block when uses different classes:
MainActivity
package com.gabrudar.conquestappgame;
public class MainActivity extends Activity implements OnTouchListener {
GameView view;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
view = new GameView(this);
view.setOnTouchListener(this);
setContentView(view);
}
#Override
protected void onPause() {
super.onPause();
view.pause();
}
#Override
protected void onResume() {
super.onResume();
view.resume();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
try {
Thread.sleep(50);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
view.processTouch(event);
return true;
}
}
GameView:
package com.gabrudar.conquestappgame;
public class GameView extends SurfaceView implements Runnable {
Thread gameThread = null;
SurfaceHolder holder;
boolean continueRunning = false;
Bitmap blob;
Bitmap background;
Sprite sprite;
Rect screenRect;
Bitmap Launcher;
LauncherC launcher;
long startTime;
float deltaTime;
public GameView(Context context) {
super(context);
holder = getHolder();
screenRect = new Rect();
background = BitmapFactory.decodeResource(getResources(), R.drawable.androidbg);
blob = BitmapFactory.decodeResource(getResources(), R.drawable.spritesheet);
Launcher = BitmapFactory.decodeResource(getResources(),
R.drawable.launcher);
launcher = new LauncherC(Launcher);
}
#Override
public void run() {
startTime = System.nanoTime();
while (continueRunning == true){
if (!holder.getSurface().isValid()){
continue;
}
deltaTime = (System.nanoTime() - startTime)/1000000;
startTime = System.nanoTime();
Canvas c = holder.lockCanvas();
onDraw(c);
holder.unlockCanvasAndPost(c);
}
}
public void pause() {
continueRunning = false;
while(true){
try{
gameThread.join();
}catch(InterruptedException e){
e.printStackTrace();
}
break;
}
gameThread = null;
}
public void resume() {
continueRunning = true;
gameThread = new Thread(this);
gameThread.start();
}
protected void update(float dt) {
}
protected void onDraw(Canvas canvas) {
this.getDrawingRect(screenRect);
canvas.drawBitmap(background, null, screenRect, null);
launcher.onDraw(canvas);
}
public void processTouch(MotionEvent me) {
launcher.Toucher(me);
}
}
Launcher:
package com.gabrudar.conquestappgame;
public class LauncherC {
float rotationAngle,x1,y1;
Bitmap L1;
public LauncherC(Bitmap Launcher){
L1 = Launcher;
}
public void onDraw(Canvas c) {
// TODO Auto-generated method stub
Paint Blackline = new Paint();
Blackline.setColor(Color.rgb(0, 0, 0));
Blackline.setStrokeWidth(10);
x1 = c.getWidth();
y1 = c.getHeight();
c.drawRect(0, (float) 0.85 * y1, x1, (float) 0.84 * y1, Blackline);
c.rotate(rotationAngle, x1 / 2, y1 - (L1.getHeight() / 2));
c.drawBitmap(L1, x1 / 2 - (L1.getWidth() / 2), y1
- (L1.getHeight()), null);
}
public void Toucher(MotionEvent event){
// TODO Auto-generated method stub
float currentX = event.getX();
float currentY = event.getY();
if (currentY >= 0.85 * y1) {
} else
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE: {
double rotationAngleRadians = Math.atan2(currentX - x1 / 2, y1
- currentY);
rotationAngle = (int) Math.toDegrees(rotationAngleRadians);
break;
}
}
}
}
Well one glaring difference I see is this in your "separated" code. I don't see it in the original code, and it will definitely induce a lag, since you're sleeping 50ms every time you receive a touch event. That can happen many times per second with a drag-type movement.
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
try {
Thread.sleep(50);
....
Related
Please I need the help regarding Undo method , I tried to implement it like the code below but it is not remove the last color,
Kindly help me to resolve it.
awaiting your kind response.
Thanks in Advance.
MainActivity
public class MainActivity extends AppCompatActivity implements
View.OnTouchListener {
Button red, blue, yellow, undo;
Paint paint;
private RelativeLayout drawingLayout;
private MyView myView;
private ArrayList<Path> paths = new ArrayList<Path>();
private ArrayList<Path> undonePaths = new ArrayList<Path>();
/**
* Called when the activity is first created.
*/
/*
*
* private ImageView imageView; private Canvas cv; private Bitmap mask,
* original, colored; private int r,g,b; private int sG, sR, sB;
*/
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myView = new MyView(this);
drawingLayout = (RelativeLayout) findViewById(R.id.relative_layout);
drawingLayout.addView(myView);
red = (Button) findViewById(R.id.btn_red);
blue = (Button) findViewById(R.id.btn_blue);
yellow = (Button) findViewById(R.id.btn_yellow);
undo = (Button) findViewById(R.id.undo);
red.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
paint.setColor(Color.RED);
}
});
yellow.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
paint.setColor(Color.YELLOW);
}
});
blue.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
paint.setColor(Color.BLUE);
}
});
undo.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
myView.onClickUndo();
}
});
}
#Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
return false;
}
// flood fill
public class MyView extends View {
final Point p1 = new Point();
Bitmap mBitmap;
ProgressDialog pd;
Canvas canvas;
private Path path;
// Bitmap mutableBitmap ;
public MyView(Context context) {
super(context);
paint = new Paint();
paint.setAntiAlias(true);
pd = new ProgressDialog(context);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setStrokeWidth(5f);
mBitmap = BitmapFactory.decodeResource(getResources(),
R.drawable.gp1_1).copy(Bitmap.Config.ARGB_8888, true);
this.path = new Path();
}
public void onClickUndo() {
if (paths.size() > 0) {
undonePaths.add(paths.remove(paths.size() - 1));
invalidate();
} else {
Toast.makeText(getContext(), getString(R.string.nomore), Toast.LENGTH_SHORT).show();
}
}
#Override
protected void onDraw(Canvas canvas) {
this.canvas = canvas;
paint.setColor(Color.GREEN);
// int width = drawingLayout.getWidth();
// int height = drawingLayout.getHeight();
// float centerX = (width - mBitmap.getWidth()) * 0.5f;
//float centerY = (height - mBitmap.getHeight()) * 0.5f;
canvas.drawBitmap(mBitmap, 0, 0, paint);
///////////////////////////////
for (Path p : paths) {
canvas.drawPath(p, paint);
//////////////////////////
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
p1.x = (int) x;
p1.y = (int) y;
final int sourceColor = mBitmap.getPixel((int) x, (int) y);
final int targetColor = paint.getColor();
new TheTask(mBitmap, p1, sourceColor, targetColor).execute();
paths.add(path);
invalidate();
}
return true;
}
public void clear() {
path.reset();
invalidate();
}
public int getCurrentPaintColor() {
return paint.getColor();
}
class TheTask extends AsyncTask<Void, Integer, Void> {
Bitmap bmp;
Point pt;
int replacementColor, targetColor;
public TheTask(Bitmap bm, Point p, int sc, int tc) {
this.bmp = bm;
this.pt = p;
this.replacementColor = tc;
this.targetColor = sc;
pd.setMessage(getString(R.string.wait));
pd.show();
}
#Override
protected void onPreExecute() {
pd.show();
}
#Override
protected void onProgressUpdate(Integer... values) {
}
#Override
protected Void doInBackground(Void... params) {
FloodFill f = new FloodFill();
f.floodFill(bmp, pt, targetColor, replacementColor);
return null;
}
#Override
protected void onPostExecute(Void result) {
pd.dismiss();
invalidate();
}
}
}
public class FloodFill {
public void floodFill(Bitmap image, Point node, int targetColor,
int replacementColor) {
int width = image.getWidth();
int height = image.getHeight();
int target = targetColor;
int replacement = replacementColor;
if (target != replacement) {
Queue<Point> queue = new LinkedList<Point>();
do {
int x = node.x;
int y = node.y;
while (x > 0 && image.getPixel(x - 1, y) == target) {
x--;
}
boolean spanUp = false;
boolean spanDown = false;
while (x < width && image.getPixel(x, y) == target) {
image.setPixel(x, y, replacement);
if (!spanUp && y > 0
&& image.getPixel(x, y - 1) == target) {
queue.add(new Point(x, y - 1));
spanUp = true;
} else if (spanUp && y > 0
&& image.getPixel(x, y - 1) != target) {
spanUp = false;
}
if (!spanDown && y < height - 1
&& image.getPixel(x, y + 1) == target) {
queue.add(new Point(x, y + 1));
spanDown = true;
} else if (spanDown && y < height - 1
&& image.getPixel(x, y + 1) != target) {
spanDown = false;
}
x++;
}
} while ((node = queue.poll()) != null);
}
}
}
}
I guess you mean the undo method doesn't work. The possible reason is the previous drawing on the canvas is not removed. Try clearing the canvas before drawing in the onDraw() method.
#Override protected void onDraw(Canvas canvas) {
this.canvas = canvas;
canvas. drawColor(0,PorterDuff.Mode.CLEAR); //This clears the canvas.
paint.setColor(Color.GREEN);
//rest of the code
}
Seems it is impossible to return previous color it is required an array for each point to store the used color in every point.
I have an app for erasing the background, And I used a seekbar for changing the size of Eraser. but when I change the progress of SeekBar, the previous path change.
I want to change the path size without changing the previous paths
Main Activity
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.image_overlay_bitmap);
scratchView = (WScratchView) findViewById(R.id.scratch_view);
global = ((Global) getApplicationContext());
scratchView.setRevealSize(1);
SeekBar seekbar = (SeekBar) findViewById(R.id.myseek);
seekbar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
// TODO Auto-generated method stub
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
// TODO Auto-generated method stub
}
#Override
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
// TODO Auto-generated method stub
scratchView.setRevealSize(progress);
}
});
if (getIntent().getExtras().getBoolean("isFromCrop")) {
Log.i("width", "" + global.getBitmap().getWidth());
Log.i("height", "" + global.getBitmap().getHeight());
// set bitmap to scratchview
// Bitmap bitmap =
// BitmapFactory.decodeResource(getResources(),R.drawable.test);
DisplayMetrics displaymetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
/*
* int height = displaymetrics.heightPixels; int width =
* displaymetrics.widthPixels;
*/
int height = global.getBitmap().getHeight();
int width = global.getBitmap().getWidth();
Bitmap scaledBitmap = Bitmap.createBitmap(width, height,
Config.ARGB_8888);
float ratioX = width / (float) global.getBitmap().getWidth();
float ratioY = height / (float) global.getBitmap().getHeight();
float middleX = width / 2.0f;
float middleY = height / 2.0f;
Matrix scaleMatrix = new Matrix();
scaleMatrix.setScale(ratioX, ratioY, middleX, middleY);
Canvas canvas = new Canvas(scaledBitmap);
canvas.setMatrix(scaleMatrix);
canvas.drawBitmap(global.getBitmap(), middleX
- global.getBitmap().getWidth() / 2, middleY
- global.getBitmap().getHeight() / 2, new Paint(
Paint.FILTER_BITMAP_FLAG));
i = seekbar.getProgress();
scratchView.setRevealSize(i);
} else {
SharedPreferences settings = getApplicationContext()
.getSharedPreferences("pref", 0);
settings = getApplicationContext().getSharedPreferences("pref", 0);
String picture = settings.getString("file_path", "");
Bitmap mbitmap = BitmapFactory.decodeFile(picture);
scratchView.setScratchBitmap(mbitmap);
}
/*
* scratchView.setScratchBitmap(getResizedBitmap(global.getBitmap(),
* width, height));
*/
// scratchView.setOverlayColor(1);
//i = seekbar.getProgress();
// seekbar.setMax(100);
}
public Bitmap getResizedBitmap(Bitmap bm, int newHeight, int newWidth) {
int width = bm.getWidth();
int height = bm.getHeight();
float scaleWidth = ((float) newWidth) / width;
float scaleHeight = ((float) newHeight) / height;
Log.i("scalewidth", "" + scaleWidth);
Log.i("scaleheight", "" + scaleHeight);
// CREATE A MATRIX FOR THE MANIPULATION
Matrix matrix = new Matrix();
// RESIZE THE BIT MAP
matrix.postScale(scaleWidth, scaleHeight);
// RECREATE THE NEW BITMAP
Bitmap resizedBitmap = Bitmap.createBitmap(bm, 0, 0, width, height,
matrix, false);
return resizedBitmap;
}
private File captureImage() {
// TODO Auto-generated method stub
OutputStream output;
Calendar cal = Calendar.getInstance();
Bitmap bitmap = Bitmap.createBitmap(scratchView.getWidth(),
scratchView.getHeight(), Config.ARGB_8888);
bitmap = ThumbnailUtils.extractThumbnail(bitmap,
scratchView.getWidth(), scratchView.getHeight());
Canvas b = new Canvas(bitmap);
scratchView.draw(b);
// Find the SD Card path
File filepath = Environment.getExternalStorageDirectory();
// Create a new folder in SD Card
File dir = new File(filepath.getAbsolutePath() + "/demotemp/");
dir.mkdirs();
mImagename = "imageTemp" + ".png";
// Create a name for the saved image
file = new File(dir, mImagename);
// Show a toast message on successful save
Toast.makeText(ImageOverlayBitmap.this, "Image Saved to SD Card",
Toast.LENGTH_SHORT).show();
try {
output = new FileOutputStream(file);
// Compress into png format image from 0% - 100%
bitmap.compress(Bitmap.CompressFormat.PNG, 100, output);
output.flush();
output.close();
}
catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return file;
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
public void onClickHandler(View view) {
switch (view.getId()) {
case R.id.reset_button:
captureImage();
SharedPreferences settings = getApplicationContext()
.getSharedPreferences("pref", 0);
settings = getApplicationContext().getSharedPreferences("pref", 0);
SharedPreferences.Editor editor = settings.edit();
editor.putString("file_path", file.getPath());
editor.commit();
Intent i = new Intent(ImageOverlayBitmap.this,
SelectedImgActivity.class);
global.setfile_path(file.getPath());
i.putExtra("isBackgroundSet", false);
startActivity(i);
finish();
// scratchView.resetView();
break;
}
} }
Draw Activity
public WScratchView(Context ctx, AttributeSet attrs) {
super(ctx, attrs);
init(ctx, attrs);
}
public WScratchView(Context context) {
super(context);
init(context, null);
}
private void init(Context context, AttributeSet attrs) {
mContext = context;
// default value
mOverlayColor = DEFAULT_COLOR;
mRevealSize = DEFAULT_REVEAL_SIZE;
setZOrderOnTop(true);
SurfaceHolder holder = getHolder();
holder.addCallback(this);
holder.setFormat(PixelFormat.TRANSPARENT);
mOverlayPaint = new Paint();
mOverlayPaint.setXfermode(new PorterDuffXfermode(Mode.CLEAR));
mOverlayPaint.setStyle(Paint.Style.STROKE);
mOverlayPaint.setStrokeCap(Paint.Cap.ROUND);
mOverlayPaint.setStrokeJoin(Paint.Join.ROUND);
// convert drawable to bitmap if drawable already set in xml
if (mScratchDrawable != null) {
mScratchBitmap = ((BitmapDrawable) mScratchDrawable).getBitmap();
}
mBitmapPaint = new Paint();
mBitmapPaint.setAntiAlias(true);
mBitmapPaint.setFilterBitmap(true);
mBitmapPaint.setDither(true);
}
#Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (mScratchBitmap != null) {
if (mMatrix == null) {
float scaleWidth = (float) canvas.getWidth() / mScratchBitmap.getWidth();
float scaleHeight = (float) canvas.getHeight() / mScratchBitmap.getHeight();
mMatrix = new Matrix();
mMatrix.postScale(scaleWidth, scaleHeight);
}
canvas.drawBitmap(mScratchBitmap, mMatrix, mBitmapPaint);
} else {
canvas.drawColor(mOverlayColor);
}
for (Path path : mPathList) {
mOverlayPaint.setAntiAlias(mIsAntiAlias);
mOverlayPaint.setStrokeWidth(mRevealSize);
canvas.drawPath(path, mOverlayPaint);
}
}
private void updateScratchedPercentage() {
if(mOnScratchCallback == null) return;
mOnScratchCallback.onScratch(getScratchedRatio());
}
#Override
public boolean onTouchEvent(MotionEvent me) {
synchronized (mThread.getSurfaceHolder()) {
if (!mIsScratchable) {
return true;
}
switch (me.getAction()) {
case MotionEvent.ACTION_DOWN:
path = new Path();
path.moveTo(me.getX(), me.getY());
startX = me.getX();
startY = me.getY();
mPathList.add(path);
break;
case MotionEvent.ACTION_MOVE:
//if (mScratchStart) {
if (path.isEmpty()) {
path.lineTo(me.getX(), me.getY());
} else {
if (isScratch(startX, me.getX(), startY, me.getY())) {
mScratchStart = true;
}
updateScratchedPercentage();
break;
case MotionEvent.ACTION_UP:
mPathList.add(path);
// mScratchStart = false;
break;
}
return true;
}
}
private boolean isScratch(float oldX, float x, float oldY, float y) {
float distance = (float) Math.sqrt(Math.pow(oldX - x, 2) + Math.pow(oldY - y, 2));
if (distance > mRevealSize * 2) {
return true;
} else {
return false;
}
}
#Override
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
// do nothing
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mScratchedTestBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
mScratchedTestCanvas = new Canvas(mScratchedTestBitmap);
}
#Override
public void surfaceCreated(SurfaceHolder arg0) {
mThread = new WScratchViewThread(getHolder(), this);
mThread.setRunning(true);
mThread.start();
mScratchedTestBitmap = Bitmap.createBitmap(arg0.getSurfaceFrame().width(), arg0.getSurfaceFrame().height(), Bitmap.Config.ARGB_8888);
mScratchedTestCanvas = new Canvas(mScratchedTestBitmap);
}
#Override
public void surfaceDestroyed(SurfaceHolder arg0) {
boolean retry = true;
mThread.setRunning(false);
while (retry) {
try {
mThread.join();
retry = false;
} catch (InterruptedException e) {
// do nothing but keep retry
}
}
}
class WScratchViewThread extends Thread {
private SurfaceHolder mSurfaceHolder;
private WScratchView mView;
private boolean mRun = false;
public WScratchViewThread(SurfaceHolder surfaceHolder, WScratchView view) {
mSurfaceHolder = surfaceHolder;
mView = view;
}
public void setRunning(boolean run) {
mRun = run;
}
public SurfaceHolder getSurfaceHolder() {
return mSurfaceHolder;
}
#Override
public void run() {
Canvas c;
while (mRun) {
c = null;
try {
c = mSurfaceHolder.lockCanvas(null);
synchronized (mSurfaceHolder) {
if (c != null) {
mView.draw(c);
}
}
} finally {
if (c != null) {
mSurfaceHolder.unlockCanvasAndPost(c);
}
}
}
}
}
#Override
public void resetView() {
synchronized (mThread.getSurfaceHolder()) {
mPathList.clear();
}
}
#Override
public boolean isScratchable() {
return mIsScratchable;
}
#Override
public void setScratchable(boolean flag) {
mIsScratchable = flag;
}
#Override
public void setOverlayColor(int ResId) {
mOverlayColor = ResId;
}
#Override
public void setRevealSize(int size) {
Canvas canvas = new Canvas();
//mScratchedTestBitmap = Bitmap.createBitmap(mScratchedTestBitmap.getWidth(), mScratchedTestBitmap.getWidth(), Bitmap.Config.ARGB_8888);
//mScratchedTestCanvas = new Canvas(mScratchedTestBitmap);
canvas.drawBitmap(mScratchBitmap,mMatrix, mBitmapPaint);
mRevealSize = size;
}
#Override
public void setAntiAlias(boolean flag) {
mIsAntiAlias = flag;
}
#Override
public void setScratchDrawable(Drawable d) {
mScratchDrawable = d;
if (mScratchDrawable != null) {
mScratchBitmap = ((BitmapDrawable) mScratchDrawable).getBitmap();
}
}
#Override
public void setScratchBitmap(Bitmap b) {
mScratchBitmap = b;
}
#Override
public float getScratchedRatio() {
return getScratchedRatio(DEFAULT_SCRATCH_TEST_SPEED);
}
/**
* thanks to https://github.com/daveyfong for providing this method
*/
#Override
public float getScratchedRatio(int speed) {
if (null == mScratchedTestBitmap) {
return 0;
}
draw(mScratchedTestCanvas);
final int width = mScratchedTestBitmap.getWidth();
final int height = mScratchedTestBitmap.getHeight();
int count = 0;
for (int i = 0; i < width; i += speed) {
for (int j = 0; j < height; j += speed) {
if (0 == Color.alpha(mScratchedTestBitmap.getPixel(i, j))) {
count++;
}
}
}
float completed = (float) count / ((width / speed) * (height / speed)) * 100;
return completed;
}
public void setOnScratchCallback(OnScratchCallback callback) {
mOnScratchCallback = callback;
}
public static abstract class OnScratchCallback{
public abstract void onScratch(float percentage);
}
#Override
public void setScratchAll(boolean scratchAll) {
// TODO Auto-generated method stub
}
#Override
public void setBackgroundClickable(boolean clickable) {
// TODO Auto-generated method stub
} }
I noticed that in your onDraw() routine, you are setting the stroke width of every path to mRevealSize. Also, this mRevealSize is what is changed by the SeekBar.
I think what you need to do is capture the stroke width mRevealSize every time an erase path is made by the user, and store that stroke width in a list that complements mPathList. Then your onDraw() would have:
for (int i = 0; i < mPathList.size(); i++) {
mOverlayPaint.setAntiAlias(mIsAntiAlias);
mOverlayPaint.setStrokeWidth(mStrokeList.get(i));
canvas.drawPath(mPathList.get(i), mOverlayPaint);
}
I am a newbie in libgdx. I am working on a game which has a player body and I have given controls but I want to create enemies at specific time in my game. I have tried creating it but only the player body is been created and but not enemy body.
This is my code
public class Player
implements Screen, InputProcessor {
private Body polybody;
private Player player;
private World world;
private Body enemybody;
private Sprite polysprite;
public final float width, height;
private Vector2 movement = new Vector2();
private float speed = 580;
public Player(World world, float x, float y, float width) {
this.width = width; //IMP
height = width * 2;
BodyDef polygon = new BodyDef();
polygon.type = BodyType.DynamicBody;
polygon.position.set(x, y); //
PolygonShape poly = new PolygonShape();
poly.setAsBox(width / 2, height / 2); //
//fixture defn
FixtureDef polyfixture = new FixtureDef();
polyfixture.shape = poly;
polyfixture.friction = 0.8f; //
polyfixture.restitution = 0.1f; //
polyfixture.density = 3; //
//creating actual body
polybody = world.createBody(polygon);
polybody.createFixture(polyfixture);
// polybody.applyAngularImpulse(52, true);
polysprite = new Sprite(new Texture("img/car.jpg"));
polysprite.setSize(0.5f, 1); //size of mario
polysprite.setOrigin(polysprite.getWidth() / 2, polysprite.getHeight() / 2);
polybody.setUserData(polysprite);
poly.dispose();
}
public void update() {
polybody.applyForceToCenter(movement, true);
}
public Body getBody() {
return polybody;
}
#Override
public void show() {
// TODO Auto-generated method stub
}
final float step = 0.1f;
float timeElapsed = 0f;
#Override
public void render(float delta) {
timeElapsed += delta;
while (timeElapsed > step) {
timeElapsed -= step;
Enemy();
}
}
public void Enemy() {
BodyDef enemy = new BodyDef();
enemy.type = BodyType.DynamicBody;
enemy.position.set(6, 3);
PolygonShape enemypoly = new PolygonShape();
enemypoly.setAsBox(2, 2);
FixtureDef enemyfixture = new FixtureDef();
enemyfixture.shape = enemypoly;
enemyfixture.friction = 0.75f;
enemyfixture.restitution = 0.1f;
enemyfixture.density = 5;
enemybody = world.createBody(enemy);
enemybody.createFixture(enemyfixture);
enemypoly.dispose();
}
#Override
public void resize(int width, int height) {
// TODO Auto-generated method stub
}
#Override
public void pause() {
// TODO Auto-generated method stub
}
#Override
public void resume() {
// TODO Auto-generated method stub
}
#Override
public void hide() {
// TODO Auto-generated method stub
}
#Override
public void dispose() {
// TODO Auto-generated method stub
}
#Override
public boolean keyDown(int keycode) {
// TODO Auto-generated method stub
switch (keycode) {
case Keys.W:
movement.y = speed;
break;
case Keys.S:
movement.y = -speed;
break;
case Keys.D:
movement.x = speed;
break;
case Keys.A:
movement.x = -speed;
}
return true;
}
#Override
public boolean keyUp(int keycode) {
// TODO Auto-generated method stub
switch (keycode) {
case Keys.W:
movement.y = 0;
break;
case Keys.S:
movement.y = 0;
break;
case Keys.D:
movement.x = 0;
break;
case Keys.A:
movement.x = 0;
}
return true;
}
#Override
public boolean keyTyped(char character) {
// TODO Auto-generated method stub
return false;
}
#Override
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
// TODO Auto-generated method stub
movement.x = speed;
Gdx.app.log("Example", "touch done ");
return true;
}
}
This is the player class that gets called first and after this on render method the enemy method gets called. The player body is working fine but I couldn't see any enemy body. Please help .Thanks in advance !!
Apparently, your Player class is responsible for:
Handling inputs for controlling the game
the construction of enemy objects
rendering the entire world (handling time) and displaying the world and all objects
creating Textures (that is supposed to be created only once, not every time you make a Sprite!)
Aaaand you don't have any other class.
I think you should fix this problem.
Also, I'm a bit weary of that you're calling dispose() each time after you create an object.
By the way, the render() method only gets called if you set the active screen for the Game, so
public class MyGame extends Game {
...
MyScreen myScreen = new MyScreen();
...
public void goToMyScreen() {
this.setScreen(myScreen);
}
}
Something like that is necessary for render() to work.
And please check How to track time in Libgdx(android) on how to handle elapsed time.
I suggest a refactoring of your application. That class Player doesn't look like the right place for creating enemies (which you seem to do in every step). Instead you should create the Enemy in the same place where you create your Player and give your Enemy an own class.
Furthermore you could write debug messages to the console or use your IDE's debugger to check what your code is actually doing.
Sorry for my question , but i am stuck. I am new in develop game with lib gdx and don`t judge me strictly.
I have my game activity:
public class MyGame extends Game {
MenuScreen menu;
SplashScreen splash;
DefendScreen def;
#Override
public void create() {
// Gdx.app.log("LogGame", "MyGame create");
menu = new MenuScreen(this);
splash = new SplashScreen(this);
def = new DefendScreen(this);
setScreen(splash);
}
#Override
public void resize(int width, int height) {
}
#Override
public void render() {
super.render();
}
#Override
public void pause() {
super.pause();
}
#Override
public void resume() {
super.resume();
}
#Override
public void dispose() {
}
}
I have two screens :
public class MenuScreen implements Screen, InputProcessor {
public MenuScreen(final MyGame gam) {
game = gam;
cam = new OrthographicCamera();
cam.setToOrtho(false, 800, 480);
w = Gdx.graphics.getWidth();
h = Gdx.graphics.getHeight();
defScreen = new DefendScreen(game);
spriteBatch = new SpriteBatch();
stage = new Stage();
}
#Override
public void dispose() {
Gdx.app.log("LogGame", "splashs dispose");
Gdx.input.setInputProcessor(null);
try {
spriteBatch.dispose();
stage.dispose();
font12.dispose();
} catch (Exception e) {
}
}
#Override
public void hide() {
// TODO Auto-generated method stub
}
#Override
public void pause() {
}
#Override
public void render(float arg0) {
SetCamera(CAMERA_WIDTH / 2, CAMERA_HEIGHT / 2f);
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
stage.act(); // update all actors
stage.draw();
}
#Override
public void resize(int arg0, int arg1) {
}
#Override
public void resume() {
// TODO Auto-generated method stub
}
#Override
public void show() {
stage.addActor(new WorldMenu(new Texture(Gdx.files
.internal("images/bg/pause_back.png"))));
Gdx.input.setInputProcessor(stage);
FreeTypeFontGenerator generator = new FreeTypeFontGenerator(
Gdx.files.internal("font/trebuchet_ms.ttf"));
FreeTypeFontParameter parameter = new FreeTypeFontParameter();
parameter.size = 25;
font12 = generator.generateFont(parameter);
generator.dispose();
DrawLeftMeu();
DrawRightMeu();
DrawSetingsMenu();
}}
And game screen where i have pause button:
public class DefendScreen implements Screen, InputProcessor {
public DefendScreen(final MyGame gam) {
game = gam;
cam = new OrthographicCamera();
cam.setToOrtho(false, 800, 480);
startTime = TimeUtils.millis();
spriteBatch = new SpriteBatch();
stage = new Stage();
w = Gdx.graphics.getWidth();
h = Gdx.graphics.getHeight();
}
#Override
public void dispose() {
Gdx.app.log("LogGame", "defend dispose");
try {
combo0.dispose();
combo1.dispose();
combo2.dispose();
good0.dispose();
good1.dispose();
bad0.dispose();
bad1.dispose();
bad2.dispose();
bad3.dispose();
bad4.dispose();
music.dispose();
music.stop();
spriteBatch.dispose();
font.dispose();
pbar.dispose();
scores.dispose();
} catch (Exception e) {
}
}
#Override
public void hide() {
}
#Override
public void pause() {
// this.state = State.PAUSE;
}
#Override
public void render(float delta) {
SetCamera(CAMERA_WIDTH / 2, CAMERA_HEIGHT / 2f);
switch (state) {
case RUN:
RunGame();
break;
case PAUSE:
// do stuff here
break;
case RESUME:
break;
default:
break;
}
}
#Override
public void resize(int arg0, int arg1) {
}
#Override
public void resume() {
this.state = State.RESUME;
}
#Override
public void show() {
regions = new ArrayList<Integer>();
addRegions();
initSounds();
speedgame = speedgameEasy;
stage.addActor(worldActor);
stage.addActor(pauseActor);
startTime = TimeUtils.millis();
stage.addListener(clickList);
FreeTypeFontGenerator generator = new FreeTypeFontGenerator(
Gdx.files.internal("font/trebuchet_ms.ttf"));
FreeTypeFontParameter parameter = new FreeTypeFontParameter();
parameter.size = 25;
font = generator.generateFont(parameter);
generator.dispose();
pbar = new Texture(Gdx.files.internal("images/bg/line_indicator.png"));
scores = new Texture(
Gdx.files.internal("images/game_images/scorebox.png"));
Gdx.input.setInputProcessor(stage);
Gdx.input.setCatchBackKey(true);
}}
And my main questions !!!
--> what i must do that on pause action i can freeze the game action and call menu screen (whish have button resume)?
--> what i mus do in resume onclick to show game action resume?
on stackoverflow an other forums i find some explains about my question, which means to implement in resume some switch case with choices of game state, but i am do not understand how its realize in my code.
Thanks everyone.
In your game screen you should have a button (an actor added to the stage) which implements a ClickListener that calls either pause() or resume() depending on the current state of the game.
It should look something like this:
pauseButton.addListener(new ClickListener() {
public void clicked(InputEvent evt, float x, float y) {
if (!paused) Gdx.app.getApplicationListener().pause();
else Gdx.app.getApplicationListener().resume();
}
});
Where paused is a boolean variable in your game screen class.
In my opinion this is the easiest way to do this.
the main class is :
public class test extends Activity{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new Game(this,null));
}
}
the Game class is extended from the view class to allow us to draw the car and set its position, and I called the onkey method to control the direction and the angle of the car
public class Game extends View {
private Paint paint= new Paint();
float x,y;
float speed = 5,angle = 0,mod = 0;
Bitmap car;
Boolean b=false;
public Game(Context context, AttributeSet attrs) {
super(context, attrs);
try { // here I call the car image as a bitmap object
AssetManager assetManager=context.getAssets();
InputStream inputStream= assetManager.open("car.png");
BitmapFactory.Options options=new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.ARGB_4444;
car=BitmapFactory.decodeStream(inputStream,null,options);
inputStream.close();
Log.d("Bitmap Text", "bobrgb888.png format: "+car.getConfig());
} catch (Exception e) {
// TODO: handle exception
}
}
#Override
protected void onDraw(Canvas canvas) {
x += (speed*mod) * Math.cos(Math.PI/180 * angle);
y += (speed*mod) * Math.sin(Math.PI/180 * angle);
canvas.rotate((float) (Math.PI/180 * angle));
canvas.drawBitmap(car,-(car.getWidth()/2), -(car.getHeight()/2), null);
canvas.restore();
}
public boolean onKey(View view, int keyCode, KeyEvent event) {
switch (event.getAction()) {
case KeyEvent.ACTION_DOWN:
break;
case KeyEvent.ACTION_UP:
{if(event.getKeyCode() == KeyEvent.KEYCODE_A || event.getKeyCode() == KeyEvent.KEYCODE_B)
{
this.mod = 0;
}}
break;
case KeyEvent.ACTION_MULTIPLE:{
if(event.getKeyCode() == KeyEvent.KEYCODE_A)
{
mod = 1;
}
if(event.getKeyCode() == KeyEvent.KEYCODE_B)
{
mod = -1;
}
if(event.getKeyCode() == KeyEvent.KEYCODE_C)
{
angle -= 5;
}
if(event.getKeyCode() == KeyEvent.KEYCODE_D)
{
angle+=5;
}
}
break;
}
invalidate();
return event.getKeyCode() != KeyEvent.KEYCODE_BACK;
}
}
I set the next point's x and y
I rotate the image,following the chosen angle
I draw the car in the current position.
when the keys A or B, are up, the car stops
when the key is pressed for a long time ( A,B,C,D) , the angle and the direction change.
use this:
#Override
public boolean onKeyDown(View view, Editable arg1, int keyCode, KeyEvent event) {
instead of this:
public boolean onKey(View view, int keyCode, KeyEvent event) {