I'm trying to make a little game with the java game engine called libGDX. I already got the player but he can't jump and I dont know why.
This is my GameScreen class:
public class GameScreen extends ScreenManager{
//For the view of the game and the rendering
private SpriteBatch batch;
private OrthographicCamera cam;
//DEBUG
private Box2DDebugRenderer b2dr;
//World, Player and so on
private GameWorld world;
private Player player;
private Ground ground;
public static float w, h;
public GameScreen(Game game) {
super(game);
//vars
w = Gdx.graphics.getWidth();
h = Gdx.graphics.getHeight();
//view and rendering
batch = new SpriteBatch();
cam = new OrthographicCamera();
cam.setToOrtho(false, w/2, h/2);
//debug
b2dr = new Box2DDebugRenderer();
//world, bodies ...
player = new Player(world);
ground = new Ground(world);
}
#Override
public void pause() {
}
#Override
public void show() {
}
#Override
public void render(float delta) {
//clearing the screen
Gdx.gl.glClearColor(0, 0, 0, 0);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
//updating
update(Gdx.graphics.getDeltaTime());
//render
batch.setProjectionMatrix(cam.combined);
//debug
b2dr.render(world.getWorld(), cam.combined);
}
#Override
public void resize(int width, int height) {
}
#Override
public void hide() {
}
#Override
public void dispose() {
}
#Override
public void onKlick(float delta) {
}
public void update(float delta){
world.update(delta);
player.keyInput();
System.out.println(player.getBody().getPosition().x);
System.out.println(player.getBody().getPosition().y);
}
}
and this is my Player class:
public class Player {
public static Body body;
public static BodyDef def;
private FixtureDef fd;
//set form
private PolygonShape shape;
private GameScreen gs;
public Player(GameWorld world){
def = new BodyDef();
def.fixedRotation = true;
def.position.set(gs.w / 4, gs.h / 4);
def.type = BodyType.DynamicBody;
body = world.getWorld().createBody(def);
shape = new PolygonShape();
shape.setAsBox(32 / 2, 32 / 2);
fd = new FixtureDef();
fd.shape = shape;
fd.density = 30;
body.createFixture(fd);
shape.dispose();
}
public static Body getBody() {
return body;
}
public static BodyDef getDef() {
return def;
}
public static void keyInput(){
if(Gdx.input.isKeyPressed(Input.Keys.UP)){
body.applyForceToCenter(0, 900, false);
System.out.println("PRESSED");
}
}
}
this finally is my GameWorld class:
public class GameWorld {
public static World world;
public GameWorld(){
world = new World(new Vector2(0f, -10f), false);
}
public void update(float delta){
world.step(1 / 60f, 5, 2);
System.out.println("WorldUPDATE");
}
public static World getWorld() {
return world;
}
}
I don't know why the body can't jump please help me if you can (: Thank you in advance.
Force pushes the body each timestep, while gravity pushes it back down again. There is a function applyLinearImpulse() which pushes it like once with all its "force" before gravity interferention.
When you are using applyForceToCenter() body should be pushed up, but its very slow process compared to impulse.
Related
For some reason, my Box2d Object code works in one Class but does not work in the other even though it is the exact same code I have read it has something to do with importing the correct library but the library is imported correctly but still, it is not working. I'm kind of desperate and don't know what to do, to be honest, maybe someone here can give me a pointer. I know this is a lot of code, but I really don't know what to do, I hope someone can give me a pointer, maybe I am just overlooking something
Here is the code with the Object:
public class Tank extends Sprite implements Renderable, PhysicsObject, Updatable {
public Body body;
public Sprite SpriteBody;
public Sprite SpriteTurret;
public Playscreen playScreen;
public InputProvider input;
public Vector2 aim;
public int readytoshoot=0;
public float canonrotation;
public World world;
public Body b2Body;
TextureRegion TankBlues;
SpriteBatch sb;
public Texture texture;
public Texture arm;
Sprite sprite;
Sprite sparm;
int horizontalForce;
float dt;
float Richtung;
float Speed = 2f;
public float Radius;
private TankType type;
public ArrayList<Flower> flowers;
float PosX,PosY;
Body TankBody,CanonBody;
RevoluteJoint joint;
private Map<ControlSpecification, Integer> controlMap;
private boolean useController;
private int currentLife;
private int maxLife;
private int fullLifeWidth;
// Playscreen playscreen, Vector2 aim, Input Inputprovider,
public Tank(World world, Playscreen screen, SurvivalMode2 survivalMode, TankType tankType) {
flowers = new ArrayList<Flower>();
// super(screen.getAtlas().findRegion("tankBody_blue"));
this.world = world;
canonrotation=0;
// TankBlues = new TextureRegion(getTexture(),0,0 , 46,46);
// setBounds(0, 0, 46 / SEPGame.PPM, 46 / SEPGame.PPM);
// setRegion(TankBlues);
sb = new SpriteBatch();
texture = new Texture(Gdx.files.internal("tankBody_.png"));
arm = new Texture(Gdx.files.internal("b-tankBlue_barrel2_outline.png"));
sprite = new Sprite(texture);
sparm = new Sprite(arm);
PosX=Gdx.graphics.getWidth() / 2 ;
PosY= Gdx.graphics.getHeight() / 2;
sprite.setPosition(PosX,PosY);
sparm.setPosition(Gdx.graphics.getWidth() / 2 - sprite.getWidth() / 2, Gdx.graphics.getHeight() / 2);
useController = false;
// defineTank();
// registerController();
controlMap = StandardControlSpecification.getMapping(tankType);
this.type = tankType;
// defineTank();
// registerController();
// TankBody erstellen
BodyDef bodyDef = new BodyDef();
bodyDef.type = BodyType.DynamicBody;
bodyDef.position.set(PosX, PosY);
PolygonShape shape = new PolygonShape();
shape.setAsBox(sprite.getWidth()/2-1, sprite.getHeight()/2-1);
Radius=(float)Math.sqrt((double)(sprite.getWidth()*sprite.getWidth()/4+sprite.getHeight()*sprite.getHeight()/4) );
FixtureDef fixDef = new FixtureDef();
fixDef.shape = shape;
fixDef.density = 1f;
fixDef.restitution = .1f;
fixDef.friction = .5f;
TankBody = world.createBody(bodyDef);
TankBody.createFixture(fixDef);
TankBody.setLinearDamping(2f);
TankBody.setAngularDamping(2f);
TankBody.setUserData(42);
this.type = tankType;
maxLife = 100;
currentLife = maxLife;
fullLifeWidth = 300;
}
public Rectangle getRect() {
Rectangle Rectanlge = new Rectangle(sprite.getX(), sprite.getY(), sprite.getWidth(), sprite.getHeight());
return Rectanlge;
}
private void registerController() {
for (Controller controller : Controllers.getControllers()) {
controller.addListener(new GamepadInputProvider(this));
}
}
public float getX() {
return sprite.getX();
}
public float getY() {
return sprite.getY();
}
public float getRotation() {
return sparm.getRotation();
}
public void collision() {
}
public void takeDamage(int damage) {
currentLife -= damage;
}
public void defineTank() { //verwenden wir net physic engine
BodyDef bDef = new BodyDef();
bDef.position.set(sprite.getX(), sprite.getY());
bDef.type = BodyDef.BodyType.DynamicBody;
b2Body = world.createBody(bDef);
FixtureDef fDef = new FixtureDef();
PolygonShape shape = new PolygonShape();
shape.setAsBox(70, 70);
// fDef.density = 1f;
fDef.shape = shape;
b2Body.createFixture(fDef);
}
public void render()
{
sb.begin();
float x=TankBody.getPosition().x-sprite.getWidth()/2;
float y=TankBody.getPosition().y-sprite.getHeight()/2;
sprite.setPosition(x, y);
sprite.setRotation((float)(TankBody.getAngle()/Math.PI*180f));
sparm.setPosition(x, y);
sparm.setRotation((float)(TankBody.getAngle()/Math.PI*180f+canonrotation) );
sprite.draw(sb);
sparm.draw(sb);
sb.end();
Flower destroy = null;
boolean del=false;
for (Flower flower : flowers)
{
if(flower.todelete==0)
{
del=true;
destroy=flower;
}
else
{
flower.render();
}
}
if(del)
{
flowers.remove(destroy);
destroy.delete();
del=false;
}
renderLifebar();
}
Here is the class where it works:
public class Playscreen extends WorldMap implements Screen {
public World world;
public SpriteBatch batch;
public float timeToSimulate;
private SEPGame game;
SpriteBatch sb;
public Tank tank;
public Target ziel;
private Tank gegner1;
boolean treffer;
public float width = Gdx.graphics.getWidth();
public float heights = Gdx.graphics.getHeight();
public WorldMap worldMap;
public Box2DDebugRenderer debugRenderer;
public Obstacle leftwall,upperwall,rightwall,lowerwall;
public Obstacle O1,O2,O3,O4;
public TextureAtlas atlas;
public MenuScreen menuScreen;
int anzahlTotePanzer = 0;
public Playscreen(SEPGame game)
{
world= new World(new Vector2(0,0), false);
ziel = new Target(MathUtils.random(Gdx.graphics.getWidth()-48),MathUtils.random(Gdx.graphics.getHeight()-48),world);
tank = new Tank(world,this, null,TankType.PLAYER_2);
gegner1 = new Tank(world, this, null,TankType.KI);
menuScreen = new MenuScreen(game);
atlas = new TextureAtlas("TanksGesamt.atlas");
leftwall=new Obstacle(world,1);
upperwall=new Obstacle(world,2);
rightwall=new Obstacle(world,3);
lowerwall=new Obstacle(world,4);
O1=new Obstacle(world, 200, 523, 30, 100, 90);
Texture t=new Texture(Gdx.files.internal("crateMetal.png"));
O2=new Obstacle(world, 400, 100, t);
O3=new Obstacle(world, 1200, 900, t);
worldMap = new WorldMap();
this.game = game;
debugRenderer = new Box2DDebugRenderer( true, true,
false, true, true, true );
world.setContactListener(new ContactListener()
{
#Override
public void beginContact(Contact contact)
{
}
#Override
public void endContact(Contact contact)
{
Fixture fixtureA = contact.getFixtureA();
Fixture fixtureB = contact.getFixtureB();
Body BodyA=contact.getFixtureA().getBody();
if(BodyA.equals(ziel.TargetBody))
{
treffer=true;
}
for (Flower flower : tank.flowers)
{
if(flower.FlowerBody.equals(contact.getFixtureB().getBody())
||flower.FlowerBody.equals(contact.getFixtureA().getBody()))
{
flower.todelete-=1;
}
}
}
#Override
public void preSolve(Contact contact, Manifold oldManifold)
{
}
#Override
public void postSolve(Contact contact, ContactImpulse impulse)
{
}
});
}
public void show() {
}
public void create() {
}
public void update(float fval) {
world.step(1 / 60f, 6, 2);
mapRenderer.setView(mainCamera);
}
public void openMenu(){
if(Gdx.input.isKeyJustPressed(Input.Keys.ESCAPE)){
game.setScreen(new MenuScreen(game));
this.dispose();
}
}
public void render(float delta) {
Gdx.gl.glClearColor(1, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
world.step(1 / 60f, 6, 2);
menuScreen.stage.dispose();
worldMap.render();
worldMap.mainCamera.update();
tank.render();
//tank.moveSprite();
tank.ControllerInput();
gegner1.render();
ziel.render();
tank.moveBody();
if(ziel!=null)
{
ziel.render();
}
if (tank.readytoshoot>0)
{
tank.readytoshoot-=1;
}
debugRenderer.render( world, worldMap.mainCamera.combined );
collision();
if (collision()) {
ziel = new Target(MathUtils.random(Gdx.graphics.getWidth()-48),
MathUtils.random(Gdx.graphics.getHeight()-48),world);
anzahlTotePanzer++;
System.out.println(anzahlTotePanzer);
}
if (treffer)
{
treffer=false;
ziel.delete();
ziel = new Target(MathUtils.random(Gdx.graphics.getWidth()-48),MathUtils.random(Gdx.graphics.getHeight()-48),world);
}
O2.render();
}
public boolean collision() {
boolean col = false;
Rectangle rectangle2 = ziel.bounds();
for(Flower f: tank.flowers) {
Rectangle rec1= f.getRec();
if(rec1.overlaps(rectangle2)){
col= true;
}else {
col= false;
}
}
return col;
}
this is the class which calls the same tank class but gives me a java.lang.UnsatisfiedLinkError: com.badlogic.gdx.physics.box2d.PolygonShape.newPolygonShape()
public class SurvivalMode2 extends WorldMap implements Screen {
public EnemyTank enemyTank;
public SEPGame game;
public WorldMap worldMap;
public Tank tank;
public int anzahlPanzer;
public int spawnPanzer;
public ArrayList<EnemyTank> tankListe;
public Obstacle O1,O2,O3,O4;
public Obstacle leftwall,upperwall,rightwall,lowerwall;
public Box2DDebugRenderer debugRenderer;
boolean treffer;
public SurvivalMode2(SEPGame game) {
enemyTank = new EnemyTank(world, this,null ,TankType.KI);
tank = new Tank(world,null,this,TankType.PLAYER_1);
this.game = game;
world = new World(new Vector2(0,0), false);
worldMap = new WorldMap();
debugRenderer = new Box2DDebugRenderer
( true, true, false, true, true, true );
world.setContactListener(new ContactListener()
{
#Override
public void beginContact(Contact contact)
{
}
#Override
public void endContact(Contact contact)
{
Fixture fixtureA = contact.getFixtureA();
Fixture fixtureB = contact.getFixtureB();
Body BodyA=contact.getFixtureA().getBody();
if(BodyA.equals(enemyTank.enemyBody))
{
treffer=true;
}
for (Flower flower : tank.flowers)
{
if(flower.FlowerBody.equals(contact.getFixtureB().getBody())
||flower.FlowerBody.equals(contact.getFixtureA().getBody()))
{
flower.todelete-=1;
}
}
}
#Override
public void preSolve(Contact contact, Manifold oldManifold)
{
}
#Override
public void postSolve(Contact contact, ContactImpulse impulse)
{
}
});
}
public void update(){
mapRenderer.setView(mainCamera);
}
#Override
public void show() {
}
#Override
public void render(float delta) {
Gdx.gl.glClearColor(1, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
worldMap.render();
worldMap.mainCamera.update();
enemyTank.render();
tank.render();
}
the error I am getting:
Caused by: java.lang.UnsatisfiedLinkError: com.badlogic.gdx.physics.box2d.PolygonShape.newPolygonShape()J
at com.badlogic.gdx.physics.box2d.PolygonShape.newPolygonShape(Native Method)
at com.badlogic.gdx.physics.box2d.PolygonShape.<init>(PolygonShape.java:29)
at de.paluno.game.gameobjects.EnemyTank.<init>(EnemyTank.java:51)
at de.paluno.game.screens.SurvivalMode2.<init>(SurvivalMode2.java:54)
at de.paluno.game.screens.MenuScreen.survivalMode(MenuScreen.java:63)
at de.paluno.game.screens.MenuScreen$2.changed(MenuScreen.java:97)
at com.badlogic.gdx.scenes.scene2d.utils.ChangeListener.handle(ChangeListener.java:28)
at com.badlogic.gdx.scenes.scene2d.Actor.notify(Actor.java:183)
at com.badlogic.gdx.scenes.scene2d.Actor.fire(Actor.java:148)
at com.badlogic.gdx.scenes.scene2d.ui.Button.setChecked(Button.java:131)
at com.badlogic.gdx.scenes.scene2d.ui.Button$1.clicked(Button.java:94)
at com.badlogic.gdx.scenes.scene2d.utils.ClickListener.touchUp(ClickListener.java:88)
at com.badlogic.gdx.scenes.scene2d.InputListener.handle(InputListener.java:59)
at com.badlogic.gdx.scenes.scene2d.Stage.touchUp(Stage.java:350)
at com.badlogic.gdx.backends.lwjgl.LwjglInput.processEvents(LwjglInput.java:342)
at com.badlogic.gdx.backends.lwjgl.LwjglApplication.mainLoop(LwjglApplication.java:217)
at com.badlogic.gdx.backends.lwjgl.LwjglApplication$1.run(LwjglApplication.java:126)
Here is my code from Enemytank its identical to tank except a few lines like moveBody method or:
package de.paluno.game.gameobjects;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.physics.box2d.*;
import de.paluno.game.SEPGame;
import de.paluno.game.screens.Playscreen;
import de.paluno.game.screens.SurvivalMode2;
import java.util.ArrayList;
public class EnemyTank extends Sprite {
public ArrayList<EnemyTank> enemyList;
public Sprite enemySprite;
public SpriteBatch enemyBatch;
public PolygonShape shape;
public Texture texture;
private int currentLife;
private int maxLife;
private int fullLifeWidth;
public TankType type;
float PosX,PosY;
public Body enemyBody;
public BodyDef bdef;
public FixtureDef fdef;
public float Radius;
public EnemyTank(World world, SurvivalMode2 survivalScreen, Playscreen screen, TankType tankType){
enemyBatch = new SpriteBatch();
texture = new Texture("tankBody_huge.png");
enemySprite = new Sprite(texture);
PosX= MathUtils.random(Gdx.graphics.getWidth()-48);
PosY= MathUtils.random(Gdx.graphics.getHeight()-48);
bdef = new BodyDef();
fdef = new FixtureDef();
// TankBody erstellen
BodyDef bodyDef = new BodyDef();
bodyDef.type = BodyDef.BodyType.DynamicBody;
bodyDef.position.set(PosX, PosY);
PolygonShape shape = new PolygonShape();
shape.setAsBox(enemySprite.getWidth()/2-1, enemySprite.getHeight()/2-1);
Radius=(float)Math.sqrt((double)(enemySprite.getWidth()*
enemySprite.getWidth()/4+enemySprite.getHeight()*enemySprite.getHeight()/4) );
FixtureDef fixDef = new FixtureDef();
fixDef.shape = shape;
fixDef.density = 1f;
fixDef.restitution = .1f;
fixDef.friction = .5f;
enemyBody = world.createBody(bodyDef);
enemyBody.createFixture(fixDef);
enemyBody.setLinearDamping(2f);
enemyBody.setAngularDamping(2f);
enemyBody.setUserData(42);
this.type = tankType;
maxLife = 100;
currentLife = maxLife;
fullLifeWidth = 300;
}
public float getX() {
return enemySprite.getX();
}
public float getY() {
return enemySprite.getY();
}
public void render() {
enemyBatch.begin();
float x=enemyBody.getPosition().x-enemySprite.getWidth()/2;
float y=enemyBody.getPosition().y-enemySprite.getHeight()/2;
enemySprite.setPosition(x, y);
enemySprite.setRotation((float)(enemyBody.getAngle()/Math.PI*180f));
enemySprite.draw(enemyBatch);
enemyBatch.end();
}
public void setupBody() {
}
public Body getBody() {
return null;
}
public void setBodyToNullReference() {
}
public void update(float fval) {
}
}
java.lang.UnsatisfiedLinkError: com.badlogic.gdx.physics.box2d.PolygonShape.newPolygonShape()J means Java tries to bind Java method marked native long newPolygonShape() to underlying non-java native method and cannot find it.
In other words there is mismatch between com.badlogic.gdx.physics.box2d Java library and corresponding native library.
I think there reason why it works for one class and does not work for other is you call different methods of PolygonShape and one method is found & binded and other is not.
I have been having a hell of a time trying to get this stage thing figured out. I basically want to draw a background image that fills the entire stage. The image is 1920x1080. The problem is that the image is being drawn at half the width and half of the height that it should be. The application is set to fullscreen and the inside corner of the image is at the center of the screen. I have tested the dimensions of the camera, the viewport, and the stage. All are correct. What am I doing wrong? By the way, I am using a custom game state manager to handle different screens so I apologize for the seemingly needless extra code.
Application.java
public class Application extends ApplicationAdapter {
public static boolean DEBUG = false;
public static final String TITLE = "Hexatan";
public static final int V_WIDTH = 720, V_HEIGHT = 480;
public static final float SCALE = 2.0f;
private GameStateManager gsm;
private OrthographicCamera camera;
private FitViewport vp;
private SpriteBatch batch;
private Stage stage;
private float w, h;
#Override
public void create() {
float w = Gdx.graphics.getWidth();
float h = Gdx.graphics.getHeight();
batch = new SpriteBatch();
camera = new OrthographicCamera();
camera.setToOrtho(true, w / SCALE, h / SCALE);
vp = new FitViewport(w, h, camera);
stage = new Stage(vp, batch);
gsm = new GameStateManager(this);
}
#Override
public void render() {
gsm.update(Gdx.graphics.getDeltaTime());
gsm.render();
}
#Override
public void pause() {
}
#Override
public void resume() {
}
#Override
public void dispose() {
gsm.dispose();
batch.dispose();
}
#Override
public void resize(int width, int height) {
gsm.resize((int)(width / SCALE), (int)(height / SCALE));
}
public SpriteBatch getBatch() {
return this.batch;
}
public OrthographicCamera getCamera(){
return this.camera;
}
public Stage getStage(){
return this.stage;
}
}
GameStateManager.java
public class GameStateManager {
private final Application app;
private Stack<GameState> states;
public enum State {
SPLASH, MAINMENU, GAME
}
public GameStateManager(final Application app){
this.app = app;
this.states = new Stack<GameState>();
this.setState(State.GAME);
}
public Application getApp(){
return app;
}
public void update(float delta){
states.peek().update(delta);
}
public void render(){
states.peek().render();
}
public void dispose(){
for(GameState gs : states){
gs.dispose();
}
states.clear();
}
public void resize(int w, int h){
states.peek().resize(w, h);
}
public void setState(State state){
if(states.size() >= 1) {
states.pop().dispose();
}
states.push(getState(state));
}
public GameState getState(State state){
return new GameLoop(this);
}
}
GameState.java
public abstract class GameState {
protected GameStateManager gsm;
protected Application app;
protected SpriteBatch batch;
protected OrthographicCamera camera;
public GameState(GameStateManager gsm){
this.gsm = gsm;
this.app = gsm.getApp();
batch = app.getBatch();
camera = app.getCamera();
}
public void resize(int w, int h){
camera.setToOrtho(true, w, h);
camera.update();
}
public abstract void update(float delta);
public abstract void render();
public abstract void dispose();
}
GameLoop.java
public class GameLoop extends GameState {
private boolean DEV_MODE = true;
private int WIDTH, HEIGHT;
private float mouseX, mouseY;
private Stage stage;
private Game game;
private Application app;
Texture hexture, water, island, robber, highlight, scoreboard;
BitmapFont font = new BitmapFont(Gdx.files.internal("core/assets/Playbill.fnt"));
BitmapFont devFont = new BitmapFont(Gdx.files.internal("core/assets/Arial.fnt"));
public GameLoop(GameStateManager gsm){
super(gsm);
app = gsm.getApp();
WIDTH = Gdx.graphics.getWidth();
HEIGHT = Gdx.graphics.getHeight();
stage = app.getStage();
System.out.println(stage.getCamera().position.x);
Gdx.input.setInputProcessor(stage);
water = new Texture(Gdx.files.internal("core/assets/img/water.png"));
island = new Texture(Gdx.files.internal("core/assets/img/island.png"));
highlight = new Texture(Gdx.files.internal("core/assets/img/highlightVertex.png"));
scoreboard = new Texture(Gdx.files.internal("core/assets/img/scoreboard.png"));
Image waterImg = new Image(new TextureRegionDrawable(new TextureRegion(water)));
waterImg.setWidth(WIDTH);
waterImg.setHeight(HEIGHT);
stage.addActor(waterImg);
}
#Override
public void render() {
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
app.getStage().act(Gdx.graphics.getDeltaTime());
app.getStage().draw();
}
#Override
public void update(float delta) {
}
#Override
public void dispose() {
}
#Override
public void resize(int w, int h){
camera.setToOrtho(true, w, h);
app.getStage().getViewport().update(w, h, true);
}
I want to draw a texture on a body, which is a box.
How do I convert the coordinates of the body to screen coordinates?
I know that the other way around is with camera.unproject(pos), is it similar to this?
I see a lot of people using constants such as WORLD_TO_SCREEN = 32, but I currently don't have that in my game. Is that a problem, and how can I implement it now? Because it seems like people that are using these factors can convert world to screen positions easily. I currently have a camera and an ExtendViewport
camera = new OrthographicCamera(VIEWPORT_WIDTH, VIEWPORT_HEIGHT);
viewport = new ExtendViewport(VIEWPORT_WIDTH, VIEWPORT_HEIGHT, camera);
camera.position.set(VIEWPORT_WIDTH/2, VIEWPORT_HEIGHT/2, 0f);
Viewport width and height are set to this
public static final int VIEWPORT_WIDTH = 20;
public static final int VIEWPORT_HEIGHT = 22;
I don't really know what I'm doing, I read documentation and read some tutorials, but if someone could give some explanation about these variables and the world_to_screen factor that would really help me out.
I also set APP_WIDTH=1280, APP_HEIGHT = 720
Do viewport width and height mean that for box2d my screen is 20 meters wide and 22 meters high?
(asking it again because I added a lot the question and I would really like to know these things)
[EDIT]
So I'm trying to draw a ground picture on the ground body
float x = stage.getGround().getX();
float y = stage.getGround().getY();
float w = stage.getGround().getWidth();
float h = stage.getGround().getHeight();
stage.act(delta);
stage.draw();
stage.updateCamera();
Texture texture = new Texture(Gdx.files.internal("ground.png"));
Sprite sprite = new Sprite(texture);
sprite.setSize(w, h);
sprite.setPosition(x-sprite.getWidth()/2, y-sprite.getHeight()/2);
But I don't see it anywhere
[EDIT 2]
Stage Class
public class Mission1Stage extends Stage{
public static final int VIEWPORT_WIDTH = 20;
public static final int VIEWPORT_HEIGHT = 22;
private World world;
private Ground ground;
private LeftWall leftWall;
private Rocket rocket;
private static final float TIME_STEP = 1 / 300f;
private float accumulator = 0f;
private OrthographicCamera camera;
private Box2DDebugRenderer renderer;
private Viewport viewport;
private SpriteBatch spriteBatch = new SpriteBatch();
private Vector3 touchPoint;
private ShapeRenderer shapeRenderer;
private Button boostButton;
private Skin boostSkin;
private Button boostLeftButton;
private Skin boostLeftSkin;
private Button boostRightButton;
private Skin boostRightSkin;
private Button resetButton;
private Skin resetSkin;
private Game game;
private boolean isTouched = false;
public Mission1Stage(Game game) {
setUpWorld();
renderer = new Box2DDebugRenderer();
shapeRenderer = new ShapeRenderer();
setupCamera();
setUpButtons();
addActor(new Background(ground));
}
private void setUpWorld() {
world = WorldUtils.createWorld();
setUpGround();
setUpRocket();
}
private void setUpGround() {
ground = new Ground(WorldUtils.createGround(world));
addActor(ground);
}
private void setUpLeftWall() {
leftWall = new LeftWall(WorldUtils.createLeftWall(world));
}
private void setUpRocket() {
rocket = new Rocket(WorldUtils.createRocket(world));
addActor(rocket);
}
private void setupCamera() {
camera = new OrthographicCamera(VIEWPORT_WIDTH, VIEWPORT_HEIGHT);
viewport = new ExtendViewport(VIEWPORT_WIDTH, VIEWPORT_HEIGHT, camera);
camera.position.set(VIEWPORT_WIDTH/2, VIEWPORT_HEIGHT/2, 0f);
camera.update();
}
private void setUpButtons() {
boostSkin = new Skin(Gdx.files.internal("skin/flat-earth-ui.json"));
boostButton = new Button(boostSkin);
boostButton.setSize(80,80);
boostButton.setPosition(Gdx.graphics.getWidth()-boostButton.getWidth()*2,0);
boostButton.setTransform(true);
boostButton.scaleBy(0.5f);
Gdx.input.setInputProcessor(this);
addActor(boostButton);
boostLeftSkin = new Skin(Gdx.files.internal("skin/flat-earth-ui.json"));
boostLeftButton = new Button(boostLeftSkin);
boostLeftButton.setSize(100, 100);
boostLeftButton.setPosition(0, 0);
addActor(boostLeftButton);
boostRightSkin = new Skin(Gdx.files.internal("skin/flat-earth-ui.json"));
boostRightButton = new Button(boostRightSkin);
boostRightButton.setSize(100, 100);
boostRightButton.setPosition(boostLeftButton.getWidth(), 0);
addActor(boostRightButton);
resetSkin = new Skin(Gdx.files.internal("skin/flat-earth-ui.json"));
resetButton = new Button(resetSkin);
resetButton.setSize(100, 100);
resetButton.setPosition(Gdx.graphics.getWidth()-100, Gdx.graphics.getHeight()-100);
addActor(resetButton);
}
#Override
public void act(float delta) {
super.act(delta);
handleInput();
accumulator += delta;
while(accumulator >= delta) {
world.step(TIME_STEP, 6, 2);
accumulator -= TIME_STEP;
}
}
#Override
public void draw() {
super.draw();
renderer.render(world, camera.combined);
float x = getGround().getBody().getPosition().x;
float y = getGround().getBody().getPosition().y;
float w = getGround().getWidth() * 2;
float h = getGround().getHeight() * 2;
spriteBatch.setProjectionMatrix(getCamera().combined);
Texture texture = new Texture(Gdx.files.internal("ground.png"));
Sprite sprite = new Sprite(texture);
sprite.setSize(w, h);
sprite.setPosition(x-sprite.getWidth()/2, y-sprite.getHeight()/2);
spriteBatch.begin();
sprite.draw(spriteBatch);
spriteBatch.end();
}
public void handleInput() {
if(boostButton.isPressed()) {
rocket.boost();
}
if(boostLeftButton.isPressed()) {
rocket.turnLeft();
}
if(boostRightButton.isPressed()) {
rocket.turnRight();
}
if(resetButton.isPressed()) {
}
}
public boolean resetScreen() {
if(resetButton.isPressed()) return true;
return false;
}
public void updateCamera() {
}
public Ground getGround() {
return ground;
}
public void resize(int width, int height) {
viewport.update(width, height);
camera.position.x = VIEWPORT_WIDTH / 2;
camera.position.y = VIEWPORT_HEIGHT /2;
}
private void translateScreenToWorldCoordinates(int x, int y) {
getCamera().unproject(touchPoint.set(x, y, 0));getCamera();
}
}
Screen class
public class Mission1Screen implements Screen{
private Game game;
private Mission1Stage stage;
private SpriteBatch spriteBatch = new SpriteBatch();
private Skin boostSkin;
private Button boostButton;
public Mission1Screen(Game game) {
this.game = game;
stage = new Mission1Stage(game);
}
#Override
public void show() {
}
#Override
public void render(float delta) {
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
if(stage.resetScreen()) {
game.setScreen(new Mission1Screen(game));
}
stage.act(delta);
stage.draw();
stage.updateCamera();
}
#Override
public void resize(int width, int height) {
stage.resize(width, height);
}
#Override
public void pause() {
}
#Override
public void resume() {
}
#Override
public void hide() {
}
#Override
public void dispose() {
}
}
[EDIT 3]
public class Main extends Game {
#Override
public void create () {
this.setScreen(new Mission1Screen(this));
}
#Override
public void render () {
super.render();
}
#Override
public void dispose () {
}
}
We mostly use Pixel to meter conversion because box2d best works in meters (0-10) but you can avoid this conversion by using small worldwidth and height of your viewport. I mostly prefer 48 and 80 as viewport width and height.
You can use unproject(vector3) method of camera that translate a point given in screen coordinates to world space. I am using this method in touchdown because I get screen coordinate as parameter then I need to convert it into camera world space so that I can generate object at a particular position in world.
public class MyGdxTest extends Game implements InputProcessor {
private SpriteBatch batch;
private ExtendViewport extendViewport;
private OrthographicCamera cam;
private float w=20;
private float h=22;
private World world;
private Box2DDebugRenderer debugRenderer;
private Array<Body> array;
private Vector3 vector3;
#Override
public void create() {
cam=new OrthographicCamera();
extendViewport=new ExtendViewport(w,h,cam);
batch =new SpriteBatch();
Gdx.input.setInputProcessor(this);
world=new World(new Vector2(0,-9.8f),true);
array=new Array<Body>();
debugRenderer=new Box2DDebugRenderer();
vector3=new Vector3();
BodyDef bodyDef=new BodyDef();
bodyDef.type= BodyDef.BodyType.StaticBody;
bodyDef.position.set(0,0);
Body body=world.createBody(bodyDef);
ChainShape chainShape=new ChainShape();
chainShape.createChain(new float[]{1,1,55,1});
FixtureDef fixtureDef=new FixtureDef();
fixtureDef.shape=chainShape;
fixtureDef.restitution=.5f;
body.createFixture(fixtureDef);
chainShape.dispose();
}
#Override
public void render() {
super.render();
Gdx.gl.glClearColor(0,1,1,1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
world.step(1/60f,6,2);
batch.setProjectionMatrix(cam.combined);
batch.begin();
world.getBodies(array);
for (Body body:array){
if(body.getUserData()!=null) {
Sprite sprite = (Sprite) body.getUserData();
sprite.setPosition(body.getPosition().x-sprite.getWidth()/2, body.getPosition().y-sprite.getHeight()/2);
sprite.setRotation(body.getAngle()*MathUtils.radDeg);
sprite.draw(batch);
}
}
batch.end();
debugRenderer.render(world,cam.combined);
}
#Override
public void resize(int width, int height) {
super.resize(width,height);
extendViewport.update(width,height);
cam.position.x = w /2;
cam.position.y = h/2;
cam.update();
}
private void createPhysicsObject(float x,float y){
float sizeX=2,sizeY=2;
BodyDef bodyDef=new BodyDef();
bodyDef.position.set(x,y);
bodyDef.type= BodyDef.BodyType.DynamicBody;
Body body=world.createBody(bodyDef);
PolygonShape polygonShape=new PolygonShape();
polygonShape.setAsBox(sizeX,sizeY);
FixtureDef fixtureDef=new FixtureDef();
fixtureDef.shape=polygonShape;
fixtureDef.restitution=.2f;
fixtureDef.density=2;
body.createFixture(fixtureDef);
body.setFixedRotation(false);
polygonShape.dispose();
Sprite sprite=new Sprite(new Texture("badlogic.jpg"));
sprite.setSize(2*sizeX,2*sizeY);
sprite.setPosition(x-sprite.getWidth()/2,y-sprite.getHeight()/2);
sprite.setOrigin(sizeX,sizeY);
body.setUserData(sprite);
}
#Override
public void dispose() {
batch.dispose();
debugRenderer.dispose();
world.dispose();
}
#Override
public boolean keyDown(int keycode) {
return false;
}
#Override
public boolean keyUp(int keycode) {
return false;
}
#Override
public boolean keyTyped(char character) {
return false;
}
#Override
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
vector3.set(screenX,screenY,0);
Vector3 position=cam.unproject(vector3);
createPhysicsObject(vector3.x,vector3.y);
return false;
}
#Override
public boolean touchUp(int screenX, int screenY, int pointer, int button) {
return false;
}
#Override
public boolean touchDragged(int screenX, int screenY, int pointer) {
return false;
}
#Override
public boolean mouseMoved(int screenX, int screenY) {
return false;
}
#Override
public boolean scrolled(int amount) {
return false;
}
}
I'm loading a .tmx map using Libgdx and the map is not filling the whole screen. I cannot figure out the problem so as a last resort I'm asking a question here.I'm following a tutorial on YouTube and he did not cover this problem and as a result I cannot continue. I have tried multiple things with no sucess. The map is width: 240 tiles, height: 13 tiles, and tiles are 16 by 16
,
.
This is the code. I think the problem has to do with
renderer = new OrthogonalTiledMapRenderer(map, 1/DBZ.PPM),
gameCam.position.set(gamePort.getWorldWidth()/2,
gamePort.getWorldHeight()/2, 0);,
gameCam = new OrthographicCamera();
gamePort = new FitViewport(DBZ.V_WIDTH/DBZ.PPM, DBZ.V_HEIGHT/DBZ.PPM, gameCam);
public class PlayScreen implements Screen {
private DBZ game;
private OrthographicCamera gameCam;
private Viewport gamePort;
private Hud hud;
private TmxMapLoader maploader;
private TiledMap map;
private OrthogonalTiledMapRenderer renderer;
private World world;
private Box2DDebugRenderer b2dr;
private Goku player;
private TextureAtlas atlas;
public PlayScreen(DBZ game){
atlas = new TextureAtlas("goku.pack");
this.game= game;
gameCam = new OrthographicCamera();
gamePort = new FitViewport(DBZ.V_WIDTH/DBZ.PPM, DBZ.V_HEIGHT/DBZ.PPM, gameCam);
hud = new Hud(game.batch);
maploader= new TmxMapLoader();
map = maploader.load("level1.tmx");
renderer = new OrthogonalTiledMapRenderer(map, 1/DBZ.PPM);
gameCam.position.set(gamePort.getWorldWidth()/2, gamePort.getWorldHeight()/2, 0);
world = new World(new Vector2(0,-10),true);
b2dr = new Box2DDebugRenderer();
new B2WorldCreator(world,map);
player = new Goku(world, this);
}
public TextureAtlas getAtlas(){
return atlas;
}
#Override
public void show() {
}
public void handleInput(float dt){
if (Gdx.input.isKeyJustPressed(Input.Keys.UP))
player.b2body.applyLinearImpulse(new Vector2(0, 4f), player.b2body.getWorldCenter(), true);
if (Gdx.input.isKeyPressed(Input.Keys.RIGHT) && player.b2body.getLinearVelocity().x <= 2)
player.b2body.applyLinearImpulse(new Vector2(0.1f, 0), player.b2body.getWorldCenter(), true);
if (Gdx.input.isKeyPressed(Input.Keys.LEFT) && player.b2body.getLinearVelocity().x >= -2)
player.b2body.applyLinearImpulse(new Vector2(-0.1f, 0), player.b2body.getWorldCenter(), true);
}
public void update(float dt){
handleInput(dt);
world.step(1/60f, 6, 2);
player.update(dt);
gameCam.position.x = player.b2body.getPosition().x;
gameCam.update();
renderer.setView(gameCam);
}
#Override
public void render(float delta) {
update(delta);
Gdx.gl.glClearColor(0, 0, 0, 0);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
renderer.render();
b2dr.render(world, gameCam.combined);
game.batch.setProjectionMatrix(gameCam.combined);
game.batch.begin();
player.draw(game.batch);
game.batch.end();
game.batch.setProjectionMatrix(hud.stage.getCamera().combined);
hud.stage.draw();
}
#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() {
map.dispose();
renderer.dispose();
world.dispose();
b2dr.dispose();
hud.dispose();
}
}
public class DBZ extends Game{
public SpriteBatch batch;
public static final int V_WIDTH = 400;
public static final int V_HEIGHT = 208;
public static final float PPM = 100;
#Override
public void create () {
batch = new SpriteBatch();
setScreen(new PlayScreen(this));
}
#Override
public void render () {
super.render();
}
#Override
public void dispose () {
batch.dispose();
}
}
public class Goku extends Sprite {
public World world;
public Body b2body;
private TextureRegion gokuStand;
public Goku(World world, PlayScreen screen){
super(screen.getAtlas().findRegion("goku_sprite"));
this.world = world;
defineGoku();
gokuStand = new TextureRegion(getTexture(), 5,12,59,85);
setBounds(0,0,59/DBZ.PPM,85/DBZ.PPM);
setRegion(gokuStand);
}
public void defineGoku(){
BodyDef bdef = new BodyDef();
bdef.position.set(32/DBZ.PPM,32/DBZ.PPM);
bdef.type = BodyDef.BodyType.DynamicBody;
b2body = world.createBody(bdef);
FixtureDef fdef = new FixtureDef();
PolygonShape shape = new PolygonShape();
shape.setAsBox(59/2/DBZ.PPM, 85/2/DBZ.PPM);
fdef.shape = shape;
b2body.createFixture(fdef);
}
public void update(float dt){
setPosition(b2body.getPosition().x - getWidth()/2, b2body.getPosition().y - getHeight()/2 );
}
}
Problem is in placement of camera, attach camera with player so that viewport of camera cover whole screen. I am trying to fix this.
public float gokuStartingPositionX;
public PlayScreen(DBZ game){
.....
new B2WorldCreator(world,map);
gokuStartingPositionX=64/DBZ.PPM; //added in your method
player = new Goku(world, this);
}
public void update(float dt){
handleInput(dt);
world.step(1/60f, 6, 2);
player.update(dt);
//camera position is decided by player position and keep camera in this way so it cover whole viewport width with screen
gameCam.position.x = player.b2body.getPosition().x + gamePort.getWorldWidth()/2 - gokuStartingPositionX;
gameCam.update();
renderer.setView(gameCam);
}
Small modification in Goku
public Goku(World world, PlayScreen screen){
super(screen.getAtlas().findRegion("goku_sprite"));
this.world = world;
defineGoku(screen.gokuStartingPositionX);
gokuStand = new TextureRegion(getTexture(), 5,12,59,85);
setBounds(0,0,59/DBZ.PPM,85/DBZ.PPM);
setRegion(gokuStand);
}
public void defineGoku(float startX){
BodyDef bdef = new BodyDef();
bdef.position.set(startX,32/DBZ.PPM);
bdef.type = BodyDef.BodyType.DynamicBody;
b2body = world.createBody(bdef);
...
}
I believe what you are looking for is the ability to clamp the camera to the map.
This can be achieved using MathUtils.clamp.
gameCam.position.x = MathUtils.clamp(gameCam.position.x, viewportWidth/2 , 38 - viewportWidth/2);
gameCam.position.y = MathUtils.clamp(gameCam.position.y, viewportHeight/2, 208 - viewportHeight/2);
EDIT: Your updated PlayScreen:
package com.edwin.game.Screens;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
import com.badlogic.gdx.maps.tiled.TiledMap;
import com.badlogic.gdx.maps.tiled.TmxMapLoader;
import com.badlogic.gdx.maps.tiled.renderers.OrthogonalTiledMapRenderer;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.Box2DDebugRenderer;
import com.badlogic.gdx.physics.box2d.World;
import com.badlogic.gdx.utils.viewport.FitViewport;
import com.badlogic.gdx.utils.viewport.Viewport;
import com.edwin.game.DBZ;
import com.edwin.game.Scenes.Hud;
import com.edwin.game.Sprites.Goku;
import com.edwin.game.Tools.B2WorldCreator;
/**
* Created by Edwin on 3/20/2017.
*/
public class PlayScreen implements Screen {
private DBZ game;
private OrthographicCamera gameCam;
private Viewport gamePort;
private Hud hud;
private TmxMapLoader maploader;
private TiledMap map;
private OrthogonalTiledMapRenderer renderer;
private World world;
private Box2DDebugRenderer b2dr;
private Goku player;
private TextureAtlas atlas;
private float viewportWidth;
private float viewportHeight;
public PlayScreen(DBZ game){
atlas = new TextureAtlas("goku.pack");
this.game= game;
gameCam = new OrthographicCamera();
gamePort = new FitViewport(DBZ.V_WIDTH/DBZ.PPM, DBZ.V_HEIGHT/DBZ.PPM, gameCam);
hud = new Hud(game.batch);
maploader= new TmxMapLoader();
map = maploader.load("level1.tmx");
renderer = new OrthogonalTiledMapRenderer(map, 1/DBZ.PPM);
viewportWidth = gamePort.getWorldWidth();
viewportHeight= gamePort.getWorldHeight();
world = new World(new Vector2(0,-10),true);
b2dr = new Box2DDebugRenderer();
new B2WorldCreator(world,map);
player = new Goku(world, this);
}
public TextureAtlas getAtlas(){
return atlas;
}
#Override
public void show() {
}
public void handleInput(float dt){
if (Gdx.input.isKeyJustPressed(Input.Keys.UP))
player.b2body.applyLinearImpulse(new Vector2(0, 4f), player.b2body.getWorldCenter(), true);
if (Gdx.input.isKeyPressed(Input.Keys.RIGHT) && player.b2body.getLinearVelocity().x <= 2)
player.b2body.applyLinearImpulse(new Vector2(0.5f, 0), player.b2body.getWorldCenter(), true);
if (Gdx.input.isKeyPressed(Input.Keys.LEFT) && player.b2body.getLinearVelocity().x >= -2)
player.b2body.applyLinearImpulse(new Vector2(-0.1f, 0), player.b2body.getWorldCenter(), true);
}
public void update(float dt){
handleInput(dt);
world.step(1/60f, 6, 2);
player.update(dt);
gameCam.position.x = player.b2body.getPosition().x;
// cam pos / var to clamp / min val / max val
gameCam.position.x = MathUtils.clamp(gameCam.position.x, viewportWidth/2 , 38 - viewportWidth/2);
gameCam.position.y = MathUtils.clamp(gameCam.position.y, viewportHeight/2, 208 - viewportHeight/2);
System.out.println(gameCam.position.x);
gameCam.update();
renderer.setView(gameCam);
}
#Override
public void render(float delta) {
update(delta);
Gdx.gl.glClearColor(0, 0, 0, 0);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
renderer.render();
//
//
b2dr.render(world, gameCam.combined);
game.batch.setProjectionMatrix(gameCam.combined);
game.batch.begin();
player.draw(game.batch);
game.batch.end();
game.batch.setProjectionMatrix(hud.stage.getCamera().combined);
hud.stage.draw();
}
#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() {
map.dispose();
renderer.dispose();
world.dispose();
b2dr.dispose();
hud.dispose();
}
}
So I have tried several different ways to put the sprite on to my coin bodies but to no avail. I initially just tried putting a texture on it, but that didn't work. Then I tried using the texture packer and atlas to see if that would help. Here is my code:
public class Coin extends Item {
public Coin(PlayScreen screen, float x, float y) {
super(screen, x, y);
setRegion(screen.getAtlas().findRegion("Coin"), 0, 0, 15, 16);
}
#Override
public void defineItem() {
BodyDef bdef = new BodyDef();
bdef.position.set(getX(), getY());
bdef.type = BodyDef.BodyType.DynamicBody;
body = world.createBody(bdef);
FixtureDef fdef = new FixtureDef();
CircleShape shape = new CircleShape();
shape.setRadius(10/Racing.PPM);
fdef.shape = shape;
Filter filter = new Filter();
filter.categoryBits = Racing.COIN_BIT;
Fixture fixture = body.createFixture(fdef);
fixture.setFilterData(filter);
fixture.setUserData(this);
}
public void update(float dt){
super.update(dt);
setPosition(body.getPosition().x - getWidth() / 2, body.getPosition().y - getHeight() / 2);
}
}
And it extends this class:
public abstract class Item extends Sprite{
protected PlayScreen screen;
protected World world;
protected Vector2 velocity;
protected boolean toDestroy;
protected boolean destroyed;
protected Body body;
public Item(PlayScreen screen, float x, float y){
this.screen = screen;
this.world = screen.getWorld();
toDestroy = false;
destroyed = false;
setPosition(x, y);
setBounds(getX(), getY(), 16 / Racing.PPM, 16 / Racing.PPM);
defineItem();
}
public abstract void defineItem();
public abstract void collect(Kart kart);
public void update(float dt){
if(toDestroy && !destroyed){
world.destroyBody(body);
destroyed = true;
}
}
public void draw(Batch batch){
if(!destroyed){
super.draw(batch);
}
}
public void destroy(){
toDestroy = true;
}
}
Any help would be greatly appreciated! Thanks!