I'm attempting to make a short game for my family for christmas using libgdx and when going forward through the level the edge of the screen flickers but when going backwards there is no flickering and it's quite annoying.
Here is a demo of what I mean.
Also, here is my code:
if (direction == "right") {
body.setTransform(body.getPosition().x + 1 / PPM, body.getPosition().y, body.getAngle());
b2dCam.position.x += (1 / PPM);
camera.position.x += (1*(PPM/(8/2)));
} else if (direction == "left") {
b2dCam.translate(-1 / PPM, 0);
camera.translate(-1*(PPM/(8/2)), 0);
}
tmr.setView(camera);
tmr.render();
camera.update();
b2dCam.update();
b2dr.render(world, b2dCam.combined);
cntrlOverlay.act();
cntrlOverlay.draw();
world.step(1 / 60f, 6, 2);
Any help would be greatly appreciated, thanks.
I just solved this issue by calling camera.update before everything else so instead of:
tmr.setView(camera);
tmr.render();
camera.update();
b2dCam.update();
b2dr.render(world, b2dCam.combined);
cntrlOverlay.act();
cntrlOverlay.draw();
world.step(1 / 60f, 6, 2);
I now use:
camera.update();
tmr.setView(camera);
tmr.render();
b2dCam.update();
b2dr.render(world, b2dCam.combined);
cntrlOverlay.act();
cntrlOverlay.draw();
world.step(1 / 60f, 6, 2);
Two things come to mind.
Do your tiles have at least 2px of padding around them?
When OpenGL pulls textures from an image, it blends the pixels surrounding the texture region you are using with the edge of the texture region. Annoying huh? But there are reasons for it. I couldn't tell for sure, but your video looks like you are getting horizontal gutters (the flickering at the bottom and between the house and the ground).
To fix this, each tile on your image asset needs to have at least 2 pixels of padding all around it. To create the padding, create a 2px wide border around each tile in your image and then copy the edge pixels of the tile into this 2px wide border.
VSync
If you still have issues after trying suggestion 1, I have had some flickering issues with libgdx scrolling when vsync was disabled. You can make sure it is enabled in your "Launcher" classes with:
LwjglApplicationConfiguration cfg = new LwjglApplicationConfiguration();
cfg.vSyncEnabled = true;
Related
so I'm working on a game where I would like to have the camera in game centered on the middle of the screen for all device lengths. I hope this picture can better explain what I'm trying to achieve. I have tried setting the position of the camera but that hasn't worked for me.
scrnHeight = Gdx.graphics.getHeight();
if (scrnHeight <= HEIGHT) {
cam.setToOrtho(false, 480, 800);
} else {
cam.setToOrtho(false, 480, scrnHeight);
}
//This is the part that seems to be giving me all the issues
cam.position.set(cam.viewportWidth/2,cam.viewportHeight/2, 0);
cam.update();
Gdx.input.setInputProcessor(this);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
gsm.update(Gdx.graphics.getDeltaTime());
gsm.render(batch);
batch.begin();
batch.draw(border, -(border.getWidth() - WIDTH) / 2, -(border.getHeight() / 4));
batch.end();
I don't know if I'm giving it the wrong coordinates when I'm setting the position or what is happening that causes the lack of vertical centering. Any help would be much appreciated.
The orthographic camera position in LibGDX means position in-game, not on the device screen, therefore changing it won't actually move the game screen on the device.
Therefore, you use the camera position to move and position the camera in-game.
For example, in response to player input movement:
if (Gdx.input.isKeyPressed(Input.Keys.LEFT)) {
cam.translate(-3, 0, 0); // Moves the camera to the left.
}
if (Gdx.input.isKeyPressed(Input.Keys.RIGHT)) {
cam.translate(3, 0, 0); // Moves the camera to the right.
}
As you can see, we are moving the camera in-game, left and right according to the player's input.
However, your code has a few more issues like not setting the batch projection matrix:
batch.setProjectionMatrix(cam.combined);
And resetting the camera position to the center of the viewport each frame:
// Don't run this each frame, it resets the camera position!
cam.position.set(cam.viewportWidth/2,cam.viewportHeight/2, 0);
cam.update(); // <- However, you must run this line each frame.
Finally, centering the LibGDX app on the device screen should be done outside of Libgdx, otherwise, if you intend to use the spare screen for the same LibGDX app, then you should create another camera to work full screen and render it before the actual game camera, usually used for HUD and such...
I pretty much finished my LibGDX project and now I'm just adding user-friendliness.
I have a Texture (also placed in a sprite) that I would like to fade in and fade out repeatedly (NOT fast blinking). It's just rectangular funky-text that says "Touch to Start".
I considered making an animation of 6 or so pictures with varying opacity and just keep changing slides. Is this the best way to go?
I'm also looking for a libGDX effect that controls the transparency to avoid all the overhead and not make my animation choppy.
Can't think of any relevant code to add, Thanks for your help
EDIT
Gdx.gl.glClearColor(0, 0, 0.2f, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.begin();
batch.draw(touchToStartImage, screenWidth / 2 - touchToStartImage.getWidth() / 2, screenHeight / 2 - touchToStartImage.getHeight() / 2);
elapsed += Gdx.graphics.getDeltaTime();
blinkFontCache.setAlphas(Interpolation.fade.apply((elapsed / 0.01f) % 1f));
blinkFontCache.draw(batch);
blinkFontCache.translate(2f, 2f);
batch.end();
I also defined blinkFontCache = new BitmapFontCache(numberPrinter); where numberPrinter is bitmapfont that is supposed to draw text. I've read the API guide for Interpolation and blinkFontCache, but unfortunately with the above I do not notice any change in the screen I have. Thanks
SOLUTION
EDIT with INTERPOLATION
elapsed += Gdx.graphics.getDeltaTime();
touchToStartSprite.setAlpha(Interpolation.fade.apply((elapsed / FADE_TIME) % 1f));
blinker.begin();
touchToStartSprite.draw(batch);
blinker.end();
EDIT with ACTIONS
definitions
text = new Image(highScoreImage);
text.addAction(Actions.alpha(0));
text.act(0);
text.addAction(Actions.forever(Actions.sequence(Actions.fadeIn(FADE_TIME), Actions.fadeOut(FADE_TIME))));
render()
blinker.begin();
text.act(Gdx.graphics.getDeltaTime());
text.draw(blinker, 1);
blinker.end();
You could use the Image class from scene2d, which is an actor that can take a texture region and gives you several methods that can be useful. Here's an implementation.
Image text = new Image(clickToStartRegion);
Float fadeTime = 1f;
//...
text.addAction(Actions.alpha(0)); //make the text transparent.
text.act(0); //update the text once
text.addAction(Actions.sequence(Actions.fadeIn(fadeTime), Actions.fadeOut(fadeTime));
//...
text.act(deltaTime);
//...
text.draw(batch, 1);
You can use the Interpolation class for the alpha. Assuming you're using a Sprite to draw this:
private float elapsed;
private static final float FADE_TIME = 1f; //time between blinks
//...
elapsed += deltaTime;
sprite.setAlpha(Interpolation.fade.apply((elapsed / FADE_TIME) % 1f));
//...
spriteBatch.begin();
sprite.draw(spriteBatch);
spriteBatch.end();
I'm trying to get the lights and reflection correct in my program. I have a big sphere, which I can move the the mouse, that should be a light source (LIGHT0), and smaller spheres bouncing around that should reflect the light. I also need a directional light that I can change the direction using the keyboard
first some colors I defined:
float whitish[] = {0.8f, 0.8f, 0.8f, 1};
float white[] = {1, 1, 1, 1};
float blackish[] = {0.2f, 0.2f, 0.2f, 1};
float black[] = {0, 0, 0, 1}
I create the directional light with
gl.glLightfv(GL.GL_LIGHT1, GL.GL_AMBIENT, blackish,0);
gl.glLightfv(GL.GL_LIGHT1, GL.GL_SPECULAR, white,0);
gl.glLightfv(GL.GL_LIGHT1, GL.GL_DIFFUSE, white,0);
gl.glLightfv(GL.GL_LIGHT1, GL.GL_POSITION, spot_position,0);
spot_position is initially [ 0, 0, 1, 0] but it can change by pressing the keyboard keys. a key press adds 0.05 to a specific component of the position vector, until it reaches 1, then it resets back to -1 (nothing fancy).
The light of the center sphere is:
gl.glLightfv(GL.GL_LIGHT0, GL.GL_POSITION, position,0);
gl.glLightfv(GL.GL_LIGHT0, GL.GL_AMBIENT, blackish,0);
gl.glLightfv(GL.GL_LIGHT0, GL.GL_DIFFUSE, white,0);
gl.glLightfv(GL.GL_LIGHT0, GL.GL_SPECULAR, white,0);
This light's position is always centered inside my big transparent sphere. w component of the position vector is 1.
I have this code to draw the picture in the back
gl.glBegin(GL_QUADS);
gl.glMaterialfv(GL.GL_FRONT, GL.GL_DIFFUSE, white,0);
gl.glMaterialfv(GL.GL_FRONT, GL.GL_SPECULAR, white,0);
gl.glMaterialfv(GL.GL_FRONT, GL.GL_SHININESS, white,0);
// Back Face
gl.glNormal3f(0, 0, 1);
gl.glTexCoord2f(texRight, texBottom);
gl.glVertex3f(rx2, ry1, rz1);
gl.glTexCoord2f(texRight, texTop);
gl.glVertex3f(rx2, ry2, rz1);
gl.glTexCoord2f(texLeft, texTop);
gl.glVertex3f(rx1, ry2, rz1);
gl.glTexCoord2f(texLeft, texBottom);
gl.glVertex3f(rx1, ry1, rz1);
To draw the spheres, I use the following functions:
public void drawtriangle(float[] v1, float[] v2, float[] v3) {
gl.glBegin(GL.GL_TRIANGLES);
gl.glNormal3fv(v1, 0);
gl.glVertex3fv(v1, 0);
gl.glNormal3fv(v2, 0);
gl.glVertex3fv(v2, 0);
gl.glNormal3fv(v3, 0);
gl.glVertex3fv(v3, 0);
gl.glEnd();
}
private void subdivideSphere2(float v1[], float v2[], float v3[], long depth) {
float v12[] = new float[3];
float v23[] = new float[3];
float v31[] = new float[3];
int i;
if (depth==0) {
float[] color= {v1[0]*v1[0], v2[1]*v2[1], v3[2]*v3[2], alpha};
gl.glMaterialfv(GL.GL_FRONT, GL.GL_AMBIENT, blackish,0);
gl.glMaterialfv(GL.GL_FRONT, GL.GL_DIFFUSE, color,0);
gl.glMaterialfv(GL.GL_FRONT, GL.GL_SPECULAR, color,0);
gl.glMaterialfv(GL.GL_FRONT, GL.GL_SHININESS, color,0);
drawtriangle(v1, v2, v3);
return;
}
for (i = 0; i<3; i++) {
v12[i] = v1[i]+v2[i];
v23[i] = v2[i]+v3[i];
v31[i] = v3[i]+v1[i];
}
normalize(v12);
normalize(v23);
normalize(v31);
subdivideSphere2(v1, v12, v31, depth-1);
subdivideSphere2(v2, v23, v12, depth-1);
subdivideSphere2(v3, v31, v23, depth-1);
subdivideSphere2(v12, v23, v31, depth-1);
}
public void drawSphere() {
subdivideSphere2(sVdata[0], sVdata[1], sVdata[2], depth);
subdivideSphere2(sVdata[0], sVdata[2], sVdata[4], depth);
subdivideSphere2(sVdata[0], sVdata[4], sVdata[5], depth);
subdivideSphere2(sVdata[0], sVdata[5], sVdata[1], depth);
subdivideSphere2(sVdata[3], sVdata[1], sVdata[5], depth);
subdivideSphere2(sVdata[3], sVdata[5], sVdata[4], depth);
subdivideSphere2(sVdata[3], sVdata[4], sVdata[2], depth);
subdivideSphere2(sVdata[3], sVdata[2], sVdata[1], depth);
}
My problem is, the small spheres aren't reflecting light at all. They are very bright all the time. I can see a little bit of the light being reflected in the green lines of the cube when I move the big sphere closer to them, but no effect at all to the spheres. Also, I can't see any difference when I move the directional light (LIGHT1). I don't see any reflection on the lines of the cube, the big sphere, small spheres or the picture in the back. Below is screenshot of my program. How can I make my spheres not shine, and reflect both the directional light and the light from the big sphere? Any help would be greatly appreciated. Thank you.
It looks like the lightning is disabled when tracing your small spheres. I don't see the code where you call the drawSphere but it really looks like you are tracing the Big sphere with GL_LIGHTING enabled and the small spheres with GL_LIGHTING disabled.
By reflect the light do you mean that it is illuminated? Reflection involves ray tracing and is a much bigger subject.
I don't have direct experience with JOGL but I've used jME3 a fair amount and this sort of problem there is usually caused either by using an unlit material (which doesn't seem to be the case here as you say it is being lit a bit), by bad normals on the object, or by simply having the ambient light and/or the ambient color of the material turned up too high.
As far as I can tell you are not setting the normals correctly. A normal should basically point into the direction you want to reflect the light to, which is usually "90° away" from the triangle (use the cross product). OpenGL will then use that normal to calculate the actual lighting reflected by the surface. See this tutorial for further explanation.
The other problem is that you use the outdated OpenGL 2.0 functionality, which does vertex-based lighting, so effectively each triangle in your sphere is lightened to the same value. If you are looking for per-pixel lighting, which is close to impossible using the outdated functionality unless the sphere has as many vertices as it has pixels on the screen, you need to update your code and use Shaders.
This tutorial isn't Java, but it explains the basics of modern OpenGL very well, and should be easily translatable to JOGL.
So, I'm new to OpenGL and trying to create a 2D Multiplayer game, I know how to do all of the networking, although the graphics portion is honestly kicking my buttox.
I have tried looking at NiftyGUI aswell as TWL as they have been recommended a-lot, although I can't seem to get a grasp of them as there aren't very many tutorials and no videos to help explain what's going on, not to mention the OpenGL Documentary page is just horribly laid out.
I've attemped drawing a black rectangle, which I was going to go ahead and outline in white somehow and making that a temporary textbox, by drawing white font onto it, although I don't even know how to draw font. These are just a few of the things I'm strugling with that I can't find and I'm aware that I'm going to have to use some libraries, so I'll name the ones I have implemented currently.
LWJGL
Slick2D
I don't have any others currently, besides for TWL but I can't figure out how to use it for the life of me.
Here's the code that I made myself while trying to get a small black rectangle going
void drawTextBox(int fromLeft, int fromTop, int width, int height) {
glColor3f(1.0f, 1.0f, 1.0f);
glBegin(GL_QUADS);
glTexCoord2f(0, 0);
glVertex2i(fromLeft, fromTop); // Upper Left
glTexCoord2f(1, 0);
glVertex2i(fromLeft - width, fromTop); // Uppright
glTexCoord2f(1, 1);
glVertex2i(fromLeft - width, fromTop + height); // Bottom right
glTexCoord2f(0, 1);
glVertex2i(fromLeft, fromTop + height); // bottom left
glEnd();
}
This is working correctly, all but one part... It's drawing the last texture that I have loaded, even though I'm not binding it anywhere in the program, because I've made sure of it. Then it's scaling it to fit into the dimensions of the text-box.
Could someone help me resolve this error and direct me to where I can learn how to set the opacity of quads as-well as draw some text?
Try binding the texture you want right before calling the function. Without knowing how you've "made sure" that the other texture is not being bound, that's all I can say. Also, for changing opacity simply use one of GL11.glColor4_ functions; the last parameter is the alpha (opacity) of the color.
void drawTextBox(int fromLeft, int fromTop, int width, int height) {
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
glColor4f(1.0f, 1.0f, 1.0f, <B>0.5f</B>);
glBegin(GL_QUADS);
glTexCoord2f(0, 0);
glVertex2i(fromLeft, fromTop); // Upper Left
glTexCoord2f(1, 0);
glVertex2i(fromLeft - width, fromTop); // Uppright
glTexCoord2f(1, 1);
glVertex2i(fromLeft - width, fromTop + height); // Bottom right
glTexCoord2f(0, 1);
glVertex2i(fromLeft, fromTop + height); // bottom left
glEnd();
glDisable(GL_BLEND);
}
This block of code allows you to draw a white rectangle with %50 opacity.
Take a look at the BOLDED part (0.5f). This float number defines the opacity of your rectangle. The bigger this number is (0.0f~1.0f), the more the opacity of the rectangle is.
The issue involves an Android Path shape. It's a triangle that I'm using as an arrow to point towards objects on a screen Canvas. This is for a 2d game. player in the middle of the screen, objects around him and offscreen.
These arrows are supposed to rotate around the center of the screen, with a radius so that they rotate in a circle around the player. The arrows point towards objects that the player needs to move towards.
What I have right now is somewhat working, but the arrows are zipping around the circle at ridiculous speeds. Funny enough, they're pointing in the right direction, but they aren't staying at the right point on the circle. (if arrow is pointing northeast, arrow should be on the northeast part of the circle, etc)
I'm sure it's because of the math. I'm probably using atan2 wrong. Or canvas.translate wrong. Or maybe I shouldn't be using atan2 at all. Help! :)
Here is the code:
// set the shape of our radar blips
oBlipPath.moveTo(0, -5);
oBlipPath.lineTo(5, 0);
oBlipPath.lineTo(0, 5);
// Paint all the enemies and radar blips!
for(int i=0; i<iNumEnemies; i++){
if (oEnemies[i].draw(canvas, (int)worldX, (int)worldY)){
//calculate the degree the object is from the center of the screen.
//(user is the player. this could be done easier using iWidth and iHeight probably)
//we use a world coordinate system. worldY and worldX are subtracted
fDegrees = (float)Math.toDegrees(Math.atan2((oEnemies[i].getEnemyCenterY()-worldY)-user.getShipCenterY(), (oEnemies[i].getEnemyCenterX()-worldX)-user.getShipCenterX()));
canvas.save();
//get to the center
canvas.translate((iWidth / 2) , (iHeight / 2) );
//move a little bit depending on direction (trying to make arrows appear around a circle)
canvas.translate((float)(20 * Math.cos(fDegrees)), (float)(20* Math.sin(fDegrees)));
//rotate canvas so arrows will rotate and point in the right direction
canvas.rotate(fDegrees);
//draw arrows
canvas.drawPath(oBlipPath, oBlipPaint);
canvas.restore();
}
}
Affine transformations are are not commutative. They are typically applied in an apparent last-specified-first-applied order. As an alternative, consider the rotate() variation that rotates about a point.
Well, I've got it doing what I wanted, but I don't really know how. I threw in some random numbers until things showed up on the screen the way I wanted. If anyone wants to clue me in as to a better way to do this, I'm all ears.
The code:
// set the shape of our radar blips
oBlipPath.moveTo(0, -5);
oBlipPath.lineTo(6, 0);
oBlipPath.lineTo(0, 5);
oBlipMatrix.setRotate(45, 0, 0);
oBlipPath.transform(oBlipMatrix);
// Paint all the enemies and radar blips!
for(int i=0; i<iNumEnemies; i++){
oEnemies[i].draw(canvas, (int)worldX, (int)worldY);
if (oEnemies[i].bActive){
//calculate the degree the object is from the center of the screen.
//(user is the player. this could be done easier using iWidth and iHeight probably)
//we use a world coordinate system. worldY and worldX are subtracted
fDegrees = (float)Math.toDegrees(Math.atan2((oEnemies[i].getEnemyCenterY()-worldY)-(iHeight / 2), (oEnemies[i].getEnemyCenterX()-worldX)-(iWidth / 2)));
canvas.save();
//get to the center
canvas.translate((iWidth / 2 + 50) , (iHeight / 2 + 50) );
//move a little bit depending on direction (trying to make arrows appear around a circle)
//canvas.translate((float)(20 * Math.cos(fDegrees)), (float)(20* Math.sin(fDegrees)));
//rotate canvas so arrows will rotate and point in the right direction
canvas.rotate(fDegrees-45, -50, -50);
//draw arrows
canvas.drawPath(oBlipPath, oBlipPaint);
canvas.restore();
}
}
For whatever reason, I have to subtract 45 degrees from the canvas rotation, but add 45 degrees to the matrix rotation of the path shape. It works, but why?! :)