当前位置: 首页 > 知识库问答 >
问题:

基于Java的游戏性能

包唯
2023-03-14

目前,我正在尝试用Java开发基于2D平铺的侧滚游戏,主要基于David Brackeen的“用Java开发游戏”中的代码和示例

目前地图文件的大小为100x100个图块(每个图块为64x64像素)。我已经将系统配置为仅显示玩家可见的图块。Graphics系统由ScreenManager类管理,该类返回当前BufferStrategy的图形对象,如下所示:

ScreenManager.java

private GraphicsDevice device;

...

/**
 * Gets the graphics context for the display. The
 * ScreenManager uses double buffering, so applications must 
 * call update() to show any graphics drawn.
 * <p>
 * The application must dispose of the graphics object.
 */
public Graphics2D getGraphics(){
    Window window = device.getFullScreenWindow();
    if(window != null){
        BufferStrategy strategy = window.getBufferStrategy();
        return (Graphics2D)strategy.getDrawGraphics();
    }
    else{
        return null;
    }
}

来自这个屏幕管理器的图形在游戏循环中传递给TreeRenderer的draw方法之后。

TreeMapRenderer.java

/**
    Draws the specified TileMap.
*/
public void draw(Graphics2D g, TileMap map,
    int screenWidth, int screenHeight, float fr)
{
    Sprite player = map.getPlayer();
    int mapWidth = tilesToPixels(map.getWidth());
    int mapHeight = tilesToPixels(map.getHeight());

    // get the scrolling position of the map
    // based on player's position
    int offsetX = screenWidth / 2 -
        Math.round(player.getX()) - TILE_SIZE;
    offsetX = Math.min(offsetX, 0);
    offsetX = Math.max(offsetX, screenWidth - mapWidth);

    // get the y offset to draw all sprites and tiles
    int offsetY = screenHeight /2 -
            Math.round(player.getY()) - TILE_SIZE;
    offsetY = Math.min(offsetY,0);
    offsetY = Math.max(offsetY, screenHeight - mapHeight);

    // draw the visible tiles
    int firstTileY = pixelsToTiles(-offsetY);
    int lastTileY = firstTileY + pixelsToTiles(screenHeight) +1;

    int firstTileX = pixelsToTiles(-offsetX);
    int lastTileX = firstTileX +
        pixelsToTiles(screenWidth) + 1;

    //HERE IS WHERE THE SYSTEM BOGS dOWN (checking ~280 tiles per iteration)
    for (int y=firstTileY; y<lastTileY; y++) {
        for (int x=firstTileX; x <= lastTileX; x++) {
            if(map.getTile(x, y) != null){
                Image image = map.getTile(x, y).getImage();
                if (image != null) {
                    g.drawImage(image,
                        tilesToPixels(x) + offsetX,
                        tilesToPixels(y) + offsetY,
                        null);
                }
            }
        }
    }

    // draw player
    g.drawImage(player.getImage(),
       Math.round(player.getX()) + offsetX,
       Math.round(player.getY()) + offsetY,
       null);

该算法为 X 轴和 Y 轴正确选择正确的 FROM 和 TO 值,将所需的切片从 10000 剔除到 ~285。

我的问题是,即使这样,游戏在渲染瓷砖时也只能以8-10 FPS左右的速度运行。如果我关闭瓷砖渲染,系统会以80 FPS运行(无事可做时易于快速运行)

你对如何加快这一进程有什么想法吗?我想看到至少在30 FPS左右的东西来让这个游戏可以玩。

最后,尽管我愿意使用第三方库来做到这一点,但我想在承认失败之前尝试自己实现这个逻辑。

编辑:< br >根据要求,此处提供了有关如何调用< code>Image image = map.getTile(x,y)的额外信息。getImage();起作用。

这里的地图来自下面的TileMap类

TileMap.java

public class TileMap {

private Tile[][] tiles;
private LinkedList sprites;
private Sprite player;
private GraphicsConfiguration gc;

/**
    Creates a new TileMap with the specified width and
    height (in number of tiles) of the map.
*/
public TileMap(GraphicsConfiguration gc, int width, int height) {
    this.gc = gc;
    tiles = new Tile[width][height];
    overlayer = new Tile[width][height];
    sprites = new LinkedList();
}


/**
    Gets the width of this TileMap (number of tiles across).
*/
public int getWidth() {
    return tiles.length;
}


/**
    Gets the height of this TileMap (number of tiles down).
*/
public int getHeight() {
    return tiles[0].length;
}


/**
    Gets the tile at the specified location. Returns null if
    no tile is at the location or if the location is out of
    bounds.
*/
public Tile getTile(int x, int y) {
    if (x < 0 || x >= getWidth() ||
        y < 0 || y >= getHeight())
    {
        return null;
    }
    else {
        return tiles[x][y];
    }
}


/**
 * Helper method to set a tile. If blocking is not defined than it is set to false.
 * 
 * @param x
 * @param y
 * @param tile
 */
public void setTile(int x, int y,Image tile){
    this.setTile(x,y,tile,false);
}

/**
    Sets the tile at the specified location.
*/
public void setTile(int x, int y, Image tile, boolean blocking) {
    if(tiles[x][y] == null){
        Tile t = new Tile(gc, tile, blocking);
        tiles[x][y] = t;
    }
    else{
        tiles[x][y].addImage(tile);
        tiles[x][y].setBlocking(blocking);
    }
}

...

此处的磁贴是以下代码的实例。从本质上讲,这个类只保存图像,可以通过添加覆盖层来更新,始终使用gc.createCompatibleImage(w,h,Transparency.TRANSLUCENT);和一个布尔值,用于判断它是否会阻止玩家。传入的映像也是以这种方式创建的。

Tile.java

public class Tile {
private Image image;
private boolean blocking = false;
private GraphicsConfiguration gc;

/**
 * Creates a new Tile to be used with a TileMap
 * @param image The base image for this Tile
 * @param blocking Will this tile allow the user to walk over/through
 */
public Tile(GraphicsConfiguration gc, Image image, boolean blocking){
    this.gc = gc;
    this.image = image;
    this.blocking = blocking;
}

public Tile(GraphicsConfiguration gc, Image image){
    this.gc = gc;
    this.image = image;
    this.blocking = false;
}

/**
Creates a duplicate of this animation. The list of frames
are shared between the two Animations, but each Animation
can be animated independently.
*/
public Object clone() {

    return new Tile(gc, image, blocking);
}

/**
 * Used to add an overlay to the existing tile
 * @param image2 The image to overlay
 */
public void addImage(Image image2){
    BufferedImage base = (BufferedImage)image;
    BufferedImage overlay = (BufferedImage)image2;

    // create the new image, canvas size is the max. of both image sizes
    int w = Math.max(base.getWidth(), overlay.getWidth());
    int h = Math.max(base.getHeight(), overlay.getHeight());
    //BufferedImage combined = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
    BufferedImage combined = gc.createCompatibleImage(w, h, Transparency.TRANSLUCENT);
    // paint both images, preserving the alpha channels
    Graphics g = combined.getGraphics();
    g.drawImage(image, 0, 0, null);
    g.drawImage(overlay, 0, 0, null);

    this.image = (Image)combined;
}

public boolean isBlocking(){
    return this.blocking;
}

public void setBlocking(boolean blocking){
    this.blocking = blocking;
}

public Image getImage(){
    return this.image;
}

}

共有2个答案

邹杰
2023-03-14

创建透明图像(非半透明),因为半透明图像需要更高的ram,并存储在系统内存中,而不是标准java堆中。创建半透明图像需要几个本机调用来访问本机系统内存。使用缓冲图像而不是图像。您可以随时将BuffereImage转换为图像。

夏振国
2023-03-14

我会使用一个像素渲染引擎(googleit;D)

基本上你所做的,它有一个巨大的整数数组对应于你所画的图像。

基本上,每个瓷砖都有一个代表其像素的整数数组。当你渲染图块时,你将图块数组“复制”(比那稍微复杂一点)到大数组中:)

然后,一旦您完成了将所有内容渲染到主数组,您就可以在屏幕上绘制它。

这样,每次你画东西时,你只处理整数,而不是整个画面。这使它更快。

我是通过mrDeathJHL的(youtube)教程并将它们与DesignsbyZephy r的(也是youtube)相结合而学到这一点的。虽然我不建议使用他的技术(他只使用4种颜色和8位图形,就像deathJHL的教程一样,您可以自定义图像的大小,甚至可以拥有多个具有不同分辨率的精灵表(对字体有用)

不过我确实用了一些偏移的东西(让屏幕移动而不是播放器)和泽法的InputHandler:)

希望这有所帮助!-Camodude009

 类似资料:
  • 所以我有(gridLayout),每个JXButton都有一个图标,一个播放器所属的片段,并且有一个。 我目前正在努力使战略游戏(两个球员-我处理两者)。我设置了图标,碎片和一个碎片应该如何移动。 现在我希望让它轮流播放。 我的思想播放器2件当播放器1转动时隐藏。 和应该改变图标时,播放器2。 如果这两种方法看起来还可以,那么我的问题在于如何实现转向。

  • 所以我是Java编码的新手,我对C#有很好的经验,我知道它们非常相似。我目前正在通过创建一个文本冒险游戏来处理Java,游戏使用案例(案例1、案例2、默认等),目前我正在开发一个保存和加载功能,但我不知道如何保存一个使用案例来进一步编码的分支游戏,有人有什么想法吗?

  • 使用Cocos2D, 模仿QQ连连看写的一个连连看游戏Demo,有声音效果。 [Code4App.com]

  • 本文向大家介绍Java基于swing实现的弹球游戏代码,包括了Java基于swing实现的弹球游戏代码的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了Java基于swing实现的弹球游戏代码。分享给大家供大家参考。 主要功能代码如下: 运行效果如下图所示: 希望本文所述对大家的Java程序设计有所帮助。

  • 本文向大家介绍基于jsp的井字游戏实例,包括了基于jsp的井字游戏实例的使用技巧和注意事项,需要的朋友参考一下 做一款回忆童年的游戏,这款游戏代码比较简单,主要是掌握算法的原理,但是也有一些需要注意的地方。 游戏界面 进入正题。项目的效果图如下: 游戏有一个开始界面可供选择玩家的角色,然后选择先手是哪一方,接着开始游戏。选择界面做了一个遮罩层,里面提供给用户选择,选择之后便把遮罩层隐藏并开始游戏。

  • 本文向大家介绍java基于swing实现的五子棋游戏代码,包括了java基于swing实现的五子棋游戏代码的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了java基于swing实现的五子棋游戏代码。分享给大家供大家参考。 主要功能代码如下: