有没有办法用 JPanels 和 Java Swing 生成地形?

问题描述 投票:0回答:1

我一直想用随机生成的 JPanel 制作一组 JPanel(3 x 3 数组),该 JPanel 可以是森林或平原,中心的总是称为房屋的 JPanel。总会有一个可见的,并且我希望它,因此当称为字符的 JLabel 的 x 位置到达 x 位置 0 时,它将检查该数组中的哪个 JPanel 正在用作 ContentPane,并且如果此事件发生在JPanel 位于第一列,它将执行 System.out.Println("Hello!") 之类的操作,但如果这种情况发生在其他两列中,则内容窗格将设置为发生在第一列上的任何行。这与此 JLabel 的 y 位置相同。我是否需要将其放在线程中,因为它应该不断检查 x 或 y 位置是否已达到 0?如果需要,我可以发布代码,但我只需要一个示例。拥有整个 Swing 窗口的类扩展了 JFrame,如果有必要,主类会调用包含所有内容的对象 Window,例如窗口和 JLabel。

我希望它像《我的世界》世界一代一样,但如果它是 2D,用 Java Swing 制作,并且为了细节而只有一个块。我试过这个:

        while(true){
            switch(guineaXPosition) {
            case 0:
                for (int i = 0; i < world.length; i++) {
                    for(int j=0;i<world.length;j++) {
                      if (frame.getContentPane()==world[i][0]) {
                        // The guinea is in the JPanel at index [i][j].
                        // Perform the desired action.
                          System.out.println("Edge of world, nothing you can do!");
                      }else {
                          frame.setContentPane(world[i][j-1]);
                      }}
                    }               
                    break;
            case 1300:
                break;
            default:
                break;
            }
        }

在一个线程中并在另一个线程中执行此操作:

        Random random = new Random();
        int terrainTypeGen=random.nextInt(2)+1;
        for(int i=0;i<world.length;i++) {
            for(int j=0;j<world[0].length;j++) {
                if(i==1&&j==1) {
                    world[i][j]=new JPanel();
                }else {
                    String terrainType=null;
                    if(terrainTypeGen==1) {
                        world[i][j]=new JPanel();
                        world[i][j].setBackground(Color.GREEN);
                    }else if(terrainTypeGen==2) {
                        world[i][j]=new JPanel();
                        world[i][j].setBackground(Color.GREEN);
                    }
                    
                }
            }
        }
    }

请不要评判我。 如果需要更多详细信息,请告诉我。

java swing 2d
1个回答
0
投票

您能否举一个我将使用的代码类型的示例?

你可能会后悔。

首先,您应该首先定义一些描述数据的模型。这允许您将 UI 与数据解耦(这是“模型-视图-控制器”概念的基础)...

public enum Biome {
    FOREST, PLAINS
}

public interface Chunk {
    public Biome getBiome();
    public Point getLocation();
}

public interface World {
    public Chunk getChunkAt(int x, int y);
}

这是非常基本的,但我们还需要某种方法来创建随机块,在这种情况下我们可以使用工厂的概念......

public interface ChunkFactory {
    public Chunk createChunk(Point worldLocation);
}

但是我们为什么要使用

interface
s?

接口允许您定义代码的契约,而无需绑定到单独的实现。将其与“依赖注入”原则联系起来。

接下来,我们需要定义某种模型来存储我们的块,该模型可以随机访问,并且可以根据放入其中的数据动态增长。

为此,我会考虑某种“矩阵”。你可以使用二维数组,但是那有什么乐趣呢😉.

以下是由

Map
支持的“矩阵”概念...

// This basically acts a multi dimensional matrix of values, keyed by the
// x/y coordinates.
public interface Matrix<Type> {
    public Type get(int x, int y);
    public void put(Type value, int x, int y);
}

public class HashMapMatrix<Type> implements Matrix<Type> {        
    private Map<Integer, Map<Integer, Type>> values = new HashMap<>(8);
    
    @Override
    public Type get(int x, int y) {
        Map<Integer, Type> rows = values.get(y);
        if (rows == null) {
            return null;
        }
        return rows.get(x);
    }
    
    @Override
    public void put(Type value, int x, int y) {
        Map<Integer, Type> rows = values.get(y);
        if (rows == null) {
            rows = new HashMap<Integer, Type>(8);
            values.put(y, rows);
        }
        rows.put(x, value);
    }
}

现在,我们可以开始一些初步的实现......

public class DefaultChunkFactory implements ChunkFactory {
    
    private List<Biome> listOfBiomes = new ArrayList<>(Arrays.asList(Biome.values()));
    
    protected List<Biome> getListOfBiomes() {
        return listOfBiomes;
    }
    
    @Override
    public Chunk createChunk(Point worldLocation) {
        List<Biome> biomes = new ArrayList<>(getListOfBiomes());
        Collections.shuffle(biomes);
        Biome biome = biomes.get(0);
        return new DefaultChunk(biome, worldLocation);
    }
}

public class DefaultChunk implements Chunk {        
    private Biome biome;
    private Point location;

    public DefaultChunk(Biome biome, Point location) {
        this.biome = biome;
        this.location = new Point(location);
    }
    
    @Override
    public Biome getBiome() {
        return biome;
    }        

    @Override
    public Point getLocation() {
        return location;
    }
}

public class DefaultWorld implements World {
    
    private Matrix<Chunk> chunkMatrix = new HashMapMatrix<>();
    private ChunkFactory chunkFactory;

    public DefaultWorld(ChunkFactory chunkFactory) {
        this.chunkFactory = chunkFactory;
    }

    public ChunkFactory getChunkFactory() {
        return chunkFactory;
    }
    
    protected Matrix<Chunk> getChunks() {
        return chunkMatrix;
    }
    
    @Override
    public Chunk getChunkAt(int x, int y) {
        Chunk chunk = getChunks().get(x, y);
        if (chunk == null) {
            chunk = getChunkFactory().createChunk(new Point(x, y));
            getChunks().put(chunk, x, y);
        }
        return chunk;
    }
}

这些都是非常基本的,但它们构建了“世界”和“块”的概念。

最后,我们可以开始使用 UI!

首先,一个可以代表

Chunk

的组件
public class ChunkPane extends JPanel {
    private Chunk chunk;

    public ChunkPane(Chunk chunk) {
        this.chunk = chunk;
        switch (chunk.getBiome()) {
            case FOREST:
                setBackground(Color.GREEN);
                break;
            case PLAINS:
                setBackground(Color.YELLOW);
                break;
        }
        
        setLayout(new GridBagLayout());
        Point location = chunk.getLocation();
        JLabel label = new JLabel(location.x + "x" + location.y);
        add(label);
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(200, 200);
    }
}

这是非常基本的,它根据生物群系设置背景颜色并显示世界中的区块位置。

好吧,接下来,我们需要一个“世界”窗格,它可以根据玩家的位置管理区块的显示。

public class SwingCraft extends JPanel {
    protected enum Direction {
        UP, DOWN, LEFT, RIGHT
    }
    
    private Matrix<ChunkPane> chunkMatrix = new HashMapMatrix<ChunkPane>();
    
    private World world;
    private Point playerLocation = new Point(0, 0);
    
    public SwingCraft(World world) {
        setLayout(new BorderLayout());
        this.world = world;
        setChunk(playerLocation);
        InputMap inputMap = getInputMap(WHEN_IN_FOCUSED_WINDOW);
        ActionMap actionMap = getActionMap();
        
        inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), Direction.LEFT);
        inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), Direction.RIGHT);
        inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), Direction.UP);
        inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), Direction.DOWN);
        
        actionMap.put(Direction.LEFT, new MoveAction(-1, 0));
        actionMap.put(Direction.RIGHT, new MoveAction(1, 0));
        actionMap.put(Direction.UP, new MoveAction(0, -1));
        actionMap.put(Direction.DOWN, new MoveAction(0, 1));
    }
    
    public void setChunk(Point location) {
        ChunkPane pane = chunkMatrix.get(location.x, location.y);
        if (pane == null) {
            Chunk chunk = world.getChunkAt(location.x, location.y);
            pane = new ChunkPane(chunk);
            chunkMatrix.put(pane, location.x, location.y);
        }
        
        removeAll();
        add(pane);
        
        revalidate();
        repaint();
    }
    
    protected void moveBy(int xDelta, int yDelta) {
        int targetX = playerLocation.x + xDelta;
        int targetY = playerLocation.y + yDelta;
        
        playerLocation.x = targetX;
        playerLocation.y = targetY;
        
        setChunk(playerLocation);
    }
    
    protected class MoveAction extends AbstractAction {
        private int xDelta, yDelta;

        public MoveAction(int xDelta, int yDelta) {
            this.xDelta = xDelta;
            this.yDelta = yDelta;
        }
        
        @Override
        public void actionPerformed(ActionEvent e) {
            moveBy(xDelta, yDelta);
        }
    }
}

这是非常基本的。它提供了使用键绑定的简单导航,该绑定将显示缓存的生物群系窗格(如果可用)或创建新的块和窗格并显示它。

可运行的示例...

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.KeyStroke;

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

    public Main() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();
                frame.add(new SwingCraft(new DefaultWorld(new DefaultChunkFactory())));
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class SwingCraft extends JPanel {
        protected enum Direction {
            UP, DOWN, LEFT, RIGHT
        }

        private Matrix<ChunkPane> chunkMatrix = new HashMapMatrix<ChunkPane>();

        private World world;
        private Point playerLocation = new Point(0, 0);

        public SwingCraft(World world) {
            setLayout(new BorderLayout());
            this.world = world;
            setChunk(playerLocation);
            InputMap inputMap = getInputMap(WHEN_IN_FOCUSED_WINDOW);
            ActionMap actionMap = getActionMap();

            inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), Direction.LEFT);
            inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), Direction.RIGHT);
            inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), Direction.UP);
            inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), Direction.DOWN);

            actionMap.put(Direction.LEFT, new MoveAction(-1, 0));
            actionMap.put(Direction.RIGHT, new MoveAction(1, 0));
            actionMap.put(Direction.UP, new MoveAction(0, -1));
            actionMap.put(Direction.DOWN, new MoveAction(0, 1));
        }

        public void setChunk(Point location) {
            ChunkPane pane = chunkMatrix.get(location.x, location.y);
            if (pane == null) {
                Chunk chunk = world.getChunkAt(location.x, location.y);
                pane = new ChunkPane(chunk);
                chunkMatrix.put(pane, location.x, location.y);
            }

            removeAll();
            add(pane);

            revalidate();
            repaint();
        }

        protected void moveBy(int xDelta, int yDelta) {
            int targetX = playerLocation.x + xDelta;
            int targetY = playerLocation.y + yDelta;

            playerLocation.x = targetX;
            playerLocation.y = targetY;

            setChunk(playerLocation);
        }

        protected class MoveAction extends AbstractAction {
            private int xDelta, yDelta;

            public MoveAction(int xDelta, int yDelta) {
                this.xDelta = xDelta;
                this.yDelta = yDelta;
            }

            @Override
            public void actionPerformed(ActionEvent e) {
                moveBy(xDelta, yDelta);
            }
        }
    }

    public class ChunkPane extends JPanel {
        private Chunk chunk;

        public ChunkPane(Chunk chunk) {
            this.chunk = chunk;
            switch (chunk.getBiome()) {
                case FOREST:
                    setBackground(Color.GREEN);
                    break;
                case PLAINS:
                    setBackground(Color.YELLOW);
                    break;
            }

            setLayout(new GridBagLayout());
            Point location = chunk.getLocation();
            JLabel label = new JLabel(location.x + "x" + location.y);
            add(label);
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }
    }

    // This basically acts a multi dimensional matrix of values, keyed by the
    // x/y coordinates.
    public interface Matrix<Type> {
        public Type get(int x, int y);
        public void put(Type value, int x, int y);
    }

    public class HashMapMatrix<Type> implements Matrix<Type> {        
        private Map<Integer, Map<Integer, Type>> values = new HashMap<>(8);

        @Override
        public Type get(int x, int y) {
            Map<Integer, Type> rows = values.get(y);
            if (rows == null) {
                return null;
            }
            return rows.get(x);
        }

        @Override
        public void put(Type value, int x, int y) {
            Map<Integer, Type> rows = values.get(y);
            if (rows == null) {
                rows = new HashMap<Integer, Type>(8);
                values.put(y, rows);
            }
            rows.put(x, value);
        }
    }

    public enum Biome {
        FOREST, PLAINS
    }

    public interface Chunk {
        public Biome getBiome();
        public Point getLocation();
    }

    public interface World {
        public Chunk getChunkAt(int x, int y);
    }

    public interface ChunkFactory {
        public Chunk createChunk(Point worldLocation);
    }

    public class DefaultChunkFactory implements ChunkFactory {

        private List<Biome> listOfBiomes = new ArrayList<>(Arrays.asList(Biome.values()));

        protected List<Biome> getListOfBiomes() {
            return listOfBiomes;
        }

        @Override
        public Chunk createChunk(Point worldLocation) {
            List<Biome> biomes = new ArrayList<>(getListOfBiomes());
            Collections.shuffle(biomes);
            Biome biome = biomes.get(0);
            return new DefaultChunk(biome, worldLocation);
        }
    }

    public class DefaultChunk implements Chunk {        
        private Biome biome;
        private Point location;

        public DefaultChunk(Biome biome, Point location) {
            this.biome = biome;
            this.location = new Point(location);
        }

        @Override
        public Biome getBiome() {
            return biome;
        }        

        @Override
        public Point getLocation() {
            return location;
        }
    }

    public class DefaultWorld implements World {

        private Matrix<Chunk> chunkMatrix = new HashMapMatrix<>();
        private ChunkFactory chunkFactory;

        public DefaultWorld(ChunkFactory chunkFactory) {
            this.chunkFactory = chunkFactory;
        }

        public ChunkFactory getChunkFactory() {
            return chunkFactory;
        }

        protected Matrix<Chunk> getChunks() {
            return chunkMatrix;
        }

        @Override
        public Chunk getChunkAt(int x, int y) {
            Chunk chunk = getChunks().get(x, y);
            if (chunk == null) {
                chunk = getChunkFactory().createChunk(new Point(x, y));
                getChunks().put(chunk, x, y);
            }
            return chunk;
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.