LWGJL3 2D tiles system programming issues

Started by wini, May 03, 2017, 10:18:46

Previous topic - Next topic

wini

Howdy everybody!

I've been toying with a 2d platformer-like java program that uses a tile system. When I hit a big problem I need to solve, I either endlessly manipulate code till it does something i want, or I give up and find some answers elsewhere. Ive based my code on the help of ElegantWhelp who can be found https://www.youtube.com/watch?v=KqgB1qYU-wg&index=18&list=PLILiqflMilIxta2xKk2EftiRHD4nQGW0u

Im having trouble manipulating the code so I can have multiple tiles, and be able to prioritize which tile is shown first (z-axis?), or even above the player.

Tile Class:
package world;

public class Tile {
	public static Tile tiles[] = new Tile[16];
	
	public static final Tile test_tile = new Tile((byte) 0, "tile1");
	public static final Tile test2 = new Tile((byte)1, "checker").setSolid();
	
	private byte id;
	private boolean solid;
	private String texture;

	
	public Tile(byte id, String texture) {
		this.id = id;
		this.texture = texture;
		this.solid = false;
		if(tiles[id] != null)
			throw new IllegalStateException("Tiles at ["+id+"] is already being used!");
		tiles[id] = this;
		

		
	}
	
	public Tile setSolid() { this.solid = true; return this; }
	public boolean isSolid() { return solid; }

	public byte getId() {
		return id;
	}

	public String getTexture() {
		return texture;
	}


}

TileRenderer class
package world;

import java.util.HashMap;

import org.joml.Matrix4f;
import org.joml.Vector3f;

import render.Camera;
import render.Model;
import render.Shader;
import render.Texture;

public class TileRenderer {
	
	private HashMap<String, Texture> tile_textures;
	private Model tile_model;
	
	public TileRenderer() {
		tile_textures = new HashMap<String, Texture>();
		float[] vertices = new float[] {
				-1f,1f,0,
				1f,1f,0,
				1f,-1f,0,
				-1f,-1f,0,

		};
		
		float[] texture = new float[] {
				0,0,
				1,0,
				1,1,
				0,1,

		};
		
		int[] indices = new int[] {
				0,1,2,
				2,3,0
		};
		
		tile_model = new Model(vertices,texture,indices);
		
		for(int i = 0; i < Tile.tiles.length; i++) {
			if(Tile.tiles[i] != null) {
				if(!tile_textures.containsKey(Tile.tiles[i].getTexture())) {
					String tex = Tile.tiles[i].getTexture();				
					tile_textures.put(tex,new Texture(tex+".png"));
				}
			}
		}
	}
	public void renderTile(Tile tile, int x, int y, Shader shader, Matrix4f world, Camera cam) {
		shader.bind();
		if(tile_textures.containsKey (tile.getTexture())) {
			tile_textures.get(tile.getTexture()).bind(0);
			
			Matrix4f tile_pos = new Matrix4f().translate( new Vector3f(x*2, y*2, 0));
			Matrix4f target = new Matrix4f();
			
			cam.getProjection().mul(world, target);
			target.mul(tile_pos);
			
			shader.setUniform("sampler", 0);
			shader.setUniform("projection", target);
			
			tile_model.render();
		}
	}

}

World Class
package world;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.imageio.ImageIO;

import org.joml.Matrix4f;
import org.joml.Vector2f;
import org.joml.Vector3f;

import collision.AABB;
import entity.Entity;
import entity.NPC;
import entity.Player;
import entity.PlayerTexture;
import entity.Transform;
import io.Window;
import render.Camera;
import render.Shader;

public class World {
	private final int view = 24;
	private byte[] tiles;
	private AABB[] bounding_boxes;
	private AABB[] bounding_boxes2;
	private List<Entity> entities;
	private int width;
	private int height;
	private int scale;
	
	private Matrix4f world;
	
	public World(String world, Camera camera) {
		
		
		try {
			BufferedImage tile_sheet = ImageIO.read(new File("./levels/" + world + "/tiles.png"));
			BufferedImage entity_sheet = ImageIO.read(new File("./levels/" + world + "/entities.png"));
			BufferedImage npc_sheet = ImageIO.read(new File("./levels/" + world + "/npc.png"));
			
			width = tile_sheet.getWidth();
			height = tile_sheet.getHeight();
			
			
			//GAME GRAPHICS SCALE VARIABLE
			scale = 20;
			
			this.world = new Matrix4f().setTranslation(new Vector3f(0));
			this.world.scale(scale);
			
			int[] colorTileSheet = tile_sheet.getRGB(0, 0, width, height, null, 0, width);
			int[] colorEntitySheet = entity_sheet.getRGB(0, 0, width, height, null, 0, width);
			int[] colorNPCSheet = npc_sheet.getRGB(0, 0, width, height, null, 0, width);
			
			tiles = new byte[width * height];
			bounding_boxes = new AABB[width * height];
			bounding_boxes2 = new AABB[width * height];
			entities = new ArrayList<Entity>();
			

			Transform transform;
			
			for(int y = 0; y < height; y++) {
				for(int x = 0; x < width; x++) {
					int red = (colorTileSheet[x + y * width] >> 16) & 0xFF;
					int entity_index = (colorEntitySheet[x + y * width] >> 16) & 0xFF;
					int entity_alpha = (colorEntitySheet[x + y * width] >> 24) & 0xFF;
					int npc_index = (colorNPCSheet[x + y * width] >> 16) & 0xFF;
					int npc_alpha = (colorNPCSheet[x + y * width] >> 24) & 0xFF;
					
					Tile t;
					try {
						t = Tile.tiles[red];
					}catch(ArrayIndexOutOfBoundsException e) {
						t = null;
					}
					
					if (t != null)
						setTile(t, x, y);
					
					if(entity_alpha > 0) {
						transform = new Transform();
						transform.pos.x = x*2;
						transform.pos.y = -y*2;
						switch(entity_index) {
						case 1:							//Player
//							Player player = new Player(transform);
//	
//							entities.add(player);
//							camera.getPosition().set(transform.pos.mul(-scale, new Vector3f()));
	
							break;
						default:
							
							break;
						}
					}
					
					if(npc_alpha > 0) {
						transform = new Transform();
						transform.pos.x = x*2;
						transform.pos.y = -y*2;
						switch(npc_index) {
						case 1:							//Player
//							NPC npc = new NPC(transform);
//							entities.add(npc);
	
							break;
						default:
							
							break;
						}
					}
				}
			}

		} catch (IOException e) {
			e.printStackTrace();
		}
			}
		
	
	public World() {
		width = 64;
		height = 64;
		scale = 16;
		
		
		tiles = new byte[width * height];
		bounding_boxes = new AABB[width * height];
		bounding_boxes2 = new AABB[width * height];
		

	}
	public Matrix4f getWorldMatrix() { return world; }
	
	public void render(TileRenderer render, Shader shader, Camera cam, Window window) {

		int posX = (int)cam.getPosition().x / (scale * 2);
		int posY = (int)cam.getPosition().y / (scale * 2);
		
		for(int i = 0; i < view; i++) {
			for(int j = 0; j < view; j++) {
				Tile t = getTile(i-posX-(view/2)+1, j+posY-(view/2));
				if(t != null)
					render.renderTile(t, i-posX-(view/2)+1, -j-posY+(view/2), shader, world, cam);
				}
			}
		
		for(Entity entity : entities) {
			entity.render(shader, cam, this);
			}
		}
	
	public void update(float delta, Window window, Camera camera) {
		for(Entity entity : entities) {
			entity.update(delta, window, camera, this);
		}
		
		for(int i = 0; i < entities.size(); i++) {
			entities.get(i).collideWithTiles(this);
			for(int j = i+1; j < entities.size(); j++) {
				entities.get(i).collideWithEntity(entities.get(j));
			}
			entities.get(i).collideWithTiles(this);
		}
	}
	
	public void correctCamera(Camera camera, Window window) {
		Vector3f pos = camera.getPosition();
		
		int w = -width * scale * 2;
		int h = height * scale * 2;
		
		if(pos.x > -(window.getWidth()/2)+scale)
			pos.x = -(window.getWidth()/2)+scale;
		if(pos.x < w +(window.getWidth()/2)+scale)
			pos.x = w + (window.getWidth()/2)+scale;
		
		if(pos.y < (window.getHeight()/2)-scale)
			pos.y = (window.getHeight()/2)-scale;
		if(pos.y > h - (window.getHeight()/2)-scale)
			pos.y = h-(window.getHeight()/2)-scale;
	}

	
	public void setTile(Tile tile, int x, int y) {
		tiles[x + y * width] = tile.getId();
		if(tile.isSolid()) {
			bounding_boxes[x + y * width] = new AABB(new Vector2f(x*2, -y*2), new Vector2f(1,1));
			bounding_boxes2[x + y * width] = new AABB(new Vector2f(x*2, -y*2), new Vector2f(1,1));
		} else {
			bounding_boxes[x + y * width] = null;
			bounding_boxes2[x + y * width] = null;
		}
	}
	
	public Tile getTile(int x, int y) {
		try {
			return Tile.tiles[tiles[x + y * width]];
		} catch (ArrayIndexOutOfBoundsException e) {
			return null;
		}
	}
	
	public AABB getTileBoundingBox(int x, int y) {
		try {
			return bounding_boxes[x + y * width];
		} catch (ArrayIndexOutOfBoundsException e) {
			return null;
		}
	}
	
	
	public AABB getTileBoundingBox2(int x, int y) {
		try {
			return bounding_boxes2[x + y * width];
		} catch (ArrayIndexOutOfBoundsException e) {
			return null;
		}
	}


	public int getScale() {

		return scale;
	}
}


Through the help of ElegantWhelps tutorial I managed to code how to set up individual graphics for each tile in the tile class. But say what if I wanted three, and prioritize each tile. I thought maybe a way to do this is to create a second

private byte[] tiles2;


and duplicate all the related code in the World class. This kind of worked, but not in the way I intended. The duplicate tiles seem to overdraw with the grass texture, maybe because its only accessing the green tile, the foreground tile. I realize that I need to look back at some of ElegantWhelps tutorial about how he applies different tile textures to seperate tiles (such as the grass foreground and the checker boundaries).

I also create a new BufferedImage tileSheet which I called:

BufferedImage tile_sheet2 = ImageIO.read(new File("./levels/" + world + "/tiles2.png"));


This World class loads a template(using BufferedImage) that assigns each tile position depending on the color value you use. In this case and in the tutorial he uses r1 g0 b0 value. So if you draw five squares in the template, it will assign a tile to those five squares. There is also a AABB and Collision class in another package that handles collision reasonably well. I may upload the code somewhere so people can check it out for themselves.

So I realize im stuck and semi-confused about how to bring in more tile textures and load them into more tile templates. If anyone has any advice on how to go about this, I would much appreciate it. Thanks :)