我所知道坦克大战(单机版)之画出坦克的实心圆、让圆动起来、双缓冲解决闪烁问题...

本篇文章目的


  • 画出坦克的实心圆
  • 让坦克圆动起来
  • 双缓冲解决闪烁问题

一、画出代表坦克的实心圆

我们需要画出一个圆,那么可以使用fillOval方法

fillOval(int x,int y ,int width ,int  height)

参数的X 和 Y是矩形框的左上角的坐标,width和height是宽和高。

image.png

而我们重写paint方法进行画出坦克的圆

@Override
public void paint(Graphics g) {

    //获取默认的颜色Color
    Color c = g.getColor();
    //将坦克颜色为红色
    g.setColor(Color.red);
    //画一个圆
    g.fillOval(50,50,30,30);
    //将原颜色填充回
    g.setColor(c);
}

image.png

当然也可以在lauchFrame方法里添加背景填充色,显得更外显眼一些

//添加设置背景颜色
this.setBackground(Color.GREEN);

二、让坦克动起来

我们使用fillOval方法画出了圆的实现,那么怎么让这个圆改变位置?

//画一个圆
g.fillOval(50,50,30,30);

我们发现x和y的做标都是50,他们是固定的!

若改变成变量的方式?是不是也是一样可以呢?

int x = 50;//坦克的x坐标

int y = 50;//坦克的y坐标


@Override
public void paint(Graphics g) {

    //获取默认的颜色Color
    Color c = g.getColor();
    //将坦克颜色为红色
    g.setColor(Color.red);
    //画一个圆
    g.fillOval(x,y,30,30);
    //将原颜色填充回
    g.setColor(c);
}

image.png

若我们每次原有的基础上进行改动,是不是就动起来了?

我们采用repaint重绘方法,每隔多少毫秒刷新最新的圆点信息坐标

private class PaintThread implements Runnable {
    @Override
    public void run() {
        while (true) {
            repaint();//重绘方法
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
//定义窗口方法
public void lauchFrame() {
    
    //省略其他关键性代码.....

    //添加设置背景颜色
    this.setBackground(Color.GREEN);

    //使用线程重绘最新圆点信息坐标
    new Thread(new PaintThread()).start();
}

@Override
public void paint(Graphics g) {

    //省略其他关键性代码.....
    
    //刷新圆点位置
    x += 5;//x坐标
    y += 5;//y坐标
}

这时我们在main方法运行起来就发现每个100毫秒就会移动圆点位置了

image.png

为什么使用线程重面,而不是每按下一个键进行一次重画?

  • 线程重画更均匀,更能控制重画的速度。
  • 按键重画不能解决子弹自动飞行的问题。

三、双缓冲解决闪烁问题

我们的显示器一般都是多少hz、多少hz的刷新率,而刷新速度太快,paint方法还没完成,没跟上导致会出现闪烁的问题

那么怎么解决呢?

1.逐条显示

2.将所有东西画在虚拟图片上,一次性显示出来

Image offScreenImage = null;//虚拟图片

@Override
public void update(Graphics g){
    if(offScreenImage == null){
        //若为null,则创建一张图片
        offScreenImage = this.createImage(800,600);
    }
    //获取到虚拟图片的画笔
    Graphics gOffScreen = offScreenImage.getGraphics();

    //使用虚拟图片的画笔画圆
    paint(gOffScreen);

    //将虚拟图片画下来
    g.drawImage(offScreenImage,0,0,null);
}

但是运行起来会发现,圆动起来后慢慢变成了一条线

image.png

这是怎么回事呢?

因为当我们不重写update方法时,它会自己用背景颜色刷一遍,刷完再画

而为什么会一条线呢,因为背景没刷,之前画出来的圆还在那

所以我们用虚拟图片的画笔画出一个方框出来代替之前的背景

@Override
public void update(Graphics g){
    if(offScreenImage == null){
        //若为null,则创建一张图片
        offScreenImage = this.createImage(800,600);
    }
    //获取到虚拟图片的画笔
    Graphics gOffScreen = offScreenImage.getGraphics();
    //默认黑色,所以需要与效果背景一致获取原色
    Color c = gOffScreen.getColor();
    gOffScreen.setColor(Color.green);//与原背景色一致
    //使用画笔画出一个实现的方框代替原画的背景效果
    gOffScreen.fillRect(0,0,800,600);
    gOffScreen.setColor(c);//设置原回来
    //使用虚拟图片的画笔画圆
    paint(gOffScreen);
    //将虚拟图片画下来
    g.drawImage(offScreenImage,0,0,null);
}

这时再运行就即可

四、使用常量代替固定的尺寸值

由于我们的虚拟图片、框框、以及一些尺寸大小都是固定的值,当需要修改变化的时候,若只有几个地方,那还比较容易改动

若有几百个地方、几千个地方,这就改动的很繁琐并且很杂乱

public class TankClient extends Frame {

    public static final int GAME_WINDTH = 800;//宽度常量

    public static final int GAME_HEIGHT = 600;//高度常量
    
    @Override
    public void update(Graphics g){
        if(offScreenImage == null){
            //若为null,则创建一张图片
            offScreenImage = this.createImage(GAME_WINDTH,GAME_HEIGHT);
        }
        //省略其他关键性代码......
    }
    //定义窗口方法
    public void lauchFrame() {
        //设置窗口出现的位置
        this.setLocation(400, 300);
        //设置窗口的宽度高度
        this.setSize(GAME_WINDTH, GAME_HEIGHT);
        //省略其他关键性代码......
    }
}

✧将以后可能需要多处改变的量定义为常量

✧Frame的宽度和高度

✧常量名一般大写

参考资料


尚学堂:坦克大战(马士兵老师)

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值