I'm new to android development and I'm having a problem regarding the memory used by my game. It constantly rises until it crashes. I would appreciate if you could help me. Thank you.
Also, regarding the Spritebatch do i need to call this.dispose in the java class where i extend to game for it to be disposed? If so where can i call it? Thank you
public class Zero implements Screen, InputProcessor {
Pmacgame game;
private Stage stage;
private Skin skin;
private Sound sound ,laser;
private Music musicbg;
private Sprite spritebg, playerImage;
private ImageButton imgbtnLeft, imgbtnRight, fire, color1, color2, color3, color4,
bullet1, bullet2, bullet3, bullet4;
public static final float fireDelay = 0.3f;
String rr2;
private static int o = 0;
Rectangle player;
ArrayList<Bullet> bullets;
ArrayList<Target> targets;
ArrayList<Explode> explodes;
//long lastDrop;
int score;
boolean a, b;
public static final float minSpawnTime = 0.5f;
public static final float maxSpawnTime = 1.25f;
float shootTimer, targetSpawnTimer;
Random random;
public static int select;
public static int dis = 0;
public float health = 1;
private Sprite greenBar, redBar, blueBar, pinkBar, greenBarO, redBarO, blueBarO, pinkBarO;
public Zero(Pmacgame game){
#Override
public void render(float delta) {
shootTimer += Gdx.graphics.getDeltaTime();
ArrayList<Bullet> bulletsToRemove = new ArrayList<>();
if (fire.isPressed() && shootTimer >= fireDelay) {
shootTimer = 0;
bullets.add(new Bullet(player.x + 32f));
}
for (Bullet bullet : bullets) {
bullet.update(Gdx.graphics.getDeltaTime());
if (bullet.remove)
bulletsToRemove.add(bullet);
}
targetSpawnTimer -= Gdx.graphics.getDeltaTime();
if (targetSpawnTimer<=0){
targetSpawnTimer = random.nextFloat() * (maxSpawnTime -minSpawnTime) + minSpawnTime;
targets.add(new Target(MathUtils.random(267, Gdx.graphics.getWidth()-350f)));
}
ArrayList<Target> targetsToRemove = new ArrayList<>();
for (Target target: targets){
target.update(delta);
if (target.remove)
targetsToRemove.add(target);
if (target.getY()<=0){
health -= 0.1f;
if (health<=0){
select = 0;
dis = 1;
this.dispose();
game.setScreen(new GameOverScreen(game, score));
return;
}
}
}
ArrayList<Explode> explodesToRemove = new ArrayList<>();
for (Explode explode: explodes){
explode.update(delta);
if (explode.remove)
explodesToRemove.add(explode);
}
explodes.removeAll(explodesToRemove);
for (Bullet bullet: bullets){
for (Target target: targets){
if (bullet.getCollisionRect().collidesWith(target.getCollisionRect())){
targetsToRemove.add(target);
bulletsToRemove.add(bullet);
score+=5;
explodes.add(new Explode(target.getX(), target.getY()));
sound.play(1f, 1.3f, 0f);
}
}
}
targets.removeAll(targetsToRemove);
bullets.removeAll(bulletsToRemove);
//Gdx.gl.glClearColor(0f, 0f, 0f, 1f);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
game.batch.begin();
spritebg.draw(game.batch);
game.batch.draw(blueBarO, 0, 575, blueBarO.getWidth(), blueBarO.getHeight());
game.batch.draw(redBarO, 0, 550, redBarO.getWidth(), redBarO.getHeight());
game.batch.draw(greenBarO, 0, 525, greenBarO.getWidth(), greenBarO.getHeight());
game.batch.draw(pinkBarO, 0, 600, pinkBarO.getWidth(), pinkBarO.getHeight());
game.font.draw(game.batch, "SCORE: " + score, 40, Gdx.graphics.getHeight() - 40 );
for (Bullet bullet: bullets){
bullet.render(game.batch);
}
for (Target target: targets){
target.render(game.batch);
}
for (Explode explode: explodes){
explode.render(game.batch);
}
if (health == 0) greenBar.setSize(greenBar.getWidth(), 0f);
game.batch.draw(greenBar, 0, 525, greenBar.getWidth() * health, greenBar.getHeight());
game.batch.draw(redBar, 0, 550, redBar.getWidth(), redBar.getHeight());
game.batch.draw(blueBar, 0, 575, blueBar.getWidth(), blueBar.getHeight());
game.batch.draw(pinkBar, 0, 600, pinkBar.getWidth(), pinkBar.getHeight());
game.batch.draw(playerImage, player.x, player.y, player.width, player.height);
game.batch.end();
stage.act(Gdx.graphics.getDeltaTime());
stage.draw();
if (a) player.x -= 450 * Gdx.graphics.getDeltaTime();
if (b) player.x += 450 * Gdx.graphics.getDeltaTime();
if (player.x < 65f + imgbtnLeft.getWidth() + imgbtnRight.getWidth())
player.x = 65f + imgbtnLeft.getWidth() + imgbtnRight.getWidth();
if (player.x > Gdx.graphics.getWidth() - 350f)
player.x = Gdx.graphics.getWidth() - 350f;
}
#Override
public void dispose () {
musicbg.dispose();
laser.dispose();
stage.dispose();
skin.dispose();
sound.dispose();
}
}
public class Pmacgame extends Game {
SpriteBatch batch;
BitmapFont font;
#Override
public void create () {
batch = new SpriteBatch();
font = new BitmapFont(Gdx.files.internal("r.fnt"));
this.setScreen(new Zero(this));
}
#Override
public void render () {
super.render();
}
#Override
public void dispose() {
font.dispose();
batch.dispose();
}
}
I'm reading between the lines, but it looks like you must be loading a Texture in the constructor of Bullet/Target/Explosion, since I don't see you passing a Texture or TextureRegion reference to their constructors or render methods.
You should be loading all your Textures in a single class and passing references to your game objects for them to "borrow" and draw with. Otherwise, you are loading many copies of the same images for no reason.
Also, a Texture is a Disposable, which means it uses native memory and must have dispose() called on it before you let the garbage collector take it. Otherwise, the native memory is leaked.
In your case, all these Bullets, Targets, and Explosions are loading many Textures over and over and never disposing them when you remove them.
Regarding your question about the SpriteBatch. Yes, you should dispose of it in the same class you instantiate it, and dispose() is the right place to do it.
Edit, barebones example:
public class Assets implements Disposable {
public final Texture horse;
public final Texture bullet;
// etc.
public Assets (){
horse = new Texture("horse.png");
//...
}
public void dispose(){
horse.dispose();
//...
}
}
public class Zero implements Screen, InputProcessor {
private final Assets assets;
//...
public Zero (){
assets = new Assets();
//...
}
//...
public void dispose(){
assets.dispose();
//...
}
}
public class Bullet {
//...
public void render(SpriteBatch batch, Assets assets){
batch.render(assets.bullet, /*...*/);
}
}
Related
I'm doing a Java Project that consists of making a "Space Invaders" clone. I'm starting with the ship movement, searching on stackOverflow I found this code:
if(Gdx.input.isKeyPressed(Input.Keys.LEFT) )
x -= Gdx.graphics.getDeltaTime() * PlayerSpeed;
if(Gdx.input.isKeyPressed(Input.Keys.RIGHT) )
x += Gdx.graphics.getDeltaTime() * PlayerSpeed;
I use it to the playerShip(the class below):
public class PlayerShip extends Ship {
private Animator animator;
private float PlayerSpeed = 20.0f;
private int x,y;
public PlayerShip(SpriteBatch batch){
this.animator=new Animator(batch,"ship.png", 5, 2);
}
public void create(){
animator.create();
}
public void render(){
this.animator.render(this.x,this.y);
if(Gdx.input.isKeyPressed(Input.Keys.LEFT) )
x -= Gdx.graphics.getDeltaTime() * PlayerSpeed;
if(Gdx.input.isKeyPressed(Input.Keys.RIGHT) )
x += Gdx.graphics.getDeltaTime() * PlayerSpeed;
}
public void setX(int x) {
this.x = x;
}
public void setY(int y) {
this.y = y;
}
}
Game(main):
public class Game extends ApplicationAdapter {
private SpriteBatch batch;
private BackgroundManagement backgroundManagement;
private BitmapFont font;
private PlayerShip player;
private SmallShip smallShip;
#Override
public void create() {
Gdx.graphics.setWindowedMode(600, 800);
batch = new SpriteBatch();
player = new PlayerShip(batch);
smallShip = new SmallShip(batch);
player.create();
player.setX(300);
player.setY(100);
smallShip.create();
smallShip.setX(200);
smallShip.setY(400);
font = new BitmapFont(Gdx.files.internal("gamefont.fnt"),
Gdx.files.internal("gamefont.png"), false);
backgroundManagement = new BackgroundManagement(batch);
}
#Override
public void render() {
Gdx.gl.glClearColor(0, 0, 0.2f, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.begin();
backgroundManagement.render();
player.render();
smallShip.render();
batch.end();
}
#Override
public void dispose() {
batch.dispose();
}
}
When trying on my code, the ship didn't move to the right, I had tried various solutions but i didn't found any, Any help is appreciated, thanks!
The position of the ship is an integer. Your increment is a float. You maybe have a decent graphics card which can render a simple game at e.g. 200+ fps continuous render (or more even could be crazy). In 200fps case the increment would be (1/200)*20 = 1/10 float.
integer += .1f
won't change the original integer.
Change your position to a float as well, then cast (or convert) to an integer when you need to actually render so x can increment very small values.
this is my first question to ask here so i am sry beforehand that i do something wrong here.
I am currently trying to develop my first own game in libgdx.
So for the start i have 4 classes.
FlipX a class that extends from Game.
StartMenu a class that implements from Screen.
GameScreen a class that implements from Screen.
Button a class that extens from Sprite.
I hope i can show you some code here, but let me first explain.
When starting the code the Class FlipX, where i have my SpriteBatch to draw, set the Screen to the StartMenu Class. There i can click on 2 Buttons which are drawn to the SpriteBatch from FlipX.
These Buttons came from the Button Class which i created to store multiple Textures to one so called Button. This Button Class extends from Sprite.
The PlayBtn will set the Screen to the GameScreen class when i click on it.
The Problem then occurs when the GameScreen Class draws another Button on the same batch after the Screen is set to GameScreen.
It is the Line from GameScreen in the drawBatch() function where i draw jumpBtn.draw(game.batch).
When i do this i get the following error.
Exception in thread "LWJGL Application" java.lang.NullPointerException
at com.badlogic.gdx.graphics.g2d.SpriteBatch.switchTexture(SpriteBatch.java:1067)
at com.badlogic.gdx.graphics.g2d.SpriteBatch.draw(SpriteBatch.java:558)
at com.badlogic.gdx.graphics.g2d.Sprite.draw(Sprite.java:580)
at de.geecogames.flipx.Screens.GameScreen.drawBatch(GameScreen.java:88)
at de.geecogames.flipx.Screens.GameScreen.render(GameScreen.java:63)
at com.badlogic.gdx.Game.render(Game.java:46)
at de.geecogames.flipx.FlipX.render(FlipX.java:26)
at com.badlogic.gdx.backends.lwjgl.LwjglApplication.mainLoop(LwjglApplication.java:232)
at com.badlogic.gdx.backends.lwjgl.LwjglApplication$1.run(LwjglApplication.java:127)
This Error does not occur when i replace the Button with a simple Sprite, which is odd because the Button Class is just a class that extends Sprite.
private Sprite jumpBtn = new Sprite(new Texture("game/UpDef.png"));
public class FlipX extends Game {
public SpriteBatch batch;
//Filemanager to load Assets from an Asset Manager
public FileManager manager;
StartMenu startMenu;
#Override
public void create () {
manager= new FileManager();
startMenu=new StartMenu(this);
batch = new SpriteBatch();
setScreen(startMenu);
}
#Override
public void render () {
super.render();
}
#Override
public void dispose () {
batch.dispose();
}
public FileManager getFileManager(){
return manager;
}
}
public class StartMenu implements Screen {
private final FlipX game;
private final FileManager fileM;
private final OrthographicCamera camera;
private final FitViewport viewport;
private Sprite img = new Sprite(new Texture("badlogic.jpg"));
private final Button playBtn, exitBtn;
private final Sprite backGround;
private boolean playPressed, exitPressed;
public StartMenu(FlipX game) {
this.game = game;
//Get Manager and load Assets
this.fileM = game.getFileManager();
fileM.loadAssetsMenu();
//Testlabel
Label testlabel = new Label(String.format("test"), new Label.LabelStyle(new BitmapFont(), Color.BLACK));
//Get the Assets from Manager
playBtn = new Button(fileM.getTexture(fileM.playBtnDefault), fileM.getTexture(fileM.playBtnHover), fileM.getTexture(fileM.playBtnClick));
exitBtn = new Button(fileM.getTexture(fileM.exitBtnDefault), fileM.getTexture(fileM.exitBtnHover), fileM.getTexture(fileM.exitBtnClick));
backGround = fileM.getSprite(fileM.backgroundMenu);
camera = new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
viewport = new FitViewport(Z.V_WIDTH, Z.V_HEIGHT, camera);
camera.position.set(viewport.getWorldWidth() / 2, viewport.getWorldHeight() / 2, 0);
//Btn Position
playBtn.setPosition(Z.V_WIDTH / 2 - playBtn.getWidth() / 2, Z.V_HEIGHT / 2 - playBtn.getHeight() / 2);
exitBtn.setPosition(Z.V_WIDTH / 2 - exitBtn.getWidth() / 2, Z.V_HEIGHT / 2 - exitBtn.getHeight() / 2 - playBtn.getHeight() - playBtn.getHeight() / 2);
img.setPosition(0, 0);
}
#Override
public void render(float delta) {
update(delta);
clearColor();
drawBatch();
}
private void update(float dt) {
handleInput();
cameraUpdates();
}
private void clearColor() {
Gdx.gl.glClearColor(0, 0.5f, 0.9f, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
}
private void drawBatch() {
game.batch.setProjectionMatrix(camera.combined);
game.batch.begin();
backGround.draw(game.batch);
img.draw(game.batch);
//Buttons
playBtn.draw(game.batch);
exitBtn.draw(game.batch);
game.batch.end();
}
private void handleInput() {
Vector3 realCoords = viewport.unproject(new Vector3(Gdx.input.getX(), Gdx.input.getY(), 0));
if (Gdx.input.isKeyPressed(Input.Keys.K)) {
float addX = 2;
float addY = 0;
img.setPosition(img.getX() + addX, img.getY() + addY);
}
if (Gdx.input.isKeyPressed(Input.Keys.UP)) {
camera.position.y = camera.position.y + 1;
} else if (Gdx.input.isKeyPressed(Input.Keys.DOWN)) {
camera.position.y = camera.position.y - 1;
}
if (Gdx.input.isKeyPressed(Input.Keys.LEFT)) {
camera.position.x = camera.position.x - 1;
} else if (Gdx.input.isKeyPressed(Input.Keys.RIGHT)) {
camera.position.x = camera.position.x + 1;
}
if (Gdx.input.isKeyPressed(Input.Keys.PAGE_UP)) {
camera.zoom = camera.zoom + 0.1f;
} else if (Gdx.input.isKeyPressed(Input.Keys.PAGE_DOWN)) {
camera.zoom = camera.zoom - 0.1f;
}
//btn test
if (BasicFunctions.isInside(realCoords.x, realCoords.y, playBtn)) {
if (Gdx.input.justTouched()) {
playBtn.setClick();
playPressed = true;
fileM.playSound(fileM.playBtnSound);
} else {
if (playPressed) {
game.setScreen(new GameScreen(game));
}
playBtn.setHover();
}
} else
playBtn.setNormal();
if (BasicFunctions.isInside(realCoords.x, realCoords.y, exitBtn)) {
if (Gdx.input.isTouched()) {
exitBtn.setClick();
exitPressed = true;
} else {
if (exitPressed)
Gdx.app.exit();
exitBtn.setHover();
}
} else
exitBtn.setNormal();
}
private void cameraUpdates() {
camera.update();
}
}
public class GameScreen implements Screen {
private final FlipX game;
private final FileManager fileM;
private final OrthographicCamera camera;
private final FitViewport viewport;
private final Button jumpBtn;
private final Sprite background;
public GameScreen(FlipX game){
this.game=game;
this.fileM=game.getFileManager();
fileM.loadAssetsGame();
camera=new OrthographicCamera(Gdx.graphics.getWidth(),Gdx.graphics.getHeight());
viewport = new FitViewport(Z.V_WIDTH,Z.V_HEIGHT,camera);
jumpBtn = new Button(new Texture("game/UpDef.png"),new Texture("game/UpHov.png"),new Texture("game/UpClick.png"));
jumpBtn.setPosition(2,2);
background = fileM.getSprite(fileM.backgroundMenu);
}
#Override
public void show() {
}
#Override
public void render(float delta) {
update(delta);
clearColor();
drawBatch();
}
private void update(float dt){
handleInput(dt);
}
private void clearColor() {
Gdx.gl.glClearColor(1, 0.5f, 0.9f, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
}
private void drawBatch(){
game.batch.setProjectionMatrix(camera.combined);
game.batch.begin();
background.draw(game.batch);
//Bug here?
jumpBtn.draw(game.batch);
game.batch.end();
}
private void handleInput(float dt){
Vector3 realCoords = viewport.unproject(new Vector3(Gdx.input.getX(), Gdx.input.getY(), 0));
if(Gdx.input.isTouched()){
if(BasicFunctions.isInside(realCoords.x,realCoords.y,jumpBtn)){
EzLog.logging("X " + jumpBtn.getX() + " Y " + jumpBtn.getY());
}
}
}
public class Button extends Sprite {
private final Texture normal, hover, click;
private float stateTimer;
public Button(Texture normal, Texture hover, Texture click){
this.normal=normal;
this.hover=hover;
this.click=click;
stateTimer=0;
setSize();
}
private void setSize(){
float height,width;
width=normal.getWidth();
height=normal.getHeight();
setBounds(0,0,width*3,height*3);
}
public void setNormal(){
setRegion(normal);
}
public void setHover(){
setRegion(hover);
}
public void setClick(){
setRegion(click);
}
}
After hours and hours i found the solution.
The Problem is that my Class Button can save up to 3 textures.
To draw one of the textures, we can use the draw function of it because Button extends from Sprite. To show it on the SpriteBatch it just needs to set the texture to the region.
setRegion("TextureHere.png")
So everytime i draw it with my playBtn.draw(game.batch) it will show this texture at the position i gave him before with setPosition(x,y)
But i never actually do "setRegion()" in the Constructor, so it will try to draw something which isn't there. And this is the thing why it says NullPointerException. I just got confused of the error because of the functions switchTexture from SpriteBatch.
In the Class StartMenu it coincidentally just calls the "setRegion()" because it is always called in the else part from the condition in "handleInput" with the function "setNormal()" from the Button Class.
Solution i know has is the following:
I added the setNormal() function in the Constructor so the first texture will always be set to region, if i can say it like this, and this works.
public class Button extends Sprite {
private final Texture normal, hover, click;
public Button(Texture normal, Texture hover, Texture click){
this.normal=normal;
this.hover=hover;
this.click=click;
setSize();
setNormal();
}
private void setSize(){
float height,width;
width=normal.getWidth();
height=normal.getHeight();
setBounds(0,0,width*3,height*3);
}
public void setNormal(){
setRegion(normal);
}
public void setHover(){
setRegion(hover);
}
public void setClick(){
setRegion(click);
}
I'm reading a book about game development: Beginning Java Game Development with LibGDX.
There was a class named CheesePlease3 that I copied from the book, it presented the Stage class, and Actor class, I had to make a subclass from the Actor class, named BaseActor.
I did everything correctly, basically copy-pasted the whole thing, and it doesn't draw any object.
So my question is why? What is wrong?
Maybe the code itself a little bit long but easy to read.
Here is the CheesePlease3 class:
public class CheesePlease3 extends Game {
public Stage mainStage;
private BaseActor mouse;
private BaseActor cheese;
private BaseActor floor;
private BaseActor winText;
#Override
public void create () {
mainStage = new Stage();
floor = new BaseActor();
floor.setTexture(new Texture("floor.png"));
floor.setPosition(0, 0);
mainStage.addActor(floor);
cheese = new BaseActor();
cheese.setTexture(new Texture("cheese.png"));
cheese.setPosition(300, 300);
mainStage.addActor(cheese);
mouse = new BaseActor();
mouse.setTexture(new Texture("mouse.png"));
mouse.setPosition(200, 200);
mainStage.addActor(mouse);
winText = new BaseActor();
winText.setTexture(new Texture("youWon.png"));
winText.setPosition(150, 150);
winText.setVisible(false);
mainStage.addActor(winText);
}
#Override
public void render(){
// process input
mouse.velocityX = 0;
mouse.velocityY = 0;
if (Gdx.input.isKeyPressed(Input.Keys.LEFT))
mouse.velocityX -= 100;
if (Gdx.input.isKeyPressed(Input.Keys.RIGHT))
mouse.velocityX += 100;
if (Gdx.input.isKeyPressed(Input.Keys.UP))
mouse.velocityY -= 100;
if (Gdx.input.isKeyPressed(Input.Keys.DOWN))
mouse.velocityY += 100;
// update
float dt = Gdx.graphics.getDeltaTime();
mainStage.act(dt);
// check win condition: Mouse must be overlapping cheese
Rectangle mouseRectangle = mouse.getBoundingRectangle();
Rectangle cheeseRectangle = cheese.getBoundingRectangle();
if (mouseRectangle.contains(cheeseRectangle))
winText.setVisible(true);
// draw graphics
Gdx.gl.glClearColor(0.8f, 0.8f, 1, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
mainStage.draw();
}
And here is the BaseActor class:
public class BaseActor extends Actor {
public TextureRegion region;
public Rectangle boundary;
public float velocityX;
public float velocityY;
public BaseActor(){
super();
region = new TextureRegion();
boundary = new Rectangle();
velocityX = 0;
velocityY = 0;
}
public void setTexture (Texture t){
int w = t.getWidth();
int h = t.getHeight();
setWidth(w);
setHeight(h);
region.setRegion(t);
}
public Rectangle getBoundingRectangle(){
return boundary.set(getX(), getY(), getWidth(), getHeight());
}
#Override
public void act (float dt){
super.act(dt);
moveBy(velocityX * dt, velocityY * dt);
}
public void drawBatch (Batch batch, float parentAlpha){
Color c = getColor();
batch.setColor(c.r, c.g, c.b, c.a);
if (isVisible())
batch.draw(region, getX(), getY(), getOriginX(), getOriginY(),
getWidth(), getHeight(), getScaleX(), getScaleY(), getRotation());
}
And here is the DesktopLauncher:
public static void main (String[] arg) {
LwjglApplicationConfiguration config = new LwjglApplicationConfiguration();
new LwjglApplication(new CheesePlease3(), config);
config.title = "Mouse - Cheese";
}
The BaseActor has to override the draw method.
I assume the drawBatch method should be renamed to draw.
Ps.:
The movement for up and down is inverted.
I am using the Android Studio IDE, with the libGDX framework to develop a game. It is a clone of the Pac-Man game with a similar gameplay to flappy bird. The concept is that the pac man moves through the planks while avoiding the ghosts coming from the right direction, that are moving off straight into the left direction (not chasing the position of the player). I am not sure how I create a 'for loop' for the ghost animations, I want the ghosts to consistently reposition and re-appear from the right side after a few seconds, with the exception that they completely gone off the screen initially.
The class for one of the Ghosts.
public class Blinky {
private Vector3 position; //x y and z axis
private Rectangle bounds;
private Texture texture1;
private Animation blinkyAnimLeft;
public Blinky(int x, int y) {
position = new Vector3(x, y, 0);
Texture texture1 = new Texture("blinkyLeft.png");
blinkyAnimLeft = new Animation(new TextureRegion(texture1), 2, 0.5f);
//bounds = new Rectangle(x,y,texture1.getWidth() / 2, texture1.getHeight());
}
public void update(float dt) {
blinkyAnimLeft.update(dt);
//bounds.setPosition(position.x, position.y);
}
public Vector3 getPosition() {
return position;
}
public TextureRegion getTexture() {
return blinkyAnimLeft.getFrame();
}
//public Rectangle getBounds() {
return bounds;
}
public void dispose() {
texture1.dispose();
}
}
Ghosts and Player initialised in the GamePlayState Class
public class GamePlayState extends State {
//Variables
private float timePassed = 0;
private Texture background;
public static final int WALK = 1;
public static final double GHOST_WALK = 0.5;
private static final int PLANKS_SPACING = 125; //gap betwen the planks
private static final int PLANK_COUNT = 4;
private Array<Obstacle> planks;
private Player player;
private Blinky blinky;
private Inky inky;
private Texture missile;
public GamePlayState(GameStateManager gsm) {
super(gsm);
player = new Player(50, 100);
blinky = new Blinky(400, 220);
inky = new Inky(400, 240);
// missile = new Texture("missile.png");
background = new Texture("black.jpg");
cam.setToOrtho(false, PacMan.WIDTH/2, PacMan.HEIGHT/2);
planks = new Array<Obstacle>();
for (int i = 1; i<= PLANK_COUNT; i++) {
planks.add(new Obstacle(i * (PLANKS_SPACING + Obstacle.PLANK_WIDTH)));
}
}
#Override
public void handleInput() {
}
#Override
public void update(float dt) {
handleInput();
player.update(dt);
blinky.update(dt);
inky.update(dt);
cam.position.x = player.getPosition().x + 80; //update the position of the camera with the bird
//update when pacman cam viewport has passed plank
//make cam follow the player
for (Obstacle plank: planks) {
if (cam.position.x - (cam.viewportWidth/1) > plank.getPosTopPlank().x + plank.getTopPlank().getWidth()) {
plank.respositionPlanks(plank.getPosTopPlank().x + ((Obstacle.PLANK_WIDTH + PLANKS_SPACING * PLANK_COUNT )));
}
if (plank.collision (player.getBounds()))
gsm.set(new GamePlayState(gsm));
}
cam.update();
}
#Override
public void render(SpriteBatch sb) {
sb.setProjectionMatrix(cam.combined);
sb.begin();
sb.draw(background, cam.position.x - (cam.viewportWidth/2), 0);
timePassed += Gdx.graphics.getDeltaTime();
//Moving Inky
sb.draw(inky.getTexture(), inky.getPosition().x, inky.getPosition().y);
inky.getPosition().x -= GHOST_WALK;
//Moving Blinky
sb.draw(blinky.getTexture(), blinky.getPosition().x, blinky.getPosition().y);
blinky.getPosition().x -= GHOST_WALK;
You should get x, y( and z) position from Vector3.
Then check for borders
if (inky.getPosition().x < 0){
Thread.sleep(/*a few sdeconds*/2000);/*Android studio would ask you about wrapping it with try - catch*/
inky.setPostion( x + /*screen x size*/,
inky.getPosition().y,inky.getPosition().z)/*add setter in ghost class*/
}
In fact, this is not the best way to do it, but the simplest one
I'm learning libgdx and currently doing a flappy bird demo. For fun I tried to implement when the score reached a certain number the bird sprite texture will update and change to another color. Instead of using the spritebatch and changing the color through tinting I wanted to create a new texture(png file).
The problem is since it is a sprite it needs to be animated so the wings will flap. When I try and update the texture at runtime it will only work but the animation wont play.
Here is my bird class:
public class Bird {
private static final int GRAVITY = -15;
private static final int MOVEMENT = 100;
private Vector3 position;
private Vector3 velocity;
private Rectangle bounds;
private Animation birdAnimation;
private Texture birdTexture;
private TextureRegion textureRegion;
private Sound flap;
public Bird(int x, int y){
position = new Vector3(x, y, 0);
velocity = new Vector3(0, 0, 0);
textureRegion = new TextureRegion(returnTexture());
birdAnimation = new Animation(textureRegion, 3, 0.5f);
bounds = new Rectangle(x, y, returnTexture().getWidth() / 3, returnTexture().getHeight());
flap = Gdx.audio.newSound(Gdx.files.internal("sfx_wing.ogg"));
}
public void update(float dt){
textureRegion = new TextureRegion(returnTexture());
birdAnimation = new Animation(textureRegion, 3, 0.5f);
birdAnimation.update(dt);
if(position.y > 0){
velocity.add(0, GRAVITY, 0);
}
velocity.scl(dt);
position.add(MOVEMENT * dt, velocity.y, 0);
if(position.y < 0){
position.y = 0;
}
velocity.scl(1/dt);
bounds.setPosition(position.x, position.y);
}
public TextureRegion getTexture() {
return birdAnimation.getFrame();
}
public Texture returnTexture(){
if(PlayState.score > 1){
return birdTexture = new Texture("birdanimation1.png");
}else{
return birdTexture = new Texture("birdanimation.png");
}
}
public Vector3 getPosition() {
return position;
}
public void jump(){
velocity.y = 250;
flap.play(0.15f);
}
public Rectangle getBounds(){
return bounds;
}
public void dispose(){
returnTexture().dispose();
flap.dispose();
}
}
Here is my animation class:
public class Animation {
private Array<TextureRegion> frames;
private float maxFrameTime;
private float currentFrameTime;
private int frameCount;
private int frame;
public Animation(TextureRegion region, int frameCount, float cycleTime){
frames = new Array<TextureRegion>();
int frameWidth = region.getRegionWidth() / frameCount;
for(int i = 0; i < frameCount; i++){
frames.add(new TextureRegion(region, i * frameWidth, 0, frameWidth, region.getRegionHeight()));
}
this.frameCount = frameCount;
maxFrameTime = cycleTime / frameCount;
frame = 0;
}
public void update(float dt){
currentFrameTime += dt;
if(currentFrameTime > maxFrameTime){
frame++;
currentFrameTime = 0;
}
if(frame >= frameCount){
frame = 0;
}
}
public TextureRegion getFrame(){
return frames.get(frame);
}
}
Here's my render code in my play state:
#Override
public void render(SpriteBatch sb) {
sb.setProjectionMatrix(cam.combined);
sb.begin();
sb.draw(bg, cam.position.x - (cam.viewportWidth /2), 0);
sb.draw(bird.getTexture(), bird.getPosition().x, bird.getPosition().y);
for(Tube tube : tubes){
sb.draw(tube.getTopTube(), tube.getPosTopTube().x, tube.getPosTopTube().y);
sb.draw(tube.getBottomTube(), tube.getPosBotTube().x, tube.getPosBotTube().y);
}
sb.draw(ground, groundPos1.x, groundPos1.y);
sb.draw(ground, groundPos2.x, groundPos2.y);
font.draw(sb, text, cam.position.x - gl.width / 2, cam.position.y + 200);
sb.end();
}
If you need any other classes just ask. I'm probably making a stupid mistake or just coding it entirely wrong for what I'm trying to achieve.
Thanks, Jackson
You need to NOT load your textures every single frame.
libgdx has its own Animation class so you don't need to make your own.
Here is an example on animation from libgdx's github:
2D Animation
To make it simple, just have 2 animaitons on Bird and switch between them when you need to.