I'm currently working on a tile-based game in Java with Java2D. However, I think I'm missing something really stupid, or maybe not, the thing is that I checked my code thousands of times and I didn't saw anything weird. So this is the print of my game right now:
我目前正在开发Java中使用Java2D的基于瓦片的游戏。但是,我觉得我漏掉了一些非常愚蠢的东西,或者可能没有,问题是我检查了我的代码几千次,我没有看到任何奇怪的东西。这就是我现在的游戏:
But it should look something like this:
但它应该是这样的:
Well, I know, it looks fine but if you take a look at the image of my tile-based level:
嗯,我知道,它看起来不错,但如果你看看我的基于瓷砖的水平的图像:
(grays tiles are bricks, green tiles are grass and brown tiles are dirt)
(灰色的砖是砖,绿色的砖是草,棕色的砖是土)
So the bricks tiles are duplicated on some weird way. So, here is my Level code:
所以砖块瓷砖以某种奇怪的方式被复制。这是我的水平代码:
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
import com.wg.MainComponent;
import com.wg.entity.Entity;
import com.wg.entity.Particle;
import com.wg.entity.Projectile;
import com.wg.entity.mob.Mob;
import com.wg.entity.mob.Player;
public abstract class Level {
public BufferedImage levelImage;
public BufferedImage[][] tile;
public Rectangle[][] rect;
public int tileSize;
public float xOffset, yOffset;
public ArrayList<BufferedImage> collision = new ArrayList<BufferedImage>();
public ArrayList<Player> players = new ArrayList<Player>();
public ArrayList<Projectile> projectiles = new ArrayList<Projectile>();
public ArrayList<Particle> particles = new ArrayList<Particle>();
private List<Entity> entities = new ArrayList<Entity>();
public BufferedImage[] tilesBufferedImages;
public int[] xCollisionOffset;
public int[] yCollisionOffset;
public Level(BufferedImage levelImage, int tileSize, BufferedImage[] tilesBufferedImages, int[] xCollisionOffset, int[] yCollisionOffset) {
this.tilesBufferedImages = tilesBufferedImages;
this.xCollisionOffset = xCollisionOffset;
this.yCollisionOffset = yCollisionOffset;
this.levelImage = levelImage;
this.tileSize = tileSize;
tile = new BufferedImage[levelImage.getWidth()][levelImage.getHeight()];
rect = new Rectangle[levelImage.getWidth()][levelImage.getHeight()];
generateLevel();
}
public abstract void generateLevel();
public void render(float xOffset, float yOffset, int scale, Graphics2D screen) {
this.xOffset = xOffset;
this.yOffset = yOffset;
for (int y = (int) Math.max(yOffset / (tileSize + scale), 0); y < Math.min((MainComponent.height + yOffset) / (tileSize + scale) + 1, levelImage.getHeight()); y++) {
for (int x = (int) Math.max(xOffset / (tileSize + scale), 0); x < Math.min((MainComponent.width + xOffset) / (tileSize + scale) + 1, levelImage.getWidth()); x++) {
if (tile[x][y] != null)
screen.drawImage(tile[x][y], (int) (x * (tileSize + scale) - xOffset), (int) (y * (tileSize + scale) - yOffset), (tileSize + scale), (tileSize + scale), null);
}
}
for (int i = 0; i < entities.size(); i++) {
entities.get(i).render(screen);
}
for (int i = 0; i < players.size(); i++) {
players.get(i).render(screen);
}
for (int i = 0; i < projectiles.size(); i++) {
projectiles.get(i).render(screen);
}
for (int i = 0; i < particles.size(); i++) {
particles.get(i).render(screen);
}
}
public void add(Entity e) {
if (e instanceof Particle) {
particles.add((Particle) e);
} else if (e instanceof Player) {
players.add((Player) e);
} else if (e instanceof Projectile) {
projectiles.add((Projectile) e);
} else {
entities.add(e);
}
}
public void update(int scale) {
for (int y = 0; y < levelImage.getHeight(); y++) {
for (int x = 0; x < levelImage.getWidth(); x++) {
if (tile[x][y] != null && rect[x][y] == null) {
for (int i = 0; i < tilesBufferedImages.length; i++) {
if (tilesBufferedImages[i] == tile[x][y])
rect[x][y] = new Rectangle(x * (tileSize + scale) - Math.round(xOffset) + xCollisionOffset[i], y * (tileSize + scale) - Math.round(yOffset) + yCollisionOffset[i], (tileSize + scale) + xCollisionOffset[i], (tileSize + scale) + yCollisionOffset[i]);
}
} else if (tile[x][y] != null && rect[x][y] != null) {
for (int i = 0; i < tilesBufferedImages.length; i++) {
if (tilesBufferedImages[i] == tile[x][y])
rect[x][y].setBounds(x * (tileSize + scale) - Math.round(xOffset) + xCollisionOffset[i], y * (tileSize + scale) - Math.round(yOffset) + xCollisionOffset[i], (tileSize + scale) + xCollisionOffset[i], (tileSize + scale) + yCollisionOffset[i]);
}
}
}
}
for (int i = 0; i < entities.size(); i++) {
entities.get(i).update();
}
for (int i = 0; i < players.size(); i++) {
players.get(i).update();
}
for (int i = 0; i < projectiles.size(); i++) {
projectiles.get(i).update();
}
for (int i = 0; i < particles.size(); i++) {
particles.get(i).update();
}
remove();
}
public List<Player> getPlayers() {
return players;
}
public Player getPlayerAt(int index) {
return players.get(index);
}
public Player getClientPlayer() {
return players.get(0);
}
private void remove() {
for (int i = 0; i < entities.size(); i++) {
if (entities.get(i).isRemoved())
entities.remove(i);
}
for (int i = 0; i < projectiles.size(); i++) {
if (projectiles.get(i).isRemoved())
projectiles.remove(i);
}
for (int i = 0; i < players.size(); i++) {
if (players.get(i).isRemoved())
players.remove(i);
}
for (int i = 0; i < particles.size(); i++) {
if (particles.get(i).isRemoved())
particles.remove(i);
}
}
public boolean tileDownCollision(Mob en, boolean fixed) {
Point p = null;
if (fixed)
p = new Point(Math.round(en.x), Math.round(en.y + en.height));
else if (!fixed)
p = new Point(Math.round(en.x - xOffset), Math.round(en.y + en.height - yOffset));
try {
for (int y = 0; y < levelImage.getHeight(); y++) {
for (int x = 0; x < levelImage.getWidth(); x++) {
if (tile[x][y] != null) {
if (rect[x][y] != null && rect[x][y].contains(p)) {
if (collision.contains(tile[x][y]))
return true;
}
}
}
}
} catch (ArrayIndexOutOfBoundsException e) {
}
return false;
}
public boolean tileUpCollision(Mob en, boolean fixed) {
Point p = null;
if (fixed)
p = new Point(Math.round(en.x), Math.round(en.y - 1));
else if (!fixed)
p = new Point(Math.round(en.x - xOffset), Math.round(en.y - 1 - yOffset));
try {
for (int y = 0; y < levelImage.getHeight(); y++) {
for (int x = 0; x < levelImage.getWidth(); x++) {
if (tile[x][y] != null) {
if (rect[x][y] != null && rect[x][y].contains(p)) {
if (collision.contains(tile[x][y]))
return true;
}
}
}
}
} catch (ArrayIndexOutOfBoundsException e) {
}
return false;
}
public boolean tileLeftCollision(Mob en, boolean fixed) {
Point p = null;
if (fixed)
p = new Point(Math.round(en.x - 1), Math.round(en.y));
else if (!fixed)
p = new Point(Math.round(en.x - 1 - xOffset), Math.round(en.y - yOffset));
try {
for (int y = 0; y < levelImage.getHeight(); y++) {
for (int x = 0; x < levelImage.getWidth(); x++) {
if (tile[x][y] != null) {
if (rect[x][y] != null && rect[x][y].contains(p)) {
if (collision.contains(tile[x][y]))
return true;
}
}
}
}
} catch (ArrayIndexOutOfBoundsException e) {
}
return false;
}
public boolean tileRightCollision(Mob en, boolean fixed) {
Point p = null;
if (fixed)
p = new Point(Math.round(en.x + en.width), Math.round(en.y));
else if (!fixed)
p = new Point(Math.round(en.x + en.width - xOffset), Math.round(en.y - yOffset));
try {
for (int y = 0; y < levelImage.getHeight(); y++) {
for (int x = 0; x < levelImage.getWidth(); x++) {
if (tile[x][y] != null) {
if (rect[x][y] != null && rect[x][y].contains(p)) {
if (collision.contains(tile[x][y]))
return true;
}
}
}
}
} catch (ArrayIndexOutOfBoundsException e) {
}
return false;
}
public boolean projectileDownCollision(Projectile en, boolean fixed) {
Point p = null;
if (fixed)
p = new Point(Math.round(en.x), Math.round(en.y + en.height));
else if (!fixed)
p = new Point(Math.round(en.x - xOffset), Math.round(en.y + en.height - yOffset));
try {
for (int y = 0; y < levelImage.getHeight(); y++) {
for (int x = 0; x < levelImage.getWidth(); x++) {
if (tile[x][y] != null) {
if (rect[x][y] != null && rect[x][y].contains(p)) {
if (collision.contains(tile[x][y]))
return true;
}
}
}
}
} catch (ArrayIndexOutOfBoundsException e) {
}
return false;
}
public boolean projectileUpCollision(Projectile en, boolean fixed) {
Point p = null;
if (fixed)
p = new Point(Math.round(en.x), Math.round(en.y - 1));
else if (!fixed)
p = new Point(Math.round(en.x - xOffset), Math.round(en.y - 1 - yOffset));
try {
for (int y = 0; y < levelImage.getHeight(); y++) {
for (int x = 0; x < levelImage.getWidth(); x++) {
if (tile[x][y] != null) {
if (rect[x][y] != null && rect[x][y].contains(p)) {
if (collision.contains(tile[x][y]))
return true;
}
}
}
}
} catch (ArrayIndexOutOfBoundsException e) {
}
return false;
}
public boolean projectileLeftCollision(Projectile en, boolean fixed) {
Point p = null;
if (fixed)
p = new Point(Math.round(en.x - 1), Math.round(en.y));
else if (!fixed)
p = new Point(Math.round(en.x - 1 - xOffset), Math.round(en.y - yOffset));
try {
for (int y = 0; y < levelImage.getHeight(); y++) {
for (int x = 0; x < levelImage.getWidth(); x++) {
if (tile[x][y] != null) {
if (rect[x][y] != null && rect[x][y].contains(p)) {
if (collision.contains(tile[x][y]))
return true;
}
}
}
}
} catch (ArrayIndexOutOfBoundsException e) {
}
return false;
}
public boolean projectileRightCollision(Projectile en, boolean fixed) {
Point p = null;
if (fixed)
p = new Point(Math.round(en.x + en.width), Math.round(en.y));
else if (!fixed)
p = new Point(Math.round(en.x + en.width - xOffset), Math.round(en.y - yOffset));
try {
for (int y = 0; y < levelImage.getHeight(); y++) {
for (int x = 0; x < levelImage.getWidth(); x++) {
if (tile[x][y] != null) {
if (rect[x][y] != null && rect[x][y].contains(p)) {
if (collision.contains(tile[x][y]))
return true;
}
}
}
}
} catch (ArrayIndexOutOfBoundsException e) {
}
return false;
}
public boolean mobProjectileCollision(Mob en, Projectile pr, boolean fixed) {
Rectangle p1 = null;
if (fixed)
p1 = new Rectangle(Math.round(en.x), Math.round(en.y), en.width, en.height);
else if (!fixed)
p1 = new Rectangle(Math.round(en.x - xOffset), Math.round(en.y - yOffset), en.width, en.height);
Rectangle p2 = null;
if (fixed)
p2 = new Rectangle(Math.round(pr.x), Math.round(pr.y), pr.width, pr.height);
else if (!fixed)
p2 = new Rectangle(Math.round(pr.x - xOffset), Math.round(pr.y - yOffset), pr.width, pr.height);
if (p1.intersects(p2))
return true;
return false;
}
public double calcDistance(Entity e1, Entity e2) {
return Math.sqrt(((e1.x - e2.x) * (e1.x - e2.x)) + ((e1.y - e2.y) * (e1.y - e2.y)));
}
}
The Level is rendered into the render(Graphics2D) method. It is an abstract class so I have a subclass of it, Level1, in the case it is the one in the image.
该级别被呈现到呈现(Graphics2D)方法中。它是一个抽象类,所以我有它的一个子类,Level1,在这个例子中它是图像中的一个。
import static com.wg.MainComponent.spritesheet;
import java.awt.Color;
import java.awt.image.BufferedImage;
import com.wg.BufferedImageLoader;
import com.wg.entity.mob.Player;
public class Level1 extends Level {
public static final BufferedImage bricks = crop(0, 2);
public static final BufferedImage dirt = crop(1, 2);
public static final BufferedImage grass = crop(2, 2);
public static final BufferedImage[] tilesList = { bricks, dirt, grass };
public static final int[] defaultxCollisionOffset = { 0, 0, 0 };
public static final int[] defaultyCollisionOffset = { 0, 0, 0 };
private static BufferedImage level = BufferedImageLoader.load("/level1.png");
private static BufferedImage crop(int x, int y) {
return spritesheet.getSubimage(x * 16, y * 16, 16, 16);
}
public void generateLevel() {
for (int y = 0; y < levelImage.getHeight(); y++) {
for (int x = 0; x < levelImage.getWidth(); x++) {
Color c = new Color(level.getRGB(x, y));
String data = String.format("%02x%02x%02x", c.getRed(), c.getGreen(), c.getBlue());
if (data.equals("838383"))
tile[x][y] = bricks;
else if (data.equals("bea100"))
tile[x][y] = dirt;
else if (data.equals("23d200"))
tile[x][y] = grass;
}
}
}
public Level1(float xOffset, float yOffset) {
super(level, 16, tilesList, defaultxCollisionOffset, defaultyCollisionOffset);
collision.add(grass);
collision.add(dirt);
collision.add(bricks);
add(new Player(50, 20, 1, 2, 32 + 32, 32 + 32, this));
this.xOffset = xOffset;
this.yOffset = yOffset;
}
}
Well, I know that would be really hard to find the error just with two classes, so I made a MCVE :). (To run it create a folder called image in your C: with this inside called level1.png and this image called tiles.png)
我知道仅仅用两个类是很难找到错误的,所以我做了MCVE:)。(要运行它,在你的C:中创建一个名为image的文件夹,其中名为level1。png和这个叫做tiles.png的图像)
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
public class MCVE extends JFrame {
public static final int WIDTH = 800;
public static final int HEIGHT = 600;
private MCVELevel1 level1 = new MCVELevel1(0, 0);
public static void main(String[] args) {
MCVE mcve = new MCVE();
mcve.setVisible(true);
mcve.setSize(WIDTH, HEIGHT);
mcve.setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public void paint(Graphics g) {
level1.render(50, 400, 32, (Graphics2D) g);
}
private static class MCVELevel1 extends MCVELevel {
private static BufferedImage spritesheet = BufferedImageLoader.load("C://image//tiles.png");
public static final BufferedImage bricks = crop(0, 0);
public static final BufferedImage dirt = crop(1, 0);
public static final BufferedImage grass = crop(2, 0);
public static final BufferedImage[] tilesList = { bricks, dirt, grass };
public static final int[] defaultxCollisionOffset = { 0, 0, 0 };
public static final int[] defaultyCollisionOffset = { 0, 0, 0 };
private static BufferedImage level = BufferedImageLoader.load("C://image//level1.png");
private static BufferedImage crop(int x, int y) {
return spritesheet.getSubimage(x * 16, y * 16, 16, 16);
}
public void generateLevel() {
for (int y = 0; y < levelImage.getHeight(); y++) {
for (int x = 0; x < levelImage.getWidth(); x++) {
Color c = new Color(level.getRGB(x, y));
String data = String.format("%02x%02x%02x", c.getRed(), c.getGreen(), c.getBlue());
if (data.equals("838383"))
tile[x][y] = bricks;
else if (data.equals("bea100"))
tile[x][y] = dirt;
else if (data.equals("23d200"))
tile[x][y] = grass;
}
}
}
public MCVELevel1(float xOffset, float yOffset) {
super(level, 16, tilesList, defaultxCollisionOffset, defaultyCollisionOffset);
this.xOffset = xOffset;
this.yOffset = yOffset;
}
}
public static class BufferedImageLoader {
public static BufferedImage load(String path) {
try {
return ImageIO.read(new File(path));
} catch (IOException e) {
e.printStackTrace();
}
throw new NullPointerException("No file found at: " + path);
}
public static BufferedImage load(URL url) {
try {
return ImageIO.read(url);
} catch (IOException e) {
e.printStackTrace();
}
throw new NullPointerException("No file found at: " + url.getPath());
}
}
}
The MCVELevel class:
MCVELevel类:
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
public abstract class MCVELevel {
public BufferedImage levelImage;
public BufferedImage[][] tile;
public Rectangle[][] rect;
public int tileSize;
public float xOffset, yOffset;
public BufferedImage[] tilesBufferedImages;
public int[] xCollisionOffset;
public int[] yCollisionOffset;
public MCVELevel(BufferedImage levelImage, int tileSize, BufferedImage[] tilesBufferedImages, int[] xCollisionOffset, int[] yCollisionOffset) {
this.tilesBufferedImages = tilesBufferedImages;
this.xCollisionOffset = xCollisionOffset;
this.yCollisionOffset = yCollisionOffset;
this.levelImage = levelImage;
this.tileSize = tileSize;
tile = new BufferedImage[levelImage.getWidth()][levelImage.getHeight()];
rect = new Rectangle[levelImage.getWidth()][levelImage.getHeight()];
generateLevel();
}
public abstract void generateLevel();
public void render(float xOffset, float yOffset, int scale, Graphics2D screen) {
this.xOffset = xOffset;
this.yOffset = yOffset;
for (int y = (int) Math.max(yOffset / (tileSize + scale), 0); y < Math.min((MCVE.HEIGHT + yOffset) / (tileSize + scale) + 1, levelImage.getHeight()); y++) {
for (int x = (int) Math.max(xOffset / (tileSize + scale), 0); x < Math.min((MCVE.WIDTH + xOffset) / (tileSize + scale) + 1, levelImage.getWidth()); x++) {
if (tile[x][y] != null)
screen.drawImage(tile[x][y], (int) (x * (tileSize + scale) - xOffset), (int) (y * (tileSize + scale) - yOffset), (tileSize + scale), (tileSize + scale), null);
}
}
}
public void update(int scale) {
for (int y = 0; y < levelImage.getHeight(); y++) {
for (int x = 0; x < levelImage.getWidth(); x++) {
if (tile[x][y] != null && rect[x][y] == null) {
for (int i = 0; i < tilesBufferedImages.length; i++) {
if (tilesBufferedImages[i] == tile[x][y])
rect[x][y] = new Rectangle(x * (tileSize + scale) - Math.round(xOffset) + xCollisionOffset[i], y * (tileSize + scale) - Math.round(yOffset) + yCollisionOffset[i], (tileSize + scale) + xCollisionOffset[i], (tileSize + scale) + yCollisionOffset[i]);
}
} else if (tile[x][y] != null && rect[x][y] != null) {
for (int i = 0; i < tilesBufferedImages.length; i++) {
if (tilesBufferedImages[i] == tile[x][y])
rect[x][y].setBounds(x * (tileSize + scale) - Math.round(xOffset) + xCollisionOffset[i], y * (tileSize + scale) - Math.round(yOffset) + xCollisionOffset[i], (tileSize + scale) + xCollisionOffset[i], (tileSize + scale) + yCollisionOffset[i]);
}
}
}
}
}
}
Many thanks.
多谢。
EDIT: updated code at MCVELevel:
编辑:MCVELevel更新的代码:
public void render(float xOffset, float yOffset, int scale, Graphics2D screen) {
this.xOffset = xOffset;
this.yOffset = yOffset;
for (int y = 0; y < levelImage.getHeight(); y++) {
for (int x = 0; x < levelImage.getWidth(); x++) {
if (tile[x][y] != null)
screen.drawImage(tile[x][y], (int) (x * (tileSize + scale) - xOffset), (int) (y * (tileSize + scale) - yOffset), (tileSize + scale), (tileSize + scale), null);
}
}
}
2 个解决方案
#1
1
(My other answer is not wrong (I think) but it doesn't answer the specific problem; it fixes a problem that would have become apparent later.)
(我的另一个回答没有错(我认为),但它没有回答具体的问题;它解决了一个后来会变得明显的问题。
Your level1.png has some unusual pixels which have RGB values that match bricks, but which look to the eye to be blank. I guess there's a transparency thing happening, but I don't know anything about pngs. Anyway, this level1.png is clean and works as expected:
你使。png有一些不同寻常的像素,它们具有与砖块匹配的RGB值,但在人眼看来是空白的。我想这是一件透明的事情,但我对pngs一无所知。不管怎样,这使有效。png是清洁的,按预期工作:
It took a while to figure this out. I created a more minimal MCVE from your one. This version may help future readers debug the problem with the original png (in the question).
花了一段时间才弄明白。我从你的作品中创造了一个更小的MCVE。这个版本可以帮助将来的读者调试原始png的问题。
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
public class MCVE extends JFrame {
private static final long serialVersionUID = 1L;
public static final int WIDTH = 800;
public static final int HEIGHT = 600;
public static void main(String[] args) {
MCVE mcve = new MCVE();
mcve.setVisible(true);
mcve.setSize(WIDTH, HEIGHT);
mcve.setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public void paint(Graphics g) {
render((Graphics2D) g);
}
public BufferedImage[][] tile;
public static final int TILE_SIZE = 16;
private static BufferedImage spritesheet = BufferedImageLoader
.load("tiles.png");
private static final BufferedImage bricks = crop(0, 0);
private static final BufferedImage dirt = crop(1, 0);
private static final BufferedImage grass = crop(2, 0);
private static final BufferedImage levelImage = BufferedImageLoader.load("level1.png");
int widthInTiles;
int heightInTiles;
private static BufferedImage crop(int x, int y) {
return spritesheet.getSubimage(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE,
TILE_SIZE);
}
public MCVE() {
widthInTiles = levelImage.getWidth();
heightInTiles = levelImage.getHeight();
generateLevel();
}
public void generateLevel() {
tile = new BufferedImage[widthInTiles][heightInTiles];
for (int y = 0; y < heightInTiles; y++) {
for (int x = 0; x < widthInTiles; x++) {
Color c = new Color(levelImage.getRGB(x, y));
switch (c.getRGB()) {
case -8158333:
tile[x][y] = bricks;
break;
case -14429696:
tile[x][y] = grass;
break;
case -4284160:
tile[x][y] = dirt;
}
}
}
}
public void render(Graphics2D screen) {
int scale = 16;
int yes = 0, no = 0;
for (int y = 0; y < heightInTiles; y++) {
for (int x = 0; x < widthInTiles; x++) {
if (tile[x][y] != null) {
screen.drawImage(tile[x][y], (int) (x * (TILE_SIZE + scale)),
(int) (y * (TILE_SIZE + scale)),
(TILE_SIZE + scale), (TILE_SIZE + scale),
Color.BLACK, null);
}
}
}
}
public static class BufferedImageLoader {
public static BufferedImage load(String path) {
try {
return ImageIO.read(new File(path));
} catch (IOException e) {
e.printStackTrace();
}
throw new NullPointerException("No file found at: " + path);
}
public static BufferedImage load(URL url) {
try {
return ImageIO.read(url);
} catch (IOException e) {
e.printStackTrace();
}
throw new NullPointerException("No file found at: " + url.getPath());
}
}
}
#2
2
The problem is in this chunk inside the render
method:
问题在于渲染方法中的这个块:
for (int y = (int) Math.max(yOffset / (tileSize + scale), 0); y < Math.min((MCVE.HEIGHT + yOffset) / (tileSize + scale) + 1, levelImage.getHeight()); y++) {
for (int x = (int) Math.max(xOffset / (tileSize + scale), 0); x < Math.min((MCVE.WIDTH + xOffset) / (tileSize + scale) + 1, levelImage.getWidth()); x++) {
if (tile[x][y] != null)
screen.drawImage(tile[x][y], (int) (x * (tileSize + scale) - xOffset), (int) (y * (tileSize + scale) - yOffset), (tileSize + scale), (tileSize + scale), null);
}
}
This seems to be saying: "for pixels that I want to draw to, draw tiles" (though I could be wrong about that.. I get a different explanation every time I read that for-loop guard). The problem is that you're calculating x and y in terms of drawing area, but you're using them in terms of indices into the tiles[]
array. You want "for tiles I want to draw, draw tiles".
这似乎是在说:“对于我想要绘制的像素,绘制瓷砖”(尽管我可能会错……)每次我读到for-loop guard时,都会得到不同的解释。问题是,你在计算x和y的绘制面积,但你在用它们的索引到tile[]数组中。你想要"我想画瓷砖"
The loop in generateLevel()
is doing the right thing. Use that sort of loop (for (y = 0 y < levelImage.getHeight(); ++y)
). The only bit of code that needs to worry about yOffset
, tileSize
and scale
is the code that actually draws a tile.
generateLevel()中的循环正在做正确的事情。使用那种循环(for (y = 0 y < levelImage.getHeight());+ + y))。需要考虑yOffset、tileSize和scale的惟一代码是实际绘制块的代码。
This reminds me again why code should be written to be testable, and why tests should be written :)
这再次提醒我为什么代码应该编写为可测试的,为什么应该编写测试:)
#1
1
(My other answer is not wrong (I think) but it doesn't answer the specific problem; it fixes a problem that would have become apparent later.)
(我的另一个回答没有错(我认为),但它没有回答具体的问题;它解决了一个后来会变得明显的问题。
Your level1.png has some unusual pixels which have RGB values that match bricks, but which look to the eye to be blank. I guess there's a transparency thing happening, but I don't know anything about pngs. Anyway, this level1.png is clean and works as expected:
你使。png有一些不同寻常的像素,它们具有与砖块匹配的RGB值,但在人眼看来是空白的。我想这是一件透明的事情,但我对pngs一无所知。不管怎样,这使有效。png是清洁的,按预期工作:
It took a while to figure this out. I created a more minimal MCVE from your one. This version may help future readers debug the problem with the original png (in the question).
花了一段时间才弄明白。我从你的作品中创造了一个更小的MCVE。这个版本可以帮助将来的读者调试原始png的问题。
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
public class MCVE extends JFrame {
private static final long serialVersionUID = 1L;
public static final int WIDTH = 800;
public static final int HEIGHT = 600;
public static void main(String[] args) {
MCVE mcve = new MCVE();
mcve.setVisible(true);
mcve.setSize(WIDTH, HEIGHT);
mcve.setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public void paint(Graphics g) {
render((Graphics2D) g);
}
public BufferedImage[][] tile;
public static final int TILE_SIZE = 16;
private static BufferedImage spritesheet = BufferedImageLoader
.load("tiles.png");
private static final BufferedImage bricks = crop(0, 0);
private static final BufferedImage dirt = crop(1, 0);
private static final BufferedImage grass = crop(2, 0);
private static final BufferedImage levelImage = BufferedImageLoader.load("level1.png");
int widthInTiles;
int heightInTiles;
private static BufferedImage crop(int x, int y) {
return spritesheet.getSubimage(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE,
TILE_SIZE);
}
public MCVE() {
widthInTiles = levelImage.getWidth();
heightInTiles = levelImage.getHeight();
generateLevel();
}
public void generateLevel() {
tile = new BufferedImage[widthInTiles][heightInTiles];
for (int y = 0; y < heightInTiles; y++) {
for (int x = 0; x < widthInTiles; x++) {
Color c = new Color(levelImage.getRGB(x, y));
switch (c.getRGB()) {
case -8158333:
tile[x][y] = bricks;
break;
case -14429696:
tile[x][y] = grass;
break;
case -4284160:
tile[x][y] = dirt;
}
}
}
}
public void render(Graphics2D screen) {
int scale = 16;
int yes = 0, no = 0;
for (int y = 0; y < heightInTiles; y++) {
for (int x = 0; x < widthInTiles; x++) {
if (tile[x][y] != null) {
screen.drawImage(tile[x][y], (int) (x * (TILE_SIZE + scale)),
(int) (y * (TILE_SIZE + scale)),
(TILE_SIZE + scale), (TILE_SIZE + scale),
Color.BLACK, null);
}
}
}
}
public static class BufferedImageLoader {
public static BufferedImage load(String path) {
try {
return ImageIO.read(new File(path));
} catch (IOException e) {
e.printStackTrace();
}
throw new NullPointerException("No file found at: " + path);
}
public static BufferedImage load(URL url) {
try {
return ImageIO.read(url);
} catch (IOException e) {
e.printStackTrace();
}
throw new NullPointerException("No file found at: " + url.getPath());
}
}
}
#2
2
The problem is in this chunk inside the render
method:
问题在于渲染方法中的这个块:
for (int y = (int) Math.max(yOffset / (tileSize + scale), 0); y < Math.min((MCVE.HEIGHT + yOffset) / (tileSize + scale) + 1, levelImage.getHeight()); y++) {
for (int x = (int) Math.max(xOffset / (tileSize + scale), 0); x < Math.min((MCVE.WIDTH + xOffset) / (tileSize + scale) + 1, levelImage.getWidth()); x++) {
if (tile[x][y] != null)
screen.drawImage(tile[x][y], (int) (x * (tileSize + scale) - xOffset), (int) (y * (tileSize + scale) - yOffset), (tileSize + scale), (tileSize + scale), null);
}
}
This seems to be saying: "for pixels that I want to draw to, draw tiles" (though I could be wrong about that.. I get a different explanation every time I read that for-loop guard). The problem is that you're calculating x and y in terms of drawing area, but you're using them in terms of indices into the tiles[]
array. You want "for tiles I want to draw, draw tiles".
这似乎是在说:“对于我想要绘制的像素,绘制瓷砖”(尽管我可能会错……)每次我读到for-loop guard时,都会得到不同的解释。问题是,你在计算x和y的绘制面积,但你在用它们的索引到tile[]数组中。你想要"我想画瓷砖"
The loop in generateLevel()
is doing the right thing. Use that sort of loop (for (y = 0 y < levelImage.getHeight(); ++y)
). The only bit of code that needs to worry about yOffset
, tileSize
and scale
is the code that actually draws a tile.
generateLevel()中的循环正在做正确的事情。使用那种循环(for (y = 0 y < levelImage.getHeight());+ + y))。需要考虑yOffset、tileSize和scale的惟一代码是实际绘制块的代码。
This reminds me again why code should be written to be testable, and why tests should be written :)
这再次提醒我为什么代码应该编写为可测试的,为什么应该编写测试:)