Java game with libGDX: my ship cant move to the right - java

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.

Related

Memory Leakage. Constantly rises until game crashes

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, /*...*/);
}
}

Libgdx class does not draw Texture

I am trying to draw a game character in my "MainGameScreen.java" class from the "germans.java" class when I touch the screen of my phone.Unfortunately my program does not draw the image nor does it give me a warning or an error.
MainGameScreen.java:
import com.daenni.trenchwarfare.mygdx.enteties.germans;
public class MainGameScreen implements Screen, InputProcessor {
Trench_Warfare game;
public SpriteBatch batch;
//Enemies
ArrayList<germans> german;
public MainGameScreen (Trench_Warfare game) {
this.game = game;
batch = new SpriteBatch();
//Enemies
//Initialise Array
german = new ArrayList<germans>();
}
#Override
public void render(float delta) {
//Colours
Gdx.gl.glClearColor(116/255f,102/255f,91/255f,1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
//Create Germans
if (Gdx.input.justTouched()){
german.add(new germans(300));
german.add(new germans(400));
}
//Update Germans
for (germans german : german) {
german.update(delta);
}
game.batch.begin();
//Render Germans
for (germans germans : german) {
germans.render(game.batch);
}
//Background
game.batch.draw(background,0,0);
game.batch.draw(background_links,-background_links.getWidth(),0);
game.batch.draw(background_rechts,background.getWidth(),0);
game.batch.end();
}
This is all of the code that I use to render it in the "MainGameScreen.java" file.
This is my class:
public class germans {
//Set speed
public static final int speed = 25;
//Constant
public static final int default_x = 300;
//Every german uses the same Texture
private static Texture texture;
//Position
float x, y;
public boolean remove = false;
//Create german
public germans(float y) {
this.x = default_x;
this.y = y;
y = 200;
if (texture == null) { //When texture is never loaded
//Set Texture
texture = new Texture("de_s1_default.png");
}
}
public void update (float deltaTime){
x += speed * deltaTime;
}
public void render (SpriteBatch batch) {
batch.draw(texture,x,y);
}
}
Although I am not keen on how libgdx exactly works I am pretty sure first drawing your "germans" and then the background is not what you want.
Try swapping it around:
//Background
game.batch.draw(background,0,0);
game.batch.draw(background_links,-background_links.getWidth(),0);
game.batch.draw(background_rechts,background.getWidth(),0);
//Render Germans
for (germans germans : german) {
germans.render(game.batch);
}

How do I reposition a moving animation during a gameplay?

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

Libgdx, Android, how to drag and move a texture

currently the method I used is to detect whether touch position (Gdx.input.getX() & Y()) is in the area whether the object texture is. If so I setPosition of the object texture to the mouse position as center. While this work but it is not robust. Because if my finger move faster than the update, as soon as the touched position is outside texture bound. It won't update any more.
There must be a more reliable way and please advice. Essentially, I want to touch on the texture and drag the texture to wherever my touch is moving.
Many thanks.
My current approach is like this:
public class PlayScreen implements Screen {
int scWidth, scHeight;
int playerWidth, playerHeight;
private SpriteBatch batch; // This is in the render.
Player player;
// Create a constructor
Game game;
public PlayScreen(Game game){
this.game = game;
}
#Override
public void show() {
batch = new SpriteBatch();
scWidth = Gdx.graphics.getWidth();
scHeight = Gdx.graphics.getHeight();
playerWidth = 180;
playerHeight = 240;
player = new Player("mario.png", new Vector2(250, 300),new Vector2(playerWidth, playerHeight)) ;
}
#Override
public void render(float delta) {
Gdx.gl.glClearColor(1,1,1,1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.begin();
// Only draw if the mouse is hover on the image.
if (Gdx.input.getX() > player.getPosition().x && Gdx.input.getX() < player.getPosition().x + playerWidth){
if (scHeight - Gdx.input.getY() > player.getPosition().y && scHeight - Gdx.input.getY() < player.getPosition().y + playerHeight)
{
player.setPosition(new Vector2(Gdx.input.getX() - playerWidth/2,
scHeight - Gdx.input.getY() - playerHeight/2));
player.draw(batch);
} else{
player.draw(batch);
}
} else{
player.draw(batch);
}
batch.end();
player.update(); // Update the bound
}
}
Also the Player class is :
package com.jiajunyang.emosonicsgame;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.scenes.scene2d.ui.Image;
public class Player extends Image {
Vector2 position, size;
Texture player;
Rectangle bounds;
public Player(String fileName, Vector2 position, Vector2 size){
super(new Texture(Gdx.files.internal(fileName)));
this.position = position;
this.size = size;
bounds = new Rectangle(position.x, position.y, size.x, size.y);
// player = new Texture(Gdx.files.internal(fileName));
}
public void update(){
bounds.set(position.x, position.y, size.x, size.y);
}
public void draw(SpriteBatch batch){
batch.draw(player, position.x, position.y, size.x, size.y);
}
public Vector2 getPosition() {
return position;
}
public void setPosition(Vector2 position) {
this.position = position;
}
public Vector2 getSize() {
return size;
}
public void setSize(Vector2 size) {
this.size = size;
}
public Rectangle getBounds() {
return bounds;
}
public void setBounds(Rectangle bounds) {
this.bounds = bounds;
}
}
Jiajun, create a Stage and have your Player extend Image. Then call stage.addActor(player) in show. In render call stage.act() and stage.draw(). Use the Image's constructor to pass your Texture into. Finally, in Player's constructor, call this:
addListener(new DragListener() {
#Override
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
return true;
}
#Override
public void touchDragged(InputEvent event, float x, float y, int pointer) {
moveBy(x - getWidth()/2, y - getHeight()/2);
}
});

libgdx simple game is stuttering a lot

I just started with libgdx and so I created a simple test application where an image just moves. The problem is that even if its an extremly simple game the image is stuttering a lot while it moves. Here is the code:
public class Game extends ApplicationAdapter {
private Entity e;
private OrthographicCamera camera;
private SpriteBatch batch;
#Override
public void create () {
batch = new SpriteBatch();
e = new Entity(50,50,"badlogic.jpg");
camera = new OrthographicCamera();
camera.setToOrtho(false, 480, 800);
camera.update();
}
#Override
public void render () {
Gdx.gl.glClearColor(1, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
camera.update();
e.setX(e.getX()+100 * Gdx.graphics.getDeltaTime());
batch.setProjectionMatrix(camera.combined);
batch.begin();
e.draw(batch);
batch.end();
}
The entity class:
public class Entity {
private Texture texture;
private Rectangle hitbox;
private float x,y;
public Entity(float x,float y,String texture){
this.x=x;
this.y=y;
this.texture=new Texture(Gdx.files.internal(texture));
this.hitbox=new Rectangle(x,y,this.texture.getWidth(),this.texture.getHeight());
}
public void draw(SpriteBatch sb){
sb.draw(texture, x, y);
}
public boolean collidesWith(Entity e){
return this.hitbox.overlaps(e.getHitbox());
}
public Rectangle getHitbox() {
return hitbox;
}
public float getX() {
return x;
}
public void setX(float x) {
this.x = x;
}
public float getY() {
return y;
}
public void setY(float y) {
this.y = y;
}
Can someone explain me why this is stuttering?
getDeltaTime() is smoothed out over multiple frames so if a average frame takes .016 seconds and suddenly there is a frame taking .030 seconds then getDeltaTime() will just return .016. So in reality the game has progressed .030 seconds but you multiply your movement by .016.
getRawDeltaTime() gives you the real time passed since last frame. Try to use this as you multiplier. Otherwise try to log both and see if there are differences.
The benefit of using the smoothed getDeltaTime() is when frame drops happen the game will be still playable. While with getRawDeltaTime() if there would suddenly a second pass for the next frame then your velocity would get multiplied by 1 instead of .016 and could immediately go of screen or miss collision detection.

Categories

Resources