我在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);
}
}
}
}
但现在这张地图非常生涩,根本不光滑。我想我需要再次重写整个渲染的东西,那么是否有某种技巧让它变得流畅?
答案 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游戏中使用这个。代码基本上不言自明。