I have seen many questions exactly like these with the same answer but it never works for me. I have a player who has a position vector that is constantly updating. I need my camera to constantly follow my players position. This is the player class
public void update(){
//velocity.y += MainScreen.GRAVITY.y;
velocity.x += MainScreen.GRAVITY.x;
oldPosition = getGridPosition();
position.x += velocity.x;
position.y += velocity.y;
if(oldPosition.x == getGridPosition().x){
hasMoved = false;
System.out.println("Hasn't moved");
System.out.println("normX- " + position.x);
System.out.println("oldX- " + oldPosition.x);
}
else{
hasMoved = true;
System.out.println("Has moved");
}
if(Gdx.input.isKeyPressed(Keys.A)){
velocity.x -= 10 * Gdx.graphics.getDeltaTime();
}
else if(Gdx.input.isKeyPressed(Keys.D)){
velocity.x += 10 * Gdx.graphics.getDeltaTime();
}else
velocity.x = 0;
}
And I have tried to set the camera position to my players position but it just does NOT for me. Here is my main render loop.
public void render () {
player.update();
camera.position.set(player.getPosition(), 0);
camera.update();
mapGrid.update();
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
mapGrid.render(tmpRend);
player.render(tmpRend);
}
I am at such a loss I don't know what I am doing wrong, here is how I initialize my camera in my create method
player = new Player();
camera = new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
camera.setToOrtho(false);
//camera.position.set(MapGrid.MAP_WIDTH / 2, MapGrid.MAP_HEIGHT, 0);
camera.position.set(player.getPosition(), 0);
camera.zoom = 2f;
camera.update();
tmpRend = new ShapeRenderer();
tmpRend.setAutoShapeType(true);
tmpRend.setProjectionMatrix(camera.combined);
input = new InputListener(camera);
Gdx.input.setInputProcessor(input);
Please I have seen many other questions just like this and I am doing what they say but mine just doesn't work. Here is an image to show what happens.
I just don't know why it won't work when I have followed everything I have been told. Any help you can give me would be extremely appreciated!
I think that you already update wrong camera - you've created an instance of it but where it is connected with other part of program?
Use Scene2d to manage your actors, viewports and cameras. You can read more about it here:
https://github.com/libgdx/libgdx/wiki/Scene2d
You are creating new stage, add player (which should inherit from Actor class) to it and then just instead of creating new Camera just get your current stage camera just like
stage.getCamera()
all you should do in render is
...
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
this.viewport.update(this.screenWidth, this.screenHeight);
this.stage.act();
this.stage.draw();
Related
In LibGDX I'm trying to have my OrthographicCamera follow the playersprite when I move it around. Currently, the playersprite gets updated first and then in the next frame the camera updates to the position of the playersprite in the previous frame. Here is an example:
https://i.imgur.com/wxJUizU.gifv
I have tried moving gameMap.render(cam) to the bottom of the method, but not only does it not solve my problem, it also places the map textures above the playersprite, so you won't be able to see the playersprite anymore when it moves under the map.
Here is the code for rendering the playersprite and camera:
public void render () {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
cam.viewportHeight = Gdx.graphics.getHeight() / 3;
cam.viewportWidth = Gdx.graphics.getWidth() / 3;
gameMap.render(cam);
gameMap.getTiledMapRenderer().getBatch().begin();
player.draw(gameMap.getTiledMapRenderer().getBatch());
gameMap.getTiledMapRenderer().getBatch().end();
cam.position.x = player.getX() + (player.getWidth() / 2);
cam.position.y = player.getY() + (player.getHeight() / 2);
cam.update();
}
Typically, you want to break your logic into two sections:
Update
Render
So, before each frame you want to perform any pertinent calculations.
Your camera is currently updating late, because it isn't performing logic until after the gameMap has been updated.
For example:
// Perform logic and update the state
public void Update () {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
cam.viewportHeight = Gdx.graphics.getHeight() / 3;
cam.viewportWidth = Gdx.graphics.getWidth() / 3;
gameMap.getTiledMapRenderer().getBatch().begin();
cam.position.x = player.getX() + (player.getWidth() / 2);
cam.position.y = player.getY() + (player.getHeight() / 2);
}
// Draw map
public void Render () {
gameMap.render(cam);
player.draw(gameMap.getTiledMapRenderer().getBatch());
gameMap.getTiledMapRenderer().getBatch().end();
cam.update();
}
I'm not familiar with the framework you're using, so I can't tell if this would run or not, but when working with frames in any game development situation, this is how you want to handle things.
Like Bradley says you should split your logic into two parts: update and render
Create a udpate() method where you place all your things to update and call this method first in the render() method:
public void update(){
//Update camera position
cam.position.x = player.getX() + (player.getWidth() / 2);
cam.position.y = player.getY() + (player.getHeight() / 2);
//apply all updates to the camera before this the changed position won't apply to the camera
cam.update();
}
#Override
public void render() {
//First call the update method we created
update();
//Clear the Screen
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
//Render
gameMap.render(cam);
gameMap.getTiledMapRenderer().getBatch().begin();
player.draw(gameMap.getTiledMapRenderer().getBatch());
gameMap.getTiledMapRenderer().getBatch().end();
}
You don't need to call:
cam.viewportHeight = Gdx.graphics.getHeight() / 3;
cam.viewportWidth = Gdx.graphics.getWidth() / 3;
every frame. It's enough to call it ones in the create() method
I am creating a game in LibGDX. I have taken the tiles used in Pixel Dungeon and created a tile map using Tiled.
The main character's class is a subclass of Actor, and because the character is animated, I am using this code to draw the sprite:
if (direction.isEastwards() || direction.isNorthwards()) {
Vector3 projectedPosition = getLocation().getCamera().project(
new Vector3(16 * getX() + 1, Gdx.graphics.getHeight()
- (16 * getY()) - 15, 0));
batch.draw(current.getKeyFrame(
animTime += Gdx.graphics.getDeltaTime(), true),
projectedPosition.x, projectedPosition.y);
} else {
Vector3 projectedPosition = getLocation().getCamera().project(
new Vector3(16 * getX() + 13, Gdx.graphics.getHeight()
- (16 * getY()) - 15, 0));
batch.draw(current.getKeyFrame(
animTime += Gdx.graphics.getDeltaTime(), true),
projectedPosition.x, projectedPosition.y);
}
When I launch the game in Eclipse, the sprite initially appears in the correct location. However, if I resize the screen, the sprite ceases to be in the correct location and eventually will disappear off the map.
The same thing happened before I started using projection, and I figured the problem was related to projection. As this is an area I have not explored before I decided after an hour of being able to solve this to ask for help.
The animation flips depending on which direction the character faces, which is why the if/else clause is there.
Addendum: The stage is created with new Stage(new ExtendViewport(800,600),batch);, the resize method updates the camera, and the batch is set to the projection matrix.
Here is more relevant code:
Camera and map initialisation:
camera=new OrthographicCamera();
camera.setToOrtho(false,Gdx.graphics.getWidth(),Gdx.graphics.getHeight());
mapRenderer=new OrthogonalTiledMapRenderer(map,batch);
Render method:
camera.update();
batch.setProjectionMatrix(camera.combined);
mapRenderer.setView(camera);
mapRenderer.render();
stage.act();
stage.draw();
Resize method:
camera.viewportWidth=width;
camera.viewportHeight=height;
camera.update();
Actor draw method:
#Override
public void draw(Batch batch, float parentAlpha) {
Color color = getColor();
batch.setColor(color.r, color.g, color.b, color.a * parentAlpha);
if (direction.isEastwards() || direction.isNorthwards()) {
Vector3 projectedPosition = getLocation().getCamera().project(
new Vector3(16 * getX() + 1, Gdx.graphics.getHeight()
- (16 * getY()) - 15, 0));
batch.draw(current.getKeyFrame(
animTime += Gdx.graphics.getDeltaTime(), true),
projectedPosition.x, projectedPosition.y);
} else {
Vector3 projectedPosition = getLocation().getCamera().project(
new Vector3(16 * getX() + 13, Gdx.graphics.getHeight()
- (16 * getY()) - 15, 0));
batch.draw(current.getKeyFrame(
animTime += Gdx.graphics.getDeltaTime(), true),
projectedPosition.x, projectedPosition.y);
}
// Walk animation displays for 0.2 seconds
if (current == walk && animTime >= 0.2) {
current = idle;
animTime = 0;
}
}
I think the problem it caused because you dont combine the sprite with camera projection. set your spriteBatch like this :
spriteBatch.setProjectionMatrix(camera.combined);
And dont miss update viewport in resize method :
public void resize(int width, int height) {
camera.viewportWidth = width;
camera.viewportHeight = height;
camera.update();
}
With that, you can resize or zoomin zoomout, the spriteBatch it scalled to the camera projection.
I have a problem with my game (jumper type game), when a player is falling down or move left/right it isn't smooth, I can see sprite multiple times (like some kind of shadow). After searching the internet I think it's something with deltaTime but I cannot find out how to fix it.
The code for render method in play screen is:
#Override
public void render(float delta) {
Gdx.gl.glClearColor(0,0,0,1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
//game running
if(state == RUNNING){
//make world step
doPhysicsStep(delta);
//update player and camera
player.update(delta);
if(player.getBody().getPosition().x < bottomLeft.x)
player.getBody().setTransform(bottomRight.x, player.getBody().getPosition().y, player.getBody().getAngle());
else if(player.getBody().getPosition().x > bottomRight.x)
player.getBody().setTransform(bottomLeft.x, player.getBody().getPosition().y, player.getBody().getAngle());
camera.position.y =player.getBody().getPosition().y > camera.position.y ? player.getBody().getPosition().y: camera.position.y;
camera.update();
levelGenerator.generate(camera.position.y + camera.viewportHeight /2,camera.position.y - camera.viewportHeight /2);
}
//game ended
if(player.getBody().getPosition().y< camera.position.y - camera.viewportHeight/2 -player.HEIGHT/2 && state == RUNNING){
gameOverScreen.updateScore(score.getText().toString().substring(7));
state = END;
}
if(state == END){
gameOverScreen.setVisible(true);
}
//drawing game
batch.setProjectionMatrix(camera.combined);
batch.begin();
renderBackground();
renderPlatform();
renderPlayer();
Assets.sparks.draw(batch, delta);
batch.end();
}
public void renderPlatform(){
//world.getBodies(tmpBodies);
//for(Body body : tmpBodies)
// if(body.getUserData() != null && body.getUserData() instanceof Platform)
for(int i=0;i<platforms.size();i++){
Body body = platforms.get(i).getBody();
Sprite sprite = platforms.get(i).getSprite();
sprite.setPosition(body.getPosition().x - sprite.getWidth()/2, body.getPosition().y - sprite.getHeight()/2);
sprite.setRotation(body.getAngle() * MathUtils.radiansToDegrees);
sprite.draw(batch);
}
}
public void renderPlayer(){
world.getBodies(tmpBodies);
for(Body body : tmpBodies)
if(body.getUserData() != null && body.getUserData() instanceof Player){
Player player = (Player) body.getUserData();
Sprite sprite = player.getSprite();
sprite.setPosition(body.getPosition().x - sprite.getWidth()/2, body.getPosition().y - sprite.getHeight()/2);
//sprite.setRotation(body.getAngle() * MathUtils.radiansToDegrees);
sprite.draw(batch);
if(player.isPlayEffect()){
Assets.sparks.setPosition(body.getPosition().x , body.getPosition().y - sprite.getHeight()/2);
Assets.sparks.setDuration(200);
Assets.sparks.start();
}
}
}
public void renderBackground(){
world.getBodies(tmpBodies);
for(Body body : tmpBodies)
if(body.getUserData() != null && body.getUserData() instanceof Background){
Background background = (Background) body.getUserData();
Sprite sprite = background.getSprite();
//sprite.setPosition(body.getPosition().x - sprite.getWidth()/2, body.getPosition().y - sprite.getHeight()/2);
sprite.setBounds(bottomLeft.x, camera.position.y - camera.viewportHeight /2, camera.viewportWidth, camera.viewportHeight);
sprite.draw(batch);
}
}
private void doPhysicsStep(float deltaTime) {
// fixed time step
// max frame time to avoid spiral of death (on slow devices)
float frameTime = Math.min(deltaTime, 0.05f);
accumulator += frameTime;
while (accumulator >= TIMESTEP) {
world.step(TIMESTEP, VELOCITYITERATIONS, POSITIONITERATIONS);
accumulator -= TIMESTEP;
}
}
and player update:
public void update(float delta) {
stateTime += delta;
if(state==JUMP){
sprite.setRegion(jump.getKeyFrame(stateTime));
if(jump.isAnimationFinished(stateTime)){
state = IDLE;
stateTime = 0;
}
}else{
sprite.setRegion(idle.getKeyFrame(stateTime));
}
if(Gdx.app.getType() == ApplicationType.Android )
velocity.x = -Gdx.input.getAccelerometerX() * (movementForce / 10f);
if(applyJump){
body.applyLinearImpulse(0, jumpPower, body.getWorldCenter().x, body.getWorldCenter().y, true);
applyJump = false;}
body.setLinearVelocity(velocity.x, body.getLinearVelocity().y);
}
where applyJump variable is setted at contact in postSolve() method.
Thanks in advance
Well, that's two different problems then, right? It isn't smooth, and its drawing multiple sprites when it shouldn't be?
Lets tackle the second one first, that should be pretty obvious. Either you're making multiple calls to render the sprite somewhere, or you're not clearing the frame properly. It looks like you're clearing it, so you've gotta go through all your render code and see how you're drawing that texture twice. Somewhere its happening.
world.getBodies(tmpBodies);
for(Body body : tmpBodies)
Why does this code exist? Does the player character have multiple sprites? I wouldn't handle it this way; does the number change over time? Are there new players being created? You should probably create a separate Player class and allow it to manage its own state and data. Use OOP principles! Too much here is being done by a single GOD class, very procedural style. Bad Java.
If left/right movement isn't smooth you need to work on your physics.
I'm playing around with creating a small voxel based project with LWJGL. Part of the project is loading small chunks of landscape around the player as they move. The loading part of this works okay, but I ran into an issue where as I walked along the +X axis, the chunks of landscape moving the same distance along the -X axis would load. This would also happen for the Z axis.
I got curious, so I tried reversing the X and Z axis rendering direction on the chunks, which seemed to fix the issue. However, I also decided to render the axis as lines as well, and verify that everything was now drawing correctly, with which I generated the following image:
(I can't embed images apparently, so link: http://i.imgur.com/y5hO1Im.png)
In this image, the red, blue and green lines are drawn along the negative axes, whereas the purple, yellow and cyan lines are drawn along the positive axes. What's really weird about this is that the image is showing that the camera is in the +X and +Z range, but internally, the position vector of the camera is in the -X and -Z range. This would make sense as to why the chunks were loading on the opposite axis, as if the camera was rendering on +X but was internally at a position of -X, then the -X chunks would be loaded instead.
So I'm not sure what's going on here anymore. I'm sure there's a small setting or incorrect positive/negative that I'm missing, but I just can't seem to find anything. So I guess my question is, is the camera rendering correctly with the internal position? If so, do I need to just reverse everything that I render? If not, is there something clearly visible in the camera that is messing up the rendering?
Some snippets of relevant code, trying to not to overflow the post with code blocks
Camera.java
public class Camera {
// Camera position
private Vector3f position = new Vector3f(x, y, z);
// Camera view properties
private float pitch = 1f, yaw = 0.0f, roll = 0.0f;
// Mouse sensitivity
private float mouseSensitivity = 0.25f;
// Used to change the yaw of the camera
public void yaw(float amount) {
this.yaw += (amount * this.mouseSensitivity);
}
// Used to change the pitch of the camera
public void pitch(float amount) {
this.pitch += (amount * this.mouseSensitivity);
}
// Used to change the roll of the camera
public void roll(float amount) {
this.roll += amount;
}
// Moves the camera forward relative to its current rotation (yaw)
public void walkForward(float distance) {
position.x -= distance * (float)Math.sin(Math.toRadians(yaw));
position.z += distance * (float)Math.cos(Math.toRadians(yaw));
}
// Moves the camera backward relative to its current rotation (yaw)
public void walkBackwards(float distance) {
position.x += distance * (float)Math.sin(Math.toRadians(yaw));
position.z -= distance * (float)Math.cos(Math.toRadians(yaw));
}
// Strafes the camera left relative to its current rotation (yaw)
public void strafeLeft(float distance) {
position.x -= distance * (float)Math.sin(Math.toRadians(yaw-90));
position.z += distance* (float)Math.cos(Math.toRadians(yaw-90));
}
// Strafes the camera right relative to its current rotation (yaw)
public void strafeRight(float distance) {
position.x -= distance * (float)Math.sin(Math.toRadians(yaw+90));
position.z += distance * (float)Math.cos(Math.toRadians(yaw+90));
}
// Translates and rotates the matrix so that it looks through the camera
public void lookThrough() {
GL11.glRotatef(pitch, 1.0f, 0.0f, 0.0f);
GL11.glRotatef(yaw, 0.0f, 1.0f, 0.0f);
GL11.glTranslatef(position.x, position.y, position.z);
}
}
Main.java render code
private void render() {
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
GL11.glLoadIdentity();
// Set the view matrix to the player's view
this.player.lookThrough();
// Render the visible chunks
this.chunkManager.render();
// Draw axis
GL11.glBegin(GL11.GL_LINES);
// X Axis
GL11.glColor3f(1, 0, 0);
GL11.glVertex3f(-100, 0, 0);
GL11.glVertex3f(0, 0, 0);
GL11.glColor3f(1, 1, 0);
GL11.glVertex3f(0, 0, 0);
GL11.glVertex3f(100, 0, 0);
// Y Axis
GL11.glColor3f(0, 1, 0);
GL11.glVertex3f(0, -100, 0);
GL11.glVertex3f(0, 0, 0);
GL11.glColor3f(0, 1, 1);
GL11.glVertex3f(0, 0, 0);
GL11.glVertex3f(0, 100, 0);
// Z Axis
GL11.glColor3f(0, 0, 1);
GL11.glVertex3f(0, 0, -100);
GL11.glVertex3f(0, 0, 0);
GL11.glColor3f(1, 0, 1);
GL11.glVertex3f(0, 0, 0);
GL11.glVertex3f(0, 0, 100);
GL11.glEnd();
// Render the origin
this.origin.render();
}
chunkManager.render() just iterates through each of the loaded chunks and calls .render() on them, which in turn creates a giant solid cube that is rendered at the origin of the chunk.
More code can be provided if needed.
Replace
GL11.glTranslatef(position.x, position.y, position.z);
with
GL11.glTranslatef(-position.x, -position.y, -position.z);
Think about it, you want to be translating the world to the inverse of where the camera is so that that 0,0,0 is where the camera is.
I am making a game in Libgdx, in which I want to fall a ball from up word to down word and move background towards up word and update camera according to it. My code is given below...
public WorldRenderer(SpriteBatch spriteBatch, World world){
this.world = world;
this.camera = new OrthographicCamera(FRUSTUM_WIDTH, FRUSTUM_HEIGHT);
this.camera.position.set(FRUSTUM_WIDTH/2, FRUSTUM_HEIGHT/2, 0);
this.spriteBatch = spriteBatch;
positionBGY1 = 0;
positionBGY2 = 0;
}
public void render(World world, float deltaTime){
if(world.ball.position.y > - camera.position.y){
camera.position.y = world.ball.position.y;
}
if(camera.position.y<0)
camera.position.y=world.ball.position.y;
camera.update();
spriteBatch.setProjectionMatrix(camera.combined);
renderBackground();
renderObjects(world, deltaTime);
}
private void calculateBGPosition(){
positionBGY2 = positionBGY1 + (int)FRUSTUM_HEIGHT;
if(camera.position.y >= positionBGY2){
positionBGY1 = positionBGY2;
}
}
private void renderBackground() {
spriteBatch.disableBlending();
spriteBatch.begin();
spriteBatch.draw(Assets.gamebackgroundRegion, camera.position.x - FRUSTUM_WIDTH / 2, positionBGY1 - FRUSTUM_HEIGHT / 2, FRUSTUM_WIDTH, 1.5f * FRUSTUM_HEIGHT);
spriteBatch.draw(Assets.gamebackgroundRegion2, camera.position.x - FRUSTUM_WIDTH / 2, positionBGY2 - FRUSTUM_HEIGHT / 2, FRUSTUM_WIDTH, 1.5f * FRUSTUM_HEIGHT);
calculateBGPosition();
spriteBatch.end();
}
Problem with my code is background screen is not moving and camera is not updated with ball movement and ball fall down out of screen.
Well, first thing you need to do is change one of the bg variables, so in render somehwere do something like:
float speed = 1;
positionBGY1+=deltaTime*speed;
positionBGY2+=deltaTime*speed;
As far as the camera moving with the ball I would just do this:
camera.position.y = Math.min(ball.y,0);
And I would in turn omit all of this:
if(world.ball.position.y > - camera.position.y){
camera.position.y = world.ball.position.y;
}
if(camera.position.y<0)
camera.position.y=world.ball.position.y;
Best way to achieve this is using ParrallaxLayer and ParrallaxBackground classes
it optimised the background operation so that u dont have to worry about the performance