Updating camera position with Libgdx - java

I am attempting to get an OrthographicCamera to follow a user controlled sprite. I can't get the camera to properly update position at all. I can't seem to see what is wrong with my code compared to what others have done.
I am still learning and at this point I would assume the problem is being caused by something simple I do not fully understand at this point.
Any help is appreciated, thank you.
This is my renderer:
public class WorldRenderer {
private static final float CAMERA_WIDTH = 10;
private static final float CAMERA_HEIGHT = 7;
private World world;
private OrthographicCamera oCam;
private Hero hero;
ShapeRenderer debugRenderer = new ShapeRenderer();
/** TEXTURES **/
private Texture heroTexture;
private Texture tileTexture;
private SpriteBatch spriteBatch;
private int width, height;
private float ppuX; // Pixels per unit on the X axis
private float ppuY; // Pixels per unit on the Y axis
public void setSize (int w, int h) {
this.width = w;
this.height = h;
ppuX = (float)width / CAMERA_WIDTH;
ppuY = (float)height / CAMERA_HEIGHT;
}
public WorldRenderer(World world, boolean debug) {
hero = world.getHero();
this.world = world;
spriteBatch = new SpriteBatch();
oCam = new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
oCam.update();
loadTextures();
}
private void loadTextures() {
tileTexture = new Texture(Gdx.files.internal("images/tile.png"));
heroTexture = new Texture(Gdx.files.internal("images/hero_01.png"));
}
public void render() {
oCam.update();
spriteBatch.begin();
spriteBatch.disableBlending();
drawTiles();
spriteBatch.enableBlending();
drawHero();
spriteBatch.end();
}
private void drawHero() {
spriteBatch.draw(heroTexture, hero.getPosition().x * ppuX, hero.getPosition().y * ppuY, Hero.SIZE * ppuX, Hero.SIZE * ppuY);
oCam.position.set(hero.getPosition().x, hero.getPosition().y, 0);
}
}

SpriteBatch manages its own projection and transformation matrixes. So, you have to set its matrixes (if possible, before calling begin()).
Unless you need to access your matrixes separately (projection and model-view, eg. in shaders), setting the projection matrix to the projection-model-view matrix will be enough.
Anyway, this should work in your code:
oCam.update();
spriteBatch.setProjectionMatrix(oCam.combined);

try calling oCam.apply(Gdx.gl10); after your oCam.update();
update() only does the calculations but you never applied them.

In relation to idaNakav's answer, I can't see an apply function on cameras in LibGDX anymore, in case anyone else stumbles upon this! So update() should be sufficient now I would imagine.
My problem was a bit different, I was trying to put my camera in certain positions/lookAts with a perspective camera and it had to be actioned twice to work.
I was calling:
camera.lookAt(xyz), camera.position.set(xyz), camera.up.set(xyz)
The first call made the camera update to a really odd transform. I should have been doing:
camera.position.set(xyz), camera.lookAt(xyz), camera.up.set(xyz)

Related

problems with multiple cameras and viewports in libgdx

so I am doing what is suppose to be a simple game but I think I might be complicating things. I have a camera for the GameScreen and a viewPort which follow the position of the player and when it reaches to points on the sides, the camera stops following the player and stays in one point.
This by itself works fine, but then I wanted to add the pause menu and some other features in the game, creating a hud class with its own camera and viewport as well as a Stage and a shapeRenderer.
The problem comes when I create the instance of this hud inside my gameScreen, the camera that I am looking while I am playing looks like is the hudCam, which does not follow the player and basically does not let me see the player when it reaches the edges of the screen.
This is my GameScreen Class:
public class GameScreen implements Screen {
WowInvasion game;
ScrollingBackground background;
private OrthographicCamera gameCam;
private Viewport gameViewPort;
/*
Basically I wanna keep the same sprites running while in the menu, playing and till dead
therefore, I'll have a switch statement with cases on where the games at, inside the functions needed. That way I'll keep
the game has a background for the menu and there's no need for running a second screen.
*/
public static final int MAIN_MENU = 0;
public static final int GAME = 1;
private static int state = 1; //current state. starts with MAIN_MENU //DEBUGGING GAME SCREEN
//STAGES
private GameStage gameStage; //game ui
private menuStage mainMenu; //Main menu of the game
private Hud hud;
//Resources
private TextureAtlas atlas; //for the textures most
private Skin skin; //for the styles and fonts
//Sprites
private Player player;
//Shapes
private float progressPower; //for the power to build up
private final float POWER_CHARGED = 1000; //limit to get power
private final float DECREASING_POWER = 20; //limit to get power
public GameScreen(WowInvasion game){
this.game = game;
gameCam = new OrthographicCamera();
gameCam.setToOrtho(false, WowInvasion.WIDTH, WowInvasion.HEIGHT);
gameViewPort = new StretchViewport(WowInvasion.WIDTH, WowInvasion.HEIGHT, gameCam);
progressPower = 0f;
game.wowAssetManager.loadTexturesGameScreen(); // tells our asset manger that we want to load the images set in loadImages method
game.wowAssetManager.loadSkins(); //load the needed skins
game.wowAssetManager.manager.finishLoading(); // tells the asset manager to load the images and wait until finsihed loading.
skin = game.wowAssetManager.manager.get("ui/menuSkin.json");
}
#Override
public void show() {
game.batch.setProjectionMatrix(gameCam.combined);
background = new ScrollingBackground();
atlas = game.wowAssetManager.manager.get(WowAssetManager.GAME_ATLAS); //declaring atlas
mainMenu = new menuStage(gameViewPort, game.batch, skin, game); //pass it so that we only use one batch and one same viewport
gameStage = new GameStage(gameViewPort, game.batch, skin, game);
hud = new Hud(game.batch, skin);
player = new Player(atlas.findRegion("player"), (int) gameCam.viewportWidth / 2, (int) gameCam.viewportHeight / 2);
switch(state){
case MAIN_MENU:
Gdx.input.setInputProcessor(mainMenu);
break;
case GAME:
background.setFixedSpeed(false); //does not work in here
}
}
#Override
public void render(float delta) {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
if(state == GAME) {
background.setFixedSpeed(false);
player.update(delta, gameCam.viewportWidth, gameCam.viewportHeight); //updating player for movement
//really cheap way to charge power with velocity
if(progressPower != POWER_CHARGED) {
progressPower += Math.abs(player.getVelocity().x) + Math.abs(player.getVelocity().y);
progressPower -= DECREASING_POWER;
}
else
progressPower = POWER_CHARGED / 4;
}
mainMenu.act(Math.min(Gdx.graphics.getDeltaTime(), 1 / 30f)); //updating while making sure delta won't be more than 1/30f.
gameStage.act(Math.min(Gdx.graphics.getDeltaTime(), 1 / 30f));
game.batch.begin();
background.updateAndRender(delta, game.batch); //updating scrolling background
player.draw(game.batch);
game.batch.end();
mainMenu.draw(); //draw the menu stage
gameStage.draw(); //draw the ui stage for the game
hud.getStage().draw();
hud.renderRotateMeter();
updateCamera(0, WowInvasion.WIDTH);
System.out.println(player.getPosition().x);
}
public void updateCamera(float startX, float endX){
Vector3 position = gameCam.position;
//linear interpolation : a + (b - a) * lerp
//b = player position
//a = current camera position
//lerp = interpolation factor
position.x = gameCam.position.x + (player.getPosition().x - gameCam.position.x) * .1f;
//making the camera stay when the player gets to close to the sides
if(position.x < startX) {
position.x = startX;
}
if(position.x > endX){
position.x = endX;
}
gameCam.position.set(position);
gameCam.update();
}
#Override
public void resize(int width, int height) {
gameViewPort.update(width, height);
//hud.getViewport().update(width, height);
}
#Override
public void pause() {
}
#Override
public void resume() {
}
#Override
public void hide() {
dispose();
}
#Override
public void dispose() {
mainMenu.dispose();
gameStage.dispose();
game.dispose();
hud.dispose();
}
public static void setState(int state) {
GameScreen.state = state;
}
}
And this is my HUD:
public class Hud implements Disposable{
private Stage stage;
private Viewport viewport;
Button buttonPause, buttonResume;
private OrthographicCamera hudCam;
private ShapeRenderer sp; //like a batch for shapes
public Hud(SpriteBatch sb, Skin skin){
hudCam = new OrthographicCamera();
hudCam.setToOrtho(false, WowInvasion.WIDTH, WowInvasion.HEIGHT);
viewport = new StretchViewport(WowInvasion.WIDTH, WowInvasion.HEIGHT, hudCam);
stage = new Stage(viewport, sb);
sp = new ShapeRenderer();
Table table = new Table();
table.top();
//this makes the table the size of the stage
table.setFillParent(true);
buttonPause = new Button(skin, "pause");
buttonPause.setTransform(true);
buttonPause.addListener(new ClickListener(){ //listener to handle event
#Override
public void clicked(InputEvent event, float x, float y) {
}
});
buttonResume = new Button(skin, "resume");
buttonResume.setTransform(true);
buttonResume.setScale(0.5f);
buttonResume.addListener(new ClickListener(){
#Override
public void clicked(InputEvent event, float x, float y) {
buttonResume.setVisible(false);
}
});
table.add(buttonPause);
table.row();
table.add(buttonResume);
stage.addActor(table);
}
public void renderRotateMeter(){
sp.setProjectionMatrix(hudCam.combined);
sp.begin(ShapeRenderer.ShapeType.Filled);
sp.setColor(Color.YELLOW);
sp.rect(hudCam.position.x,hudCam.position.y, WowInvasion.WIDTH / 2, 20);
sp.end();
}
public Viewport getViewport() {
return viewport;
}
public Stage getStage() {
return stage;
}
#Override
public void dispose() {
stage.dispose();
sp.dispose();
}
}
thanks in advance!
EDIT
so I tried passing the gameCam has a parameter to the hud and instead of making a new OrthographicCamera I used that one has the hudCamara as well and well, the movement with the player is perfect except now the thins from the Hud do not move at all..
It looks like you only set projectionMatrix to only HUD camera as seen in
sp.setProjectionMatrix(hudCam.combined);
Try to set it the same to other stuff outside of the HUD class prior to draw call too.
Another thing to keep in mind is that, when you involve using multiple Viewport and Camera in the game as most of the time it will be 1 Viewport matching with 1 Camera and work with another set as in your case. In draw call, you need to call apply() or apply(true) of Viewport class too to tell the system that you will draw based on which viewport thus in turn it will adhere to screen coordinate that was set up by viewport's attaching camera.
So assume you have 2 objects that needed to be called in different viewport consecutively, do it like the following code. The methods call is correct according to libgdx API but variable names are fictional.
// draw objA adhering to viewportA (thus cameraA) <-- assume it's player cam
sb.setProjectionMatrix(cameraA.combined);
viewportA.apply();
objA.draw();
// draw objB adhering to viewportB (thus cameraB) <-- assume it's HUD cam
sb.setProjectionMatrix(cameraB.combined);
viewportB.apply(true); // send in true as for HUD, we always want to center the screen
objB.draw();
In summary, 2 things to keep in mind when drawing objects that use multiple of camera and viewport in consecutive draw call.
Set projection matrix to either SpriteBatch or ShapeRenderer.
Call apply() or apply(true) of Viewport class to let it know you work with this viewport.

libgdx, movement specific

I have issue with movement. My goal is to make player move once key is pressed for its own width/height. For example:
if (Gdx.input.isKeyJustPressed(Input.Keys.A))
player.position.x = player.position.x-moveSpeed;
that works precise, but I want it more smooth, to move exact distance in a second, but each millisecond a bit, not all at once.
This makes player move smooth, but it's not precise:
if (Gdx.input.isKeyJustPressed(Input.Keys.A))
player.position.x = player.position.x-moveSpeed*deltaTime;
How can I make smooth transition, but precise?
Change (or extend) your player class, so that it contains the following:
class Player {
public final Vector2 position = new Vector2(); // you already have this
public final Vector2 target = new Vector2();
private final float speed = 10f; // adjust this to your needs
private final static Vector2 tmp = new Vector2();
public void update(final float deltaTime) {
tmp.set(target).sub(position);
if (!tmp.isZero()) {
position.add(tmp.limit(speed*deltaTime));
}
}
//The remainder of your Player class
}
Then in your render method you call:
if (Gdx.input.isKeyJustPressed(Input.Keys.A)) {
player.target.x -= moveSpeed; //consider renaming moveSpeed to moveDistance
}
player.update(deltaTime);

Libgdx Box2d collision detection using physics body editor

Hy guys,
I am developing a game for android using libgdx. I am completely stuck at the part of detecting collision between two bodies.
I have a player which I create through the function below
public Body createPlayer(String file_path, String fixture_name) {
// 0. Create a loader for the file saved from the editor.
BodyEditorLoader loader = new BodyEditorLoader(Gdx.files.internal(file_path));
// 1. Create a BodyDef, as usual.
BodyDef bd = new BodyDef();
bd.type = BodyDef.BodyType.DynamicBody;
// 2. Create a FixtureDef, as usual.
FixtureDef fd = new FixtureDef();
fd.density = 1;
fd.friction = 0.5f;
fd.restitution = 0.3f;
// 3. Create a Body, as usual.
body= world.createBody(bd);
//body.setBullet(true);
// 4. Create the body fixture automatically by using the loader.
loader.attachFixture(body, fixture_name, fd, 1);
body.setUserData(this);
return body;
}
and an enemy that I create with the same function of the player where I change only the file_path and the fixture_name.
The file_path points to a .json file that I created with box2d editor (site: http://www.aurelienribon.com/blog/projects/physics-body-editor/).
After the creation of the body I draw the player and the enemy with two similar functions ( I only post one):
private void drawPlayer(){
player_sprite = new Sprite(player_TR);
player_sprite.setSize(player.getWidth(), player.getHeight());
player_sprite.setPosition(player.getX(), player.getY());
player_sprite.setOrigin(0, 0);
player_sprite.draw(sb);
}
If I start the game everything is drawn where it should be. Obviously if the player touches the enemy nothing happen.
So i started trying to search how to make the two bodies collides but I don't really understand how to use ContactListener and beginContact.
beginContact wants as input a Contact but what is a Contact?
I have found this code online which appears to solve my problem but I don't know how to use it:
worldbox.setContactListener(new ContactListener() {
#Override
public void beginContact(Contact contact) {
if(contact.getFixtureA().getBody().getUserData()== "body1" &&
contact.getFixtureB().getBody().getUserData()== "body2")
Colliding = true;
System.out.println("Contact detected");
}
Can you help me (if it is possible through some code) to solve my problem?
Thanks in advance,
Francesco
Update of my question
Here is my render method:
public class GameRenderer{
private GameWorld myWorld;
private ShapeRenderer shapeRenderer;
private SpriteBatch sb;
private Camera camera;
private Constants constant;
private Rectangle viewport;
//dichiaro le variabili per caricare gli asset
private Player player;
private ScrollHandler scroller;
private Bordo frontBordoSX_1, backBordoSX_1, frontBordoSX_2, backBordoSX_2;
private Bordo frontBordoDX_1, backBordoDX_1, frontBordoDX_2, backBordoDX_2;
/*
private Ostacolo ob1_sx, ob2_sx, ob3_sx;
private Ostacolo ob4_dx, ob5_dx, ob6_dx;
*/
private TextureRegion player_TR;
private TextureRegion bordoSX_1, bordoSX_2;
private TextureRegion bordoDX_1, bordoDX_2;
private TextureRegion obstacleSX, obstacleSX_flip;
private TextureRegion obstacleDX, obstacleDX_flip;
private TextureRegion enemyS;
private TextureRegion blackBar;
//box2dpart
private World worldbox;
private Sprite fbDx_1,fbDx_2,fbSx_1,fbSx_2;
private Sprite player_sprite;
private Body player_body, bordo_destro;
private MyContactListener contactListener;
public GameRenderer(GameWorld world) {
myWorld = world;
constant = new Constants();
camera = new OrthographicCamera(constant.getWidth(), constant.getHeight());
shapeRenderer = new ShapeRenderer();
shapeRenderer.setProjectionMatrix(camera.combined);
sb = new SpriteBatch();
sb.setProjectionMatrix(camera.combined);
contactListener = new MyContactListener();
worldbox= new World(new Vector2(0,-10),true);
worldbox.setContactListener(contactListener);
//initialize objects and assets
initGameObjects();
initAssets();
}
private void initGameObjects(){
player = myWorld.getPlayer();
scroller = myWorld.getScroller();
frontBordoSX_1 = scroller.getFrontBordoSX_1();
backBordoSX_1 = scroller.getBackBordoSX_1();
frontBordoSX_2 = scroller.getFrontBordoSX_2();
backBordoSX_2 = scroller.getBackBordoSX_2();
frontBordoDX_1 = scroller.getFrontBordoDX_1();
backBordoDX_1 = scroller.getBackBordoDX_1();
frontBordoDX_2 = scroller.getFrontBordoDX_2();
backBordoDX_2 = scroller.getBackBordoDX_2();
/* other objects
ob1_sx = scroller.getOb1_sx();
ob2_sx = scroller.getOb2_sx();
ob3_sx = scroller.getOb3_sx();
ob4_dx = scroller.getOb4_dx();
ob5_dx = scroller.getOb5_dx();
ob6_dx = scroller.getOb6_dx();
*/
}
private void initAssets(){
player_TR = AssetLoader.player;
bordoSX_1 = AssetLoader.bordoSX;
bordoSX_2 = AssetLoader.bordoSX;
bordoDX_1 = AssetLoader.bordoDX;
bordoDX_2 = AssetLoader.bordoDX;
obstacleDX = AssetLoader.obstacleDX;
obstacleSX = AssetLoader.obstacleSX;
obstacleDX_flip = AssetLoader.obstacleDX_flip;
obstacleSX_flip = AssetLoader.obstacleSX_flip;
enemyS = AssetLoader.enemyS;
blackBar = AssetLoader.blackBar;
//box2d part
}
private void drawMargin(){
//bordo SX
/*
sb.draw(bordoSX_1, frontBordoSX_2.getX(), frontBordoSX_2.getY(), frontBordoSX_2.getWidth(),
frontBordoSX_2.getHeight());
sb.draw(bordoSX_2, frontBordoSX_1.getX(), frontBordoSX_1.getY(), frontBordoSX_1.getWidth(),
frontBordoSX_1.getHeight());
*/
fbSx_1 = new Sprite(bordoSX_1);
fbSx_1.setSize(frontBordoSX_1.getWidth(),frontBordoSX_1.getHeight());
fbSx_1.setPosition(frontBordoSX_1.getX(), frontBordoSX_1.getY());
fbSx_1.setOrigin(0, 0);
fbSx_1.draw(sb);
fbSx_2 = new Sprite(bordoSX_2);
fbSx_2.setSize(frontBordoSX_2.getWidth(),frontBordoSX_2.getHeight());
fbSx_2.setPosition(frontBordoSX_2.getX(), frontBordoSX_2.getY());
fbSx_2.setOrigin(0, 0);
fbSx_2.draw(sb);
fbDx_1 = new Sprite(bordoDX_1);
fbDx_1.setSize(frontBordoDX_1.getWidth(),frontBordoDX_1.getHeight());
fbDx_1.setPosition(frontBordoDX_1.getX(), frontBordoDX_1.getY());
fbDx_1.setOrigin(0, 0);
fbDx_1.draw(sb);
fbDx_2 = new Sprite(bordoDX_2);
fbDx_2.setSize(frontBordoDX_2.getWidth(),frontBordoDX_2.getHeight());
fbDx_2.setPosition(frontBordoDX_2.getX(), frontBordoDX_2.getY());
fbDx_2.setOrigin(0, 0);
fbDx_2.draw(sb);
sb.draw(blackBar,-constant.getWidth()/2,-constant.getHeight()/2,
(float) (0.573913)*(constant.getWidth()/6),constant.getHeight());
sb.draw(blackBar,(float)(constant.getWidth()/2-(0.573913)*(constant.getWidth()/6)),-constant.getHeight()/2,
(float)(0.573913)*(constant.getWidth()/6),constant.getHeight());
}
private void drawPlayer(){
player_sprite = new Sprite(player_TR);
player_sprite.setSize(player.getWidth(), player.getHeight());
player_sprite.setPosition(player.getX(), player.getY());
player_sprite.setOrigin(0, 0);
player_sprite.draw(sb);
}
/*
private void drawOstacoli(){
sb.draw(obstacleSX_flip,ob1_sx.getX(),ob1_sx.getY(),ob1_sx.getWidth(),ob1_sx.getHeight());
sb.draw(obstacleSX,ob2_sx.getX(),ob2_sx.getY(),ob2_sx.getWidth(),ob2_sx.getHeight());
sb.draw(obstacleSX_flip,ob3_sx.getX(),ob3_sx.getY(),ob3_sx.getWidth(),ob3_sx.getHeight());
sb.draw(obstacleDX,ob4_dx.getX()+constant.getWidth()/2-ob4_dx.getWidth(),ob4_dx.getY(),ob4_dx.getWidth(),ob4_dx.getHeight());
sb.draw(obstacleDX_flip,ob5_dx.getX()+constant.getWidth()/2-ob5_dx.getWidth(),ob5_dx.getY(),ob5_dx.getWidth(),ob5_dx.getHeight());
sb.draw(obstacleDX,ob6_dx.getX()+constant.getWidth()/2-ob6_dx.getWidth(),ob6_dx.getY(),ob6_dx.getWidth(),ob6_dx.getHeight());
}
*/
public void render(float runTime) {
Box2D.init();
int width = constant.getWidth();
int height = constant.getHeight();
float ratio = constant.getRatio();
//viewport
float aspectRatio = (float) width / (float) height;
float scale = 1f;
Vector2 crop = new Vector2(0f, 0f);
if(aspectRatio > ratio)
{
scale = (float)height/(float)height;
crop.x = (width - width * scale) / 2f;
} else if (aspectRatio < ratio) {
scale = (float)width/(float)width;
crop.y = (height - height*scale)/2f;
}
else
{
scale = (float) width / (float) width;
}
float w = (float) width * scale;
float h = (float) height * scale;
viewport = new Rectangle(crop.x, crop.y, w, h);
// update camera
camera.update();
// clear previous frame
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
shapeRenderer.begin(ShapeRenderer.ShapeType.Filled);
// Draw Background color
shapeRenderer.setColor(255 / 255.0f, 255 / 255.0f, 250 / 255.0f, 1);
shapeRenderer.rect(-constant.getWidth() / 2, -constant.getHeight() / 2, constant.getWidth(),
constant.getHeight());
// End ShapeRenderer
shapeRenderer.end();
// set viewport
Gdx.gl.glViewport((int) viewport.x, (int) viewport.y,
(int) viewport.width, (int) viewport.height);
// Begin SpriteBatch
sb.begin();
// The player needs transparency, so we enable that again.
sb.enableBlending();
// Draw player at its coordinates.
drawPlayer();
//draw right and left side
drawMargin();
// End SpriteBatch
sb.end();
worldbox.step(1 / 60f, 6, 2);
}
}
And if I start the program my view is my player in the middle and to margins ,one on the left and one on the right. (unfortunatly I cannot post images of my view because I don't have enough rep).
Everithing is fine. I move my player with the accelerometer and it works fine without any problem. The only problem is that if I move the player near the margin the two entities overlap instead of colliding and I don't understand why.
I also fixed the line:
loader.attachFixture(body, fixture_name, fd, 1);
to
loader.attachFixture(body, fixture_name, fd, player_width);
but nothing changes.
First, from here, the object Contact manages contact between two shapes, and from here, the listener ContactListener will be called when two fixtures begin to touch.
So, to make your code work, you should set a custom object to your bodies with the method: setUserData(Object userData). Usually this method is used to link the sprite or the actor with the physic body, but for example purpose you could just send a simple ID (like a string).
So in this part:
// 3. Create a Body, as usual.
body= world.createBody(bd);
//body.setBullet(true);
You could add an identificator to your object like this:
body.setUserData("player");
to idenfity your object, and then, when the listener get fired, you could retrieve this value:
#Override
public void beginContact(Contact contact) {
String userDataA = contact.getFixtureA().getBody().getUserData().toString();
String userDataB = contact.getFixtureB().getBody().getUserData().toString();
if(userDataA.equals("player") && userDataB.equals("otherEntity")){
colliding = true;
//do stuffs when collision has started
} else if(userDataB.equals("player") && userDataA.equals("otherEntity")){
colliding = true;
//do stuffs when collision has started
}
System.out.println("Contact detected");
}
After that, you could be able to do whatever you want to do with this collision.
Hope you find this useful!

LibGDX - Sanity Check - Tiled Maps & The Player

everyone! This is my first post on StackOverflow, and I thought I might start off on the website with a desperate cry for assistance!
I'm currently making a game in LibGDX, and am trying to get my player to collide with a Tiled map, which I believe I've correctly initialized in the code.
However, my program is NullPointer-ing where it is trying to find the tileWidth and the tileHeight of the TiledMapLayer I specified.
I've been rolling this around in my head, but I can't seem to find a solution...
What am I doing wrong?
Here's my code:
public class PlayScreen implements Screen{
EscapeGame game;
Player player;
OrthographicCamera cam;
private TiledMap prototype;
private OrthogonalTiledMapRenderer renderer;
private SpriteBatch batch;
Texture playerTexture;
public PlayScreen(EscapeGame game){
this.game = game;
}
#Override
public void show() {
float w = Gdx.graphics.getWidth();
float h = Gdx.graphics.getHeight();
TmxMapLoader tmx = new TmxMapLoader();
prototype = new TmxMapLoader().load("maps/Prototype2.tmx");
renderer = new OrthogonalTiledMapRenderer(prototype);
cam = new OrthographicCamera();
batch = new SpriteBatch();
playerTexture = new Texture("Sprites/prototagonist1.png");
player = new Player(new Sprite(playerTexture), (TiledMapTileLayer) prototype.getLayers().get("MetaLayer"));
player.setPosition(7 * player.getMeta().getTileWidth(), 11 * player.getMeta().getTileHeight());
}
...
public class Player extends Sprite {
float gravity = 360 * 3.5f;
public Vector2 velocity;
private TiledMapTileLayer MetaLayer; float oldY = getY(), oldX = getX(), tileWidth = MetaLayer.getTileWidth(), tileHeight = MetaLayer.getTileHeight();
//getters and setters
public Player (Sprite sprite, TiledMapTileLayer Meta){
super(sprite);
this.MetaLayer = MetaLayer;
}
public TiledMapTileLayer getMeta() {
return MetaLayer;
}
public void setMeta(TiledMapTileLayer Meta) {
this.MetaLayer = MetaLayer;
}
...
class variable will be loaded before the constructor invoke, when accessing MetaLayer.getTileWidth(), MetaLayer not initialized and it is null. to solve the NPE modify the code like this
....
private TiledMapTileLayer MetaLayer;
float oldY, oldX, tileWidth, tileHeight;
public Player (Sprite sprite, TiledMapTileLayer Meta){
super(sprite);
this.MetaLayer = Meta;
tileWidth = MetaLayer.getTileWidth();
tileHeight = MetaLayer.getTileHeight();
/** Recommended **/
oldY = getY();
oldX = getX();
}
....

libgdx Background TextureRegion repeat

I'm new in libdgx developement and also in game developement. I am reading the book "Learning Libgdx Game Development" from Andreas Oehlke and I am trying to develop my own game in parallel.
I have a problem when I try to add the background. In the book, he uses a color, so it's very simple. But I want to add an image from a texture atlas. The image is to small to recover all the screen, so I want to repeat it. I can't use regBackground.setWrap(TextureWrap.Repeat, TextureWrap.Repeat) because regBackground is not a texture. How i can resolve my problem properly?
public class Background extends AbstractGameObject {
private TextureRegion regBackground;
public Background () {
init();
}
private void init () {
dimension.set(1f, 1f);
regBackground = Assets.instance.levelDecoration.background;
}
public void render (SpriteBatch batch) {
TextureRegion reg = null;
reg = regBackground;
batch.draw(reg.getTexture(),
position.x, position.y,
origin.x, origin.y,
dimension.x, dimension.y,
scale.x, scale.y,
rotation,
reg.getRegionX(), reg.getRegionY(),
reg.getRegionWidth(), reg.getRegionHeight(),
false, false);
}
}
In my Assets class, I have this code to find the region in the texture atlas :
public class AssetLevelDecoration {
public final AtlasRegion background;
public AssetLevelDecoration (TextureAtlas atlas) {
background = atlas.findRegion("background");
}
}
I progressed in solving my problem. I use the setWrap method to repeat my texture :
public class Background extends AbstractGameObject {
private TextureRegion regBackground;
public Background (int width, int heigth) {
init(width, heigth);
}
private void init (int width, int heigth) {
dimension.set(width, heigth);
regBackground = Assets.instance.levelDecoration.background;
origin.x = -dimension.x/2;
origin.y = -dimension.y/2;
}
public void render (SpriteBatch batch) {
TextureRegion reg = null;
reg = regBackground;
Texture test = reg.getTexture();
test.setWrap(TextureWrap.Repeat, TextureWrap.Repeat);
batch.draw(test,
position.x + origin.x, position.y + origin.y,
test.getWidth(), test.getHeight(),
reg.getRegionX(), reg.getRegionY(),
reg.getRegionWidth(), reg.getRegionHeight()
);
}
}
Now, I obtain this, but I just want to repeat my background image (wood square).
http://s24.postimg.org/c1m92ffwx/Capture_du_2013_11_12_15_49_03.jpg
The problem is that the getTexture() recover the all image and not only my background. How can I fix this?
I would just add a comment but I don't have the rep.
To solve the issue of the repeating of the whole texture instead of only the wooden square you have 2 choices. A) separate the textureregion onto a separate texture. B) loop over the to repeat the draw, which should be negligible in terms of performance.
http://badlogicgames.com/forum/viewtopic.php?f=11&t=8883
a simpler approach will be
batch.draw(imageReference,startX,startY,widthOfScreen,heightOfScreen);
batch.draw() is an overloaded method so use only those parameter u need
the syntax is just a pseudo code
MOst importantlu This may give image stretching(depending on image).
I have created an introduction to images including repeating texture here: https://libgdx.info/basic_image/
I hope it helps
This creates an image along this line:

Categories

Resources