Making a triangle rotate in LWJGL3 with keycallback - java

So, how do I rotate a triangle by pressing Up, Down, Left or Right. I have a Keyboard class which can read keys and create events. But I don't know the function for rotating in LWJGL 3. I think I'm familiar with the classic gl.h way of rotating, but since LWJGL 3 is pretty new there aren't alot of information on this. Here is code for Display class and KeyboardHandler class.
Display
public class Driver implements Runnable{
private GLFWKeyCallback keyCallback;
private Thread thread = new Thread();
private boolean running = false;
public long window;
private static final int WIDTH = 600;
private static final int HEIGHT = WIDTH / 12 * 9;
public Driver(){
}
private synchronized void start(){
thread.start();
running = true;
}
private synchronized void stop(){
try {
thread.join();
running = false;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void run(){
init();
while(running){
render();
update();
if(glfwWindowShouldClose(window) == GL_TRUE){
running = false;
keyCallback.release();
}
}
}
public void init() {
if(glfwInit() != GL_TRUE){
System.err.println("Failed to initilaize OpenGL");
}
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
window = glfwCreateWindow(WIDTH, HEIGHT, "Endless", NULL, NULL);
if(window == NULL){
System.err.println("Could not create window. ");
}
glfwSetKeyCallback(window, keyCallback = new KeyboardHandler());
ByteBuffer vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor());
glfwSetWindowPos(window, 100, 100);
glfwMakeContextCurrent(window);
glfwShowWindow(window);
}
public void update() {
if(KeyboardHandler.isKeyDown(GLFW_KEY_LEFT)){
//event who'll start rotation
}
glfwPollEvents();
}
public void render() {
GLContext.createFromCurrent();
glBegin(GL_TRIANGLES);
glColor3f(1.0f, 0.0f, 0.0f);
glVertex2f(-1.0f / 2, -1.0f / 2);
glColor3f(0.0f, 1.0f, 0.0f);
glVertex2f(0.0f / 2, 1.0f / 2);
glColor3f(0.0f, 0.0f, 1.0f);
glVertex2f(1.0f / 2, -1.0f / 2);
glEnd();
//rotation of triangle
glfwSwapBuffers(window);
}
public static void main(String[] args) {
Driver game = new Driver();
game.start();
game.run();
}
}
And KeyboardHandler
public class KeyboardHandler extends GLFWKeyCallback{
private static boolean keys[] = new boolean[65536];
public void invoke(long window, int key, int scancode, int action, int mods)
{
keys[key] = action != GLFW_RELEASE;
}
public static boolean isKeyDown(int keycode){
return keys[keycode];
}
}
I guess the rotation itself should happen in render() while the keycallback who triggers it should be in update()

With the introduction of LWJGL 3, you must use shaders to rotate, scale, and transform your objects. You can find many resources on the internet that show you how to do this, one of them being the OpenGL programming WikiBook. Specifically, in tutorial four, which deals with rotating objects in modern OpenGL

Related

Memory Leakage. Constantly rises until game crashes

I'm new to android development and I'm having a problem regarding the memory used by my game. It constantly rises until it crashes. I would appreciate if you could help me. Thank you.
Also, regarding the Spritebatch do i need to call this.dispose in the java class where i extend to game for it to be disposed? If so where can i call it? Thank you
public class Zero implements Screen, InputProcessor {
Pmacgame game;
private Stage stage;
private Skin skin;
private Sound sound ,laser;
private Music musicbg;
private Sprite spritebg, playerImage;
private ImageButton imgbtnLeft, imgbtnRight, fire, color1, color2, color3, color4,
bullet1, bullet2, bullet3, bullet4;
public static final float fireDelay = 0.3f;
String rr2;
private static int o = 0;
Rectangle player;
ArrayList<Bullet> bullets;
ArrayList<Target> targets;
ArrayList<Explode> explodes;
//long lastDrop;
int score;
boolean a, b;
public static final float minSpawnTime = 0.5f;
public static final float maxSpawnTime = 1.25f;
float shootTimer, targetSpawnTimer;
Random random;
public static int select;
public static int dis = 0;
public float health = 1;
private Sprite greenBar, redBar, blueBar, pinkBar, greenBarO, redBarO, blueBarO, pinkBarO;
public Zero(Pmacgame game){
#Override
public void render(float delta) {
shootTimer += Gdx.graphics.getDeltaTime();
ArrayList<Bullet> bulletsToRemove = new ArrayList<>();
if (fire.isPressed() && shootTimer >= fireDelay) {
shootTimer = 0;
bullets.add(new Bullet(player.x + 32f));
}
for (Bullet bullet : bullets) {
bullet.update(Gdx.graphics.getDeltaTime());
if (bullet.remove)
bulletsToRemove.add(bullet);
}
targetSpawnTimer -= Gdx.graphics.getDeltaTime();
if (targetSpawnTimer<=0){
targetSpawnTimer = random.nextFloat() * (maxSpawnTime -minSpawnTime) + minSpawnTime;
targets.add(new Target(MathUtils.random(267, Gdx.graphics.getWidth()-350f)));
}
ArrayList<Target> targetsToRemove = new ArrayList<>();
for (Target target: targets){
target.update(delta);
if (target.remove)
targetsToRemove.add(target);
if (target.getY()<=0){
health -= 0.1f;
if (health<=0){
select = 0;
dis = 1;
this.dispose();
game.setScreen(new GameOverScreen(game, score));
return;
}
}
}
ArrayList<Explode> explodesToRemove = new ArrayList<>();
for (Explode explode: explodes){
explode.update(delta);
if (explode.remove)
explodesToRemove.add(explode);
}
explodes.removeAll(explodesToRemove);
for (Bullet bullet: bullets){
for (Target target: targets){
if (bullet.getCollisionRect().collidesWith(target.getCollisionRect())){
targetsToRemove.add(target);
bulletsToRemove.add(bullet);
score+=5;
explodes.add(new Explode(target.getX(), target.getY()));
sound.play(1f, 1.3f, 0f);
}
}
}
targets.removeAll(targetsToRemove);
bullets.removeAll(bulletsToRemove);
//Gdx.gl.glClearColor(0f, 0f, 0f, 1f);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
game.batch.begin();
spritebg.draw(game.batch);
game.batch.draw(blueBarO, 0, 575, blueBarO.getWidth(), blueBarO.getHeight());
game.batch.draw(redBarO, 0, 550, redBarO.getWidth(), redBarO.getHeight());
game.batch.draw(greenBarO, 0, 525, greenBarO.getWidth(), greenBarO.getHeight());
game.batch.draw(pinkBarO, 0, 600, pinkBarO.getWidth(), pinkBarO.getHeight());
game.font.draw(game.batch, "SCORE: " + score, 40, Gdx.graphics.getHeight() - 40 );
for (Bullet bullet: bullets){
bullet.render(game.batch);
}
for (Target target: targets){
target.render(game.batch);
}
for (Explode explode: explodes){
explode.render(game.batch);
}
if (health == 0) greenBar.setSize(greenBar.getWidth(), 0f);
game.batch.draw(greenBar, 0, 525, greenBar.getWidth() * health, greenBar.getHeight());
game.batch.draw(redBar, 0, 550, redBar.getWidth(), redBar.getHeight());
game.batch.draw(blueBar, 0, 575, blueBar.getWidth(), blueBar.getHeight());
game.batch.draw(pinkBar, 0, 600, pinkBar.getWidth(), pinkBar.getHeight());
game.batch.draw(playerImage, player.x, player.y, player.width, player.height);
game.batch.end();
stage.act(Gdx.graphics.getDeltaTime());
stage.draw();
if (a) player.x -= 450 * Gdx.graphics.getDeltaTime();
if (b) player.x += 450 * Gdx.graphics.getDeltaTime();
if (player.x < 65f + imgbtnLeft.getWidth() + imgbtnRight.getWidth())
player.x = 65f + imgbtnLeft.getWidth() + imgbtnRight.getWidth();
if (player.x > Gdx.graphics.getWidth() - 350f)
player.x = Gdx.graphics.getWidth() - 350f;
}
#Override
public void dispose () {
musicbg.dispose();
laser.dispose();
stage.dispose();
skin.dispose();
sound.dispose();
}
}
public class Pmacgame extends Game {
SpriteBatch batch;
BitmapFont font;
#Override
public void create () {
batch = new SpriteBatch();
font = new BitmapFont(Gdx.files.internal("r.fnt"));
this.setScreen(new Zero(this));
}
#Override
public void render () {
super.render();
}
#Override
public void dispose() {
font.dispose();
batch.dispose();
}
}
I'm reading between the lines, but it looks like you must be loading a Texture in the constructor of Bullet/Target/Explosion, since I don't see you passing a Texture or TextureRegion reference to their constructors or render methods.
You should be loading all your Textures in a single class and passing references to your game objects for them to "borrow" and draw with. Otherwise, you are loading many copies of the same images for no reason.
Also, a Texture is a Disposable, which means it uses native memory and must have dispose() called on it before you let the garbage collector take it. Otherwise, the native memory is leaked.
In your case, all these Bullets, Targets, and Explosions are loading many Textures over and over and never disposing them when you remove them.
Regarding your question about the SpriteBatch. Yes, you should dispose of it in the same class you instantiate it, and dispose() is the right place to do it.
Edit, barebones example:
public class Assets implements Disposable {
public final Texture horse;
public final Texture bullet;
// etc.
public Assets (){
horse = new Texture("horse.png");
//...
}
public void dispose(){
horse.dispose();
//...
}
}
public class Zero implements Screen, InputProcessor {
private final Assets assets;
//...
public Zero (){
assets = new Assets();
//...
}
//...
public void dispose(){
assets.dispose();
//...
}
}
public class Bullet {
//...
public void render(SpriteBatch batch, Assets assets){
batch.render(assets.bullet, /*...*/);
}
}

JFrame screen is flashing white and black

I have a problem where my JFrame is constantly flashing white and black, but I only set the colour to black. I think it has to do with the while (running) {} bit.
It just turns white and black forever, until I close it. I really don't know what is going on.. I only just started to use JFrame so I'm sure I have just put some wrong code.
public class Game extends Canvas implements Runnable {
private static final long serialVersionUID = 1L;
public static int width = 300;
public static int height = width / 16 * 9;
public static int scale = 3;
public static boolean running = false;
private Thread thread;
private JFrame frame;
public Game() {
Dimension window = new Dimension(width * scale, height * scale);
setPreferredSize(window);
frame = new JFrame();
}
public synchronized void start() {
running = true;
thread = new Thread(this, "Display");
thread.start();
}
public synchronized void stop() {
try {
running = false;
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void run() {
while (running) {
render();
}
}
public void update() {
}
public void render() {
BufferStrategy buffer = getBufferStrategy();
if (buffer == null) {
createBufferStrategy(3);
return;
}
Graphics g = buffer.getDrawGraphics();
g.setColor(Color.BLACK);
g.drawRect(0, 0, getWidth(), getHeight());
g.dispose();
buffer.show();
}
public static void main(String[] args) {
Game game = new Game();
game.frame.setResizable(false);
game.frame.setTitle("Game");
game.frame.add(game);
game.frame.pack();
game.frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
game.frame.setLocationRelativeTo(null);
game.frame.setVisible(true);
game.start();
}
}
Solved it myself... I used the method drawRect() And I read the documentation page and it says it only draws the outline of the rectangle.. So I just did drawRect()
Also I changed the buffer to 2.
Sorry for wasting your time.

No GLCapabilities instance has been set for the current thread

I've been trying OpenGL, following ThinMatrix's tutorials. Only thing I'm doing differently is he was using lwjgl 2 and i'm using 3. I thought it would be a good challenge, and it has definitely proven to be. It say's no glcapabilities have been set but I'm pretty sure I set them already!
Basically the full error I'm getting is
Exception in thread "main" java.lang.IllegalStateException: No GLCapabilities instance has been set for the current thread.
at org.lwjgl.opengl.GL.getCapabilities(GL.java:211)
at org.lwjgl.opengl.GL20.getInstance(GL20.java:378)
at org.lwjgl.opengl.GL20.glCreateShader(GL20.java:464)
at net.robharding.base.shaders.ShaderProgram.loadShader(ShaderProgram.java:67)
at net.robharding.base.shaders.ShaderProgram.<init>(ShaderProgram.java:17)
at net.robharding.base.shaders.StaticShader.<init>(StaticShader.java:9)
at net.robharding.base.engine.Display.init(Display.java:77)
at net.robharding.base.engine.Display.<init>(Display.java:31)
at net.robharding.base.MainComponent.main(MainComponent.java:8)
To me, this makes no sense because I Did do GL.CreateCapabilities();, and I can't find anything online about this error...
package net.robharding.base.engine;
import org.lwjgl.glfw.*;
import org.lwjgl.opengl.*;
import net.robharding.base.shaders.StaticShader;
import static org.lwjgl.glfw.GLFW.*;
import static org.lwjgl.system.MemoryUtil.*;
public class Display {
private String title;
private int width, height;
#SuppressWarnings("unused")
private GLFWErrorCallback errorCallback;
#SuppressWarnings("unused")
private GLFWKeyCallback keyCallback;
private long windowID;
private Loader loader;
private Renderer renderer;
private StaticShader shader;
public Display(String title, int width, int height) {
this.title = title;
this.width = width;
this.height = height;
init();
}
private void keyPressed(int key, int scancode, int mods) {
}
private void keyReleased(int key, int scancode, int mods) {
if(key == GLFW_KEY_ESCAPE)
glfwSetWindowShouldClose(windowID, GLFW_TRUE);
}
private void init() {
// Setup an error callback. The default implementation
// will print the error message in System.err.
glfwSetErrorCallback(errorCallback = GLFWErrorCallback.createPrint(System.err));
if(glfwInit() != GLFW_TRUE)
throw new IllegalStateException("Unable to initialize GLFW");
glfwDefaultWindowHints();
glfwWindowHint(GLFW_VISIBLE, GLFW_TRUE);
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
windowID = glfwCreateWindow(width, height, title, NULL, NULL);
if(windowID == NULL)
throw new RuntimeException("Failed to create the GLFW window");
glfwSetKeyCallback(windowID, keyCallback = new GLFWKeyCallback() {
#Override
public void invoke(long window, int key, int scancode, int action, int mods) {
if(action == GLFW_PRESS)
keyPressed(key, scancode, mods);
else if(action == GLFW_RELEASE)
keyReleased(key, scancode, mods);
}
});
GLFWVidMode vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor());
glfwSetWindowPos(windowID, (vidmode.width() - width) / 2, (vidmode.height() - height) / 2);
glfwMakeContextCurrent(windowID);
glfwSwapInterval(1);
loader = new Loader();
renderer = new Renderer();
shader = new StaticShader();
glfwShowWindow(windowID);
}
public void run() {
GL.createCapabilities();
GL11.glViewport(0, 0, width, height);
float[] vertices = {
-0.5f, 0.5f, 0, // V1
-0.5f, -0.5f, 0, // V2
0.5f, -0.5f, 0, // V3
0.5f, 0.5f, 0 // V4
};
int[] indices = {
0, 1, 3,
3, 2, 1
};
RawModel model = loader.loadToVAO(vertices, indices);
while(glfwWindowShouldClose(windowID) == GLFW_FALSE) {
renderer.prepare();
shader.start();
renderer.render(model);
shader.stop();
glfwSwapBuffers(windowID);
glfwPollEvents();
}
shader.cleanUp();
loader.cleanUp();
}
}
Here is the method where it's tracing back to.
private static int loadShader(String file, int type) {
StringBuilder shaderSource = new StringBuilder();
try {
BufferedReader reader = new BufferedReader(new FileReader(file));
String line;
while((line = reader.readLine()) != null) {
shaderSource.append(line).append("\n");
}
reader.close();
} catch(IOException e) {
System.err.print("Count not read file!");
e.printStackTrace();
System.exit(-1);
}
int shaderID = GL20.glCreateShader(type);
GL20.glShaderSource(shaderID, shaderSource);
GL20.glCompileShader(shaderID);
if(GL20.glGetShaderi(shaderID, GL20.GL_COMPILE_STATUS) == GL11.GL_FALSE) {
System.out.println(GL20.glGetShaderInfoLog(shaderID, 500));
System.err.println("Could not compile shader!");
System.exit(-1);
}
return shaderID;
}
Your code tries to use OpenGL before you have created the context.
The init method in which the shader is created is called in the constructor, but the context is created in the begin of the run method. To solve this, move the call of the init method to the run method after GL.createCapabilities();.
Please also note, that OpenGL contexts are always associated with exactly one thread. So all OpenGL commands have to be issued from this one thread.

How to zoom in and out on a stage in libgdx Scene2d?

I am making a 2d game using libgdx and am adding hexagon shaped actors to a group which is then added to a stage. For a normal camera you can use camera.zoom in the render method to zoom in and out along with camera.translate to pan around the world.
I have been getting the camera used by the stage using stage.getCamera() and I can still call stage.getcamera().translate however there is no stage.getCamera().zoom option.
Here is my code:
//import statements
public class HexGame implements ApplicationListener{
private Stage stage;
private Texture hexTexture;
private Group hexGroup;
private int screenWidth;
private int screenHeight;
#Override
public void create() {
hexTexture = new Texture(Gdx.files.internal("hex.png"));
screenHeight = Gdx.graphics.getHeight();
screenWidth = Gdx.graphics.getWidth();
stage = new Stage(new ScreenViewport());
hexGroup = new HexGroup(screenWidth,screenHeight,hexTexture);
stage.addActor(hexGroup);
}
#Override
public void dispose() {
stage.dispose();
hexTexture.dispose();
}
#Override
public void render() {
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
stage.act(Gdx.graphics.getDeltaTime());
stage.draw();
handleInput();
stage.getCamera().update();
}
private void handleInput() {
if (Gdx.input.isKeyPressed(Input.Keys.LEFT)) {
stage.getCamera().translate(-3, 0, 0);
}
if (Gdx.input.isKeyPressed(Input.Keys.RIGHT)) {
stage.getCamera().translate(3, 0, 0);
}
if (Gdx.input.isKeyPressed(Input.Keys.DOWN)) {
stage.getCamera().translate(0, -3, 0);
}
if (Gdx.input.isKeyPressed(Input.Keys.UP)) {
stage.getCamera().translate(0, 3, 0);
}
//This is the part that doesn't work
/*
if (Gdx.input.isKeyPressed(Input.Keys.Z)) {
stage.getCamera().zoom += 0.02;
}
*/
}
#Override
public void resize(int width, int height) {
stage.getViewport().update(width, height);
}
#Override
public void pause() {
}
#Override
public void resume() {
}
}
Any help is appreciated, and if there is anything else wrong with my code please let me know, I'm new to libgdx. Thanks
Zoom is available in OrthographicCamera class and by default Stage class create a OrthographicCamera
/** Creates a stage with a {#link ScalingViewport} set to {#link Scaling#stretch}. The stage will use its own {#link Batch}
* which will be disposed when the stage is disposed. */
public Stage () {
this(new ScalingViewport(Scaling.stretch, Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), new OrthographicCamera()),
new SpriteBatch());
ownsBatch = true;
}
So what you need is to cast your camera to OrthographicCamera:
((OrthographicCamera)stage.getCamera()).zoom += 0.02f;

Speeding up rotation fluently

When I press down 'A' the square is speeding up its own rotation, but when I release 'A' it's rotating fasted than before but looks slower than when pressing 'A'.
package backend;
import java.nio.ByteBuffer;
import org.lwjgl.glfw.*;
import org.lwjgl.opengl.*;
import static org.lwjgl.glfw.GLFW.*;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.system.MemoryUtil.*;
public class runGame {
private long window;
private GLFWKeyCallback keyCallback;
private GLFWErrorCallback errorCallback;
public static void main(String[] args) {
new runGame().run();
}
private void run() {
try {
init();
loop();
glfwDestroyWindow(window);
keyCallback.release();
} finally {
glfwTerminate();
}
}
private static final int width = 640;
private static final int height = 480;
private void init() {
glfwSetErrorCallback(errorCallback);
if(glfwInit() != GL11.GL_TRUE) {
throw new IllegalStateException("Unable to initialize GLFW");
}
glfwDefaultWindowHints();
glfwWindowHint(GLFW_VISIBLE, GL_FALSE);
//glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
window = glfwCreateWindow(width, height, "mazeRunner Game", 0, 0);
if (window == NULL)
throw new RuntimeException("Failed to create the GLFW window");
glfwSetKeyCallback(window, keyCallback = new GLFWKeyCallback() {
#Override
public void invoke(long window, int key, int scancode, int action, int mods) {
if( key == GLFW_KEY_ESCAPE && action == GLFW_RELEASE ) {
glfwSetWindowShouldClose(window, GL_TRUE);
}
if( key == GLFW_KEY_A && action == GLFW_PRESS ) {
speedUp = true;
}
if( key == GLFW_KEY_A && action == GLFW_RELEASE ) {
speedUp = false;
}
}
});
ByteBuffer glfwvidmode = glfwGetVideoMode(glfwGetPrimaryMonitor());
glfwSetWindowPos(window,
(GLFWvidmode.width(glfwvidmode)-width)/2,
(GLFWvidmode.height(glfwvidmode)-height)/2);
glfwMakeContextCurrent(window);
glfwSwapInterval(1);
glfwShowWindow(window);
GLContext.createFromCurrent();
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
float aspect_ratio = ((float)height) / width;
glFrustum(.5, -.5, -.5 * aspect_ratio, .5 * aspect_ratio, 1, 50);
glMatrixMode(GL_MODELVIEW);
}
private final double fps = 60.0f;
private double time;
private void loop() {
time = glfwGetTime();
while(glfwWindowShouldClose(window) == GL_FALSE) {
if(glfwGetTime()-time>=1/fps) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
time = glfwGetTime(); draw();
glfwSwapBuffers(window);
glfwPollEvents();
}
}
}
private void draw() {
glLoadIdentity();
glTranslatef(0.0f, 0.0f, -3.0f);
if(speedUp==true) speed = speed+0.9f;
drawSquare(1.0f, 0.0f, 0.0f);
}
boolean speedUp;
private float speed = 20.0f;
private void drawSquare(float red,float green,float blue) {
glRotatef(speed*(float)time, 0.0f, 0.0f, 1.0f);
glBegin(GL_QUADS); // Draw The Cube Using quads
{
glColor3f(red, green, blue);
glVertex2f(0, 0);
glColor3f(red * .8f, green * .8f, blue * .8f);
glVertex2f(0, 1);
glColor3f(red * .5f, green * .5f, blue * .5f);
glVertex2f(1, 1);
glColor3f(red * .8f, green * .8f, blue * .8f);
glVertex2f(1, 0);
}
glEnd(); // End Drawing The Cube
}
}
The problem with different speed is related to the way you are handling the time. The variable 'time' will contain the total time since the program start when you calculate the rotation angle.
glRotatef(speed*(float)time, 0.0f, 0.0f, 1.0f);
This means that the speed difference is applied not just to the current frame but all previous frames since the program start as well. This is the reason why the rotation is faster than expected when pressing 'a' key.
It's easy to verify this. If you press 'a' directly when the program starts and you see that the speed difference is minimal. Now wait a minute or so and press 'a' again. Now the speed difference is much higher since the accumulated time is higher.
To solve the problem you probably should change the rotation calculation so that the frame time is used instead of the total program time. I.e. store the current rotation angle in a variable which you increase each frame based on the speed and frame time.

Categories

Resources