How to move a sprite device-independent along the x-axis (libgdx) - android

I've a Sprite that I draw in the render method, I also set the position (x and y) on the screen there while drawing.
The render method looks like this for me (Doesn't work with the try and catch below and it would not be device independent):
#Override
public void render(float delta) {
game.batch.begin();
game.batch.draw(backgroundgame, 0, 0, Gdx.graphics.getWidth(),
Gdx.graphics.getHeight());
game.batch.draw(car.sprite, xcar,
(ycar));
game.batch.end();
/*try {
xcar++;
this.wait(50);
game.batch.end();
} catch (Exception e) {
e.printStackTrace();
}*/
}
In the consructor of the class I set the x and y-position of the sprite.
I was just wondering how I can move the sprite along the x-axis device-independent? Can I do it in the render method or do I need a new Thread for the Sprite?
Any help is much appreciated!

Every frame, if you want to move the sprite along x axis, do:
sprite.setposition(lastx + 1*Gdx.graphics.getdeltatime(), some y)
lastx = sprite.getX()
And do not do batch.draw() instead use sprite.draw(batch). Batch.draw uses sprite as a dumb texture with no position. With sprite.draw, it does all the position and size drawing for you.
And threading in games is a bad thing to do. Never use threads unless you absolutely need to.
I. E. Loading something
Everything in games is done each frame(using the main thread). Or else you get sync issues with other threads and it becomes a mess.
And that's why you get fps drops and lag in games if your hardware cannot run them, because the time to process all the commands per frame becomes noticeable.

Related

Any way to get touch coordinates from non-UI thread

If I have an openGL app that has 2 threads (not created by me, these are the standard 'provided' threads). Those being:
GLRendering thread
Main / UI thread
And lets say that in my rendering thread I draw a sprite like so: (The methods shown are my own methods)
sprite.draw(); //This will draw the sprite at it's own internal X and Y coordinates
Now, on the UI Thread, I capture the current finger position: (The following occurs within onTouchEvent(MotionEvent event))....
case MotionEvent.ACTION_MOVE: {
sprite.setX(event.getX());
sprite.setY(event.setY());
}
So, what happens is that my sprite is drawn where the finger is allowing the user to drag it around the screen.
However, clearly, the two threads aren't guaranteed to run 'alternately' like so:
UI Thread: Capture finger position and set (X:10, Y:10)
Renderer Thread: Draw at 10, 10
UI Thread: Capture finger position and set (X:22, Y:31)
Renderer Thread Draw at 22, 31 etc.......
The above is great, but what happens when this occurs:
UI Thread: Capture finger position and set (X:10, Y:10)
Renderer Thread: Draw at 10, 10
Renderer Thread: Draw at 10, 10 << Draws again at the same position even though the finger has physically now moved to a different location causing an offset between object's on-screen position and the finger's physical positionon the screen
UI Thread: Capture finger position and set (X:22, Y:31)
Renderer Thread Draw at 22, 31 etc.......
This can seem to cause 'choppiness' in the drawing of the object.
So, what I'm asking is, is there any way for force the Rendering thread to somehow retrieve the actual current physical position of the currently-down pointer/finger before it draws it? Or some other solution to the problem? (Put simply the problem being that the rendering thread should always have access to the current position and not the previous position).
The short answer is NO!
The problem you are experiencing is not due to the two threads running in parallel. Instead, it is due to the fact that either
Your frame rate is too low
Your movement is so fast that choppiness becomes visible.
Solution to the first problem is to profile your app and reduce the lag time - try to hit the nominal frame rate of 60fps.
The solution to the second problem, however, is just a small trick. Instead of adjusting the position of the sprite to be exactly your touch points, make it move towards the touch point.
A crude implementation is like this:
case MotionEvent.ACTION_MOVE: {
sprite.setNewX(event.getX());
sprite.setNewY(event.setY());
}
In your Sprite Class add these:
private int mNewX, mNewY;
public void setNewX(int x){
mNewX = x;
}
public void setNewY(int y){
mNewY = y;
}
add these two lines to your draw method of your Sprite class:
public void draw(){
this.x = this.x + (int)(0.5 * (this.newX-this.x));
this.y = this.y + (int)(0.5 * (this.newY-this.y));
// of course, you can get rid of the "this" keywords above. I just put them there for the sake of clarity.
// drawing stuff
}

Objects not moving at the same speed, when Thread sleeps for a millisec

I am currently trying to move some rectangle objects (displayed as bitmaps on my surfaceview).
They should all move with the same speed, therefor my code looks like this:
new Thread (new Runnable()
{
#Override
public void run()
{
while(true)
{
newTime = System.currentTimeMillis();
frameTime = newTime - currentTime;
currentTime = newTime;
physics(frameTime);
try {
Thread.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}).start();
i move my rectangle objects in the physics method based on the frametime parameter.
So my problem is the following: with the code i just posted all my rectangles move at the same speed, but the graphics are lagging. The lag disappears as soon as i remove the Thread.sleep(1), but then my rectangle objects wont move with the same speed anymore (some rectangles move faster than others).
any ideas?
Edit:
the physics and movedown methods are just normal methods in my classes, both are not in any threads or something. they are only getting called from my Thread i posted above
public void physics(double delta)
{
for(int i=0; i<=5; i++)
{
rectangles[i].moveDown(delta);
}
}
public void moveDown(double delta)
{
setY((double) (getY() + ((sH)*(delta/1000))));
//sH is the screen height
}
Edit2:
Graphics code
while(true)
{
if(!ourHolder.getSurface().isValid())
{
continue;
}
Canvas canvas = ourHolder.lockCanvas();
synchronized(ourHolder) {
graphics(canvas);
// in this method all the drawings happen
// e.g. canvas.drawBitmap
}
ourHolder.unlockCanvasAndPost(canvas);
}
It is difficult to analyse given the code you posted, since it's unclear what physics(frameTime); is actually doing. It seems like each moving rectangle is updated in its own Thread. Then the result you get has to be expected because one thread or the other will be called more often than the others depending on thread scheduling. Instead, use one single thread to control your simulation (e.g. update your frameTime and provide it to the other threads). However, IMHO you have to rethink your architecture.
It's hard to tell from your posted code what the problem could be, but one thing I notice is that you could experience some clock drift. See: Does time jump in android devices?.
Although, it looks like you are moving the rectangles using a fixed offset, so even if there were clock drift, I would expect them to jump around but by the same amount. So I agree with Axel that there appears to be some thread interaction going on.
How are you drawing to the screen? If you have another thread processing the graphics, the two threads could get out of sync and you'll need to ensure you are locking things properly. If you are using the deltas to update the location on the screen in your paint method, maybe instead use an absolute position that you update in your physics() method and draw based on that. It seems you probably need to rethink some of the architecture.

Libgdx Rendering Textures vs Sprites

I am trying to build my first game with Libgdx and Box2d.
The game has a similar concept as Flappy Bird. My issue is rendering the pipes.
I have tried drawing rectangles and then drawing new sprite which I can size down to different pipe sizes every time the render method is called. the issue with doing so is that I cant dispose of the texture once the rectangle leaves the screen because it will make all the other rectangles that are still visible lose their texture. if I don't dispose of the texture once it leaves the screen it will make the game very slow after 20 seconds.
The other option is to use about 10 different textures for different pipe sizes but still there is the issue of disposing of the textures.
I would appreciate any suggestions how to efficiently render different pipe sizes. I have attached my render code below
#Override
public void render(float delta) {
Gdx.gl.glClearColor(0,0,0,0);
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
world.step(BOX_STEP, BOX_VELOCITY_ITERATIONS, BOX_POSITION_ITERATIONS);
batch.setProjectionMatrix(camera.combined);
batch.begin();
//background.setPosition(camera.position.x-camera.viewportWidth/2, camera.position.y-14);
//background.draw(batch);
batch.end();
//bg1.update();
//bg2.update();
updateAnimation();
if((TimeUtils.nanoTime()/10) - (lastDropTime/10) > 300000000)
createPipes();
batch.begin();
for(Rectangle raindrop: raindrops) {
pipe_top.setSize(4, raindrop.height);
pipe_top.setPosition(raindrop.x, raindrop.y);
pipe_top.draw(batch);
pipe_bottom.setSize(4, raindrop.height);
pipe_bottom.setPosition(raindrop.x, camera.position.y + (camera.viewportHeight/2-pipe_bottom.getHeight()));
pipe_bottom.draw(batch);
}
batch.end();
if(pipe.getX() < 0){
pipe.getTexture().dispose();
}
Iterator<Rectangle> iter = raindrops.iterator();
while(iter.hasNext()) {
Rectangle raindrop = iter.next();
raindrop.x -= 4 * Gdx.graphics.getDeltaTime();
if(raindrop.x < -35) iter.remove();
}
debug.render(world, camera.combined);
}
You have to maintain the render() method as fast as possible. Loading resources is pretty slow, so you should create your textures and sprites in the create() method.
Also, you don't need as many sprites as raindrops, you can reuse the same sprite, change its position and size and draw it multples times.
Hope this helps.

Confusion over Canvas/OpenGl Techniques

I'm a completely newbie to android programming, having done some java for my computing levels but nothing too complex!
I'm working on a game where an object falls down the screen and has to be sorted into the relevant 'box' when it reaches the bottom.
I've got a surface view running with a thread etc, using canvas draw methods, however, i can't for the life of me see how i will be able to make the falling object reach a speed where it'll present a challenge to the user.
Running the thread with a change of 1 in the y direction causes the object to crawl down the screen. Greater changes in Y lead to jumpy graphics.
Would OpenGL make any difference or are there other canvas methods i can implement?
Hope that makes sense!
Thanks in advance
----Thread------
public void run()
{
Canvas canvas;
while(running)
{
canvas = null;
try{
canvas = this.surfaceholder.lockCanvas();
synchronized(surfaceholder)
{
gamepanel.Check();
this.gamepanel.onDraw(canvas);
}
}finally
{
if(canvas != null)
{
surfaceholder.unlockCanvasAndPost(canvas);
}
}
}
}
----SurfaceView-------
protected void onDraw(Canvas canvas){
canvas.drawBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.gamebackground), 0, 0, null);
SortItOut.sortitout.Letter.draw(canvas);
}
-----Letter----- (Each object is a different letter)
public static void draw(Canvas canvas)
{
y += 1;
canvas.drawBitmap(LetterObject, x, y, null);
}
Those are the methods i would believe are relevant (The Check method is simply to check whether the object has reached the bottom of the screen).
You must load all your bitmaps in the constructor for the SurfaceView, never in onDraw()
Aside from the bitmap loading problem, you can make it fall faster my increasing the rate of the y change. If you do it too much, the box will appear to jump, but I bet you could get away with up to 10 pixel changes before that would happen (experiment).
You would only need to do OpenGL in this case if performance was slowing you down. I don't think that's the case. Although, I would stop loading the bitmap in the onDraw method and put it in the onCreate or some constructor. onDraw gets called hundreds of times and that's killing your app.

Timer task not being performed accurately

I am trying to perform basic task of rotating a canvas 20 times a
second using timer but it doesn't seem to be working properly and its
lagging. for example, if I rotate rectangle 0.3 degrees per 50 ms it
should rotate 6 degree in on second, but that is not the case. It
really slow in rotation. Here is my sample code:
//Code for update task
class UpdateTimeTask extends TimerTask {
public void run() {
hndView.post(new Runnable() {
public void run() {
hndView.invalidate(); //this code invalidates custom view that calls onDraw to draw rotated hand
}
});
}
}
//Code for onDraw method of custom view that needs to be update
#Override
protected void onDraw(Canvas canvas){
super.onDraw(canvas);
//ang is angle to rotate and inc is float value of 0.3 degree to be incremented
ang = ang + inc;
if (ang >= 360) ang = ang - 360;
canvas.rotate(ang, canvas.getWidth()/2, canvas.getHeight()/2);
canvas.drawRect((canvas.getWidth()/2 - 2), (canvas.getHeight()/2 - 125), (canvas.getWidth()/2 + 2), (canvas.getHeight()/2 + 10), mTextPaint);
canvas.restore();
}
//code to schedule task
Timer timer = new Timer();
UpdateTimeTask tt = new UpdateTimeTask();
timer.schedule(tt, 0, 50);
Can anyone please tell me what am I doing wrong here? Should I used
different approach to perform this task? Because its hard to believe
that you cannot have simple smooth rotation of rectangle 20 times in
one second.
Timer/TimerTask are not supposed to be precise and are not supposed to be used for this purpose. Follow the recipes for 2D game development, such as the LunarLander sample that is included in your SDK. Or, you could just search StackOverflow and find all sorts of useful posts on the subject.
I believe you are not using a SurfaceView.
Drawing like that to a canvas was meant for controls and not fast rendering(read >10fps)
If you want performance you need either to use a SurfaceView where you'll average a 25-30 fps or opengl
Please read : http://developer.android.com/guide/topics/graphics/index.html
The number of calls to invalidate need not equal the number of calls to onDraw. If your timer ends up running twice successively before the UI thread gets a chance to run, then the double invalidate will end up only causing a single rotation. Consider putting in debug code to validate the number of calls to those two methods.

Categories

Resources