Java - 移动随机生成的Tilemap

时间:2015-04-07 16:17:42

标签: java dictionary random tile terrain

我对java很新鲜,但我想创建一个探索式游戏。我研究了最近两周,并且能够在一些非常好的地形上实施钻石平方算法。但现在我无法弄清楚如何移动地图以及如何继续随机生成。这是我到目前为止所拥有的。

Game.java

package com.game.main;

import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferStrategy;
import java.util.Random;
//import java.util.Random;

public class Game extends Canvas implements Runnable{

    private static final long serialVersionUID = 5420209024354289119L;

    public static final int WIDTH = 1000, HEIGHT = WIDTH / 12 * 9;

    private Thread thread;
    private boolean running = false;

    //private Random r;
    private Handler handler;

    public Game(){
        handler = new Handler();
        this.addKeyListener(new KeyInput(handler));

        new Window(WIDTH, HEIGHT, "Game", this);
        final int[][] map = DSAlgorithm.makeHeightMap(10, 45, 200);

        //r = new Random();


        handler.addObject(new Player(WIDTH/2 - 32, HEIGHT/2 - 32, ID.Player));
        //handler.addObject(new World(0, 0, ID.World));
        int squareSize = 10;
        for(int y = 0; y < map.length; y+=squareSize){
            for(int x = 0; x < map.length; x+=squareSize){
                int value = map[x][y];
                handler.addObject(new TerrianTile(x, y, value));
            }
        }
    }

    public synchronized void start(){
        thread = new Thread(this);
        thread.start();
        running = true;
    }

    public synchronized void stop(){
        try {
            thread.join();
            running = false;
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void run(){
        long lastTime = System.nanoTime();
        double amountOfTicks = 60.0;
        double ns = 1000000000 / amountOfTicks;
        double delta = 0;
        long timer = System.currentTimeMillis();
        int frames = 0;
        while (running){
            long now = System.nanoTime();
            delta += (now - lastTime) / ns;
            lastTime = now;
            while(delta >= 1){
                tick();
                delta --;

            }
            if (running)
                render();
            frames++;

            if (System.currentTimeMillis() - timer > 1000){
                timer += 1000;
                System.out.println("FPS: " + frames);
                frames = 0;
            }
        }
        stop();
    }

    private void tick(){
        handler.tick();
    }

    private void render(){
        BufferStrategy bs = this.getBufferStrategy();
        if (bs == null){
            this.createBufferStrategy(3);
            return;
        }

        Graphics g = bs.getDrawGraphics();

        g.setColor(Color.black);
        g.fillRect(0, 0, WIDTH, HEIGHT);

        handler.render(g);

        g.dispose();
        bs.show();
    }

    public static void main(String args[]){
        new Game();
    }

    public static int randInt(int min, int max){
        Random rand = new Random();
        int randomNum = rand.nextInt((max - min) + 1) + min;
        return randomNum;
    }

}

Window.java

package com.game.main;

import java.awt.Canvas;
import java.awt.Dimension;

import javax.swing.JFrame;

public class Window extends Canvas {

    private static final long serialVersionUID = -1478604005915452565L;

    public Window(int width, int height, String title, Game game) {
        JFrame frame = new JFrame(title);

        frame.setPreferredSize(new Dimension(width, height));
        frame.setMaximumSize(new Dimension(width, height));
        frame.setMinimumSize(new Dimension(width, height));

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setResizable(false);
        frame.setLocationRelativeTo(null);
        frame.add(game);
        frame.setVisible(true);
        game.start();
    }
}

DSAlgorithm.java

package com.game.main;

public class DSAlgorithm {

    /**
     * This method uses the seed value to initialize the four corners of the
     * map. The variation creates randomness in the map. The size of the array
     * is determined by the amount of iterations (i.e. 1 iteration -> 3x3 array,
     * 2 iterations -> 5x5 array, etc.).
     * 
     * @param iterations
     *            the amount of iterations to do (minimum of 1)
     * @param seed
     *            the starting value
     * @param variation
     *            the amount of randomness in the height map (minimum of 0)
     * @return a height map in the form of a 2-dimensional array containing
     *         integer values or null if the arguments are out of range
     */
    public static int[][] makeHeightMap(int iterations, int seed, int variation) {
         if (iterations < 1 || variation < 0) {
              return null;
         }

         int size = (1 << iterations) + 1;
         int[][] map = new int[size][size];
         final int maxIndex = map.length - 1;

         // seed the corners
         map[0][0] = seed;
         map[0][maxIndex] = seed;
         map[maxIndex][0] = seed;
         map[maxIndex][maxIndex] = seed;

         for (int i = 1; i <= iterations; i++) {
              int minCoordinate = maxIndex >> i;// Minimum coordinate of the
                                                        // current map spaces
              size = minCoordinate << 1;// Area surrounding the current place in
                                              // the map

              diamondStep(minCoordinate, size, map, variation);
              squareStepEven(minCoordinate, map, size, maxIndex, variation);
              squareStepOdd(map, size, minCoordinate, maxIndex, variation);

              variation = variation >> 1;// Divide variation by 2
         }

         return map;
    }

    /**
     * Calculates average values of four corner values taken from the smallest
     * possible square.
     * 
     * @param minCoordinate
     *            the x and y coordinate of the first square center
     * @param size
     *            width and height of the squares
     * @param map
     *            the height map to fill
     * @param variation
     *            the randomness in the height map
     */
    private static void diamondStep(int minCoordinate, int size, int[][] map,
              int variation) {
         for (int x = minCoordinate; x < (map.length - minCoordinate); x += size) {
              for (int y = minCoordinate; y < (map.length - minCoordinate); y += size) {
                   int left = x - minCoordinate;
                   int right = x + minCoordinate;
                   int up = y - minCoordinate;
                   int down = y + minCoordinate;

                   // the four corner values
                   int val1 = map[left][up];   // upper left
                   int val2 = map[left][down]; // lower left
                   int val3 = map[right][up];  // upper right
                   int val4 = map[right][down];// lower right

                   calculateAndInsertAverage(val1, val2, val3, val4, variation,
                             map, x, y);
              }
         }
    }

    /**
     * Calculates average values of four corner values taken from the smallest
     * possible diamond. This method calculates the values for the even rows,
     * starting with row 0.
     * 
     * @param minCoordinate
     *            the x-coordinate of the first diamond center
     * @param map
     *            the height map to fill
     * @param size
     *            the length of the diagonals of the diamonds
     * @param maxIndex
     *            the maximum index in the array
     * @param variation
     *            the randomness in the height map
     */
    private static void squareStepEven(int minCoordinate, int[][] map,
              int size, int maxIndex, int variation) {
         for (int x = minCoordinate; x < map.length; x += size) {
              for (int y = 0; y < map.length; y += size) {
                   if (y == maxIndex) {
                        map[x][y] = map[x][0];
                        continue;
                   }

                   int left = x - minCoordinate;
                   int right = x + minCoordinate;
                   int down = y + minCoordinate;
                   int up = 0;

                   if (y == 0) {
                        up = maxIndex - minCoordinate;
                   } else {
                        up = y - minCoordinate;
                   }

                   // the four corner values
                   int val1 = map[left][y]; // left
                   int val2 = map[x][up];   // up
                   int val3 = map[right][y];// right
                   int val4 = map[x][down]; // down

                   calculateAndInsertAverage(val1, val2, val3, val4, variation,
                             map, x, y);
              }
         }
    }

    /**
     * Calculates average values of four corner values taken from the smallest
     * possible diamond. This method calculates the values for the odd rows,
     * starting with row 1.
     * 
     * @param minCoordinate
     *            the x-coordinate of the first diamond center
     * @param map
     *            the height map to fill
     * @param size
     *            the length of the diagonals of the diamonds
     * @param maxIndex
     *            the maximum index in the array
     * @param variation
     *            the randomness in the height map
     */
    private static void squareStepOdd(int[][] map, int size, int minCoordinate,
              int maxIndex, int variation) {
         for (int x = 0; x < map.length; x += size) {
              for (int y = minCoordinate; y < map.length; y += size) {
                   if (x == maxIndex) {
                        map[x][y] = map[0][y];
                        continue;
                   }

                   int left = 0;
                   int right = x + minCoordinate;
                   int down = y + minCoordinate;
                   int up = y - minCoordinate;

                   if (x == 0) {
                        left = maxIndex - minCoordinate;
                   } else {
                        left = x - minCoordinate;
                   }

                   // the four corner values
                   int val1 = map[left][y]; // left
                   int val2 = map[x][up];   // up
                   int val3 = map[right][y];// right
                   int val4 = map[x][down]; // down

                   calculateAndInsertAverage(val1, val2, val3, val4, variation,
                             map, x, y);
              }
         }
    }

    /**
     * Calculates an average value, adds a variable amount to that value and
     * inserts it into the height map.
     * 
     * @param val1
     *            first of the values used to calculate the average
     * @param val2
     *            second of the values used to calculate the average
     * @param val3
     *            third of the values used to calculate the average
     * @param val4
     *            fourth of the values used to calculate the average
     * @param variation
     *            adds variation to the average value
     * @param map
     *            the height map to fill
     * @param x
     *            the x-coordinate of the place to fill 
     * @param y
     *            the y-coordinate of the place to fill
     */
    private static void calculateAndInsertAverage(int val1, int val2, int val3,
              int val4, int variation, int[][] map, int x, int y) {
         int avg = (val1 + val2 + val3 + val4) >> 2;// average
         int var = (int) ((Math.random() * ((variation << 1) + 1)) - variation);
         map[x][y] = avg + var;
    }

    public static void main(String[] args) {

    }

}

Handler.java

package com.game.main;

import java.awt.Graphics;
import java.util.LinkedList;

public class Handler {

    LinkedList<GameObject> object = new LinkedList<GameObject>();
    LinkedList<Tiles> tile = new LinkedList<Tiles>();

    public void tick(){
        for (int i = 0; i < object.size(); i++){
            GameObject tempObject = object.get(i);

            tempObject.tick();
        }

        for (int t = 0; t < tile.size(); t++){
            Tiles tempObject = tile.get(t);

            tempObject.tick();
        }
    }

    public void render(Graphics g){
        for (int i = 0; i < object.size(); i++){
            GameObject tempObject = object.get(i);

            tempObject.render(g);
        }

        for (int t = 0; t < tile.size(); t++){
            Tiles tempObject = tile.get(t);

            tempObject.render(g);
        }
    }

    public void addObject(GameObject object){
        this.object.add(object);
    }

    public void removeObject(GameObject object){
        this.object.remove(object);
    }

    public void addObject(Tiles tile){
        this.tile.add(tile);
    }

    public void removeObject(Tiles tile){
        this.tile.remove(tile);
    }

}

Tiles.java

package com.game.main;

import java.awt.Graphics;
import java.util.LinkedList;

public class Handler {

    LinkedList<GameObject> object = new LinkedList<GameObject>();
    LinkedList<Tiles> tile = new LinkedList<Tiles>();

    public void tick(){
        for (int i = 0; i < object.size(); i++){
            GameObject tempObject = object.get(i);

            tempObject.tick();
        }

        for (int t = 0; t < tile.size(); t++){
            Tiles tempObject = tile.get(t);

            tempObject.tick();
        }
    }

    public void render(Graphics g){
        for (int i = 0; i < object.size(); i++){
            GameObject tempObject = object.get(i);

            tempObject.render(g);
        }

        for (int t = 0; t < tile.size(); t++){
            Tiles tempObject = tile.get(t);

            tempObject.render(g);
        }
    }

    public void addObject(GameObject object){
        this.object.add(object);
    }

    public void removeObject(GameObject object){
        this.object.remove(object);
    }

    public void addObject(Tiles tile){
        this.tile.add(tile);
    }

    public void removeObject(Tiles tile){
        this.tile.remove(tile);
    }

}

TerrianTile.java

package com.game.main;

import java.awt.Color;
import java.awt.Graphics;

public class TerrianTile extends Tiles {

    public TerrianTile(int x, int y, int tileType) {
        super(x, y, tileType);
    }

    public void tick(){

    }

    public void render(Graphics g){
        if (tileType <= 0){
            g.setColor(Color.BLUE);
            g.fillRect(x, y, 10, 10);
        }
        //water
        if (tileType > 0 && tileType < 40){
            g.setColor(Color.BLUE);
            g.fillRect(x, y, 10, 10);
        }
        //sand
        if (tileType >= 40 && tileType < 55){
            g.setColor(Color.YELLOW);
            g.fillRect(x, y, 10, 10);
        }
        //grass
        if (tileType >= 55 && tileType < 120){
            g.setColor(Color.GREEN);
            g.fillRect(x, y, 10, 10);
        }
        //forest
        if (tileType >= 120 && tileType < 140){
            g.setColor(Color.LIGHT_GRAY);
            g.fillRect(x, y, 10, 10);
        }
        //stone
        if (tileType >= 140 && tileType < 170){
            g.setColor(Color.GRAY);
            g.fillRect(x, y, 10, 10);
        }
        //snow
        if (tileType >= 170){
            g.setColor(Color.WHITE);
            g.fillRect(x, y, 10, 10);
        }
    }
}

KeyInput.java

package com.game.main;

import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

public class KeyInput extends KeyAdapter{

    private Handler handler;

    public KeyInput(Handler handler){
        this.handler = handler;
    }

    public void keyPressed(KeyEvent e){
        int key = e.getKeyCode();

        for (int i = 0; i < handler.object.size(); i++){
            GameObject tempObject = handler.object.get(i);

            if (tempObject.getId() == ID.Player){
                // key events for player 1
                if (key == KeyEvent.VK_W) tempObject.setVelY(-5);
                if (key == KeyEvent.VK_S) tempObject.setVelY(5);
                if (key == KeyEvent.VK_D) tempObject.setVelX(5);
                if (key == KeyEvent.VK_A) tempObject.setVelX(-5);
            }
        }
    }

    public void keyReleased(KeyEvent e){
        int key = e.getKeyCode();

        for (int i = 0; i < handler.object.size(); i++){
            GameObject tempObject = handler.object.get(i);

            if (tempObject.getId() == ID.Player){
                // key events for player 1
                if (key == KeyEvent.VK_W) tempObject.setVelY(0);
                if (key == KeyEvent.VK_S) tempObject.setVelY(0);
                if (key == KeyEvent.VK_D) tempObject.setVelX(0);
                if (key == KeyEvent.VK_A) tempObject.setVelX(0);
            }
        }
    }

}

不确定是否有方法将图块容纳在矩形中,然后移动矩形。任何帮助将不胜感激。

1 个答案:

答案 0 :(得分:0)

我真的不知道你在矩形中移动瓷砖是什么意思,但如果你只是想在某个方向上移动它们,你可以在绘制它们之前使用g.translate(dx,dY)。

或者如果地形没有改变,你可以在开头的图像上绘制它们,然后在不同的位置每帧绘制图像。