有没有一种有效的方法可以将纹理加载为简单的 2D 游戏的.PNG图像



我正在编写一个简单的基于2D块的游戏(类似于Minecraft(来开始使用Java。我有很多游戏机制,比如世界生成工作,但加载纹理体积庞大且效率低下。基本上,我使用加载函数单独加载了所有纹理(纹理是 16x16 .PNG文件(。游戏中的每个方块都有一个名称(例如。"石头"、"污垢"(,当游戏渲染图块时,它会从 textureManager 类加载纹理。这有效,但我必须对加载和返回的每个纹理进行硬编码。我想做的是让纹理自动加载,但仍然有它们的字符串索引。例如,我希望游戏加载纹理文件夹中的所有.PNG文件,但保留它们的名称,以便我可以说类似 loadTexture("stone"(之类的内容。

这是我当前的纹理管理器代码。它只是在游戏开始时加载每个文件,并使背景图块的每个文件变暗。添加新纹理是一种痛苦,而且效率不高。

package graphics;
import java.awt.image.BufferedImage;
import java.awt.image.RescaleOp;
public class textureManager {
private static final BufferedImage darken(BufferedImage image) {
return new RescaleOp(.7f, 0, null).filter(image, null);
}
private static final String path = "/assets/textures/";
// textures 
public static final BufferedImage unknown   = renderer.loadImage(path + "unknown.png");
private static final BufferedImage stone    = renderer.loadImage(path + "stone.png");
private static final BufferedImage grass    = renderer.loadImage(path + "grass.png");
private static final BufferedImage dirt     = renderer.loadImage(path + "dirt.png");
private static final BufferedImage iron_ore = renderer.loadImage(path + "iron_ore.png");
private static final BufferedImage coal_ore = renderer.loadImage(path + "coal_ore.png");
private static final BufferedImage diamond_ore = renderer.loadImage(path + "diamond_ore.png");
private static final BufferedImage bedrock  = renderer.loadImage(path + "bedrock.png");
private static final BufferedImage andesite = renderer.loadImage(path + "andesite.png");
private static final BufferedImage granite  = renderer.loadImage(path + "granite.png");
private static final BufferedImage marble   = renderer.loadImage(path + "marble.png");
// darkened textures
private static final BufferedImage dark_stone = darken(stone);
private static final BufferedImage dark_grass = darken(grass);
private static final BufferedImage dark_dirt = darken(dirt);
private static final BufferedImage dark_iron_ore = darken(iron_ore);
private static final BufferedImage dark_coal_ore = darken(coal_ore);
private static final BufferedImage dark_diamond_ore = darken(diamond_ore);
private static final BufferedImage dark_andesite = darken(andesite);
private static final BufferedImage dark_granite = darken(granite);
private static final BufferedImage dark_marble = darken(marble);
// animations
private static Animation player   = new Animation("player");
private static Animation lava     = new Animation("lava");
private static Animation plant_01 = new Animation("plant_01");
/** returns the textures of the name provided */
public static BufferedImage getTexture(String name, boolean darken) {
if(name.equals("air")) return null;
if(name.equals("stone"))    if(!darken) return stone;           else return dark_stone;
if(name.equals("grass"))    if(!darken) return grass;           else return dark_grass;
if(name.equals("dirt"))     if(!darken) return dirt;            else return dark_dirt;
if(name.equals("iron_ore")) if(!darken) return iron_ore;        else return dark_iron_ore;
if(name.equals("coal_ore")) if(!darken) return coal_ore;        else return dark_coal_ore;
if(name.equals("diamond_ore")) if(!darken) return diamond_ore;  else return dark_diamond_ore;
if(name.equals("bedrock"))  return bedrock;
if(name.equals("andesite")) if(!darken) return andesite;        else return dark_andesite;
if(name.equals("granite"))  if(!darken) return granite;         else return dark_granite;
if(name.equals("marble"))   if(!darken) return marble;          else return dark_marble;
return unknown;
}
/** returns the animation of the name provided */
public static Animation getAnimation(String name) {
if(name.equals("player"))   return player;
if(name.equals("lava"))     return lava;
if(name.equals("plant_01")) return plant_01;
return null;
}
}

虽然这段代码有效,但我想添加一种更有效的方法,但我不知道如何。我正在考虑使用数组列表来存储图像,但后来它不接受字符串索引。也许是一个可以管理数组列表和名称索引的自定义类?

注: 动画是一个自定义类,用于对从文件夹加载的纹理进行动画处理。 这些可以忽略。

我这样做的方法是而不是列出您要加载的所有文件。 加载该路径中的所有文件。 将它们放入地图中Map<String, BufferedImage> textures = new HashMap<>();然后从文件名创建密钥。 然后,您可以生成并添加深色纹理,将"dark_"或"d"添加到Key。 然后在获取纹理中,您需要做的就是if (darken) textures.get('d'+name) else textures.get(name)加载
所有纹理后从文件中获取深色版本

textures.putAll(textures.entrySet().stream().collect(Collectors.toMap(entry->"d"+entry.getKey(),entry->darken(entry.getValue()))));

你想要一个地图。

Map的一个常见(可能是最常见的(实现是 HashMap:

private static final Map<String, Map<Boolean, BufferedImage>> textures;
static {
String[] baseNames = {
"unknown",
"stone",
"grass",
"dirt",
"iron_ore",
"coal_ore",
"diamond_ore",
"bedrock",
"andesite",
"granite",
"marble",
};
Map<String, Map<Boolean, BufferedImage>> map = new HashMap<>();
for (String baseName : baseNames) {
BufferedImage regular =
renderer.loadImage(path + baseName + ".png");
BufferedImage dark = darken(regular);
Map<Boolean, BufferedImage> regularAndDark = new HashMap<>(2);
regularAndDark.put(false, regular);
regularAndDark.put(true, dark);
map.put(baseName, Collections.unmodifiableMap(regularAndDark));
}
textures = Collections.unmodifiableMap(map);
}
/** returns the textures of the name provided */
public static BufferedImage getTexture(String name, boolean darken) {
Map<Boolean, BufferedImage>> matches = textures.get(name);
assert matches != null : "No textures for name "" + name + """;
return matches.get(darken);
}

然而。。。还有改进的余地:

  • 如您所见,我添加了一个assert语句以确保没有提供无效的字符串参数。 这可以通过使用enum值作为图像键而不是字符串来避免,从而消除拼写错误的可能性。
  • Map<Boolean, BufferedImage>>有点难以理解。 我会做一个简单的内部类来保存两者,所以结构更明显。

考虑到这一点,它看起来像这样:

public enum TextureType {
UNKNOWN,
STONE,
GRASS,
DIRT,
IRON_ORE,
COAL_ORE,
DIAMOND_ORE,
BEDROCK,
ANDESITE,
GRANITE,
MARBLE,
}
private static class Textures {
final BufferedImage regular;
final BufferedImage dark;
Textures(BufferedImage regular) {
this.regular = Objects.requireNonNull(regular,
"Image cannot be null");
this.dark = darken(regular);
}
}
private static final Map<TextureType, Textures> textures;
static {
Map<TextureType, Textures> map = new EnumMap(TextureType.class);
for (TextureType type : TextureType.values()) {
map.put(type,
new Textures(renderer.loadImage(path + baseName + ".png")));
}
textures = Collections.unmodifiableMap(map);
}
/** returns the textures of the name provided */
public static BufferedImage getTexture(TextureType type, boolean darken) {
Objects.requireNonNull(type, "Texture type cannot be null");
Textures match = textures.get(type);
return darken ? match.dark : match.regular;
}

最新更新