I'm making a game in libgdx where the main character has a light on him and where the light doesn't reach it should be dark, I'm using the setBlendFunction from SpriteBash to emulate the light. My problem is I don't know how I can make all around the light texture dark, I could size the light texture to fit the whole screen but that would be sloppy and an inconveniente in code. Does anyone have any ideas? Thanks you.
Here is a picture of the game showing my problem
Why dont't you use Box2dlight for your requirement. In my opinion you can use shader for lighting but the effect that you want that can only be achieved by using box2d body and box2dlight.
public class MyGdxGame extends ApplicationAdapter implements InputProcessor{
SpriteBatch batch;
OrthographicCamera cam;
RayHandler rayHandler;
World world;
Texture texture;
PointLight box2d;
Box2DDebugRenderer renderer;
Vector3 vector3;
Array<Body> bodies;
#Override
public void create() {
Pixmap pixmap=new Pixmap(1, 1, Pixmap.Format.RGBA8888);
pixmap.setColor(Color.WHITE);
pixmap.fillRectangle(0,0, pixmap.getWidth(), pixmap.getHeight());
world=new World(new Vector2(0,-9.8f),false);
rayHandler=new RayHandler(world);
renderer=new Box2DDebugRenderer();
bodies=new Array<>();
vector3=new Vector3();
batch=new SpriteBatch();
cam = new OrthographicCamera();
cam.setToOrtho(true,40,64);
texture=new Texture(pixmap);
rayHandler.setAmbientLight(0,0,0,.5f);
box2d=new PointLight(rayHandler, 100, new Color(1,1,1,1), 25, 10, 10);
Gdx.input.setInputProcessor(this);
{
BodyDef bodyDef = new BodyDef();
bodyDef.position.set(20, 10);
bodyDef.type = BodyDef.BodyType.StaticBody;
PolygonShape p = new PolygonShape();
p.setAsBox(8, 1.5f);
FixtureDef fixtureDef = new FixtureDef();
fixtureDef.shape = p;
Body body = world.createBody(bodyDef);
body.createFixture(fixtureDef);
Sprite sprite=new Sprite(texture);
sprite.setSize(8*2,1.5f*2);
body.setUserData(sprite);
}
{
BodyDef bodyDef = new BodyDef();
bodyDef.position.set(20, 40);
bodyDef.type = BodyDef.BodyType.StaticBody;
PolygonShape p = new PolygonShape();
p.setAsBox(8, 1.5f);
FixtureDef fixtureDef = new FixtureDef();
fixtureDef.shape = p;
Body body = world.createBody(bodyDef);
body.createFixture(fixtureDef);
Sprite sprite=new Sprite(texture);
sprite.setSize(8*2,1.5f*2);
body.setUserData(sprite);
}
}
#Override
public void render() {
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
Gdx.gl.glClearColor(1,1,1,1);
world.step(1/60f,4,6);
renderer.render(world,cam.combined);
batch.setProjectionMatrix(cam.combined);
batch.begin();
world.getBodies(bodies);
for (Body body:bodies){
Sprite sprite=(Sprite) body.getUserData();
sprite.setPosition(body.getPosition().x-sprite.getWidth()/2,body.getPosition().y-sprite.getHeight()/2);
sprite.draw(batch);
}
batch.draw(texture,100,100);
batch.end();
rayHandler.setCombinedMatrix(cam);
rayHandler.updateAndRender();
}
#Override
public void resize(int width, int height) {
}
#Override
public void dispose() {
batch.dispose();
rayHandler.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) {
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) {
vector3.set(screenX,screenY,0);
Vector3 v=cam.unproject(vector3);
box2d.setPosition(v.x,v.y);
return false;
}
#Override
public boolean mouseMoved(int screenX, int screenY) {
return false;
}
#Override
public boolean scrolled(int amount) {
return false;
}
}
OUTPUT IS :
This is typically done with a FrameBuffer.
You want to instantiate and recreate as necessary in the resize() method so it always matches the size of the screen/window. In resize():
if (frameBuffer != null && (frameBuffer.getWidth() != width || frameBuffer.getHeight() != height)){
frameBuffer.dispose();
frameBuffer = null;
}
if (frameBuffer == null){
try {
frameBuffer = new FrameBuffer(Pixmap.Format.RGBA8888, width, height, false);
} catch (GdxRuntimeException e){ // device doesn't support 8888
frameBuffer = new FrameBuffer(Pixmap.Format.RGB565, width, height, false);
}
}
And in render(), before drawing anything in your game, you first draw the shadow map on the frameBuffer:
frameBuffer.begin();
Gdx.gl.glClearColor(/* ... */); // This will be your ambient color, a dark color, like gray
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
spriteBatch.setProjectionMatrix(camera.combined); // same camera as your game scene
spriteBatch.setBlendFunction(GL20.GL_ONE, GL20.GL_ONE); //additive blending
spriteBatch.begin();
// draw light sprites, such as a white circle where your character is standing
spriteBatch.end();
frameBuffer.end();
Then draw your game scene normally. Don't forget to change your blend function back to what you normally use (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA by default) before drawing that. And finally, draw the shadow map over the game:
// Use identity matrix so you don't have to worry about lining up the frame buffer texture
spriteBatch.setProjectionMatrix(spriteBatch.getProjectionMatrix().idt());
// Set multiplicative blending for shadows
spriteBatch.setBlendFunction(GL20.GL_ZERO, GL20.GL_SRC_COLOR);
spriteBatch.begin();
spriteBatch.draw(frameBuffer.getColorBufferTexture(), -1, 1, 2, -2); //dimensions for full screen with identity matrix
spriteBatch.end();
Related
Im trying to do a little game in LibGdx, right now i have a spaceship that can move with a touchpad in every directions and the camera follows it.
Im tryng to accomplish a parallax background made of stars that moves depending of where the spaceship is going.
Here it is the code, Im giving you all the class just to be sure to not mess up, for im new with this programming code.
public class TouchPadTest extends OrthographicCamera implements ApplicationListener {
public static final int WIDTH=480;
public static final int HEIGHT=800;
private OrthographicCamera camera;
private Stage stage;
private SpriteBatch batch;
private Touchpad touchpad;
private TouchpadStyle touchpadStyle;
private Skin touchpadSkin;
private Drawable touchBackground;
private Drawable touchKnob;
private Texture blockTexture;
private Sprite blockSprite;
private float blockSpeed;
public void create() {
batch = new SpriteBatch();
//Create camera
float aspectRatio = (float) Gdx.graphics.getWidth() / (float) Gdx.graphics.getHeight();
camera = new OrthographicCamera();
camera.setToOrtho(false, TouchPadTest.WIDTH, TouchPadTest.HEIGHT);
//Create a touchpad skin
touchpadSkin = new Skin();
//Set background image
touchpadSkin.add("touchBackground", new Texture("data/touchBackground.png"));
//Set knob image
touchpadSkin.add("touchKnob", new Texture("data/touchKnob.png"));
//Create TouchPad Style
touchpadStyle = new TouchpadStyle();
//Create Drawable's from TouchPad skin
touchBackground = touchpadSkin.getDrawable("touchBackground");
touchKnob = touchpadSkin.getDrawable("touchKnob");
//Apply the Drawables to the TouchPad Style
touchpadStyle.background = touchBackground;
touchpadStyle.knob = touchKnob;
//Create new TouchPad with the created style
touchpad = new Touchpad(10, touchpadStyle);
//setBounds(x,y,width,height)
touchpad.setBounds(15, 15, 200, 200);
//Create a Stage and add TouchPad
stage = new Stage(new FitViewport(Gdx.graphics.getWidth(),Gdx.graphics.getHeight()));
stage.addActor(touchpad);
Gdx.input.setInputProcessor(stage);
//Create block sprite
blockTexture = new Texture(Gdx.files.internal("data/shuttle2.png"));
blockSprite = new Sprite(blockTexture);
//Set position to centre of the screen
blockSprite.setPosition(Gdx.graphics.getWidth()/2-blockSprite.getWidth()/2, Gdx.graphics.getHeight()/2-blockSprite.getHeight()/2);
blockSpeed=5;
}
public void movePlayer(){
Vector2 v = new Vector2(touchpad.getKnobPercentX(), touchpad.getKnobPercentY());
float angle = v.angle();
if (touchpad.isTouched()){
blockSprite.setRotation(angle);
}
blockSprite.setX(blockSprite.getX() + touchpad.getKnobPercentX()*blockSpeed);
blockSprite.setY(blockSprite.getY() + touchpad.getKnobPercentY()*blockSpeed);
//Draw
camera.position.set(blockSprite.getX() + blockSprite.getWidth() / 2, blockSprite.getY() + blockSprite.getHeight() / 2, 0);
camera.update();
batch.setProjectionMatrix(camera.combined);
}
public void renderBackground() {
//---------------PARALLAX BACKGROUND---------------------//
}
public void dispose() {
}
public void render() {
Gdx.gl.glClearColor(0/255f,5/255f,15/255f,1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
//Move blockSprite with TouchPad
movePlayer();
batch.begin();
renderBackground();
blockSprite.draw(batch);
batch.end();
stage.act(Gdx.graphics.getDeltaTime());
stage.draw();
}
#Override
public void pause() {
}
#Override
public void resume() {
}
#Override
public void resize(int width, int height) {
}
}
For a better exemple, this is the kind of result that i want to achieve: https://www.youtube.com/watch?v=zA91SaOR-Io, if you can help me it will be amazing. Thank You.
This working example of a 3 layer parallax background was adapted from the LibGdx Parallax test and should give you an idea on how to implement a parallax effect. The three images used are all 1024x1024px.
import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.InputProcessor;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.Matrix4;
import com.badlogic.gdx.math.Vector3;
public class Test extends ApplicationAdapter implements InputProcessor{
private SpriteBatch batch;
private ParallaxCamera camera;
private Texture bgClose;
private Texture bgMid;
private Texture bgFar;
final Vector3 curr = new Vector3();
final Vector3 last = new Vector3(-1, -1, -1);
final Vector3 delta = new Vector3();
#Override
public void create () {
bgClose = new Texture(Gdx.files.internal("starbg-close.png"));
bgMid = new Texture(Gdx.files.internal("starbg-mid.png"));
bgFar = new Texture(Gdx.files.internal("starbg-far.png"));
camera = new ParallaxCamera(1920,1080);
batch = new SpriteBatch();
Gdx.input.setInputProcessor(this);
}
#Override
public void render () {
//clear screen
Gdx.gl.glClearColor(0f, 0f, 0f, 1f);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
// background layer, no parallax, centered around origin
batch.setProjectionMatrix(camera.calculateParallaxMatrix(0, 0));
batch.disableBlending();
batch.begin();
batch.draw(bgFar, -(int)(bgFar.getWidth() / 2), -(int)(bgFar.getHeight() / 2));
batch.end();
batch.enableBlending();
batch.setProjectionMatrix(camera.calculateParallaxMatrix(0.25f, 0.25f));
batch.begin();
for (int i = 0; i < 9; i++) {
batch.draw(bgMid, i * bgClose.getWidth() - 512, -512);
}
batch.end();
batch.setProjectionMatrix(camera.calculateParallaxMatrix(.5f, .5f));
batch.begin();
for (int i = 0; i < 9; i++) {
batch.draw(bgClose, i * bgClose.getWidth() - 512, -512);
}
batch.end();
}
//.. omitted empty methods ..//
#Override
public boolean touchUp(int screenX, int screenY, int pointer, int button) {
last.set(-1, -1, -1);
return false;
}
#Override
public boolean touchDragged(int x, int y, int pointer) {
camera.unproject(curr.set(x, y, 0));
if (!(last.x == -1 && last.y == -1 && last.z == -1)) {
camera.unproject(delta.set(last.x, last.y, 0));
delta.sub(curr);
camera.position.add(delta.x, delta.y, 0);
}
last.set(x, y, 0);
return false;
}
private class ParallaxCamera extends OrthographicCamera {
Matrix4 parallaxView = new Matrix4();
Matrix4 parallaxCombined = new Matrix4();
Vector3 tmp = new Vector3();
Vector3 tmp2 = new Vector3();
public ParallaxCamera (float viewportWidth, float viewportHeight) {
super(viewportWidth, viewportHeight);
}
public Matrix4 calculateParallaxMatrix (float parallaxX, float parallaxY) {
update();
tmp.set(position);
tmp.x *= parallaxX;
tmp.y *= parallaxY;
parallaxView.setToLookAt(tmp, tmp2.set(tmp).add(direction), up);
parallaxCombined.set(projection);
Matrix4.mul(parallaxCombined.val, parallaxView.val);
return parallaxCombined;
}
}
}
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;
}
}
In my game, I have my objects represented as a actors, thus all of the game objects would be on a Stage. For some reason when I try to move the Stage's camera around, it won't work, or actually it doesn't seem to work. I have added a game Actor to the location of 0,0. When I translate the camera's position around, the Actor still stays at the bottom left corner, despite when I log the camera's position, it shows that the camera has moved.
public class Striker extends Actor {
private Sprite img;
private World worldRef;
private Body body;
//constructor
public Striker(float size, float x, float y, World world) {
img = new Sprite(new Texture(Gdx.files.internal("Striker.png")));
//mains the aspect size ratio
img.setSize((275f / 300f) * size, size);
img.setPosition(x, y);
worldRef = world;
//set up the physics
BodyDef bodyDef = new BodyDef();
bodyDef.type = BodyDef.BodyType.DynamicBody;
bodyDef.position.set(x,y);
body = world.createBody(bodyDef);
}
#Override
public void draw(Batch batch, float parentAlpha) {
img.draw(batch);
}
#Override
public void act(float delta) {
super.act(delta);
}
#Override
public float getX() {
return body.getPosition().x;
}
#Override
public float getY() {
return body.getPosition().y;
}
#Override
public float getWidth() {
return img.getWidth();
}
#Override
public float getHeight() {
return img.getHeight();
}
}
The results of the 2 logs show that the camera's positions have moved, but it doesn't look like it.
public class StrikerScreen implements Screen {
public static float WIDTH = 1920;
public static float HEIGHT = 1080;
public static float PPM = 200;
private Launcher launcherRef;
private OrthographicCamera camera;
private FitViewport viewport;
private World world;
private Box2DDebugRenderer debugRenderer;
private Striker striker;
private Stage gameStage;
//constructor
public StrikerScreen(Launcher launcher) {
launcherRef = launcher;
world = new World(new Vector2(0, -9.8f), true);
debugRenderer = new Box2DDebugRenderer();
gameStage = new Stage();
camera = (OrthographicCamera) gameStage.getCamera();
viewport = new FitViewport(WIDTH / PPM, HEIGHT / PPM, gameStage.getCamera());
viewport.apply();
gameStage.setViewport(viewport);
striker = new Striker(160f / PPM, 0, 0, world);
gameStage.addActor(striker);
gameStage.getCamera().translate(viewport.getWorldWidth() / 2f, 500f, 0);
viewport.apply();
camera.update();
Gdx.app.log("StrikerScreen.java", "Camera position: " + gameStage.getCamera().position.toString());
Gdx.app.log("StrikerScreen.java", "Camera size: " + gameStage.getCamera().viewportWidth + ", " + gameStage.getCamera().viewportHeight);
}
#Override
public void show() {
}
public void update(float delta) {
world.step(1 / 30f, 6, 2);
gameStage.act(delta);
}
#Override
public void render(float delta) {
update(delta);
debugRenderer.render(world, camera.combined);
gameStage.draw();
}
#Override
public void resize(int width, int height) {
viewport.update(width, height, true);
}
#Override
public void pause() {
}
#Override
public void resume() {
}
#Override
public void hide() {
}
#Override
public void dispose() {
}
}
In the code you posted, the only times you move the camera are in the StrikerScreen constructor where you explicitly translate it, and in the resize method, where you have called viewport.update(width, height, true); Passing true to viewport.update tells it to move the camera to where (0, 0) is in the bottom left of corner of the viewport. Since resize is automatically called when you set your screen to this screen, that is the most recent position you have set the camera to.
How can the coords returned from GestureListener (TouchDown method for example) be converted into world-unit coords.
EG. My device screen is 1080p, my game is set up to use 540x960 (portrait).
In my current example project (code below) the paddle moves along x-axis twice as quickly as my finger, hence the position being set is given in screen-pixels.
Of course in this exact example, I could easily just divide it by 2 as I know the gameworld-units are exactly half of the device-pixels, however what if I wanted to make my world size 150x150 units --or if I was testing on a device with different screen sizes??
package com.moneylife.breakingass;
import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.input.GestureDetector;
import com.badlogic.gdx.math.Vector2;
public class BreakingAss extends ApplicationAdapter {
SpriteBatch batch;
Sprite bgSprite, bgCoverSprite, menu1Sprite;
Paddle paddle;
enum ScreenState { StartScreen, PlayScreen, GameOverScreen }
ScreenState currentScreenState;
public int DeviceScreenWidth, DeviceScreenHeight;
public int WorldWidth = 540, WorldHeight = 960;
public OrthographicCamera camera;
int zAxis = 0;
MyGestureDetector myGestureDetector;
#Override
public void create () {
currentScreenState = ScreenState.StartScreen;
batch = new SpriteBatch();
DeviceScreenWidth = Gdx.graphics.getWidth();
DeviceScreenHeight = Gdx.graphics.getHeight();
myGestureDetector = new MyGestureDetector();
bgSprite = new Sprite(new Texture("bentoverass.jpg"));
bgCoverSprite = new Sprite(new Texture("half1080coverup.png"));
menu1Sprite = new Sprite(new Texture("menu1.jpg"));
menu1Sprite.setSize(WorldHeight * DeviceScreenWidth / DeviceScreenHeight,WorldHeight);
menu1Sprite.setPosition(0,0);
camera = new OrthographicCamera(WorldWidth, WorldHeight);
camera.position.set(camera.viewportWidth / 2, camera.viewportHeight / 2, zAxis);
camera.update();
paddle = new Paddle(WorldWidth, WorldHeight);
Gdx.input.setInputProcessor(new GestureDetector(myGestureDetector));
}
#Override
public void render () {
Gdx.gl.glClearColor(1, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
paddle.update();
camera.update();
batch.setProjectionMatrix(camera.combined);
batch.begin();
if (currentScreenState == ScreenState.StartScreen){
menu1Sprite.draw(batch);
}
if (currentScreenState == ScreenState.PlayScreen){
paddle.draw(batch);
}
batch.end();
}
#Override
public void dispose () {
batch.dispose();
}
public class MyGestureDetector implements GestureDetector.GestureListener {
#Override
public boolean touchDown(float x, float y, int pointer, int button) {
if (currentScreenState == ScreenState.StartScreen) {
if (x > 0) {
currentScreenState = ScreenState.PlayScreen;
}
}
if (currentScreenState == ScreenState.PlayScreen){
paddle.position = new Vector2(x - paddle.texture.getWidth() / 2, paddle.fixedYPosition);
}
return false;
}
#Override
public boolean tap(float x, float y, int count, int button) {
return false;
}
#Override
public boolean longPress(float x, float y) {
return false;
}
#Override
public boolean fling(float velocityX, float velocityY, int button) {
return false;
}
#Override
public boolean pan(float x, float y, float deltaX, float deltaY) {
if (currentScreenState == ScreenState.PlayScreen){
paddle.position = new Vector2(x - paddle.texture.getWidth() / 2, paddle.fixedYPosition);
}
return false;
}
#Override
public boolean panStop(float x, float y, int pointer, int button) {
return false;
}
#Override
public boolean zoom(float initialDistance, float distance) {
return false;
}
#Override
public boolean pinch(Vector2 initialPointer1, Vector2 initialPointer2, Vector2 pointer1, Vector2 pointer2) {
return false;
}
#Override
public void pinchStop() {
}
}
}
Getting input coordinates always yields the coordinates of the screen. Logically because the input does not (need to) know about your game world. The camera is responsible for what is being drawn to the screen and the camera can be used to transform your screen coordinates to the coordinates of your world.
//Get screen coordinates
Vector3 mousePosition = new Vector3(Gdx.input.getX, Gdx.input.getY, 0);
//Transform to world coordinates using the correct camera
camera.unproject(mousePosition);
//The mousePosition vector is changed in the above method and now contains the game world coordinates of the camera you used.
PS.
For your paddle you can make a transform method so you can use the deltaX and deltaY in the pan method. Since the delta's hand you the change in "pan"there is no need at all to transform between screen and world.
Like my question says can someone tell me, why does my circle texture/sprite are acting like a rectangle ?
Code:
`
#Override
public void create() {
batch = new SpriteBatch();
img = new Texture("ball.png");
sprite = new Sprite(img);
sprite.setPosition(-sprite.getWidth()/2,-sprite.getHeight()/2);
world = new World(new Vector2(0, -1f),true);
BodyDef bodyDef = new BodyDef();
bodyDef.type = BodyDef.BodyType.DynamicBody;
bodyDef.position.set((sprite.getX() + sprite.getWidth()/2) /
PIXELS_TO_METERS,
(sprite.getY() + sprite.getHeight()/2) / PIXELS_TO_METERS);
body = world.createBody(bodyDef);
PolygonShape shape = new PolygonShape();
shape.setAsBox(sprite.getWidth()/2 / PIXELS_TO_METERS, sprite.getHeight()
/2 / PIXELS_TO_METERS);
FixtureDef fixtureDef = new FixtureDef();
fixtureDef.shape = shape;
fixtureDef.density = 0.1f;
fixtureDef.restitution = 0.8f;
body.createFixture(fixtureDef);
shape.dispose();
//CONTINUE
// BOTTOM
BodyDef bodyDefBottom = new BodyDef();
bodyDefBottom.type = BodyDef.BodyType.StaticBody;
float w = Gdx.graphics.getWidth()/PIXELS_TO_METERS;
// Set the height to just 50 pixels above the bottom of the screen so we can see the edge in the
// debug renderer
float h = Gdx.graphics.getHeight()/PIXELS_TO_METERS- 50/PIXELS_TO_METERS;
bodyDefBottom.position.set(0,0);
FixtureDef fixtureDef2 = new FixtureDef();
EdgeShape edgeShape = new EdgeShape();
edgeShape.set(-w/2,-h/2,w/2,-h/2);
fixtureDef2.shape = edgeShape;
bodyEdgeScreenBottom = world.createBody(bodyDefBottom);
bodyEdgeScreenBottom.createFixture(fixtureDef2);
edgeShape.dispose();
// TOP
BodyDef bodyDefTop = new BodyDef();
bodyDefTop.type = BodyDef.BodyType.StaticBody;
w = Gdx.graphics.getWidth()/PIXELS_TO_METERS;
// Set the height to just 50 pixels above the bottom of the screen so we can see the edge in the
// debug renderer
h = Gdx.graphics.getHeight()/PIXELS_TO_METERS;
bodyDefTop.position.set(0,0);
fixtureDef2 = new FixtureDef();
edgeShape = new EdgeShape();
edgeShape.set(-w/2,h/2,w/2,h/2);
fixtureDef2.shape = edgeShape;
bodyEdgeScreenTop = world.createBody(bodyDefTop);
bodyEdgeScreenTop.createFixture(fixtureDef2);
edgeShape.dispose();
// LEFT
BodyDef bodyDefLeft = new BodyDef();
bodyDefLeft.type = BodyDef.BodyType.StaticBody;
w = Gdx.graphics.getWidth()/PIXELS_TO_METERS;
// Set the height to just 50 pixels above the bottom of the screen so we can see the edge in the
// debug renderer
h = Gdx.graphics.getHeight()/PIXELS_TO_METERS;
bodyDefLeft.position.set(0,0);
fixtureDef2 = new FixtureDef();
edgeShape = new EdgeShape();
edgeShape.set(w/2,-h/2,w/2,h/2);
fixtureDef2.shape = edgeShape;
bodyEdgeScreenLeft = world.createBody(bodyDefLeft);
bodyEdgeScreenLeft.createFixture(fixtureDef2);
edgeShape.dispose();
// RIGHT
BodyDef bodyDefRight = new BodyDef();
bodyDefRight.type = BodyDef.BodyType.StaticBody;
w = Gdx.graphics.getWidth()/PIXELS_TO_METERS;
// Set the height to just 50 pixels above the bottom of the screen so we can see the edge in the
// debug renderer
h = Gdx.graphics.getHeight()/PIXELS_TO_METERS;
bodyDefRight.position.set(0,0);
fixtureDef2 = new FixtureDef();
edgeShape = new EdgeShape();
edgeShape.set(-w/2,-h/2,-w/2,h/2);
fixtureDef2.shape = edgeShape;
bodyEdgeScreenRight = world.createBody(bodyDefRight);
bodyEdgeScreenRight.createFixture(fixtureDef2);
edgeShape.dispose();
//CONTINUE
Gdx.input.setInputProcessor(this);
//debugRenderer = new Box2DDebugRenderer();
font = new BitmapFont();
font.setColor(Color.BLACK);
camera = new OrthographicCamera(Gdx.graphics.getWidth(),Gdx.graphics.
getHeight());
}
private float elapsed = 0;
#Override
public void render() {
camera.update();
// Step the physics simulation forward at a rate of 60hz
world.step(1f / 60f, 6, 2);
body.applyTorque(torque, true);
sprite.setPosition((body.getPosition().x * PIXELS_TO_METERS) - sprite.
getWidth() / 2,
(body.getPosition().y * PIXELS_TO_METERS) - sprite.getHeight() / 2)
;
sprite.setRotation((float) Math.toDegrees(body.getAngle()));
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.setProjectionMatrix(camera.combined);
//debugMatrix = batch.getProjectionMatrix().cpy().scale(PIXELS_TO_METERS,
// PIXELS_TO_METERS, 0);
batch.begin();
if(drawSprite)
batch.draw(sprite, sprite.getX(), sprite.getY(),sprite.getOriginX(),
sprite.getOriginY(),
sprite.getWidth(),sprite.getHeight(),sprite.getScaleX(),sprite.
getScaleY(),sprite.getRotation());
font.draw(batch,
"Restitution: " + body.getFixtureList().first().getRestitution(),
-Gdx.graphics.getWidth()/2,
Gdx.graphics.getHeight()/2 );
batch.end();
//debugRenderer.render(world, debugMatrix);
}
#Override
public void dispose() {
img.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;
}
// On touch we apply force from the direction of the users touch.
// This could result in the object "spinning"
#Override
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
body.applyForce(1f,1f,screenX,screenY,true);
//body.applyTorque(0.4f,true);
return true;
}
#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 have tried searching for other posts but couldn't find anything that explains to me why it is acting like a rectangle and how to resolve this. I have also tried searching for other methods to draw the texture , even using CircleShape but that cannot put inside texture from image. I'm pretty newbie in libgdx, I'm still learning everyday.
I'm little confused... You are creating PolygonShape and expecting it will behave as circle?
PolygonShape shape = new PolygonShape();
shape.setAsBox(...
All you can achieve this way is polygon with ball sprite inside. If you want to have a circle use mentioned by you CircleShape
CircleShape shape = new CircleShape();
shape.setRadius(1); //or anything you need
...
//assing it to the fixture etc
then update it when drawing with its position and angle - that's all