Hot questions for Using Lightweight Java Game Library in slick

Question:

Trying to work on a game for school and I keep getting a "java.lang.NoClassDefFoundError: org/lwjgl/LWJGLException" when trying to run using eclipse. Any ideas? Here is my code

package javagame;
import org.newdawn.slick.*;
import org.newdawn.slick.state.*;


public class Game extends StateBasedGame{

private static final String GAME_NAME = "TEST";
private static final int MENU = 0;
private static final int PLAY = 1;

public Game(String GAME_NAME){
    super(GAME_NAME);
    this.addState(new Menu(MENU));
    this.addState(new Play(PLAY));
}// end constructor

public void initStatesList(GameContainer gc) throws SlickException{
    this.getState(MENU).init(gc, this);
    this.getState(PLAY).init(gc, this);
    this.enterState(MENU);
}//end initStateList method

public static void main(String[] args) {
    AppGameContainer appgc;
    try{
        appgc = new AppGameContainer(new Game(GAME_NAME));
        appgc.setDisplayMode(640, 360, false);
        appgc.start();
    }//end try
    catch(SlickException e){
        e.printStackTrace();
    }//end catch

}//end main method

}//end Game class

And the full error I am getting.

Exception in thread "main" java.lang.NoClassDefFoundError:    org/lwjgl/LWJGLException
at javagame.Game.main(Game.java:27)
Caused by: java.lang.ClassNotFoundException: org.lwjgl.LWJGLException
at java.net.URLClassLoader$1.run(Unknown Source)
at java.net.URLClassLoader$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
... 1 more

And I'm pretty sure I have this set correct. http://i.imgur.com/YD77T2C.png


Answer:

I figured it out so I will post it in case anyone else having the same problem stumbles upon this page. I had to use an older version of lwjgl.jar, version 2.9.3 worked from the old lwjgl website http://legacy.lwjgl.org/ .

Question:

I have now written high scores to a text file at gameover, and read them at game load. The problem I have now is that the txt file highscores.txt isn't found anywhere because I haven't created it. Is it possible to have the file created whenever it isn't found? Here is the relevant code:

Write highscores to file at gameover:

if(gameOver == true){
        sbg.enterState(5, new FadeOutTransition(), new FadeInTransition());
        if(score > Highscores.highscore3 && score < Highscores.highscore2){
            Highscores.highscore3 = score;
        }else if(score > Highscores.highscore2 && score < Highscores.highscore1){
            Highscores.highscore3 = Highscores.highscore2;
            Highscores.highscore2 = score;  
        }else if(score > Highscores.highscore1){
            Highscores.highscore3 = Highscores.highscore2;
            Highscores.highscore2 = Highscores.highscore1;
            Highscores.highscore1 = score;
        }else Highscores.highscore1 = score;

        //Write highscores to highscores.txt
        try{
            PrintWriter writer = new PrintWriter("highscores.txt", "UTF-8");
            writer.println(String.valueOf(Highscores.highscore1));
            writer.println(String.valueOf(Highscores.highscore1));
            writer.println(String.valueOf(Highscores.highscore1));
            writer.close();
        }catch(Exception e){
            e.printStackTrace();
        }
        gameOver = false;
        gameStart = false;
    }

Read highscores from highscores.txt at program start:

public static void main(String[] args) throws IOException{

    BufferedReader in = new BufferedReader(new FileReader("highscores.txt"));
    String line;

    while((line = in.readLine()) != null){
        System.out.println(line);
    }
    in.close();

I know that I can create a file if it doesn't exist like this:

try{
File save = new File("highscores.txt");
if (!save.exists()){
    save.createNewFile();
System.out.println("\n----------------------------------");
System.out.println("The file has been created.");
System.out.println("------------------------------------");
}

But I don't know how to do that with buffers. Please help!


Answer:

Let me preface by saying I am not familiar with the best practices for storing game related information on a filesystem. That being said, it sounds like you are trying to learn as you develop this, so with that in mind, I would suggest starting out with writing to a simple .txt file.

The basics can actually be found on SO already:

How to create and write to a txt file: How do I create a file and write to it in Java? How to read from a txt file: Reading and displaying data from a .txt file And the Java tutorials for good measure: https://docs.oracle.com/javase/tutorial/essential/io/file.html

What I would do is: 1. Figure out when you want to trigger a write. When do you want to update your high scores file? To me, it looks like this would be in your Gameplay class around ln 158, where you determine that the game has ended:

//Change to GameOverEasy state if gameOver is true
            if(gameOver == true){

2. Figure out when you need to read in your file to populate Highscores. Poking around your code in pastebin, that to me seems like something you would want to do on startup in the main method of your Blop class, before you start loading game states/looping:

        public static void main(String[] args) throws IOException{

            AppGameContainer appgc;
            try{
                    appgc = new AppGameContainer(new Blop(NAME));

                    //Window size
                    appgc.setDisplayMode(960, 640, false);
                    appgc.setShowFPS(false);
                    appgc.setAlwaysRender(true);
                    appgc.setTargetFrameRate(60);
                    appgc.setVSync(true);
                    Display.setIcon(new ByteBuffer[] {
                new ImageIOImageData().imageToByteBuffer(ImageIO.read(new File("res/images/general/Icon16.png")), false, false, null),
                new ImageIOImageData().imageToByteBuffer(ImageIO.read(new File("res/images/general/Icon32.png")), false, false, null)
                });

//TODO: Read in high scores file and populate Highscores class

                    appgc.start();
            }catch(SlickException e){
                    e.printStackTrace();
            }

3. Figure out how to format your text file. You are ordering the scores already, so you could store them that way as well. Either saving one score per line or using a delimiter like "," or "|" would work with what you currently have.

Start with the simple text file, and change to something else if it suits your needs. If this is a test/learning project, I strongly recommend you keep it simple and stick with a simple .txt file until you wrap your head around it a bit more

A few things to keep in mind:

  1. You are going to run into a lot of exception handling. When reading that file in, you will need to determine if your game should fail to start because you could not load the high scores file? On the other side, is it a critical error when you fail to write to that file?
  2. Always be closing

EDIT: Regarding your followup questions, you want to use the actual name of the file you are using. Javadocs are your friend. Regarding your second question, check out some other SO posts. It's pretty well covered.

Question:

So I've recently started making a simple 2-D java game using jlwgl and slick-util. I ran into a problem when trying to load in textures to place on my tiles. I am using slick util to try and load textures in. This is the method I am using to do so.

 public static Texture loadTex(String path, String fileType) {
    Texture tex = null;
    InputStream in = ResourceLoader.getResourceAsStream(path);

    try {
        tex = TextureLoader.getTexture(fileType, in);
    } catch (IOException e) {
        e.printStackTrace();
    }
    return tex;
}

I then set a variable "t" to store a variable to check if the texture loading works.

     Texture t = loadTex("res/grass64.png","PNG");

I use a glQUADS method to draw a textured square.

public static void drawQuadTex(Texture tex, float x, float y, float width,
        float height) {
    tex.bind();
    glTranslatef(x, y, 0);

    glBegin(GL_QUADS);
    glTexCoord2f(0, 0);
    glVertex2f(0, 0);
    glTexCoord2f(1, 0);
    glVertex2f(width, 0);
    glTexCoord2f(1, 1);
    glVertex2f(width, height);
    glTexCoord2f(0, 1);
    glVertex2f(0, height);
    glLoadIdentity();
    glEnd();
}

Calling drawQuadTex...

drawQuadTex(t,0,0,64,64);

I encountered an error:

"Exception in thread "main" java.lang.NoSuchMethodError: org.lwjgl.opengl.GL11.glGetInteger(ILjava/nio/IntBuffer;)V "

I'm not sure what quite is going on. Any assistance would be appreciated as this is my first attempt at any java that's not a simple school assignment. If I need to post anything else, please let me know.


Answer:

The slick-util library is part of slick2d, which is now deprecated and no longer compatible with recent LWJGL versions such as the one which you appear to be using. This is why you are getting this error.

Question:

I am currently using Slick to render a custom chat in a game.

What I want to do, is I want to be able to create a custom "fading" effect for the chat, which smoothly fades from the right to the left. I'm not too great on explaining things in text, so instead I will show an example of what I want.

Example:

I want to render the text bernhardkiv: hello world!, running my regular font renderer, results in this:

And what I want to be able to do, is to cut off the text smoothly, as follows;

And I have no idea how to do that! I believe that this is possible using glScissoring, but I have been trying to use it and nothing seems to be working (nothing happens at all, everything stays the same way).

I would appreciate anyone helping, I essentially want to be able to, instead of rendering at x, y, I want to be able to render at x,y with width string_width - smooth_cut, to be able to make a little fading effect.


Answer:

Disclaimer:

  1. This is new territory for me, but since no one else seems to be answering, I will make an attempt since this question seems kind of interesting to me. I haven't thoroughly tested these code modifications, so there may be bugs/side-effects I am unaware of. Use at your own risk. :-)

  2. The org.newdawn.slick.Font implementation classes (and supporting classes) in the Slick2D library don't appear to be extension-friendly (private members and methods). As far as I can tell, in order to achieve the desired effect, changes are required to be made to some of the these internal Slick2D classes. (The alternative being to copy entire classes and packages.) To my understanding from the question asker's comments, the Slick2D source code is contained within the question asker's project, so making changes to internal Slick2D classes should be workable in this case.

  3. It can be argued that the said classes were not made extension-friendly for a reason, and there may better ways to go about making the changes necessary to make them extensible. I might even go about it differently myself given an actual project and more time. However, the goal of this answer is to show the question asker the essence of how I achieved the desired effect with minimal code changes to the internal Slick2D classes. The question asker can make his/her own decisions how to go about the details of applying these changes to his/her project.

This code uses Slick build 237.


You can see the complete code changes at this github repo. Below I show only the code changes most relevant to achieve the desired fade effect.

Think of each character as being drawn in an GL_QUAD with the four corners each having an RGBA value (as described here where this picture is taken from):

 (x,x,x,1)       (x,x,x,0)
     -----------------
     |               |
     |               |
     |               |
     |               |
     |               |
     |               |
     -----------------
  (x,x,x,1)      (x,x,x,0)

What we are doing is leaving the top left and bottom left corner colors unchanged and changing the top right and bottom right corner colors to have an alpha of 0 (transparent). OpenGL will gradually fade the transparency for us. To do this we extend org.newdawn.slick.Image to create a FadableImage with the following method (which is very similar to Image's drawEmbedded method but does not override it):

public class FadableImage extends Image {

   //.....

    public void drawEmbeddedFaded(float x,float y,float width,float height, Color color, float fadePercentWidth) {
        init();

        //if percent width is set to an invalid amount, default it to 1.
        if(fadePercentWidth < 0.0f || fadePercentWidth > 1.0f)
            fadePercentWidth = 1.0f;

        if (corners == null) {
            GL.glTexCoord2f(textureOffsetX, textureOffsetY);
            GL.glVertex3f(x, y, 0);
            GL.glTexCoord2f(textureOffsetX, textureOffsetY + textureHeight);
            GL.glVertex3f(x, y + height, 0);

            //set the color of x2 and y2 of the quad to 0 alpha
            GL.glColor4f(color.r, color.g, color.b, 0.0f);
            GL.glTexCoord2f(textureOffsetX + textureWidth*fadePercentWidth, textureOffsetY
                    + textureHeight);
            GL.glVertex3f(x + width*fadePercentWidth, y + height, 0);
            GL.glTexCoord2f(textureOffsetX + textureWidth*fadePercentWidth, textureOffsetY);
            GL.glVertex3f(x + width*fadePercentWidth, y, 0);
            //reset the color
            GL.glColor4f(color.r, color.g, color.b, color.a);
        } else {
            corners[TOP_LEFT].bind();
            GL.glTexCoord2f(textureOffsetX, textureOffsetY);
            GL.glVertex3f(x, y, 0);
            corners[BOTTOM_LEFT].bind();
            GL.glTexCoord2f(textureOffsetX, textureOffsetY + textureHeight);
            GL.glVertex3f(x, y + height, 0);
            //set the color of x2 and y2 of the quad to 0 alpha
            GL.glColor4f(color.r, color.g, color.b, 0.0f);
            //corners[BOTTOM_RIGHT].bind();
            GL.glTexCoord2f(textureOffsetX + textureWidth*fadePercentWidth, textureOffsetY
                    + textureHeight);
            GL.glVertex3f(x + width*fadePercentWidth, y + height, 0);
            //corners[TOP_RIGHT].bind();
            GL.glTexCoord2f(textureOffsetX + textureWidth*fadePercentWidth, textureOffsetY);
            GL.glVertex3f(x + width*fadePercentWidth, y, 0);
            //reset the color
            GL.glColor4f(color.r, color.g, color.b, color.a);
        }
    }

}

You can see the diff of what I am about to describe.

In order to use FadableImage, we also need to extend org.newdawn.slick.font.GlyphPage to create FadableGlyphPage. To support FadableGlyphPage we need to modify org.newdawn.slick.font.GlyphPage's constructor and add a new one.

Then we need to modify org.newdawn.slick.UnicodeFont to use our FadableGlyphPage when UnicodeFont loads the glyphs in loadGlyphs.

We change UnicodeFont's drawDisplayList(...) method to call our FadableImage's special drawEmbeddedFaded(...) method for the character at the specified end index of the given string. We also have to make modifications so that the DisplayList caching will be handled correctly.

We add a convenience method to UnicodeFont to draw a string with the character at endIndex-1 faded and drawn to the width percentage specified by fadePercentWidth:

public void drawString(float x, float y, String text, int endIndex, float fadePercentWidth) {
    drawDisplayList(x, y, text, Color.white, 0, endIndex, fadePercentWidth);
}

So the idea is that the last character rendered will be the character at endIndex-1. The fade width percentage is the percentage of the width that will be drawn of the quad containing the character at endIndex-1. So you can play with that parameter to fine tune the effect you want (0.0f to 1.0f). With the fade width percentage set to 0.5f, 50% of the total width of the quad will be drawn. And the fade will be to that 50% width:

 (x,x,x,1)       (x,x,x,0)

     ------------|------------
     |           |            |
     | drawn     | not        |
     |           |  drawn     |
     |           |            |
     |           |            |
     |           |            |
     ------------|------------

  (x,x,x,1)      (x,x,x,0)

Now let's test it with this code:

import java.awt.Font;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.newdawn.slick.AppGameContainer;
import org.newdawn.slick.BasicGame;
import org.newdawn.slick.Color;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.UnicodeFont;
import org.newdawn.slick.font.effects.ColorEffect;

public class TextFadeTest extends BasicGame {

    private final int Y_OFFSET = 50;
    private final org.newdawn.slick.Color bgColor =  new org.newdawn.slick.Color(126, 166, 240);

    private UnicodeFont unicodeFont;

    public TextFadeTest(String gamename) {
        super(gamename);
    }

    @Override
    public void init(GameContainer gc) throws SlickException {
        gc.setShowFPS(false);
        gc.getGraphics().setBackground(bgColor);

        Font awtFont = new Font(Font.SERIF, Font.PLAIN, 36);
        unicodeFont = new UnicodeFont(awtFont);
        unicodeFont.getEffects().add(new ColorEffect(java.awt.Color.WHITE));
        unicodeFont.addAsciiGlyphs();
        unicodeFont.loadGlyphs();
    }

    @Override
    public void update(GameContainer gc, int i) throws SlickException {}

    @Override
    public void render(GameContainer gc, Graphics g) throws SlickException {

        String str = "bernhardkiv: hello world!";
        int y = 0;
        unicodeFont.drawString(10, y, str);
        unicodeFont.drawString(10, y+=Y_OFFSET, str, Color.white, 0, 22);
        unicodeFont.drawString(10, y+=Y_OFFSET, str, 22, 0f);
        unicodeFont.drawString(10, y+=Y_OFFSET, str, 22, 0.10f);
        unicodeFont.drawString(10, y+=Y_OFFSET, str, 22, 0.25f);
        unicodeFont.drawString(10, y+=Y_OFFSET, str, 22, 0.50f);
        unicodeFont.drawString(10, y+=Y_OFFSET, str, 22, 0.75f);
        unicodeFont.drawString(10, y+=Y_OFFSET, str, 22, 0.90f);
        unicodeFont.drawString(10, y+=Y_OFFSET, str, 22, 1.0f);

    }

    public static void main(String[] args) {
        try {
            AppGameContainer appgc;
            appgc = new AppGameContainer(new TextFadeTest("TextFadeTest"));
            appgc.setDisplayMode(640, 480, false);
            appgc.start();
        }
        catch(SlickException ex) {
            Logger.getLogger(TextFadeTest.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

}

Which gives this result:

Question:

On Mac OS X El Capitan, OpenGL version 4.1, my LWJGL 3.0 app hangs when calling the Slick2D function TextureLoader.getTexture()

Here's the code I'm attempting to use to load the texture. It is run on the same thread as the main loop, and is called after the window is set up.

FileInputStream file = new FileInputStream("src/AppIcon.png");
texture = TextureLoader.getTexture("PNG", file);

The file does exist, and the code works fine when I comment out the code for texturing, which is this method

public int loadTexture(String filename){
    Texture texture = null;
    try{
        FileInputStream file = new FileInputStream(filename + ".png");
        //The app freezes here
        texture = TextureLoader.getTexture("png", file);
        //"LOADED" is never printed to the console.
        System.out.println("LOADED");
    }
    catch(FileNotFoundException e){
        e.printStackTrace();
    }
    catch(IOException e){
        e.printStackTrace();
    }
     return texture.getTextureID();
}

The texture I'm attempting to use is a 1024 x 1024 PNG image,

I've also tried using a much smaller 16 x 16 pixel image,

but I get the same result.

Both images are physically okay, no errors are logged, and the last thing that is printed in console is from Slick2D, stating

INFO:Use Java PNG Loader = true

Is this an OS specific bug, or am I doing something wrong?


Answer:

As it turns out, Slick2D is not compatible with GLFW on OS X. Because of this, I had to use the stb binding, which is LWJGL 3.0's STBImage, org.lwjgl.stb.STBImage.

Here's the code that I use

public int loadTexture(String filename){
    ByteBuffer imageBuffer;
    try{
        imageBuffer = readFile(filename);
    }
    catch (IOException e) {
        throw new RuntimeException(e);
    }

    IntBuffer w = BufferUtils.createIntBuffer(1);
    IntBuffer h = BufferUtils.createIntBuffer(1);
    IntBuffer comp = BufferUtils.createIntBuffer(1);

    ByteBuffer image = STBImage.stbi_load_from_memory(imageBuffer, w, h, comp, 0);
    if(image == null){
        throw new RuntimeException("Failed to load image: " + STBImage.stbi_failure_reason());
    }

    this.width = w.get(0);
    this.height = h.get(0);
    this.comp = comp.get(0);

    if(this.comp == 3){
        GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGB, this.width, this.height, 0, GL11.GL_RGB, GL11.GL_UNSIGNED_BYTE, image);
    }
    else{
        GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA, this.width, this.height, 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, image);

        GL11.glEnable(GL11.GL_BLEND);
        GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
    }

    GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR);
    GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR);

    GL11.glEnable(GL11.GL_TEXTURE_2D);

    return GL11.glGenTextures();
}

private ByteBuffer readFile(String resource) throws IOException{
    File file = new File(resource);

    FileInputStream fis = new FileInputStream(file);
    FileChannel fc = fis.getChannel();

    ByteBuffer buffer = BufferUtils.createByteBuffer((int) fc.size() + 1);

    while(fc.read(buffer) != -1);

    fis.close();
    fc.close();
    buffer.flip();

    return buffer;
}

And it works as expected

Question:

I am building a game in Java using some openGL libraries. I have almost finished the application but i have some really ridiculous problem. All I need to to is to change the default color of the text to some other color, in my case its black.

Exactly more than an hour i was trying to make this and every time i start a game the whole window turns into that color... I put the code down there and if any of you have some ideas I would like to consider that.

import java.awt.Font;
import org.newdawn.slick.Color;
import org.newdawn.slick.TrueTypeFont;
import player.Player;


public class GameMenu {

    private TrueTypeFont gameFont;
    private Font font;

    public GameMenu() {

    font = new Font("Times New Roman", Font.BOLD, 24);
    gameFont = new TrueTypeFont(font, false);

 }

    public void drawChangableText(int x, int y, String changableText) {
    gameFont.drawString(x, y, changableText, Color.black);
 }

    public void update() {
    drawChangableText(1330, 700, "Lives " + Player.lives);
    drawChangableText(1330, 750, "Gold " + Player.gold);
 }
}

And then I am calling this update method further somewhere. Let me not forget to mention that if omit 4. parameter of drawString() method, everything works perfectly fine but with white text on the screen.

Once again, if someone could help i would appreciate that. Maybe some of you will mark my question as duplicated but technically its not, someone had the similar problem but in his case he just imported wrong package. Here is the link of the similar problem

LWJGL Drawing colored text to the screen issue


Answer:

You are drawing frames with current color, in this case you're using Color.black for everything in your frame not just the text.

So to avoid something like that you can do this:

public void drawChangableText(int x, int y, String text) {
    //pick your color
    Color.black.bind();
    //do the job
    gameFont.drawString(x, y, text, Color.black);
    //reset the color
    Color.white.bind();
}

Question:

I get this error when I try to load a texture. Any ideas on why this has occured? or if the method has changed since I last used the libraries?

Exception in thread "main" java.lang.NoSuchMethodError: org.lwjgl.opengl.GL11.glGetInteger(ILjava/nio/IntBuffer;)V
at org.newdawn.slick.opengl.renderer.ImmediateModeOGLRenderer.glGetInteger(ImmediateModeOGLRenderer.java:194)
at org.newdawn.slick.opengl.InternalTextureLoader.getTexture(InternalTextureLoader.java:317)
at org.newdawn.slick.opengl.InternalTextureLoader.getTexture(InternalTextureLoader.java:254)
at org.newdawn.slick.opengl.InternalTextureLoader.getTexture(InternalTextureLoader.java:200)
at org.newdawn.slick.opengl.TextureLoader.getTexture(TextureLoader.java:64)
at org.newdawn.slick.opengl.TextureLoader.getTexture(TextureLoader.java:24)
at engine.Loader.loadTexture(Loader.java:39)
at game.Game.main(Game.java:51)

My code to load a texture is this.

public int loadTexture(String fileName){
    Texture texture = null;
    try {
        texture = TextureLoader.getTexture("PNG", new FileInputStream("res/" + fileName + ".png"));
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }

    int textureID = texture.getTextureID();
    textures.add(textureID);
    return textureID;
}

Answer:

Slick-Util is not compatible with LWJGL 3 and it is unsure whether it will be continued. There seems to be a version that works with it, but I haven't tried it.

The LWJGL developers recommend using the included STB library for loading textures because it is still being developed, lightweight and quite good at loading simple files. You can have a look at the tests and the getting started guide for examples of how to use it.

Question:

Is it possible to change size of panel in NiftyGui while the application is running? I tried this code : //init

 mainScreen = new ScreenBuilder("main") {{
     controller(sc);
     layer(new LayerBuilder("foreground"){{
         childLayoutCenter();
         panel(new PanelBuilder("p1"){{
             childLayoutAbsoluteInside();
             backgroundColor("#00ff00");
             width("100%");
             height("100%");
             padding("10px");
             panel(new PanelBuilder("p4"){{
                 x("100%");y("100%");
                 height("20%");
                 width("20%");
                 backgroundColor("#0000ff");
             }});
         }});
     }});
   }}.build(nifty);

//update()

Element f = nifty.getCurrentScreen().findElementById("p4");
f.getParent().layoutElements();
f.setHeight(f.getHeight() + 300);

and nothing is changing.


Answer:

Ok, I solved this. I was using wrong method. Solution was to use setConstraintHeight(SizeValue) instead of setHeight(int)

`Element f = nifty.getCurrentScreen().findElementById("p4");
f.getParent().layoutElements();
f.setConstraintHeight(new SizeValue(f.getHeight() + 5 + "px"));`

Question:

I am currently testing something out with GLSL, but now whenever I use shaders, my texture doesn't show up on the screen. I have 2 classes. It works without the shaders though...

Main Class

public class Main {

    private static final int WIDTH = 1280;
    private static final int HEIGHT = 720;
    private static int shaderProgram;

    private static int vertexShader;
    private static int fragmentShader;

    private static Terrain terrain;

    public static void main(String[] args) {


        initDisplay();
        initGL();

        terrain = new Terrain();
        terrain.createTerrain();

        createShader();

        gameLoop();

        removeShader();

    }

    private static void gameLoop() {
        while (!Display.isCloseRequested()) {
            glClear(GL_COLOR_BUFFER_BIT);
            glUseProgram(shaderProgram);

            terrain.drawTerrain();
            glUseProgram(0);


            Display.update();
            Display.sync(60);

        }
    }

    private static void initGL() {
        glMatrixMode(GL_PROJECTION);

        glLoadIdentity();

        glOrtho(0, WIDTH, 0, HEIGHT, -1, 1);

        glMatrixMode(GL_MODELVIEW);

        glDisable(GL_DEPTH_TEST);
        glEnable(GL_TEXTURE_2D);

        glClearColor(0, 0, 0, 1);
    }

    private static void initDisplay() {
        try {
            Display.setDisplayMode(new DisplayMode(WIDTH, HEIGHT));
            Display.create();

        } catch (LWJGLException e) {
            e.printStackTrace();
        }
    }

    private static void createShader() {
        shaderProgram = glCreateProgram();
        vertexShader = glCreateShader(GL_VERTEX_SHADER);
        fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
        StringBuilder vertexShaderSource = new StringBuilder();
        StringBuilder fragmentShaderSource = new StringBuilder();
        try {
            BufferedReader reader = new BufferedReader(new FileReader("src/me/mateo226/shaders/vertexShader.txt"));
            String line;
            while ((line = reader.readLine()) != null) {
                vertexShaderSource.append(line).append("\n");
            }
            reader.close();
        } catch (IOException e) {
            System.err.println("Vertex shader wasn't loaded properly!");
            Display.destroy();
            System.exit(1);
        }
        try {
            BufferedReader reader = new BufferedReader(new FileReader("src/me/mateo226/shaders/fragmentShader.txt"));
            String line;
            while ((line = reader.readLine()) != null) {
                fragmentShaderSource.append(line).append("\n");
            }
            reader.close();
        } catch (IOException e) {
            System.err.println("Fragment shader wasn't loaded properly!");
            Display.destroy();
            System.exit(1);
        }

        glShaderSource(vertexShader, vertexShaderSource);
        glCompileShader(vertexShader);
        if (glGetShader(vertexShader, GL_COMPILE_STATUS) == GL_FALSE) {
            System.err.println("Vertex shader not compiled!");
        }
        glShaderSource(fragmentShader, fragmentShaderSource);
        glCompileShader(fragmentShader);
        if (glGetShader(fragmentShader, GL_COMPILE_STATUS) == GL_FALSE) {
            System.err.println("Fragment shader not compiled!");
        }

        glAttachShader(shaderProgram, vertexShader);
        glAttachShader(shaderProgram, fragmentShader);
        glLinkProgram(shaderProgram);
        glValidateProgram(shaderProgram);
    }

    private static void removeShader() {

        glDeleteProgram(shaderProgram);
        glDeleteShader(vertexShader);
        glDeleteShader(fragmentShader);
        Display.destroy();
    }

}

Terrain Class

public class Terrain {
    private static List<Tile> tiles = new ArrayList<Tile>();

    public Terrain() {

    }

    public void createTerrain() {
        Random rand = new Random();
        for (int i = 0; i < 20; i++) {
            for (int j = 0; j < 15; j++) {
                int r = rand.nextInt(2);
                tiles.add(new Tile(i * 64, j * 64, r));
            }
        }
    }

    public void drawTerrain() {
        for (Tile t : tiles) {
            t.draw();
        }
    }

}

class Tile {

    int type = 0;

    private float x = 0;
    private float y = 0;
    private float width = 64;
    private float height = 64;

    private Texture tex;

    public Tile(float x, float y, int type) {
        this.type = type;
        this.x = x;
        this.y = y;
        try {
            if (this.type == 1) {
                tex = TextureLoader.getTexture("PNG", new FileInputStream(new File("res/grass.png")));
            } else {
                tex = TextureLoader.getTexture("PNG", new FileInputStream(new File("res/grass.png")));
            }
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public void draw() {
        tex.bind();
        glBegin(GL_QUADS);
        {
            glTexCoord2f(0, 0);
            glVertex2f(x, y);
            glTexCoord2f(0, 1);
            glVertex2f(x, y + height);
            glTexCoord2f(1, 1);
            glVertex2f(x + width, y + height);
            glTexCoord2f(1, 0);
            glVertex2f(x + width, y);
        }
        glEnd();
    }

}

While it may seem like a lot of code, it really isn't, just a simple program. However I am still unable to figure out what makes it not work. My vertex shader just has:

gl_Position = ftransform();

I tried adding gl_FragColor to the fragment shader but it doesn't help. Cheers!


Answer:

If you don't want to do anything with the texture e.g. lighting, you just have to assign texture2D(TexSampler, TexCoord) to the gl_FragColor in your frag shader. That's because fragment shader will take care of each pixel (fragment) on screen (in current shader program). If you don't assign any value to the gl_FragColor variable, nothing will drawn. What you want is to assign your texture (a bunch of pixels) to the gl_FragColor and you're good to go.

Question:

I've got Eclipse IDE for Java Developers Version: Neon.3 Release (4.6.3)

I loaded LWJGL3, the latest version 3.1.2. I've added it (like here) to a test project (Hello World from lwjgl.org/guide) and it works without setting anything (...like natives...).

Then i added Sling2D (like here) except for setting the Natives Library Location because in the latest version of lwjgl3 there is no natives folder with native<OS>.dll files! It's only 1 folder with only .jar files.

If i run the Hello World test project (from here) I got the following error:

"Exception in thread "main" java.lang.UnsatisfiedLinkError: no lwjgl64 in java.library.path"

I read everywhere I have to set the Natives Library Location to the lwjgl/native folder with the OS-specific .dll files but i haven't this folder!


Answer:

The answer is: You cant. Slick2D is made to work with lwjgl 2, lwjgl 3 however is way newer than Slick2D and therefore Slick2D does not support using lwjgl 3. I'd recommend you to use the newest 2.9.x version of lwjgl if you want to use Slick2D.

There might be a workaround though see: http://slick.ninjacave.com/forum/viewtopic.php?f=1&t=7095

Question:

I'm working in Slick2D, a wrapper for the LWJGL. I'm trying to animate/scale the font size of a string, without having the performance cost of creating a new Font and TrueTypeFont each render. Here's what I currently have:

public void render(GameContainer gc, StateBasedGame sbg, Graphics g) throws SlickException {
    Font pulsingFont = new Font("Verdana", Font.PLAIN, (int) Math.abs(Math.sin(frameCount) * 20) + 10);
    TrueTypeFont pulsing = new TrueTypeFont(pulsingFont, true);
    pulsing.drawString(200, 200, "Pulsing Text", Color.black);
}

public void update(GameContainer gc, StateBasedGame sbg, int DELTA) throws SlickException {
    frameCount += 0.1;
}

The only way I know to change to font size is in Font, which means I also need to make a new instance of a TrueTypeFont every single frame. Just these lines alone cause massive lag.

So is there a way to animate a font size without create a new instance each frame?


Answer:

Yes you can scale the Graphics component. This will scale everything though, so make sure to rescale it after you are down with rendering you text.

Note that you will have to adapt your x/y position due to the increment/decrement of your graphics scale.

From the Slick2d doc: http://slick.ninjacave.com/javadoc/org/newdawn/slick/Graphics.html :

    scale(float sx, float sy) 
    Apply a scaling factor to everything drawn on the graphics context

That means you could scale up or down the graphics component. Render your text. Rescale your graphics component back to normal. Do the rest of your rendering.

Question:

I followed this: https://www.youtube.com/watch?v=5stQZqOAM70 tutorial online. (exported to runnable jar file, then made jar file with jarsplice). I included all the necessary jars and natives like he explained, but when I try to run the application I get an alert box that says this: LoadLibrary failed with error 1114.

Please speak up if you need to see any files or code. Help me! I am using Eclipse


Answer:

Ok, managed to "fix" my problem. The problem was not with the jar file itself, but with my computer. Turns out Java 1.8 has some problems on the intel 3000 graphics card, which is the one I have. I downgraded to 1.7 and the runnables are now working perfectly ;) Sent the jar to a friend of mine, and he was also able to run it without problems

Question:

I've searched this site for a definitive answer to my problem but it seems that everyone has a different answer as to the origin of the problem but no specific solutions.

I'm using the Slick-Util library with lwjgl and when I load my texture file for my basic shape, the program take a bit longer to start (as opposed to being instantaneous without the texture loading) and despite the fact that I get my texture on screen, I get this error in the console (which could explain the initial loading lag)

Sat Mar 07 05:35:42 EST 2015 WARN:class org.newdawn.slick.opengl.PNGImageData failed to read the data
java.lang.UnsupportedOperationException: Unsupported format for this image

the code where I load the file:

public int loadTexture(String fileName)
{
    Texture texture = null;
    try {
        texture = TextureLoader.getTexture("PNG", new FileInputStream("res/" + fileName + ".png"));
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
    int textureID = texture.getTextureID();
    textures.add(textureID);
    return textureID;
}

I'm using a regular png file, non-interlaced, 8 bits 256 x 256 without transparency. Any idea why i get this error, how I can prevent it and if I could use something else than slick-util that would not give me that error?

A file that works:

and one that does not:


Answer:

I found a solution to the annoyance of having to use regular paint to draw all my textures:

  1. Create the image in paint.net as usual despite the compatibility problem.

  2. Select all and copy the entire image.

  3. Open a new document in regular paint and paste the texture to it.

  4. Save the image with regular paint as a .PNG and everythign should be working fine!

If your texture is already saved in a file that throws an error with slick utils, open it and repeat steps 2-4

Question:

I'm creating a game using LWJGL and Slick Utils. I'm trying to load an animated texture as a set of frames contained in a single PNG image.

I have tried to figure out how to get subimages using Slick, but so far all I've been able to find on the subject is a way to do it outside of Slick using BufferedImages. I'd like to know if there is a way to do this using the Slick Utils library, since all of my image loading code in my project so far has been using Slick.


Answer:

Sure, Slick provides a way to do this. If you look at org.newdawn.slick.SpriteSheet.initImpl() and later org.newdawn.slick.SpriteSheet.getSprite(), you will notice how org.newdawn.slick.Image.getSubImage() can be used to quickly extract specific portions of an existing image.

SpriteSheet.java

protected void initImpl() {
    if (subImages != null) {
        return;
    }

    int tilesAcross = ((getWidth()-(margin*2) - tw) / (tw + spacing)) + 1;
    int tilesDown = ((getHeight()-(margin*2) - th) / (th + spacing)) + 1; 
    if ((getHeight() - th) % (th+spacing) != 0) {
        tilesDown++;
    }

    subImages = new Image[tilesAcross][tilesDown];
    for (int x=0;x<tilesAcross;x++) {
        for (int y=0;y<tilesDown;y++) {
            //extract parts of the main image and store them in an array as sprites
            subImages[x][y] = getSprite(x,y);
        }
    }
}

/**
 * Get a sprite at a particular cell on the sprite sheet
 * 
 * @param x The x position of the cell on the sprite sheet
 * @param y The y position of the cell on the sprite sheet
 * @return The single image from the sprite sheet
 */
public Image getSprite(int x, int y) {
    target.init();
    initImpl();

    if ((x < 0) || (x >= subImages.length)) {
        throw new RuntimeException("SubImage out of sheet bounds: "+x+","+y);
    }
    if ((y < 0) || (y >= subImages[0].length)) {
        throw new RuntimeException("SubImage out of sheet bounds: "+x+","+y);
    }
    //Call Image.getSubImage() to get a portion of the image
    return target.getSubImage(x*(tw+spacing) + margin, y*(th+spacing) + margin,tw,th); 
}

You should be able to use that as reference. I remember having fully ported the Tiled renderer bundled with Slick to Java2D once, using the old good PixelGrabber to extract sprites.

And if you decide to use SpriteSheet, you can find an example of use in org.newdawn.slick.tiled.Layer.render():

Layer.java

public void render(int x, int y, int sx, int sy, int width, int ty,
        boolean lineByLine, int mapTileWidth, int mapTileHeight) {
    for (int tileset = 0; tileset < map.getTileSetCount(); tileset++) {
        TileSet set = null;

        for (int tx = 0; tx < width; tx++) {
            if ((sx + tx < 0) || (sy + ty < 0)) {
                continue;
            }
            if ((sx + tx >= this.width) || (sy + ty >= this.height)) {
                continue;
            }

            if (data[sx + tx][sy + ty][0] == tileset) {
                if (set == null) {
                    set = map.getTileSet(tileset);
                    set.tiles.startUse();
                }

                int sheetX = set.getTileX(data[sx + tx][sy + ty][1]);
                int sheetY = set.getTileY(data[sx + tx][sy + ty][1]);

                int tileOffsetY = set.tileHeight - mapTileHeight;

                //Call SpriteSheet.renderInUse() to render the sprite cached at slot [sheetX, sheetY]
                set.tiles.renderInUse(x + (tx * mapTileWidth), y
                        + (ty * mapTileHeight) - tileOffsetY, sheetX,
                        sheetY);
            }
        }

        if (lineByLine) {
            if (set != null) {
                set.tiles.endUse();
                set = null;
            }
            map.renderedLine(ty, ty + sy, index);
        }

        if (set != null) {
            set.tiles.endUse();
        }
    }
}

SpriteSheet.java

public void renderInUse(int x,int y,int sx,int sy) {
    //Draw the selected sprite at (x,y), using the width/height defined for this SpriteSheet
    subImages[sx][sy].drawEmbedded(x, y, tw, th);
}

Hope this helps you.

Question:

How can I rotate the text drawing with Unicodefont. I can draw text using any font in this way.

UnicodeFont font = new UnicodeFont(fontpath,fontsize, false, false);
font.drawString(0,0,"hoge");

But I can not find any rotation method. If I can convert the drawing text to Image object, I can rotate.


Answer:

Kenichi. To rotate the text, you must do the following. Add the following line to the top of your file in the imports: import static org.lwjgl.opengl.GL11.*; After this, you must modify your code to say this: UnicodeFont font = new UnicodeFont(fontpath,fontsize, false, false); glRotatef(90, 0, 0, 1); font.drawString(0,0,"hoge"); The glRotatef(float, float, float, float) method is part of LWJGL and rotates on the Z axis 90 degrees.

Question:

I am creating a simple 2D game for my computer class. I already have a box that moves around through a level. But, i want to change this box to instead display a stickman standing that I drew. Then, more specifically, i would like in my MovementInput class (where i assign movements to the buttons), I want when neither A(my moving left button) or D(my moving right button) OR when both A and D are held down to display this standing.png image. How would i go about doing this?!

This is my code for drawing the box

public class Man extends AbstractMoveableEntity {
    public Man(double x, double y, double width, double height) {
        super(x, y, width, height);
    }
    @Override
    public void draw() {
        glColor3d(0, 0, 255);
        glRectd(x - width / 2, y, x + width / 2, y + height);
    }
}

And in my MovementInput class, this is my code for the A&D thing

if ((Keyboard.isKeyDown(Keyboard.KEY_D) &&Keyboard.isKeyDown(Keyboard.KEY_A))||(!Keyboard.isKeyDown(Keyboard.KEY_D) && !Keyboard.isKeyDown(Keyboard.KEY_A))) {
    man.setDX(0);
}

Answer:

Use something called Texture Atlases for multiple frames of animation and a simple timer to loop through the frames. ThinMatrix on YouTube has a really good tutorial for this here as well as many other concepts.

Question:

Whenever I draw my display list my slick util text wont render properly.

While using glCallList:

Without using glCallList:

Rendering the display list:

    if (dlLocation != -1) {
        GL11.glPushMatrix();

        GL11.glTranslatef(x, y, 0);
        GL11.glCallList(dlLocation);

        GL11.glPopMatrix();
    }

All of the display lists are created with this method:

private static int createDisplayList(Texture t, int width, int height) {
    int returnInt = glGenLists(1);

    glNewList(returnInt, GL_COMPILE);
    {
        t.bind();
        glEnable(GL_TEXTURE_2D);
        glColor4f(1, 1, 1, 1);
        glBegin(GL_QUADS);
        {
            glTexCoord2f(0, 0);
            glVertex2f(0, 0);

            glTexCoord2f(1, 0);
            glVertex2f(width, 0);

            glTexCoord2f(1, 1);
            glVertex2f(width, height);

            glTexCoord2f(0, 1);
            glVertex2f(0, height);
        }
        glEnd();
        glDisable(GL_TEXTURE_2D);
    }
    glEndList();

    return returnInt;
}

I'm rendering the text using slick-util's TrueTypeFont.


Answer:

Placing glBindTexture ( in your case t.bind() ) outside of glNewList might help.

glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texture)
glCallList(newList)
glBindTexture(GL_TEXTURE_2D, 0)

Question:

For some reason, my game will NOT freeze when the level starts, while the menu loads just fine! The game will freeze when the boss music starts. EDIT: Sorry, I found out that the screen froze because the canMove variables were stuck to false. But, the game will still randomly crash and say the image can not be found.

Here is my code:

This is the menu (Which works fine):

//Sprite sheeting
private SpriteSheet sleepSpriteSheet;
private Animation sleepAnimation;
private SpriteSheet walkSpriteSheet;
private Animation walkAnimation;

//System info
private String operatingSystem = Client.getOS();

//Game texuring
private static String IntroBackground = "res/images/level/IntroBackground.png";
private static String KnightQuestLogo = "res/images/icons/KnightQuestLogo.png";

//Menu Info
private static boolean readyForIntro = false;
private static boolean readyForPlay = false;
private static boolean showArrow = false;
private static String playButton = Button.PlayButton;
private static boolean playerSleeping = true;
private static boolean knightWalking = false;
private static float knightX = 145;
private static float knightY = 456;
private static float knightQuestLogoX = -750;
private static float knightQuestLogoY = 75;
private static boolean soundStarted = false;

public GameMenu(int State) {
}

// Render the game
@Override
public void render(GameContainer GameContainer, StateBasedGame SBG,
        Graphics G) throws SlickException {
    //Draw Background Image
    G.drawImage(new Image(IntroBackground), 0, 0);

    //Choose what animation to use
    if(playerSleeping) {
        sleepAnimation.draw(145, 406, 250, 250);
    }
    else {
        walkAnimation.draw(knightX, knightY, 175, 200);
    }

    //Draw Floor
    G.drawImage(new Image(Block.GroundTile), 0, 656);

    //Draw The Logo
    G.drawImage(new Image(KnightQuestLogo), knightQuestLogoX, knightQuestLogoY);

    //Draw the Play Button
    if(readyForPlay) {
        G.drawImage(new Image(playButton), 750, 315);
        if(showArrow) {
            G.drawImage(new Image(Icon.Arrow), 730, 335);
        }
    }

    //System Info
    G.drawString("Game State: " + this.getID(), 10, 30);
    G.drawString("X:" + Mouse.getX() + " Y:" + Mouse.getY(), 10, 50);
    G.drawString("Your OS: " + operatingSystem, 10, 70);
}

// Update the game
@Override
public void update(GameContainer GameContainer, StateBasedGame SBG,
        int Delta) throws SlickException {
    //Start Sound (Would be started in init(), But the StopSound function will not work if done so.
    if(!soundStarted) {
        PlaySound.playSound("res/sounds/startup/MainMenu.wav");
        soundStarted = true;
    }

    //When ready, slide the logo to the right
    if (readyForIntro) {
        if (knightQuestLogoX < 750.0) {
            knightQuestLogoX += Delta * .5f;
        }
    }

    //When ready, allow the player the press the play button
    if(readyForPlay) {
        if(Mouse.getX() > 755 && Mouse.getX() < 875 && Mouse.getY() > 345 && Mouse.getY() < 400) {
            showArrow = true;
            if(Mouse.isButtonDown(0)) {
                playerSleeping = false;
                knightWalking = true;
            }
        }
        else {
            showArrow = false;
        }
    }

    //If the knight is walking in the intro, slide him off the screen
    if(knightWalking) {
        if(knightX < 1290) {
            knightX += Delta* .5f;
        }
        else {
            SBG.enterState(1, new FadeOutTransition(new Color(Color.black)), new FadeInTransition(new Color(Color.black)));
            PlaySound.stopSound();
            PlaySound.playSound("res/sounds/events/LeaveState.wav");
        }
    }
}

// Initialize the GameState
@Override
public void init(GameContainer GameContainer, StateBasedGame SBG)
        throws SlickException {
    //Start the thread for the Intro
    new Thread(new MenuIntro()).start();

    //Create the Sprite sheets
    sleepSpriteSheet = new SpriteSheet("res/images/characters/knight/spritesheets/SleepAnimation.png", 52, 50);
    sleepAnimation = new Animation(sleepSpriteSheet, 250);
    walkSpriteSheet = new SpriteSheet("res/images/characters/knight/spritesheets/WalkAnimation.png", 35, 48);
    walkAnimation = new Animation(walkSpriteSheet, 75);

}

// Get the ID of the GameState
@Override
public int getID() {
    return 0;
}

// MenuIntro thread
static class MenuIntro implements Runnable {

    @Override
    public void run() {
        try {
            Thread.sleep(3000);
            readyForIntro = true;
            Thread.sleep(4000);
            readyForPlay = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

This is the game level (Which is broken):

//Colors RGB
private static String Grey = "rgb/Grey.png";
private static String Blue = "rgb/Blue.png";
private static String Red = "rgb/Red.png";

// Level Variables
private static boolean stateStarted = false;
private static boolean startBossBattle = false;
private static boolean startedBossBattle = false;
private static boolean startedBossMusic = false;
private static boolean BothTouching = false;

// Player Variables
/* Coordinates, And Direction */
private static float PlayerX = 25;
private static float PlayerY = 470;
private static String Knight = "res/images/characters/knight/Knight.png";
private static String PlayerDirection = "right";
private static int PlayerHealth = 100;
private static boolean PlayerWalking = false;
private static boolean PlayerJumping = false;
private static boolean PlayerJumped = false;
private static float AmountPlayerJumped;
private static boolean PlayerAttacking = false;
private static boolean PlayerCanAttack = true;
private static int PlayerRegenTime = 100;
/* Sprite Sheets */
private static String PlayerLeftSword = "res/images/icons/sword/SwordLeft.png";
private static String PlayerLeftAttackSword = "res/images/icons/sword/SwordLeftAttacking.png";
private static String PlayerRightSword = "res/images/icons/sword/SwordRight.png";
private static String PlayerRightAttackSword = "res/images/icons/sword/SwordRightAttacking.png";
private static String PlayerCurrentSword = PlayerRightSword;
private static String RightKnight = "res/images/characters/knight/ResizedKnightRight.png";
private static String LeftKnight = "res/images/characters/knight/ResizedKnightLeft.png";
/* Everything Else */
private static boolean PlayerCanMove = false;

// AI Variables
/* Coordiantes and Direction */
private static float EnemyX = 1000;
private static float EnemyY = 470;
private static String EnemyKnight = "res/images/characters/knight/Knight.png";
private static String EnemyDirection = "right";
private static int EnemyHealth = 100;
private static boolean EnemyWalking = false;
private static boolean DecidedJump = false;
private static int JumpPossibility = 1;
private static boolean EnemyJumping = false;
private static boolean EnemyJumped = false;
private static float AmountEnemyJumped;
private static boolean EnemyAttacking = false;
private static boolean EnemyCanAttack = true;
private static int EnemyRegenTime = 100;
/* Sprite Sheets */
private static String EnemyLeftSword = "res/images/icons/sword/SwordLeft.png";
private static String EnemyLeftAttackSword = "res/images/icons/sword/SwordLeftAttacking.png";
private static String EnemyRightSword = "res/images/icons/sword/SwordRight.png";
private static String EnemyRightAttackSword = "/res/images/icons/sword/SwordRightAttacking.png";
private static String EnemyCurrentSword = EnemyRightSword;
private static String RightEnemy = "res/images/characters/knight/ResizedKnightRight.png";
private static String LeftEnemy = "res/images/characters/knight/ResizedKnightLeft.png";

/* Everything Else */
private static boolean EnemyTalking = false;
private static String EnemyMessage = "";
private static boolean EnemyCanMove = false;

// Mixed Variables
/* Sprite Sheets */
private static SpriteSheet WalkRightSpriteSheet;
private static Animation WalkRightAnimation;
private static SpriteSheet WalkLeftSprite;
private static Animation WalkLeftAnimation;
private static int SpriteSheetWidth = 135;
private static int SpriteSheetHeight = 188;



// System Variables
private String operatingSystem = Client.getOS();

// Constructor
public FinalBattle(int State) {
}

@Override
public void render(GameContainer GameContainer, StateBasedGame SBG,
        Graphics G) throws SlickException {
    //GameContainer Things
    GameContainer.setShowFPS(false);

    //Level
    /* Draw Background */
    G.drawImage(new Image("res/images/level/FinalBattle.png"), 0, 0);

    /* Draw Floor */
    G.drawImage(new Image(Block.GroundTile), 0, 656);

    //Player
    /* Draw Player */
    if(PlayerWalking) {
        if(PlayerDirection.equalsIgnoreCase("right")) {
            if(!PlayerJumping) {
                WalkRightAnimation.draw(PlayerX, PlayerY, SpriteSheetWidth, SpriteSheetHeight);
            }
            else {
                G.drawImage(new Image(RightKnight), PlayerX, PlayerY);
            }
            G.drawImage(new Image(PlayerCurrentSword), PlayerX + 60, PlayerY + 90);
        }
        if(PlayerDirection.equalsIgnoreCase("left")) {
            if(!PlayerJumping) {
                WalkLeftAnimation.draw(PlayerX, PlayerY, SpriteSheetWidth, SpriteSheetHeight);
            }
            else {
                G.drawImage(new Image(LeftKnight), PlayerX, PlayerY);
            }
            G.drawImage(new Image(PlayerCurrentSword), PlayerX + 6, PlayerY + 90);
        }
    }

    /* Draw his/her sword */
    else {
        if(PlayerDirection.equalsIgnoreCase("right")) {
            G.drawImage(new Image(RightKnight), PlayerX, PlayerY);
            G.drawImage(new Image(PlayerCurrentSword), PlayerX + 60, PlayerY + 90);
        }
        if(PlayerDirection.equalsIgnoreCase("left")) {
            G.drawImage(new Image(LeftKnight), PlayerX, PlayerY);
            G.drawImage(new Image(PlayerCurrentSword), PlayerX + 6, PlayerY + 90);
        }
    }

    /* Draw his/her power level */
    G.setColor(new Color(Color.blue.darker()));
    G.drawString("Knight Power Level", 10, 20);
    G.setColor(new Color(Color.white));
    G.drawImage(new Image(Grey).getScaledCopy(100, 10), 10, 40);
    G.drawImage(new Image(Blue).getScaledCopy(PlayerRegenTime, 10), 10, 40);

    /* Draw his/her health level */
    G.setColor(new Color(Color.red.darker()));
    G.drawString("Knight Health", 10, 60);
    G.setColor(new Color(Color.white));
    G.drawImage(new Image(Grey).getScaledCopy(100, 10), 10, 80);
    G.drawImage(new Image(Red).getScaledCopy(PlayerHealth, 10), 10, 80);

    /* Draw his/her name */
    G.setColor(new Color(Color.red.darker()));
    G.drawString("You\n |\n\\ /", PlayerX + 50, PlayerY - 70);
    G.setColor(new Color(Color.white));


    //Enemy 
    if(EnemyWalking) {
        if(EnemyDirection.equalsIgnoreCase("right")) {
            if(!EnemyJumping) {
                WalkRightAnimation.draw(EnemyX, EnemyY, SpriteSheetWidth, SpriteSheetHeight);
            }
            else {
                G.drawImage(new Image(RightKnight), EnemyX, EnemyY);
            }
            G.drawImage(new Image(EnemyCurrentSword), EnemyX + 60, EnemyY + 90);
        }
        if(EnemyDirection.equalsIgnoreCase("left")) {
            if(!EnemyJumping) {
                WalkLeftAnimation.draw(EnemyX, EnemyY, SpriteSheetWidth, SpriteSheetHeight);
            }
            else {
                G.drawImage(new Image(LeftKnight), EnemyX, EnemyY);
            }
            G.drawImage(new Image(EnemyCurrentSword), EnemyX + 6, EnemyY + 90);
        }
    }

    /* Draw enemy sword */
    else {
        if(EnemyDirection.equalsIgnoreCase("right")) {
            if(!EnemyAttacking) {
                EnemyCurrentSword = EnemyRightSword;
            }
            G.drawImage(new Image(RightKnight), EnemyX, EnemyY);
            G.drawImage(new Image(EnemyCurrentSword), EnemyX + 60, EnemyY + 90);
        }
        if(EnemyDirection.equalsIgnoreCase("left")) {
            if(!EnemyAttacking) {
                EnemyCurrentSword = EnemyLeftSword;
            }
            G.drawImage(new Image(LeftKnight), EnemyX, EnemyY);
            G.drawImage(new Image(EnemyCurrentSword), EnemyX + 6, EnemyY + 90);
        }
    }

    /* Draw enemy power level */
    G.setColor(new Color(Color.blue.darker()));
    G.drawString("Enemy Power Level", 1115, 20);
    G.setColor(new Color(Color.white));
    G.drawImage(new Image(Grey).getScaledCopy(100, 10), 1165, 40);
    G.drawImage(new Image(Blue).getScaledCopy(EnemyRegenTime, 10), 1165, 40);

    /* Draw enemy health level */
    G.setColor(new Color(Color.red.darker()));
    G.drawString("Enemy Health", 1115, 60);
    G.setColor(new Color(Color.white));
    G.drawImage(new Image(Grey).getScaledCopy(100, 10), 1165, 80);
    G.drawImage(new Image(Red).getScaledCopy(EnemyHealth, 10), 1165, 80);

    // System Info (Not used currently)
    /*G.drawString("Game State: " + this.getID(), 10, 30);
    G.drawString("X:" + Mouse.getX() + " Y:" + Mouse.getY(), 10, 50);
    G.drawString("Your OS: " + operatingSystem, 10, 70);
    G.drawString("Player X: " + PlayerY + " Enemy X:" + EnemyX, 10, 170);*/
}

@Override
public void update(GameContainer GameContainer, StateBasedGame SBG,
        int Delta) throws SlickException {

    // Fixes for some stuff that might happen
    if(PlayerY > 470) {
        PlayerY = 470;
    }
    if(EnemyY > 470) {
        EnemyY = 470;
    }

    // Enemy
    if(!EnemyTalking) {
        new Thread(new startFight()).start();
        EnemyTalking = true;
    }
    /* Boss Battle Music */
    if(startBossBattle && !startedBossBattle) {
        if(!startedBossMusic) {
            PlaySound.playSound("res/sounds/events/BossBattleLoop.wav");
            PlaySound.startLoop(1000);
            startedBossMusic = true;
        }
        startedBossBattle = true;
    }

    // Player
    /* Player Movement */
    if(PlayerCanMove) {
        Input playerInput = GameContainer.getInput();
        if(playerInput.isKeyDown(Input.KEY_A)) {
            PlayerX -= Delta*.3f;
            PlayerWalking = true;
            PlayerDirection = "left";
            if(!PlayerAttacking) {
                PlayerCurrentSword = PlayerLeftSword;
            }
        }
        else if(playerInput.isKeyDown(Input.KEY_D)) {
            PlayerX += Delta*.3f;
            PlayerWalking = true;
            PlayerDirection = "right";
            if(!PlayerAttacking) {
                PlayerCurrentSword = PlayerRightSword;
            }
        }
        else {
            PlayerWalking = false;
        }

        /* Player Jumping */
        if(playerInput.isKeyPressed(Input.KEY_SPACE)) {
            if(!PlayerJumped) {
                new Thread(new playerJump()).start();
            }
        }
        if(PlayerJumping) {
            PlayerY -= Delta*.5f;
            AmountPlayerJumped = PlayerY;
        }
        else {
            if(PlayerY < 470) {
                PlayerY += Delta*.5f;
            }
            if(Math.round(PlayerY) == 470 || Math.round(PlayerY) == 471) {
                PlayerJumped = false;
            }
        }

        /* Player Attack */
        if(playerInput.isKeyPressed(Input.KEY_ENTER)) {
            if(PlayerCanAttack) {
                new Thread(new playerAttack()).start();
            }
            else {
            }
        }
    }

    /* Player Collision Detection */
    if(PlayerX < 0) {
        PlayerX = 0;
    }
    if (PlayerX > 1155) {
        PlayerX = 1155;
    }

    //Enemy
    /* Enemy Movement and Jumping */
    if(EnemyCanMove) {
            if(PlayerX < EnemyX) {
                if(PlayerDirection.equalsIgnoreCase("right")) {
                    if(!(EnemyX - 125 < PlayerX)) {
                        EnemyX -= Delta*.2f;
                        EnemyDirection = "right";
                        EnemyWalking = true;
                        BothTouching = false;
                        if(!(EnemyX - 50 < PlayerX)) {
                            if(!DecidedJump) {
                                int Jump = GenerateNumber.generateNumber(JumpPossibility);
                                if(Jump == JumpPossibility) {
                                    new Thread(new enemyJump()).start();
                                }
                                DecidedJump = true;
                            }
                        }
                        else {
                            DecidedJump = false;
                        }
                    }
                    else {
                        EnemyWalking = false;
                        BothTouching = true;
                        if(EnemyRegenTime == 100) {
                            if(EnemyCanAttack) {
                                new Thread(new enemyAttack()).start();
                            }
                        }
                    }
                }
                if(PlayerDirection.equalsIgnoreCase("left")) {
                    if(!(EnemyX - 110 < PlayerX)) {
                        EnemyX -= Delta*.2f;
                        EnemyDirection = "left";
                        EnemyWalking = true;
                        BothTouching = false;
                        if(!(EnemyX + 50 < PlayerX)) {
                            if(!DecidedJump) {
                                int Jump = GenerateNumber.generateNumber(JumpPossibility);
                                if(Jump == JumpPossibility) {
                                    new Thread(new enemyJump()).start();
                                }
                                DecidedJump = true;
                            }
                        }
                        else {
                            DecidedJump = false;
                        }
                    }
                    else {
                        EnemyWalking = false;
                        BothTouching = true;
                        if(EnemyRegenTime == 100) {
                            if(EnemyRegenTime == 100) {
                                if(EnemyCanAttack) {
                                    new Thread(new enemyAttack()).start();
                                }
                            }
                        }
                    }
                }
                EnemyDirection = "left";
            }
            if(PlayerX > EnemyX) {
                if(PlayerDirection.equalsIgnoreCase("right")) {
                    if(!(EnemyX + 119 > PlayerX)) {
                        EnemyX += Delta*.2f;
                        EnemyDirection = "right";
                        EnemyWalking = true;
                        BothTouching = false;
                        if(!(EnemyX - 50 < PlayerX)) {
                            if(!DecidedJump) {
                                int Jump = GenerateNumber.generateNumber(JumpPossibility);
                                if(Jump == JumpPossibility) {
                                    new Thread(new enemyJump()).start();
                                }
                                DecidedJump = true;
                            }
                        }
                        else {
                            DecidedJump = false;
                        }
                    }
                    else {
                        EnemyWalking = false;
                        BothTouching = true;
                        if(EnemyRegenTime == 100) {
                            if(EnemyRegenTime == 100) {
                                if(EnemyCanAttack) {
                                    new Thread(new enemyAttack()).start();
                                }
                            }
                        }
                    }
                }
                if(PlayerDirection.equalsIgnoreCase("left")) {
                    if(!(EnemyX + 135 > PlayerX)) {
                        EnemyX += Delta*.2f;
                        EnemyDirection = "left";
                        EnemyWalking = true;
                        BothTouching = false;
                        if(!(EnemyX + 50 < PlayerX)) {
                            if(!DecidedJump) {
                                int Jump = GenerateNumber.generateNumber(JumpPossibility);
                                if(Jump == JumpPossibility) {
                                    new Thread(new enemyJump()).start();
                                }
                                DecidedJump = true;
                            }
                        }
                        else {
                            DecidedJump = false;
                        }
                    }
                    else {
                        EnemyWalking = false;
                        BothTouching = true;
                        if(EnemyRegenTime == 100) {
                            if(EnemyRegenTime == 100) {
                                if(EnemyCanAttack) {
                                    new Thread(new enemyAttack()).start();
                                }
                            }
                        }
                    }
                }
                EnemyDirection = "right";
            }
            /* Enemy Jumping */
            if(EnemyJumping) {
                EnemyY -= Delta*.5f;
                AmountEnemyJumped = EnemyY;
            }
            else {
                if(EnemyY < 470) {
                    EnemyY += Delta*.5f;
                }
                if(Math.round(EnemyY) == 470 || Math.round(EnemyY) == 471) {
                    EnemyJumped = false;
                }
            }
    }

}

// Initializing Constructor
@Override
public void init(GameContainer GameContainer, StateBasedGame SBG)
        throws SlickException {
    WalkRightSpriteSheet = new SpriteSheet("res/images/characters/knight/spritesheets/WalkAnimationRight.png", 35, 48);
    WalkRightAnimation = new Animation(WalkRightSpriteSheet, 100);
    WalkLeftSprite = new SpriteSheet("res/images/characters/knight/spritesheets/WalkAnimationLeft.png", 35, 48);
    WalkLeftAnimation = new Animation(WalkLeftSprite, 100);
}

// Gets the ID of the current State
@Override
public int getID() {
    return 1;
}

// Start Fight
static class startFight implements Runnable {

    @Override
    public void run() {
        try {
            Thread.sleep(1000);
            startBossBattle = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

// Player Threads
/* Player Attack */
static class playerAttack implements Runnable {

    @Override
    public void run() {
        try {
            PlayerAttacking = true;
            if(PlayerDirection.equalsIgnoreCase("right")) {
                PlayerCurrentSword = PlayerRightAttackSword;
            }
            if(PlayerDirection.equalsIgnoreCase("left")) {
                PlayerCurrentSword = PlayerLeftAttackSword;
            }
            if(BothTouching) {
                EnemyHealth -= 10;
            }
            Thread.sleep(100);
            if(PlayerDirection.equalsIgnoreCase("right")) {
                PlayerCurrentSword = PlayerRightSword;
            }
            if(PlayerDirection.equalsIgnoreCase("left")) {
                PlayerCurrentSword = PlayerLeftSword;
            }
            PlayerAttacking = false;
            PlayerCanAttack = false;
            PlayerRegenTime = 0;
            while(PlayerRegenTime != 100) {
                Thread.sleep(100);
                PlayerRegenTime++;
            }
            PlayerCanAttack = true;
        }
        catch (Exception e) {

        }
    }

}

/* Player Jump */
static class playerJump implements Runnable {

    @Override
    public void run() {
        try {
            PlayerJumped = true;
            PlayerJumping = true;
            Thread.sleep(750);
            PlayerJumping = false;
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}

// Enemy Threads
/* Enemy Attack */
static class enemyAttack implements Runnable {

    @Override
    public void run() {
        try {
                EnemyAttacking = true;
                if(EnemyDirection.equalsIgnoreCase("right")) {
                    EnemyCurrentSword = EnemyRightAttackSword;
                }
                if(EnemyDirection.equalsIgnoreCase("left")) {
                    EnemyCurrentSword = EnemyLeftAttackSword;
                }
                PlayerHealth -= 10;
                Thread.sleep(100);
                if(EnemyDirection.equalsIgnoreCase("right")) {
                    EnemyCurrentSword = EnemyRightSword;
                }
                if(EnemyDirection.equalsIgnoreCase("left")) {
                    EnemyCurrentSword = EnemyLeftSword;
                }
                EnemyAttacking = false;
                EnemyCanAttack = false;
                EnemyRegenTime = 0;
                while(EnemyRegenTime != 100) {
                    Thread.sleep(100);
                    EnemyRegenTime++;
                }
                EnemyCanAttack = true;
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }

}

/* Decide Jump */
static class decideJump implements Runnable {

    @Override
    public void run() {
        try {
            Thread.sleep(1000 * 10);
            int number = GenerateNumber.generateNumber(20);
            if(number == 20) {
                if(!EnemyJumping) {
                    new Thread(new enemyJump()).start();
                }
            }
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }

}

/* Enemy Jump */
static class enemyJump implements Runnable {

    @Override
    public void run() {
        try {
            EnemyJumped = true;
            EnemyJumping = true;
            Thread.sleep(750);
            EnemyJumping = false;
        }
        catch (Exception e) {
        }
    }

}

Answer:

Turns out, that I wasnt adding it to the build path. If you are viewing this with this problem, make sure to add it to your build path in Eclipse (Or netbeans).

Question:

Hi I'm fairly new to LWJGL (or OpenGL in general) although I have experience with Java. I'm wondering how I would render a cube with a different PNG Texture on each side, and I'd like to stay away from other Third-Party Libraries other than LWJGL. Thanks for any help!


Answer:

As of LWJGL3 bindings for the STB library have been included. This is a small single-file utility library that does things like loading textures, sound files or fonts.


For rendering a cube with a different texture on each side you have two options:

  1. Render each face separately with another texture bound. This is the more straightforward option.
  2. Make a texture atlas of all the textures and render the whole cube once. This is not as easy to do but will give better performance, especially when rendering multiple cubes.

Introductory tutorial on how to use textures. (It is in C++, but should be easy to convert to Java.)

Question:

I created a simple mouse listener example using Slick2D in Windows 10 environment in Intellij. It is not reporting the correct coordinates or not working at all:

State class:

import org.lwjgl.input.Mouse;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.state.BasicGameState;
import org.newdawn.slick.state.StateBasedGame;
public class StateMain extends BasicGameState
{
@Override
public int getID() {return 0;}
@Override
public void init(GameContainer container, StateBasedGame game) throws SlickException {}
@Override
public void render(GameContainer container, StateBasedGame game, Graphics g) throws SlickException {}
@Override
public void update(GameContainer container, StateBasedGame game, int delta) throws SlickException
    {
    System.out.printf("Position: %d,%d\n", Mouse.getX(), Mouse.getY()); // Only reports position (-1,-1)
    }
@Override
public void mouseClicked(int button, int x, int y, int clickCount)
    {
    System.out.printf("Clicked: %d,%d\n", x, y); // Doesn't report
    }
@Override
public void mousePressed(int button, int x, int y)
    {
    System.out.printf("Pressed: %d,%d\n", x, y); // Only reports (-1,501)
    }
}

I have the following files in my libs folder:

jinput-dx8.dll jinput-dx8_64.dll jinput-raw.dll jinput-raw_64.dll lwjgl.dll lwjgl64.dll OpenAL32.dll OpenAL64.dll

The following are my VM arguments:

-Djava.library.path=libs/ -Dorg.lwjgl.opengl.Display.allowSoftwareOpenGL=true

I always get the following error when running the code:

Oct 05, 2017 11:26:30 AM net.java.games.input.DefaultControllerEnvironment getControllers WARNING: Found unknown Windows version: Windows 10 Oct 05, 2017 11:26:30 AM net.java.games.input.DefaultControllerEnvironment getControllers INFO: Attempting to use default windows plug-in. Oct 05, 2017 11:26:30 AM net.java.games.input.DefaultControllerEnvironment getControllers INFO: Loading: net.java.games.input.DirectAndRawInputEnvironmentPlugin

I suspect that the input environment plugin it is loading is causing the weird mouse position errors?


Answer:

It's working for me. Could you try lwjgl 2.9.1 and put this in your init method: System.setProperty("org.lwjgl.input.Mouse.allowNegativeMouse‌​Coords", "false");

Question:

I'm very new to using external Java libraries, and I'm starting with Slick2D which is built upon LWJGL. I wrote a simple StateBasedGame that just prints three options on a screen. It gives me an error though about some (jar?) file not being present (see below for reference).

This reminds me of the fact that most of the tutorials I come across were made one or two years ago when LWJGL 3 hadn't come out or wasn't stable yet. This means that they were all using LWJGL 2. The problem is, that a lot of the code that I try using LWJGL 3 doesn't work with the code that was originally written in LWJGL 2. Why is this? Would it be a good idea to switch back to LWJGL 2 if I wanted to learn SLick2D? Please help because simple programs that I write don't even compile.

Here's my code that doesn't work (at least in LWJGL 3):

import org.newdawn.slick.AppGameContainer;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.state.StateBasedGame;

public class Game extends StateBasedGame {

    Menu menu;

    public Game(String title) {
        super(title);
        menu = new Menu(0);
    }

    public static void main(String[] args) {
        try {
            AppGameContainer agc = new AppGameContainer(new Game("Text Based"));
            agc.setDisplayMode(600, 600, false);
            agc.start();
        } catch (SlickException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    @Override
    public void initStatesList(GameContainer container) throws SlickException {
        System.out.println("InitStates");
        addState(new Menu(0));
        getState(menu.getID()).init(container, this);
        enterState(menu.getID());
    }
}


import org.newdawn.slick.Color;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.state.BasicGameState;
import org.newdawn.slick.state.StateBasedGame;

public class Menu extends BasicGameState {

    private int ID;
    private int menu;

    public Menu(int id) {
        this.ID = id;
    }

    @Override
    public void init(GameContainer container, StateBasedGame sbg) throws SlickException {
    }

    @Override
    public void render(GameContainer container, StateBasedGame game, Graphics g) throws SlickException {
        g.setColor(Color.white);
        g.drawString("Higher or Lower", 50, 10);

        g.drawString("1. Play Game", 50, 100);
        g.drawString("2. High Scores", 50, 120);
        g.drawString("3. Quit", 50, 140);

    }

    @Override
    public void update(GameContainer arg0, StateBasedGame arg1, int arg2) throws SlickException {

    }

    @Override
    public int getID() {
        return ID;
    }

}

Here is the error:

Exception in thread "main" java.lang.UnsatisfiedLinkError: no lwjgl64 in java.library.path
    at java.lang.ClassLoader.loadLibrary(Unknown Source)
    at java.lang.Runtime.loadLibrary0(Unknown Source)
    at java.lang.System.loadLibrary(Unknown Source)
    at org.lwjgl.Sys$1.run(Sys.java:72)
    at java.security.AccessController.doPrivileged(Native Method)
    at org.lwjgl.Sys.doLoadLibrary(Sys.java:66)
    at org.lwjgl.Sys.loadLibrary(Sys.java:87)
    at org.lwjgl.Sys.<clinit>(Sys.java:117)
    at org.lwjgl.opengl.Display.<clinit>(Display.java:135)
    at org.newdawn.slick.AppGameContainer$1.run(AppGameContainer.java:39)
    at java.security.AccessController.doPrivileged(Native Method)
    at org.newdawn.slick.AppGameContainer.<clinit>(AppGameContainer.java:36)
    at Game.main(Game.java:17)

Answer:

LWJGL 3 is a complete rewrite of the library, so naturally most code from LWJGL 2 won't work with it. Slick2D still uses LWJGL 2 under the hood, which makes it incompatible with LWJGL 3.

The error you are getting is there because Slick2D calls the LWJGL 2 display functionality, which tries to load the lwjgl64.dll native file. However, in LWJGL 3 the native libraries have been renamed (lwjgl32 and lwjgl instead of lwjgl and lwjgl64), so it can't find it. Even if it did, loading dlls and jars of both versions at the same time (LWJGL 2 by Slick2D and LWJGL 3 by your code) most likely won't work well.

If you want to use Slick2D you have to use LWJGL 2. However, LWJGL 3 is already quite stable and comes with some helper libraries you can use to do common tasks like loading image files, so I advise you to at least take a look at it (it offers some nice features like multi-window support).

Question:

I'm trying to draw a text to the screen in LWJGL following this tutorial. The problem is that when ever I draw a text to the screen, it draws perfectly but when I draw a quad with the text, the quad does not show.

Game class

package moa.bermudez;

import static org.lwjgl.opengl.GL11.*;

import java.awt.Font;
import java.io.InputStream;

import moa.bermudez.utils.Artist;

import org.lwjgl.LWJGLException;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.newdawn.slick.TrueTypeFont;

public class Game 
{
public static final int WIDTH = 320;
public static final int HEIGHT = WIDTH * 9 / 16;
public static final int SCALE = 3;
public static final String NAME = "----";
public static final float VERSION = 0.1f;
public static final int MAX_FPS = 60;

private TrueTypeFont font;
private boolean fontAS = true;

public Game() 
{
    try 
    {
        Display.setDisplayMode(new DisplayMode(WIDTH * SCALE, HEIGHT * SCALE));
        Display.setTitle(NAME + " " + VERSION);
        Display.create();
    } catch(LWJGLException e)
    {
        e.printStackTrace();
        Display.destroy();
    }

    init();
    while(!Display.isCloseRequested())
    {
        setCamera();
        update();
        Display.sync(MAX_FPS);
    }

    Display.destroy();
}

public void update()
{       
    glClear(GL_COLOR_BUFFER_BIT);

    font.drawString(0, 0, "This text is showing");
    Artist.drawQuad(0, 0, 100, 100);    // This is not showing.

    Display.update();
}

public void setCamera()
{
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glViewport(0, 0, WIDTH * SCALE, HEIGHT * SCALE);
    glOrtho(0, WIDTH * SCALE, HEIGHT * SCALE, 0, 1, -1);
    glMatrixMode(GL_MODELVIEW);
    glEnable(GL_TEXTURE_2D);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}

public void init()
{
    try {
        InputStream inputStream = moa.bermudez.fonts.Font.DEFAULT_FONT;

        Font awtFont = Font.createFont(Font.TRUETYPE_FONT, inputStream);
        awtFont = awtFont.deriveFont(24f); 
        font = new TrueTypeFont(awtFont, fontAS);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

public static void main(String[] args)
{
    new Game();
}
}

Artist's DrawQuad method

public static void drawQuad(float x, float y, float width, float height)
{
    glBegin(GL_QUADS);

        glColor3d(0, 0, 1);
        glVertex2f(x, y);
        glVertex2f(x + width, y);
        glVertex2f(x + width, y + height);
        glVertex2f(x, y + height);

    glEnd();
}

Answer:

After searching, I found a solution to this from this stackoverflow post

Not calling glEnable(GL_BLEND) in initGL but calling glEnable(GL_BLEND) when you draw the text should make it work.

glEnable(GL_BLEND);
font.drawString(0, 0, "This is a text that should appear");
glDisable(GL_BLEND);

Question:

I use this to initiate openGL:

GL11.glMatrixMode(GL11.GL_PROJECTION);
GL11.glLoadIdentity();
GL11.glOrtho(0, width, height, 0, -1, 1);
GL11.glViewport(0, 0, width, height);
GL11.glMatrixMode(GL11.GL_MODELVIEW);

I create a True Type Font like this:

Font awtFont = new Font(font, i, size);
return new TrueTypeFont(awtFont, false);

However binding/ unbinding a texture messes up the font, forcing me to re-crate the font every time i want to draw some text. I can not afford to do this as it causes a major lag spike.

This is the method i use to draw textures:

public static void drawImage(image i, int x, int y) {
    i.bind();
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glBegin(7);
    {
        glTexCoord2f(0, 0);
        glVertex2f(x, y);

        glTexCoord2f(0, 1);
        glVertex2f(x, y + i.height);

        glTexCoord2f(1, 1);
        glVertex2f(x + i.width, y + i.height);

        glTexCoord2f(1, 0);
        glVertex2f(x + i.width, y);
    }
    glEnd();
    i.unBind();
}

When i removed i.bind() and i.unbind() the text drawing started working perfectly, but then i did not have my texture draw. So how can i have my texture and my text drawn?

PS:

I have enabled alpha blending:

glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

and do not disable it because the texture i want to render requires it.


Answer:

Inserting TextureImpl.bindNone() before every call to render text seamed to fix the problem. I am still not sure where the problem came from because i have used the slick util text render before without using TextureImpl.bindNone() without problems.

Question:

Full source of what I'm trying to do can be found here

I am trying to make a background scroll as mentioned above, I have made progress to the point where it is infinite, but it seems to disappear mid way through. I am currently stuck and have no idea how to progress from this point.

You can demo this by cloning the git provided above into eclipse. It should work on the fly without any setup needed. The canvas size is 1000 by 720.

int bgend=-(1000-bg.getWidth());
public void update(int delta){
    x-=delta*0.2;
    nx-=delta*0.2;
    if(x<=bgend&&x>=-bgend+delta*0.2){nx=1000;}
    else if(nx<=bgend&&nx>=-bgend+delta*0.2){x=1000;

    }

This is the logic associated with the scrolling. Then these values are used to render the image,

public void render(Graphics g){

bg.draw(x, y, bg.getWidth(), 720);

bg.draw(nx, y, bg.getWidth(), 720);


}

All of this is also in the link provided. Thank you.


Answer:

Can i know the size of the picture and the size of the screen ?! I think maybe u need to "cut" the image in the render method depend on how much u scrolled down/up in the state.. let me be more cleary using bottons: lets assume that every "W" is 1 pixel up and every "S" is 1 pixel down in "y" axis ,the pic is 1000 pixels hight and the state is set to 500 pixel hight ,and lets assume that we start from the bottom of the that photo so we need to get higher ,so every W push we update a param "UP" in the update method and then in the render method we cut the photo using "IMAGE.getSubImage(XstartPoint,YstartPoint,hight,width)".. i hope that was useful to you mate.

Question:

I am trying to execute this server code.

package server;

import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;

import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;

import org.apache.logging.log4j.message.Message;

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryonet.Server;
import com.esotericsoftware.minlog.Log;

import Client.PlayerChar;
import NetworkClasses.LoginRequest;
import NetworkClasses.LoginResponse;

public class MainServer {

    private int tcpPort;
    private int udpPort;
    public static Server server;
    private Kryo kryo;

    static JFrame jFrame;
    static JTextArea jTextArea;
    static MainServerListener listener = new MainServerListener();

    public MainServer(int tcpPort, int udpPort) {
        this.tcpPort = tcpPort;
        this.udpPort = udpPort;
        server = new Server();

        kryo = server.getKryo();
        registerKryoClasses();
    }

    public void startServer() {
        Log.info("Starting Server");
        jTextArea.append("Starting Server...");
        jTextArea.append("\n");
        server.start();
        try {
            server.bind(tcpPort, udpPort);
            server.addListener(listener);
            jTextArea.append("Server online! \n");
            jTextArea.append("----------------------------");
            jTextArea.append("\n");
            update();
        } catch (IOException e) {
            Log.info("Port already used");
            jTextArea.append("Port already in use");
            jTextArea.append("\n");
            e.printStackTrace();
        }
    }

    // Try changing this to non staic and see where this effects our game
    public static void stopServer() {
        Log.info("Server stopped");
        jTextArea.append("Server stopped.");
        jTextArea.append("\n");
        server.stop();
    }

    public void update() {
        while (true) {

        }
    }

    private void registerKryoClasses() {
        kryo.register(LoginRequest.class);
        kryo.register(LoginResponse.class);
        kryo.register(Message.class);
        kryo.register(PlayerChar.class);
        kryo.register(org.newdawn.slick.geom.Rectangle.class);
        kryo.register(float[].class);
        kryo.register(NetworkClasses.PacketUpdateX.class);
        kryo.register(NetworkClasses.PacketUpdateY.class);
        kryo.register(NetworkClasses.PacketAddPlayer.class);
        kryo.register(NetworkClasses.PacketRemovePlayer.class);

    }

    public static void createServerInterface() {
        jFrame = new JFrame("GameServerInterface");
        jTextArea = new JTextArea();
        jTextArea.append("\n");
        jTextArea.setLineWrap(true);
        jTextArea.setEditable(false);

        jFrame.add(jTextArea);
        jFrame.setSize(400, 600);
        jFrame.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                int i = JOptionPane.showConfirmDialog(null, "You want to shut down the server?");
                if(i == 0) {
                    stopServer();
                    System.exit(0); // successful exit
                }
            }
        });

        JScrollPane scrollPane = new JScrollPane(jTextArea);
        scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
        scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
        jFrame.add(scrollPane);
    }

    public static void main(String args[]) {
        Log.set(Log.LEVEL_INFO);

        MainServer main = new MainServer(55555, 55556);
        createServerInterface();
        main.startServer();
    }

} // end total class

Full source code is at Github. However when I try to run this server, I keep getting this error/exception and there are no solutions online at all. How can I solve this?

Exception in thread "main" java.lang.IllegalArgumentException: Unable to create serializer "com.esotericsoftware.kryo.serializers.FieldSerializer" for class: com.esotericsoftware.kryonet.FrameworkMessage$RegisterTCP
    at com.esotericsoftware.kryo.Kryo.newSerializer(Kryo.java:337)
    at com.esotericsoftware.kryo.Kryo.newDefaultSerializer(Kryo.java:316)
    at com.esotericsoftware.kryo.Kryo.getDefaultSerializer(Kryo.java:309)
    at com.esotericsoftware.kryo.Kryo.register(Kryo.java:353)
    at com.esotericsoftware.kryonet.KryoSerialization.<init>(KryoSerialization.java:33)
    at com.esotericsoftware.kryonet.KryoSerialization.<init>(KryoSerialization.java:25)
    at com.esotericsoftware.kryonet.Server.<init>(Server.java:91)
    at com.esotericsoftware.kryonet.Server.<init>(Server.java:73)
    at server.MainServer.<init>(MainServer.java:36)
    at server.MainServer.main(MainServer.java:118)
Caused by: java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
    at java.lang.reflect.Constructor.newInstance(Unknown Source)
    at com.esotericsoftware.kryo.Kryo.newSerializer(Kryo.java:324)
    ... 9 more
Caused by: java.lang.IncompatibleClassChangeError: Found interface org.objectweb.asm.MethodVisitor, but class was expected
    at com.esotericsoftware.reflectasm.FieldAccess.insertConstructor(FieldAccess.java:144)
    at com.esotericsoftware.reflectasm.FieldAccess.get(FieldAccess.java:109)
    at com.esotericsoftware.kryo.serializers.FieldSerializer.rebuildCachedFields(FieldSerializer.java:104)
    at com.esotericsoftware.kryo.serializers.FieldSerializer.<init>(FieldSerializer.java:50)
    ... 14 more

Answer:

I looked up online and somewhere in the corner of the internet, I found that I needed to import lwjgl or slick2d library after importing kryonet. Hope it helps others.

Question:

I'm testing the use of TileD with Slick2D in Java, but when I try to import the map and render it, the render function runs smoothly but the map doesn't show up on my screen. My player shows but not the map. I'm new to java so excuse my messy code.

MapRender class:

The render() function is called in a loop after a KeyListener that calls the loadMap() function, and "render" prints to the console but the map never shows. How could I fix this?

package com;

import org.newdawn.slick.SlickException;
import org.newdawn.slick.tiled.TiledMap;

public class MapRender {

    private TiledMap testMap;
    public boolean mapAdded = false;

    public MapRender() {

    }

    public void render() throws SlickException {

        if(mapAdded)
        {
            //Rendering map
            testMap.render(100,100,0,0,100,100);
            System.out.println("render");
        }

    }

    public void loadMap() throws SlickException {

        //Adding map
        testMap = new TiledMap("maps/testMap.tmx", false);
        mapAdded = true;



    }

}

Loop calling render in Main class

public static void main(String[] args) {



    while(true)
    {

        try {
            mapRender.render();
        } catch (SlickException e1) {
            e1.printStackTrace();
        }
    }
}

Any and all help would be appreciated!


Answer:

The loop you've coded in your main function does not allow Slick2D to run any code of its own in order to update the image on the screen. As a result, your program is probably stuck just rendering the map over and over to some invisible buffer.

Check out the "Hello World" example on the Slick2D wiki about how to implement the core loop, and add your map rendering call in its render method.

Question:

I am attempting to learn more about displaying and interacting with graphics and GUI elements. As part of this, I have been following along with a Tower Defense Tutorial that uses LWJGL and Slick-Util: https://www.youtube.com/watch?v=rfR09erJu7U&list=PLFUqwj4q1Zr8GHs6bO4d6gxMGUh_2pcNg

Extending some things out a bit on my own, I am trying to draw some basic untextured shapes with textured shapes. I can get a 2d line to draw, however, it only appears when drawn after certain textured shapes are drawn, but doesn't appear after other textured shapes are drawn. I'm wondering what I don't understand that is causing this divergent behavior.

Here is my main class, LineTest.java:

package main;

import static helpers.Artist.BeginSession;
import static helpers.Artist.DrawQuadTex;
import static helpers.Artist.QuickLoad;
import static helpers.Artist.drawLine;

import org.lwjgl.opengl.Display;
import org.newdawn.slick.opengl.Texture;

import helpers.Artist;

public class LineTest {

    public LineTest() {
        BeginSession();
        Texture bg = QuickLoad("bg");
        //Texture bg = QuickLoad("exitbutton");

        while(!Display.isCloseRequested()) {
            DrawQuadTex(bg,0,0,Artist.WIDTH,Artist.HEIGHT);
            drawLine(0,0,800,800);

            Display.update();
            Display.sync(60);
        }
        Display.destroy();
    }

    public static void main(String[] args) {
        new LineTest();
    }
}

And my helper class, Artist.java:

package helpers;

import static org.lwjgl.opengl.GL11.GL_BLEND;
import static org.lwjgl.opengl.GL11.GL_LINES;
import static org.lwjgl.opengl.GL11.GL_MODELVIEW;
import static org.lwjgl.opengl.GL11.GL_ONE_MINUS_SRC_ALPHA;
import static org.lwjgl.opengl.GL11.GL_PROJECTION;
import static org.lwjgl.opengl.GL11.GL_QUADS;
import static org.lwjgl.opengl.GL11.GL_SRC_ALPHA;
import static org.lwjgl.opengl.GL11.GL_TEXTURE_2D;
import static org.lwjgl.opengl.GL11.glBegin;
import static org.lwjgl.opengl.GL11.glBlendFunc;
import static org.lwjgl.opengl.GL11.glClearColor;
import static org.lwjgl.opengl.GL11.glClearDepth;
import static org.lwjgl.opengl.GL11.glColor4f;
import static org.lwjgl.opengl.GL11.glEnable;
import static org.lwjgl.opengl.GL11.glEnd;
import static org.lwjgl.opengl.GL11.glLoadIdentity;
import static org.lwjgl.opengl.GL11.glMatrixMode;
import static org.lwjgl.opengl.GL11.glOrtho;
import static org.lwjgl.opengl.GL11.glTexCoord2f;
import static org.lwjgl.opengl.GL11.glTranslatef;
import static org.lwjgl.opengl.GL11.glVertex2f;

import java.io.IOException;
import java.io.InputStream;

import org.lwjgl.LWJGLException;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.newdawn.slick.opengl.Texture;
import org.newdawn.slick.opengl.TextureLoader;
import org.newdawn.slick.util.ResourceLoader;

public class Artist {

    public static final int WIDTH = 640, HEIGHT = 480;

    public static void BeginSession() {
        Display.setTitle("Line Test");
        try {
            Display.setDisplayMode(new DisplayMode(WIDTH, HEIGHT));
            Display.create();
        } catch (LWJGLException e) {
            e.printStackTrace();
        }

        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        glOrtho(0, WIDTH, HEIGHT, 0, 1, -1);
        glMatrixMode(GL_MODELVIEW);
        glEnable(GL_TEXTURE_2D);
        glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
        glClearDepth(1);
        glEnable(GL_BLEND);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    }

    public static void drawLine(int x1, int y1, int x2, int y2) {
        glColor4f(0.0f, 1.0f, 0.2f, 1.0f);
        glBegin(GL_LINES);
        glVertex2f((float) x1, (float) y1);
        glVertex2f((float) x2, (float) y2);
        glEnd();
        glColor4f(1f,1f,1f,1f);
    }   
    public static void DrawQuadTex(Texture tex, float x, float y, float width, float height) {
        tex.bind();
        glTranslatef(x, y, 0);
        glBegin(GL_QUADS);
        glTexCoord2f(0, 0);
        glVertex2f(0, 0);
        glTexCoord2f(1, 0);
        glVertex2f(width, 0);
        glTexCoord2f(1, 1);
        glVertex2f(width, height);
        glTexCoord2f(0,1);
        glVertex2f(0, height);
        glEnd();
        glLoadIdentity();
    }
    public static Texture LoadTexture(String path, String fileType) {
        Texture tex = null;
        InputStream in = ResourceLoader.getResourceAsStream(path);
        try {
            tex = TextureLoader.getTexture(fileType, in);
            in.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return tex;
    }

    public static Texture QuickLoad(String name) {
        Texture tex = null;
        tex = LoadTexture(name + ".png", "PNG");
        return tex;
    }
}

The important part of my problem is within the main class, right here:

Texture bg = QuickLoad("bg");
//Texture bg = QuickLoad("exitbutton");

while(!Display.isCloseRequested()) {
    DrawQuadTex(bg,0,0,Artist.WIDTH,Artist.HEIGHT);
    drawLine(0,0,800,800);

When my Texture bg is getting my 'bg' graphic (a solid black PNG file), the drawLine function doesn't seem to actually draw a line. However, if I change my Texture bg to get my 'exitbutton' graphic (a blue square with "Exit" written in it, still a PNG file) the drawLine function does create a visible line.

This imgur album contains the output for both: Texture bg = QuickLoad("bg"); & Texture bg = QuickLoad("exitbutton");

http://imgur.com/a/OVOzD

If necessary, I can also upload both PNG files that I using, but I currently cannot include more than 2 links in my question. bg.png is a mono-black 64x64 PNG. exitbutton.png is 512x512.

Just looking to understand what is causing this. Thank you!


Answer:

The problem is most likely that you enable texturing in the BeginSession() method, and then keep it enabled for the whole rendering:

glEnable(GL_TEXTURE_2D);

This means that your lines will be textured. Now, you may say: "But... I'm not specifying texture coordinates for the lines!" That does not matter. The immediate mode rendering API in OpenGL is state based, so whichever texture coordinates were specified last are the ones used. Since you call DrawQuadTex() before drawLine(), the last texture coordinates specified in DrawQuadTex() will be your current texture coordinates when drawing the line:

glTexCoord2f(0,1);

So the color of the line will be the texel at position (0, 1) of the currently bound texture, modulated with the color specified for the line:

glColor4f(0.0f, 1.0f, 0.2f, 1.0f);

If the two colors multiplied together result in black, e.g. because the given texel is black, the result will be a black line on black background. Which looks a lot like not rendering anything at all.

The cleanest solution is to enable texturing only while drawing primitives that you want to texture, and disable it afterwards. For example, in the DrawQuadTex() method:

public static void DrawQuadTex(Texture tex, float x, float y, float width, float height) {
    tex.bind();
    glEnable(GL_TEXTURE_2D);
    ...
    glDisable(GL_TEXTURE_2D);
}

A few hints on how to track down these types of problems, or avoid them altogether:

  1. Set the clear color to something other than black during development. Then you can easily tell if you're rendering black geometry, or nothing at all.
  2. Use shader based rendering. The fixed function pipeline may look easier at first, but it's really not. With shaders, the resulting color is exactly what you implement, not some magic combination of values based on a bunch of fixed state.
  3. While you're at it, you may also want to avoid using immediate mode rendering. While not directly causing this problem, it's just as obsolete as using the fixed function pipeline.

Question:

I'm trying to detect when a mouse is hovering an image (Play Image) and when I'm clicking the mouse something happens.

I draw an image on the center of the screen and I don't know how to implement this on my own code:

    @Override
        public void init(GameContainer arg0, StateBasedGame arg1) throws SlickException {
            f = (float) (0.1 * Main_Activity.apg.getHeight() / 180);
            play = new Image("res/play_image.png");
            play_Original_Width = play.getWidth();
            play_Original_Height = play.getHeight();
            Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
            width = screenSize.getWidth();
            height = screenSize.getHeight();
        }

        @Override
        public void render(GameContainer arg0, StateBasedGame arg1, Graphics g) throws SlickException {

            play.draw(Main_Activity.apg.getWidth() / 2 - ((play_Original_Width * f) / 2),
                    Main_Activity.apg.getHeight() / 2 - ((play_Original_Height * f) / 2), f);

        }

@Override
    public void update(GameContainer gc, StateBasedGame sbg, int arg2) throws SlickException {
        int x = Mouse.getX();
        int y = Mouse.getY();

    }

apg:

apg = new AppGameContainer(new Main_Activity(game_Name));
            apg.setDisplayMode((int) width, (int) height, false);
            apg.setShowFPS(false);
            apg.start();

How can I manage to detect when the mouse is hovering the image (Play Image)?

Thanks in advanace.


Answer:

You just have to test if your x value is between your Image X and Image X + image width, and same for your y value.

In your update method :

int x = Mouse.getX();
int y = Mouse.getY();
int playX = Main_Activity.apg.getWidth() / 2 - ((play_Original_Width * f) / 2);
int playY = Main_Activity.apg.getHeight() / 2 - ((play_Original_Height * f) / 2);

if (x > playX && x < playX+play_Original_Width && y > playY && y < playY + play_Original_Height) {
    // then your mouse coordinates are over your image.
}

Additional (use if useful to you):

In some personal code, I used to implement a ImageRectangle that inherits from Rectangle and contains an Image. With this behaviour I could use the method intersects to detect this over. And I prefer using a mouseListener to manage these mouse event.

public ImageRectangle extends Rectangle {
    Image play;
    public ImageRectangle(Image,x,y,f){...}
    public void init(...){...}
    public void render(...){this.image.draw();}
    public void update(...){...}
}

In your mouseMoved method :

Rectangle mousePosition = new Rectangle(x,y,1,1);
if(mousePosition.intersects(playImageRectangle)) {//do whatever you need}

Question:

I'm trying to run this code that is used to see if things were setup properly:

package simpleslickgame;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.newdawn.slick.AppGameContainer;
import org.newdawn.slick.BasicGame;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.SlickException;

public class SimpleSlickGame extends BasicGame
{
    public SimpleSlickGame(String gamename)
    {
        super(gamename);
    }

    @Override
    public void init(GameContainer gc) throws SlickException {}

    @Override
    public void update(GameContainer gc, int i) throws SlickException {}

    @Override
    public void render(GameContainer gc, Graphics g) throws SlickException
    {
        g.drawString("Howdy!", 10, 10);
    }

    public static void main(String[] args)
    {
        try
        {
            AppGameContainer appgc;
            appgc = new AppGameContainer(new SimpleSlickGame("Simple Slick Game"));
            appgc.setDisplayMode(640, 480, false);
            appgc.start();
        }
        catch (SlickException ex)
        {
            Logger.getLogger(SimpleSlickGame.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}

All of the Googling I've done has led me to checking the natives over and over and I"m pretty sure I've done it right. When I go to the libraries in this project's build path, JRE System library and Slick2D both say Native library location: .../windows/x64. I've tried just .../windows, and I've tried it with the JRE not having a native location. I followed two different tutorials on how to do this and I keep getting errors trying to run this simple code. Any help?


Answer:

basically what you need is to add slick.jar and lwjgl.jar to your build path and then right click your project >> open properties >> click on Java Build Path >> open Libraries tab >> expand JRE System Library >> click Native library location >> edit >> External Folder >> find ..\lwjgl-2.9.0\native\windows folder on your hard drive >> select it >> and you're done

g.drawString("Howdy!", 10, 10);

I would just move this string to some other location, cause it's showing over the FPS counter :)

EDIT:

you can use the natives from ..\slick\lib\natives-windows.jar.

open it with WinRAR or something and extract to a folder, then just set that folder to be your Native library location

Question:

I'm making a game with LWJGL (and Slick-util) and I was going to use the Texture.getWidth() and Texture.getHeight() to get the width and height of a Texure object, instead of typing in the width and height manually, but I found out that those functions returns a float. I want to get the width of the Texture in pixels, but the function returns a float, so I'm unsure what "unit" the function actually returns, because pixels must be int (not floats, because you cant render the half of a pixel with one color and the other half of it with another color).

Can I just cast them to int and it's fine?


Answer:

Sorry for the quick asking, I found the answer by looking in the javadocs for Slick-util.

To get the size of the original image, use Texture.getImageWidth() and Texture.getImageHeight().

Question:

I'm following along with a youtube tutorial on programming in Java using Slick2D and lwjgl. When I run this code:

package game;
import org.newdawn.slick.*;
import org.newdawn.slick.state.*;

public class Game extends StateBasedGame{
    public static final String gamename = "Ham Blaster!";
    public static final int menu = 0;
    public static final int play = 1;

public Game(String name) {
    super(name);
    this.addState(new Menu(menu));
    this.addState(new Play(play));
}

public static void main(String[] args){
    try{
        AppGameContainer appgc;
        appgc = new AppGameContainer(new Game(gamename));
        appgc.setDisplayMode(640, 360, false);
    }catch(SlickException e){
        e.printStackTrace();
    }

}

@Override
public void initStatesList(GameContainer gc) throws SlickException {
    this.getState(menu).init(gc, this);
    this.getState(play).init(gc, this);
    this.enterState(menu);

}

}

It throws a security exception saying that the package org.lwjgl is sealed. I've added the lwjgl jar file and the two jar files associated with slick (slick2d and lwjgl . jar) to the build path. Is there a solution?


Answer:

I had the same problem ones. And I Found that going into the Jar file(s) and opening up the Manifest file, and then removing the

Sealed: true

line entirely fixed my problem. And just so you know there would be no need to re package or something if you open the jar file with e.g. Winrar and then editing the file while it is in the jar.

You probably only need to go into the lwjgl jar files.

Hope it works out for you!

Question:

I'm using Slick2D and LWJGL for my StateBasedGame and I was wondering if there was a way to enter into my splashscreen on application load using a transition?

I tried using:

this.enterState(SPLASH, new FadeInTransition(Color.black), new FadeInTransition(Color.black));

However, it fades in nicely but then it flashes again for the second transition :(

Anyone know how I can get around that?

Would I have to create my own transition?


Answer:

Reading the docs I found that I can use an empty transition to the second transition parameter to prevent the additional transition from playing.

this.enterState(SPLASH, new FadeInTransition(Color.black), new EmptyTransition());

Question:

I am making a game and I noticed whenever I use the graphics.translate function and after the translate this happens to the images.

Before Translation

After Translation

I was wondering if there is anyway to fix that or anyone else has the same issue. All these sprites are rendered from a spritesheet

EDIT: Translate code

public void translate(Graphics g, GameContainer container, int delta) {
        g.translate(((container.getWidth() / 2) - this.x), ((container.getHeight() / 2) - this.y));
    }

    public void update(GameContainer container, int type){
        if (type == 0) {
            x = p.getX(); //p is the player
            y = p.getY();
        } else if (type == 1) {
            x = player.x;
            y = player.y;
        }

        if (offset) {
            if (this.x - container.getWidth() / 2 < offsetMin[0]) {
                x = offsetMin[0] + container.getWidth() / 2;
            } else if (this.x + container.getWidth() / 2 > offsetMax[0]) {
                x = offsetMax[0] - container.getWidth() / 2;
            }

            if (this.y - container.getHeight() / 2 < offsetMin[1]) {
                y = offsetMin[1] + container.getHeight() / 2;
            } else if (this.y + container.getHeight() > offsetMax[1]) {
                y = offsetMax[1] - container.getHeight() / 2;
            }
        }
    }

Answer:

Try casting the x and y parameters for g.translate() to ints. That would eliminate any rounding errors where tiles don't end up on perfect pixel coords (IE 4, not 4.2).

Moved answer from comments to answer so it can be marked as accepted by OP

Question:

I think windows 8.1 is the problem anyway.

I'm using the tutorial on Slick2D's website to create a hello, world program to ensure that my installation of slick went well.

This is the relevant code:

        //init stuff
        AppGameContainer appgc;
        appgc = new AppGameContainer(new Game("Simple Slick Game"));
        appgc.setDisplayMode(640, 480, false);
        appgc.start();
        //draw a string that says howdy
        g.drawString("Howdy!", 10, 10);

But when I execute it, it looks like this glitchy mess:

The numbers change several times/second.

I think that Slick not supporting win8.1 might be the issue, because this is logged in the console:

 WARNING: Found unknown Windows version: Windows 8.1
 Attempting to use default windows plug-in.

Other than that, not sure. Maybe an issue with the font? Or some weird utf thing?


Answer:

I don't exactly what is your problem but what you see is "Howdy!" text over the text "FPS 9860".

Try to change the position of Howdy, for example:

g.drawString("Howdy!", 100, 100);

If you don't want to show the FPS (frames per second) you probably can disabled it but if you are implementing a game or graphic stuff, it is a good info to know when running your program.