1 Replies - 639 Views - Last Post: 04 October 2013 - 11:05 AM Rate Topic: -----

#1 TechnoBear  Icon User is offline

  • D.I.C Head

Reputation: 18
  • View blog
  • Posts: 222
  • Joined: 02-November 11

LWJGL & Slick2D - Only binding one texture

Posted 27 September 2013 - 11:23 AM

Ok, I don't know how I have managed this. I have started a new project, what I have right now should be a character (created as an animation but currently not dealing with movement) and a cursor (Just a construct using vertex arrays). The code for each class which is relevant should be posted below (If I'm missing something tell me).

The issue is that when I call for the cursor to be rendered it is making the cursor texture the sprite sheet for the character, if I unbind the texture inside the cursor class or after the cursor has been rendered then the character just becomes a white rectangle.

I have looked through my older projects (do not remember having this particular issue) and cannot find anything to do with updating or rendering which is different from what I am already doing (and those projects had multiple entities to display at one time)

Code follows:
GameWindow:
package knightmare2d.engine.window;

import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;

import knightmare2d.engine.sound.SoundLoader;
import knightmare2d.engine.state.GameState;
import knightmare2d.game.state.*;

import org.lwjgl.LWJGLException;
import org.lwjgl.Sys;
import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.GL11;

/**
 * A window to display Project Knightmare using LWJGL.
 * 
 * @author Guy Curtis
 */
public class GameWindow {
	/** The list of game states currently registered */
	private HashMap<String, GameState> gameStates = new HashMap<String, GameState>();
	/** The current state being rendered */
	private GameState currentState;
	/** The Width of the screen */
	private int screenWidth = 1280;
	/** The height of the screen */
	private int screenHeight = 768;
	/** Flag for whether to use full screen mode or windowed mode*/
	private boolean fullScreen = false;
	/** Flag for if game is running */
	private boolean gameRunning = true;
	/** Variable for length of time since last loop (Used to set delta)*/
	private long lastLoop;

	/**
	 * Return width of screen (x component of resolution)
	 * 
	 * @return Width of screen
	 */
	public int getScreenWidth() {
		return screenWidth;
	}

	/**
	 * Return height of screen (y component of resolution)
	 * 
	 * @return Height of screen
	 */
	public int getScreenHeight() {
		return screenHeight;
	}

	/**
	 * Create a new game window
	 */
	public GameWindow() {

		try {
			// find out what the current bits per pixel of the desktop is
			int currentBpp = Display.getDisplayMode().getBitsPerPixel();
			// find a display mode at 800x600
			DisplayMode mode = findDisplayMode(screenWidth, screenHeight,
					currentBpp);

			// if can't find a mode, notify the user the give up
			if (mode == null) {
				Sys.alert("Error", screenWidth + "x" + screenHeight + "x"
						+ currentBpp + " display mode unavailable");
				return;
			}

			// configure and create the LWJGL display
			Display.setTitle("Project Knightmare 2D");
			Display.setDisplayMode(mode);
			Display.setFullscreen(fullScreen);

			Display.create();

			// initialise the game states
			init();
		} catch (LWJGLException e) {
			e.printStackTrace();
			Sys.alert("Error", "Failed: " + e.getMessage());
		}
	}

	/**
	 * Start the game
	 */
	public void startGame() {
		// enter the game loop
		gameLoop();
	}

	/**
	 * Get the current time in milliseconds based on the LWJGL high res system
	 * clock.
	 * 
	 * @return The time in milliseconds based on the LWJGL high res clock
	 */
	private long getTime() {
		return (Sys.getTime() * 1000) / Sys.getTimerResolution();
	}

	/**
	 * Determine an available display that matches the specified paramaters.
	 * 
	 * @param width
	 *            The desired width of the screen
	 * @param height
	 *            The desired height of the screen
	 * @param bpp
	 *            The desired colour depth (bits per pixel) of the screen
	 * @return The display mode matching the requirements or null if none could
	 *         be found
	 * @throws LWJGLException
	 *             Indicates a failure interacting with the LWJGL library.
	 */
	private DisplayMode findDisplayMode(int width, int height, int bpp)
			throws LWJGLException {
		DisplayMode[] modes = Display.getAvailableDisplayModes();
		DisplayMode mode = null;

		for (int i = 0; i < modes.length; i++) {
			if ((modes[i].getBitsPerPixel() == bpp) || (mode == null)) {
				if ((modes[i].getWidth() == width)
						&& (modes[i].getHeight() == height)) {
					mode = modes[i];
				}
			}
		}

		return mode;
	}

	/**
	 * Add a game state to this window. This state can be used via its unique
	 * name.
	 * 
	 * @param state
	 *            The state to be added
	 * @see GameState.getName()
	 */
	public void addState(GameState state) {
		if (currentState == null) {
			currentState = state;
		}

		gameStates.put(state.getName(), state);
	}

	/**
	 * Initialise the window and the resources used for the game
	 */
	public void init() {
		// initialize our sound loader to determine if we can
		// play sounds on this system
		SoundLoader.get().init();
		// enable textures since we're going to use these for our sprites
		GL11.glEnable(GL11.GL_TEXTURE_2D);

		// disable the OpenGL depth test since we're rendering 2D graphics
		GL11.glDisable(GL11.GL_DEPTH_TEST);

		GL11.glMatrixMode(GL11.GL_PROJECTION);
		GL11.glLoadIdentity();

		GL11.glOrtho(0, screenWidth, screenHeight, 0, -1, 1);

		addState(new MenuState());
		addState(new InGameState());

		try {
			// Initialize all the game states we've just created. This allows
			Iterator<GameState> states = gameStates.values().iterator();

			// loop through all the states that have been registered
			// causing them to initialize
			while (states.hasNext()) {
				GameState state = (GameState) states.next();

				state.init(this);
			}
		} catch (IOException e) {
			// if anything goes wrong, show an error message and then exit.
			// This is a bit abrupt.
			Sys.alert("Error", "Unable to initialise state: " + e.getMessage());
			System.exit(0);
		}
	}

	/**
	 * The main game loop which is cycled rendering and updating the registered
	 * game states
	 */
	private void gameLoop() {
		while (gameRunning) {
			// calculate how long it was since we last came round this loop
			// and hold on to it so we can let the updating/rendering routine
			// know how much time to update by
			int delta = (int) (getTime() - lastLoop);
			lastLoop = getTime();
			// clear screen
			GL11.glClear(GL11.GL_COLOR_BUFFER_BIT);
			GL11.glMatrixMode(GL11.GL_MODELVIEW);
			GL11.glLoadIdentity();

			// Enable transparency
			GL11.glEnable(GL11.GL_BLEND);
			GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);

			// cause the game state that we're currently running to update
			// based on the amount of time passed
			int remainder = delta % 10;
			int step = delta / 10;
			for (int i = 0; i < step; i++) {
				currentState.update(this, 10);
			}
			if (remainder != 0) {
				currentState.update(this, remainder);
			}

			// cause the game state that we're currently running to be
			// rendered
			currentState.render(this, delta);

			// update window contents
			Display.update();

			if (Display.isCloseRequested()
					|| Keyboard.isKeyDown(Keyboard.KEY_ESCAPE)) {
				gameRunning = false;
				Display.destroy();
			}
		}
	}

	/**
	 * Change the current state being rendered and updated. Note if no state
	 * with the specified name can be found no action is taken.
	 * 
	 * @param name
	 *            The name of the state to change to.
	 */
	public void changeToState(String name) {
		GameState newState = (GameState) gameStates.get(name);
		if (newState == null) {
			return;
		}

		currentState.leave(this);
		currentState = newState;
		currentState.enter(this);
	}

	/**
	 * The entry point into our game. This method is called when you execute the
	 * program. Its simply responsible for creating the game window
	 * 
	 * @param argv
	 *            The command line arguments provided to the program
	 */
	public static void main(String argv[]) {
		GameWindow myGameWindow = new GameWindow();
		Mouse.setGrabbed(true);
		myGamewindow.startGame();
	}
}



InGameState:
package knightmare2d.game.state;

import java.io.IOException;

import knightmare2d.engine.entity.CharacterClass;
import knightmare2d.engine.state.GameState;
import knightmare2d.engine.window.GameWindow;
import knightmare2d.game.entity.EntityManager;
import knightmare2d.game.entity.PlayableCharacter;
import knightmare2d.game.gui.cursor.Cursor;

public class InGameState implements GameState {
	/** The game unique name of this state */
	public static final String NAME = "ingame";
	/** Entity manager for use during game play */
	EntityManager entityManager = new EntityManager();
	/** Variable for use as player */
	PlayableCharacter player;
	/** Cursor for use in game */
	Cursor gameCursor = null;

	@Override
	public String getName() {
		return NAME;
	}

	@Override
	public void init(GameWindow window) throws IOException {
		// TODO Auto-generated method stub

	}

	@Override
	public void render(GameWindow window, int delta) {
		// TODO Auto-generated method stub
		player.render();
		gameCursor.render();
	}

	@Override
	public void update(GameWindow window, int delta) {
		// TODO Auto-generated method stub
		gameCursor.update();
		entityManager.update();
		player.update();
	}

	@Override
	public void enter(GameWindow window) {
		// TODO Auto-generated method stub
		gameCursor = new Cursor(window, "res/sprite/cursor/targetcursor.png");
		player = new PlayableCharacter("Male", CharacterClass.OFFICER, window, gameCursor);
		entityManager.addEntity(player);
	}

	@Override
	public void leave(GameWindow window) {
		// TODO Auto-generated method stub

	}

}



TextureArraySquare:
package knightmare2d.engine.gui;

import java.nio.FloatBuffer;

import knightmare2d.engine.texture.Texture;

import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL11;

public class TextureArraySquare {
	Texture texture;
	/** Vertex Array Variables */
	int amountOfVertices = 4;
	int vertexSize;
	private FloatBuffer textureData;
	
	/**
	 * Create new Texture Array
	 * 
	 * @param vertices Amount of vertices (e.g. single quad = 4)
	 * @param vertexSize Number of axis (e.g. [x,y] = 2)
	 */
	public TextureArraySquare(int vertexSize){
		this.vertexSize = vertexSize;
		
		textureData = BufferUtils.createFloatBuffer(amountOfVertices * vertexSize);
		textureData.put(new float[] {
        		0, 1,
        		0, 0,
        		1, 0,
        		1, 1
        });
		
		textureData.flip();
	}
	
	public void prerender() {
		GL11.glEnableClientState(GL11.GL_TEXTURE_COORD_ARRAY);
		GL11.glTexCoordPointer(vertexSize, 0, textureData);
	}
	
	public void destroy() {
		GL11.glDisableClientState(GL11.GL_TEXTURE_COORD_ARRAY);
	}
}



VertexArraySquare:
package knightmare2d.engine.gui;

import java.nio.FloatBuffer;

import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL11;

public class VertexArraySquare {
	float x0, x1, y0, y1;
	/** Vertex Array Variables */
	int amountOfVertices = 4;
	int vertexSize;
	private FloatBuffer vertexData;
	
	/**
	 * Create new Vertex Array
	 * @param x0 First X value
	 * @param x1 Second X value
	 * @param y0 First Y value
	 * @param y1 Second X value
	 * @param vertices Amount of vertices (e.g. single quad = 4)
	 * @param vertexSize Number of axis (e.g. [x,y] = 2)
	 */
	public VertexArraySquare(float x0, float x1, float y0, float y1, int vertexSize) {
		this.x0 = x0;
		this.x1 = x1;
		this.y0 = y0;
		this.y1 = y1;
		this.vertexSize = vertexSize;
		
		vertexData = BufferUtils.createFloatBuffer(amountOfVertices * vertexSize);
		vertexData.put(new float[] {
        		x0, y0,
        		x0, y1,
        		x1, y1,
        		x1, y0
        });
		vertexData.flip();
	}
	
	public void prerender() {
		GL11.glEnableClientState(GL11.GL_VERTEX_ARRAY);
		GL11.glVertexPointer(vertexSize, 0, vertexData);
	}
	
	public void render() {
		GL11.glDrawArrays(GL11.GL_QUADS, 0, amountOfVertices);
	}
	
	public void destroy() {
		GL11.glDisableClientState(GL11.GL_VERTEX_ARRAY);
	}
}



Cursor:
package knightmare2d.game.gui.cursor;

import java.io.IOException;

import org.lwjgl.input.Mouse;

import knightmare2d.engine.gui.TextureArraySquare;
import knightmare2d.engine.gui.VertexArraySquare;
import knightmare2d.engine.texture.*;
import knightmare2d.engine.window.GameWindow;

public class Cursor {
	/** The window in which the game is being rendered */
	GameWindow gameWindow;
	/** Texture to use when rendering cursor */
	private Texture cursorTexture;
	/** X coordinate of cursor */
	private float positionX;
	/** Y Coordinate of cursor */
	private float positionY;
	/** Vertex array to render cursor */
	private VertexArraySquare vertexArray;
	/** Texture array to render cursor */
	private TextureArraySquare textureArray;

	/**
	 * Create a new in game cursor
	 * 
	 * @param Window
	 *            is which game is being rendered
	 * @param texture
	 *            Texture to use for cursor
	 * @throws IOException
	 */
	public Cursor(GameWindow window, String textureLocation) {
		loadTexture(textureLocation);
		this.gameWindow = window;
		positionX = window.getScreenWidth() / 2;
		positionY = window.getScreenHeight() / 2;

		createCursor();
	}

	/**
	 * Get X coordinate of Cursor position
	 * 
	 * @return Cursor's PositionX
	 */
	public float getX() {
		return positionX;
	}

	/**
	 * Get Y Coordinate of Cursor Position
	 * 
	 * @return Cursor's PositionY
	 */
	public float getY() {
		return positionY;
	}

	/**
	 * Set the texture to use for cursor
	 * 
	 * @param cursorTexture
	 *            Texture to use for Cursor
	 */
	public void setCursorTexture(String textureLocation) {
		loadTexture(textureLocation);
	}

	/**
	 * Load cursor texture
	 * 
	 * @param textureLocation
	 *            Location of texture to load
	 */
	private void loadTexture(String textureLocation) {
		TextureLoader cursorLoader = new TextureLoader();
		try {
			cursorTexture = cursorLoader.getTexture(textureLocation);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/**
	 * Create a new Cursor to display on screen
	 */
	private void createCursor() {
		vertexArray = new VertexArraySquare(positionX, positionX + 16,
				positionY, positionY + 16, 2);
		textureArray = new TextureArraySquare(2);
	}

	/**
	 * Update position of cursor on screen
	 * 
	 * @param delta
	 *            current timing for game
	 */
	public void update() {
		positionX += Mouse.getDX();
		positionY += -Mouse.getDY();

		createCursor();
	}

	/**
	 * Render the cursor to the screen
	 */
	public void render() {
		
		vertexArray.prerender();
		textureArray.prerender();
		cursorTexture.bind();
		vertexArray.render();
		textureArray.destroy();
		vertexArray.destroy();
		
	}
}



PlayableCharacter:
package knightmare2d.game.entity;

import org.lwjgl.input.Mouse;
import org.newdawn.slick.Animation;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.SpriteSheet;

import knightmare2d.engine.entity.AbstractEntity;
import knightmare2d.engine.entity.CharacterClass;
import knightmare2d.engine.entity.Entity;
import knightmare2d.engine.entity.ManageEntities;
import knightmare2d.engine.entity.Player;
import knightmare2d.engine.window.GameWindow;
import knightmare2d.game.gui.cursor.Cursor;

public class PlayableCharacter extends AbstractEntity implements Player {
	//TODO: Move these to abstract entity once dents have been hammered out - For now this is test class
	/**Animation for character*/
	Animation animation = new Animation(); //Black Animation for character
	/** Sprite Sheet for Character */
	SpriteSheet spriteSheet = null;
	/** Cursor being used in game*/
	Cursor gameCursor;
	
	public PlayableCharacter(String gender, CharacterClass characterClass, GameWindow gameWindow, Cursor gameCursor) {
		this.gameCursor = gameCursor;
		
		try {
			spriteSheet = new SpriteSheet(spriteLocation, spriteWidth, spriteHeight);
		} catch (SlickException e) {
			e.printStackTrace();
		}

		animation.setAutoUpdate(false);

		for (int row=0;row<4;row++) {
			for(int col=0;col<3;col++){
				animation.addFrame(spriteSheet.getSprite(col,row), 150);
			}
		}
	}
	
	public void update() {
		if (Mouse.isButtonDown(0)) {
			positionX = gameCursor.getX();
			positionY = gameCursor.getY();
		}
	}
	
	@Override
	public void render() {
		animation.draw(getX(), getY());
		
	}

	@Override
	public float getSize() {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public void collide(ManageEntities manager, Entity other) {
		// TODO Auto-generated method stub
		
	}

}



AbstractEntity:
package knightmare2d.engine.entity;

/**
 * An abstract implementation of an in game entity. This provides
 * the code for the common functionality between the majority of 
 * entities including movement, rotating and collision detection.
 * 
 * @author Guy Curtis
 */
public abstract class AbstractEntity implements Entity {
	/** Location of sprite texture for current entity (defaults to male base template) */
	protected String spriteLocation = "res/sprite/character/MaleBase.png";
	/** Sprite Height for entity (defaults to 48) */
	protected int spriteHeight = 48;
	/** Sprite Width for entity (defaults to 32) */
	protected int spriteWidth = 32;
	/** Character Class (For use with allocating skills etc.) */
	protected CharacterClass characterClass = CharacterClass.OFFICER;
	/** The x position of this entity */
	protected float positionX = 0;
	/** The y position of this entity */
	protected float positionY = 0;
	
	/** The X component of the velocity of this entity */
	protected float velocityX = 0;
	/** The y component of the velocity of this entity */
	protected float velocityY = 0;
	
	/**
	 * @see org.newdawn.asteroids.entity.Entity#update(org.newdawn.asteroids.entity.EntityManager, int)
	 */
	public void update(ManageEntities manager, int delta) {
		// update the position of this entity based on its current
		// velocity. 
		positionX += (velocityX * delta) / 1000.0f;
		positionY += (velocityY * delta) / 1000.0f;
		
	}
	
	/**
	 * @see org.newdawn.asteroids.entity.Entity#getX()
	 */
	public float getX() {
		return positionX;
	}
	
	/**
	 * @see org.newdawn.asteroids.entity.Entity#getY()
	 */
	public float getY() {
		return positionY;
	}
	
	/**
	 * @see org.newdawn.asteroids.entity.Entity#collides(org.newdawn.asteroids.entity.Entity)
	 */
	public boolean collides(Entity other) {
		// We're going to use simple circle collision here since we're 
		// only worried about 2D collision.
		//
		// Normal math tells us that if the distance between the two
		// centers of the circles is less than the sum of their radius
		// then they collide. However, working out the distance between
		// the two would require a square root (Math.sqrt((dx*dx)+(dy*dy))
		// which could be quite slow.
		//
		// Instead we're going to square the sum of their radius and compare
		// that against the un-rooted value. This is equivalent but 
		// much faster
		
		// Get the size of the other entity and combine it with our
		// own, giving the range of collision. Square this so we can
		// compare it against the current distance.
		float otherSize = other.getSize();
		float range = (otherSize + getSize());
		range *= range;

		// Get the distance on X and Y between the two entities, then
		// find the squared distance between the two.
		float dx = getX() - other.getX();
		float dy = getY() - other.getY();
		float distance = (dx*dx)+(dy*dy);
		
		// if the squared distance is less than the squared range
		// then we've had a collision!
		return (distance <= range);
	}
}



Is This A Good Question/Topic? 0
  • +

Replies To: LWJGL & Slick2D - Only binding one texture

#2 TechnoBear  Icon User is offline

  • D.I.C Head

Reputation: 18
  • View blog
  • Posts: 222
  • Joined: 02-November 11

Re: LWJGL & Slick2D - Only binding one texture

Posted 04 October 2013 - 11:05 AM

Still looking for some help on this one
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1