I'm new to libgdx, I'm trying to make a sprite move while the camera follows. I can make the sprite move perfectly until I attach the camera to it. When I click, the sprite will move wherever it feels like (it seems) and the camera will follow properly. I've tried a few different things but at this point its just guessing and checking.
public class MyGdxGame implements ApplicationListener {
OrthographicCamera mCamera;
SpriteBatch mBatch;
Texture mTexture, mMap;
Sprite sprite;
float touchX, touchY;
float spriteX, spriteY, speed = 5;
#Override
public void create() {
float CAMERA_WIDTH = 480, CAMERA_HEIGHT = 320;
mBatch = new SpriteBatch();
mTexture = new Texture(Gdx.files.internal("data/logo.png"));
mMap = new Texture(Gdx.files.internal("data/sc_map.png"));
mCamera = new OrthographicCamera(CAMERA_WIDTH, CAMERA_HEIGHT);
mCamera.setToOrtho(false, CAMERA_WIDTH, CAMERA_HEIGHT);
}
#Override
public void dispose() {
}
#Override
public void render() {
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
mBatch.setProjectionMatrix(mCamera.combined);
mCamera.update();
mBatch.begin();
updateInput();
drawD();
mBatch.end();
}
#Override
public void resize(int width, int height) {
}
#Override
public void pause() {
}
#Override
public void resume() {
}
public void drawD() {
mCamera.position.set(spriteX, spriteY, 0);
mBatch.draw(mMap, 0, 0);
mBatch.draw(mTexture, spriteX, spriteY);
}
public void updateInput() {
if (Gdx.input.justTouched()) {
touchX = Gdx.input.getX();
touchY = Gdx.input.getY();
}
if (touchX != spriteX) {
if (spriteX < touchX) {
spriteX += speed;
}
if (spriteX > touchX) {
spriteX -= speed;
}
}
if (touchY != spriteY) {
if (spriteY > Gdx.graphics.getHeight() - touchY) {
spriteY -= 10;
}
if (spriteY < Gdx.graphics.getHeight() - touchY) {
spriteY += 10;
}
}
}
}
Since you have spent a decent amount of time and are trying to get it working, I will give you a little push forward closer to what you are looking for. Look over the changes I made and below I will outline what I did to help you understand the code better.
Orthographic Camera, when you setup the camera 0,0 is the center of the screen. The width and the height are what you specified into the constructor. So the top edge would be x, 160 and the bottom edge would be x, -160. The left edge would be -240, y and the right edge would be 240, y.
drawD() Notice that I'm drawing the sprite in the middle of the image and it isn't moving. I instead move the map around in the opposite direction (y is inverted).
updateInput() Notice I pass in a delta value (this is the time in seconds between frames) this allows you to smoothly move things. The speed is 120, so this will smoothly move your character at a rate of 120/second.
The if condition is basically a simply way to compare the float values so it stops when it gets close enough. This prevents it from over shooting the target position and then bouncing back and forth because it might not be able to get to the exact value.
I added dispose calls for the textures you loaded, these are important as you don't want to fill up your memory.
I hope this helps get you started and pointed in the right direction. Working on games is a lot of work and takes time, so be patient and be ready to learn lots along the way!
Based on your comment I believe what you are looking for is something closer to this:
public class MyGdxGame implements ApplicationListener {
OrthographicCamera mCamera;
SpriteBatch mBatch;
Texture mTexture, mMap;
float touchX, touchY;
float spriteX, spriteY, speed = 120;
final float CAMERA_WIDTH = 480, CAMERA_HEIGHT = 320;
#Override public void create() {
mCamera = new OrthographicCamera(CAMERA_WIDTH, CAMERA_HEIGHT);
mBatch = new SpriteBatch();
mTexture = new Texture(Gdx.files.internal("data/logo.png"));
mMap = new Texture(Gdx.files.internal("data/sc_map.png"));
}
#Override public void dispose() {
mTexture.dispose();
mMap.dispose();
}
#Override public void render() {
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
updateInput(Gdx.graphics.getDeltaTime());
mCamera.update();
mBatch.setProjectionMatrix(mCamera.combined);
mBatch.begin();
drawD();
mBatch.end();
}
#Override public void resize(final int width, final int height) {}
#Override public void pause() {}
#Override public void resume() {}
public void drawD() {
mBatch.draw(mMap, -spriteX - (mMap.getWidth() / 2), spriteY - (mMap.getHeight() / 2));
mBatch.draw(mTexture, -32, -32, 64, 64);
}
public void updateInput(final float delta) {
if (Gdx.input.justTouched()) {
touchX = Gdx.input.getX() - (Gdx.graphics.getWidth() / 2);
touchY = Gdx.input.getY() - (Gdx.graphics.getHeight() / 2);
}
final float dv = delta * speed;
if (Math.abs(touchX - spriteX) > 1) {
if (spriteX < touchX) {
spriteX += dv;
}
if (spriteX > touchX) {
spriteX -= dv;
}
}
if (Math.abs(touchY - spriteY) > 1) {
if (spriteY > touchY) {
spriteY -= dv;
}
if (spriteY < touchY) {
spriteY += dv;
}
}
}
}
Related
This is my first try in libGDX and I've not seen an issue like this before, googling didn't help either. What I'm trying to to display a background, Later on I'll make this move, but for me it was a great start to actually display the image. It displays, but it's streched out (See picture below)
And my code is:
private BombArrangement game;
private OrthographicCamera gameCamera;
private Viewport gamePort;
private Texture backGroundTexture;
public PlayScreen(BombArrangement game) {
this.game = game;
gameCamera = new OrthographicCamera();
gamePort = new FitViewport(BombArrangement.V_WIDTH, BombArrangement.V_HEIGHT, gameCamera);
backGroundTexture = new Texture("startbackground.png");
}
#Override
public void show() {
}
#Override
public void render(float delta) {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
game.batch.begin();
game.batch.draw(new TextureRegion(backGroundTexture, 0, 0, BombArrangement.V_WIDTH, BombArrangement.V_HEIGHT), 0, 0);
game.batch.end();
}
#Override
public void resize(int width, int height) {
gamePort.update(width, height);
}
#Override
public void pause() {
}
#Override
public void resume() {
}
#Override
public void hide() {
}
#Override
public void dispose() {
}
}
I tried several things like textureregions, sprites and more but all of them give this result.
not exactly sure what your want to do but i use this to render my background in my main menu:
//Camera
camera = new OrthographicCamera();
camera.setToOrtho(false, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
//Viewport
ScreenViewport viewport = new ScreenViewport(camera);
//Background
backgroundImage = new Texture(pathToImage);
//Stage
stage = new Stage();
stage.setViewport(viewport);
(this is located in my constructor and camera, backgroundImage and stage are fields in my class)
in render method
(ConfigData holds data of settings applied to the game; DEFAULT_WIDHT and -HEIGHT are just some values I use to initialize the window when not in fullscreen mode; Replace them with your values used in the DesktopLauncher for
config.widht
and
config.height
):
#Override
public void render(float delta) {
//Clear screen
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
stage.act();
stage.getBatch().begin();
stage.getBatch().draw(backgroundImage, 0, 0, ConfigData.DEFAULT_WIDTH, ConfigData.DEFAULT_HEIGHT);
stage.getBatch().end();
stage.draw();
}
my resize method:
#Override
public void resize(int width, int height) {
camera.setToOrtho(false, width, height);
stage.getViewport().update(width, height);
}
hopes this helps somehow someone because i figured out this by myself and it costed some effort (:
As a response to your last comment:
You are now scaling down the height correctly but the width remains the same. Try to multiply the width by the same amount you scale the height down, so with some alterations to the code you linked in the comment (not tested):
private Texture texture;
private int x1, x2, speed, scaledHeight, scaledWidth;
public StartBackground() {
texture = new Texture("startbackground.png");
x1 = 0;
x2 = texture.getWidth();
speed = 5;
float imageRatio = Gdx.graphics.getHeight() / texture.getHeight();
scaledHeight = (int) (texture.getHeight() * imageRatio);
scaledWidth = (int) (texture.getWidth() * imageRatio);
}
public void updateAndRender(float deltaTime, SpriteBatch spriteBatch) {
x1 -= speed;
x2 -= speed;
// If image is off screen and not visible
if (x1 + texture.getWidth() <= 0) x1 = x2 + texture.getWidth();
if (x2 + texture.getWidth() <= 0) x2 = x1 + texture.getWidth();
// Render
spriteBatch.draw(texture, x1, 0, scaledWidth, scaledHeight);
spriteBatch.draw(texture, x2, 0, scaledWidth, scaledHeight);
}
This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 5 years ago.
For some reason, when I try to pass through Gdx.graphics.getDeltaTime() into my player class, the float delta time is null giving a null pointer exception. I already tried to check if the getDeltaTime method worked, and its counting, but when i try to pass through the function it doesn't work.
My Main Code
public class MyGdxGame extends ApplicationAdapter implements InputProcessor {
SpriteBatch batch;
private Player1 player1;
private TiledMap iceLevel;
private OrthogonalTiledMapRenderer renderer;
private OrthographicCamera camera;
float elaspedTime;
#Override
public void create() {
batch = new SpriteBatch();
Gdx.input.setInputProcessor(this);
TmxMapLoader loader = new TmxMapLoader();
iceLevel = loader.load("IceLevel.tmx");
renderer = new OrthogonalTiledMapRenderer(iceLevel);
camera = new OrthographicCamera();
camera.setToOrtho(false);
player1 = new Player1(new Sprite(new Texture("player1Right.png")), (TiledMapTileLayer) iceLevel.getLayers().get("Land"));
player1.setPosition(player1.getCollisionLayer().getTileWidth(), 6 * player1.getCollisionLayer().getTileHeight());
}
#Override
public void render() {
player1.update(Gdx.graphics.getDeltaTime());
Gdx.gl.glClearColor(1, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.begin();
camera.update();
renderer.setView(camera);
renderer.render();
renderer.getBatch().begin();
player1.draw(renderer.getBatch());
renderer.getBatch().end();
batch.end();
}
#Override
public void dispose() {
batch.dispose();
iceLevel.dispose();
renderer.dispose();
player1.getTexture().dispose();
}
A part of my player class
public class Player1 extends Sprite implements InputProcessor {
private Vector2 velocity;
private float speed = 60 * 2;
private float gravity = 60 * 1.8f;
private TiledMapTileLayer collisionLayer;
public Player1(Sprite sprite, TiledMapTileLayer collisionLayer) {
super(sprite);
this.collisionLayer = collisionLayer;
}
public void draw(SpriteBatch spriteBatch) {
update(Gdx.graphics.getDeltaTime());
super.draw(spriteBatch);
}
public void update(float delta) {
//gravity
velocity.y -= gravity * delta;
//set limit
if (velocity.y > speed) {
velocity.y = speed;
} else if (velocity.y < -speed) {
velocity.y = -speed;
}
// save old position
float oldX = getX();
float oldY = getY();
boolean collisionX = false;
boolean collisionY = false;
// move on x
setX(getX() + velocity.x * delta);
if (velocity.x < 0) { //going left
collisionX = collidesLeft();
} else if (velocity.x > 0) { //going right
collisionX = collidesRight();
}
// react to x collision
if (collisionX) {
setX(oldX);
velocity.x = 0;
}
// move on y
setY(getY() + velocity.y * delta * 5f);
if (velocity.y < 0) { // going down
collisionY = collidesBottom();
} else if (velocity.y > 0) { // going up
collisionY = collidesTop();
}
if (collisionY) {
setY(oldY);
velocity.y = 0;
}
}
Just to rule out delta time refactor you code like this:-
#Override
public void render() {
float delta = Gdx.graphics.getDeltaTime();
// Log or print this
if(delta > 0){
player1.update(Gdx.graphics.getDeltaTime());
Gdx.gl.glClearColor(1, 0, 0, 1);
.......
.......
}
Sounds like your player class update() method is the issue, but not the float delta. Looks like it is velocity. It is null.
private Vector2 velocity;
...
//gravity
velocity.y -= gravity * delta;
You are trying to set the y public float value of velocity (Vector2) but you don't have a velocity object instantiated.
Try
private Vector2 velocity = new Vector2();
I have the following class:
public class AnimationDemo implements ApplicationListener {
private SpriteBatch batch;
private TextureAtlas textureAtlas;
private Animation animation;
private float elapsedTime = 0;
private OrthographicCamera camera;
private int width;
private int height;
private int texturewidth;
private int textureheight;
#Override
public void create() {
width = Gdx.graphics.getWidth();
height = Gdx.graphics.getHeight();
camera = new OrthographicCamera(width, height);
camera.position.set(width / 2, height / 2, 0);
camera.update();
batch = new SpriteBatch();
textureAtlas = new TextureAtlas(Gdx.files.internal("data/packone.atlas"));
textureAtlas.getRegions().sort(new Comparator<TextureAtlas.AtlasRegion>() {
#Override
public int compare(TextureAtlas.AtlasRegion o1, TextureAtlas.AtlasRegion o2) {
return Integer.parseInt(o1.name) > Integer.parseInt(o2.name) ? 1 : -1;
}
});
animation = new Animation(1 / 15f, textureAtlas.getRegions());
}
#Override
public void dispose() {
batch.dispose();
textureAtlas.dispose();
}
#Override
public void render() {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL30.GL_COLOR_BUFFER_BIT);
batch.begin();
elapsedTime += Gdx.graphics.getDeltaTime();
batch.draw(animation.getKeyFrame(elapsedTime, true), 0, 0);
batch.end();
}
#Override
public void resize(int width, int height) {
}
#Override
public void pause() {
}
#Override
public void resume() {
}
}
In the above I am using the Animation class to simply draw from a texture atlas. I am following an example from another SO question which is here but the co-ordinates don't fit my equation. How should I set these:
private int texturewidth;
private int textureheight;
Any help would be great :)
you need to care about proper offset - the origin is always at the left bottom corner and that is why you need to subtract half of width and height when drawing.
In a nutshell it should be like:
TextureRegion region = animation.getKeyFrame(elapsedTime, true);
batch.draw(region, 0 - (region.getRegionWidth()/2f), 0 - (region.getRegionHeight()/2f));
Here is my Core project :
public class GameClass extends Game {
public static int screenWidth, screenHeight;
public static CustomScreen currentScreen;
public static PlayScreen playScreen;
#Override
public void create () {
screenWidth = Gdx.graphics.getWidth();
screenHeight = Gdx.graphics.getHeight();
CustomScreen.initialize();
playScreen = new PlayScreen(this);
SetScreen(playScreen);
}
public void SetScreen(CustomScreen screen) {
currentScreen = screen;
setScreen(currentScreen);
}
}
public abstract class CustomScreen implements Screen {
GameClass game;
static BitmapFont font;
static SpriteBatch batcher;
static OrthographicCamera cam;
public CustomScreen(GameClass game) {
this.game = game;
}
public static void initialize() {
cam = new OrthographicCamera();
cam.setToOrtho(true, GameClass.screenWidth, GameClass.screenHeight);
batcher = new SpriteBatch();
batcher.setProjectionMatrix(cam.combined);
font = new BitmapFont();
font.setScale(4f, -4f);
}
public void Clear() {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
}
#Override
public abstract void render(float delta);
}
public class PlayScreen extends CustomScreen {
public static final int speed = 300;
public ArrayList<Entity> entityList;
Random rand = new Random();
float timer = rand.nextInt(2) + rand.nextFloat();
public PlayScreen(GameClass game) {
super(game);
entityList = new ArrayList<Entity>();
}
void update(float delta) {
timer -= delta;
if (timer <= 0) {
entityList.add(new Enemy(GameClass.screenWidth, rand.nextInt(GameClass.screenHeight - Enemy.Height)));
timer += rand.nextInt(2) + rand.nextFloat() + 1/2;
}
for (int i = entityList.size(); i > 0; --i)
entityList.get(i-1).update(delta);
}
#Override
public void render(float delta) {
Clear();
update(delta);
batcher.begin();
for (int i = 0; i < entityList.size(); ++i) {
entityList.get(i).Display(batcher);
}
if (entityList.size() > 1)
System.out.println(entityList.get(1).posX - entityList.get(0).posX);
batcher.end();
}
}
public abstract class Entity {
protected Sprite sprite;
public int posX, posY, width, height;
public Entity(int posX, int posY, int width, int height) {
this.posX = posX;
this.posY = posY;
this.width = width;
this.height = height;
}
public abstract void update(float delta);
public void Display(SpriteBatch batcher) {
batcher.draw(sprite, posX, posY, width, height);
}
}
public class Enemy extends Entity {
static Sprite texture = new Sprite(new Texture(Gdx.files.internal("enemy.png")));
public static int Width = 300, Height = 200;
public Enemy(int posX, int posY) {
super(posX, posY, Width, Height);
this.sprite = Enemy.texture;
}
#Override
public void update(float delta, int i) {
posX -= delta * PlayScreen.speed;
if (posX + width < 0) {
GameClass.playScreen.entityList.remove(this);
}
}
}
In PlayScreen, enemies keep spawning randomly, and they move from the right of the screen to the left, at a constant speed (final int 300). But when they reach the left edge of the screen (when posX <= 0), they slow down, for an unknown reason. The thing is, I didn't program anything to happen when an enemy reaches the edge of the screen. (I programmed them to disappear when they are completely outside of the screen, when posX + width <= 0, but it has nothing to do with my problem, since even when I remove this, they keep slowing down when reaching the edge of the screen).
It happends with both the desktop and the android projects, so this definitely comes from the Core project.
I have no idea why this happens, this is really, really awkward.
Here is a couple picture to show you what happens.
http://i.stack.imgur.com/DrOSH.png
http://i.stack.imgur.com/Zjtju.png
We can see that the two enemies are closer to each other on the second picture than on the first one.
You can set PlayScreen.speed to 100 instead of 300, it will be even more noticeable.
And if you set it to a low enough value, like 20, enemies will not just slow down, they will basically stop moving.
I'm lost and have no idea how to fix this problem. If you have any, please feel free to share it.
I fixed it. The problem was that Enemy.posX was an int instead of a float.
I'm not quite certain but I'd guess that your calculations in the Enemy class involving delta get rounded (since PlayScreen.Speed is an integer).
Having a low enough PlayScreen.Speed or a low enough delta will result in delta * PlayScreen.Speed being 0.something which will get cut off to 0 when converting to an integer, resulting in posX never changing.
I usually use floats for all calculations involving positions (e.g. posX and posY and so on...) so that this cutting off doesn't happen until something gets drawn on the screen (since pixels are always integers). This produces more accurate results and solves a lot of problems around movement on the screen.
This question has been posted before, but i have problems with flickering sprites in libGdx.
I have looked everywhere on stackoverflow, google, etc but nothing helped me.
The sprites only flicker when they move. It flickers less when i move them slower, but it flickers a lot when a little bit faster. This is very annoying and ofcourse unplayable.
This is my code:
package com.wouter.DuelArena;
import com.badlogic.gdx.Game;
import ...
public class DuelArena extends Game {
Sprite player;
float playerX;
float playerY;
boolean fireBool;
Sprite fireSprite;
Texture fireText;
OrthographicCamera cam;
Texture playerTexture;
SpriteBatch batch;
#Override
public void create() {
fireBool = false;
fireText = new Texture("data/droplet.png");
fireText.setFilter(TextureFilter.Linear, TextureFilter.Linear);
fireSprite = new Sprite(fireText);
playerTexture = new Texture("data/bucket.png");
playerTexture.setFilter(TextureFilter.Linear, TextureFilter.Linear);
player = new Sprite(playerTexture);
player.setSize(70, 128);
playerX = 0f;
playerY = 0f;
cam = new OrthographicCamera();
cam.setToOrtho(false, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
batch = new SpriteBatch();
}
#Override
public void dispose() {
super.dispose();
}
#Override
public void render() {
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(Gdx.gl10.GL_COLOR_BUFFER_BIT);
cam.update();
batch.setProjectionMatrix(cam.combined);
batch.begin();
player.draw(batch);
input();
update();
batch.end();
super.render();
}
private void update()
{
player.setPosition(playerX, playerY);
if (fireBool)
{
fireSprite.setX(fireSprite.getX() + 300 * Gdx.graphics.getDeltaTime());
fireSprite.draw(batch);
if (fireSprite.getX() > 1280)
fireBool = false;
}
}
private void input()
{
if (Gdx.input.isKeyPressed(Keys.LEFT) && player.getX() > 0)
{
playerX -= 200f * Gdx.graphics.getDeltaTime();
}
if (Gdx.input.isKeyPressed(Keys.RIGHT) && player.getX() < 1280)
{
playerX += 200f * Gdx.graphics.getDeltaTime();
}
if (Gdx.input.isKeyPressed(Keys.SPACE) && !fireBool)
{
fireBool = true;
fireSprite.setPosition(playerX, playerY + 35f * Gdx.graphics.getDeltaTime());
}
}
#Override
public void resize(int width, int height) {
super.resize(width, height);
}
#Override
public void pause() {
super.pause();
}
#Override
public void resume() {
super.resume();
}
}
Thanks beforehand!
The problem is the position of the call to the super.render:
super.render();
In a Game class, the super.render needs to be the first line in the code, not the last, like this:
#Override
public void render(){
super.render(); //<-----
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(Gdx.gl10.GL_COLOR_BUFFER_BIT);
cam.update();
batch.setProjectionMatrix(cam.combined);
batch.begin();
player.draw(batch);
input();
update();
batch.end();
}
It is actually very important to put it there if you override the render method in Game, because thats the one that calls the render of the current Screen. You aren't using Screens in this example, but if you are using Game you probably should (will :p).