Java:如何平滑地渲染播放器周围的地图?

时间:2016-02-04 16:02:21

标签: java rendering slick2d

我在Slick2D上写了一个与玩家一起移动的地图渲染器:

//takes camera x and camera y as arguments
//values of those are based on player location
public static void render(float xrender, float yrender) {
    xstart = (int) (xrender / Tile.SIZE);
    ystart = (int) (yrender / Tile.SIZE);
    int xend = (int) Math.ceil((float) Window.WIDTH / Tile.SIZE);
    int yend = (int) Math.ceil((float) Window.HEIGHT / Tile.SIZE);

    for (int x = xstart; x < xend; x++) {
        for (int y = ystart; y < yend; y++) {
            int tx = x-xstart;
            int ty = y-ystart;
            if (groundExists(tx, ty)) {//checks all tiles on current viewport and draws them
                //ground[][] is defined as Image[][]
                ground[tx][ty].draw(x * Tile.SIZE, y * Tile.SIZE, Tile.SIZE, Tile.SIZE);
            }
        }
    }
}

这个问题在于它基于整数,每个图块由一个数字表示,而不是表示为图块的每个像素(此处为Tile.SIZE = 64)。这会导致地图逐块移动而不是平滑移动。

我尝试通过将xrender和yrender中的小数添加到绘图坐标来解决问题,如下所示:

public static void render(float xrender, float yrender) {
    xstart = (int) (xrender / Tile.SIZE);
    ystart = (int) (yrender / Tile.SIZE);
    int xend = (int) Math.ceil((float) Window.WIDTH / Tile.SIZE);
    int yend = (int) Math.ceil((float) Window.HEIGHT / Tile.SIZE);
    float xdecimal = xrender - (int) xrender; //hotfix for preserving decimals
    float ydecimal = yrender - (int) yrender;

    for (int x = xstart; x < xend; x++) {
        for (int y = ystart; y < yend; y++) {
            int tx = x-xstart;
            int ty = y-ystart;
            if (groundExists(tx, ty)) {
                //decimals added to the starting coordinates
                float dx = (float) x * Tile.SIZE + xdecimal;
                float dy = (float) y * Tile.SIZE + ydecimal;
                ground[tx][ty].draw(dx, dy, Tile.SIZE, Tile.SIZE);
            }
        }
    }
}

但现在这张地图非常生涩,根本不光滑。我想我需要再次重写整个渲染的东西,那么是否有某种技巧让它变得流畅?

1 个答案:

答案 0 :(得分:0)

这是我发现谷歌搜索的相机类。

 /**
 *
* @author Ceri
*/
import java.awt.geom.Point2D;

import org.lwjgl.Sys;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.geom.Shape;
import org.newdawn.slick.tiled.TiledMap;

public class Camera {

/**
 * the map used for our scene
 */
protected TiledMap map;

/**
 * the number of tiles in x-direction (width)
 */
protected int numTilesX;

/**
 * the number of tiles in y-direction (height)
 */
protected int numTilesY;

/**
 * the height of the map in pixel
 */
protected int mapHeight;

/**
 * the width of the map in pixel
 */
protected int mapWidth;

/**
 * the width of one tile of the map in pixel
 */
protected int tileWidth;

/**
 * the height of one tile of the map in pixel
 */
protected int tileHeight;

/**
 * the GameContainer, used for getting the size of the GameCanvas
 */
protected GameContainer gc;

/**
 * the x-position of our "camera" in pixel
 */
protected float cameraX;

/**
 * the y-position of our "camera" in pixel
 */
protected float cameraY;


/**
 * the offset which is neccessary to tell the mouse where the camera is at
 */
public static float MOUSE_X_OFFSET;
public static float MOUSE_Y_OFFSET;

protected Point2D.Float currentCenterPoint = new Point2D.Float(0, 0);

/**
 * Create a new camera
 *
 * @param gc the GameContainer, used for getting the size of the GameCanvas
 * @param map the TiledMap used for the current scene
 */
public Camera(GameContainer gc, TiledMap map) {
    this.map = map;

    this.numTilesX = map.getWidth();
    this.numTilesY = map.getHeight();

    this.tileWidth = map.getTileWidth();
    this.tileHeight = map.getTileHeight();

    this.mapWidth = this.numTilesX * this.tileWidth; // + 160; MIT Schwarzem Rahmen
    this.mapHeight = this.numTilesY * this.tileHeight; //  + 120; Ohne Schwarzem Rahmen

    this.gc = gc;
}

/**
 * "locks" the camera on the given coordinates. The camera tries to keep the
 * location in it's center.
 *
 * @param x the real x-coordinate (in pixel) which should be centered on the
 * screen
 * @param y the real y-coordinate (in pixel) which should be centered on the
 * screen
 */
public Point2D.Float centerOn(float x, float y) {
    //try to set the given position as center of the camera by default
    cameraX = x - gc.getWidth() / 2;
    cameraY = y - gc.getHeight() / 2;

    //if the camera is at the right or left edge lock it to prevent a black bar
    if (cameraX < 0) {
        cameraX = 0;
    }
    if (cameraX + gc.getWidth() > mapWidth) {
        cameraX = mapWidth - gc.getWidth();
    }

    //if the camera is at the top or bottom edge lock it to prevent a black bar
    if (cameraY < 0) {
        cameraY = 0;
    }
    if (cameraY + gc.getHeight() > mapHeight) {
        cameraY = mapHeight - gc.getHeight();
    }

    MOUSE_X_OFFSET = cameraX;
    MOUSE_Y_OFFSET = cameraY;

    currentCenterPoint.setLocation(cameraX, cameraY);
    return currentCenterPoint;
}

/**
 * "locks" the camera on the center of the given Rectangle. The camera tries
 * to keep the location in it's center.
 *
 * @param x the x-coordinate (in pixel) of the top-left corner of the
 * rectangle
 * @param y the y-coordinate (in pixel) of the top-left corner of the
 * rectangle
 * @param height the height (in pixel) of the rectangle
 * @param width the width (in pixel) of the rectangle
 */
public void centerOn(float x, float y, float height, float width) {
    this.centerOn(x + width / 2, y + height / 2);
}

/**
 * "locks the camera on the center of the given Shape. The camera tries to
 * keep the location in it's center.
 *
 * @param shape the Shape which should be centered on the screen
 */
public void centerOn(Shape shape) {
    this.centerOn(shape.getCenterX(), shape.getCenterY());
}

/**
 * draws the part of the map which is currently focussed by the camera on
 * the screen
 */
public void drawMap(int layer) {
    this.drawMap(0, 0, layer);
}

/**
 * draws the part of the map which is currently focussed by the camera on
 * the screen.<br>
 * You need to draw something over the offset, to prevent the edge of the
 * map to be displayed below it<br>
 * Has to be called before Camera.translateGraphics() !
 *
 * @param offsetX the x-coordinate (in pixel) where the camera should start
 * drawing the map at
 * @param offsetY the y-coordinate (in pixel) where the camera should start
 * drawing the map at
 */
public void drawMap(int offsetX, int offsetY, int layer) {
    //calculate the offset to the next tile (needed by TiledMap.render())
    int tileOffsetX = (int) -(cameraX % tileWidth);
    int tileOffsetY = (int) -(cameraY % tileHeight);

    //calculate the index of the leftmost tile that is being displayed
    int tileIndexX = (int) (cameraX / tileWidth);
    int tileIndexY = (int) (cameraY / tileHeight);


    //finally draw the section of the map on the screen
    map.render(
            tileOffsetX + offsetX,
            tileOffsetY + offsetY,
            tileIndexX,
            tileIndexY,
            (gc.getWidth() - tileOffsetX) / tileWidth + 1,
            (gc.getHeight() - tileOffsetY) / tileHeight + 1, layer, false);
}

/**
 * Translates the Graphics-context to the coordinates of the map - now
 * everything can be drawn with it's NATURAL coordinates.
 */
public void translateGraphics() {
    gc.getGraphics().translate(-cameraX, -cameraY);
}

/**
 * Reverses the Graphics-translation of Camera.translatesGraphics(). Call
 * this before drawing HUD-elements or the like
 */
public void untranslateGraphics() {
    gc.getGraphics().translate(cameraX, cameraY);
}

}

我在所有的2D游戏中使用这个。代码基本上不言自明。