使用JTextArea的游戏测试

news/2024/7/7 14:45:17

效果
在这里插入图片描述
核心类(主要是使用char[][]存储显示信息,StringBuilder用于拼接信息在JTextArea上显示)

public class MyTextPanel extends JTextArea implements MyListener,Runnable, Input {

    //宽 88   高 29
    private StringBuilder builder;
    private char[][] map;
    private int updateTime;
    private WallContainer walls;
    private boolean[] lastKey;
    private boolean[] currentKey;
    private List<Integer> dirtyKey;
    private Player player;

    public MyTextPanel(){
        initData();
        setOther();
        startLoop();
    }

    private void startLoop() {
        Thread thread = new Thread(this);
        thread.setDaemon(true);
        thread.start();
    }

    private void setOther() {
        setFont(new Font("consolas",Font.PLAIN,16));
        setEditable(false);
        addKeyListener(this);
    }

    private void initData() {
        builder=new StringBuilder();
        map=new char[29][88];
        updateTime=17;
        walls=new WallContainer();
        lastKey=new boolean[26];
        currentKey=new boolean[26];
        dirtyKey=new ArrayList<>();
        player=new Player(walls,this);
    }

    @Override//65
    public void keyPressed(KeyEvent e) {
        int index=getIndex(e.getKeyCode());
        if(index!=-1)setValue(index,true);
    }

    private void setValue(int index, boolean value) {
        currentKey[index]=value;
        dirtyKey.add(index);
    }

    private int getIndex(int keyCode) {
        if(keyCode<65||keyCode>90)return -1;
        return keyCode-65;
    }

    @Override
    public void keyReleased(KeyEvent e) {
        int index=getIndex(e.getKeyCode());
        if(index!=-1)setValue(index,false);
    }

    @Override
    public void run() {
        while (true){
            long start = System.currentTimeMillis();
            action();
            draw();
            long end = System.currentTimeMillis();
            if(end-start<updateTime){
                sleep(updateTime+start-end);
            }
        }
    }

    private void sleep(long time) {
//        System.out.println("OK");//测试性能
        try {
            Thread.sleep(time);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private void draw() {
        clearMap();
        drawOther();
        postMap();
    }

    private void postMap() {
        builder.setLength(0);
        for (char[] aMap : map) {
            builder.append(aMap).append("\n");
        }
        setText(builder.toString());
    }

    private void drawOther() {
        walls.draw(map);
        player.draw(map);
    }

    private void clearMap() {
        for (char[] aMap : map) {
            Arrays.fill(aMap, ' ');
        }
    }

    private void action() {
        player.action();
        updateKey();
    }

    private void updateKey() {
        if(dirtyKey.isEmpty())return;
        dirtyKey.forEach(index->lastKey[index]=currentKey[index]);
        dirtyKey.clear();
    }

    //  存储按键状态  把监听按键状态 变为查询按键状态
    @Override
    public boolean keyDown(int keyCode) {
        int index=getIndex(keyCode);
        if(index==-1)return false;
        return !lastKey[index]&&currentKey[index];
    }

    @Override
    public boolean keyUp(int keyCode) {
        int index=getIndex(keyCode);
        if(index==-1)return false;
        return lastKey[index]&&!currentKey[index];
    }

    @Override
    public boolean keyPress(int keyCode) {
        int index=getIndex(keyCode);
        if(index==-1)return false;
        return lastKey[index]&&currentKey[index];
    }

}

适配器接口

public interface MyListener extends KeyListener {

    @Override
    default void keyTyped(KeyEvent e) {

    }

}

判断输入接口(用于把按键事件的监听改为查询,更适合游戏)

public interface Input {

    boolean keyDown(int keyCode);
    boolean keyUp(int keyCode);
    boolean keyPress(int keyCode);

}

玩家类

public class Player {

    private WallContainer walls;
    private Input input;
    private int x;
    private float y;
    private float ySpeed;
    private float g;
    private int width;
    private int height;
    private int offsetX;
    private int offsetY;
    private char dir;
    private boolean air;

    public Player(WallContainer walls, Input input) {
        this.walls = walls;
        this.input = input;
        x=44;
        y=4;
        width=6;
        height=3;
        offsetX=-3;
        offsetY=-3;
        dir='P';
        ySpeed=0;
        g=0.1f;
        air=false;
    }

    public void draw(char[][] map){
        for (int i = (int) (y+offsetY); i < y+offsetY+height; i++) {
            if(i>=0){
                Arrays.fill(map[i],x+offsetX,x+offsetX+width,dir);
            }
        }
    }

    public void action(){
        if(input.keyPress(KeyEvent.VK_D)){
            dir='P';
            moveH(1);
        }else if(input.keyPress(KeyEvent.VK_A)){
            dir='q';
            moveH(-1);
        }
        if(air){
            if(ySpeed<2){
                ySpeed+=g;
            }
            if(ySpeed>0&&walls.collisionH(x-2,x+2, (int) (y+ySpeed))){//下降 且要碰撞对象
                while (!walls.collisionH(x-2,x+2, (int) (y+1))){
                    y+=1;
                }
                ySpeed=0;
                air=false;
            }else {//上升不管
                y+=ySpeed;
            }
        }else {
            if(!walls.collisionH(x-2,x+2, (int) (y+1))){
                air=true;
            }
            if(input.keyDown(KeyEvent.VK_J)){
                ySpeed=-2;
                y-=1;
            }
        }
    }

    private void moveH(int speed) {
        if(!walls.collisionV(x+speed*3,(int)(y-height), (int) y)){
            x+=speed;
        }
    }

}

墙类

public class Wall {

    private int x;
    private int y;
    private int width;
    private int height;

    public Wall(int x, int y, int width, int height) {
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
    }

    public void draw(char[][] map){
        for (int i = y; i < y+height; i++) {
            Arrays.fill(map[i],x,x+width,'W');
        }
    }

    public boolean collisionH(int x1,int x2,int y){
        if(x2<x||x1>x+width)return false;
        if(y<this.y||y>this.y+height)return false;
        return true;
    }

    public boolean collisionV(int x,int y1,int y2){
        if(y2<y||y1>y+height)return false;
        if(x<this.x||x>this.x+width)return false;
        return true;
    }

}

墙类容器类(用于判断与墙的碰撞,以及绘制墙)

public class WallContainer {

    private List<Wall> hWall;
    private List<Wall> vWall;

    public WallContainer() {
        hWall=new ArrayList<>();
        vWall=new ArrayList<>();
        initData();
    }

    private void initData() {
        hWall.add(new Wall(0,26,88,3));
        hWall.add(new Wall(22,13,44,3));
        vWall.add(new Wall(0,0,4,26));
        vWall.add(new Wall(84,0,4,26));
    }

    public boolean collisionH(int x1,int x2,int y){
        for (Wall wall:hWall){
            if(wall.collisionH(x1, x2, y))return true;
        }
        return false;
    }

    public boolean collisionV(int x,int y1,int y2){
        for (Wall wall:vWall){
            if(wall.collisionV(x, y1, y2))return true;
        }
        return false;
    }

    public void draw(char[][] map){
        hWall.forEach(wall -> wall.draw(map));
        vWall.forEach(wall -> wall.draw(map));
    }

}

主启动类(实际循环等逻辑应该放到该类中,MyTextPanel应该只负责显示)

public class MainGame extends JFrame {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(MainGame::new);
    }

    public MainGame() throws HeadlessException{
        setSize(802,604);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        add(new MyTextPanel());
        setResizable(false);
        setVisible(true);
    }

}

实际,只是转换一下输出形式,其他游戏逻辑都可以按之前的写


http://www.niftyadmin.cn/n/658010.html

相关文章

Jersey 2.x 服务器端应用支持的容器

基于 JAX-RS Servlet-based 部署的一部分标准&#xff0c;能运行在任何支持 Servlet 2.5 和更高标准的的容器上。Jersey 提供支持程序化部署在下面的容器中&#xff1a;Grizzly 2 &#xff08;HTTP 和 Servlet&#xff09;&#xff0c; JDK Http server&#xff0c;Simple Http…

一个用xml存储日志信息的程序

本程序中利用asp代码生成的日志信息存储到xml文件中&#xff0c;然后由xslt格式化输出 该程序共分三个部分:1. 生成日志的asp程序 代码见以前的一篇文章&#xff1a; http://blog.csdn.net/precipitant/archive/2005/04/28/366634.aspx 2. 由 上面的 程序 生成的日志文…

properties与yaml互转工具类

没事写的&#xff0c;实际更加推荐使用网上一些更加完善的在线工具 效果 正向转换 原内容 转换结果 反向 原内容 结果 主要类 public class p2y {private static final String REVERSE "-r";private static final Pattern PATTERN Pattern.compile("(.)\…

IDEA default keymap整理

main menu ctrlalts 打开settings ctrlaltshifts 打开project Structure alt1 打开项目目录 alt7 打开Structure目录 altf12 代开teminal git ctrlaltz revert ctrlk commit project ctrlshiftk push edit ctrly删除行 ctrldelete删除到单词末尾 ctrlbackspace删除到单词首 ctr…

马化腾在小程序首次获选世界互联网领先科技成果奖发表演讲

昨日小程序斩获一项世界级殊荣——在乌镇举行的第五届世界互联网大会“世界互联网领先科技成果发布活动”上&#xff0c;作为一项全新的技术和应用创新&#xff0c;小程序首次获选世界互联网领先科技成果。腾讯公司董事会主席兼首席执行官马化腾作为腾讯公司代表上台领奖&#…

Java小图片拼接为图集

使用的是暴力拼接(从左向右&#xff0c;从上到下&#xff0c;先放矮的图片进去) 对于后缀为_strip[数字]的图片会再次分割提高图集密度 效果 拼接前 拼接后 对应子图的偏移信息记录类(自动生成) 单张图片信息类(可能有多张图片因为有后面名为_strip[数字]的情况) public cl…

以xml文件作为数据库的程序一例

xml分为三种&#xff0c;index.xml保存一个最大的索引 &#xff0c;相当于一个序列。flfgcx_list.xml为一个目录&#xff0c;里面保存了所有的信息的索引信息另一种就是内容xml&#xff0c;每一种法律都有一个文件。文件名为一个数字&#xff0c;当录入当前的法律的时候自动创造…

三汇自动挂断问题

三汇自动挂断问题 ACK检测 转载于:https://www.cnblogs.com/devour/p/10901341.html