When I run this app, it's a little bit shaking. I can't understand, why that happens? What I should to do to circle's pixels don't shake?
public class Main extends ApplicationAdapter {
ShapeRenderer shapeRenderer;
float x,y;
#Override
public void create() {
shapeRenderer = new ShapeRenderer();
x = Gdx.graphics.getWidth() / 2;
y = Gdx.graphics.getHeight() / 2;
}
#Override
public void render() {
//Gdx.gl.glClearColor(0, 0, 0, 1);
//Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
shapeRenderer.begin(ShapeRenderer.ShapeType.Filled);
shapeRenderer.setColor(1, 0, 0, 1);
shapeRenderer.circle(x++, y, 100);
shapeRenderer.end();
}
#Override
public void dispose() {
shapeRenderer.dispose();
}
}
Your render is not being called with the same delta(time interval) between frames causing the perceived speed to judder. Normally with LibGDX the render method is called with the delta i.e. the time since the last render, however, you are using the ApplicationAdapter.
You can compensate though by just getting the delta time yourself and changing your increment from
shapeRenderer.circle(x++, y, 100);
to
x=x+ (Gdx.graphics.getDeltaTime()* incrementConstant);
Adjust the float incrementConstant as you like for speed.
Read this excellent article on adjusting for irregular time steps in games.
https://gafferongames.com/post/fix_your_timestep/
Related
I am creating a top-down shooter game, and whenever I move the camera, or zoom, black likes appear like a grid
I am using Tiled to create the map, and I have the camera following my centered box2d body. I have found that making the camera position equal the position of the box2d body with an int cast results in the black lines disappearing like this:
The problem though, is that because I have the game scaled down, the player will move for a second or two and then when the player reaches the next whole number on either axis, the camera snaps to the player, which is not what I want for the game as it's jarring. The player's movement is granular, but, while rounded, the camera's is not. I do not know if this is a problem with my tile sheet or if it's something I can fix by altering some code. I have tried all different kinds of combinations of padding, and values of spacing and margins. So ultimately, how can I have the camera match the player's position smoothly and not cause the black lines? I'd greatly appreciate any help or recommendations. Thank you in advance!
Where I am type casting the player's float position to an int in game class:
public void cameraUpdate(float delta) {
//timeStep = 60 times a second, velocity iterations = 6, position iterations = 2
world.step(1/60f, 6, 2); //tells game how many times per second for Box2d to make its calculations
cam.position.x = (int)playerOne.b2body.getPosition().x;
cam.position.y = (int)playerOne.b2body.getPosition().y;
cam.update();
}
Majority of player class:
public class PlayerOne extends Sprite implements Disposable{
public World world; // world player will live in
public Body b2body; //creates body for player
private BodyDef bdef = new BodyDef();
private float speed = 1f;
private boolean running;
TextureAtlas textureAtlas;
Sprite sprite;
TextureRegion textureRegion;
private Sound runningSound;
public PlayerOne(World world) {
this.world = world;
definePlayer();
textureAtlas = new TextureAtlas(Gdx.files.internal("sprites/TDPlayer.atlas"));
textureRegion = textureAtlas.findRegion("TDPlayer");
sprite =new Sprite(new Texture("sprites/TDPlayer.png"));
sprite.setOrigin((sprite.getWidth() / 2) / DunGun.PPM, (float) ((sprite.getHeight() / 2) / DunGun.PPM - .08));
runningSound = Gdx.audio.newSound(Gdx.files.internal("sound effects/running.mp3"));
}
public void definePlayer() {
//define player body
bdef.position.set(750 / DunGun.PPM, 400 / DunGun.PPM);
bdef.type = BodyDef.BodyType.DynamicBody;
//create body in the world
b2body = world.createBody(bdef);
FixtureDef fdef = new FixtureDef();
CircleShape shape = new CircleShape();
shape.setRadius(12 / DunGun.PPM);
fdef.shape = shape;
b2body.createFixture(fdef);
}
public void renderSprite(SpriteBatch batch) {
float posX = b2body.getPosition().x;
float posY = b2body.getPosition().y;
float posX2 = (float) (posX - .14);
float posY2 = (float) (posY - .1);
sprite.setSize(32 / DunGun.PPM, 32 / DunGun.PPM);
sprite.setPosition(posX2, posY2);
float mouseX = Level1.mouse_position.x; //grabs cam.unproject x vector value
float mouseY = Level1.mouse_position.y; //grabs cam.unproject y vector value
float angle = MathUtils.atan2(mouseY - getY(), mouseX - getX()) * MathUtils.radDeg; //find the distance between mouse and player
angle = angle - 90; //makes it a full 360 degrees
if (angle < 0) {
angle += 360 ;
}
float angle2 = MathUtils.atan2(mouseY - getY(), mouseX - getX()); //get distance between mouse and player in radians
b2body.setTransform(b2body.getPosition().x, b2body.getPosition().y, angle2); //sets the position of the body to the position of the body and implements rotation
sprite.setRotation(angle); //rotates sprite
sprite.draw(batch); //draws sprite
}
public void handleInput(float delta) {
setPosition(b2body.getPosition().x - getWidth() / 2, b2body.getPosition().y - getHeight() / 2 + (5 / DunGun.PPM));
this.b2body.setLinearVelocity(0, 0);
if(Gdx.input.isKeyPressed(Input.Keys.W)){
this.b2body.setLinearVelocity(0f, speed);
}if(Gdx.input.isKeyPressed(Input.Keys.S)){
this.b2body.setLinearVelocity(0f, -speed);
}if(Gdx.input.isKeyPressed(Input.Keys.A)){
this.b2body.setLinearVelocity(-speed, 0f);
}if(Gdx.input.isKeyPressed(Input.Keys.D)){
this.b2body.setLinearVelocity(speed, 0f);
}if(Gdx.input.isKeyPressed(Input.Keys.W) && Gdx.input.isKeyPressed(Input.Keys.A)){
this.b2body.setLinearVelocity(-speed, speed);
}if(Gdx.input.isKeyPressed(Input.Keys.W) && Gdx.input.isKeyPressed(Input.Keys.D)){
this.b2body.setLinearVelocity(speed, speed);
}
if(Gdx.input.isKeyPressed(Input.Keys.S) && Gdx.input.isKeyPressed(Input.Keys.A)){
this.b2body.setLinearVelocity(-speed, -speed );
}if(Gdx.input.isKeyPressed(Input.Keys.S) && Gdx.input.isKeyPressed(Input.Keys.D)){
this.b2body.setLinearVelocity(speed, -speed);
}
Where I declare the pixels per meter scale:
public class DunGun extends Game{
public SpriteBatch batch;
//Virtual Screen size and Box2D Scale(Pixels Per Meter)
public static final int V_WIDTH = 1500;
public static final int V_HEIGHT = 800;
public static final float PPM = 100; //Pixels Per Meter
Game render and resize methods:
#Override
public void render(float delta) {
cameraUpdate(delta);
playerOne.handleInput(delta);
//clears screen
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
if (Gdx.input.isButtonPressed(Input.Buttons.LEFT)) {
cam.zoom -= .01;
}
if (Gdx.input.isButtonPressed(Input.Buttons.RIGHT)) {
cam.zoom += .01;
}
mapRenderer.render();
b2dr.render(world, cam.combined); //renders the Box2d world
mapRenderer.setView(cam);
//render our game map
//mapRenderer.render(); // renders map
//mapRenderer.render(layerBackround); //renders layer in Tiled that p1 covers
game.batch.setProjectionMatrix(cam.combined); //keeps player sprite from doing weird out of sync movement
mouse_position.set(Gdx.input.getX(), Gdx.input.getY(), 0);
cam.unproject(mouse_position); //gets mouse coordinates within viewport
game.batch.begin(); //starts sprite spriteBatch
playerOne.renderSprite(game.batch);
game.batch.end(); //starts sprite spriteBatch
//mapRenderer.render(layerAfterBackground); //renders layer of Tiled that hides p1
}
#Override
public void resize(int width, int height) {
viewport.update(width, height, true); //updates the viewport camera
}
I solved it by fiddling around with the padding of the tilesets in GDX Texture Packer. I added 5 pixels of padding around the 32x32 tiles. I set the margins to 2, and spacing to 4 in Tiled. I had tried a lot of different combinations of padding/spacing/margins that didn't work which made me think it was a coding problem, but those settings worked, and I didn't have to round the floats.
I want to use libgdx ShapeRenderer to mock my graphics but i get a small nevertheless annoying mismatch of coordinates. As mentioned at libgdx wiki, screen coordinates range: (0,0) (lower left corner) to (Gdx.graphics.getWidth()-1, Gdx.graphics.getHeight()-1) (upper right corner).
Here is a code sample of what i'm trying to do:
public static final int APP_WIDTH = 160;
public static final int APP_HEIGHT = 120;
private SpriteBatch batch;
private ShapeRenderer shapeRenderer;
private Texture texture;
...
public void render() {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
if (DEBUG_MODE) {
shapeRenderer.setAutoShapeType(true);
shapeRenderer.setColor(Color.RED);
shapeRenderer.begin();
shapeRenderer.rect(0, 0, APP_WIDTH - 1, APP_HEIGHT - 1);
shapeRenderer.end();
} else {
batch.begin();
batch.draw(texture, 0, 0);
batch.end();
}
}
And the result i get:
image link
As you can see, texture (160x120) is drawn exactly like it should be but rectangle (that was drawn with shapeRenderer) has -1 x-axis offset.
Of course, I can just draw everything at x+1 but maybe I'm doing something wrong and there is a way to make coordinates match?
I am new to libgdx.
This is what I know:
We can create a rectangular box with red color using this:
shapeRenderer.begin(ShapeType.FilledRectangle);
shapeRenderer.setColor(Color.RED);
shapeRenderer.filledRect(0, 0, 300, 20);
shapeRenderer.end();
What I want to know:
I want this rectangle to persist between different frames.what I want is to create a rectangle object, and increase its length after every 3 seconds or so.
How to do this esactly? as from what i gather, if i use this code in betwen batch.begin() and batch.end() of render, it will create a new box in every frame.
You could create an integer instance in your main class such as shape_length, and have it increase every every 3 second through storing a another variable that would be set to 0 after its accumulated delta time is more than or equal to 3 seconds.
//member functions
private int shape_length = 300;
private float total_time = 0f;
//inside render loop
public void render(float deltaTime){
total_time += deltaTime;
if(total_time >= 3.0f){
//add 1 to length every 3 seconds
shape_length += 1;
total_time = 0.f;
}
shapeRenderer.begin(ShapeType.FilledRectangle);
shapeRenderer.setColor(Color.RED);
shapeRenderer.filledRect(0, 0, shape_length, 20);
shapeRenderer.end();
//fun times here
}
Update: The author wanted a way to have the rectangle as a usable class and not something constantly drawn every frame, so here's an alternative solution:
What could work is that you create a class such as RectShape that could store relative information such as height, width, a Vector2 position, etc, and then have a method on your main class that would specifically render your RectShape as follows:
class RectShape {
private float width;
private float height;
private Vector2 pos;
private Color color;
public RectShape(float w, float h, Vector2 p){
width = w;
height = h;
pos = p;
}
public void increaseLength(){
width += 2.f;
}
//getters: getColor(), getPosition(), getWidth, getHeight()
}
Create a drawRectangle method that takes both the RectShape object and ShapeRenderer
public void drawRectangle(RectShape mainRect, ShapeRenderer renderer){
renderer.begin(ShapeType.FilledRectangle);
renderer.setColor(mainRect.getColor());
renderer.filledRect(mainRect.getPosition().x,mainRect.getPosition().y,mainRect.getWidth(),mainRect.getHeight());
Then, on your main file
//instantiate object
RectShape s = new RectShape(300.f,200.f,new Vector2(3,2));
//render loop
total_time += deltaTime;
if(total_time >= 3.0f){
//add 1 to length every 3 seconds
s.increaseLength();
total_time = 0.f;
}
shapeRenderer.begin();
drawRectangle(s,shapeRenderer);
shapeRenderer.end();
The box is redrawn every frame yes.
To increase the length (a.k.a width) of the rectangle over time you could work with a timer:
In your game class have a variable for length
int rectWidth = 300;
int counter = 0; // And a counter
In your update(float delta) method you can now modify the width of the rectangle.
If your games runs at 60 Frames per second ** , the render method is called 60times/second. So to update the width of the rectangle every 3 seconds do:
public void update(float delta) {
if(counter > 60 * 3) {
rectWidth++;
counter = 0;
}
}
public void render() {
[...]
shapeRenderer.filledRect(0, 0, rectWidth, 20);
[...]
counter++;
}
There are better methods to do time dependent tasks but this should give you a starting point.
** You can define the framerate by setting ForegroundFPS
LwjglApplicationConfiguration cfg = new LwjglApplicationConfiguration();
cfg.foregroundFPS = 60;
In order to increase the rectangles length you need to replace the 300 and 20 with variables.
shapeRenderer.filledRect(0, 0, 300, 20);
should be
shapeRenderer.filledRect(0, 0, rWidth, rHeight);
Then declare those variables in your class
int rWidth,rHeight;
and put this in your default constructor
rWidth=300;
rHeight=20;
Then in your render class you will have a seperate method in the beginning of it that will increase the rWidth and rHeight. To make it grow very quickly you can just put this in the top of your render method.
rWidth++;
rHeight++;
try this for now so you get the idea then you can use Gdx.graphics.getDeltaTime() to adjust it based on time rather than rendering frames.
I am new to LWJGL but am slowly learning. I was wanting to make a square that rotated when you pressed the key. Like d rotates it 90 degrees as you can tell below, but when I use glRotatef(); it gives me an error and I don't know why. There error tells me I need to create a method for it, I know I don't need to though. Anything helps!
public class MainPlayer {
private Draw draw;
private int rotation;
private float WIDTH = (float) (Display.getWidth() * 0.1);
private float HEIGHT = (float) (WIDTH / 2);
private float x = Display.getWidth() / 2 - WIDTH / 2;
private float y = Display.getHeight() / 2 - HEIGHT / 2;
public MainPlayer(){
draw = new Draw(1.0f, 1.0f, 1.0f, WIDTH, HEIGHT);
}
public void update(){
}
public void render(){
glTranslatef(x, y, 0);
glRotatef(rotation,0,0,1);
draw.render();
}
public void getInput(){
if(Keyboard.isKeyDown(Keyboard.KEY_W)){
rotation = 0;
}
if(Keyboard.isKeyDown(Keyboard.KEY_S)){
rotation = 180;
}
if(Keyboard.isKeyDown(Keyboard.KEY_A)){
rotation = 270;
}
if(Keyboard.isKeyDown(Keyboard.KEY_D)){
rotation = 90;
}
}
}
You create an int rotation and I assume your render() loops the whole time, and you only set rotation in getInput().
So I am assuming that you should declare it as int rotation = 0.
glRotatef() is a OpenGL call to rotate objects, just like glTranslatef() moves them. glRotatef() does it in the same way.
glRotatef(AngleOfRotationf, 0, 1, 0) would rotate it horisontally, like in this video i just made: http://www.youtube.com/watch?v=SHsssrj9qr8& uses that line to rotate a ship.
Also in that video i demonstrated moving it with glTranslatef().
To use it you must use GL11.glRotatef(), or import static org.lwjgl.opengl.GL11.*;
That probably means that you haven't statically imported glRotatef
Either use
GL11.glRotatef(rotation, 0, 0, 1);
or import it at the beginning of your program with
import static org.lwjgl.opengl.GL11.glRotatef
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