I'm new with libgdx and I have read a Tutorial (the Tutorial Code is my base).
I have a character that I can move, but the camera won't follow the character :(
Here's my WorldRenderer.java:
package com.evolutio.tee.view;
import com.evolutio.tee.model.Block;
import com.evolutio.tee.model.Tee;
import com.evolutio.tee.model.World;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType;
import com.badlogic.gdx.math.Rectangle;
public class WorldRenderer {
private static final float CAMERA_WIDTH = 10f;
private static final float CAMERA_HEIGHT = 7f;
private World world;
private OrthographicCamera cam;
/** for debug rendering **/
ShapeRenderer debugRenderer = new ShapeRenderer();
/** Textures **/
private Texture teeTexture;
private Texture blockTexture;
private SpriteBatch spriteBatch;
private boolean debug = false;
private int width;
private int 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) {
Tee tee = world.getTee();
this.world = world;
cam = new OrthographicCamera(CAMERA_WIDTH, CAMERA_HEIGHT);
cam.position.set(CAMERA_WIDTH / 2f, CAMERA_HEIGHT / 2f, 0);
cam.update();
this.debug = debug;
spriteBatch = new SpriteBatch();
loadTextures();
}
private void loadTextures() {
teeTexture = new Texture(Gdx.files.internal("tee/tee.png"));
blockTexture = new Texture(Gdx.files.internal("world/dreck.png"));
}
public void render() {
spriteBatch.begin();
drawBlocks();
drawTee();
spriteBatch.end();
//if (debug) drawDebug();
}
private void drawBlocks() {
for (Block block : world.getBlocks()) {
spriteBatch.draw(blockTexture, block.getPosition().x * ppuX, block.getPosition().y * ppuY, Block.SIZE * ppuX, Block.SIZE * ppuY);
}
}
private void drawTee() {
Tee tee = world.getTee();
spriteBatch.draw(teeTexture, tee.getPosition().x * ppuX, tee.getPosition().y * ppuY, Tee.SIZE * ppuX, Tee.SIZE * ppuY);
cam.position.set(tee.getPosition().x, tee.getPosition().y, 0);
}
private void drawDebug() {
// render blocks
debugRenderer.setProjectionMatrix(cam.combined);
debugRenderer.begin(ShapeType.Rectangle);
for (Block block : world.getBlocks()) {
Rectangle rect = block.getBounds();
float x1 = block.getPosition().x + rect.x;
float y1 = block.getPosition().y + rect.y;
debugRenderer.setColor(new Color(1, 0, 0, 1));
debugRenderer.rect(x1, y1, rect.width, rect.height);
}
// render Tee
Tee tee = world.getTee();
Rectangle rect = tee.getBounds();
float x1 = tee.getPosition().x + rect.x;
float y1 = tee.getPosition().y + rect.y;
debugRenderer.setColor(new Color(0, 1, 0, 1));
debugRenderer.rect(x1, y1, rect.width, rect.height);
debugRenderer.end();
}
}
at drawTee() I try to make the camera following the Tee.
cam.position.set(tee.getPosition().x, tee.getPosition().y, 0);
Try this
public class WorldRenderer {
private static final float CAMERA_WIDTH = 10f;
private static final float CAMERA_HEIGHT = 7f;
private World world;
private OrthographicCamera cam;
/** for debug rendering **/
ShapeRenderer debugRenderer = new ShapeRenderer();
/** Textures **/
private Texture teeTexture;
private Texture blockTexture;
private SpriteBatch spriteBatch;
private boolean debug = false;
private int width;
private int 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) {
Tee tee = world.getTee();
this.world = world;
this.cam = new OrthographicCamera(CAMERA_WIDTH, CAMERA_HEIGHT);
this.cam.setToOrtho(false,CAMERA_WIDTH,CAMERA_HEIGHT);
this.cam.position.set(CAMERA_WIDTH / 2f, CAMERA_HEIGHT / 2f, 0);
this.cam.update();
this.debug = debug;
spriteBatch = new SpriteBatch();
loadTextures();
}
private void loadTextures() {
teeTexture = new Texture(Gdx.files.internal("tee/tee.png"));
blockTexture = new Texture(Gdx.files.internal("world/dreck.png"));
}
public void render() {
moveCamera(tee.getPosition().x, CAMERA_HEIGHT / 2);
spriteBatch.setProjectionMatrix(cam.combined);
spriteBatch.begin();
drawBlocks();
drawTee();
spriteBatch.end();
//if (debug) drawDebug();
}
public void moveCamera(float x,float y){
if ((tee.getPosition().x > CAMERA_WIDTH / 2)) {
cam.position.set(x, y, 0);
cam.update();
}
}
private void drawBlocks() {
for (Block block : world.getBlocks()) {
spriteBatch.draw(blockTexture, block.getPosition().x, block.getPosition().y, Block.SIZE, Block.SIZE);
}
}
private void drawTee() {
Tee tee = world.getTee();
spriteBatch.draw(teeTexture, tee.getPosition().x, tee.getPosition().y, Tee.SIZE, Tee.SIZE);
}
Using the sprite.setProjectionMatrix(cam.combined) before the spriteBatch.begin() is needed because if you don't the spriteBatch uses it's own camera, therefore your updates do nothing for what appears on screen.
You have to take out the ppuX, ppuY stuff. I know that's to resize the screen for different devices, but it screws up the camera, therefore if you keep it in and call the setProjectionMatrix, it will be way way zoomed in (actually the size of all images will be huge.)
Related
I make a game called Space Shooter. I added the lasers to both ships and put the Laser into LinkedList but when I run the game the laser is going on from one side of the player ship. Where are the other 3 lasers what should be on the sides. You can see what I mean in the photo below. I've already check the code twice but can't find what's wrong.
class GameScreen implements Screen {
//screen
private Camera camera;
private Viewport viewport;
//graphics
private SpriteBatch batch;
private TextureAtlas textureAtlas;
private TextureRegion[] backgrounds;
private float backgroundHeight; //height of background in World units
private TextureRegion playerShipTextureRegion, playerShieldTextureRegion,
enemyShipTextureRegion, enemyShieldTextureRegion,
playerLaserTextureRegion, enemyLaserTextureRegion;
//timing
private float[] backgroundOffsets = {0, 0, 0, 0};
private float backgroundMaxScrollingSpeed;
//world parameters
private final int WORLD_WIDTH = 72;
private final int WORLD_HEIGHT = 128;
//game objects
private Ship playerShip;
private Ship enemyShip;
private LinkedList<Laser>PlayerLaserList;
private LinkedList<Laser>EnemyLaserList;
GameScreen() {
camera = new OrthographicCamera();
viewport = new StretchViewport(WORLD_WIDTH, WORLD_HEIGHT, camera);
//set up the texture atlas
textureAtlas = new TextureAtlas("images.atlas");
//setting up the background
backgrounds = new TextureRegion[4];
backgrounds[0] = textureAtlas.findRegion("Starscape00");
backgrounds[1] = textureAtlas.findRegion("Starscape01");
backgrounds[2] = textureAtlas.findRegion("Starscape02");
backgrounds[3] = textureAtlas.findRegion("Starscape03");
backgroundHeight = WORLD_HEIGHT * 2;
backgroundMaxScrollingSpeed = (float) (WORLD_HEIGHT) / 4;
//initialize texture regions
playerShipTextureRegion = textureAtlas.findRegion("playerShip2_red");
enemyShipTextureRegion = textureAtlas.findRegion("enemyBlack2");
playerShieldTextureRegion = textureAtlas.findRegion("shield2");
enemyShieldTextureRegion = textureAtlas.findRegion("shield1");
enemyShieldTextureRegion.flip(false, true);
playerLaserTextureRegion= textureAtlas.findRegion("laserGreen15");
enemyLaserTextureRegion= textureAtlas.findRegion("laserRed03");
//set up game objects
playerShip = new PlayerShip(2, 3, 10, 10,
WORLD_WIDTH/2, WORLD_HEIGHT/4,2f,3,1,
0.05f, playerShipTextureRegion,playerShieldTextureRegion,playerLaserTextureRegion);
enemyShip = new EnemyShip(2, 1, 10, 10,
WORLD_WIDTH/2, WORLD_HEIGHT*4/5,0.3f,3,1,0.8f
, enemyShipTextureRegion,enemyShieldTextureRegion,enemyLaserTextureRegion);
PlayerLaserList = new LinkedList<>();
EnemyLaserList = new LinkedList<>();
batch = new SpriteBatch();
}
#Override
public void render(float deltaTime) {
batch.begin();
playerShip.update(deltaTime);
enemyShip.update(deltaTime);
//scrolling background
renderBackground(deltaTime);
//enemy ships
enemyShip.draw(batch);
//player ship
playerShip.draw(batch);
//lasers
//create new Laser
//player lasr
if (playerShip.canFireLaser()) {
Laser[] lasers = playerShip.fireLaser();
for (Laser laser: lasers) {
PlayerLaserList.add(laser);
}
}
//enemy lasers
if (enemyShip.canFireLaser()) {
Laser[] lasers = enemyShip.fireLaser();
for (Laser laser: lasers) {
EnemyLaserList.add(laser);
}
}
//draw the Lasers
//remove old Laser
ListIterator<Laser> iterator = PlayerLaserList.listIterator();
while(iterator.hasNext()) {
Laser laser = iterator.next();
laser.draw(batch);
laser.yPosition += laser.movementSpeed*deltaTime;
if (laser.yPosition > WORLD_HEIGHT) {
iterator.remove();
}
}
//enemy lsaer list
iterator = EnemyLaserList.listIterator();
while(iterator.hasNext())
{
Laser laser = iterator.next();
laser.draw(batch);
laser.yPosition -= laser.movementSpeed*deltaTime;
if(laser.yPosition + laser.height < 0)
{
iterator.remove();
}
}
//explosions
batch.end();
}
package com.mygdx.game;
import com.badlogic.gdx.graphics.g2d.Batch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
class EnemyShip extends Ship
{
public EnemyShip(float movementSpeed, int shield, float width, float height, float xCentre, float yCentre,
float laserWidth, float laserHeight, float laserMovementSpeed, float timeBetweenShoots,
TextureRegion shipTexture, TextureRegion shieldTexture, TextureRegion laserTextureRegion) {
super(movementSpeed, shield, width, height, xCentre, yCentre, laserWidth, laserHeight, laserMovementSpeed,
timeBetweenShoots, shipTexture, shieldTexture, laserTextureRegion);
}
#Override
public Laser[] fireLaser() {
Laser[] laser = new Laser[2];
laser[0] = new Laser(xPosition + width * 0.18f, yPosition - laserHeight,
laserWidth, laserHeight,
laserMovementSpeed, laserTextureRegion);
laser[1] = new Laser(xPosition + width * 0.82f, yPosition - laserHeight,
laserWidth, laserHeight,
laserMovementSpeed, laserTextureRegion);
timeSinceLastShoot = 0;
return laser;
}
#Override
public void draw(Batch batch) {
batch.draw(shipTexture, xPosition, yPosition, width, height);
if (shield > 0) {
batch.draw(shieldTexture, xPosition, yPosition-height*0.2f, width, height);
}
}
package com.mygdx.game;
import com.badlogic.gdx.graphics.g2d.Batch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
public class Laser
{
float movementSpeed;
//position and dimension
float xPosition, yPosition;
float width, height;
//graphics
TextureRegion textureRegion;
public Laser(float movementSpeed, float xPosition, float yPosition, float width, float height, TextureRegion textureRegion) {
this.movementSpeed = movementSpeed;
this.xPosition = xPosition;
this.yPosition = yPosition+33;
this.width = width;
this.height = height;
this.textureRegion = textureRegion;
}
public void draw(Batch batch)
{
batch.draw(textureRegion,xPosition,yPosition,width,height);
}
}package com.mygdx.game;
package com.mygdx.game;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
class PlayerShip extends Ship {
public PlayerShip(float movementSpeed, int shield, float width, float height, float xCentre, float yCentre,
float laserWidth, float laserHeight, float laserMovementSpeed, float timeBetweenShoots,
TextureRegion shipTexture, TextureRegion shieldTexture, TextureRegion laserTextureRegion) {
super(movementSpeed, shield, width, height, xCentre, yCentre, laserWidth, laserHeight, laserMovementSpeed,
timeBetweenShoots, shipTexture, shieldTexture, laserTextureRegion);
}
public Laser[] fireLaser()
{
Laser[] laser = new Laser[2];
laser[0] = new Laser(xPosition + width * 0.07f, yPosition + height * 0.45f,
laserHeight, laserWidth ,
laserMovementSpeed, laserTextureRegion);
laser[1] = new Laser(xPosition + width * 0.93f, yPosition + height * 0.45f,
laserHeight, laserWidth,
laserMovementSpeed, laserTextureRegion);
timeSinceLastShoot = 0;
return laser;
}
}
I had to adjust my scene coordinates to find useful gravity for my objects.
So I decided to reduce the screen coordinates so that the gravity behavior on my objects was getting ok.
But I have a problem right now, is that when I type sprite.setPosition(0,0), the sprite seems doesn't appear in the right place.
Here is my code:
package com.mygdx.game;
import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.audio.Sound;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.InputAdapter;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.BodyDef;
import com.badlogic.gdx.physics.box2d.FixtureDef;
import com.badlogic.gdx.physics.box2d.PolygonShape;
import com.badlogic.gdx.physics.box2d.CircleShape;
import com.badlogic.gdx.physics.box2d.World;
public class MyGdxGame extends ApplicationAdapter {
public OrthographicCamera camera;
Sound sound;
BitmapFont font,font2;
SpriteBatch batch;
Texture img1,img2,img3,img4,img5,img6;
Sprite sprite1,sprite2,sprite3;
World world;
Body solKose,sagKose,ustKose,altKose,body1,body2,body3;
int width=0;
float axes=0;
private int enemyGoalCounter, playerGoalCounter=0;
Sphere _player;
Sphere _enemyPlayer;
Sphere ball;
Vector2 directionVector;
Vector3 touchCoordinate;
int direction=-1;
#Override
public void create () {
camera = new OrthographicCamera(Gdx.graphics.getWidth(),Gdx.graphics.getHeight());
camera.viewportWidth = Gdx.graphics.getWidth()/100;
camera.viewportHeight = Gdx.graphics.getHeight()/100;
camera.update();
font = new BitmapFont();
font2 = new BitmapFont();
font.setColor(Color.RED);
font2.setColor(Color.BLUE);
touchCoordinate = new Vector3(0,0,0);
sound = Gdx.audio.newSound(Gdx.files.internal("taktak.wav"));
batch = new SpriteBatch();
img1 = new Texture("sphere2.png");
img2 = new Texture("sphere2.png");
img3 = new Texture("ball.png");
sprite1 = new Sprite(img1);
sprite2 = new Sprite(img2);
sprite3 = new Sprite(img3);
sprite1.setPosition(0,0);
sprite2.setPosition(0,0);
world = new World(new Vector2(0, 0),true);
BodyDef bodyDef = new BodyDef();
bodyDef.type = BodyDef.BodyType.DynamicBody;
bodyDef.position.set(sprite1.getX()/2,sprite1.getY()/2);
body1 = world.createBody(bodyDef);
CircleShape shape = new CircleShape();
shape.setRadius(1f);
FixtureDef fixtureDef = new FixtureDef();
fixtureDef.shape = shape;
fixtureDef.restitution=0.6f;
body1.createFixture(fixtureDef);
shape.dispose();
BodyDef bodyDef2 = new BodyDef();
bodyDef2.type = BodyDef.BodyType.DynamicBody;
bodyDef2.position.set(sprite2.getX()/2,sprite2.getY()/2);
body2 = world.createBody(bodyDef2);
CircleShape shape2 = new CircleShape();
shape2.setRadius(1f);
FixtureDef fixtureDef2 = new FixtureDef();
fixtureDef2.shape = shape2;
fixtureDef.restitution=0.6f;
body2.createFixture(fixtureDef2);
shape2.dispose();
}
#Override
public void render () {
System.out.println();
camera.update();
play();
inputController(); // A function for keyboard input controlling
math(); // For Collision controlling
world.step(1f/60f, 6, 2);
sprite1.setPosition(body1.getPosition().x,body1.getPosition().y);
sprite2.setPosition(body2.getPosition().x,body2.getPosition().y);
Gdx.gl.glClearColor(0, 0, 0, 0);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.setProjectionMatrix(camera.combined);
batch.begin();
batch.draw(sprite1,sprite1.getX(),sprite1.getY(),2,2);
batch.draw(sprite2,sprite2.getX(),sprite2.getY(),2,2);
batch.end();
}
#Override
public void dispose () {
batch.dispose();
world.dispose();
}
void play() {
}
void inputController() {
if(Gdx.input.isTouched()){
Vector2 directionVector = new Vector2(0,0);
touchCoordinate.x = Gdx.input.getX();
touchCoordinate.y = Gdx.input.getY();
camera.unproject(touchCoordinate);
double distance = Math.pow(sprite1.getWidth()/2,2)-(Math.pow((sprite1.getOriginX()-touchCoordinate.x),2)+Math.pow((sprite1.getOriginY()-touchCoordinate.y),2));
System.out.println(touchCoordinate);
if(distance>0){
body1.applyForceToCenter(20,20,true);
}else if(distance==0){
body1.applyForceToCenter(20,20,true);
}else{
////
}
}
//_player.setCenterPosition(touchCoordinate.x,touchCoordinate.y);
}
void math() {
goalSystem();
}
void restartPositions(){
}
void goalSystem() {
/*
if(!goal) {
if(ball.getCenterPosition(ball.position.x, ball.position.y).y < 20) {
if((ball.getCenterPosition(ball.position.x, ball.position.y).x >= Gdx.graphics.getWidth()/2-325/2) && (ball.getCenterPosition(ball.position.x, ball.position.y).x <= Gdx.graphics.getWidth()/2+325/2)) {
goal=true;
enemyGoalCounter++;
restartPositions();
}
}
if(ball.getCenterPosition(ball.position.x, ball.position.y).y > Gdx.graphics.getHeight()-20) {
if((ball.getCenterPosition(ball.position.x, ball.position.y).x >= Gdx.graphics.getWidth()/2-325/2) && (ball.getCenterPosition(ball.position.x, ball.position.y).x <= Gdx.graphics.getWidth()/2+325/2)) {
goal=true;
playerGoalCounter++;
restartPositions();
}
}
}
*/
}
public class Sphere{
Vector2 firstPos,firstDirection;
float firstSpeed;
Vector2 position, direction,centerPosition;
float x,y,width,height;
float radius;
float xCenter,yCenter;
float speed;
float velocity;
public Sphere(float x, float y, float radius, float width, float height) {
this.x = x;
this.y = y;
this.radius = radius;
this.width = width;
this.height = height;
this.position = new Vector2(x,y);
this.direction = new Vector2(x,y);
this.speed = 0;
this.firstSpeed = speed;
this.firstPos = new Vector2(x,y);
this.firstDirection = new Vector2(x,y);
}
Vector2 getCenterPosition(float x, float y) {
centerPosition = new Vector2(x+width/2,y);
return centerPosition;
}
void setCenterPosition(float x, float y){
position.x = x-width/2;
position.y = y-height/2;
}
void setSpeed(float speed) {
this.speed = speed;
}
float getSpeed() {
return this.speed;
}
}
}
Image:
I think the issue is the camera and viewport not a rendered position issue. Your code to set the camera and viewport can be changed. If you are using viewports -You- decide the coordinate range for rendering, its arbitary. This rendering is -then- scaled as you like to fit the screen. In your case you get the width and height of the device (which is not constant across devices even aspect ratio changes) before setting your own viewport parameters?
So try instead
camera = new OrthographicCamera(100, 500); //You pick as you like
camera.position.set(camera.viewportWidth / 2, camera.viewportHeight / 2, 0); //centre camera
viewport = new FitViewport(camera.viewportWidth, camera.viewportHeight, camera);//stretch proportionally
Read this as well
How Camera works in Libgdx and together with Viewport
(Also you didn't add the offset to y here.
Vector2 getCenterPosition(float x, float y) {
centerPosition = new Vector2(x+width/2,y);
....
)
I want to add a background like blockbunny and I have a background image image in my assets/images folder under the android folder. I have tried to separate the image into three sections and add it as sky, clouds and mountains in Background class. For some reason, it is throwing null pointer exception because spritebatch is null in MyMainGame class. I have initialised SpriteBatch in create method of MyMainGame class.
Here is my MyMainGame.class
package com.mygdx.game;
import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.GL30;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.mygdx.manager.Content;
import com.mygdx.manager.GameInputProcessor;
import com.mygdx.manager.GameStateManager;
import com.mygdx.manager.MyInput;
import javafx.scene.layout.Background;
import static com.mygdx.manager.Box2DVariables.PPM;
public class MyMainGame implements ApplicationListener {
SpriteBatch batch;
Texture img;
public static final int Width=320;
public static final int Height=240;
public static final int SCALE=2;
public static final float STEP= 1/60f; //60 frames per second
private float accumulator;
private SpriteBatch sb;
protected OrthographicCamera cam;
protected OrthographicCamera hud;
private Texture tex;
private Background[] backgrounds;
private GameStateManager gsm;
public SpriteBatch getSb() {
return sb;
}
public OrthographicCamera getCam() {
return cam;
}
public OrthographicCamera getHud() {
return hud;
}
public static Content con;
#Override
public void create () {
Gdx.input.setInputProcessor(new GameInputProcessor());
con=new Content();
con.loadTexture("images//sprite.jpg","sprite");
con.loadTexture("images//background.png","background");
gsm=new GameStateManager(this);
sb=new SpriteBatch();
cam=new OrthographicCamera(160,120);
cam.setToOrtho(false,Width/2,Height/2);
hud=new OrthographicCamera();
hud.setToOrtho(false,Width/2,Height/2);
}
#Override
public void render () {
cam.update();
hud.update();
accumulator +=Gdx.graphics.getDeltaTime();
while(accumulator>=STEP){
accumulator-=STEP;
gsm.update(STEP);
gsm.render();
MyInput.update();
}
}
public void resize(int width,int height){
sb.getProjectionMatrix().setToOrtho2D(0, 0, width, height);
}
public void dispose(){
con.disposeTexture("sprite");
con.disposeTexture("background");
}
public void pause(){
}
public void resume(){
gsm.setState(GameStateManager.PLAY);
}
}
GameState is an abstract class containing unimplemented methods
package com.mygdx.gamestate;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.mygdx.game.MyMainGame;
import com.mygdx.manager.GameStateManager;
public abstract class GameState {
protected GameStateManager gsm;
protected MyMainGame game;
protected SpriteBatch sb;
protected OrthographicCamera cam;
protected OrthographicCamera hud;
protected GameState(GameStateManager gsm){
this.gsm=gsm;
game=gsm.game();
sb=game.getSb();
cam=game.getCam();
hud=game.getHud();
init();
}
public abstract void init();
public abstract void update(float dt);
public abstract void draw();
public abstract void render();
public abstract void handleInput();
public abstract void dispose();
}
The Play class is extending GameState class
public class Play extends GameState{
// private BitmapFont font=new BitmapFont();
private World world;
private Body playerBody;
private int viewportWidth= 10 * 32 ;
int viewportHeight= 8 * 32 ;
private Box2DDebugRenderer b2d;
private OrthographicCamera B2DCAM;
private TiledMap tileMap;
private OrthogonalTiledMapRenderer orthomap;
private MyContactListener cl;
private float tileSize;
private Background[] backgrounds;
private Texture back;
//file name
private final String LEVEL_1 ="maps/tilemap1.tmx";
public Play(GameStateManager gsm) {
super(gsm);
//setup box2d
world=new World(new Vector2(0,-9.8f),true);
cl=new MyContactListener();
world.setContactListener(cl);
sb=new SpriteBatch(1000);
//cam=new OrthographicCamera();
b2d=new Box2DDebugRenderer();
//create Player
createPlayer();
//create Tiles
createTiles();
orthomap = new OrthogonalTiledMapRenderer(tileMap,1/32f);
//setup Box2D Cam
B2DCAM=new OrthographicCamera();
B2DCAM.setToOrtho(false, MyMainGame.Width/PPM,MyMainGame.Height/PPM);
cam=new OrthographicCamera();
cam.setToOrtho(false,10,7);
back = MyMainGame.con.getTexture("background");
TextureRegion sky = new TextureRegion(back, 0, 0, 320, 240);
TextureRegion clouds = new TextureRegion(back, 0, 240, 320, 240);
TextureRegion mountains = new TextureRegion(back, 0, 480, 320, 240);
backgrounds = new Background[3];
backgrounds[0] = new Background(sky,cam, 0f);
backgrounds[1] = new Background(clouds, cam, 0.1f);
backgrounds[2] = new Background(mountains, cam, 0.2f);
/* //TODO - remove me
File file = new File(LEVEL_1);
if(file.exists())
System.out.println("file exists");*/
}
#Override
public void init() {
}
#Override
public void update(float dt) {
handleInput();
world.step(dt,6,2);
MyMainGame.con.getTexture("sprite");
for (Background b : backgrounds) {
b.update(dt);
}
}
#Override
public void draw() {
}
#Override
public void render() {
//clear screen
Gdx.gl20.glClear(GL20.GL_COLOR_BUFFER_BIT);
//
cam.position.set(playerBody.getPosition().x * PPM +MyMainGame.Width / 4,MyMainGame.Height / 2,0);
// cam.setToOrtho(false,playerBody.getPosition().x * PPM +MyMainGame.Width / 4,MyMainGame.Height / 2);
//cam.setPosition(playerBody.getPosition().x * PPM +MyMainGame.Width / 4, MyMainGame.Height / 2);
cam.setToOrtho(false,10,7);
cam.update();
sb.setProjectionMatrix(cam.combined);
for(int i = 0; i < backgrounds.length; i++) {
backgrounds[i].render(sb);
}
orthomap.setView(cam);
orthomap.render();
b2d.render(world,B2DCAM.combined);
}
#Override
public void handleInput() {
if(MyInput.isPressed((MyInput.SPACE))){
System.out.println("space pressed");
if(cl.isPlayerOnGround())
System.out.println(cl.isPlayerOnGround());
playerBody.applyForceToCenter(0,200,true);
}
}
#Override
public void dispose() {
world.dispose();
b2d.dispose();
tileMap.dispose();
orthomap.dispose();
}
private void createPlayer(){
BodyDef bodydef=new BodyDef();
FixtureDef fixdef=new FixtureDef();
PolygonShape shape=new PolygonShape();
//create player
bodydef.position.set(160/PPM,200/PPM);
bodydef.type= BodyDef.BodyType.DynamicBody;
playerBody=world.createBody(bodydef);
shape.setAsBox(5/PPM,5/PPM);
fixdef.shape=shape;
fixdef.filter.categoryBits= BIT_PLAYER;
fixdef.filter.maskBits=Box2DVariables.BIT_BLUE;
playerBody.createFixture(fixdef).setUserData("PLAYER");
//create foot sensor
shape.setAsBox(2/PPM,2/PPM,new Vector2(0,-5/PPM),0);
fixdef.shape=shape;
fixdef.filter.categoryBits= BIT_PLAYER;
fixdef.filter.maskBits=Box2DVariables.BIT_BLUE;
fixdef.isSensor=true;
playerBody.createFixture(fixdef).setUserData("FOOT");
}
private void createTiles(){
//load tile map
tileMap = new TmxMapLoader().load(LEVEL_1);
//orthomap = new OrthogonalTiledMapRenderer(tileMap,1);
tileSize=(int)tileMap.getProperties().get("tilewidth", Integer.class);
System.out.println("Tile Size " +tileSize);
TiledMapTileLayer layer;
layer=(TiledMapTileLayer)tileMap.getLayers().get("Blue");
createLayer(layer,Box2DVariables.BIT_BLUE);
layer=(TiledMapTileLayer)tileMap.getLayers().get("Green");
createLayer(layer,Box2DVariables.BIT_GREEN);
layer=(TiledMapTileLayer)tileMap.getLayers().get("Red");
createLayer(layer,Box2DVariables.BIT_RED);
System.out.println("Layer Height " +layer.getHeight());
System.out.println("Layer Width " +layer.getWidth());
}
private void createLayer(TiledMapTileLayer layer,short bits){
BodyDef bodydef=new BodyDef();
FixtureDef fixdef=new FixtureDef();
//go through cells in layer
for(int row=0;row<layer.getHeight();row++){
for(int col=0;col<layer.getWidth();col++){
//get cells
TiledMapTileLayer.Cell cell=layer.getCell(col,row);
//check if cell exists
if(cell==null) continue;
if(cell.getTile()==null) continue;
//create body and fixture from cell
bodydef.type= BodyDef.BodyType.StaticBody;
bodydef.position.set((col+0.5f)*tileSize/PPM,(row+0.5f)*tileSize/PPM);
ChainShape cs=new ChainShape();
Vector2[] v=new Vector2[3];
//bottom left
v[0]=new Vector2(-tileSize/2/PPM,-tileSize/2/PPM);
//top left
v[1]=new Vector2(-tileSize/2/PPM,tileSize/2/PPM);
//top right corner
v[2]=new Vector2(tileSize/2/PPM,tileSize/2/PPM);
cs.createChain(v);
fixdef.friction=0;
fixdef.shape =cs;
fixdef.filter.categoryBits=Box2DVariables.BIT_BLUE;
fixdef.filter.maskBits=BIT_PLAYER;
fixdef.isSensor=false;
world.createBody(bodydef).createFixture(fixdef);
}
}
}
}
I have loaded the Texture in MyMainClass.java and it is stored in HashMap in Content class
I am getting the background image as Texture named 'back', and seperating them as TextureRegions sky,clouds and mountains in Play constructor of Play class and passing them in Background class.
TextureRegion sky = new TextureRegion(back, 0, 0, 320, 240);
TextureRegion clouds = new TextureRegion(back, 0, 240, 320, 240);
TextureRegion mountains = new TextureRegion(back, 0, 480, 320, 240);
backgrounds = new Background[3];
backgrounds[0] = new Background(sky,cam, 0f);
backgrounds[1] = new Background(clouds, cam, 0.1f);
backgrounds[2] = new Background(mountains, cam, 0.2f);
Background class
package com.mygdx.manager;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.mygdx.game.MyMainGame;
public class Background {
private TextureRegion image;
private OrthographicCamera camera;
private float scale;
private float x;
private float y;
private int drawX;
private int drawY;
private float dx;
private float dy;
public Background(TextureRegion image, OrthographicCamera camera, float scale) {
this.image = image;
this.camera = camera;
this.scale = scale;
drawX = MyMainGame.Width / image.getRegionWidth() + 1;
drawY = MyMainGame.Height / image.getRegionHeight() + 1;
System.out.println("Image width"+image.getRegionWidth());
System.out.println("Image height"+image.getRegionHeight());
}
public void setVector(float dx, float dy) {
this.dx = dx;
this.dy = dy;
}
public void update(float ts) {
x += (dx * scale) * ts;
y += (dy * scale) * ts;
}
public void render(SpriteBatch sb) {
float x = ((this.x + camera.viewportWidth / 2 - camera.position.x) * scale) % image.getRegionWidth();
float y = ((this.y + camera.viewportHeight / 2 - camera.position.y) * scale) % image.getRegionHeight();
sb.begin();
int colXOffset = x > 0 ? -1 : 0;
int rowYOffset = y > 0 ? -1 : 0;
for (int rowY = 0; rowY < drawY; rowY++) {
for (int colX = 0; colX < drawX; colX++) {
sb.draw(image, x + (colX + colXOffset) * image.getRegionWidth(), y + (rowY + rowYOffset) * image.getRegionHeight());
}
}
sb.end();
}
}
I am getting an error in Play class in render method as null pointer exception.Dont really know whats going on! sb.setProjectionMatrix is giving nullpointer exception!
public void render() {
//clear screen
Gdx.gl20.glClear(GL20.GL_COLOR_BUFFER_BIT);
//
cam.position.set(playerBody.getPosition().x * PPM +MyMainGame.Width / 4,MyMainGame.Height / 2,0);
// cam.setToOrtho(false,playerBody.getPosition().x * PPM +MyMainGame.Width / 4,MyMainGame.Height / 2);
//cam.setPosition(playerBody.getPosition().x * PPM +MyMainGame.Width / 4, MyMainGame.Height / 2);
cam.setToOrtho(false,10,7);
cam.update();
sb.setProjectionMatrix(cam.combined);
for(int i = 0; i < backgrounds.length; i++) {
backgrounds[i].render(sb);
}
orthomap.setView(cam);
orthomap.render();
b2d.render(world,B2DCAM.combined);
}
How do I split the background image and add it as shown above in my Game?
I am having a problem with the libGDX engine. I have a pair of variables to set the width and height of the screen, and another pair to set the width and height of the camera. However, whenever the camera is not the same size as the screen, the engine will not render any sprites. Here is my code for you to look at:
My Constants:
public abstract class Constants
{
public static final int WINDOW_WIDTH = 800;
public static final int WINDOW_HEIGHT = 600;
public static final int CAMERA_WIDTH = 800;
public static final int CAMERA_HEIGHT = 600;
}
Where the Sprite is Created:
public class GameController
{
public static final String TAG = GameController.class.getName();
public Sprite[] testSprites;
public int selectedSprite;
public GameController()
{
init();
}
private void init()
{
initTestObjects();
}
private void initTestObjects()
{
testSprites = new Sprite[1];
int width = 32;
int height = 32;
Pixmap pixmap = createProceduralPixmap(width, height);
Texture texture = new Texture(pixmap);
for(int i = 0; i < testSprites.length; i++)
{
Sprite spr = new Sprite(texture);
spr.setSize(32, 32);
spr.setOrigin(spr.getWidth() / 2.0f, spr.getHeight() / 2.0f);
spr.setPosition(0, 0);
testSprites[i] = spr;
}
selectedSprite = 0;
}
private Pixmap createProceduralPixmap(int width, int height)
{
Pixmap pixmap = new Pixmap(width, height, Format.RGBA8888);
pixmap.setColor(1, 0, 0, 0.5f);
pixmap.fill();
pixmap.setColor(1, 1, 0, 1);
pixmap.drawLine(0, 0, width, height);
pixmap.drawLine(width, 0, 0, height);
pixmap.setColor(0, 1, 1, 1);
pixmap.drawRectangle(0, 0, width, height);
return pixmap;
}
public void update(float deltaTime)
{
updateTestObjects(deltaTime);
}
public void updateTestObjects(float deltaTime)
{
float rotation = testSprites[selectedSprite].getRotation();
rotation += 90 * deltaTime;
rotation %= 360;
testSprites[selectedSprite].setRotation(rotation);
}
}
And the Drawing:
public class GameRenderer implements Disposable
{
public static final String TAG = GameRenderer.class.getName();
private OrthographicCamera camera;
private SpriteBatch batch;
private GameController gameController;
public GameRenderer(GameController gameController)
{
this.gameController = gameController;
init();
}
private void init()
{
batch = new SpriteBatch();
camera = new OrthographicCamera(Constants.CAMERA_WIDTH,
Constants.CAMERA_HEIGHT);
camera.position.set(0, 0, 0);
camera.update();
}
public void render()
{
renderTestObjects();
}
private void renderTestObjects()
{
batch.setProjectionMatrix(camera.combined);
batch.begin();
for(Sprite sprite : gameController.testSprites)
{
sprite.draw(batch);
}
batch.end();
}
public void resize(int width, int height)
{
camera.viewportWidth =
(Constants.CAMERA_HEIGHT / height) * width;
camera.update();
}
#Override
public void dispose()
{
batch.dispose();
}
}
The code above works fine and will render a sprite in the center of the screen, but when I change CAMERA_WIDTH and CAMERA_HEIGHT to say 80 and 60 respectively, instead of making the sprite 10x larger like it should, it doesn't draw anything. Any advice?
You are dividing ints by ints, so you end up with poorly scaled numbers. For example:
camera.viewportWidth =
(Constants.CAMERA_HEIGHT / height) * width;
If the screen width and height are 800 and 600, and CAMERA_HEIGHT is 60, then the equation becomes
camera.viewportWidth =
(60 / 600) * 800;
which becomes (due to pure integer math):
camera.viewportWidth =
(0) * 800;
which becomes 0. You need to cast those ints to floats before dividing! This may not be the only issue, but it alone could be causing your problem.
I tried everything I could, but my libgdx application won't scale down on android 2.2. It displays a full image of 640x480 on a screen of only 480x320. Here's the code I got so far;
private static final int VIRTUAL_WIDTH = 640;
private static final int VIRTUAL_HEIGHT = 480;
private static final float ASPECT_RATIO = (float)VIRTUAL_WIDTH/(float)VIRTUAL_HEIGHT;
public static Texture BMP_BACKGROUND;
public static Rectangle viewport;
public static OrthographicCamera camera;
public static SpriteBatch batch;
public void create()
{
float w = Gdx.graphics.getWidth();
float h = Gdx.graphics.getHeight();
BMP_BACKGROUND = new Texture(Gdx.files.internal("data/bmpSpaceBackground.png"));
BMP_BACKGROUND.setFilter(TextureFilter.Nearest, TextureFilter.Nearest);
batch = new SpriteBatch();
camera = new OrthographicCamera(VIRTUAL_WIDTH, VIRTUAL_HEIGHT);
}
#Override
public void dispose()
{
batch.dispose();
BMP_BACKGROUND.dispose();
}
#Override
public void render()
{
camera.update();
camera.apply(Gdx.gl10);
// set viewport
Gdx.gl.glViewport((int) viewport.x, (int) viewport.y,
(int) viewport.width, (int) viewport.height);
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
batch.draw(BMP_BACKGROUND, 0, 0);
Game.run();
}
public void resize(int width, int height)
{
float aspectRatio = (float)width/(float)height;
float scale = 1f;
Vector2 crop = new Vector2(0f, 0f);
if(aspectRatio > ASPECT_RATIO)
{
scale = (float)height/(float)VIRTUAL_HEIGHT;
crop.x = (width - VIRTUAL_WIDTH*scale)/2f;
}
else if(aspectRatio < ASPECT_RATIO)
{
scale = (float)width/(float)VIRTUAL_WIDTH;
crop.y = (height - VIRTUAL_HEIGHT*scale)/2f;
}
else
{
scale = (float)width/(float)VIRTUAL_WIDTH;
}
float w = (float)VIRTUAL_WIDTH*scale;
float h = (float)VIRTUAL_HEIGHT*scale;
viewport = new Rectangle((int)crop.x, (int)crop.y, (int)w, (int)h);
}
Anyone can tell me what I'm doing wrong?
Try this
public void resize(int width, int height)
{
cam.viewportHeight = height; //set the viewport
cam.viewportWidth = width;
if (Config.VIRTUAL_VIEW_WIDTH / cam.viewportWidth < Config.VIRTUAL_VIEW_HEIGHT
/ cam.viewportHeight) {
//sett the right zoom direct
cam.zoom = Config.VIRTUAL_VIEW_HEIGHT / cam.viewportHeight;
} else {
//sett the right zoom direct
cam.zoom = Config.VIRTUAL_VIEW_WIDTH / cam.viewportWidth;
}
cam.update();
}
This does work and i can work with the virutal resolution. But dont forget to set the camera of your stage you are using! Else it does have no effect!
stage.setCamera(camera).
if you have done that you can work with the virtual resolution inside of your stage.
regards
Your code is 1:1 from an example online.