2016-02-04 2 views
0

j'ai écrit une carte renderer sur Slick2D qui se déplace avec le joueur:Java: Comment rendre la carte autour du lecteur en douceur?

//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); 
      } 
     } 
    } 
} 

Le problème est qu'il est basé sur des entiers et chaque carreau est représenté par un seul chiffre au lieu d'être représenté comme chaque pixel de la tuile (Tile.SIZE = 64 ici). Cela provoque le déplacement de la carte bloc par bloc au lieu d'un mouvement fluide.

J'ai essayé de résoudre le problème en ajoutant les décimales de XRender et yrender au tirage au sort des coordonnées comme ceci:

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); 
      } 
     } 
    } 
} 

Mais maintenant, la carte est incroyablement saccadé et pas lisse du tout. Je pense que j'ai besoin de réécrire à nouveau tout ce qui est rendu. Y a-t-il une sorte de truc pour le rendre lisse?

+1

Pourriez-vous utiliser [double tampon] (https://en.wikipedia.org/wiki/Multiple_buffering) – Shark

Répondre

1

C'est la classe de caméra que j'ai trouvé googling.

/** 
* 
* @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); 
} 

}

J'utilise celui-ci pour tous mes jeux 2D. Le code parle essentiellement pour lui-même.