I get this strange error from loading "Player.png" file from the Player Class.
I understand that my organization of the code is very sloppy and the methods I use are terrible. half of the code is borrowed from tutorials.
What 2 classes are supposed to do is create a screen with green colored tiles filling up the screen with a "player" sprite that can move right, left, up, and down with the W,A,S,D keys.
error:
java.io.IOException: Attempt to allocate a texture to big for the current hardware
at org.newdawn.slick.opengl.InternalTextureLoader.getTexture(InternalTextureLoader.java:293)
at org.newdawn.slick.opengl.InternalTextureLoader.getTexture(InternalTextureLoader.java:231)
at
org.newdawn.slick.opengl.InternalTextureLoader.getTexture(InternalTextureLoader.java:184)
at org.newdawn.slick.opengl.TextureLoader.getTexture(TextureLoader.java:64)
at org.newdawn.slick.opengl.TextureLoader.getTexture(TextureLoader.java:24)
at test.PlayerClass.render(PlayerClass.java:69)
at test.Main.render(Main.java:110)
at test.Main.run(Main.java:82)
at test.Main.main(Main.java:27)
Main Class
public class Main{
private static boolean running = true;
public static final int WIDTH = 1024;
public static final int HEIGHT = 768;
private static Texture tile;
static PlayerClass playerClass = new PlayerClass(100, 100, 32, 32);
public static void main(String[] args){
Main main = new Main();
main.run();
}
//Initialize Method
public static void init(int width, int height ) throws LWJGLException
{
DisplayMode[] m = Display.getAvailableDisplayModes();
for(DisplayMode mode : m)
{
if(mode.getWidth() == 1024 && mode.getHeight() == 768 && mode.getBitsPerPixel() == 32)
{
Display.setDisplayMode(mode);
}
}
Display.setTitle("Game");
Display.setVSyncEnabled(true);
Display.sync(100);
Display.create();
GL11.glMatrixMode(GL11.GL_PROJECTION);
GL11.glLoadIdentity();
GL11.glOrtho(0, Display.getDisplayMode().getWidth(), Display.getDisplayMode().getHeight(), 0, -1, 1 );
GL11.glMatrixMode(GL11.GL_MODELVIEW);
GL11.glLoadIdentity();
GL11.glEnable(GL11.GL_ALPHA_TEST);
GL11.glAlphaFunc(GL11.GL_GREATER, 0.2f);
GL11.glEnable(GL11.GL_TEXTURE_2D);
try {
tile = TextureLoader.getTexture("PNG", ResourceLoader.getResourceAsStream("RPG/tile.png"));
}
catch (IOException e)
{
e.printStackTrace();
}
}
public void run()
{
try {
init(1024, 768);
} catch (LWJGLException e) {
e.printStackTrace();
}
while(running)
{
Display.update();
drawTiled(WIDTH, HEIGHT);
input();
update();
render();
}
cleanup();
}
public static void input()
{
if(Keyboard.isKeyDown(Keyboard.KEY_ESCAPE))
{
running = false;
}
playerClass.input();
}
public static void update()
{
}
public static void render()
{
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT);
GL11.glLoadIdentity();
try {
playerClass.render();
} catch (IOException e) {
e.printStackTrace();
}
Display.update();
}
public static void cleanup()
{
Display.destroy();
}
public void drawTiled(int screenWidth, int screenHeight) {
Color.white.bind();
tile.bind();
int numberPerRow = screenWidth / tile.getTextureWidth();
int numberOfRows = screenHeight / tile.getTextureHeight();
GL11.glBegin(GL11.GL_QUADS);
for (int j = 0; j < numberOfRows; j++) {
//System.out.print("{");
for (int i = 0; i < numberPerRow; i++)
{
//top left
GL11.glTexCoord2f(0, 0);
GL11.glVertex2f(tile.getTextureWidth() * i, tile.getTextureHeight() * j);
//top right
GL11.glTexCoord2f(1, 0);
GL11.glVertex2f(tile.getTextureWidth() * (i + 1), tile.getTextureHeight() * j);
//bottom right
GL11.glTexCoord2f(1, 1);
GL11.glVertex2f(tile.getTextureWidth() * (i + 1), tile.getTextureHeight() * (j + 1));
//bottom left
GL11.glTexCoord2f(0, 1);
GL11.glVertex2f(tile.getTextureWidth() * i, tile.getTextureHeight() * (j + 1));
}
}
}
}
Player Class
public class PlayerClass {
private float x, y;
private int w, h;
private Texture player;
private FloatBuffer verts = BufferUtils.createFloatBuffer(2 * 4);
private FloatBuffer tex = BufferUtils.createFloatBuffer(2 * 4);
public PlayerClass(float X, float Y, int W, int H)
{
x = X;
y = Y;
w = W;
h = H;
verts.put(new float[]{
0.0f, 0.0f,
32.0f, 0.0f,
32.0f, 32.0f,
0.0f, 32.0f
});
tex.put(new float[]{
0.0f, 0.0f,
1.0f, 0.0f,
1.0f, 1.0f,
0.0f, 1.0f
});
}
public void input()
{
if(Keyboard.isKeyDown(Keyboard.KEY_W))
{
y -= 10;
}
else if(Keyboard.isKeyDown(Keyboard.KEY_S))
{
y += 10;
}
if(Keyboard.isKeyDown(Keyboard.KEY_A))
{
x -= 10;
}
else if(Keyboard.isKeyDown(Keyboard.KEY_D))
{
x += 10;
}
}
public void render() throws IOException
{
player = TextureLoader.getTexture("PNG", ResourceLoader.getResourceAsStream("RPG/player.png"));
player.bind();
verts.rewind();
tex.rewind();
GL11.glEnableClientState(GL11.GL_VERTEX_ARRAY);
GL11.glEnableClientState(GL11.GL_TEXTURE_COORD_ARRAY);
GL11.glTranslatef(x, y, 0.0f);
GL11.glVertexPointer(2, 0, verts);
GL11.glTexCoordPointer(2, 0, tex);
GL11.glDrawArrays(GL11.GL_QUADS, 0, 4);
GL11.glTranslatef(-x, -y, 0.0f);
GL11.glDisableClientState(GL11.GL_VERTEX_ARRAY);
GL11.glDisableClientState(GL11.GL_TEXTURE_COORD_ARRAY);
}
}
Run this:
System.out.println(GL11.glGetInteger(GL11.GL_MAX_TEXTURE_SIZE));
It'll tell you the max texture size allowed by your Graphics card. Make sure that your graphics card can handle a texture of the size that you are trying to use. According to the error, it can't.
How large is tile.png - the maximum texture size can vary depending your card, and I think, some other factors. Your file is probably outside this dimension.
Cody's answer gives you the way to get the max texture size for your card. If you're writing a game for use by many other people, you'll probably want to integrate that code into your game code in such a way that it loads different resolution textures based on the capabilities of the card it's running on, or simply find a default that works on any card that you want to support, and use that for all installations.
Here's some additional reading that will explain more about this issue, some history about it, and more technical info that you might find useful:
Official OpenGL wiki on 'Texture'
List of maximum texture size by video card (from 2006, but you'll get the idea)
An FAQ of texture mapping
Related
I am creating a 2D turn-based Star Wars game where the player has to move from tile to tile in a grid system, all the while avoiding enemies (I know, exciting stuff right!!). The grid is a 2D Array of Tiles, which are objects that I created using Slick and Light-Weight Java Game Library (lwjgl) so that I could add texture to them. I'm pretty new to all of this, and I'm trying to add click listeners to my tiles (or TileGrid?) so that when I click on a tile the player will move there, but I'm having no luck thus far. If any one could help in this matter they will receive my heartfelt thank you and 50% of the game rights when I sell the game to LucasArts!
Getters and Setters omitted
Tile Class
public class Tile {
private float x, y, width, height;
private Texture texture;
private TileType type;
public Tile(float x, float y, float width, float height, TileType type) {
setX(x);
setY(y);
setWidth(width);
setHeight(height);
setType(type);
setTexture(quickLoad(type.textureName));
}
public void draw() {
drawQuadTex(texture, x, y, width, height);
}
}
TileGrid Class
public class TileGrid extends JFrame {
public Tile[][] map;
public TileGrid() {
int width = Artist.getGridWidth();
int height = Artist.getGridHeight();
map = new Tile[width][height];
for(int i = 0; i < map.length; i++) {
for(int j = 0; j < map[i].length; j++) {
map[i][j] = new Tile(i * 64, j * 64, 64, 64, TileType.Space1);
}
}
}
public static int[][] randomGridGenerator() {
Random random = new Random();
int width = Artist.getGridWidth();
int height = Artist.getGridHeight();
int[][] map = new int[width][height];
for(int i = 0; i < map.length; i++) {
for(int j = 0; j < map[i].length; j++) {
int randInt = random.nextInt(20) + 1;
map[i][j] = randInt;
}
}
return map;
}
public TileGrid(int[][] newMap) {
addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
int x = e.getX();
int y = e.getY();
System.out.println(x + ", " + y);
}
});
int width = Artist.getGridWidth();
int height = Artist.getGridHeight();
map = new Tile[width][height];
for(int i = 0; i < map.length; i++) {
for(int j = 0; j < map[i].length; j++) {
switch (newMap[i][j]) {
case 1:
map[i][j] = new Tile(i * 64, j * 64, 64, 64, TileType.Space1);
break;
case 2:
map[i][j] = new Tile(i * 64, j * 64, 64, 64, TileType.Space2);
break;
}
}
}
}
public void setTile(int xCoord, int yCoord, TileType type) {
map[xCoord][yCoord] = new Tile(xCoord * 64, yCoord * 64, 64, 64, type);
}
public Tile getRandomTile() {
Random rand = new Random();
int width = Artist.getGridWidth();
int height = Artist.getGridHeight();
int x = rand.nextInt(width) ;
int y = rand.nextInt(height);
return map[x][y];
}
public Tile getTile(int xCoord, int yCoord) {
return map[xCoord][yCoord];
}
public void draw() {
for(int i = 0; i < map.length; i++) {
for(int j = 0; j < map[i].length; j++) {
Tile t = map[i][j];
drawQuadTex(t.getTexture(), t.getX(), t.getY(), t.getWidth(), t.getHeight());
}
}
}
TileType Class
public enum TileType {
Space1("space64-1"), Space2("space64-2"), Space3("space64-3"), Space4("space64-4"), Space5("space64-5"),
Space6("space64-6"), Space7("space64-7"), Space8("space64-8"), Space9("space64-9"), Space10("space64-10"),
Space11("space64-11"), Space12("space64-12"), Space13("space64-13"), Space14("space64-14"), Space15("space64-15"),
Space16("space64-16"), Space17("space64-17"), Space18("space64-18"), Space19("space64-19"), Space20("space64-20");
String textureName;
TileType(String textureName) {
this.textureName = textureName;
}
}
Player Class
public class Player extends SpaceShip {
private TileGrid grid;
private int width, height, health;
float x, y;
private Texture texture;
private Tile locationTile;
/*
public Player(Texture texture, Tile startTile, int width, int height) {
setTexture(texture);
setX(startTile.getX());
setY(startTile.getY());
setWidth(width);
setHeight(height);
}
*/
public Player(Texture texture, TileGrid grid, int width, int height) {
setTexture(texture);
Tile tile = grid.getRandomTile();
setLocationTile(tile);
setX(tile.getX());
setY(tile.getY());
setWidth(width);
setHeight(height);
setGrid(grid);
}
public void movePlayer() {
int height = Artist.getHeight();
Tile newLocation = grid.getTile((int) Math.floor(Mouse.getX() / 64), (int) Math.floor((height - Mouse.getY() - 1)/ 64));
setLocationTile(newLocation);
setX(newLocation.getX());
setY(newLocation.getY());
}
public void draw() {
drawQuadTex(texture, x, y, width, height);
}
Entry Point
public class Boot {
public Boot() {
beginSession();
int[][] map = randomGridGenerator();
TileGrid grid = new TileGrid(map);
// Player p = new Player(quickLoad("x-wing"), grid.getTile(10, 10), 64, 64);
Player p = new Player(quickLoad("x-wing"), grid, 64, 64);
while(!Display.isCloseRequested()) {
grid.draw();
p.draw();
//p.movePlayer();
Display.update();
Display.sync(60);
}
Display.destroy();
}
public static void main(String[] args) {
new Boot();
}
}
}
Artist Class (for rendering etc.)
public class Artist {
public static final int WIDTH = 1280, HEIGHT = 960;
public static final int GRID_WIDTH = 20, GRID_HEIGHT = 15;
public static void beginSession() {
Display.setTitle("Star Wars");
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);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
public static void drawQuad(float x, float y, float width, float height) {
glBegin(GL_QUADS);
glVertex2f(x, y);
glVertex2f(x + width, y);
glVertex2f(x + width, y + height);
glVertex2f(x, y + height);
glEnd();
}
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);
} catch (IOException e) {
e.printStackTrace();
}
return tex;
}
public static Texture quickLoad(String name) {
Texture tex = null;
tex = loadTexture("resources/" + name + ".png", "PNG");
return tex;
}
In my attempt above the event should just return the coordinates when I click on it. My intention is to complete the player move logic once I've set up the event listener. All help appreciated.
I wrote a method that makes it easy to draw images when you set the size of a normal picture, there is no problem, but when you try to draw an image with alpha channel image is smaller than it should be.
To give you a clearer view two pictures:
Knight left is theoretically the same size as a green square.
In the second picture you can see it clearly. I do not know where the problem lies, the usual images you can set the size of the problem but without including the alpha channel is not.
#SuppressWarnings("unused")
public class Start {
float x = 400, y = 300;
float rotation = 0;
/** time at last frame */
long lastFrame;
/** frames per second */
int fps;
/** last fps time */
long lastFPS;
/** is VSync Enabled */
boolean vsync;
public void start() {
try {
Display.setDisplayMode(new DisplayMode(1280, 720));
Display.create();
} catch (LWJGLException e) {
e.printStackTrace();
System.exit(0);
}
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, 1280, 720, 0, 1, -1);
glMatrixMode(GL_MODELVIEW);
glEnable(GL_TEXTURE_2D);
getDelta(); // call once before loop to initialise lastFrame
lastFPS = getTime(); // call before loop to initialise fps timer
Texture tex = LoadTexture("res/1.png", "PNG");
Texture t2 = LoadTexture("res/image.png", "PNG");
Texture t3 = LoadTexture("res/atack1/1.png", "PNG");
while (!Display.isCloseRequested()) {
int delta = getDelta();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
update(delta);
DrawImage(t3, 0, 0, 100, 120);
glEnd();
Display.update();
Display.sync(60); // cap fps to 60fps
}
Display.destroy();
System.exit(0);
}
public void update(int delta) {
// rotate quad
rotation += 0.15f * delta;
if (Keyboard.isKeyDown(Keyboard.KEY_LEFT)) x -= 0.35f * delta;
if (Keyboard.isKeyDown(Keyboard.KEY_RIGHT)) x += 0.35f * delta;
if (Keyboard.isKeyDown(Keyboard.KEY_UP)) y -= 0.35f * delta;
if (Keyboard.isKeyDown(Keyboard.KEY_DOWN)) y += 0.35f * delta;
while (Keyboard.next()) {
if (Keyboard.getEventKeyState()) {
if (Keyboard.getEventKey() == Keyboard.KEY_F) {
setDisplayMode(1280, 720, !Display.isFullscreen());
}
else if (Keyboard.getEventKey() == Keyboard.KEY_V) {
vsync = !vsync;
Display.setVSyncEnabled(vsync);
}
}
}
// keep quad on the screen
if (x < 0) x = 0;
if (x > 800) x = 800;
if (y < 0) y = 0;
if (y > 600) y = 600;
updateFPS(); // update FPS Counter
}
/**
* Set the display mode to be used
*
* #param width The width of the display required
* #param height The height of the display required
* #param fullscreen True if we want fullscreen mode
*/
public void setDisplayMode(int width, int height, boolean fullscreen) {
// return if requested DisplayMode is already set
if ((Display.getDisplayMode().getWidth() == width) &&
(Display.getDisplayMode().getHeight() == height) &&
(Display.isFullscreen() == fullscreen)) {
return;
}
try {
DisplayMode targetDisplayMode = null;
if (fullscreen) {
DisplayMode[] modes = Display.getAvailableDisplayModes();
int freq = 0;
for (int i=0;i<modes.length;i++) {
DisplayMode current = modes[i];
if ((current.getWidth() == width) && (current.getHeight() == height)) {
if ((targetDisplayMode == null) || (current.getFrequency() >= freq)) {
if ((targetDisplayMode == null) || (current.getBitsPerPixel() > targetDisplayMode.getBitsPerPixel())) {
targetDisplayMode = current;
freq = targetDisplayMode.getFrequency();
}
}
// if we've found a match for bpp and frequence against the
// original display mode then it's probably best to go for this one
// since it's most likely compatible with the monitor
if ((current.getBitsPerPixel() == Display.getDesktopDisplayMode().getBitsPerPixel()) &&
(current.getFrequency() == Display.getDesktopDisplayMode().getFrequency())) {
targetDisplayMode = current;
break;
}
}
}
} else {
targetDisplayMode = new DisplayMode(width,height);
}
if (targetDisplayMode == null) {
System.out.println("Failed to find value mode: "+width+"x"+height+" fs="+fullscreen);
return;
}
Display.setDisplayMode(targetDisplayMode);
Display.setFullscreen(fullscreen);
} catch (LWJGLException e) {
System.out.println("Unable to setup mode "+width+"x"+height+" fullscreen="+fullscreen + e);
}
}
/**
* Calculate how many milliseconds have passed
* since last frame.
*
* #return milliseconds passed since last frame
*/
public int getDelta() {
long time = getTime();
int delta = (int) (time - lastFrame);
lastFrame = time;
return delta;
}
/**
* Get the accurate system time
*
* #return The system time in milliseconds
*/
public long getTime() {
return (Sys.getTime() * 1000) / Sys.getTimerResolution();
}
/**
* Calculate the FPS and set it in the title bar
*/
public void updateFPS() {
if (getTime() - lastFPS > 1000) {
Display.setTitle("FPS: " + fps);
fps = 0;
lastFPS += 1000;
}
fps++;
}
public void initGL() {
GL11.glMatrixMode(GL11.GL_PROJECTION);
GL11.glLoadIdentity();
GL11.glOrtho(0, 800, 0, 600, 1, -1);
GL11.glMatrixMode(GL11.GL_MODELVIEW);
}
public static void main(String[] argv) {
Start fullscreenExample = new Start();
fullscreenExample.start();
}
public static void DrawImage(Texture texture,float x,float y, float width, float height){
if(texture != null){
texture.bind();
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
//set transparency
glColor4f(1, 1, 1,1);
//
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);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return tex;
}
}
It looks like the images are different sizes but you're applying the full 0-1 texcoord on both quads. This will use the full width and height of the texture as you've loaded it.
The way to fix this is to determine how many pixels the knight sprite actually is and use that to calculate a value between 0 and 1 for your texcoord.
For example, if the knight width is 60 pixels and the full image width is 100 pixels, your X texcoord would be (60.0f / 100.0f) which is 0.6f. Do the same thing for the Y axis.
Here's a great tutorial on OpenGL textures that may also help clear a few other things up for you: https://open.gl/textures
I am trying to make a scrolling game - where the player (in space) is constantly at the center of the screen. As he moves left right up and down, a background spritesheet will randomly generate coloured stars - so the moving stars will be an indication of which direction the player is moving in.
The problem I am now having is that the stars are not displaying when I run the game. Each tile is supposed to be 32x32, each containing at least one star, with the 'nostars' tile being empty. When I run the game, I just get a black screen.
RandomLevel.java:
protected void generateLevel() {
for(int y = 0; y < height; y++) {
for(int x = 0; x < width; x++) {
bgtiles[x + y * width] = random.nextInt(4);
}
}
}
Level.java
public void render(int xScroll, int yScroll, Screen screen) {
screen.setOffset(xScroll, yScroll);
int x0 = xScroll >> 5;
int x1 = (xScroll + screen.width + 32) >> 5;
int y0 = yScroll >> 5;
int y1 = (yScroll + screen.height + 32) >> 5;
for(int y = y0; y < y1; y++) {
for(int x = x0; x < x1; x++) {
getTile(x, y).render(x, y, screen);
}
}
}
public Tile getTile(int x, int y) {
if(x < 0 || y < 0 || x >= width || y >= height) return Tile.nostars;
if(bgtiles[x + y * width] == 0) return Tile.stars1;
if(bgtiles[x + y * width] == 1) return Tile.stars2;
if(bgtiles[x + y * width] == 2) return Tile.stars3;
if(bgtiles[x + y * width] == 3) return Tile.stars4;
else return Tile.nostars;
}
SpaceTile.java
public class SpaceTile extends Tile {
public SpaceTile(Sprite sprite) {
super(sprite);
}
public void render(int x, int y, Screen screen) {
screen.renderTile(x << 5, y << 5, this);
}
}
SpriteSheet.java
public static SpriteSheet bgtiles = new SpriteSheet("/textures/bgsheet.png", 256);
Sprite.java
public static Sprite spaceSprite = new Sprite(32, 0, 0, SpriteSheet.bgtiles);
public static Sprite stars1 = new Sprite(64, 0, 0, SpriteSheet.bgtiles);
public static Sprite stars2 = new Sprite(96, 0, 0, SpriteSheet.bgtiles);
public static Sprite stars3 = new Sprite(128, 0, 0, SpriteSheet.bgtiles);
public static Sprite stars4 = new Sprite(160, 0, 0, SpriteSheet.bgtiles);
Tile.java
public class Tile {
public int x, y;
public Sprite sprite;
public static Tile nostars = new SpaceTile(Sprite.spaceSprite);
public static Tile stars1 = new SpaceTile(Sprite.stars1);
public static Tile stars2 = new SpaceTile(Sprite.stars2);
public static Tile stars3 = new SpaceTile(Sprite.stars3);
public static Tile stars4 = new SpaceTile(Sprite.stars4);
public Tile(Sprite sprite) {
this.sprite = sprite;
}
public void render(int x, int y, Screen screen) {
}
public boolean solid() {
return false;
}
}
Game.java
public class Game extends Canvas implements Runnable {
private static final long serialVersionUID = 1L;
public static int width = 300;
public static int height = width / 16 * 9;
public static int scale = 3;
public static String title = "Game";
private Thread thread;
private JFrame frame;
private Keyboard key;
private Level level;
private boolean running = false;
private Screen screen;
private BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
private int[] pixels = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
public Game() {
Dimension size = new Dimension(width * scale, height * scale);
setPreferredSize(size);
screen = new Screen(width, height);
frame = new JFrame();
key = new Keyboard();
level = new RandomLevel(64, 64);
addKeyListener(key);
}
public synchronized void start() {
running = true;
thread = new Thread(this, "Display");
thread.start();
}
public synchronized void stop() {
running = false;
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void run() {
double ns = 1000000000.0 / 60.0;
double delta = 0;
int frames = 0;
int updates = 0;
long lastTime = System.nanoTime();
long timer = System.currentTimeMillis();
requestFocus();
while (running) {
long now = System.nanoTime();
delta += (now - lastTime) / ns;
lastTime = now;
while(delta >= 1) {
update();
updates++;
delta--;
}
render();
frames++;
if(System.currentTimeMillis() - timer >= 1000) {
timer += 1000;
frame.setTitle(title + " | " + updates + " ups, " + frames + " fps");
frames = 0;
updates = 0;
}
}
stop();
}
int x, y = 0;
public void update() {
key.update();
if(key.up == true) y--;
if(key.down == true) y++;
if(key.left == true) x--;
if(key.right == true) x++;
}
public void render() {
BufferStrategy bs = getBufferStrategy();
if (bs == null) {
createBufferStrategy(3);
return;
}
screen.clear();
level.render(x, y, screen);
for(int i = 0; i < pixels.length; i++) {
pixels[i] = screen.pixels[i];
}
Graphics g = bs.getDrawGraphics();
g.drawImage(image, 0, 0, getWidth(), getHeight(), null);
g.dispose();
bs.show();
}
public static void main(String[] args) {
Game game = new Game();
game.frame.setResizable(false);
game.frame.setTitle(Game.title);
game.frame.add(game);
game.frame.pack();
game.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
game.frame.setLocationRelativeTo(null);
game.frame.setVisible(true);
game.start();
}
}
bgsheet.png
https://i.imgur.com/0yUKql2.png?1
In the generatelevel() I am only trying it out with the first 4 tiles, not all of the 64 tiles.
When I run the game, I expect to see 4 different stars scattered everywhere but instead I just get a black screen.
Thanks in advance for any help !
From the code posted, it appears that you forgot to load the background into image. I placed this code into a new public method called loadAssets(). Call this before you call game.start().
public void loadAssets() {
try {
image = ImageIO.read(new URL("https://i.imgur.com/0yUKql2.png?1"));
} catch (MalformedURLException ex) {
Logger.getLogger(GameTwo.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(GameTwo.class.getName()).log(Level.SEVERE, null, ex);
}
}
I also commented out the following code in render().
screen.clear();
level.render(x, y, screen);
for(int i = 0; i < pixels.length; i++) {
pixels[i] = screen.pixels[i];
}
So from what I understand, you make a call to draw using BufferedImage image, however you have not actually loaded your image data into the variable image. I will provide a code snippet that you may need to tailor a bit
File imageFile = new File("/path/to/image.file");
BufferedImage image = ImageIO.read(imageFile);
There may be a faster way as you have already called
private BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
But as you can probably imagine, that doesn't actually connect you image variable to an image file. My best guess is that the code I provided will work, but honestly you'll have to try it.
Happy coding and leave a comment if you have any questions!
The problem turned out to be simply that I had the wrong co-ordinates for each sprite. Sorry for wasting your time and thanks for the help anyway!
public static Sprite spaceSprite = new Sprite(32, 0, 0, SpriteSheet.bgtiles);
public static Sprite stars1 = new Sprite(32, 1, 0, SpriteSheet.bgtiles);
public static Sprite stars2 = new Sprite(32, 2, 0, SpriteSheet.bgtiles);
public static Sprite stars3 = new Sprite(32, 3, 0, SpriteSheet.bgtiles);
public static Sprite stars4 = new Sprite(32, 4, 0, SpriteSheet.bgtiles);
*THIS HAS BEEN SOLVED
Well, the problem is that in LWJGL I made a basic FPS camera using glTranslatef and glRotatef. It acts like it should at first, but when I move the camera it starts rotating around a pivot from where the camera originally was! Here's my code (Without the imports and such) :
public class Main {
public static float camera_x,camera_y,camera_z,camera_rot;
public static ArrayList<Block>blocks = new ArrayList<Block>();
public Main(){
try{
Display.setDisplayMode(new DisplayMode(800,600));
Display.setTitle("Voxel");
Display.create();
}catch(LWJGLException e){
e.printStackTrace();
}
//Init
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective((float)45,800f/600f,0.1f,1000.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glShadeModel(GL_SMOOTH);
glEnable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);
glDepthFunc(GL_LEQUAL);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
generateWorld();
glTranslatef(0,15,0);
float dt,time,lastTime = 0;
Mouse.setGrabbed(true);
while(!Display.isCloseRequested() && !Keyboard.isKeyDown(Keyboard.KEY_ESCAPE)){
time = Sys.getTime();
dt = (time - lastTime)/1000.0f;
lastTime = time;
render();
tick();
Display.update();
Display.sync(60);
}
Display.destroy();
System.exit(0);
}
public void tick(){
camera_x = 0;
camera_y = 0;
camera_z = 0;
camera_rot = 0;
if(Keyboard.isKeyDown(Keyboard.KEY_W)){
camera_z = +1;
}
else if(Keyboard.isKeyDown(Keyboard.KEY_S)){
camera_z = -1;
}
if(Keyboard.isKeyDown(Keyboard.KEY_A)){
camera_x = +1;
}
else if(Keyboard.isKeyDown(Keyboard.KEY_D)){
camera_x = -1;
}
if(Keyboard.isKeyDown(Keyboard.KEY_SPACE)){
camera_y = -1;
}
else if(Keyboard.isKeyDown(Keyboard.KEY_LSHIFT)){
camera_y = +1;
}
while(Keyboard.next()){
if(Keyboard.isKeyDown(Keyboard.KEY_R)){
generateWorld();
}
}
//Updating all of the blocks
for(int i=0; i < blocks.size(); i++){
blocks.get(i).tick();
}
camera_rot += Mouse.getDX();
}
public void render(){
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glRotatef(camera_rot, 0f, 1f, 0f);
glTranslatef(camera_x, camera_y, camera_z);
for(int i=0; i < blocks.size(); i++){
blocks.get(i).render();
}
}
public static void main(String[] arguments){
new Main();
}
public void generateWorld(){
blocks.clear();
int heightlevel = 0;
Random r = new Random();
for(int i=0; i < 50; i++){
for(int j=0; j < 50; j++){
if(r.nextBoolean() == false){
heightlevel -= 4;
}
else{
heightlevel += 4;
}
blocks.add(new Block((i*4)-64,-8+ heightlevel,(j*4)-64,4,4,4));
float y = -8+heightlevel;
for(int k = 0; k < 10; k++){
blocks.add(new Block((i*4)-64,y - (k*4),(j*4)-64,4,4,4));
}
}
}
}
}
There's a Block class as well:
public class Block {
public float x,y,z,width,height,depth,shade;
public Random rand;
public Block(float xx,float yy,float zz,float ww,float hh,float dd){
x = xx;
y = yy;
z = zz;
width = ww;
height = hh;
depth = dd;
rand = new Random();
shade = (rand.nextFloat()+0.2f);
}
public void tick(){
}
public void render(){
glBegin(GL_QUADS);
glColor3f(0,shade,0);
//Front
glTexCoord2f(0,0);
glVertex3f(x,y,z);
glTexCoord2f(1,0);
glVertex3f(x+width,y,z);
glTexCoord2f(1,1);
glVertex3f(x+width,y+height,z);
glTexCoord2f(0,1);
glVertex3f(x,y+height,z);
//Back
glVertex3f(x,y,z+depth);
glVertex3f(x+width,y,z+depth);
glVertex3f(x+width,y+height,z+depth);
glVertex3f(x,y+height,z+depth);
//Left
glVertex3f(x,y,z);
glVertex3f(x,y,z+depth);
glVertex3f(x,y+height,z+depth);
glVertex3f(x,y+height,z);
//Right
glVertex3f(x+width,y,z);
glVertex3f(x+width,y,z+depth);
glVertex3f(x+width,y+height,z+depth);
glVertex3f(x+width,y+height,z);
//Top
glVertex3f(x,y,z);
glVertex3f(x+width,y,z);
glVertex3f(x+width,y,z+depth);
glVertex3f(x,y,z+depth);
//Bottom
glVertex3f(x,y+height,z);
glVertex3f(x+width,y+height,z);
glVertex3f(x+width,y+height,z+depth);
glVertex3f(x,y+height,z+depth);
glEnd();
}
}
That is because you need to flip the calls. So it is like:
glRotatef(camera_rot, 0f, 1f, 0f);
glTranslatef(camera_x, camera_y, camera_z);
and not like this:
glTranslatef(camera_x, camera_y, camera_z);
glRotatef(camera_rot, 0f, 1f, 0f);
The reason is that you rotate the camera, and then you translate the camera. This gives the effect you are seeing, since it rotates using camera_rot, and then it translates according to camera_x, camera_y, camera_z.
Edit
You need to change this:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glRotatef(camera_rot, 0f, 1f, 0f);
glTranslatef(camera_x, camera_y, camera_z);
Into this:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glRotatef(camera_rot, 0f, 1f, 0f);
glTranslatef(camera_x, camera_y, camera_z);
So when you've done that you will realize that your cameras position and rotation will be stuck. That is because each time you call tick()
You call:
camera_x = 0;
camera_y = 0;
camera_z = 0;
camera_rot = 0;
What that does is resetting the position and rotation, and that is why the camera "gets stuck".
So you need to change that so the values increment or decrement and not just stay at -1, 0 and 1.
There may be some mess with coordinates since they are also rotated. You can try rotating your (camera_x, camera_y, camera_z) vector, but I'd recommend you to use GLU.gluLookAt().
It does all the work for you, you just have to do some simple vector math to evaluate eye point, reference point and up vector from your camera_x, camera_y, camera_z and camera_rot values.
You can read gluLookAt specification and learn about Up vector.
UPD: Also I tried to mess with glTranslate* and glRotate* a bit, here is what I got:
while (!Display.isCloseRequested()) {
//clear:
GL11.glLoadIdentity();
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
GL11.glRotatef(90.0f, -1.0f, 0.0f, 0.0f); //with z axis looking up we get Oxy plane being wrong oriented, it is a little odd for me and I prefer to set z axis vertical ))
//rotate and translate:
GL11.glRotatef(camera_rot, 0.0f, 0.0f, 1.0f); //rotate
GL11.glTranslatef(camera_x, camera_y, camera_z); //translate
/* draw here */
//process input:
float move = 0.0f;
float strife = 0.0f;
if (Keyboard.isKeyDown(Keyboard.KEY_A)) {
strife -= 0.1f;
}
if (Keyboard.isKeyDown(Keyboard.KEY_D)) {
strife += 0.1f;
}
if (Keyboard.isKeyDown(Keyboard.KEY_W)) {
move += 0.1f;
}
if (Keyboard.isKeyDown(Keyboard.KEY_S)) {
move -= 0.1f;
}
//we move relatively to the direction we are looking
camera_x -= strife * Math.cos(Math.toRadians(rotp)) + move * Math.sin(Math.toRadians(rotp));
camera_y -= - strife * Math.sin(Math.toRadians(rotp)) + move * Math.cos(Math.toRadians(rotp));
camera_rot += Mouse.getDX();
//Display stuff
Display.update();
Display.sync(60);
}
This code works well for me.
I have researched this for days. It appears that most folks want to place buttons on a transparent canvas or shell. I need to place transparent clickable objects over a canvas/component. In my testing I find that if I don't attempt to put the object on the canvas it simply never displays.
In the final project the application will be showing animated objects with a number of controls that I plan to use images for.
In the example I am trying to work out I have taken Snipped195 which displays a turning torus. I am attempting to place an image label over the torus such that as the torus turns it will show through the area of the label that is transparent. I have set up a gif file that is a red plus sign and has a transparent background. I also picked up some code (can't remember where it came from now) that is part of the paintControl method that looks for transparent pixels and builds a Region object. The region object obviously is doing what it needs to do to define where the image goes. Do I need to apply the region somehow to the image instead of the canvas?
At first when I tried to do this I did get the image displayed. However where the transparent areas where it displayed white. After implementing the paintControl code it at least handled the transparent area properly. Now I need to get the actual image content to display.
I built an object to take care of the image label. I called it TransparentImageLabel. It looks like:
public class TransparentImageLabel extends Canvas {
private Image labelImage;
public TransparentImageLabel(Composite parent, Image image, int style) {
super(parent, style);
this.labelImage = image;
addDisposeListener(new DisposeListener() {
public void widgetDisposed(DisposeEvent e) {
TransparentImageLabel.this.widgetDisposed(e);
}
});
addPaintListener(new PaintListener() {
public void paintControl(PaintEvent e) {
TransparentImageLabel.this.paintControl(e);
}
});
}
private void widgetDisposed(DisposeEvent e) {
}
private void paintControl(PaintEvent event) {
System.out.println("at paint control");
ImageData imgData = this.labelImage.getImageData();
Region region = new Region();
if (imgData.alphaData != null) {
Rectangle pixel = new Rectangle(0, 0, 1, 1);
for (int y = 0; y < imgData.height; y++) {
for (int x = 0; x < imgData.width; x++) {
if (imgData.getAlpha(x, y) == 255) {
pixel.x = imgData.x + x;
pixel.y = imgData.y + y;
region.add(pixel);
}
}
}
} else {
ImageData mask = imgData.getTransparencyMask();
Rectangle pixel = new Rectangle(0, 0, 1, 1);
for (int y = 0; y < mask.height; y++) {
for (int x = 0; x < mask.width; x++) {
if (mask.getPixel(x, y) != 0) {
pixel.x = imgData.x + x;
pixel.y = imgData.y + y;
region.add(pixel);
}
}
}
}
this.setRegion(region);
event.gc.drawImage(labelImage, this.getBounds().x, this.getBounds().y);
region.dispose();
}
}
After adding this to Snipped195 the code looks like:
public class Snippet195 {
private Image redPlus;
static void drawTorus(float r, float R, int nsides, int rings) {
float ringDelta = 2.0f * (float) Math.PI / rings;
float sideDelta = 2.0f * (float) Math.PI / nsides;
float theta = 0.0f, cosTheta = 1.0f, sinTheta = 0.0f;
for (int i = rings - 1; i >= 0; i--) {
float theta1 = theta + ringDelta;
float cosTheta1 = (float) Math.cos(theta1);
float sinTheta1 = (float) Math.sin(theta1);
GL11.glBegin(GL11.GL_QUAD_STRIP);
float phi = 0.0f;
for (int j = nsides; j >= 0; j--) {
phi += sideDelta;
float cosPhi = (float) Math.cos(phi);
float sinPhi = (float) Math.sin(phi);
float dist = R + r * cosPhi;
GL11.glNormal3f(cosTheta1 * cosPhi, -sinTheta1 * cosPhi, sinPhi);
GL11.glVertex3f(cosTheta1 * dist, -sinTheta1 * dist, r * sinPhi);
GL11.glNormal3f(cosTheta * cosPhi, -sinTheta * cosPhi, sinPhi);
GL11.glVertex3f(cosTheta * dist, -sinTheta * dist, r * sinPhi);
}
GL11.glEnd();
theta = theta1;
cosTheta = cosTheta1;
sinTheta = sinTheta1;
}
}
private Snippet195() {
final Display display = new Display();
Shell shell = new Shell(display, SWT.NO_REDRAW_RESIZE);
shell.setLayout(new FillLayout());
Composite comp = new Composite(shell, SWT.NONE);
comp.setLayout(new FillLayout());
GLData data = new GLData();
data.doubleBuffer = true;
redPlus = new Image(shell.getDisplay(), new ImageData(
Snippet237.class.getResourceAsStream("/red-plus.png")));
final GLCanvas canvas = new GLCanvas(comp, SWT.NONE, data);
canvas.addPaintListener(new PaintListener() {
public void paintControl(PaintEvent e) {
e.gc.setAlpha(15);
e.gc.drawImage(Snippet195.this.redPlus, 0, 0);
}
});
canvas.setCurrent();
try {
GLContext.useContext(canvas);
} catch (LWJGLException e) {
e.printStackTrace();
}
canvas.addListener(SWT.Resize, new Listener() {
public void handleEvent(Event event) {
Rectangle bounds = canvas.getBounds();
float fAspect = (float) bounds.width / (float) bounds.height;
canvas.setCurrent();
try {
GLContext.useContext(canvas);
} catch (LWJGLException e) {
e.printStackTrace();
}
GL11.glViewport(0, 0, bounds.width, bounds.height);
GL11.glMatrixMode(GL11.GL_PROJECTION);
GL11.glLoadIdentity();
GLU.gluPerspective(45.0f, fAspect, 0.5f, 400.0f);
GL11.glMatrixMode(GL11.GL_MODELVIEW);
GL11.glLoadIdentity();
}
});
GL11.glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
GL11.glColor3f(1.0f, 0.0f, 0.0f);
GL11.glHint(GL11.GL_PERSPECTIVE_CORRECTION_HINT, GL11.GL_NICEST);
GL11.glClearDepth(1.0);
GL11.glLineWidth(2);
GL11.glEnable(GL11.GL_DEPTH_TEST);
TransparentImageLabel redPlusLabel = new TransparentImageLabel(canvas,
redPlus, SWT.NONE);
redPlusLabel.setSize(48, 48);
redPlusLabel.setLocation(500, 200);
shell.setText("SWT/LWJGL Example");
shell.setSize(880, 720);
shell.open();
final Runnable run = new Runnable() {
int rot = 0;
public void run() {
if (!canvas.isDisposed()) {
canvas.setCurrent();
try {
GLContext.useContext(canvas);
} catch (LWJGLException e) {
e.printStackTrace();
}
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT
| GL11.GL_DEPTH_BUFFER_BIT);
GL11.glClearColor(.3f, .5f, .8f, 1.0f);
GL11.glLoadIdentity();
GL11.glTranslatef(0.0f, 0.0f, -10.0f);
float frot = rot;
GL11.glRotatef(0.15f * rot, 2.0f * frot, 10.0f * frot, 1.0f);
GL11.glRotatef(0.3f * rot, 3.0f * frot, 1.0f * frot, 1.0f);
rot++;
GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_LINE);
GL11.glColor3f(0.9f, 0.9f, 0.9f);
drawTorus(1, 1.9f + ((float) Math.sin((0.004f * frot))), 25, 75);
canvas.swapBuffers();
display.asyncExec(this);
}
}
};
canvas.addListener(SWT.Paint, new Listener() {
public void handleEvent(Event event) {
run.run();
}
});
display.asyncExec(run);
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}
public static void main(String[] args) {
new Snippet195();
}
}
I have to be close. The areas of the image that are defined as transparent are being drawn as transparent. But I'm not getting anything but a white plus instead of the red that is in the image.
The problem is in your TransparentImageLabel#paintControl(..) method. Correct the second last line to the following:
event.gc.drawImage(labelImage, 0, 0);
Since you are drawing within the context of the canvas so the coordinates you specify for location should be relative to that Canvas. You are currently using the location of canvas which is returned relative to it's parent.