awt绘图_弹球小游戏
原理:小球和球拍不断重绘repain,重绘的频次足够高就变成了动画。标准来说就是间隔一定的时间就不断重新调用组件的repain方法
Java也可以用来开发一些动画。所谓动画,就是间隔一定的时间(通常小于0.1秒)重新绘制的图形,两次绘制的图像之间差异比较小,肉眼看起来就成为所谓的动画
为了实现间隔一定的时间就不断重新调用组件的repain方法,可以借助Swing提供的Timer类,Timer类是一个定时器,它有如下一个构造器:
Timer(int delay,ActionListener):每间隔delay毫秒,系统自动触发ActionLinster监听器的事件处理器的方法,在方法内部我们就可以调用组件的repaint方法,完成组件重新绘制
xxxxxxxxxxpackage ch29;import javax.swing.*;import java.awt.*;import java.awt.event.*;
public class a_7_2awt_绘图_弹球小游戏 {
private Frame frame = new Frame("弹球游戏");
//注意下面的几个被Final修饰的成员变量是常量,不是变量
//设置桌面宽度 private final int TABLE_WIDTH = 300;//中间画布,即小球的活动窗口的宽度 //设置桌面高度 private final int TABLE_HEIGHT = 400;//中间画布,即小球的活动窗口的高度
//球拍的高度和宽度 private final int RACKET_WIDTH = 100;//球拍是矩形的,即定义了底部移动的球拍的宽度 private final int RACKET_HEIGHT = 10;//球拍是矩形的,即定义了底部移动的球拍的高度
//小球的大小 private final int BALL_SIZE = 16;//小球的直径是16px
//定义变量,记录小球的坐标。注意0,0的点是在整个Frame视图的左上角。坐标的单位是像素 private int ballX = 120; private int ballY = 20; //x和y就能形成一个坐标,即是小球的初始位置。后续会由这两个变量来记录小球的新位置
//定义变量,记录小球在x和y方向上分别移动的速度 private int speedY = 10;//每次移动10px private int speedX = 5;//每次移动5px //小球在x方向和y方向的和速度就是小球的移动速度
//定义变量,记录球拍的坐标 private int racketX = 120; private final int racketY = 340;//注意这个变量是被Final修饰的,即表示是常量,常量是不可改变的,也就是球拍只能左右移动不能上下移动 //x和y就能形成一个坐标,即是球拍的初始位置。后续会由这两个变量来记录球拍的新位置
//定义变量,标识当前游戏是否已结束 private boolean isOver = false;//默认是未结束的,即默认是可以玩的
//声明一个定时器 private Timer timer;
//小球和球拍是在画布上的。如何定义画布,即自定义一个类,继承canvas,就可以有画布了 private class Mycanvas extends Canvas { //记得重写paint public void paint(Graphics g) {//重写paint方法,作用是在画布里面绘制内容 //TODO 在这里绘制内容 if (isOver) { //游戏结束的内容 g.setColor(Color.RED);//设置字体颜色为红色 g.setFont(new Font("Times", Font.BOLD, 30));//标题,字体、字号 g.drawString("游戏结束!", 75, 200); } else { //游戏进行的内容
//绘制小球 g.setColor(Color.BLUE);//小球的填充颜色 g.fillOval(ballX, ballY, BALL_SIZE, BALL_SIZE); //标、绘制球拍 g.setColor(Color.PINK); g.fillRect(racketX, racketY, RACKET_WIDTH, RACKET_HEIGHT);//x坐标、y坐、宽、高 } } }
//创建我们上面自定义类的对象,作用是创建绘画区域 Mycanvas drawArea = new Mycanvas();
//组件组装方法 public void init() { //组装视图,以及游戏逻辑的控制 //1、球拍的控制逻辑 //2、小球的控制逻辑
//完成球拍坐标的变化,包含创建监听器、按键事件、键盘事件 KeyListener listener = new KeyAdapter() { public void keyPressed(KeyEvent e) {
//获取当前按下的键 int keyCode = e.getKeyCode();//我们的键盘每一个键位都对应一个整数keycode
if (keyCode == KeyEvent.VK_LEFT) {//VK_LEFT是左箭头
//应该向左移动 if (racketX > 0) {//大于0,即当向左移动时,不能移除到左边框外 racketX -= 30; } } if (keyCode == KeyEvent.VK_RIGHT) {//VK_RIGHT是右箭头
//应该向右移动 if (racketX < (TABLE_WIDTH - RACKET_WIDTH)) {//左移的距离<桌面宽减球拍宽。即当向右移动时,不能移除到右边框外 racketX += 30; } }
} };
//给frame和drawArea注册监听器 frame.addKeyListener(listener); drawArea.addKeyListener(listener);
//小球坐标的控制 ActionListener task = new ActionListener() { //更新小球的坐标,重绘界面 public void actionPerformed(ActionEvent e) {
//根据边界范围,修正速度 //----->修正x轴弹出碰到边界的方向 if (ballX <= 0 || ballX >= (TABLE_WIDTH - BALL_SIZE)) {//如果球的x位置超出左边框|超出有边框,就反方向运动 speedX = -speedX;//x方向上做反方向运动 } //----->修正y轴弹出碰到边界的方向。当y速度超出上边框|球y位置大于球拍y位置&&球的x位置大于球拍的x位置&&球的x位置小于球拍 if (ballY <= 0 || ballY > racketY - BALL_SIZE && ballX > racketX && ballX < racketX + RACKET_WIDTH) { speedY = -speedY; } //当前小球超出了球拍范围。游戏结束 if (ballY > racketY - BALL_SIZE && (ballX < racketX || ballX > racketX + RACKET_WIDTH)) {
//停止定时器 timer.stop(); //修改游戏是否结束标记 isOver = true;//游戏结束的标记 //重新绘制界面 drawArea.repaint(); }
ballX += speedX; ballY += speedY;
//重新绘制界面 drawArea.repaint();
} };
//这里需要手动导包import javax.swing.Timer.*; timer = new Timer(80,task);//多少毫秒执行一次task,task是小球坐标的控制 timer.start();//启动定时器
drawArea.setPreferredSize(new Dimension(TABLE_WIDTH, TABLE_HEIGHT));//给画布设置一个大小 frame.add(drawArea);//将画布添加到Frame容器里面
//frame窗口关闭 frame.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); //frame最佳大小 frame.pack(); frame.setVisible(true); }
public static void main(String[] args) { new a_7_2awt_绘图_弹球小游戏().init(); }
}