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.
Related
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.
Hi guys so i was trying to make this simple game in libgdx and everything was fine until i noticed that i need to apply a big force just to make the player move a little is there any way to make it need less force?
This is my PlayScreen where I render the player.
`
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();
gamecam.update();
Box2D.init();
//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.GHEIGHT, gamecam);
p = new Player(new Sprite(new Texture("hud_p3.png")), 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
}
#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(),Logang.GHEIGHT / 2, 0); // x and y could be changed by Keyboard input for example
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("hud_p3.png");
tmp.setWrap(Texture.TextureWrap.MirroredRepeat, Texture.TextureWrap.MirroredRepeat);
for (int i = 0; i < 50; i++) {
EntityManager.add(new Ground(new Sprite(tmp), world, (int)(i * Logang.TILE), 1, 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
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 void update(float dt){
if(Gdx.input.isKeyPressed(Input.Keys.LEFT)){
getBody().applyLinearImpulse(new Vector2(-Logang.PPM,0f), getBody().getWorldCenter(), true);
}
if(Gdx.input.isKeyPressed(Input.Keys.RIGHT)){
getBody().applyLinearImpulse(new Vector2(Logang.PPM,0f), getBody().getWorldCenter(), true);
}
if(Gdx.input.isKeyPressed(Input.Keys.SPACE)){
getBody().applyLinearImpulse(0f,-Logang.GRAVITY * Logang.PPM, getBody().getPosition().x, getBody().getPosition().y, true);
}
}
}
public void define(int tipo){
BodyDef bdef = new BodyDef();
bdef.position.set((getSprite().getX() + getSprite().getWidth() / 2), (getSprite().getY() + getSprite().getHeight() / 2));
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() / 2, getSprite().getHeight() / 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;
float posY = getBody().getPosition().y;
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;
}
}
Thank everybody for any answer
Box2D is a physics engine so tries to imitate real life physics in game. So if your object is large and heavy it will require a large amount of force to move it.
To make it so your objects can move with less force you can either make them smaller or change the density of them to make them lighter which will allow them to be moved with less force.
To change the density you set it in the fixtureDefinition
FixtureDef fdef = new FixtureDef();
fdef.density=0.1f; // (weight: range 0.01 to 1 is good)
fdef.friction = 0.7f; // (how slippery it is: 0=like ice 1 = like rubber)
fdef.restitution = 0.3f; //(how bouncy is it 0= not bouncy 1 = 100% bouncy)
Another thing I noticed is you are using what seems to be a PixelPerMeter ratio for your forces in this line:
getBody().applyLinearImpulse(new Vector2(-Logang.PPM,0f), getBody().getWorldCenter(), true);
You shouldn't use this value for your forces as this is for converting box2d world to render coordinates and you can use the following code to apply the force to the center.
getBody().applyLinearImpulse(new Vector2((10f*getBody().getMass()),0f), getBody().getWorldCenter(), true);
As a side note the impulse is used to create a single application of force whereas body.applyForceToCenter(force,wake); is used to apply a constant force over time. Try with the apply force method and see if this helps.
So I am just trying to make my game character, which is a texture (ball), to jump up in the air and then return back down to the position that it started at when the screen is pressed. I was just wondering if someone could give me a code example or help me to do this with my current code which is below. I have basically just drawn the background and the ball texture and positioned the ball where I want it to start the jump. The ball texture is what I want to make jump straight up.
public class MyGdxGame extends ApplicationAdapter {
SpriteBatch batch;
Texture background;
Texture ball;
#Override
public void create () {
batch = new SpriteBatch();
background = new Texture("gamebackground.png");
ball = new Texture("ball2.png");
ball.setFilter(Texture.TextureFilter.Nearest, Texture.TextureFilter.Nearest);
}
#Override
public void render () {
batch.begin();
float scaleFactor = 2.0f;
batch.draw(background, 0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
batch.draw(ball, 80, 145, ball.getWidth() * scaleFactor, ball.getHeight() * scaleFactor);
batch.end();
}
#Override
public void dispose () {}
}
There are a million ways to do this.
Here's a simple (and not very flexible way). Create a Ball class that has variables for x and y position, velocity, and acceleration. Then give it an update method for applying the acceleration and velocity to the position:
public class Ball {
public static final float GRAVITY = -100; // size depends on your world scale
public static final float BOUNCE_DAMPENING = 0.6f;
public final Vector2 position = new Vector2();
public final Vector2 velocity = new Vector2();
public final Vector2 acceleration = new Vector2(0, GRAVITY);
public void update (){
float dt = Gdx.graphics.getDeltaTime();
velocity.add(acceleration.x * dt, acceleration.y * dt));
position.add(velocity.x * dt, velocity.y * dt);
if (position.y <= 0){ // hit ground, so bounce
position.y = -position.y * BOUNCE_DAMPENING;
velocity.y = -velocity.y * BOUNCE_DAMPENING;
}
}
}
This is a very rudimentary way of handling physics. It would be more sophisticated to use Box2D, but the above is fine if you're just learning.
Now, you need to create a ball instance and use it to track your ball position. Use the Ball object's position when drawing it. And you can react to taps to apply a velocity.
public class MyGdxGame extends ApplicationAdapter {
SpriteBatch batch;
Texture background;
Texture ballTexture;
Ball ball;
#Override
public void create () {
batch = new SpriteBatch();
background = new Texture("gamebackground.png");
ballTexture = new Texture("ball2.png");
ballTexture.setFilter(Texture.TextureFilter.Nearest, Texture.TextureFilter.Nearest);
ball = new Ball();
}
#Override
public void render () {
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); // don't forget to clear screen
if (Gdx.input.justTouched())
ball.velocity.y += 100;
ball.update();
batch.begin();
float scaleFactor = 2.0f;
batch.draw(background, 0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
batch.draw(ballTexture, ball.position.x, ball.position.y, ballTexture.getWidth() * scaleFactor, ballTexture.getHeight() * scaleFactor);
batch.end();
}
#Override
public void dispose () {
batch.dispose();
background.dispose();
ballTexture.dispose();
}
}
You also need to read up on pixel units vs. world units and how to solve the scale problem with Viewports. See https://xoppa.github.io/blog/pixels/ and https://github.com/libgdx/libgdx/wiki/Viewports
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
UPDATE
I have a hint. That is because the center of the screen in JBox2D is (0, 0). This is so weird because x and y are not from -1 to 1, it depends of the screen size.
This means the Util class I copied from the internet (everybody shared this code) is not up to date. I still need help because I can't find any 'algorithm' to have aspect ratio + screen size dependency.
BASE QUESTION
Since I have added the "slick2D to jbox2D position" and vice versa (it's like position in screen = position in screen / 100 for JBox), I don't get a good result. Screenshots below
I'm explaining with code:
public class Util {
private static final float SCALE = 0.01f; // 1/100 pixels
public static float toPosX(float posX) { return (posX * SCALE); }
public static float toPosY(float posY) { return (-posY * SCALE); }
public static float toScreenX(float posX) { return (posX / SCALE); }
public static float toScreenY(float posY) { return (-posY / SCALE); }
}
Square.java :
public class Square {
private Body body;
private Rectangle rectangle;
Square(World world, BodyType type, Vec2 pos, Vec2 size) {
float x = Util.toPosX(pos.x);
float y = Util.toPosY(pos.y);
float sx = Util.toPosX(size.x);
float sy = Util.toPosY(size.y);
//body definition
BodyDef bd = new BodyDef();
bd.position.set(x, y);
bd.type = type;
//define shape of the body.
PolygonShape cs = new PolygonShape();
cs.setAsBox(sx, sy);
//define fixture of the body.
FixtureDef fd = new FixtureDef();
fd.shape = cs;
fd.density = 1f;
fd.friction = 0.3f;
fd.restitution = 1.0f;
//create the body and add fixture to it
body = world.createBody(bd);
body.createFixture(fd);
rectangle = new Rectangle(0, 0, size.x, size.y);
rectangle.setLocation(pos.x, pos.y);
}
public Body getBody() { return this.body; }
public Rectangle getRectangle() { return this.rectangle; }
}
And finally my display class:
public class DisplayManager extends BasicGame {
private GameManager gameManager;
private Body b1, b2;
private Rectangle r1, r2;
private World world;
public DisplayManager(GameManager game) {
super("Title");
this.gameManager = game;
}
#Override
public void init(GameContainer container) throws SlickException {
this.gameManager.initPlayersSprites();
world = new World(new Vec2(0, -10));
Square s1, s2;
s1 = new Square(world, BodyType.STATIC, new Vec2(10, 800), new Vec2(1900, 30));
b1 = s1.getBody();
r1 = s1.getRectangle();
s2 = new Square(world, BodyType.DYNAMIC, new Vec2(945, 200), new Vec2(30, 30));
b2 = s2.getBody();
r2 = s2.getRectangle();
}
public void render(GameContainer container, Graphics g) throws SlickException {
float step = 1.0f / 600.0f;
world.step(step, 6, 2);
r1.setLocation(Util.toScreenX(b1.getPosition().x), Util.toScreenY(b1.getPosition().y));
r2.setLocation(Util.toScreenX(b2.getPosition().x), Util.toScreenY(b2.getPosition().y));
g.draw(r1);
g.draw(r2);
}
}
Here is the result :
first frame :
http://i.stack.imgur.com/WgQPK.png
some frames later :
http://i.stack.imgur.com/a1XyL.png
(the ground didn't move, it's just another screenshot took from my hand)
In other words, the cube falls down like for ever. I debugged the position of the cube and it doesn't stop to go down.
With Slick2D DebugDraw it doesn't help because the cube goes through the ground anyway.
Please note that in JBox2D, it worked with pixels measurements (that was not accurate at all but collisions worked well)
That was because of the negative size. (toPoxY reverse the y pos)