2

(不是这样)这里的简短问题。我正在使用 Swing 作为 UI 而不是控制台(这使得在 Eclipse 中更容易使用,等等),但我似乎遇到了障碍。

我遇到的问题是,当我进入游戏循环时,UI 将无法正常显示。我得到了一个丑陋的窗框,它在整个过程中给了我“纸牌”的效果,并且在运行时它的 RAM 使用量迅速增长。

我在这里错过了关于 Swing 的一些重要内容吗?我必须使用 Swing 的并发设置来执行此操作吗?如果是这样,最好的方法是什么?

完整代码如下:

package roguelike;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.LinkedList;

import javax.swing.*;
import javax.swing.text.*;

public class roguelike {
    Color c_black = new Color(0x000000);
    Color c_white = new Color(0xffffff);
    Color c_red = new Color(0xff0000);
    Color c_blue = new Color(0x0000ff);
    Color c_green = new Color(0x00ff00);

    UI ui = null;
    Player me = null;
    Map gamemap = null;
    LinkedList<Character> keyqueue = new LinkedList<Character>();

    int charheight = 20;
    int charwidth = 80;

    public static void main(String[] args){
        SwingUtilities.invokeLater(new Runnable(){
            public void run(){
                roguelike game = new roguelike();
                game.run();
            }
        });
    }
    public roguelike(){
        gamemap = new Map();
        ui = new UI(charheight,charwidth,"Monospaced");
        me = new Player();
    }
    private class UI extends JFrame implements KeyListener{
        private static final long serialVersionUID = 9065411532125953842L;
        JPanel disp_screen = null;
        JTextPane disp_screen_text = null;
        StyledDocument disp_doc = null;
        Font mono_norm = null;
        int pxheight = 0;
        int pxwidth = 0;
        String[][] ctemp = new String[charheight][charwidth];
        String[][] stemp = new String[charheight][charwidth];


        public UI(int h,int w,String fontname){
            setVisible(true);
            charheight = h;
            charwidth = w;
            addKeyListener(this);

            this.setResizable(false);
            mono_norm = new Font(fontname,0,25);
            initScreen(h,w);
            add(disp_screen);
            makeStyles();
            try {
                disp_doc.insertString(0, "12345678901234567890123456789012345678901234567890123456789012345678901234567890\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20", disp_doc.getStyle("Default"));
            } catch (BadLocationException e) {
                e.printStackTrace();
            }

            Dimension temp = disp_screen.getSize();
            this.setSize(temp);
            this.setDefaultCloseOperation(EXIT_ON_CLOSE);           


            pack();
            try {
                disp_doc.remove(0, disp_doc.getLength());
            } catch (BadLocationException e) {
                e.printStackTrace();
            }
            renderMap(gamemap.getText(),gamemap.getStyles());

        }
        @Override
        public void keyPressed(KeyEvent e) {
            // TODO Auto-generated method stub

        }
        @Override
        public void keyReleased(KeyEvent e) {
            // TODO Auto-generated method stub

        }
        @Override
        public void keyTyped(KeyEvent e) {
            keyqueue.add(e.getKeyChar());
        }
        private void initScreen(int height, int width){
            FontMetrics metric = getFontMetrics(mono_norm);
            String temp = null;

            //generate a string of the right width from which to grab metrics
            for(int x=0;x<=width;x++){
                temp += '.';
            }
            pxwidth = SwingUtilities.computeStringWidth(metric, temp);
            pxheight = (metric.getHeight())*charheight;

            disp_screen = new JPanel();
            disp_screen_text = new JTextPane();
            disp_screen_text.setEditable(false);
            disp_screen_text.setAlignmentX(LEFT_ALIGNMENT);
            disp_screen_text.setAlignmentY(TOP_ALIGNMENT);
            disp_screen_text.setFont(mono_norm);
            disp_screen_text.setBackground(c_black);
            disp_screen_text.setForeground(c_green);
            disp_doc = disp_screen_text.getStyledDocument();


            disp_screen.add(disp_screen_text);
            disp_screen.setAlignmentX(LEFT_ALIGNMENT);
            disp_screen.setAlignmentY(TOP_ALIGNMENT);
            disp_screen.setLayout(new BoxLayout(disp_screen,BoxLayout.Y_AXIS));
        }
        private void makeStyles(){
            //The default style removes all special formatting and returns the text to standard nonsense
            Style sty_default = disp_doc.addStyle("Default", null);
            StyleConstants.setFontFamily(sty_default, "Monospaced");
            StyleConstants.setFontSize(sty_default, 18);
            StyleConstants.setForeground(sty_default, c_green);
            StyleConstants.setBackground(sty_default, c_black);
            StyleConstants.setItalic(sty_default, false);
            StyleConstants.setBold(sty_default, false);
            //StyleConstants.setSpaceAbove(sty_default, 0);
            //StyleConstants.setSpaceBelow(sty_default, 0);

            //The following styles apply certain effects. They are meant to be set without replacing styles
            Style sty_bold = disp_doc.addStyle("Bold", disp_doc.getStyle("Default"));
            StyleConstants.setBold(sty_bold,true);

            Style sty_ital = disp_doc.addStyle("Italic", disp_doc.getStyle("Default"));
            StyleConstants.setItalic(sty_ital, true);

        }
        private void clearMap(){
            try {
                disp_doc.remove(0, disp_doc.getLength());
            } catch (BadLocationException e1) {
                e1.printStackTrace();
            }
            try {
                //CLEAR THE MAP
                //For every row...
                for(int y=0;y<charheight;y++){
                    //For every column location in a row...
                    for(int x=0;x<charwidth;x++){
                        disp_doc.insertString(disp_doc.getLength(),".", disp_doc.getStyle("Default"));
                    }
                    disp_doc.insertString(disp_doc.getLength(),"\n", disp_doc.getStyle("Default"));
                }
            } catch (BadLocationException e){
                    e.printStackTrace();
            }
        }
        public void renderMap(String[][] chars, String[][] styles){
            System.out.print("Rendering map...");
            clearMap();
            ctemp = chars;
            stemp = styles;

            try {

                //For every row...
                for(int y=0;y<charheight;y++){
                    //For every column location in a row...
                    for(int x=0;x<charwidth;x++){
                        if(ctemp[y][x] != null){
                            if(stemp[y][x] == "D"){
                                disp_doc.remove((y*charwidth)+x, 1);
                                disp_doc.insertString((y*charwidth)+x,ctemp[y][x], disp_doc.getStyle("Default"));
                            } else if(stemp[y][x] == "B"){
                                disp_doc.remove((y*charwidth)+x, 1);
                                disp_doc.insertString((y*charwidth)+x,ctemp[y][x], disp_doc.getStyle("Bold"));
                            } else if(stemp[y][x] == "I"){
                                disp_doc.remove((y*charwidth)+x, 1);
                                disp_doc.insertString((y*charwidth)+x,ctemp[y][x], disp_doc.getStyle("Italic"));
                            } else{
                                disp_doc.remove((y*charwidth)+x, 1);
                                disp_doc.insertString((y*charwidth)+x,ctemp[y][x], disp_doc.getStyle("Default"));
                            }
                        }
                    }
                }
            } catch (BadLocationException e){
                e.printStackTrace();
                System.err.print(e.getCause());
            }
        }
    }

    //Handles the virtualized information of characters on the map. Does NOT handle display of map on screen
    //Displaying the screen happens by passing required data to the ui member
    private class Map{
        //Holds an array of map characters
        String[][] text = new String[charheight][charwidth];
        //Holds an array of styles associated with each map character
        String[][] styles = new String[charheight][charwidth];


        public Map(){
        }
        public String[][] getText(){

            return text;
        }
        public String[][] getStyles(){
            return styles;
        }
        public void putch(String thing, String styledef,int y, int x){
            text[y][x] = thing;
            styles[y][x] = styledef;
        }
    }

    private class Player{
        //Player location, [y][x]
        int[] location = {0,0};
        String sym = "@";
        public Player(){
        }
        public int[] getLocation(){
            return location;
        }
        public String getSymbol(){
            return sym;
        }
        public void setLocation(int y, int x){
            location[0]=y;
            location[1]=x;
        }
        public void setSymbol(String newsym){
            sym = newsym;
        }
        public void move(int dir){
            //Movement will be handled in an 8 directional fashion
            //North is 1, like below
            //     812
            //     703
            //     654
            //////////////////////
            switch(dir){
                case 0:
                    break;
                case 1:
                    location[0] += 1;
                    break;
                case 2:
                    location[0] += 1;
                    location[1] += 1;
                    break;
                case 3:
                    location[1] += 1;
                    break;
                case 4:
                    location[0] -= 1;
                    location[1] += 1;
                    break;
                case 5:
                    location[0] -= 1;
                    break;
                case 6:
                    location[0] -= 1;
                    location[1] -= 1;
                    break;
                case 7:
                    location[1] -= 1;
                    break;
                case 8:
                    location[0] += 1;
                    location[1] -= 1;
                default:
                    System.err.print("ERROR! "+dir+" is not a valid direction!");
                    break;
            }
        }
    }

    /////////////////////////////////////////////////////
    /////////////FUNCTIONS///////////////////////////////
    /////////////////////////////////////////////////////
    public void run(){
        boolean running = true;
        while(running){
            //Render Map
            gamemap.putch(me.getSymbol(), "D", me.getLocation()[0], me.getLocation()[1]);
            ui.renderMap(gamemap.getText(), gamemap.getStyles());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //Wait for player input
            if(keyqueue.isEmpty()){
                continue;
            }
            //Act on input
            else{
                char input = keyqueue.getFirst();
                keyqueue.removeFirst();
                if(input == 'w'){
                    me.move(1);
                }
                if(input =='a'){
                    me.move(7);
                }
                if(input == 's'){
                    me.move(5);
                }
                if(input == 'd'){
                    me.move(3);
                }
            }
        }

    }
}
4

1 回答 1

5

Swing 应用程序必须是事件驱动的——你的game.run()调用将阻止 Swing 做任何其他有用的事情。请注意,“事件”可能是用户事件、计时器或其他可能的东西。

如果您的设计需要game.run()或类似的东西运行并且永不返回,则可以在另一个线程(甚至 SwingWorker 后台线程)上完成,但必须在 Swing 线程上访问所有 UI 组件。

建议:您的键盘处理可以通过您编写的KeyListener轻松完成,附加到窗口或其他组件上的事件处理程序,然后在用户按下键时调用 - 即您不需要使用此设计进行轮询.

于 2012-07-19T21:25:51.013 回答