Рендеринг изображения Java приводит к падению fps
Я делаю 2d платформерную игру, я использую сетку 16 на 16 пикселей для блоков. Я пытаюсь загрузить их 5 петлями для всех шириной 10000 пикселей, пример ниже. Проблема в том, что каждый блок загружает свою собственную текстуру из листа спрайта. Я не уверен, что с этим делать. Проблема в том, что я пошел с 4000 кадров в секунду до 200/300. Мне нужно загрузить больше блоков позже случайным генератором местности.
Я обнаружил, что вы можете кэшировать все тайлы вместе, но я понятия не имею, как это сделать. Как предотвратить падение FPS при загрузке таблицы спрайтов в Java?
Я нашел сообщение о том, что я должен загружать только текстуры, которые видны на экране. Возможно, это лучший вариант, но я не понимаю, как я смогу это сделать. Одна из причин этого заключается в том, что, поскольку я хочу, чтобы карта генерировалась случайным образом, ее нужно загружать как минимум, как только я это выдумал?
Игровой класс
public class Game extends Canvas implements Runnable{
private boolean running = false;
private Thread thread;
// Object
Handler handler;
Camera cam;
private void init() {
tex = new Texture();
handler = new Handler();
handler.createTerrain();
handler.addObject(new Player(0, 300, handler, ObjectId.Player));
this.addKeyListener(new KeyInput(handler));
}
public synchronized void start() {
if(running)
return;
running = true;
thread = new Thread(this);
thread.start();
}
// runs the main loop
public void run() {
// get all game objects into the game
init();
this.requestFocus();
// very fun math to calculate frame and tick :/ * leave it as it is *
long lastTime = System.nanoTime();
double amountOfTicks = 60.0;
double ns = 1000000000 / amountOfTicks;
double delta = 0;
long timer = System.currentTimeMillis();
int updates = 0;
int frames = 0;
while(running){
long now = System.nanoTime();
delta += (now - lastTime) / ns;
lastTime = now;
while(delta >= 1){
tick();
updates++;
delta--;
}
render();
frames++;
if(System.currentTimeMillis() - timer > 1000){
timer += 1000;
System.out.println("FPS: " + frames + " TICKS: " + updates);
frames = 0;
updates = 0;
}
}
}
private void tick() {
handler.tick();
}
private void render() {
BufferStrategy bs = this.getBufferStrategy();
if(bs == null) {
this.createBufferStrategy(3);
return;
}
Graphics g = bs.getDrawGraphics();
Graphics2D g2d = (Graphics2D) g;
g.setColor(Color.black);
g.fillRect(0, 0, getWidth(), getHeight());
handler.render(g);
g.dispose();
bs.show();
}
public static Texture getInstance() {
return tex;
}
public static void main(String args[]) {
new Window(800, 600, "#", new Game());
}
}
Класс обработчика
public class Handler {
public ArrayList<GameObject> object = new ArrayList<GameObject>();
public void tick() {
// get a item out the array list
for(GameObject o: object) {
o.tick(object);
}
}
public void render(Graphics g) {
// get a item out the array list
for(GameObject o: object) {
o.render(g);
}
}
public void createTerrain() {
//floor grass
for(int xx = -10000; xx < Game.WIDTH * 2; xx += 16) {
addObject(new Block(xx, Game.HEIGHT - 32, 0,ObjectId.Block));
}
//floor dirt
for(int xx = -10000; xx < Game.WIDTH * 2; xx += 16) {
addObject(new Block(xx, Game.HEIGHT - 16, 1,ObjectId.Block));
}
//floor stone
for(int xx = -10000; xx < Game.WIDTH * 2; xx += 16) {
addObject(new Block(xx, Game.HEIGHT - 0, 2,ObjectId.Block));
}
// sand
for(int xx = -10000; xx < Game.WIDTH * 2; xx += 16) {
addObject(new Block(xx, Game.HEIGHT + 16, 3,ObjectId.Block));
}
//floor water
for(int xx = -10000; xx < Game.WIDTH * 2; xx += 16) {
addObject(new Block(xx, Game.HEIGHT + 32, 4,ObjectId.Block));
}
}
}
Класс текстуры
public class Texture {
SpriteSheet bs, ps;
private BufferedImage block_sheet = null;
private BufferedImage player_sheet = null;
public BufferedImage[] block = new BufferedImage[5];
public BufferedImage[] player = new BufferedImage[9];
public BufferedImage[] player_jump = new BufferedImage[1];
public Texture() {
BufferedImageLoader loader = new BufferedImageLoader();
try {
block_sheet = loader.loadImage("/Block.png");
player_sheet = loader.loadImage("/Player.png");
}catch(Exception e) {
e.printStackTrace();
}
bs = new SpriteSheet(block_sheet);
ps = new SpriteSheet(player_sheet);
getTextures();
}
private void getTextures() {
block[0] = bs.grabImage(1, 1, 16, 16); // grass not broken
block[1] = bs.grabImage(1, 2, 16, 16); // dirt not broken
block[2] = bs.grabImage(1, 3, 16, 16); // stone not broken
block[3] = bs.grabImage(1, 4, 16, 16); // sand not broken
block[4] = bs.grabImage(1, 5, 16, 16); // water
// right
player[0] = ps.grabImage(1, 1, 32, 64); // player standing
player[1] = ps.grabImage(2, 1, 32, 64); // player move right
player[2] = ps.grabImage(3, 1, 32, 64); // player move right
player[3] = ps.grabImage(4, 1, 32, 64); // player move right
// left
player[4] = ps.grabImage(1, 2, 32, 64); // player standing
player[5] = ps.grabImage(2, 2, 32, 64); // player move left
player[6] = ps.grabImage(3, 2, 32, 64); // player move left
player[7] = ps.grabImage(4, 2, 32, 64); // player move left
// jump
player_jump[0] = ps.grabImage(1, 3, 32, 64); // player jumps
}
}
Блок Класс
public class Block extends GameObject{
Texture tex = Game.getInstance();
private int type;
public Block(float x, float y, int type ,ObjectId id) {
super(x, y, id);
this.type = type;
}
public void tick(ArrayList<GameObject> object) {
}
public void render(Graphics g) {
if(type == 0) /* grass */ {
g.drawImage(tex.block[type], (int)x, (int)y, null);
}
if(type == 1) /* dirt */ {
g.drawImage(tex.block[type], (int)x, (int)y, null);
}
if(type == 2) /* stone */ {
g.drawImage(tex.block[type], (int)x, (int)y, null);
}
if(type == 3) /* sand */ {
g.drawImage(tex.block[type], (int)x, (int)y, null);
}
if(type == 4) /* water */ {
g.drawImage(tex.block[type], (int)x, (int)y, null);
}
}
public Rectangle getBounds() {
return new Rectangle((int)x, (int)y, 16, 16);
}
}
Класс SpriteSheet Проблема должна быть здесь, я полагаю, так как все изображения получают свою собственную текстуру
public class SpriteSheet {
private BufferedImage image;
public SpriteSheet(BufferedImage image) {
this.image = image;
}
public BufferedImage grabImage(int col, int row, int width, int height) {
BufferedImage img = image.getSubimage((col * width) - width, (row * height) - height, width, height);
return img;
}
}