Before I decided that I wanted to use box2d for all my game physics, I had set up all the non-animated shapes using shaperenderer. I have converted my box2d world and shape to meters at a scale of 32 ppm but all my regular shapes are still drawn with pixels.
Since my box2d circle has been scaled along with the camera, it renders fine with the right size. However, all the shapes that I drew with pixels using shaperenderer are way out of view.
Do I need to redo all of my original shapes with box2d shapes?
Can I just scale all the original shapes with my PPM scaling?
From what I understand, I should be able to just scale all the dimensions of the original shapes by the PPM since I have already scaled the camera?
public class Controller extends Game {
public OrthographicCamera cam;
public ShapeRenderer shape;
public ShapeRenderer circle;
public FitViewport viewport;
public Stage stage;
public World world;
public Body ball;
public Box2DDebugRenderer box2DDebugRenderer;
#Override
public void create() {
cam = new OrthographicCamera();
viewport = new FitViewport(Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), cam);
cam.setToOrtho(false, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
shape = new ShapeRenderer();
circle = new ShapeRenderer(); //balls shot from cannon
world = new World(new Vector2(0, 0), true);
box2DDebugRenderer = new Box2DDebugRenderer();
setScreen(new GameScreen(this));
//setScreen(new TitleScreen(this));
}
#Override
public void dispose() {
shape.dispose();
stage.dispose();
circle.dispose();
box2DDebugRenderer.dispose();
world.dispose();
}
#Override
public void pause() {
}
#Override
public void resume() {
}
#Override
public void resize(int width, int height) {
viewport.update(width, height);
}
public Body createBall(){
Body bBody;
BodyDef def = new BodyDef();
def.type = BodyDef.BodyType.DynamicBody;
def.position.set(500,500);
def.fixedRotation = true;
bBody = world.createBody(def);
return bBody;
}
}
And here is is the actual game screen that implements all the original shapes and the box2d shapes:
import static com.mygdx.game.Utils.Constants.PPM;
public class GameScreen extends ScreenAdapter {
Controller game;
//x-axis length for top/bottom bar
private float goalWidth;
//y-axis height for back bar
private float goalHeight;
private float goalPostThickness;
//Screen height and width
private float screenWidth;
private float screenHeight;
//How far down/up posts are from edge of screen
private float goalPostTopOffset;
private float goalPostBottomOffset;
private float cannonOriginX; //Variables used for starting position of balls
private float cannonOriginY;
float ballX;
float ballY;
public GameScreen (Controller game){
this.game = game;
}
#Override
public void show(){
game.ball = game.createBall();
// Create a circle shape and set its radius to 6
CircleShape circle = new CircleShape();
circle.setRadius(32/2/PPM);
// Create a fixture definition to apply our shape to
FixtureDef fixtureDef = new FixtureDef();
fixtureDef.shape = circle;
fixtureDef.density = 0.5f;
fixtureDef.friction = 0.4f;
fixtureDef.restitution = 0.6f; // Make it bounce a little bit
// Create our fixture and attach it to the body
Fixture fixture = game.ball.createFixture(fixtureDef);
circle.dispose();
}
#Override
public void render(float delta){
//Logic
screenWidth = Gdx.graphics.getWidth();
screenHeight = Gdx.graphics.getHeight();
goalPostTopOffset = screenHeight/7;
goalPostBottomOffset = goalPostTopOffset * 3;
goalHeight = screenHeight - (goalPostTopOffset + goalPostBottomOffset);
goalWidth = screenWidth / 6;
goalPostThickness = screenWidth / 75;
cannonOriginX = goalWidth / 2; //Variables used for starting position of balls
cannonOriginY = (goalPostThickness*5) / 2;
ballX = 0 + cannonOriginX;
ballY = (goalPostBottomOffset - (goalPostBottomOffset / 4)) + cannonOriginY;
game.world.step(1/60f, 6, 2);
//Draw
game.cam.update();
Gdx.gl.glClearColor(0, 0, 0, 0);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
game.box2DDebugRenderer.render(game.world, game.cam.combined.scl(PPM));
game.shape.setProjectionMatrix(game.cam.combined);
drawNonAnimated();
drawAnimated();
}
#Override
public void hide(){
}
//draws stationary objects such as goal posts
public void drawNonAnimated(){
//Top goal bar
game.shape.setColor(1, 1, 1, 1);
game.shape.begin(ShapeRenderer.ShapeType.Filled);
game.shape.rect(screenWidth - goalWidth, screenHeight - goalPostTopOffset, goalWidth, goalPostThickness);
game.shape.end();
//Bottom goal bar
game.shape.setColor(1, 1, 1, 1);
game.shape.begin(ShapeRenderer.ShapeType.Filled);
game.shape.rect(screenWidth - goalWidth, goalPostBottomOffset, goalWidth, goalPostThickness);
game.shape.end();
//Back goal bar
game.shape.setColor(1, 1, 1, 1);
game.shape.begin(ShapeRenderer.ShapeType.Filled);
game.shape.rect(screenWidth - goalPostThickness, goalPostBottomOffset, goalPostThickness, goalHeight);
game.shape.end();
//Cannon platform
game.shape.setColor(1, 1, 1, 1);
game.shape.begin(ShapeRenderer.ShapeType.Filled);
game.shape.rect(0, goalPostBottomOffset - (goalPostBottomOffset / 4),goalWidth, goalPostThickness*2);
game.shape.end();
//Cannon
game.shape.setColor(1, 1, 1, 1);
game.shape.begin(ShapeRenderer.ShapeType.Filled);
game.shape.rect(0, goalPostBottomOffset - (goalPostBottomOffset / 4), cannonOriginX,
cannonOriginY, goalWidth, goalPostThickness*5, 1, 1, 45);
game.shape.end();
}
public void drawAnimated(){
//Ball(s)
game.circle.setColor(1, 1, 1, 1);
game.circle.begin(ShapeRenderer.ShapeType.Filled);
game.circle.circle(ballX, ballY, goalPostThickness * 2.5f);
game.circle.end();
game.cam.update();
ballX += 1;
}
}
As I mentioned earlier, the circle shape rendered with box2d shows fine with the PPM scale. However, all the shapes that I drew with shaperenderer are off the screen.
Related
I have been puzzling my mind with the code and I've made a huge amount of progress from not doing pixel to meter to now having a body and sprite almost in line however ive reached another point where i can't seem to figure out where I have gone wrong.
As you can see from the image the body is off from the actual sprite, I have a hunch that it might be origin as it the difference is very slight but I can't seem to work out how to get it in line.
My Create method
public class Physics1 extends ApplicationAdapter implements InputProcessor {
SpriteBatch batch;
Sprite sprite;
Texture img;
World world;
Body body;
Box2DDebugRenderer debugRenderer;
Matrix4 debugMatrix;
OrthographicCamera camera;
Vector2 bodyOrigin;
float torque = 0.0f;
boolean drawSprite = true;
final float PIXELS_TO_METERS = 100f;
final float WORLD_WIDTH =100;
final float WORLD_HEIGHT=100;
#Override
public void create() {
Assets.instance.init(new AssetManager());
batch = new SpriteBatch();
bodyOrigin = new Vector2();
sprite = new Sprite();
sprite.setRegion(Assets.instance.tyre.tyre);
sprite.setSize(12,12);
sprite.setOrigin(sprite.getWidth()/2, sprite.getHeight()/2);
sprite.setPosition(50-sprite.getWidth()/2,25);
Gdx.app.log("Physics1", "Sprite positions"+ -sprite.getWidth()/2+ " ,"+ -sprite.getHeight()/2);
world = new World(new Vector2(0, 0f),true);
BodyDef bodyDef = new BodyDef();
bodyDef.type = BodyDef.BodyType.DynamicBody;
BodyEditorLoader load = new BodyEditorLoader(Gdx.files.internal("levels/pittstop.json"));
bodyDef.position.set(sprite.getX()/PIXELS_TO_METERS,sprite.getY()/PIXELS_TO_METERS);
Gdx.app.log("Physics1", "Body positions calculations"+ sprite.getX() +" "+ sprite.getWidth()/2);
Gdx.app.log("Physics1", "Body positions"+ bodyDef.position);
body = world.createBody(bodyDef);
FixtureDef fixtureDef = new FixtureDef();
fixtureDef.density = 0.1f;
fixtureDef.friction = 0.0f;
fixtureDef.restitution = 0.0f;
float scale =0.2f;
load.attachFixture(body, "tyre", fixtureDef, scale);
Gdx.app.log("Physics1"," Orgin of body" +load.getOrigin("tyre", scale).cpy());
bodyOrigin = load.getOrigin("tyre", scale).cpy();
body.setUserData("tyre");
Gdx.input.setInputProcessor(this);
debugRenderer = new Box2DDebugRenderer();
camera = new OrthographicCamera(WORLD_WIDTH,WORLD_HEIGHT);
Gdx.app.log("Physics1", "camera "+ camera.viewportWidth+" "+camera.viewportHeight);
camera.position.set(WORLD_WIDTH / 2f, WORLD_HEIGHT / 2f, 0);
Gdx.app.log("Physics1", "camera "+ camera.viewportWidth+" "+camera.viewportHeight);
}
My render method
public void render() {
camera.update();
world.step(1f/60f, 6, 2);
body.applyTorque(torque,true);
sprite.setPosition((body.getPosition().x * PIXELS_TO_METERS),
(body.getPosition().y * PIXELS_TO_METERS))
;
sprite.setRotation((float)Math.toDegrees(body.getAngle()));
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.setProjectionMatrix(camera.combined);
debugMatrix = batch.getProjectionMatrix().cpy().scale(PIXELS_TO_METERS,
PIXELS_TO_METERS, 0);
batch.begin();
if(drawSprite)
batch.draw(sprite, sprite.getX(), sprite.getY(),bodyOrigin.x,
bodyOrigin.y,
sprite.getWidth(),sprite.getHeight(),sprite.getScaleX(),sprite.
getScaleY(),sprite.getRotation());
batch.end();
debugRenderer.render(world, debugMatrix);
}
False alarm, turns out in physics editor you have the opportunity to change the origin of the body you are drawing up, just by clicking around I was able to move the origin to the centre and there you have it.
Hi guys i'm quite new to libgdx I tried to make the camera follow the player.
Trying to do so i read online that i had to add this line of code.
game.getBatch().setProjectionMatrix(gamecam.combined);
By doing so i noticed that my game was really zoomed i tried to dezoom it but i was not able to make it work. Do you guys have any suggestion?
This is my GameScreen where i render the player.
`public class GameScreen implements Screen {
private Logang game;
//basic playscreen variables
private OrthographicCamera gamecam;
private Viewport gamePort;
//Box2d variables
private World world;
private Box2DDebugRenderer b2dr;
boolean drawn = true;
private Player p;
private int pX = 100, pY = 300;
public GameScreen(Logang game) {
this.game = game;
//create cam used to follow mario through cam world
gamecam = new OrthographicCamera(Logang.GWIDTH, Logang.GHEIGHT);
gamecam.update();
//create our Box2D world, setting no gravity in X, -10 gravity in Y, and allow bodies to sleep
world = new World(new Vector2(0, Logang.GRAVITY), true);
//allows for debug lines of our box2d world.
b2dr = new Box2DDebugRenderer();
//create a FitViewport to maintain virtual aspect ratio despite screen size
gamePort = new ScalingViewport(Scaling.fill, Logang.GWIDTH / Logang.PPM, Logang.GHEIGHT / Logang.PPM, gamecam);
p = new Player(new Sprite(new Texture("badlogic.jpg")), world, pX, pY, 1);
//initially set our gamcam to be centered correctly at the start of of map
//gamecam.position.set(gamePort.getWorldWidth() / 2, gamePort.getWorldHeight() / 2, 0);
line();
}
#Override
public void show() {
}
public void update(float dt) {
//handle user input first
p.update(dt);
//update our gamecam with correct coordinates after changes
/*gamecam.position.set(p.getSprite().getX(),0,0);
gamecam.update();*/
}
#Override
public void render(float delta) {
//separate our update logic from render
update(delta);
//Clear the game screen with Black
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
world.step(1f / 60f, 6, 2);
gamecam.position.set(p.getSprite().getX(), p.getSprite().getY(), 0); // x and y could be changed by Keyboard input for example
//gamecam.position.set(p.getSprite().getX(), p.getSprite().getY(), 0);
gamecam.update();
game.getBatch().setProjectionMatrix(gamecam.combined);
//renderer our Box2DDebugLines
b2dr.render(world, gamecam.combined);
System.out.println("Player x: " + p.getSprite().getX() + " Camera X: " + gamecam.position.x + " Body X: " + p.getBody().getPosition().x);
//System.out.println("Player y: " + p.getSprite().getY() + " Camera Y: " + gamecam.position.y + " Body Y: " + p.getBody().getPosition().y);
game.getBatch().begin();
if (p.getBody() != null)
p.render(game.getBatch());
EntityManager.renderTerra(game.getBatch(), delta);
game.getBatch().end();
}
public void line() {
Texture tmp = new Texture("dirt.png");
tmp.setWrap(Texture.TextureWrap.MirroredRepeat, Texture.TextureWrap.MirroredRepeat);
for (int i = 0; i < 10; i++) {
EntityManager.add(new Ground(new Sprite(tmp), world, i * Logang.TILE, 0, 2));
}
//EntityManager.changeSize(Logang.TILE * 5,Logang.TILE);
}
#Override
public void resize(int width, int height) {
//updated our game viewport
gamePort.update(width, height);
}
public World getWorld() {
return world;
}
#Override
public void pause() {
}
#Override
public void resume() {
}
#Override
public void hide() {
}
#Override
public void dispose() {
world.dispose();
b2dr.dispose();
}`
And this is my Entity class which is extended by the Player which i empty for now`
public abstract class Entity {
private World world;
private Sprite sprite;
private Body body;
private int tipo;
public Entity(Sprite sprite, World world, int x, int y, int tipo){
this.sprite = sprite;
this.world = world;
getSprite().setPosition(x, y);
getSprite().setSize(Logang.TILE, Logang.TILE);
define(tipo);
this.tipo = tipo;
}
public abstract void update(float dt);
public void define(int tipo){
BodyDef bdef = new BodyDef();
bdef.position.set((getSprite().getX() + getSprite().getWidth() / 2) / Logang.PPM, (getSprite().getY() + getSprite().getHeight() / 2) / Logang.PPM);
switch(tipo){
case 1: {
bdef.type = BodyDef.BodyType.DynamicBody;
break;
}
case 2:{
bdef.type = BodyDef.BodyType.StaticBody;
break;
}
case 3:{
bdef.type = BodyDef.BodyType.DynamicBody;
break;
}
}
body = world.createBody(bdef);
FixtureDef fdef = new FixtureDef();
PolygonShape shape = new PolygonShape();
shape.setAsBox(getSprite().getWidth() / Logang.PPM / 2, getSprite().getHeight() / Logang.PPM / 2);
fdef.shape = shape;
body.createFixture(fdef);
body.setUserData(this);
shape.dispose();
}
public void render(SpriteBatch batch){
if(tipo != 2) {
float posX = getBody().getPosition().x * Logang.PPM;
float posY = getBody().getPosition().y * Logang.PPM;
getSprite().setPosition(posX - getSprite().getWidth() / 2, posY - getSprite().getHeight() / 2);
}
getSprite().draw(batch);
}
public Sprite getSprite() {
return sprite;
}
public void setSprite(Sprite sprite) {
this.sprite = sprite;
}
public Body getBody() {
return body;
}
public void setBody(Body body) {
this.body = body;
}`
If I remove that line at the start the game sizes are good but my camera doesn't follow my player.
Thanks for the answer and sorry if the question was not well asked.
1) If your viewport dimensions divided by Logang.PPM then all Textures size should be also divided by Logang.PPM.
Logang.TILE should be float and divided by Logang.PPM
Player sprite also should be resized**.
2) To follow player try dividing gamecam resolution by Logang.PPM.
Initialize it like this:
gamecam = new OrthographicCamera(Logang.GWIDTH / Logang.PPM, Logang.GHEIGHT / Logang.PPM);
UPD: I found issue, it was in player render method:
float posX = getBody().getPosition().x; // delete * Logang.PPM
float posY = getBody().getPosition().y; // delete * Logang.PPM
The camera takes in two variables: the width and height of the world. That's an important keyword here, as it defines the rendered size of the world. If the width and height of the camera is 300x300, that means there's 300x300 units visible on the screen, even if the screen is 1920x1080.
When you do:
gamecam = new OrthographicCamera(Logang.GWIDTH, Logang.GHEIGHT);
You set the width and height of the camera to a given value.
The second you apply it:
game.getBatch().setProjectionMatrix(gamecam.combined);
the batch you use to render uses the projection matrix of the camera, meaning it converts screen coordinates to world coordinates based on the width and height of what's visible at once. For an instance 300x300.
If you think the world is too small (meaning what you render shows up as too big) you can of course zoom out by adding a scale factor, but you can also increase the width and height of the camera. I have no clue what you set the width and height to, but if you increase the width and height it'll probably work.
And as I already mentioned, the world coordinates can be different from the screen coordinates.
I have a Circle shape that is going to represent the character I will play and control. I have a tmx map, and in the map there are red squares that are meant to represent "fences". The fences are in each corner of the map, inside the fences I have the ground that looks the same as the rest of the ground in the map, but I want to make it so that the game knows when the character is standing on those tiles in the map. can anyone help me? I don't know if it will help but here is the code:
public class PlayScreen implements Screen{
private Game game;
private OrthographicCamera gamecam;
private Viewport gamePort;
private TmxMapLoader mapLoader;
private TiledMap map;
OrthogonalTiledMapRenderer renderer;
//Box#d variables
private World world;
private Box2DDebugRenderer b2dr;
private Hero hero;
private ArrayList<Rectangle> specGroundList;
private boolean heroOnGround;
public PlayScreen(BasicGame game){
this.game = game;
gamecam = new OrthographicCamera();
gamePort = new FitViewport(BasicGame.V_WIDTH, BasicGame.V_HEIGHT, gamecam);
mapLoader = new TmxMapLoader();
map = mapLoader.load("Basic Map.tmx");
renderer = new OrthogonalTiledMapRenderer(map);
gamecam.position.set(gamePort.getWorldWidth() / 2, gamePort.getWorldHeight() / 2, 0);
world = new World(new Vector2(0, 0), true);
b2dr = new Box2DDebugRenderer();
hero = new Hero(world, this);
specGroundList = new ArrayList<Rectangle>();
world.setContactListener(new WorldContactListener());
BodyDef bdef = new BodyDef();
PolygonShape shape = new PolygonShape();
FixtureDef fdef = new FixtureDef();
Body body;
//create fence bodies/fixtures
for(MapObject object: map.getLayers().get(3).getObjects().getByType(RectangleMapObject.class)){
Rectangle rect = ((RectangleMapObject) object).getRectangle();
bdef.type = BodyDef.BodyType.StaticBody;
bdef.position.set(rect.getX() + rect.getWidth() / 2, rect.getY() + rect.getHeight() / 2);
body = world.createBody(bdef);
shape.setAsBox(rect.getWidth() / 2, rect.getHeight() / 2);
fdef.shape = shape;
body.createFixture(fdef);
}
//create special ground bodies/fixtures
for(MapObject object: map.getLayers().get(2).getObjects().getByType(RectangleMapObject.class)) {
Rectangle rect = ((RectangleMapObject) object).getRectangle();
bdef.type = BodyDef.BodyType.StaticBody;
bdef.position.set(rect.getX() + rect.getWidth() / 2, rect.getY() + rect.getHeight() / 2);
body = world.createBody(bdef);
shape.setAsBox(rect.getWidth() / 2, rect.getHeight() / 2);
fdef.shape = shape;
body.createFixture(fdef);
}
}
#Override
public void render(float delta) {
update(delta);
// Clear the game screen with Black
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
renderer.render();
b2dr.render(world, gamecam.combined);
}
#Override
public void show() {
}
public void handleInput(float dt){
if(Gdx.input.isTouched()) {
// gamecam.position.x += 100 * dt;
gamecam.position.y -= 100 * dt;
}
}
public void update(float dt){
handleInput(dt);
world.step(1/60f, 6, 0);
hero.update(dt);
for(Rectangle rect: specGroundList){
}
gamecam.update();
renderer.setView(gamecam);
}
#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() {
}
public Viewport getGamePort() {
return gamePort;
}
}
Assuming your hero has a known position, and your regions of special ground are oriented rectangles then can't you just use a boolean function that returns something along the lines of:
Hero.x > rectangle.left & Hero.x < rectangle.right & hero.y > rectangle.bottom & hero.y < rectangle.top
So, I just want to draw Box2DDebugRenderer same with sprite size.
I have use same SpriteBatch same Camera and same Viewport. It took me 8 hours, tried finding a solution around google and still not solve the problem.
Here what I got:
I just change this line:
PolygonShape shape = new PolygonShape();
shape.setAsBox(32, 32);
Some tutorial said to div by 2. I tried that I got result like 2nd picture.
Here my script
PlayScreen.java:
public class PlayScreen implements Screen {
private SpriteBatch batch;
private TiledMap tileMap;
private TiledMapRenderer tiledMapRenderer;
private OrthographicCamera cam;
private Player player;
private World world;
private Box2DDebugRenderer debugRenderer;
private FitViewport gamePort;
public PlayScreen(HookaHookaGame game) {
this.batch = game.getSpriteBatch();
this.world = new World(new Vector2(0, -20), true);
// Create cam
cam = new OrthographicCamera();
gamePort = new FitViewport(800, 600, cam);
gamePort.apply(true);
//initially set our gamcam to be centered correctly at the start of of map
// cam.position.set(400, 300, 0);
// cam.update();
// Load tilemap
tileMap = new TmxMapLoader().load("simulation01.tmx");
tiledMapRenderer = new OrthogonalTiledMapRenderer(tileMap, batch);
// Create box2d debug renderer
debugRenderer = new Box2DDebugRenderer();
// Create player sprite
player = new Player(this.world);
}
#Override
public void show() {
}
#Override
public void render(float delta) {
//cam.update();
// Update sprite
player.update(delta);
//Clear the game screen with Black
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
// Draw tilemap
tiledMapRenderer.setView(cam);
tiledMapRenderer.render();
// Set camera to spritebatch
batch.setProjectionMatrix(cam.combined);
// Draw sprite
batch.begin();
batch.draw(player.getKeyFrame(), 300, 300);
player.draw(batch);
batch.end();
// Draw box2d debug renderer
debugRenderer.render(world, cam.combined);
}
#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() {
}
}
Player.java, extended from Sprite Class:
public class Player extends Sprite {
private Animation anim;
private float stateTimer;
private World world;
private Body body;
// Debug
public Player(World world) {
stateTimer = 0;
this.world = world;
loadAnim();
}
private void loadAnim() {
Array<TextureRegion> temp = new Array<TextureRegion>(40);
Texture texture = new Texture("sprite.png");
temp.add(new TextureRegion(texture, 3*32, 3*32, 32, 32));
temp.add(new TextureRegion(texture, 2*32, 3*32, 32, 32));
temp.add(new TextureRegion(texture, 32, 3 * 32, 32, 32));
temp.add(new TextureRegion(texture, 0, 3*32, 32, 32));
anim = new Animation(0.1f, temp, Animation.PlayMode.LOOP);
BodyDef bodyDef = new BodyDef();
bodyDef.position.set(100, 100);
bodyDef.type = BodyDef.BodyType.DynamicBody;
body = world.createBody(bodyDef);
PolygonShape shape = new PolygonShape();
shape.setAsBox(32, 32);
FixtureDef fixture = new FixtureDef();
fixture.shape = shape;
body.createFixture(fixture);
setBounds(0, 0, 32, 32);
setPosition(100, 100);
}
public void update(float delta) {
stateTimer += delta;
setRegion(getKeyFrame());
setSize(32, 32);
}
public TextureRegion getKeyFrame() {
return anim.getKeyFrame(stateTimer, true);
}
}
Could you explain what happen exactly?
Box2d and Textures have different origins.
The origin of the body is its center.
The origin of the Texture is the bottom left corner.
As you can see, the center of the box2d object is exactly at the bottom left corner of the texture, if you draw them both at the same position.
Pseudo code:
batch.draw(texture, body.x - texture.width / 2, body.y - texture.heigth / 2);
Otherwise you could set the origin of the box2d body to "the bottom left corner", but that might give you trouble if you follow other tutorials.
you can also put the origin of your sprite to center by calling the function setOriginCenter() of your Sprites before drawing them
so the spritebatch will draw them from center just like your box
When i run the game in Desktop works fine, but when i run it in my android device, the image looks cuted in a half and when i use the PLAY button the game closes, anyone can help me? thank you.
public class GameScreen extends AbstractScreen {
private Viewport viewport;
private Camera camera;
private SpriteBatch batch;
private Texture texture;
private float escala;
private Paddle Lpaddle, Rpaddle;
private Ball ball;
private BitmapFont font;
private int puntuacion, puntuacionMaxima;
private Preferences preferencias;
private Music music;
private Sound sonidoex;
public GameScreen(Main main) {
super(main);
preferencias = Gdx.app.getPreferences("PuntuacionAppPoints");
puntuacionMaxima = preferencias.getInteger("puntuacionMaxima");
music =Gdx.audio.newMusic(Gdx.files.internal("bgmusic.mp3"));
music.play();
music.setVolume((float) 0.3);
music.setLooping(true);
sonidoex = Gdx.audio.newSound(Gdx.files.internal("explosion5.wav"));
}
public void create(){
camera = new PerspectiveCamera();
viewport = new FitViewport(800, 480, camera);
}
public void show(){
batch = main.getBatch();
texture = new Texture(Gdx.files.internal("spacebg.png"));
Texture texturaBola = new Texture(Gdx.files.internal("bola.png"));
ball = new Ball(Gdx.graphics.getWidth() / 2 - texturaBola.getWidth() / 2, Gdx.graphics.getHeight() / 2 - texturaBola.getHeight() / 2);
Texture texturaPala= new Texture(Gdx.files.internal("pala.png"));
Lpaddle = new LeftPaddle(80, Gdx.graphics.getHeight()/2 -texturaPala.getHeight() /2);
Rpaddle = new RightPaddle(Gdx.graphics.getWidth() -100, Gdx.graphics.getHeight()/2 - texturaPala.getHeight() /2, ball);
font = new BitmapFont();
font.setColor(Color.WHITE);
font.setScale(1f);
puntuacion = 0;
}
public void render(float delta){
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
updatePuntuacion();
Lpaddle.update();
Rpaddle.update();
ball.update(Lpaddle, Rpaddle);
batch.begin();
batch.draw(texture, 0, 0,texture.getWidth(), texture.getHeight());
ball.draw(batch);
Lpaddle.draw(batch);
Rpaddle.draw(batch);
font.draw(batch, "Points: " + Integer.toString(puntuacion), Gdx.graphics.getWidth() / 4 ,Gdx.graphics.getHeight() - 5);
font.draw(batch, "High score: " + Integer.toString(puntuacionMaxima),Gdx.graphics.getWidth() - Gdx.graphics.getWidth() / 4 ,Gdx.graphics.getHeight() - 5);
batch.end();
}
private void updatePuntuacion(){
if(ball.getBordes().overlaps(Lpaddle.getBordes())) {
puntuacion = puntuacion + 1;
if(puntuacion > puntuacionMaxima)
puntuacionMaxima = puntuacion;
}
if(ball.getBordes().x <= 0)
sonidoex.play();
if(ball.getBordes().x <= 0)
puntuacion =0;
if(ball.getBordes().x <=0)
Gdx.input.vibrate(1000);
if(ball.getBordes().x <=0)
Screens.juego.setScreen(Screens.MAINSCREEN);
ball.comprobarPosicionBola();
}
public void hide(){
font.dispose();
texture.dispose();
}
#Override
public void dispose(){
preferencias.putInteger("puntuacionMaxima", puntuacionMaxima);
preferencias.flush();
}
public void resize(int width, int height){
float widthImage = texture.getWidth();
float heightImage = texture.getHeight();
float r = heightImage / widthImage;
if(heightImage > height) {
heightImage = height;
widthImage = heightImage / r;
}
if(widthImage > width) {
widthImage = width;
heightImage = widthImage * r;
}
escala = width / widthImage;
if(Gdx.app.getType()== ApplicationType.Android)
viewport.update(width, height);
}
}
Firstly, use an orthograpic camera.
camera=new OrthographicCamera(800,480);
camera.position.set(800/2f,480/2f,0);
viewport=new FitViewport(800,480,camera);
Now 0,0 is in the left bottom corner of your screen.
And before doing batch.begin don't forget to set your projection matrix
batch.setProjectionMatrix(camera.combined);
batch.begin();
////
////
batch.end();