How to move an object similar to sinusoidal wave movement?-LibGdx - libgdx

I want to move my object vertically in zig-zag motion,similar to sisnusoidal motion;
I am moving my object like this:
public void moveLeavesDown(float delta) {
setY(getY() - (getSpeed()* delta));
}
How can I get this kind of movement?

You can add a timer and use the math.sin function to add an offset to your leaves.
This demo below shows how it can be done:
import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.math.Vector2;
public class Test extends ApplicationAdapter{
float time =0; // timer to store current elapsed time
Vector2 leaf = new Vector2(150,150); // holds the leaf x,y pos
float sinOffset = 0; // the offset for adding to the image
private SpriteBatch sb; // spritebatch for rendering
TextureRegion tx; // a texture region(the leaf)
#Override
public void create() {
sb = new SpriteBatch(); // make spritebatch
tx = DFUtils.makeTextureRegion(10, 10, "FFFFFF"); // makes a textureRegion of 10x10 of pure white
}
#Override
public void render() {
// clear screen
Gdx.gl.glClearColor(0f, 0f, 0f, 0f);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
leaf.y = leaf.y-0.2f; // move downwards
time+= Gdx.graphics.getDeltaTime(); // update sin timer
sinOffset =(float)Math.sin(time)*10; // calculate offset
// draw leaf with offset
sb.begin();
sb.draw(tx, leaf.x+sinOffset, leaf.y);
sb.end();
}
}

Related

LibGdx - Adding array of actors to a table, with delay

I want to have several comets falling in the background of my UI,I have a working comet Actor that does what it is supposed to, but I am not sure how to create a continuous spawn with these comets (with a random delay between each) in a table, without scene2d/actors it would look something like:
cometTimer += delta
if(cometTimer >= interval){
addCometToArray();
cometTimer = 0;
}
With the cometArray being looped over and drawn every frame, and then removing the entity when it goes out of bounds.
The only way I know how to add Actors to a table is like this:
table().add(new DialogComet());
How would I go about adding this type of behaviour using Scene2d?
Not sure if this is what you were looking for, but the below is a small working app that shows comets "falling" from the top to bottom, using Tables and having the tables manage the comets (no separate array/data structure). I created a small Comet class that extends Actor as well, to allow for movement and placement.
"main" class:
import java.util.Iterator;
import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.g2d.Batch;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.scenes.scene2d.ui.Table;
public class StageComet implements ApplicationListener {
private static final float INTERVAL = 0.3f;
private Batch batch;
private ShapeRenderer shapeRenderer;
private OrthographicCamera camera;
private BitmapFont font;
private Table rootTable;
private Table cometTable;
private Stage stage;
private Iterator<Actor> iter;
private Comet comet;
private float cometTimer = 0;
private float delta = 0;
#Override
public void create() {
camera = new OrthographicCamera();
camera.setToOrtho(false, 960, 640);
shapeRenderer = new ShapeRenderer();
batch = new SpriteBatch();
font = new BitmapFont();
stage = new Stage();
/*
* The root table could contain main "play" actors. It is empty in this example.
*/
rootTable = new Table();
rootTable.setFillParent(true);
/*
* Usually in Scene2d I think the practice is only to have 1 root table that takes up the entire screen (above),
* but for simplicity/illustrative purposes, I created a cometTable only, set it to Fill Parent as well, and the
* getChildren() of the table will have our array of comets in play at any given time.
*/
cometTable = new Table();
cometTable.setFillParent(true);
stage.addActor(rootTable);
stage.addActor(cometTable);
}
#Override
public void render() {
Gdx.gl.glClearColor(0, 0, 0.2f, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
camera.update();
batch.setProjectionMatrix(camera.combined);
delta = Gdx.app.getGraphics().getDeltaTime();
stage.act(delta); // make sure the comets "fall"
shapeRenderer.begin(ShapeType.Filled); // simple rendering of comets, they are just a circle ...
iter = cometTable.getChildren().iterator(); // Table subclasses Group, which has a snapshot array of its Actors
while ( iter.hasNext() ) {
comet = (Comet)iter.next();
shapeRenderer.circle(comet.getX(), comet.getY(), 20.0f); // Draw the comet
if ( comet.getY() < -100 ) { // Hack/hardcode, if the comet fell far enough "off stage" ...
iter.remove(); // ... remove it from the stage
}
}
shapeRenderer.end();
/*
* Sample code from original question on how to create a comet without scene2d ...
*/
cometTimer += delta;
if ( cometTimer > INTERVAL ) {
cometTable.add(new Comet()); // ... but in this case, we use scene2d
cometTimer = 0;
}
/*
* To keep track, display a simple message of # of comets on stage at any given time.
*/
batch.begin();
font.draw(batch, "Comets on stage: " + cometTable.getChildren().size, 100, 100);
batch.end();
}
/*
* I may have missed disposing something, but you get the idea ...
*/
#Override
public void dispose() {
shapeRenderer.dispose();
batch.dispose();
stage.dispose();
font.dispose();
}
#Override
public void resize(int width, int height) { }
#Override
public void pause() { }
#Override
public void resume() { }
}
And the small Comet class:
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.scenes.scene2d.Actor;
public class Comet extends Actor{
/*
* Spawn a comet at the top of the screen, in the middle
*/
public Comet() {
super();
this.setY(Gdx.app.getGraphics().getHeight());
this.setX(Gdx.app.getGraphics().getWidth()/2.0f);
}
/*
* Let the comet fall (same speed) to the bottom of the screen ...
*/
#Override
public void act (float delta) {
this.setY(this.getY() - 10);
super.act(delta);
}
}

LibGDX Stage and Actor, Events and Actor properties

I'm just starting android game development with LibGdx framework.
I read many online tutorial so far and the more I read the more I got confused: ApplicationListener, ApplicationAdapter, Stages, Game, Screens, Actors, Sprites, Images... not mentioning Input and Gesture listeners of all king).
I finally understood what kind of "model" I should use for the game I have in mind (a kind of puzzle game): Game, Screens, Stage and Actor.
So here is my first code.
This is the main application (Game):
package com.my.game1;
import com.badlogic.gdx.Game;
public class MyGame extends Game {
#Override
public void create () {
setScreen(new StarterScreen());
}
}
This is the main screen class:
package com.my.game1;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.scenes.scene2d.Stage;
public class StarterScreen implements Screen {
private Stage stage;
private float screenW, screenH;
private Tess tessera;
#Override
public void show() {
tessera = new Tess("image.png");
stage = new Stage();
screenW = stage.getViewport().getWorldWidth();
screenH = stage.getViewport().getWorldHeight();
Gdx.input.setInputProcessor(stage);
stage.addActor(tessera);
}
#Override
public void render(float delta) {
Gdx.gl.glClearColor(0,0,0,1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
stage.act();
stage.draw();
}
#Override
public void resize(int width, int height) {
// TODO Auto-generated method stub
}
#Override
public void pause() {
// TODO Auto-generated method stub
}
#Override
public void resume() {
// TODO Auto-generated method stub
}
#Override
public void hide() {
dispose();
}
#Override
public void dispose() {
stage.dispose();
}
}
And the following is the class that extends Actor:
package com.my.game1;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Batch;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.utils.ActorGestureListener;
public class Tess extends Actor {
private Texture texture;
private boolean selected = false;
public Tess (String img) {
this.texture = new Texture(Gdx.files.internal(img));
this.setBounds(0f, 0f, this.texture.getWidth(), this.texture.getHeight());
this.setOrigin(this.texture.getWidth() / 2, this.texture.getHeight() / 2);
this.setScale(0.25f);
this.addListener(new ActorGestureListener() {
public void tap(InputEvent event, float x, float y, int pointer, int button) {
((Tess)event.getTarget()).toggleSelect();
((Tess)event.getTarget()).setColor(0.5f, 0f, 0.5f, 1f);
}
});
}
#Override
public void draw(Batch batch, float alpha){
batch.draw(texture, 0, 0);
}
public void finalize() {
this.texture.dispose();
}
public void toggleSelect(){
this.selected = !this.selected;
if (this.selected == true)
this.setColor(0.5f, 0f, 0.5f, 1f);
else
this.setColor(0f, 0f, 0f, 0f);
}
}
The screen shows correctly the actor, but I cannot set the Actor's position or its scale, nor the "tap" event seems to get detected; and the color doesn't change.
What I did wrong?
Several things were wrong. First, just on the side, you don't want to call dispose() from the Screen's hide() method. hide() can be called simply when the screen is turned off, or when the app is switched to the background, and disposing of the Screen during that would cause serious issues on resume.
With that out of the way, here's what your Actor should have looked like:
package com.my.game1;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Batch;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.InputListener;
import com.badlogic.gdx.scenes.scene2d.Touchable;
public class Tess extends Actor {
private Sprite sprite;
private boolean selected = false;
public Tess (String img) {
this.sprite = new Sprite(new Texture(Gdx.files.internal(img)));
this.setTouchable(Touchable.enabled);
this.setBounds(this.sprite.getX(), this.sprite.getY(), this.sprite.getWidth(), this.sprite.getHeight());
this.setOrigin(this.sprite.getWidth() / 2, this.sprite.getHeight() / 2);
this.setScale(0.25f);
this.addListener(new ActorGestureListener() {
#Override
public void tap (InputEvent event, float x, float y, int pointer, int button) {
((Tess)event.getTarget()).toggleSelect();
}
});
}
#Override
public void draw(Batch batch, float alpha){
sprite.draw(batch);
}
#Override
public void positionChanged(){
sprite.setPosition(getX(), getY());
}
public void toggleSelect(){
this.selected = !this.selected;
if (this.selected == true)
sprite.setColor(0.5f, 0f, 0.5f, 1f);
else
sprite.setColor(0f, 0f, 0f, 0f);
}
}
First thing changed: you should use a Sprite, not a Texture, to handle color, drawing and transformations easily. Texture is possible, but is not as straightforward as Sprite is.
Next, you need to call setTouchable(Touchable.enabled) inside the actor to actually enable hit detection. Without this, no touch events are passed to the Actor.
After that, with setBounds(), you need to use sprite.getX() and sprite.getY(), to utilize the Sprite's positional values. Setting them to any arbitrary number seems to disable any touch capacity for that Actor.
Another thing, if all of that had been OK, is that you were setting the color twice for each touch, once based on the selected field, and then immediately after straight to the dark purple, so I removed the second set and just used your toggle method.
Next, since we have a Sprite now, we can use the draw() method attached to the Sprite itself and feed it the Batch, instead of calling the Batch's draw.
Finally, when you want to change the position of the image, call setPosition on the actor itself, and utilize an override of the positionChanged() method to set the Sprite's position based on the Actor's new position.

Box2D can't understand the way it works - libgdx

I'm trying to play around with Box2D in libgdx but unfortunately I can't seem to understand the way it works.
Here are a few examples that drive me crazy:
.1. It is known that Box2D works with meters. Everybody knows that. Then, why I getting results by Pixels? For instance, if I define some body definition and I set the position to 0,1, It draws the related fixture/sprite at the bottom-left corner of the screen! I thought the 0,0 point in Box2D is at the center of the screen.
.2. Another problem that I have been struggling to understand and solve is the values of the Shapes, Joints and other stuff. Let's start with the shapes: I defined a Polygon shape like this:
shape.setAsBox(1, 2);
Now the shape was supposed to be 2 meters wide and 4 meters height, but it's not the case. What I got is a super small shape.
And lastly, the values of the joints. I defined a body with a polygon shape and a ground body. Now I "pinned" those two to the center of the ground body using the Revolute Joint, with the goal to create some sort of a catapult that rotates nicely within a certain range.
Now I defined also a Mouse Joint so I could drag the catapult(the polygon shape) back and forth nicely, but it seems that I need to set the maxForce of the joint to an enormous value so I can actually see movement/rotation of the catapult! I don't understand. All this matter should be operated by small values, with regard to the values I had to set up.
Here is my very basic code that contains all of the above. Please tell me what I'm doing wrong, I'm freaking out here:
GameScreen.java
package com.david.box2dpractice;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Screen;
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.math.Vector2;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.BodyDef;
import com.badlogic.gdx.physics.box2d.Box2DDebugRenderer;
import com.badlogic.gdx.physics.box2d.ChainShape;
import com.badlogic.gdx.physics.box2d.FixtureDef;
import com.badlogic.gdx.physics.box2d.PolygonShape;
import com.badlogic.gdx.physics.box2d.BodyDef.BodyType;
import com.badlogic.gdx.physics.box2d.World;
import com.badlogic.gdx.physics.box2d.joints.RevoluteJointDef;
import com.badlogic.gdx.utils.Array;
public class GameScreen implements Screen{
private Box2DDebugRenderer debugRenderer;
private Texture texture;
private Sprite sprite;
private Sprite tempSprite;
private SpriteBatch batch;
private Body arm , ground;
private World world;
public OrthographicCamera camera;
private RevoluteJointDef jointDef;
private Array<Body> tempBodies;
public GameScreen() {
debugRenderer = new Box2DDebugRenderer();
batch = new SpriteBatch();
texture = new Texture(Gdx.files.internal("catapult_arm.png"));
camera = new OrthographicCamera();
camera.setToOrtho(false, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
tempBodies = new Array<Body>();
}
#Override
public void render(float delta) {
// TODO Auto-generated method stub
Gdx.gl.glClearColor(0, 0, 0, 0);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.setProjectionMatrix(camera.combined);
world.getBodies(tempBodies);
batch.begin();
for(Body body : tempBodies) {
if(body.getUserData() != null && body.getUserData() instanceof Sprite) {
tempSprite = (Sprite) body.getUserData();
tempSprite.setPosition(body.getPosition().x-tempSprite.getWidth()/2, body.getPosition().y-tempSprite.getHeight()/2);
tempSprite.setRotation((float) Math.toDegrees(body.getAngle()));
tempSprite.draw(batch);
}
}
batch.end();
debugRenderer.render(world, camera.combined);
world.step(1/60f, 6, 2);
}
#Override
public void resize(int width, int height) {
// TODO Auto-generated method stub
Gdx.app.log("System", "resize() was invoked");
}
#Override
public void show() {
// TODO Auto-generated method stub
Gdx.app.log("System", "show() was invoked");
world = new World(new Vector2(0,0), true);
sprite = new Sprite(texture);
BodyDef bodyDef = new BodyDef();
bodyDef.position.set(Gdx.graphics.getWidth()/2,Gdx.graphics.getHeight()/2+sprite.getHeight()/2);
bodyDef.type = BodyType.DynamicBody;
// The shape
PolygonShape shape = new PolygonShape();
shape.setAsBox(11, 91);
// The fixture
FixtureDef fixtureDef = new FixtureDef();
fixtureDef.shape = shape;
fixtureDef.density = .10f;
arm = world.createBody(bodyDef);
arm.createFixture(fixtureDef);
sprite.setOrigin(sprite.getWidth()/2, sprite.getHeight()/2);
arm.setUserData(sprite);
shape.dispose();
bodyDef = new BodyDef();
bodyDef.position.set(Gdx.graphics.getWidth()/2,Gdx.graphics.getHeight()/2);
bodyDef.type = BodyType.StaticBody;
ChainShape shape2 = new ChainShape();
shape2.createChain(new Vector2[] {new Vector2(-20*Pixels_To_Meters,0),new Vector2(20*Pixels_To_Meters,0)});
// The fixture
fixtureDef.shape = shape2;
fixtureDef.restitution = .65f;
fixtureDef.friction = .75f;
ground = world.createBody(bodyDef);
ground.createFixture(fixtureDef);
shape2.dispose();
// joint
jointDef = new RevoluteJointDef();
jointDef.bodyA = arm;
jointDef.bodyB = ground;
jointDef.localAnchorB.set(ground.getLocalCenter());
jointDef.localAnchorA.set(arm.getLocalCenter().x,arm.getLocalCenter().y-sprite.getHeight()/2);
jointDef.enableLimit = true;
jointDef.enableMotor = true;
jointDef.motorSpeed = 15;
jointDef.lowerAngle = (float) -Math.toRadians(75);
jointDef.upperAngle = (float) -Math.toRadians(9);
jointDef.maxMotorTorque = 4800;
world.createJoint(jointDef);
Gdx.input.setInputProcessor(new InputHandler(arm,ground,world,camera));
}
#Override
public void hide() {
// TODO Auto-generated method stub
Gdx.app.log("System", "hide() was invoked");
dispose();
}
#Override
public void pause() {
// TODO Auto-generated method stub
Gdx.app.log("System", "pause() was invoked");
}
#Override
public void resume() {
// TODO Auto-generated method stub
Gdx.app.log("System", "resume() was invoked");
}
#Override
public void dispose() {
// TODO Auto-generated method stub
Gdx.app.log("System", "dispose() was invoked");
texture.dispose();
batch.dispose();
world.dispose();
}
}
InputHandler.java
package com.david.box2dpractice;
import com.badlogic.gdx.InputProcessor;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.Fixture;
import com.badlogic.gdx.physics.box2d.QueryCallback;
import com.badlogic.gdx.physics.box2d.World;
import com.badlogic.gdx.physics.box2d.joints.MouseJoint;
import com.badlogic.gdx.physics.box2d.joints.MouseJointDef;
public class InputHandler implements InputProcessor{
Body ground;
MouseJoint mouseJoint;
MouseJointDef mouseJointDef;
World world;
Vector2 target,initialPos;
Vector3 temp;
QueryCallback query;
OrthographicCamera camera;
boolean firstTime = true;
public InputHandler(Body arm, Body ground, final World world, OrthographicCamera camera) {
this.camera = camera;
this.ground = ground;
this.world = world;
mouseJointDef = new MouseJointDef();
target = new Vector2();
temp = new Vector3();
mouseJointDef.bodyA = ground;
mouseJointDef.collideConnected = true;
mouseJointDef.maxForce = 9000;
query = new QueryCallback() {
#Override
public boolean reportFixture(Fixture fixture) {
// TODO Auto-generated method stub
if(!fixture.testPoint(temp.x, temp.y))
return true;
if(firstTime) {
initialPos = new Vector2(fixture.getBody().getPosition().x,fixture.getBody().getPosition().y);
firstTime = false;
}
mouseJointDef.bodyB = fixture.getBody();
mouseJointDef.target.set(temp.x,temp.y);
mouseJoint = (MouseJoint) world.createJoint(mouseJointDef);
return false;
}
};
}
#Override
public boolean keyDown(int keycode) {
// TODO Auto-generated method stub
return false;
}
#Override
public boolean keyUp(int keycode) {
// TODO Auto-generated method stub
return false;
}
#Override
public boolean keyTyped(char character) {
// TODO Auto-generated method stub
return false;
}
#Override
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
// TODO Auto-generated method stub
camera.unproject(temp.set(screenX, screenY, 0));
world.QueryAABB(query, temp.x, temp.y, temp.x, temp.y);
return true;
}
#Override
public boolean touchUp(int screenX, int screenY, int pointer, int button) {
// TODO Auto-generated method stub
if(mouseJoint == null)
return false;
mouseJoint.setTarget(initialPos);
world.destroyJoint(mouseJoint);
mouseJoint = null;
firstTime = true;
return true;
}
#Override
public boolean touchDragged(int screenX, int screenY, int pointer) {
// TODO Auto-generated method stub
if(mouseJoint == null)
return false;
camera.unproject(temp.set(screenX, screenY, 0));
mouseJoint.setTarget(target.set(temp.x, temp.y));
return true;
}
#Override
public boolean mouseMoved(int screenX, int screenY) {
// TODO Auto-generated method stub
return false;
}
#Override
public boolean scrolled(int amount) {
// TODO Auto-generated method stub
return false;
}
}
If you could help me out here I would really really appreaciate that. Thanks!!
Box2D is only the Physic-Engine, the logical part. It does nothing with the view, so it is your job to convert the meters to pixels.
In Libgdx this could be done by using a Camera.
You are allready using a Camera, but you give it the "wrong" Viewport-Size.
You tell the Camera to be as big as the game (Gdx.graphics.getWidth, Gdx.graphics.getHeight), instead you should think about how many meters you want to show on your Screen.
If you want to show 80 meters in width and 45 meters i height (16/9), then you need to setup the Camera like this:
camera = new OrthographicCamera();
camera.setToOrtho(false, 80, 45);
So if your Game has a resolution of 1600*900 px, every meter would be convertet to 20px (camera does this for you), if you are using a resolution of 800*450, every meter would be converted to 10px.
Also box2Ds P(0/0) is not in the middle of the Screen, it is nowhere on the screen. It is on the P(0/0) of the box2D world, it is your job to draw it in the middle or the bottom or whererever you want.
Again, this is done by Camera. the Cameras P(0/0) by default is in the middle of the Screen, but you can move the camera arround, so it could be everywhere.
Now it should be clear, that the shape you created is not "super-small", but you just did not "zoom in". A 3m long car seems verry small if you watch it from a few 100m of distance. If you instead stand 1m away from it, you are almost unable to see the whole car at one time, as it is bigger then your "viewport".
I am not sure about the joints/forces, but it could be, that your problem is solved, if you "zoom in" by using a camera. But i also can be wrong, as i never used box2D...
Some tutorials:
IForce2D - Box2D, it is a tutorial fpr C++. but by reading the explanations you should understand it and be able to implement it in java/libgdx.
Using Box2D in Libgdx Game, this tutorial showes you how to create a game with box2D and libgdx. It really helps by understanding how to connect box2D with Libgdx.

How to properly use setposition in libgdx?

This is the java file created by gdx-setup-ui.jar of v0.9.7
sprite.setPosition(-sprite.getWidth()/2, -sprite.getHeight()/2);
Why we need to set position to negative value in order to center the picture?
Where is the reference base point of the libgdx picture? (left-bottom corner?)
I was told that the origin of libgdx is left-bottom corner. Given the above values, part of the picture should have been outside the screen....It turns out not! I am very confused.
Thanks in advance
Complete listing:
package com.packtpub.libgdx.basic;
import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL10;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.Texture.TextureFilter;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
public class Basic implements ApplicationListener {
private OrthographicCamera camera;
private SpriteBatch batch;
private Texture texture;
private Sprite sprite;
#Override
public void create() {
float w = Gdx.graphics.getWidth();
float h = Gdx.graphics.getHeight();
camera = new OrthographicCamera(1, h/w);
batch = new SpriteBatch();
texture = new Texture(Gdx.files.internal("data/libgdx.png"));
texture.setFilter(TextureFilter.Linear, TextureFilter.Linear);
TextureRegion region = new TextureRegion(texture, 0, 0, 512, 275);
sprite = new Sprite(region);
sprite.setSize(0.9f, 0.9f * sprite.getHeight() / sprite.getWidth());
sprite.setOrigin(sprite.getWidth()/2, sprite.getHeight()/2);
sprite.setPosition(-sprite.getWidth()/2, -sprite.getHeight()/2);
}
#Override
public void dispose() {
batch.dispose();
texture.dispose();
}
#Override
public void render() {
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
batch.setProjectionMatrix(camera.combined);
batch.begin();
sprite.draw(batch);
batch.end();
}
#Override
public void resize(int width, int height) {
}
#Override
public void pause() {
}
#Override
public void resume() {
}
}
It's because the default center point for the orthographic camera is (0,0,0), so if you just draw your image at (0,0) its bottom left cornet will be in the center of the screen.
You can change this center point by using cam.position.set(w / 2, h / 2, 0) method
See here for more detailed example of OrthographiCamera use: https://github.com/libgdx/libgdx/wiki/Orthographic-camera

Why does my Player follow the OrthographicCamera

My game renders a tiledmap. I let the OrthographicCamera change its position.x to the right and can see the background (the tiledmap) scroll. This is fine.
But other Objects (the player and some balls) do (visually) change their position corresponding to the camera. They should not move, because only the camera moves.
package com.me.drop;
import java.util.Iterator;
import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Game;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input.Keys;
import com.badlogic.gdx.audio.Music;
import com.badlogic.gdx.audio.Sound;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL10;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.PerspectiveCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.VertexAttributes.Usage;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g3d.Environment;
import com.badlogic.gdx.graphics.g3d.Material;
import com.badlogic.gdx.graphics.g3d.Model;
import com.badlogic.gdx.graphics.g3d.ModelBatch;
import com.badlogic.gdx.graphics.g3d.ModelInstance;
import com.badlogic.gdx.graphics.g3d.attributes.ColorAttribute;
import com.badlogic.gdx.graphics.g3d.environment.DirectionalLight;
import com.badlogic.gdx.graphics.g3d.utils.ModelBuilder;
import com.badlogic.gdx.maps.tiled.TiledMap;
import com.badlogic.gdx.maps.tiled.TiledMapRenderer;
import com.badlogic.gdx.maps.tiled.TiledMapTileLayer;
import com.badlogic.gdx.maps.tiled.TmxMapLoader;
import com.badlogic.gdx.maps.tiled.renderers.OrthogonalTiledMapRenderer;
import com.badlogic.gdx.math.Circle;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.BodyDef;
import com.badlogic.gdx.physics.box2d.BodyDef.BodyType;
import com.badlogic.gdx.physics.box2d.Box2DDebugRenderer;
import com.badlogic.gdx.physics.box2d.CircleShape;
import com.badlogic.gdx.physics.box2d.Fixture;
import com.badlogic.gdx.physics.box2d.FixtureDef;
import com.badlogic.gdx.physics.box2d.PolygonShape;
import com.badlogic.gdx.physics.box2d.World;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.GdxNativesLoader;
import com.badlogic.gdx.utils.TimeUtils;
public class MyTestGame extends Game {
Texture dropImage;
Texture bucketImage;
Sound dropSound;
Music rainMusic;
SpriteBatch batch;
OrthographicCamera camera;
Rectangle bucket;
Array<Rectangle> raindrops;
long lastDropTime;
Animator animator = new Animator();
Body animatorBody;
private Physics physics;
public Environment environment;
// public PerspectiveCamera cam;
public Model model;
public ModelBatch modelBatch;
public ModelInstance instance;
static final int WIDTH = 1600;
static final int HEIGHT = 960;
public final static float ORTHO_SCALE=1;
public final static float WORLD_SCALE=32;
Ball balls[] = new Ball[10];
Spieler player;
#Override
public void create() {
environment = new Environment();
environment.set(new ColorAttribute(ColorAttribute.AmbientLight, 0.4f, 0.4f, 0.4f, 1f));
environment.add(new DirectionalLight().set(0.8f, 0.8f, 0.8f, -1f, -0.8f, -0.2f));
glViewport = new Rectangle(0, 0, WIDTH, HEIGHT);
// load the images for the droplet and the bucket, 64x64 pixels each
dropImage = new Texture(Gdx.files.internal("droplet.png"));
bucketImage = new Texture(Gdx.files.internal("bucket.png"));
// load the drop sound effect and the rain background "music"
dropSound = Gdx.audio.newSound(Gdx.files.internal("drop.wav"));
rainMusic = Gdx.audio.newMusic(Gdx.files.internal("rain.mp3"));
// start the playback of the background music immediately
rainMusic.setLooping(true);
rainMusic.play();
// create the camera and the SpriteBatch
camera = new OrthographicCamera();
//camera.setToOrtho(false, 400, 240);
camera.setToOrtho(false, 800/ORTHO_SCALE, 480/ORTHO_SCALE);
batch = new SpriteBatch();
ModelBuilder modelBuilder = new ModelBuilder();
model = modelBuilder.createBox(5f, 5f, 5f,
new Material(ColorAttribute.createDiffuse(Color.GREEN)),
Usage.Position | Usage.Normal);
instance = new ModelInstance(model);
// Box2d
physics = Physics.getInstance();
// floor
physics.initFloor(0f, 0f, camera.viewportWidth, 0f);
// ceiling
// physics.initFloor(0f, camera.viewportHeight, camera.viewportWidth, 10f);
// left Wall
physics.initFloor(0f, 0f, 0f, camera.viewportHeight);
// right Wall
physics.initFloor(camera.viewportWidth, 0f, 0f, camera.viewportHeight);
float x = 150;
float y = camera.viewportHeight;
for (int i = 0; i < balls.length; i++) {
if (i%10==0) {
x += 10;
y = camera.viewportHeight / 2;
}
y += x;
balls[i] = new Ball(x, y , 20f , 20f, 0.4f, 0.8f);
}
player = new Spieler(50, camera.viewportHeight, 60f, 120f);
loadBackground();
}
TiledMapRenderer tileRenderer;
public void loadBackground() {
TiledMap map = new TmxMapLoader().load("maps/mymap.tmx");
System.out.println(map.getTileSets().toString());
float unitScale = 1 / 1;
tileRenderer = new OrthogonalTiledMapRenderer(map, unitScale);
physics.createFixturesForMap(map);
}
private Rectangle glViewport;
//#Override
public void render() {
GL10 gl = Gdx.graphics.getGL10();
// Camera --------------------- /
gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
gl.glViewport((int) glViewport.x, (int) glViewport.y,
(int) glViewport.width, (int) glViewport.height);
//
// tell the camera to update its matrices.
camera.update();
camera.apply(gl);
// tell the SpriteBatch to render in the
// coordinate system specified by the camera.
batch.setProjectionMatrix(camera.combined);
// background
tileRenderer.setView(camera);
tileRenderer.render();
for (Ball b : balls)
b.render();
player.render();
grabUserAction();
// Box2d
physics.step();
updateObjects();
physics.debugRenderer.render(physics.world, camera.combined);
}
private void grabUserAction() {
// process user input
if(Gdx.input.isTouched()) {
Vector3 touchPos = new Vector3();
touchPos.set(Gdx.input.getX(), Gdx.input.getY(), 0);
camera.unproject(touchPos);
bucket.x = touchPos.x - 64 / 2;
}
Vector2 vel = this.player.getBody().getLinearVelocity();
Vector2 pos = this.player.getBody().getPosition();
// apply left impulse, but only if max velocity is not reached yet
if (Gdx.input.isKeyPressed(Keys.LEFT)) { // && vel.x > -MAX_VELOCITY) {
// this.animatorBody.localPoint2.x -= 200 *
// Gdx.graphics.getDeltaTime();
pos.x -= 2 * Gdx.graphics.getDeltaTime();
this.player.getBody().setTransform(pos, 0);
// this.animatorBody.applyLinearImpulse(0, -0.8f, pos.x, pos.y,
// true);
// this.animatorBody.applyLinearImpulse(-5000, 0, pos.x, pos.y,
// true);
}
// apply right impulse, but only if max velocity is not reached yet
if (Gdx.input.isKeyPressed(Keys.RIGHT)) { // && vel.x < MAX_VELOCITY) {
// this.animatorBody.localPoint2.x += 200 *
// Gdx.graphics.getDeltaTime();
pos.x += 2 * Gdx.graphics.getDeltaTime();
this.player.getBody().setTransform(pos, 0);
// this.animatorBody.applyLinearImpulse(5000, 0, pos.x, pos.y,
// true);
}
if (Gdx.input.isKeyPressed(Keys.UP)) {
Vector2 impuls = new Vector2(0, 500f);
this.player.getBody().applyLinearImpulse(impuls, player.getBody().getWorldCenter(),true);
// this.animatorBody.applyAngularImpulse(-5.0f, true);
//(impulse, wake);(new b2Vec2(0.0, -3.0), Body.GetWorldCenter());
}
if (Gdx.input.isKeyPressed(Keys.D)) {
this.camera.position.x += 2;
this.camera.update();
}
else if (Gdx.input.isKeyPressed(Keys.A)) {
this.camera.position.x -= 2;
this.camera.update();
}
}
private void updateObjects() {
Array<Body> array = new Array<Body>();
physics.world.getBodies(array);
Iterator<Body> bi = array.iterator();
while (bi.hasNext()){
Body b = bi.next();
// Get the body's user data - in this example, our user
// data is an instance of the Entity class
IObject e = (IObject) b.getUserData();
if (e != null) {
// Update the entities/sprites position and angle
e.setPosition((b.getPosition().x - e.getWidth()/2/WORLD_SCALE) * WORLD_SCALE
, (b.getPosition().y - e.getHeight()/2/WORLD_SCALE) * WORLD_SCALE);
// We need to convert our angle from radians to degrees
//e.setRotation(MathUtils.radiansToDegrees * b.getAngle());
}
}
}
#Override
public void dispose() {
// dispose of all the native resources
dropImage.dispose();
bucketImage.dispose();
dropSound.dispose();
rainMusic.dispose();
batch.dispose();
// modelBatch.dispose();
model.dispose();
}
#Override
public void resize(int width, int height) {
super.resize(width, height);
//
// Vector3 oldpos = new Vector3(camera.position);
// camera.setToOrtho(false,
// width/WORLD_SCALE,
// height/WORLD_SCALE);
// camera.translate(oldpos.x-camera.position.x,oldpos.y-camera.position.y);
}
#Override
public void pause() {
super.pause();
}
#Override
public void resume() {
super.resume();
}
}