libGDX creating a minimap of a tiledmap - libgdx

I am developing a top-down 2D game with a TiledMap.
Currently i want to create a minimap of my TiledMap, but i´m really confused how to do this.
I´ve read something that i should create another camera, zoom out and render the map again, but how should i draw the zoomed out map in the upper right corner?
Am i overthinking this whole thing?
My Map:
public class LiquidMap {
private TiledMap map;
private OrthogonalTiledMapRenderer renderer;
private OrthographicCamera camera = new OrthographicCamera();
private MiniMap miniMap;
public LiquidMap(String filePath) {
map = new TmxMapLoader().load(filePath);
renderer = new OrthogonalTiledMapRenderer(map, 1 / 32f);
camera.setToOrtho(false, 30, 20);
miniMap = new MiniMap(map);
}
public void update(float x, float y){
camera.position.x = x;
camera.position.y = y;
camera.update();
//renderer.setView(camera.combined, x - 10, y - 10, 20, 20);
renderer.setView(camera);
miniMap.update(x, y);
}
public void update(HostPlayer player){
this.update(player.position.x + (player.skin.getWidth()/2f)/32f, player.position.y + (player.skin.getHeight()/2f)/32f);
}
public void render(HostPlayer player){
renderer.render();
renderer.getBatch().begin();
renderer.getBatch().draw(player.skin, player.position.x, player.position.y, 1/32f * player.skin.getWidth(), 1/32f * player.skin.getHeight());
renderer.getBatch().end();
miniMap.render();
}
And my MiniMap:
public class MiniMap {
private OrthogonalTiledMapRenderer renderer;
private OrthographicCamera camera = new OrthographicCamera();
public MiniMap(TiledMap map) {
renderer = new OrthogonalTiledMapRenderer(map, 1 / 32f);
camera.setToOrtho(false, 30, 20);
camera.zoom = 10;
}
public void update(){
}
public void update(float x, float y){
//Pixventure.instance.gameScreen.getCamera()
camera.position.x = x;
camera.position.y = y;
camera.update();
renderer.setView(camera.combined, x-15, y-15, 30, 30);
//renderer.setView(camera);
}
public void render(){
renderer.render();
}
}
The whole situation is looking like this:

Minimap's camera position is updated by player position. Place your minimap at the corner and don't change his position by your update() method.

Related

libgdx isometric tiled map screen to world with viewport

I wanted to create a simple 30x30 isometric tiled map and add a listener to be able to click on the tiles. I looked up a lot of the articles and posts here but none of them helped me.
My issue is, i have a viewport, 30x17, a camera, a stage and a tiled map with tileWidth = 32 and tileHeight = 16 pixels.
Now when i render the tiled map it looks fine.
When i click on stage and try to get the world coordinates i see some really weird coordinates.
This is the code:
private static final float TILE_WIDTH = 32;
private static final float TILE_HEIGHT = 16;
private OrthographicCamera camera;
private Viewport viewport;
private Stage stage;
private IsometricTiledMapRenderer isometricTiledMapRenderer;
private Matrix4 isoTransform;
private Matrix4 invIsotransform;
public void load(AssetManagerLoaderV2 assetManagerLoader) {
assetManagerLoader.load();
init();
camera = new OrthographicCamera();
viewport = new FitViewport(30, 17, camera);
stage = new Stage(viewport);
TiledMap tiledMap = new TiledMapGenerator(assetManagerLoader).generate(30, 30);
isometricTiledMapRenderer = new IsometricTiledMapRenderer(tiledMap, 1/32f);
stage.addListener(new InputListener() {
#Override
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
System.out.println(screenToCell(x, y));
return true;
}
});
}
#Override
public void show() {
Gdx.input.setInputProcessor(stage);
}
#Override
public void render(float delta) {
DrawUtils.clearScreen();
viewport.apply();
isometricTiledMapRenderer.setView(camera);
isometricTiledMapRenderer.render();
}
#Override
public void resize(int width, int height) {
stage.getViewport().update(width, height, true);
}
#Override
public void pause() {
}
#Override
public void resume() {
}
#Override
public void hide() {
}
#Override
public void dispose() {
isometricTiledMapRenderer.dispose();
stage.dispose();
}
public void init () {
//create the isometric transform
isoTransform = new Matrix4();
isoTransform.idt();
isoTransform.translate(0.0f, 0.25f, 0.0f);
isoTransform.scale((float)(Math.sqrt(2.0) / 2.0), (float)(Math.sqrt(2.0) / 4.0), 1.0f);
isoTransform.rotate(0.0f, 0.0f, 1.0f, -45.0f);
//... and the inverse matrix
invIsotransform = new Matrix4(isoTransform);
invIsotransform.inv();
}
public Vector2 worldToCell(float x, float y) {
float halfTileWidth = TILE_WIDTH * 0.5f;
float halfTileHeight = TILE_HEIGHT * 0.5f;
float row = (1.0f/2) * (x/halfTileWidth + y/halfTileHeight);
float col = (1.0f/2) * (x/halfTileWidth - y/halfTileHeight);
return new Vector2((int)col,(int)row);
}
public Vector2 screenToWorld(float x, float y){
Vector3 touch = new Vector3(x,y,0);
camera.unproject(touch);
touch.mul(invIsotransform);
touch.mul(isoTransform);
return new Vector2(touch.x,touch.y);
}
public Vector2 screenToCell(float x, float y) {
Vector2 world = screenToWorld(x,y);
world.y -= TILE_HEIGHT *0.5f;
return worldToCell(world.x,world.y);
}
Does anyone have an idea how to write worldToCell to get the proper coordinates?
I found the issue, i was missing one step.
This is what touchDown should look like:
#Override
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
Vector2 newCoords = stage.stageToScreenCoordinates(new Vector2(x, y));
System.out.println(screenToCell(newCoords.x, newCoords.y));
return true;
}
I need to convert stage coordinates to screen coordinates, now this code is working.

RayHandler doesn't goes with Box2D world

I have a difficult situation.
I'm making a 2D game and I'm on the step
of integrating box2Dlights part.
But when i'm rendering my RayHandler, I have a black screen.
Here is another image, where I don't render my lights. There is no lights now.
I need to have collision of Box2D and Box2Dlights mixed together.
Please note:
All my boxes are made in units, equal to 1, so that one room is 16 squares length.
All entire world is zoomed by setToOrtho((16 - 1.875f) / Gdx.graphics.getHeight()), where 16 is tile size.
If I scaled my tile size, I would like to have this stuff work.
All code is complicated so I send the only GameScreen and GameMap classes for now:
#Override
public void show() {
InstanceVars inst = InstanceVars.getInstance();
inst.world = new World(new Vector2(0, 0f), true);
inst.engine = new Engine();
inst.handler = new RayHandler(inst.world);
LevelCreator creator = new LevelCreator("level_def.cfg");
try {
gameWorld = creator.createNewLevel();
gameWorld.start();
} catch (FileCorruptedException e) {
e.printStackTrace();
}
}
#Override
public void render(float delta) {
gameWorld.render();
}
#Override
public void resize(int width, int height) {
gameWorld.resize(width, height);
}
#Override
public void dispose() {
gameWorld.dispose();
InstanceVars.getInstance().dispose();
}
for the GameScreen.java
and
private World physWorld = InstanceVars.getInstance().world;
private Box2DDebugRenderer physRender = new Box2DDebugRenderer();
private OrthographicCamera cam = new OrthographicCamera();
private RayHandler lights = new RayHandler(physWorld);
private PlayerController controls;
private float STD_ZOOM = ((float) CELL_SIZE + 16) / Gdx.graphics.getHeight();
private Body playerBody;
public GameMap() {
cam.zoom = STD_ZOOM;
}
public void start() {
GameObject player = (GameObject) getProperties().get("ent_player");
playerBody = player.getComponent(PhysicsComponent.class).getBody();
controls = new PlayerController();
Gdx.input.setInputProcessor(controls);
physWorld.setContactListener(new CollisionInteractor(InstanceVars.getInstance().engine));
PointLight light = new PointLight(lights, 1000, Color.GOLDENROD, 500, playerBody.getPosition().x, playerBody.getPosition().y);
}
public void render() {
updatePlayer();
physWorld.step(1/60f, 8, 2);
updateCamera();
physRender.render(physWorld, cam.combined);
// lights.updateAndRender();
}
private void updatePlayer() {
if (controls.up) playerBody.setLinearVelocity(playerBody.getLinearVelocity().x, -controls.speed);
else playerBody.setLinearVelocity(playerBody.getLinearVelocity().x, controls.down ? controls.speed : 0);
if (controls.down) playerBody.setLinearVelocity(playerBody.getLinearVelocity().x, controls.speed);
else playerBody.setLinearVelocity(playerBody.getLinearVelocity().x, controls.up ? -controls.speed : 0);
if (controls.left) playerBody.setLinearVelocity(-controls.speed, playerBody.getLinearVelocity().y);
else playerBody.setLinearVelocity(controls.right ? controls.speed : 0, playerBody.getLinearVelocity().y);
if (controls.right) playerBody.setLinearVelocity(controls.speed, playerBody.getLinearVelocity().y);
else playerBody.setLinearVelocity(controls.left ? -controls.speed : 0, playerBody.getLinearVelocity().y);
}
public void resize(float width, float height) {
STD_ZOOM = ((float) CELL_SIZE - 1.875f) / Gdx.graphics.getHeight();
cam.setToOrtho(true, width, height);
}
private void updateCamera() {
cam.position.set(playerBody.getPosition(), 0);
cam.update();
}
public void dispose() {
super.dispose();
physWorld.dispose();
physRender.dispose();
}
for GameMap.java.
If you need more details, don't be afraid to ask.
I cannot solve the problem on my own.

Box2dlights textures isn't drawn

I am using box2dlights in my project and there seem to be an issue. When I actually use RayHandler in the program, only the light is drawn but no textures. And so when I remove RayHandler from the render loop it all works fine. I want the light to be drawn and then textures to be drawn above it. How do I reach that?
This is the code:
public class GameScreen implements Screen {
private Core core;
private SpriteBatch batch;
private Sprite spiderSprite;
private OrthographicCamera camera;
private RayHandler rayHandler;
private Box2DDebugRenderer debugRenderer;
private World world;
private Body spider, prop;
private PointLight spiderLight;
private Stage stage;
private boolean paused, lost, check;
private int pointsCount;
private float time;
public GameScreen(Core c) {
core = c;
stage = new Stage();
batch = new SpriteBatch();
camera = new OrthographicCamera();
camera.setToOrtho(false, core.SCREEN_WIDTH, core.SCREEN_HEIGHT);
batch.setProjectionMatrix(camera.combined);
debugRenderer = new Box2DDebugRenderer();
spiderSprite = core.chars.createSprite("spider");
world = new World(new Vector2(.0f, -10.0f), true);
BodyDef spiderDef = new BodyDef();
spiderDef.type = BodyDef.BodyType.DynamicBody;
spiderDef.position.set(core.SCREEN_WIDTH / 2, core.SCREEN_HEIGHT / 2);
spider = world.createBody(spiderDef);
CircleShape shape = new CircleShape();
shape.setRadius(core.SCREEN_WIDTH / 15);
spider.createFixture(shape, .1f);
BodyDef propDef = new BodyDef();
propDef.type = BodyDef.BodyType.StaticBody;
propDef.position.set(core.SCREEN_WIDTH / 2, core.SCREEN_HEIGHT);
prop = world.createBody(propDef);
CircleShape propShape = new CircleShape();
propShape.setRadius(0.1f);
prop.createFixture(propShape, 1.0f);
RopeJointDef rope = new RopeJointDef();
rope.bodyA = spider;
rope.bodyB = prop;
rope.maxLength = core.SCREEN_HEIGHT / 2;
world.createJoint(rope);
rayHandler = new RayHandler(world);
rayHandler.setAmbientLight(.5f);
spiderLight = new PointLight(rayHandler, 100, Color.WHITE, core.SCREEN_WIDTH, 100, 100);
spiderLight.attachToBody(spider);
}
#Override
public void show() {
Gdx.input.setInputProcessor(stage);
stage.addAction(Actions.fadeIn(0.85f));
}
#Override
public void render(float delta) {
clearScreen();
batch.setProjectionMatrix(camera.combined);
batch.begin();
if (!lost && !paused) {
updateWorld();
updateSpider();
}
drawSpider();
stage.act();
stage.draw();
batch.end();
}
private void clearScreen() {
Gdx.gl.glClearColor(0, 0, 0, 0);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
}
private void updateSpider() {
//spider.setLinearVelocity(Gdx.input.getAccelerometerX() > 0 ? 50.0f : -50.0f, 0.0f);
float angle = MathUtils.radiansToDegrees * MathUtils.atan2(core.SCREEN_HEIGHT - spider.getPosition().y, core.SCREEN_WIDTH / 2 - spider.getPosition().x) - 90;
spiderSprite.setPosition(spider.getPosition().x, spider.getPosition().y);
spiderSprite.setRotation(angle);
}
private void drawSpider() {
spiderSprite.draw(batch);
rayHandler.render();
}
private void updateWorld() {
world.step(1/60f, 6, 2);
rayHandler.setCombinedMatrix(camera);
rayHandler.update();
time += Gdx.graphics.getDeltaTime();
}
}
I also removed a redundant part of the code which is not connected with the issue.
Stage has it's own batch with it's own .begin() and .end(). You should call batch.end(); before calling stage.draw();
I found it out. RayHandler.render() must not be invoked between batch.begin() and batch.end().

Unable to see Box2DdebugRenderer's body outlines

I am using box2ddebugrenderer temporarily as of now to render the bodies into the world but I am not able the see the mono-color outlines of bodies being created in the world upon running.
This is the code of my game's Screen:
public class GameScreen implements Screen {
static final int VIEWPORT_WIDTH = 20;
static final int VIEWPORT_HEIGHT = 13;
World world;
Body ground;
final float TIME_STEP = 1 / 300f;
float accumulator = 0f;
OrthographicCamera camera;
private Box2DDebugRenderer renderer;
#Override
public void render(float delta) {
//Clear the screen
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
renderer.render(world, camera.combined);
accumulator += delta;
while (accumulator >= delta) {
world.step(TIME_STEP, 6, 2);
accumulator -= TIME_STEP;
}
}
#Override
public void show() {
world = createWorld();
ground = createGround(world);
renderer = new Box2DDebugRenderer();
camera = new OrthographicCamera(VIEWPORT_WIDTH, VIEWPORT_HEIGHT);
camera.position.set(camera.viewportWidth / 2, camera.viewportHeight / 2, 0f);
camera.update();
}
public World createWorld() {
return new World(Constants.WORLD_GRAVITY, true);
}
public Body createGround(World world) {
BodyDef bodyDef = new BodyDef();
bodyDef.position.set(new Vector2(Constants.GROUND_X, Constants.GROUND_Y));
Body body = world.createBody(bodyDef);
PolygonShape shape = new PolygonShape();
shape.setAsBox(Constants.GROUND_WIDTH / 2, Constants.GROUND_HEIGHT / 2);
body.createFixture(shape, Constants.GROUND_DENSITY);
shape.dispose();
return body;
}
}
Need to define BodyType of physics body in BodyDef
BodyDef bodyDef=new BodyDef();
bodyDef.BodyType= BodyType.STATIC;
value of different constant should be appropriate so that body lie within the camera viewport like you have
Constants.GROUND_X,
Constants.GROUND_Y,
Constants.GROUND_WIDTH,
Constants.GROUND_HEIGHT
create small body and check, body outline is visible or not.
After this, still if you got nothing on screen draw simple Sprite using SpriteBatch.
One more condition
May be you are overriding render method of Game in your Child Game class and not calling parent render method.

libGDX 1.4.1 button listener on a secondary screen

I have two screens, a MainActivity in my core folder, that has the render() method split into a few switch cases. On game-over, this part of the switch case gets triggered, which calls the render part of my game-over class:
case STOPPED:
// Exit and clean the game
gameOverScreen.render(Gdx.graphics.getDeltaTime());
break;
...
This is my GameOverScreen class:
public class GameOverScreen implements Screen {
private SpriteBatch gameOverBatch;
private FreeTypeFontGenerator gameOverFontGen;
private FreeTypeFontGenerator.FreeTypeFontParameter gameOverLogoParam;
private FreeTypeFontGenerator.FreeTypeFontParameter gameOverButtonParam;
private final MainActivity mainActivity;
private OrthographicCamera camera;
private BitmapFont bitmapLogoFont;
private BitmapFont bitmapButtonFont;
private Button exitGameButton;
private Button gameRestartButton;
private Sound buttonSound;
private Stage stage;
private float w;
private float h;
// Constructor
public GameOverScreen(MainActivity mainActivity) {
w = Gdx.graphics.getWidth();
h = Gdx.graphics.getHeight();
gameOverBatch = new SpriteBatch();
this.mainActivity = mainActivity;
camera = new OrthographicCamera();
camera.setToOrtho(false, 300, 300);
// Instantiate the font for this screen from file
gameOverFontGen = new FreeTypeFontGenerator(Gdx.files.internal("fonts/SF_Wonder_Comic.ttf"));
gameOverLogoParam = new FreeTypeFontGenerator.FreeTypeFontParameter();
gameOverLogoParam.size = 110;
gameOverButtonParam = new FreeTypeFontGenerator.FreeTypeFontParameter();
gameOverButtonParam.size = 40;
// Font for the logo
bitmapLogoFont = new BitmapFont();
bitmapLogoFont = gameOverFontGen.generateFont(gameOverLogoParam);
// Font for the buttons
bitmapButtonFont = new BitmapFont();
bitmapButtonFont = gameOverFontGen.generateFont(gameOverButtonParam);
// Instantiate the buttonSound
buttonSound = Gdx.audio.newSound(Gdx.files.internal("sounds/pauseBtn_sound.ogg"));
/*************************************** Create a Stage *******************************************/
stage = new Stage();
// Add some actors as the buttons
exitGameButton = new Button(new TextureRegionDrawable(
new TextureRegion(new Texture(Gdx.files.internal("images/off_red.png")))),
new TextureRegionDrawable(new TextureRegion(new Texture(Gdx.files.internal("images/off_white.png")))));
//exitGameButton.setX((w, 150));
//pauseButton.setY(flipCoordinates(h, 150));
exitGameButton.setOrigin(exitGameButton.getWidth() / 2, exitGameButton.getHeight() / 2);
exitGameButton.setBounds(w / 2 + 100, h / 2 - 60, exitGameButton.getWidth(), exitGameButton.getHeight());
exitGameButton.act(Gdx.graphics.getDeltaTime());
stage.addActor(exitGameButton);
exitGameButton.addListener(new ChangeListener() {
#Override
public void changed (ChangeEvent event, Actor actor) {
buttonSound.play();
}
});
// Add some actors as the buttons
TextButton.TextButtonStyle restartStyle = new TextButton.TextButtonStyle();
restartStyle.font = bitmapButtonFont;
restartStyle.up = new TextureRegionDrawable(new TextureRegion(new Texture(Gdx.files.internal("images/back_red.png"))));
restartStyle.down = new TextureRegionDrawable(new TextureRegion(new Texture(Gdx.files.internal("images/back_white.png"))));
gameRestartButton = new Button(new TextButton.TextButtonStyle(restartStyle));
gameRestartButton.setOrigin(gameRestartButton.getWidth() / 2, gameRestartButton.getHeight() / 2);
gameRestartButton.setBounds(w / 2 - 100, h / 2 - 60, gameRestartButton.getWidth(), gameRestartButton.getHeight());
gameRestartButton.act(Gdx.graphics.getDeltaTime());
stage.addActor(gameRestartButton);
// Capture the event listener for the return button
gameRestartButton.addListener(new ChangeListener() {
#Override
public void changed(ChangeEvent event, Actor actor) {
// Do something on restart
//MainActivity.state = MainActivity.State.RUN;
Gdx.app.log("GameRestartButton", " has been pressed");
}
});
gameRestartButton.act(Gdx.graphics.getDeltaTime());
//stage.addActor(exitGameButton);
//stage.addActor(gameRestartButton);
}
#Override
public void render(float delta) {
Gdx.gl.glClearColor(0, 0, 0, 0);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
camera.update();
gameOverBatch.begin();
bitmapLogoFont.setColor(Color.RED);
bitmapLogoFont.draw(gameOverBatch, "Game Over", w / 2 - 210, h / 2 + 150f);
gameOverBatch.end();
exitGameButton.act(Gdx.graphics.getDeltaTime());
stage.act(Gdx.graphics.getDeltaTime());
stage.draw();
}
#Override
public void resize(int width, int height) {
}
#Override
public void show() {
}
#Override
public void hide() {
}
#Override
public void pause() {
}
#Override
public void resume() {
}
#Override
public void dispose() {
gameOverFontGen.dispose();
}
}
In GameOverScreen constructor I have two buttons (exitGameButton and gameReturnButton) I'd like to be able to trigger their event-listeners, but I can't seem to be able to do it. Neither of my buttons responds to the event listener. What am I doing wrong? Do I need to add something else on to my MainActivity class for these buttons to work ? Thanks much.
I figured it out, on the second screen I was missing from the constructor this: Gdx.input.setInputProcessor(stage); , of course, that only works if a stage has been previously created.
try this in your class GameOverScreen
.//
public Stage getStageGameOverScreen(){
return this.stage;
}
your Case:
case STOPPED:
// Exit and clean the game
Gdx.input.setInputProcessor(gameOverScreen.getStageGameOverScreen());
gameOverScreen.render(Gdx.graphics.getDeltaTime());
break;
...