Hi I am not getting a smooth move, in my game train moves front and back it is nice, but train movement is not smooth(like not train move fixed speed and smooth). Please help............
public void run() {
Canvas canvas = null;
while (mRun) {
long beginTimeMillis, timeTakenMillis, timeLeftMillis;
canvas = mHolder.lockCanvas();
if (canvas != null) {
beginTimeMillis = System.currentTimeMillis();
gp.doDraw(canvas);
gp.animate();
timeTakenMillis = System.currentTimeMillis() - beginTimeMillis;
timeLeftMillis = (1000L / 30) - timeTakenMillis;
Log.i("timeLeftMillis"+timeLeftMillis,"");
mHolder.unlockCanvasAndPost(canvas);
if (timeLeftMillis < 5) {
timeLeftMillis = 5;
}
try {
TimeUnit.MILLISECONDS.sleep(timeLeftMillis);
} catch (InterruptedException ie) {
}
}
}
}
Edit: I don't know how to use the thread while getting a smooth move.
are you using View or SurfaceView. If your using View, use surfaceview. It will make your application much smoother.
Related
I want to build a dx ball game. In my game, I want to draw a ball, a bar, bricks individually. It means when ball position is ready, the ball will draw; when bricks are ready bricks will draw. In the normal way, I lock surface holder then draw everything. Example:
#Override
public void run() {
while(ballPlay){
try{
gameCanvas = null;
gameCanvas = surfaceHolder.lockCanvas();
gameCanvas.drawColor(Color.WHITE);
ballPosition.drawBall(gameCanvas);
for (int i = 0; i < brickCount; i++) {
brick[i].drawBrick(gameCanvas);
}
gameBar.drawBar(gameCanvas);
}catch (Exception e){
e.printStackTrace();
} finally {
if(gameCanvas!=null){
surfaceHolder.unlockCanvasAndPost(gameCanvas);
}
}
}
}
Then, we unlock it and post. But, how can I draw everything separately?
Currently I'm trying to implement a simple animation: I draw on the canvas of an Surfaceview and want to move a single-colored circle smoothly across the screen.
To achieve that I calculate a slightly moved circle, draw the canvas and let the thread then sleep for a few miliseconds. This doesn't run very smoothly.
So I found the animator object of google, that was written for that use. Does it something different then my code or will it just similarly calculate the moved circle every few miliseconds?
Here is the code I use for the drawing:
public void run() {
circle= new Circle(getRandPoint());
Canvas canvas = null;
while (running) {
if(!circle.IsMoving()){
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
newPos = getRandPoint();
circle.setNewPos(newPos);
}
circle.calculateMovement();
// PAINT
try {
canvas = holder.lockCanvas();
synchronized (holder) {
draw(canvas);
}
} finally {
if (canvas != null) {
holder.unlockCanvasAndPost(canvas);
}
}
// WAIT
try {
Thread.sleep(30); // Wait some time until I need to display again
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
And here are the important methods of my Circle class:
public void setNewPos(Point p){
nPosX = p.x;
nPosY = p.y;
dx = (nPosX - posX);
dy = (nPosY - posY);
// normalize dx and dy and multiply it by speed
double dxdy = Math.abs(dx+dy);
dx = dx/dxdy;
dy = dy/dxdy;
dx *= speed;
dy *= speed;
}
public void calculateMovement(){
posX += dx;
posY += dy;
}
Thanks for every answer.
Does it something different then my code or will it just similarly calculate the moved circle every few miliseconds?
Android's animation framework does a number of things that your code does not. Some of the convenient things it offers out of the box are the ability to pause animations, or play animations on different views in coordination with each other (either at the same time or in sequence, for example).
It also has the distinct benefit of already being written and tested, so you don't need to do that yourself.
There are some much bigger benefits that you can from the framework though-
First, one issue that you have in your code is that it doesn't care about when your graphics are actually rendered on screen. By blindly delaying for 30 milliseconds, you could be skipping GPU frames or performing draws that won't actually be visible to the user. The framework's animation functions are optimized to avoid these issues. This is likely the source of the jank you are seeing in your implementation.
Second, the framework provides the ability to define more authentic motion through the use of interpolators. Real objects don't move in a linear fashion, so using an interpolator allows you to define more realistic motion, such as slowing down as the animation reaches the final position.
I'm writing my very first android game. The graphics are primitive, some rectangles moving through the screen. The game seems smooth but with occasional stutters, every 0.5 - 1.0 secs, and I can't figure out what's causing it. I've already eliminated all the GC calls inside my draw / update routines, enabled hw acceleration in my surfaceView, activity and in the manifest file.
This is how my game loop looks like currently (taken from some sort of tutorial):
public void run() {
while (!terminated) {
if (!gameEngine.isRunning())
continue;
Canvas canvas = null;
try {
canvas = surfaceHolder.lockCanvas();
synchronized (surfaceHolder) {
long beginTime = SystemClock.elapsedRealtime();
int framesSkipped = 0;
gameEngine.update();
if(canvas != null)
gameEngine.draw(canvas);
long timeDiff = SystemClock.elapsedRealtime() - beginTime;
int sleepTime = (int) (FRAME_PERIOD - timeDiff);
if (sleepTime > 0) {
try {
Thread.sleep(sleepTime);
} catch (InterruptedException ignored) {
}
}
while (sleepTime < 0 && framesSkipped < MAX_FRAME_SKIPS) {
gameEngine.update();
sleepTime += FRAME_PERIOD;
framesSkipped++;
}
}
} finally {
if (canvas != null)
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
}
If I log the value of timeDiff at every frame, it stays in the 5-15 range, so it doesn't indicate the stutters.
I'm using SystemClock.elapsedRealtime() instead of System.currentTimeMillis() because I've read that System.currentTimeMillis isn't accurate enough. (Or should I be using System.nanoTime() ?)
This isn't the first solution I tried using, and none of them have so far solved my issue. So I suspect the problem may lie somewhere else. I appreciate any help!
Hi I am working on plotting a real time graph of incoming signals using SurfaceView.
The sampling rate is 128Hz and the target graph refresh rate is 50Zh.
Things run pretty smoothly, the points are drawn real-time properly.
I plot the data in segments of a few points using Path()
for each segment I call path.computeBounds() to get a rect that I will use to call holder.lockCanvas(rect) and draw the path. Using a rect prevents flickering and reduces cpu usage
when the graph reaches the end I lock the entire canvas and clear the background, draw the graph frame and then continue on plotting.
the problem is that at the beginning of each new "page" I get a ghost image from the last page:
I believe this is caused by double buffering / use of a dirty area when plotting.
I have looked for solutions to this problem but none seem adequate for this type of application. Any help is most welcome.
Thanks
Jean-Pierre
Code follows:
private void draw() {
Point point = null;
Canvas canvas = null;
Path path = new Path();
ArrayList<Point> pointArray;
float oldX = -1;
boolean setToClear = false;
boolean isNewSegment = false;
if (samplesInQueue == 0) {
return;
}
pointArray = new ArrayList<Point>((int) samplesInQueue);
for (int i = 0; i < samplesInQueue; i++) {
// take a peek at the point without retrieving it from the point
// queue
point = Points.peek();
// check if first point of segment is the start of a page
if (i == 0) {
if (lastSegmentEndPoint != null) {
if (point.x < lastSegmentEndPoint.x) {
// yes then we will need to clear the screen now
isNewSegment = true;
}
} else {
// yes then we will need to clear the screen now
isNewSegment = true;
}
}
if (point != null) {
if (point.x > oldX) {
// put consecutive points in the path point array
point = Points.poll();
samplesInQueue--;
pointArray.add(point);
oldX = point.x;
} else {
// we have a wrap around, stop and indicate we need to clear
// the screen on the next pass
if (!isNewSegment) {
setToClear = true;
}
break;
}
}
}
// no points, return
if (pointArray.size() == 0) {
return;
}
// fill the path
for (int i = 0; i < pointArray.size(); i++) {
Point p = pointArray.get(i);
if (i == 0) {
if (lastSegmentEndPoint != null) {
if (p.x >= lastSegmentEndPoint.x) {
// if we have the end of the last segment, move to it
// and line to the new point
path.moveTo(lastSegmentEndPoint.x, lastSegmentEndPoint.y);
path.lineTo(p.x, p.y);
} else {
// otherwise just line to the new point
path.moveTo(p.x, p.y);
}
} else {
path.moveTo(p.x, p.y);
}
} else {
path.lineTo(p.x, p.y);
}
}
if (clear || isNewSegment) {
if (clear) {
clear = false;
}
// we need to clear, lock the whole canvas
canvas = holder.lockCanvas();
// draw the graph frame / scales
drawGraphFrame = true;
drawGraphFrame(canvas);
} else {
// just draw the path
RectF bounds = new RectF();
Rect dirty = new Rect();
// calculate path bounds
path.computeBounds(bounds, true);
int extra = 0;
dirty.left = (int) java.lang.Math.floor(bounds.left - extra);
dirty.top = (int) java.lang.Math.floor(bounds.top - extra);
dirty.right = (int) java.lang.Math.round(bounds.right + 0.5);
dirty.bottom = (int) java.lang.Math.round(bounds.bottom + 0.5);
// just lock what is needed to plot the path
canvas = holder.lockCanvas(dirty);
}
// draw the path
canvas.drawPath(path, linePaint);
// unlock the canvas
holder.unlockCanvasAndPost(canvas);
// remember last segment end point
lastSegmentEndPoint = pointArray.get(pointArray.size() - 1);
// set clear flag for next pass
if (setToClear) {
clear = true;
}
}
Draw frame / clear graph code
private void drawGraphFrame(Canvas canvas) {
if (!drawGraphFrame) {
return;
}
if (canvas == null) {
Log.e(TAG, "trying to draw on a null canvas");
return;
}
drawGraphFrame = false;
// clear the graph
canvas.drawColor(Color.BLACK, Mode.CLEAR);
// draw the graph frame
canvas.drawLine(leftMargin, topMargin, leftMargin, mCanvasHeight - bottomMargin, framePaint);
canvas.drawLine(leftMargin, mCanvasHeight - bottomMargin, mCanvasWidth - rightMargin, mCanvasHeight
- bottomMargin, framePaint);
// more drawing
}
Your problem is quite straight forward.. your only locking the new portion of the canvas that the new path covers. So the best thing to do is to make your path and dirty rect's private members of your class. Then at the start of your draw method get the path's current bounds (the old bounds) in your dirty rect. Now call path.rewind(); and start modifying your path. After do a union on the dirty rect with the new bounds. Now your dirty rect covers the old and new rect's. So your clear will remove the old path. This also reduces overhead because you don't want to be allocating 100+ objects per second for rect's and path's. Now since your drawing an oscilloscope then you probably want to adjust the old bounds to only be a portion of the width of the view. The same amount your new portion covers.
Hope that's cleared things up.
My simple answer is just using this function clear_holder() wherever you want to clear the canvas. I copy and paste 3 line for 3 times because it need 3 times clear to leave holder blank.
After clearing holder, you should draw any new thing you want!
This link give me this source code!
private void clear_holder(SurfaceHolder holder){
Canvas c = holder.lockCanvas();
c.drawColor( 0, PorterDuff.Mode.CLEAR );
holder.unlockCanvasAndPost(c);
c = holder.lockCanvas();
c.drawColor( 0, PorterDuff.Mode.CLEAR );
holder.unlockCanvasAndPost(c);
c = holder.lockCanvas();
c.drawColor( 0, PorterDuff.Mode.CLEAR );
holder.unlockCanvasAndPost(c);
}
It looks like you are clearing the canvas so, it's not double buffering problem. I think it's related to your path been reused.
Try adding adding the next line when starting new page.
path.reset();
I'm trying to do a menu based on bitmaps. The menu itself should be movable through screentouch move events, basically I want to drag the buttons around on the view. The button also includes collision detection, so whenever they touch they bounce from each other.
But I have some problems when it comes to drawing my bitmaps. Currently I'm using a rectangle to scale my bitmap to fit the window of my device. Want i want and can not get currently is for smoother movements of my bitmaps without flickering. Is the only option to move to open gl? Or have I missed something big in my code?
This is in my surfaceview for drawing each button, where MenuButton is the class that holds the bitmap and updates its position according to a touch and drag move.
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.WHITE);
for(MenuButton menuButton : menuButtonSprites) {
menuButton.onDraw(canvas);
}
}
I want the bitmaps to scale to each device's width and for that i use a rectangle for the bitmap to fit in.
public MenuButton(MenuView v, Bitmap bmp, int yPosition){
this.menuView = v;
this.menuButton = bmp;
this.xMax = v.getWidth();
this.yPosistion = yPosition;
menuButtonRectangle = new Rect(xMin, this.yPosistion-yMin, xMax, this.yPosistion+yMax);
}
public void update(int y){
if(menuButtonPressed)
{
this.yPosistion = y;
menuButtonRectangle.set(xMin, yPosistion-yMin, xMax, yPosistion+yMax);
}
}
public void onDraw(Canvas canvas){
canvas.drawBitmap(menuButton, null, menuButtonRectangle, null);
}
I also have a thread that updates the draw
public void run() {
long ticksPS = 1000 / FPS;
long startTime;
long sleepTime;
Canvas c = null;
while (running) {
startTime = System.currentTimeMillis();
try {
c = view.getHolder().lockCanvas();
synchronized (view.getHolder()) {
view.onDraw(c);
}
}
finally {
if (c != null) {
view.getHolder().unlockCanvasAndPost(c);
}
}
sleepTime = ticksPS - (System.currentTimeMillis() - startTime);
try {
if (sleepTime > 0)
sleep(sleepTime);
else
sleep(10);
}
catch (Exception e) {
}
}
}
I don't really know what I'm doing wrong and why i can't manage to get a smooth movements of my buttons. Is it a downside for using canvas or have I missed something really important :D?
Usually This problem occurs when there is sync problem exists while painting. This may due to the higher Frame rate or also may be the lower frame rate. These kind of issue can be fixed by Double buffering or adjusting the Frame Rate.
Double buffering means, Instead of drawing the Image directly on to the main canvas, we will be creating an empty bitmap of screen size and getting the graphics object. Drawing every thing on to the bitmap then directly drawing this bitmap to the main canvas.