java - 使用 Slick2d 渲染大量图像的最佳方法?
问题描述
所以我正在尝试使用 Slick2d 制作一个自上而下的 2D 游戏。
我有一个世界对象,它包含一个包含瓷砖列表的块列表。那些瓷砖是渲染的。我将平铺位置存储在 Vector2f 中。每个块也有一个 Vector2f 位置。这是我当前的工作代码:
主要的:
public class Main extends BasicGame {
public static Main instance;
private Renderer renderer;
private long lastFrameTime;
private float delta;
public Main() {
super("Test");
}
public static void main(String[] arguments) {
try {
instance = new Main();
AppGameContainer app = new AppGameContainer(instance);
app.setDisplayMode(1240, 720, false);
app.setShowFPS(true);
app.start();
app.setAlwaysRender(true);
} catch (SlickException e) {
e.printStackTrace();
}
}
@Override
public void init(GameContainer container) throws SlickException {
renderer = new Renderer(new World(), new Player());
for(Chunk chunk : renderer.getWorld().getChunks()) {
System.out.println(chunk.getPosition().x + "," +
chunk.getPosition().y + "," + chunk.getTiles().size());
}
}
@Override
public void update(GameContainer container, int delta)
throws SlickException {
long currentFrameTime = getCurrentTime();
this.delta = (currentFrameTime - lastFrameTime)/1000f;
lastFrameTime = currentFrameTime;
renderer.move();
}
public void render(GameContainer container, Graphics g)
throws SlickException {
renderer.update(g);
}
public float getFrameTimeSeconds() {
return delta;
}
private static long getCurrentTime() {
return Sys.getTime()*1000/Sys.getTimerResolution();
}
public Renderer getRenderer() {
return renderer;
}
}
渲染器类:
public class Renderer {
World world;
Player player;
public Renderer(World world, Player player) {
this.world = world;
this.player = player;
}
public World getWorld() {
return world;
}
public void setWorld(World world) {
this.world = world;
}
public Player getPlayer() {
return player;
}
public void setPlayer(Player player) {
this.player = player;
}
public void update(Graphics g) {
for (int i = 0; i < 2; i++) {
for (int i2 = 0; i2 < 2; i2++) {
Vector2f pos = player.getPos();
Chunk chunk = world.getChunk(new Vector2f((int) Math
.floor(pos.x / 16) + i, (int) Math.floor(pos.y / 16)
+ i2));
if (chunk != null) {
for (Tile tile : chunk.getTiles()) {
if (tile.getPos().x < player.getPos().x +
((Display.getWidth() / 2) + 64 + 50) &&
tile.getPos().x > player.getPos().x -
((Display.getWidth() / 2) + 64 + 50) &&
tile.getPos().y < player.getPos().y +
((Display.getHeight() / 2) + 64 + 50) &&
tile.getPos().y > player.getPos().y -
((Display.getHeight() / 2) + 64 + 50))
g.drawImage(tile.getTexture().getScaledCopy(64, 64),
(pos.x - tile.getPos().x)*64+Display.getWidth(),
(pos.y -
tile.getPos().y)*64+Display.getHeight());
}
}
}
}
}
public void move() {
Vector2f pos = player.getPos();
if (Keyboard.isKeyDown(Keyboard.KEY_W)) {
pos.y += 1 * Main.instance.getFrameTimeSeconds();
} else if (Keyboard.isKeyDown(Keyboard.KEY_S)) {
pos.y -= 1 * Main.instance.getFrameTimeSeconds();
}
if (Keyboard.isKeyDown(Keyboard.KEY_A)) {
pos.x += 1 * Main.instance.getFrameTimeSeconds();
} else if (Keyboard.isKeyDown(Keyboard.KEY_D)) {
pos.x -= 1 * Main.instance.getFrameTimeSeconds();
}
int width = Display.getWidth();
int height = Display.getHeight();
Vector2f npos2;
Vector2f constant = new Vector2f((int) Math.floor((width / 2 -
pos.x)/256), (int) Math.floor((height / 2 - pos.y)/256));
Vector2f npos = constant;
if (world.getChunk(npos) == null) {
npos2 = npos;
npos2.x += 1;
//Right
if (world.getChunk(npos2) == null) {
for (int i = 0; i < 2; i++) {
System.out.println("Generating new chunk! (1) " + npos2.x +
", " + npos2.y + ", Player: x: " + player.getPos().x + ", y: " +
player.getPos().y);
npos.x += i;
world.generateChunk(npos);
}
}
npos2.x -= 1;
npos2.y -= 1;
//Down
if (world.getChunk(npos2) == null) {
for (int i = 0; i < 2; i++) {
System.out.println("Generating new chunk! (2) " + npos2.x +
", " + npos2.y + ", Player: x: " + player.getPos().x + ", y: " +
player.getPos().y);
npos.y -= i;
world.generateChunk(npos);
}
}
}
npos = constant;
if (world.getChunk(npos) == null) {
npos2 = npos;
npos2.x -= 1;
//Left
if (world.getChunk(npos2) == null) {
for (int i = 0; i < 2; i++) {
System.out.println("Generating new chunk! (3) " + npos2.x +
", " + npos2.y + ", Player: x: " + player.getPos().x + ", y: " +
player.getPos().y);
npos.x -= i;
world.generateChunk(npos);
}
}
npos2.x += 1;
npos2.y += 1;
//Up
if (world.getChunk(npos2) == null) {
for (int i = 0; i < 2; i++) {
System.out.println("Generating new chunk! (4) " + npos2.x +
", " + npos2.y + ", Player: x: " + player.getPos().x + ", y: " +
player.getPos().y);
npos.y += i;
world.generateChunk(npos);
}
}
}
}
}
该代码运行良好,但问题是帧速率为 4-5 fps。我有一个想法尝试将纹理缝合在一起并像这样渲染它们,这是我的新渲染器代码:
public class Renderer {
World world;
Player player;
public Renderer(World world, Player player) {
this.world = world;
this.player = player;
}
public World getWorld() {
return world;
}
public void setWorld(World world) {
this.world = world;
}
public Player getPlayer() {
return player;
}
public void setPlayer(Player player) {
this.player = player;
}
public void update(Graphics g) {
for (int i = 0; i < 2; i++) {
for (int i2 = 0; i2 < 2; i2++) {
Vector2f pos = player.getPos();
Chunk chunk = world.getChunk(new Vector2f((int) Math
.floor(pos.x / 16) + i, (int) Math.floor(pos.y / 16)
+ i2));
if (chunk != null) {
Image image = null;
try {
image = new Image(4096, 4096);
} catch (SlickException e1) {
e1.printStackTrace();
}
Graphics ig = null;
try {
ig = image.getGraphics();
} catch (SlickException e) {
e.printStackTrace();
}
for (Tile tile : chunk.getTiles()) {
if (tile.getPos().x < player.getPos().x +
((Display.getWidth() / 2) + 64 + 50) &&
tile.getPos().x > player.getPos().x -
((Display.getWidth() / 2) + 64 + 50) &&
tile.getPos().y < player.getPos().y +
((Display.getHeight() / 2) + 64 + 50) &&
tile.getPos().y > player.getPos().y -
((Display.getHeight() / 2) + 64 + 50))
ig.drawImage(tile.getTexture().getScaledCopy(64, 64),
(pos.x - tile.getPos().x)*64+Display.getWidth(),
(pos.y -
tile.getPos().y)*64+Display.getHeight());
}
ig.flush();
g.drawImage(image, chunk.getPosition().x*256 - pos.x,
chunk.getPosition().y*256-pos.y);
}
}
}
}
public void move() {
Vector2f pos = player.getPos();
if (Keyboard.isKeyDown(Keyboard.KEY_W)) {
pos.y += 1 * Main.instance.getFrameTimeSeconds();
} else if (Keyboard.isKeyDown(Keyboard.KEY_S)) {
pos.y -= 1 * Main.instance.getFrameTimeSeconds();
}
if (Keyboard.isKeyDown(Keyboard.KEY_A)) {
pos.x += 1 * Main.instance.getFrameTimeSeconds();
} else if (Keyboard.isKeyDown(Keyboard.KEY_D)) {
pos.x -= 1 * Main.instance.getFrameTimeSeconds();
}
int width = Display.getWidth();
int height = Display.getHeight();
Vector2f npos2;
Vector2f constant = new Vector2f((int) Math.floor((width / 2 -
pos.x)/256), (int) Math.floor((height / 2 - pos.y)/256));
Vector2f npos = constant;
if (world.getChunk(npos) == null) {
npos2 = npos;
npos2.x += 1;
//Right
if (world.getChunk(npos2) == null) {
for (int i = 0; i < 2; i++) {
System.out.println("Generating new chunk! (1) " + npos2.x +
", " + npos2.y + ", Player: x: " + player.getPos().x + ", y: " +
player.getPos().y);
npos.x += i;
world.generateChunk(npos);
}
}
npos2.x -= 1;
npos2.y -= 1;
//Down
if (world.getChunk(npos2) == null) {
for (int i = 0; i < 2; i++) {
System.out.println("Generating new chunk! (2) " + npos2.x +
", " + npos2.y + ", Player: x: " + player.getPos().x + ", y: " +
player.getPos().y);
npos.y -= i;
world.generateChunk(npos);
}
}
}
npos = constant;
if (world.getChunk(npos) == null) {
npos2 = npos;
npos2.x -= 1;
//Left
if (world.getChunk(npos2) == null) {
for (int i = 0; i < 2; i++) {
System.out.println("Generating new chunk! (3) " + npos2.x +
", " + npos2.y + ", Player: x: " + player.getPos().x + ", y: " +
player.getPos().y);
npos.x -= i;
world.generateChunk(npos);
}
}
npos2.x += 1;
npos2.y += 1;
//Up
if (world.getChunk(npos2) == null) {
for (int i = 0; i < 2; i++) {
System.out.println("Generating new chunk! (4) " + npos2.x +
", " + npos2.y + ", Player: x: " + player.getPos().x + ", y: " +
player.getPos().y);
npos.y += i;
world.generateChunk(npos);
}
}
}
}
}
问题是,当我在图块上移动太多时,程序不仅会崩溃,而且我只能得到 1 fps,这根本不是更好。所以我的问题是,以体面的帧速率做到这一点的最佳方法是什么?
使用第二种方法程序崩溃时出错:
# EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x000000006996dfce,
pid=10024, tid=0x0000000000001ec8
#
# JRE version: Java(TM) SE Runtime Environment (8.0_161-b12) (build
1.8.0_161-b12)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.161-b12 mixed mode windows-
amd64 compressed oops)
# Problematic frame:
# C [atio6axx.dll+0x102dfce]
更新:我没有运气,但是看着其他 2D 游戏渲染数百张图像而不会丢失很多帧,我认为有一些方法可以大大加快我的代码速度。我不渲染屏幕瓷砖,只尝试渲染我需要的尽可能多的内容。
更新 #2:我切换到 libgdx,现在它运行起来就像一个魅力。libgdx 中包含的批处理渲染更适合我的目的。
解决方案
推荐阅读
- android - 删除记录时如何从适配器刷新活动?
- javascript - 使用 jquery 隐藏 div 和 cookie 未正确隐藏
- windows - 如何使用 Powershell 在桌面上创建磁盘快捷方式?
- php - 基于php中的点击生成热图颜色
- javascript - 为某事修改程序然后将其改回
- wordpress - Htaccess url 映射到同一域根目录的子文件夹
- laravel - 如何暂时关闭 laravel 垃圾过滤器?
- android - 未在异步函数中调用 Kotlin 回调
- angular - Angular:如何获取 Google 访问令牌
- javascript - 设置从 axios 到 state 的响应