我正在制作一个游戏(如“文明”),它具有我想要呈现为图像的不同图块类型。我有9个不同的16x16 png图像加载(称为Con1,Con2等),这里是我的图像加载代码:(img []是我的BufferedImage数组)
public void loadImages(){
for(int i = 0; i < 9; i++){
try {
img[i] = ImageIO.read(this.getClass().getResource("Con"+i+".png"));
}catch (Exception ex) {
System.out.println("Missing Image");
ex.printStackTrace();
}
}
}
然后我用这段代码绘制这些图像:(t [] []是我的瓦片类型数组)
public void paint(Graphics g){
if(loop){
BufferedImage B = new BufferedImage(this.getWidth(), this.getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics r = B.getGraphics();
for (int x = 0; x < WIDTH; x++){
for (int y = 0; y < HEIGHT; y++){
if(i[x][y] == 0){
if (t[x][y] == 0){
g.drawImage(img[0], x, y, this);
}
else if(t[x][y] == 1){
g.drawImage(img[1], x, y, this);
}
else if(t[x][y] == 3){
g.drawImage(img[3], x, y, this);
}
else if(t[x][y] == 4){
g.drawImage(img[4], x, y, this);
}
else if(t[x][y] == 5){
g.drawImage(img[5], x, y, this);
}
}
r.fillRect(x*SCALE, y*SCALE, SCALE, SCALE);
}
}
g.drawImage(B, 0, 22, this);
}
}
我的问题是它在运行时没有正确显示。我得到这个图片:
在窗口的左上角闪烁。我应该看到的是一张类似于上面左侧部分(海洋环绕的陆地)的图像,除了大到足以填满窗户。这里有一些可运行的代码:(我不认为代码会在没有所需图像的情况下运行,但我会很感激帮助您获取所有图像。)
//imports
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
public class MCVCon extends JFrame implements KeyListener, MouseListener{
//setting up variables
public BufferedImage[] img = new BufferedImage[9];
private final int WIDTH = 50, HEIGHT = 50;
private boolean loop = false;
private int SCALE = 16;
int t[][] = new int[WIDTH][HEIGHT]; //terrain type (since I took out the terrain generation it is set to 0 or ocean)
public MCVCon(){
//creating the window
super("Conqueror");
setSize(SCALE*WIDTH, SCALE*HEIGHT+22);
setVisible(true);
requestFocusInWindow();
setDefaultCloseOperation(EXIT_ON_CLOSE);
loadImages();
loop = true;
while(true){
this.repaint();
//delay for repaint
try{
Thread.sleep(50);
}
catch(Exception ex){
ex.printStackTrace();
}
}
}
//load images
public void loadImages(){
for(int i = 0; i < 9; i++){
try {
img[i] = ImageIO.read(this.getClass().getResource("Con"+i+".png"));
}catch (Exception ex) {
System.out.println("Missing Image");
ex.printStackTrace();
}
}
}
//paint the images
public void paint(Graphics g){
if(loop){
BufferedImage B = new BufferedImage(this.getWidth(), this.getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics r = B.getGraphics();
for (int x = 0; x < WIDTH; x++){
for (int y = 0; y < HEIGHT; y++){
if (t[x][y] == 0){
g.drawImage(img[0], x, y, this);
}
else if(t[x][y] == 1){
g.drawImage(img[1], x, y, this);
}
r.fillRect(x*SCALE, y*SCALE, SCALE, SCALE);
}
}
g.drawImage(B, 0, 22, this);
}
}
//run the program
public static void main(String[] args) {
new MCVCon();
}
//necessary overrides
@Override
public void keyTyped(KeyEvent e) {
}
@Override
public void keyPressed(KeyEvent e) {
}
@Override
public void keyReleased(KeyEvent e) {
}
@Override
public void mouseClicked(MouseEvent e) {
}
@Override
public void mousePressed(MouseEvent e) {
}
@Override
public void mouseReleased(MouseEvent e) {
}
@Override
public void mouseEntered(MouseEvent e) {
}
@Override
public void mouseExited(MouseEvent e) {
}
}
我想知道问题可能是什么。提前谢谢。
答案 0 :(得分:1)
所以,我看看你的代码,没有简单的方法可以说,但这是一个混乱,复杂的问题,这将很难隔离任何一个问题的起源,除了说,他们都互相喂食。
让我们从绘画开始......
你直接在画框上画画。出于多种原因,通常不鼓励这样做。
让我们从JFrame
不是单个组件的事实开始,它由多个复合组件组成
这使得直接绘制本身就很危险,因为任何一个子组件都可以在没有调用框架的paint
方法的情况下进行绘制。
直接绘制到一个框架也意味着你在不考虑框架的边框/装饰的情况下进行绘画,这些边框/装饰被添加到窗口的可见区域,但是等待......
setSize(SCALE*WIDTH, SCALE*HEIGHT+22);
建议你试图弥补这一点,但这是“猜测”工作,因为装饰可能会占用更多或更少的空间,具体取决于系统的配置
最后,顶级容器实际上并不是双缓冲的。
“但我正在画自己的缓冲区”你说 - 但你不是
您创建了BufferdImage
并指定了Graphics
上下文t r
BufferedImage B = new BufferedImage(this.getWidth(), this.getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics r = B.getGraphics();
但是当您绘制任何内容时,您使用的是g
,这是传递给Graphics
方法的paint
上下文
g.drawImage(img[0], x, y, this);
这也是非常低效的,因为每次调用BufferedImage
时你都会创建一个新的paint
,这需要时间来创建,占用内存并给垃圾收集过程带来额外的压力。本地对象几乎可以立即获得处置
甚至不让我开始“主要的油漆循环”
您遇到的下一个问题是,您没有虚拟和现实世界空间的概念。
使用t
创建一个虚拟的世界地图,它可以维护有关给定x / y坐标应使用哪个图块的信息,但是您永远不会将其映射到现实世界,而是绘制每个图块瓦片恰好位于相同的像素x / y位置,这意味着它们现在重叠,瓦片具有宽度和高度,这意味着它们在绘制到现实世界时需要偏移。
最后,我认为这是你的实际问题,是关于扩展。您可以通过多种方式应用缩放,可以在加载时预先缩放切片,这样可以大大控制缩放的“方式”,但会将您锁定为单个缩放。
您可以改为维护从主列表生成的缩放图块列表,如果比例更改,则可以更新
或者您可以直接缩放Graphics
上下文。
现在,我根据您的代码创建了一个简单的示例,对上述大部分内容进行了修正。它创建了一系列10x10像素的随机彩色矩形,而不是瓷砖,但概念是相同的。
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class MCVCon extends JFrame {
//setting up variables
public MCVCon() {
//creating the window
super("Conqueror");
add(new GamePane());
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
MCVCon frame = new MCVCon();
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
//necessary overrides
public class GamePane extends JPanel {
public BufferedImage[] img = new BufferedImage[9];
private final int width = 5, height = 5;
private int scale = 16;
int t[][] = new int[width][height]; //terrain type (since I took out the terrain generation it is set to 0 or ocean)
Color[] colors = new Color[]{
Color.RED,
Color.BLUE,
Color.CYAN,
Color.DARK_GRAY,
Color.GRAY,
Color.GREEN,
Color.LIGHT_GRAY,
Color.MAGENTA,
Color.ORANGE,
Color.PINK,
Color.YELLOW
};
int tileHeight = 10;
int tileWidth = 10;
public GamePane() {
loadImages();
Random rnd = new Random();
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int value = rnd.nextInt(9);
System.out.println(value + "- " + colors[value]);
t[x][y] = value;
}
}
Timer timer = new Timer(50, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
repaint();
}
});
timer.start();
}
@Override
public Dimension getPreferredSize() {
return new Dimension(width * tileWidth * scale, height * tileHeight * scale);
}
public void loadImages() {
for (int i = 0; i < 9; i++) {
try {
img[i] = new BufferedImage(tileWidth, tileHeight, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = img[i].createGraphics();
g2d.setColor(colors[i]);
g2d.fill(new Rectangle(0, 0, tileWidth, tileHeight));
g2d.dispose();
} catch (Exception ex) {
System.out.println("Missing Image");
ex.printStackTrace();
}
}
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setTransform(AffineTransform.getScaleInstance(scale, scale));
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
g2d.drawImage(img[t[x][y]], x * tileWidth, y * tileHeight, this);
}
}
g2d.dispose();
}
}
}