Android game crashes FATAL EXCEPTION main - java

My app has 2 activities a main menu and a game play activity. you click play to start the game play and when you die you can click back to go to the main menu. For some reason when i click play for the third time (meaning ive died and went back to the main menu twice) the game crashes with this error.
FATAL EXCEPTION: main
Process: com.example.jordanschanzenbach.myapplication, PID: 1875
java.lang.OutOfMemoryError: Failed to allocate a 360012 byte allocation with 79976 free bytes and 78KB until OOM
at dalvik.system.VMRuntime.newNonMovableArray(Native Method)
at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:700)
at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:535)
at android.graphics.BitmapFactory.decodeResource(BitmapFactory.java:558)
at android.graphics.BitmapFactory.decodeResource(BitmapFactory.java:588)
at com.example.jordanschanzenbach.myapplication.Obstacle.<init>(Obstacle.java:44)
at com.example.jordanschanzenbach.myapplication.ObstacleManager.populateObstacles(ObstacleManager.java:57)
at com.example.jordanschanzenbach.myapplication.ObstacleManager.<init>(ObstacleManager.java:38)
at com.example.jordanschanzenbach.myapplication.GamePlayScene.<init>(GamePlayScene.java:41)
at com.example.jordanschanzenbach.myapplication.GamePanel.<init>(GamePanel.java:29)
at com.example.jordanschanzenbach.myapplication.MainActivity.onCreate(MainActivity.java:27)
that's not the entire error message but i think i gave you what you needed. Now i tried to make an animation for the obstacles to be spikes instead of just black rectangles but for some reason the spikes will not display and i think it might correspond with the error i receive. But i don't understand why the spikes wont display as i used the same code for the animation for my player.
here is the code for my obstacle
public class Obstacle implements GameObject
{
private Rect rectangle;
private Rect rectangle2;
private int color;
private Animation falling;
private Animation fallingStill;
private Animation fallingAgain;
private AnimationManagerObstacle animationManagerObstacle;
public Rect getRectangle()
{
return rectangle;
}
public void IncrementY(float y )
{
rectangle.top += y;
rectangle.bottom += y;
rectangle2.top += y;
rectangle2.bottom += y;
}
public Obstacle(int rectHeight, int color, int startX, int startY, int playerGap)
{
this.color = color;
BitmapFactory bitfac = new BitmapFactory();
Bitmap fallings = bitfac.decodeResource(GlobalVariables.CURRENT_CONTEXT.getResources(), R.drawable.spikesupsidedown);
Bitmap fallingStills = bitfac.decodeResource(GlobalVariables.CURRENT_CONTEXT.getResources(), R.drawable.spikesupsidedown);
Bitmap fallingAgains = bitfac.decodeResource(GlobalVariables.CURRENT_CONTEXT.getResources(), R.drawable.spikesupsidedown);
falling = new Animation(new Bitmap[]{fallings}, 2);
fallingStill = new Animation(new Bitmap[]{fallings, fallingStills}, 0.5f);
fallingAgain = new Animation(new Bitmap[]{fallings, fallingAgains}, 0.5f);
animationManagerObstacle = new AnimationManagerObstacle(new Animation[]{falling, fallingStill, fallingAgain});
rectangle = new Rect(0, startY, startX, startY + rectHeight);
rectangle2 = new Rect(startX + playerGap, startY, GlobalVariables.SCREEN_WIDTH, startY + rectHeight);
}
public boolean playerCollide(RectPlayer player)
{
return Rect.intersects(rectangle, player.getRectangle()) || Rect.intersects(rectangle2, player.getRectangle());
}
#Override
public void draw(Canvas canvas)
{
Paint paint = new Paint();
paint.setColor(color);
animationManagerObstacle.draw(canvas, rectangle);
canvas.drawRect(rectangle, paint);
canvas.drawRect(rectangle2, paint);
}
#Override
public void update()
{
animationManagerObstacle.update();
}
public void update(Point point)
{
float oldTop = rectangle.top;
rectangle.set(point.x - rectangle.width() / 2,
point.y - rectangle.height() / 2,
point.x + rectangle.width() / 2,
point.y + rectangle.height() / 2);
int state = 0;
if (rectangle.left - oldTop > 1)
{
state = 1;
}
else if (rectangle.left - oldTop < 2)
{
state = 2;
}
animationManagerObstacle.playAnim(state);
animationManagerObstacle.update();
}
}
this is the line that the error message points to
Bitmap fallings = bitfac.decodeResource(GlobalVariables.CURRENT_CONTEXT.getResources(), R.drawable.spikesupsidedown);
here is my obstacle manager where i add and display the obstacles
public class ObstacleManager
{
private ArrayList<Obstacle> obstacles;
private int playerGap;
private int obstacleGap;
private int obstacleHeight;
private int color;
private long startTime;
private long initTime;
private int score = 0;
public ObstacleManager(int playerGap, int obstacleGap, int obstacleHeight, int color)
{
this.playerGap = playerGap;
this.obstacleGap = obstacleGap;
this.obstacleHeight = obstacleHeight;
this.color = color;
startTime = initTime = System.currentTimeMillis();
obstacles = new ArrayList<>();
populateObstacles();
}
public boolean playerCollide(RectPlayer player)
{
for(Obstacle ob : obstacles)
{
if(ob.playerCollide(player))
return true;
}
return false;
}
private void populateObstacles()
{
int currY = -5 * GlobalVariables.SCREEN_HEIGHT / 4;
while(currY < 0)
{
int xStart = (int)(Math.random()*(GlobalVariables.SCREEN_WIDTH - playerGap));
obstacles.add(new Obstacle(obstacleHeight, color, xStart, currY, playerGap));
currY += obstacleHeight + obstacleGap;
}
}
public void update()
{
if (GlobalVariables.GAMEOVER)
{
for (int i = 0; i < 3; i++)
{
obstacles.remove(obstacles.size() - 2);
}
}
int elapsedTime = (int)(System.currentTimeMillis() - startTime);
startTime = System.currentTimeMillis();
float speed = (float)(Math.sqrt((1 + startTime - initTime) / 1750.0)) * GlobalVariables.SCREEN_HEIGHT /17500.0f;
for(Obstacle ob : obstacles)
{
ob.IncrementY(speed * elapsedTime);
}
if(obstacles.get(obstacles.size() - 1).getRectangle().top >= GlobalVariables.SCREEN_HEIGHT * 3/4)
{
int xStart = (int)(Math.random()*(GlobalVariables.SCREEN_WIDTH - playerGap));
obstacles.add(0, new Obstacle(obstacleHeight, color, xStart,
obstacles.get(0).getRectangle().top - obstacleHeight - obstacleGap, playerGap));
obstacles.remove(obstacles.size() - 1);
score++;
if (score > GlobalVariables.HIGHSCORE)
GlobalVariables.HIGHSCORE = score;
}
}
public void draw(Canvas canvas)
{
for(Obstacle ob : obstacles)
ob.draw(canvas);
Paint paint = new Paint();
paint.setTextSize(100);
paint.setColor(Color.RED);
canvas.drawText("" + score, 50, 50 + paint.descent() - paint.ascent(), paint);
canvas.drawText("HighScore: " + GlobalVariables.HIGHSCORE, GlobalVariables.SCREEN_WIDTH / 2 + 50, 50 + paint.descent() - paint.ascent(), paint);
}
}
here is my animation manager
public class AnimationManager
{
private Animation[] animations;
private int animationsIndex = 0;
public AnimationManager(Animation[] animations)
{
this.animations = animations;
}
public void playAnim(int index)
{
for (int i = 0; i < animations.length; i++)
{
if (i == index)
{
if (!animations[index].isPlaying())
{
animations[i].play();
}
}
else
{
animations[i].stop();
}
}
animationsIndex = index;
}
public void draw(Canvas canvas, Rect rect)
{
if (animations[animationsIndex].isPlaying())
{
animations[animationsIndex].draw(canvas, rect);
}
}
public void update()
{
if (animations[animationsIndex].isPlaying())
{
animations[animationsIndex].update();
}
}
}
and finally my animation class
public class Animation
{
private Bitmap[] frames;
private int frameIndex;
private boolean isPlaying = false;
public boolean isPlaying()
{
return isPlaying;
}
public void play()
{
isPlaying = true;
frameIndex = 0;
lastFrame = System.currentTimeMillis();
}
public void stop()
{
isPlaying = false;
}
private float frameTime;
private long lastFrame;
public Animation(Bitmap[] frames, float animTime)
{
this.frames = frames;
frameIndex = 0;
frameTime = animTime / frames.length;
lastFrame = System.currentTimeMillis();
}
public void draw(Canvas canvas, Rect destination)
{
if (!isPlaying)
return;
scaleRect(destination);
canvas.drawBitmap(frames[frameIndex], null, destination, new Paint());
}
private void scaleRect(Rect rect)
{
float whRatio = (float)(frames[frameIndex].getWidth() / frames[frameIndex].getHeight());
if (rect.width() > rect.height())
{
rect.left = rect.right - (int)(rect.height() * whRatio);
}
else
{
rect.top = rect.bottom - (int)(rect.width() * (1 / whRatio));
}
}
public void update()
{
if (!isPlaying)
return;
if (System.currentTimeMillis() - lastFrame > frameTime * 1000)
{
frameIndex++;
if (frameIndex >= frames.length)
frameIndex = 0;
lastFrame = System.currentTimeMillis();
}
}
}
i dont think you necessarily needed all that but just in case :). thanks for any comments to improve or help.

OutOfMemoryError basically means that you tried to use more memory than you can. In this specific example you (bitmap) tried to allocate 360KB though you could only allocate 78KB more. You might have a memory leak somewhere or your bitmap might be too big. I think your Bitmaps might be leaking memory. I'm not an Android expert though.
I'd recommend you to create a method in Obstacle like recycle or something along this way. Then every time you remove Obstacle from obstacles in ObstacleManager call that method. In that method you should aim to recycle all no longer used bitmaps. I'd do it by calling either Animation#recycle on every of your animations or calling AnimationManagerObstacle#recycle. (Animation#recycle would be meant to call recycle on every one of your frames.)

Related

Temporary Sprite in Android App

I have an android game where there are sprites moving about the screen. When one is hit, it adds or takes away from the score and then disappears.
What I would like it to do is create a blood splatter when it is hit which will also disappear.
I have actually achieved this but the blood splatter doesn't appear where the sprite was hit. It always goes to the bottom right-hand corner. I was wondering if there is anyone out there that can see where my problem is.
I have a TempSprite class just for the blood splatter and this is below:
public class TempSprite {
private float x;
private float y;
private Bitmap bmp;
private int life = 12;
private List<TempSprite> temps;
public TempSprite(List<TempSprite> temps, GameView gameView, float x,
float y, Bitmap bmp) {
this.x = Math.min(Math.max(x - bmp.getWidth() / 2, 0),
gameView.getWidth() - bmp.getWidth());
this.y = Math.min(Math.max(y - bmp.getHeight() / 2, 0),
gameView.getHeight() - bmp.getHeight());
this.bmp = bmp;
this.temps = temps;
}
public void onDraw(Canvas canvas) {
update();
canvas.drawBitmap(bmp, x, y, null);
}
private void update() {
if (--life < 1) {
temps.remove(this);
}
}
}
All the other code is in the GameView class, specifically in the doDraw and GameView methods:
public class GameView extends SurfaceView implements SurfaceHolder.Callback {
private final Bitmap bmpBlood;
/* Member (state) fields */
private GameLoopThread gameLoopThread;
private Paint paint; //Reference a paint object
/** The drawable to use as the background of the animation canvas */
private Bitmap mBackgroundImage;
// For creating the game Sprite
private Sprite sprite;
private BadSprite badSprite;
// For recording the number of hits
private int hitCount;
// For displaying the highest score
private int highScore;
// To track if a game is over
private boolean gameOver;
// To play sound
private SoundPool mySound;
private int zapSoundId;
private int screamSoundId;
// For multiple sprites
private ArrayList<Sprite> spritesArrayList;
private ArrayList<BadSprite> badSpriteArrayList;
// For the temp blood image
private List<TempSprite> temps = new ArrayList<TempSprite>();
//int backButtonCount = 0;
private void createSprites() {
// Initialise sprite object
spritesArrayList = new ArrayList<>();
badSpriteArrayList = new ArrayList<>();
for (int i = 0; i < 20; i++) {
spritesArrayList.add(new Sprite(this));
badSpriteArrayList.add(new BadSprite(this));
}
}
public GameView(Context context) {
super(context);
// Focus must be on GameView so that events can be handled.
this.setFocusable(true);
// For intercepting events on the surface.
this.getHolder().addCallback(this);
// Background image added
mBackgroundImage = BitmapFactory.decodeResource(this.getResources(), R.drawable.castle);
// Populate multiple sprites
//createSprites();
//Vibrator vibe = (Vibrator) sprite.getSystemService(Context.VIBRATOR_SERVICE);
//vibe.vibrate(500);
// For the temp blood splatter
bmpBlood = BitmapFactory.decodeResource(getResources(), R.drawable.blood1);
//Sound effects for the sprite touch
mySound = new SoundPool(10, AudioManager.STREAM_MUSIC, 0);
screamSoundId = mySound.load(context, R.raw.scream, 1);
zapSoundId = mySound.load(context, R.raw.zap, 1);
}
/* Called immediately after the surface created */
public void surfaceCreated(SurfaceHolder holder) {
createSprites();
// We can now safely setup the game start the game loop.
ResetGame();//Set up a new game up - could be called by a 'play again option'
mBackgroundImage = Bitmap.createScaledBitmap(mBackgroundImage, getWidth(), getHeight(), true);
gameLoopThread = new GameLoopThread(this.getHolder(), this);
gameLoopThread.running = true;
gameLoopThread.start();
}
// For the countdown timer
private long startTime; // Timer to count down from
private final long interval = 1 * 1000; // 1 sec interval
private CountDownTimer countDownTimer; // Reference to the class
private boolean timerRunning = false;
private String displayTime; // To display the time on the screen
//To initialise/reset game
private void ResetGame(){
/* Set paint details */
paint = new Paint();
paint.setColor(Color.WHITE);
paint.setTextSize(20);
sprite = new Sprite(this);
hitCount = 0;
// Set timer
startTime = 10; // Start at 10s to count down
// Create new object - convert startTime to milliseconds
countDownTimer = new MyCountDownTimer(startTime*1000, interval);
countDownTimer.start(); // Start the time running
timerRunning = true;
gameOver = false;
}
// Countdown Timer - private class
private class MyCountDownTimer extends CountDownTimer {
public MyCountDownTimer (long startTime, long interval) {
super(startTime, interval);
}
public void onFinish() {
//displayTime = "Time is up!";
timerRunning = false;
countDownTimer.cancel();
gameOver = true;
}
public void onTick (long millisUntilFinished) {
displayTime = " " + millisUntilFinished / 1000;
}
}
//This class updates and manages the assets prior to drawing - called from the Thread
public void update(){
}
/**
* To draw the game to the screen
* This is called from Thread, so synchronisation can be done
*/
#SuppressWarnings("ResourceAsColor")
public void doDraw(Canvas canvas) {
canvas.drawBitmap(mBackgroundImage, 0, 0, null);
if (!gameOver) {
sprite.draw(canvas);
//paint.setColor(R.color.red);
canvas.drawText("Time Remaining: " + displayTime, 35, 50, paint);
canvas.drawText("Number of hits: " + hitCount, 35, 85, paint);
// Draw the blood splatter
for (int i = temps.size() - 1; i >= 0; i--) {
temps.get(i).onDraw(canvas);
}
// Draw all the objects on the canvas
for (int i = 0; i < spritesArrayList.size(); i++) {
Sprite sprite = spritesArrayList.get(i);
sprite.draw(canvas);
}
for (int i = 0; i < badSpriteArrayList.size(); i++) {
BadSprite badSprite = badSpriteArrayList.get(i);
badSprite.draw(canvas);
}
} else {
canvas.drawText("Game Over!", 35, 50, paint);
canvas.drawText("Your score was: " + hitCount, 35, 80, paint);
canvas.drawText("To go back home,", 280, 50, paint);
canvas.drawText("press the 'back' key", 280, 70, paint);
}
}
//To be used if we need to find where screen was touched
public boolean onTouchEvent(MotionEvent event) {
for (int i = spritesArrayList.size()-1; i>=0; i--) {
Sprite sprite = spritesArrayList.get(i);
if (sprite.wasItTouched(event.getX(), event.getY())) {
mySound.play(zapSoundId, 1.0f, 1.0f, 0,0, 1.5f);
spritesArrayList.remove(sprite);
//temps.add(new TempSprite(temps, this, x, y, bmpBlood));
hitCount--;
return super.onTouchEvent(event);
}
for (int i1 = badSpriteArrayList.size()-1; i1>=0; i1--) {
BadSprite badSprite = badSpriteArrayList.get(i1);
if (badSprite.wasItTouched(event.getX(), event.getY())) {
mySound.play(screamSoundId, 1.0f, 1.0f, 0, 0, 1.5f);
badSpriteArrayList.remove(badSprite);
temps.add(new TempSprite(temps, this, x, y, bmpBlood));
hitCount++;
return super.onTouchEvent(event);
}
}
}
//else {
return true;
// }
}
public void surfaceDestroyed(SurfaceHolder holder) {
gameLoopThread.running = false;
// Shut down the game loop thread cleanly.
boolean retry = true;
while(retry) {
try {
gameLoopThread.join();
retry = false;
} catch (InterruptedException e) {}
}
}
public int getHitCount() {
return hitCount;
}
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
}
As always, any help greatly appreciated.
Thanks
This was solved with the following code:
public class TempSprite {
private float x;
private float y;
private Bitmap bmp;
private int life = 12;
private List<TempSprite> temps;
public TempSprite(List<TempSprite> temps, GameView gameView, float x,
float y, Bitmap bmp) {
/*this.x = Math.min(Math.max(x - bmp.getWidth() / 2, 0),
gameView.getWidth() - bmp.getWidth());
this.y = Math.min(Math.max(y - bmp.getHeight() / 2, 0),
gameView.getHeight() - bmp.getHeight());*/
this.x = x;
this.y = y;
this.bmp = bmp;
this.temps = temps;
}
public void onDraw(Canvas canvas) {
update();
canvas.drawBitmap(bmp, x, y, null);
}
private void update() {
if (--life < 1) {
temps.remove(this);
}
}
}
You can see where the commented out sections are and below are what they were replaced with. I was trying to make things a little too complicated.

Libgdx Jiggering Sprite Movement

I recently got into LibGDX using the book "LibGDX Game Development By Example" (Pretty good one btw) and have been playing around with the tutorial projects for the last month.
One of these games is a FlappyBird-clone (of course it is) and I decided to add features, change sprites etc.
Now the problem is that the normal obstacle graphics (flowers) don't fit the new theme and need to be exchanged.
Doing so results in jiggering graphics for the new sprites.
I should point out that the code used to visualize these obstacles has not changed at all, simply exchanging the sprites causes this problem.
I tried a lot of different sprites and all that are not identical to the flowers seem to have this problem.
So whatever is the cause, the old flower sprites are unaffected, every other sprite is.
On to the code (Removed some Getters/Setters and other unrelated methods)
The Flower/Obstacle Class:
public class Flower
{
private static final float COLLISION_RECTANGLE_WIDTH = 13f;
private static final float COLLISION_RECTANGLE_HEIGHT = 447f;
private static final float COLLISION_CIRCLE_RADIUS = 33f;
private float x = 0;
private float y = 0;
private static final float MAX_SPEED_PER_SECOND = 100f;
public static final float WIDTH = COLLISION_CIRCLE_RADIUS * 2;
private static final float HEIGHT_OFFSET = -400.0f;
private static final float DISTANCE_BETWEEN_FLOOR_AND_CEILING = 225.0f;
private final Circle floorCollisionCircle;
private final Rectangle floorCollisionRectangle;
private final Circle ceilingCollisionCircle;
private final Rectangle ceilingCollisionRectangle;
private boolean pointClaimed = false;
private final TextureRegion floorTexture;
private final TextureRegion ceilingTexture;
float textureX,textureY;
public Flower(TextureRegion floorTexture, TextureRegion ceilingTexture)
{
this.floorTexture = floorTexture;
this.ceilingTexture = ceilingTexture;
this.y = MathUtils.random(HEIGHT_OFFSET);
this.floorCollisionRectangle = new Rectangle(x,y,COLLISION_RECTANGLE_WIDTH,COLLISION_RECTANGLE_HEIGHT);
this.floorCollisionCircle = new Circle(x + floorCollisionRectangle.width / 2, y + floorCollisionRectangle.height, COLLISION_CIRCLE_RADIUS);
this.ceilingCollisionRectangle = new Rectangle(x,floorCollisionCircle.y + DISTANCE_BETWEEN_FLOOR_AND_CEILING,COLLISION_RECTANGLE_WIDTH,
COLLISION_RECTANGLE_HEIGHT);
this.ceilingCollisionCircle = new Circle(x + ceilingCollisionRectangle.width / 2, ceilingCollisionRectangle.y, COLLISION_CIRCLE_RADIUS);
}
public void update(float delta)
{
setPosition(x - (MAX_SPEED_PER_SECOND * delta));
}
public void setPosition(float x)
{
this.x = x;
updateCollisionCircle();
updateCollisionRectangle();
}
private void updateCollisionCircle()
{
floorCollisionCircle.setX(x + floorCollisionRectangle.width / 2);
ceilingCollisionCircle.setX(x + ceilingCollisionRectangle.width / 2);
}
private void updateCollisionRectangle()
{
floorCollisionRectangle.setX(x);
ceilingCollisionRectangle.setX(x);
}
public void draw(SpriteBatch batch)
{
drawFloorFlower(batch);
drawCeilingFlower(batch);
}
private void drawFloorFlower(SpriteBatch batch)
{
textureX = floorCollisionCircle.x - floorTexture.getRegionWidth() / 2;
textureY = floorCollisionRectangle.getY() + COLLISION_CIRCLE_RADIUS;
batch.draw(floorTexture,textureX,textureY);
}
private void drawCeilingFlower(SpriteBatch batch)
{
textureX = ceilingCollisionCircle.x - ceilingTexture.getRegionWidth() / 2;
textureY = ceilingCollisionRectangle.getY() - COLLISION_CIRCLE_RADIUS;
batch.draw(ceilingTexture,textureX, textureY);
}
}
And the GameScreen/Main Class:
public class GameScreen extends ScreenAdapter
{
private static final float WORLD_WIDTH = 480;
private static final float WORLD_HEIGHT = 640;
private java.util.prefs.Preferences prefs;
private int highscore;
FlappeeBeeGame flappeeBeeGame;
private ShapeRenderer shapeRenderer;
private Viewport viewport;
private Camera camera;
private SpriteBatch batch;
private Flappee flappee;
private Flower flower;
private Array<Flower> flowers = new Array<Flower>();
private static final float GAP_BETWEEN_FLOWERS = 200.0f;
private boolean gameOver = false;
int score = 0;
BitmapFont bitmapFont;
GlyphLayout glyphLayout;
private TextureRegion background;
private TextureRegion flowerBottom;
private TextureRegion flowerTop;
private TextureRegion bee;
private TextureRegion smallCloud;
private TextureRegion lowCloud;
private Music music_background;
TextureAtlas textureAtlas;
List<Cloud> activeClouds = new ArrayList<Cloud>();
List<Cloud> cloudBarriers = new ArrayList<Cloud>();
private float cloud_minScale = 0.6f;
private float cloud_maxScale = 1.0f;
private float cloud_minY, cloud_maxY;
private float cloud_minDis, cloud_maxDis;
private float cloud_minSpeed = 17.0f;
private float cloud_maxSpeed = 27.0f;
private final float barrierCloud_speed = 150.0f;
private boolean inputBlocked = false;
private float blockTime = 0.5f;
private float remainingblockTime = blockTime;
public GameScreen(FlappeeBeeGame fpg)
{
flappeeBeeGame = fpg;
flappeeBeeGame.getAssetManager().load("assets/flappee_bee_assets.atlas",TextureAtlas.class);
flappeeBeeGame.getAssetManager().finishLoading();
textureAtlas = flappeeBeeGame.getAssetManager().get("assets/flappee_bee_assets.atlas");
prefs = java.util.prefs.Preferences.userRoot().node(this.getClass().getName());
highscore = prefs.getInt("highscore",0);
music_background = Gdx.audio.newMusic(Gdx.files.internal("assets/backgroundmusic.ogg"));
music_background.setLooping(true);
music_background.setVolume(0.5f);
music_background.play();
}
private void createNewFlower()
{
Flower newFlower = new Flower(flowerBottom,flowerTop);
newFlower.setPosition(WORLD_WIDTH + Flower.WIDTH);
flowers.add(newFlower);
}
private void checkIfNewFlowerIsNeeded()
{
if(flowers.size == 0)
{
createNewFlower();
}
else
{
Flower flower = flowers.peek();
if(flower.getX() < WORLD_WIDTH - GAP_BETWEEN_FLOWERS)
{
createNewFlower();
}
}
}
private void drawFlowers()
{
for(Flower flower : flowers)
{
flower.draw(batch);
}
}
private void removeFlowersIfPassed()
{
if(flowers.size > 0)
{
Flower firstFlower = flowers.first();
if(firstFlower.getX() < -Flower.WIDTH)
{
flowers.removeValue(firstFlower,true);
}
}
}
#Override
public void resize(int width, int height) {
super.resize(width, height);
viewport.update(width,height);
}
#Override
public void show() {
super.show();
camera = new OrthographicCamera();
camera.position.set(WORLD_WIDTH / 2, WORLD_HEIGHT / 2, 0);
camera.update();
viewport = new FitViewport(WORLD_WIDTH,WORLD_HEIGHT, camera);
shapeRenderer = new ShapeRenderer();
batch = new SpriteBatch();
bitmapFont = new BitmapFont(Gdx.files.internal("assets/score_new.fnt"));
glyphLayout = new GlyphLayout();
background = textureAtlas.findRegion("bg");
flowerBottom = textureAtlas.findRegion("pipeBottom");
flowerTop = textureAtlas.findRegion("flowerTop");
bee = textureAtlas.findRegion("bee");
smallCloud = textureAtlas.findRegion("smallCloud");
lowCloud = textureAtlas.findRegion("lowerCloud");
flower = new Flower(flowerBottom,flowerTop);
flappee = new Flappee(bee,textureAtlas);
flappee.setPosition(WORLD_WIDTH/4,WORLD_HEIGHT/2);
cloud_minDis = smallCloud.getRegionWidth() / 4;
cloud_maxDis = smallCloud.getRegionWidth();
cloud_maxY = viewport.getWorldHeight() - smallCloud.getRegionHeight()/2;
cloud_minY = viewport.getWorldHeight() - smallCloud.getRegionHeight() * 2;
Cloud a = generateCloud(null);
Cloud b = generateCloud(a);
Cloud c = generateCloud(b);
Cloud d = generateCloud(c);
Cloud e = generateCloud(d);
activeClouds.add(a);
activeClouds.add(b);
activeClouds.add(c);
activeClouds.add(d);
activeClouds.add(e);
a = new Cloud(lowCloud,batch,0,0 - lowCloud.getRegionHeight()/4,barrierCloud_speed,1.0f);
b = new Cloud(lowCloud,batch,lowCloud.getRegionWidth(),0 - lowCloud.getRegionHeight()/4,barrierCloud_speed,1.0f);
c = new Cloud(lowCloud,batch,lowCloud.getRegionWidth()*2,0 - lowCloud.getRegionHeight()/4,barrierCloud_speed,1.0f);
cloudBarriers.add(a);
cloudBarriers.add(b);
cloudBarriers.add(c);
}
public Cloud generateCloud(Cloud formerCloud)
{
Cloud d;
if(formerCloud == null)
{
float randomVal = (float)Math.random();
d = new Cloud(smallCloud,batch,viewport.getWorldWidth(),
(float)Math.random() * (cloud_maxY - cloud_minY) + cloud_minY,
randomVal * (cloud_maxSpeed-cloud_minSpeed) + cloud_minSpeed,
randomVal * (cloud_maxScale-cloud_minScale) + cloud_minScale);
return d;
}
float randomVal = (float)Math.random();
d = new Cloud(smallCloud,batch,formerCloud.getPosX() + ((float)
Math.random() * (cloud_maxDis - cloud_minDis) + cloud_minDis),(float)Math.random() * (cloud_maxY - cloud_minY) + cloud_minY,
randomVal * (cloud_maxSpeed-cloud_minSpeed) + cloud_minSpeed,
randomVal * (cloud_maxScale-cloud_minScale) + cloud_minScale);
return d;
}
#Override
public void render(float delta) {
super.render(delta);
clearScreen();
shapeRenderer.setProjectionMatrix(camera.projection);
shapeRenderer.setTransformMatrix(camera.view);
shapeRenderer.begin(ShapeRenderer.ShapeType.Line);
shapeRenderer.end();
draw(delta);
update(delta);
}
private void draw(float delta)
{
batch.setProjectionMatrix(camera.projection);
batch.setTransformMatrix(camera.view);
batch.begin();
batch.draw(background,0,0);
drawClouds(delta);
drawScore();
drawFlowers();
//drawDebug();
if(!gameOver)
{
flappee.draw(batch,delta);
}
drawBarrierClouds(delta);
batch.end();
}
private void updateClouds(float delta)
{
boolean move = false;
Cloud tmp = null;
for(Cloud c : cloudBarriers)
{
c.update(delta);
if(c.getPosX() <= -lowCloud.getRegionWidth())
{
tmp = c;
move = true;
}
}
if(move)
{
float positionX = cloudBarriers.get(cloudBarriers.size()-1).getPosX() + lowCloud.getRegionWidth();
if(positionX < viewport.getWorldWidth())
{
positionX = viewport.getWorldWidth();
}
tmp.setPos(positionX,0 - lowCloud.getRegionHeight()/4);
cloudBarriers.remove(tmp);
cloudBarriers.add(tmp);
tmp = null;
move = false;
}
for(Cloud c : activeClouds)
{
c.update(delta);
if(c.getPosX() <= -smallCloud.getRegionWidth())
{
tmp = c;
move = true;
}
}
if(move)
{
float randomVal = (float)Math.random();
float positionX = activeClouds.get(activeClouds.size()-1).getPosX() + ((float)
Math.random() * (cloud_maxDis - cloud_minDis) + cloud_minDis);
if(positionX < viewport.getWorldWidth())
{
positionX = viewport.getWorldWidth();
}
tmp.setPos(positionX,(float)Math.random() * (cloud_maxY - cloud_minY) + cloud_minY);
tmp.setSpeed(randomVal * (cloud_maxSpeed - cloud_minSpeed) + cloud_minSpeed);
tmp.setScale(randomVal * (cloud_maxScale - cloud_minScale) + cloud_minScale);
activeClouds.remove(tmp);
activeClouds.add(tmp);
move = false;
tmp = null;
}
}
private void drawBarrierClouds(float delta)
{
for(Cloud c : cloudBarriers)
{
c.render();
}
}
private void drawClouds(float delta)
{
for(Cloud c : activeClouds)
{
c.render();
}
}
private void clearScreen()
{
Gdx.gl.glClearColor(Color.BLACK.r,Color.BLACK.g,Color.BLACK.b, Color.BLACK.a);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
}
private void blockFlappeeLeavingTheWorld()
{
flappee.setPosition(flappee.getX(), MathUtils.clamp(flappee.getY(),0,WORLD_HEIGHT));
}
private void updateFlowers(float delta)
{
for(Flower flower : flowers)
{
flower.update(delta);
}
checkIfNewFlowerIsNeeded();
removeFlowersIfPassed();
}
private void update(float delta)
{
updateClouds(delta);
if(!gameOver) {
updateFlappee(delta);
updateFlowers(delta);
updateScore();
if (checkForCollision())
{
gameOver = true;
inputBlocked = true;
remainingblockTime = blockTime;
restart();
}
}
else
{
if((Gdx.input.isKeyJustPressed(Input.Keys.SPACE) || Gdx.input.isButtonPressed(Input.Buttons.LEFT)) && !inputBlocked)
{
gameOver = false;
score = 0;
}
if(inputBlocked)
{
if(remainingblockTime > 0)
{
remainingblockTime -= delta;
}
else
{
inputBlocked = false;
remainingblockTime = blockTime;
}
}
}
}
private void restart()
{
flappee.setPosition(WORLD_WIDTH / 4, WORLD_HEIGHT / 2);
flowers.clear();
}
#Override
public void dispose() {
super.dispose();
}
private boolean checkForCollision()
{
for(Flower flower : flowers)
{
if(flower.isFlappeeColliding(flappee))
{
if(score > highscore)
{
highscore = score;
prefs.putInt("highscore",highscore);
inputBlocked = true;
remainingblockTime = blockTime;
}
return true;
}
}
return false;
}
}
I'd love to give you a runnable jar but I've got some problems building a working version. Let's just say a jar is out of the question for now.
What I can give you are screenshots:
Jiggering Sprite View
Functional Flower Sprite View
The first image shows the problem: The new sprites (which are just debug) become edgy like the top of the sprite can't compete with the speed of its lower half.
The second image shows the old sprites for comparison: They don't show any of this behaviour, even if they are longer than the one on the screenshot.
So what do you people think?
What causes this behaviour and how should I fix it?
Thanks in advance for any help, I appreciate it :)
Greetz!
EDIT:
I kind of fixed it.
When switching to another computer and running the game the issue didn't come up anymore.
Specifically I went from Debian to Windows 10 and from NVIDIA Optimus to a standard desktop AMD-Card.
If you should encounter this problem try another PC with a different OS and/or GPU.
Sadly (if you were to google this question) I can't tell you how to solve it on the first machine or what exactly caused it, but at least it shouldn't come up on anyone else's computer when you send them your project.

Android : moving bmp leaving a trail ( Surface View and Canvas )

I was trying to animate a sprite for an android app and i've encounter a small problem. I'm drawing on a surfaceView that i add on top of already existing layouts. On this surfaceView, i wanted to animate few sprites so they would walk along a path.
So this is the result i'm facing right now :
The walking sprite is leaving a trail. So i decided to google this problem and apparently i had to clear the canvas first before drawing on it.
This was my onDraw method before :
public void onDraw(Canvas canvas) {
update();
int srcX = currentFrame * width;
int srcY = directionX * height;
Rect src = new Rect(srcX, srcY, srcX + width, srcY + height);
Rect dst = new Rect(x, y, x + width, y + height);
canvas.drawBitmap(bmp, src, dst, null);
}
And this was my onDraw method after
public void onDraw(Canvas canvas) {
canvas.drawRGB(0, 0, 0);
update();
int srcX = currentFrame * width;
int srcY = directionX * height;
Rect src = new Rect(srcX, srcY, srcX + width, srcY + height);
Rect dst = new Rect(x, y, x + width, y + height);
canvas.drawBitmap(bmp, src, dst, null);
}
So i now have this as a result
which is great because it leaves no more trail BUT i cant see the layouts underneath. Is there anyway i can get the best of both world ? I thought clearing the canvas would work but it obviously doesnt not work as expected.
I'll post my code below
SurfaceView :
public class MonsterView extends SurfaceView {
private Bitmap monsterImg;
private SurfaceHolder holder;
private MonsterThread mainThread;
private Sprite monsterSprite;
private int x;
private int xSpeed = 1;
public MonsterView(Context context) {
super(context);
this.mainThread = new MonsterThread(this);
this.x = 0;
holder = getHolder();
holder.setFormat(PixelFormat.TRANSPARENT);
holder.addCallback(new SurfaceHolder.Callback() {
#Override
public void surfaceCreated(SurfaceHolder holder) {
mainThread.setRunning(true);
mainThread.start();
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
mainThread.setRunning(false);
while (retry) {
try {
mainThread.join();
retry = false;
} catch (InterruptedException e) {
}
}
}
});
setZOrderOnTop(true);
monsterImg = BitmapFactory.decodeResource(getResources(), R.drawable.fire);
monsterSprite = new Sprite(this,monsterImg);
}
#Override
public void onDraw(Canvas canvas) {
if (x == getWidth() - monsterImg.getWidth()) {
xSpeed = -1;
}
if (x == 0) {
xSpeed = 1;
}
x = x + xSpeed;
monsterSprite.onDraw(canvas);
}
Thread :
public class MonsterThread extends Thread {
private MonsterView monsterSurface;
private boolean running;
static final long FPS = 35;
public MonsterThread(MonsterView monsterSurface){
this.monsterSurface = monsterSurface;
this.running = false;
}
#Override
public void run() {
long ticksPS = 1000 / FPS;
long startTime;
long sleepTime;
while(running){
Canvas c = null;
startTime = System.currentTimeMillis();
try{
c = monsterSurface.getHolder().lockCanvas();
synchronized (monsterSurface.getHolder()){
monsterSurface.onDraw(c);
}
} finally {
if( c!= null){
monsterSurface.getHolder().unlockCanvasAndPost(c);
}
}
sleepTime = ticksPS-(System.currentTimeMillis() - startTime);
try {
if(sleepTime > 0)
sleep(sleepTime);
else
sleep(10);
} catch (Exception e){}
}
}
public MonsterView getMonsterSurface() {
return monsterSurface;
}
public void setMonsterSurface(MonsterView monsterSurface) {
this.monsterSurface = monsterSurface;
}
public boolean isRunning() {
return running;
}
public void setRunning(boolean running) {
this.running = running;
}
Sprite :
public class Sprite {
private static final int BMP_ROWS = 4;
private static final int BMP_COLUMNS = 3;
private int x = 0;
private int y = 0;
private int xSpeed = 5;
private MonsterView monsterView;
private Bitmap bmp;
private int currentFrame = 0;
private int width;
private int height;
private int directionX;
public Sprite(MonsterView monsterView, Bitmap bmp) {
this.monsterView = monsterView;
this.bmp=bmp;
this.width = bmp.getWidth() / BMP_COLUMNS;
this.height = bmp.getHeight() / BMP_ROWS;
this.directionX = 2;
}
private void update() {
if (x > monsterView.getWidth() - width - xSpeed) {
xSpeed = -5;
directionX = 1;
}
if (x + xSpeed < 0) {
xSpeed = 5;
directionX = 2;
}
x = x + xSpeed;
currentFrame = ++currentFrame % BMP_COLUMNS;
Log.d("test", ""+currentFrame);
}
public void onDraw(Canvas canvas) {
update();
int srcX = currentFrame * width;
int srcY = directionX * height;
Rect src = new Rect(srcX, srcY, srcX + width, srcY + height);
Rect dst = new Rect(x, y, x + width, y + height);
canvas.drawBitmap(bmp, src, dst, null);
}
You're using setZOrderOnTop(), which is putting the Surface part of the SurfaceView on a layer above everything else. (By default, it's a separate layer below everything else.) When you clear it with canvas.drawRGB(0, 0, 0) you're setting the entire layer to opaque black, which is going to obscure the View layer beneath it.
If instead you clear it to transparent black, with canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR), you should get the results you want.
FWIW, you shouldn't override onDraw() if you're only drawing on the Surface. The onDraw() method is called by the View hierarchy to draw on the View part of the SurfaceView. If something manages to invalidate the SurfaceView's View, your onDraw() will be called, and you'll end up with a character sprite on the View layer. (Depending on your layout this may not be visible.) Just give the method a different name.
There are a number of ways to handle this, but generally, the way to do this is by maintaining a background layer (which is just another image), and sprite layers. Instead of clearing, at each frame you blit (copy) your background onto the surface (which erases everything), then you blit your sprites.
So you're going to have to draw the background bitmap onto the surface first before drawing your sprite. Right now you're drawing black which is covering your background layouts.
Alternatively you might be able to do canvas.drawRect with a Paint with paint.setColor to Color.Transparent.

Multiple sprites and animation problems

I'm trying to add multiple sprites to android game using an Array but at the minute only one will display and when I click it rather than it changing to the new sprite animation it freezes on the screen here is the code within my GameView.java and Sprite.java.
GameView.java:
/**
* This class takes care of surface for drawing and touches
*
*/
public class GameView extends SurfaceView implements SurfaceHolder.Callback {
/* Member (state) fields */
private GameLoopThread gameLoopThread;
private Paint paint; // Reference a paint object
/** The drawable to use as the background of the animation canvas */
private Bitmap mBackgroundImage;
private Sprite sprite;
private ArrayList<Sprite> spritesArrayList;
int SpriteAmount = 3;
private int hitCount;
private boolean GameOver = false;
/* For the countdown timer */
private long startTime; // Timer to count down from
private final long interval = 1 * 1000; // 1 sec interval
private CountDownTimer countDownTimer; // Reference to class
private boolean timerRunning = false;
private String displayTime; // To display time on the screen
public GameView(Context context) {
super(context);
spritesArrayList = new ArrayList<Sprite>();
// Focus must be on GameView so that events can be handled.
this.setFocusable(true);
// For intercepting events on the surface.
this.getHolder().addCallback(this);
mBackgroundImage = BitmapFactory.decodeResource(this.getResources(),
R.drawable.dbz);
}
/* Called immediately after the surface created */
public void surfaceCreated(SurfaceHolder holder) {
mBackgroundImage = Bitmap.createScaledBitmap(mBackgroundImage,
getWidth(), getHeight(), true);
// We can now safely setup the game start the game loop.
ResetGame();// Set up a new game up - could be called by a 'play again
// option'
gameLoopThread = new GameLoopThread(this.getHolder(), this);
gameLoopThread.running = true;
gameLoopThread.start();
}
// Sprite List
// To initialise/reset game
private void ResetGame() {
//sprite = new Sprite(this);
for (int P = 0; P < SpriteAmount; P++) {
spritesArrayList.add(sprite = new Sprite(this));
}
hitCount = 0;
GameOver = false;
/* Set paint details */
paint = new Paint();
paint.setColor(Color.WHITE);
paint.setTextSize(20);
// Set timer
startTime = 10;// Start at 10s to count down
// Create new object - convert startTime to milliseconds
countDownTimer = new MyCountDownTimer(startTime * 1000, interval);
countDownTimer.start();// Start it running
timerRunning = true;
}
// This class updates and manages the assets prior to drawing - called from
// the Thread
public void update() {
for (int P = 0; P < SpriteAmount; P++) {
GameOver = false;
spritesArrayList.get(P).update();
}
}
/**
* To draw the game to the screen This is called from Thread, so
* synchronisation can be done
*/
public void doDraw(Canvas canvas) {
canvas.drawBitmap(mBackgroundImage, 0, 0, null);
if (GameOver == false) {
sprite.draw(canvas);
} else if (GameOver == true) {
}
// Draw all the objects on the canvas
canvas.drawText("Hits Obtained =" + hitCount, 5, 25, paint);
canvas.drawText("Time Remaining =" + displayTime, 5, 40, paint);
if (GameOver == true) {
canvas.drawText("Return To Main Menu using return button", 5, 60,
paint);
}
}
// To be used if we need to find where screen was touched
public boolean onTouchEvent(MotionEvent event) {
for (int P = 0; P < SpriteAmount; P++) {
if (spritesArrayList.get(P).wasItTouched(event.getX(), event.getY())) {
/* For now, just renew the Sprite */
spritesArrayList.add(sprite = new Sprite(this));
hitCount++;
}
}
return true;
}
public void surfaceDestroyed(SurfaceHolder holder) {
gameLoopThread.running = false;
// Shut down the game loop thread cleanly.
boolean retry = true;
while (retry) {
try {
gameLoopThread.join();
retry = false;
} catch (InterruptedException e) {
}
}
}
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
}
/* Countdown Timer - private class */
private class MyCountDownTimer extends CountDownTimer {
public MyCountDownTimer(long startTime, long interval) {
super(startTime, interval);
}
public void onFinish() {
displayTime = "Times Over!";
timerRunning = false;
countDownTimer.cancel();
GameOver = true;
}
public void onTick(long millisUntilFinished) {
displayTime = " " + millisUntilFinished / 1000;
}
}// End of MyCountDownTimer
public int getHitCount() {
// TODO Auto-generated method stub
return hitCount;
}
}
Sprite.java:
public class Sprite {
// Needed for new random coordinates.
private Random random = new Random();
// x,y position of sprite - initial position (0,50)
int x = random.nextInt(500);
int X = random.nextInt(500);
int y = random.nextInt(1000);
int Y = random.nextInt(1000);
private int xSpeed = 10;// Horizontal increment of position (speed)
// apply at later date random.nextInt(10)
private int ySpeed = 10;// Vertical increment of position (speed)
// apply at later date random.nextInt(10)
private GameView gameView;
private Bitmap spritebmp;
// Width and Height of the Sprite image
private int bmp_width;
private int bmp_height;
private Integer[] imgid = { R.drawable.kidbuu, R.drawable.guko,
R.drawable.guko_ssj1
};
// Calculation for reverse direction
// x = x - (x - x)
// y = y - (y - y)
public Sprite(GameView gameView) {
this.gameView = gameView;
spritebmp = BitmapFactory.decodeResource(gameView.getResources(),
R.drawable.guko);
this.bmp_width = spritebmp.getWidth();
this.bmp_height = spritebmp.getHeight();
}
// update the position of the sprite
public void update() {
x = x + xSpeed;
y = y + ySpeed;
wrapAround(); // Adjust motion of sprite.
}
public void ReverseRandom() {
X = (x - (x - x));
Y = (y - (y - y));
}
public void draw(Canvas canvas) {
// Draw sprite image
// y = random.nextInt(500);
// x = random.nextInt(500);
canvas.drawBitmap(spritebmp, x, y, null);
}
public int calcX(int value) {
return random.nextInt(value);
}
public int calcY(int value) {
return random.nextInt(value);
}
public void wrapAround() {
ReverseRandom();
// Code to wrap around
if (x < 0)
x = X; // increment x whilst not off screen
if (x >= gameView.getWidth() - spritebmp.getWidth() - xSpeed) { // if
// gone
// of
// the
// right
// sides
// of
// screen
xSpeed = -5;
}
if (x + xSpeed <= 0) {
xSpeed = 5;
}
x = x + xSpeed;
if (y < 0)
y = Y;// increment y whilst not off screen
if (y >= gameView.getHeight() - spritebmp.getWidth() - ySpeed) {// if
// gone
// of
// the
// bottom
// of
// screen
ySpeed = -5;
}
if (y + ySpeed <= 0) {
ySpeed = 5;
}
y = y + ySpeed;
}
/* Checks if the Sprite was touched. */
public boolean wasItTouched(float ex, float ey) {
boolean touched = false;
if ((x <= ex) && (ex < x + bmp_width) && (y <= ey)
&& (ey < y + bmp_height)) {
touched = true;
}
return touched;
}// End of wasItTouched
public void change(Integer[] P) {
imgid = P;
spritebmp = BitmapFactory.decodeResource(gameView.getResources(),
R.drawable.guko_ssj1);
}
}

LibGDX android translating spritebatch sometimes jumps 1-2 pixels forward (lag)?

I am making my first game using LibGDX on android.
I have a background which is 288*511, Now in my game, I need to repeat that background and then translate over it. I have made that game for desktop using Slick2D, and had the same problem, just a bit lower than on my LG G2 phone (4.0.4), is there a way to fix this lag or I am doing something wrong?
The problem is that when it's translating, its moving fine and sometimes jumps 1-2 pixels forward or just stuck for 0.5 seconds or so.
This is my class:
public class Background {
private class RepeatedBackground implements GameObject {
private int x;
private int y = 0;
Sprite background;
public RepeatedBackground(int x, Sprite s) {
this.x = x;
this.background = s;
}
#Override
public void render() {
}
public float getPreferedWidth() {
int w = Gdx.graphics.getWidth();
return (float) (w / 1.15);
}
public float getPreferedHeight() {
int h = Gdx.graphics.getHeight();
return (float) (h / 1.15);
}
#Override
public int getX() {
return this.x;
}
#Override
public int getY() {
return this.y;
}
public Sprite getSprite() {
return this.background;
}
}
private int tra = 0;
private long traTime = 0;
private List<RepeatedBackground> backgrounds = new ArrayList<RepeatedBackground>();
private Level level;
private SpriteBatch backgroundRenderer;
public Background(Level level) {
this.level = level;
this.backgroundRenderer = new SpriteBatch();
}
public void generateBackgrounds() {
int x = 0;
Sprite background = this.level.getFactory().createBackgroundSprite();
for (int i = 0; i < LevelConfig.MAX_BACKGROUND_REPEATS; i++) {
this.backgrounds.add(new RepeatedBackground(x, background));
x += background.getWidth();
}
}
public void render() {
this.backgroundRenderer.getTransformMatrix().translate(-6, 0, 0);
this.backgroundRenderer.begin();
this.backgroundRenderer.setProjectionMatrix(this.level.getInstance().getCamera().combined);
Iterator<RepeatedBackground> itr = this.backgrounds.iterator();
while (itr.hasNext()) {
RepeatedBackground b = itr.next();
Sprite s = b.getSprite();
if (b.getX() - b.getPreferedHeight() < this.level.getInstance().getCamera().viewportWidth) { // this doesn't work properly, but it doesn't load all backgorunds at once but still lags..
this.backgroundRenderer.draw(s, b.getX(), b.getY(), b.getPreferedWidth(), b.getPreferedHeight());
}
}
this.backgroundRenderer.end();
}
}
My create values for camera:
float w = Gdx.graphics.getWidth();
float h = Gdx.graphics.getHeight();
camera = new OrthographicCamera(w,h);
camera.setToOrtho(false);
batch = new SpriteBatch();
Texture.setEnforcePotImages(false);
You can use ParallaxBackground class from here
http://www.badlogicgames.com/forum/viewtopic.php?f=17&t=1795
It doesn't depends on the size of the image or camera. It just translates your background continuously
source: http://code.google.com/p/libgdx-users/wiki/ParallaxBackgound

Categories

Resources