我正在尝试开发一种从[100] [100]矩阵中导入背景图像的游戏。矩阵将保持int值以与应在背景上绘制的内容相关联。循环将图像绘制到画布并根据用户的键输入更新它。然而,一切都是油漆和移动都很好,它很慢。是否有更好的方法来加载图像而不是我正在做的方式?
这是主要的游戏类:
package com.game.src.main;
import java.awt.Canvas;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.event.KeyEvent;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.swing.JFrame;
public class Game extends Canvas implements Runnable{
static GraphicsEnvironment environment;
static GraphicsDevice device;
private static final long serialVersionUID = 1L;
public static final int WIDTH = 320;
public static final int HEIGHT = WIDTH / 12 * 9;
public static final int SCALE = 2;
public static final String TITLE = "fgfdsa";
private boolean running = false;
private Thread thread;
private Player p;
private Background b;
private Controller c;
private BufferedImage spriteSheet;
boolean isFiring = false;
public void init(){
BufferedImageLoader loader = new BufferedImageLoader();
try{
spriteSheet = loader.loadImage("/sprite_sheet_test.png");
}catch(IOException e){
e.printStackTrace();
}
requestFocus();
addKeyListener(new KeyInput(this));
c = new Controller();
p = new Player(getWidth() / 2, getHeight() / 2, this);
b = new Background(this);
}
private synchronized void start(){
if(running)
return;
running = true;
thread = new Thread(this);
thread.start();
}
private synchronized void stop(){
if(!running)
return;
running = false;
try {
thread.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.exit(1);
}
public void run(){
init();
long lastTime = System.nanoTime();
final double amountOfTicks = 60.0;
double ns = 1000000000 / amountOfTicks;
double delta = 0;
int updates = 0;
int frames = 0;
long timer = System.currentTimeMillis();
while(running){
long now = System.nanoTime();
delta += (now - lastTime) / ns;
lastTime = now;
if(delta >= 1){
tick();
updates++;
delta--;
}
render();
frames++;
if(System.currentTimeMillis() - timer > 1000){
timer += 1000;
System.out.println(updates + " Ticks, Fps " + frames);
updates = 0;
frames = 0;
}
}
stop();
}
public void tick(){
p.tick();
b.tick();
c.tick();
}
public void render(){
BufferStrategy bs = this.getBufferStrategy();
if(bs == null){
createBufferStrategy(3);
return;
}
Graphics g = bs.getDrawGraphics();
b.render(g);
p.render(g);
c.render(g);
g.dispose();
bs.show();
}
public void keyPressed(KeyEvent e){
int key = e.getKeyCode();
switch(key){
case 37:
b.setX(5);
break;
case 38:
b.setY(5);
break;
case 39:
b.setX(-5);
break;
case 40:
b.setY(-5);
break;
case 32:
if(!isFiring){
c.addBullet(new Bullet(p.getX(), p.getY(), this));
isFiring = true;
}
}
}
public void keyReleased(KeyEvent e){
int key = e.getKeyCode();
switch(key){
case 37:
b.setX(0);
break;
case 38:
b.setY(0);
break;
case 39:
b.setX(0);
break;
case 40:
b.setY(0);
break;
case 32:
isFiring = false;
}
}
public static void main(String[] args){
Game game = new Game();
game.setPreferredSize(new Dimension(600, 600));
game.setMaximumSize(new Dimension(WIDTH * SCALE, HEIGHT * SCALE));
game.setMinimumSize(new Dimension(WIDTH * SCALE, HEIGHT * SCALE));
JFrame frame = new JFrame(game.TITLE);
frame.add(game);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
environment = GraphicsEnvironment.getLocalGraphicsEnvironment();
device = environment.getDefaultScreenDevice();
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
game.start();
}
public BufferedImage getSpriteSheet(){
return spriteSheet;
}
}
这是用于将图像绘制到屏幕的背景类:
package com.game.src.main;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
public class Background {
private BufferedImage grass;
private BufferedImage background;
private BufferedImage tree;
int[][] matrix;
Game game;
//original starting coordinates of matrix to be drawn
int setX = -3200;
int setY = -3200;
//integers used to update coordinates of the matrix to be drawn
int helpX = 0;
int helpY = 0;
public Background(Game game){
this.game = game;
// load matrix into matrix array
GetMatrix gm = new GetMatrix();
matrix = gm.getMatrix();
//import the sprite from game class
background = game.getSpriteSheet();
//call sprite sheet class
SpriteSheet ss = new SpriteSheet(background);
//get coordinates of grass image
grass = ss.grabImage(1, 1, 32, 32);
// get coordinates of tree image
tree = ss.grabImage(4, 1, 32, 32);
}
public void tick(){
//update the start pixel of the background
setX += helpX;
setY += helpY;
if(setX > 0)
setX = 0;
if(setX < -4500)
setX = -4500;
if(setY > 0)
setY = 0;
if(setY < -5340)
setY = -5340;
}
public void render(Graphics g){
int x = 0;
int y = 0;
for(int i = setX; i < setX + 6400; i +=64){
x = 0;
for(int j = setY; j < setY + 6400; j += 64){
switch(matrix[x][y]){
case 0: g.drawImage(grass, i, j, i + 64, j + 64,
0, 0, 32, 32, null);
break;
case 1:
g.drawImage(grass, i, j, i + 64, j + 64,
0, 0, 32, 32, null);
g.drawImage(tree, i, j, i + 64, j + 64,
0, 0, 32, 32, null);
}
x++;
}
y++;
}
}
//sets the background start coordinates from key input
public void setX(int x){
helpX = x;
}
public void setY(int y){
helpY = y;
}
}
答案 0 :(得分:3)
SpriteSheet#grabImage(...)
的作用并不明显。但我很确定有一些涉及BufferedImage#getSubImage(...)
的电话。是吗?
如果这是正确的,这里有两个潜在的问题:
使用ImageIO加载图像时,生成图像的类型未知。通过“类型”我引用BufferedImage#getType()
。此类型可能是BufferedImage.TYPE_CUSTOM
,特别是当它是具有透明度的PNG时。当绘制具有此类型的图像时,此绘画非常慢,因为内部已完成一些颜色转换。
当您致电BufferedImage#getSubImage(...)
时,您调用此方法的图片将变为“非托管”。这意味着实际的图像数据不能再直接保存在视频内存中。 (这个细节背后有一些非常复杂的技术细节。这些细节可能会在不同的JRE版本之间发生变化。例如,它们在Java 6和Java 7之间发生了变化。但是,经验法则是:如果你想要绘制高图像性能,不要在要绘制的图像上调用BufferedImage#getSubImage(...)
这两个问题的解决方案可以是将图像转换为BufferedImage.TYPE_INT_ARGB
类型的托管图像。因此,对于您想要绘制的每个图像,您可以调用
BufferedImage toPaint = convertToARGB(originalImage);
用这种方法:
public static BufferedImage convertToARGB(BufferedImage image)
{
BufferedImage newImage = new BufferedImage(
image.getWidth(), image.getHeight(),
BufferedImage.TYPE_INT_ARGB);
Graphics2D g = newImage.createGraphics();
g.drawImage(image, 0, 0, null);
g.dispose();
return newImage;
}
在您的示例中,您可以将其应用于grass
和tree
图片。
另一个(可能更重要的)问题是你似乎正在绘制你的平铺缩放:你似乎画了一个尺寸为32x32的64x64像素精灵。如果这是正确的,那么您可以考虑重新调整输入图像一次,然后绘制原始大小为32x32的图块。
在任何情况下,很难预测这些变化实际带来多少加速,但它们应该值得一试。