• 绘图(一)弹球小游戏


    AWT编程 · 语雀

    仓库Java图形化界面: Java图形化界面学习demo与资料 (gitee.com)

    很多程序如各种小游戏都需要在窗口中绘制各种图形,除此之外,即使在开发JavaEE项目时, 有 时候也必须"动态"地向客户 端生成各种图形、图表,比如 图形验证码、统计图等,这都需要利用AWT的绘图功能。

    组件绘图原理

    之前我们已经学习过很多组件,例如Button、Frame、Checkbox等等,不同的组件,展示出来的图形都不一样,其实这些组件展示出来的图形,其本质就是用AWT的绘图来完成的。

    在AWT中,真正提供绘图功能的是Graphics对象,那么Component组件和Graphics对象存在什么关系,才能让Component绘制自身图形呢?在Component类中,提供了下列三个方法来完成组件图形的绘制与刷新:

    paint(Graphics g):绘制组件的外观;

    update(Graphics g):内部调用paint方法,刷新组件外观;

    repaint():调用update方法,刷新组件外观;

    一般情况下,update和paint方法是由AWT系统负责调用,如果程序要希望系统重新绘制组件,可以调用repaint方法完成。

    Graphics类的使用

    实际生活中如果需要画图,首先我们得准备一张纸,然后在拿一支画笔,配和一些颜色,就可以在纸上画出来各种各样的图形,例如圆圈、矩形等等。

    程序中绘图也一样,也需要画布,画笔,颜料等等。AWT中提供了Canvas类充当画布,提供了Graphics类来充当画笔,通过调用Graphics对象的setColor()方法可以给画笔设置颜色。

    画图的步骤:

    1.自定义类,继承Canvas类,重写paint(Graphics g)方法完成画图;

    2.在paint方法内部,真正开始画图之前调用Graphics对象的setColor()、setFont()等方法设置画笔的颜色、字体等属性;

    3.调用Graphics画笔的drawXxx()方法开始画图。

    其实画图的核心就在于使用Graphics画笔在Canvas画布上画出什么颜色、什么样式的图形,所以核心在画笔上,下表中列出了Graphics类中常用的一些方法:

    案例:

    使用AWT绘图API,完成下图效果

    演示代码:

    1. import java.awt.*;
    2. import java.awt.event.ActionEvent;
    3. import java.awt.event.ActionListener;
    4. import java.util.Random;
    5. public class SimpleDraw {
    6. private final String RECT_SHAPE="rect";
    7. private final String OVAL_SHAPE="oval";
    8. private Frame frame = new Frame("这里测试绘图");
    9. private Button drawRectBtn = new Button("绘制矩形");
    10. private Button drawOvalBtn = new Button("绘制椭圆");
    11. //用来保存当前用户需要绘制什么样的图形
    12. private String shape="";
    13. private MyCanvas drawArea = new MyCanvas();
    14. public void init(){
    15. //为按钮添加点击事件
    16. drawRectBtn.addActionListener(new ActionListener() {
    17. @Override
    18. public void actionPerformed(ActionEvent e) {
    19. shape = RECT_SHAPE;
    20. drawArea.repaint();
    21. }
    22. });
    23. drawOvalBtn.addActionListener(new ActionListener() {
    24. @Override
    25. public void actionPerformed(ActionEvent e) {
    26. shape = OVAL_SHAPE;
    27. drawArea.repaint();
    28. }
    29. });
    30. //定义一个Panel,装载两个按钮
    31. Panel p = new Panel();
    32. p.add(drawRectBtn);
    33. p.add(drawOvalBtn);
    34. //把panel添加到frame底部
    35. frame.add(p,BorderLayout.SOUTH);
    36. //设置画布的大小
    37. drawArea.setPreferredSize(new Dimension(300,200));
    38. //把画布添加到frame中
    39. frame.add(drawArea);
    40. frame.pack();
    41. frame.setVisible(true);
    42. }
    43. public static void main(String[] args) {
    44. new SimpleDraw().init();
    45. }
    46. //1.自定义类,继承Canvas类,重写paint方法
    47. private class MyCanvas extends Canvas{
    48. @Override
    49. public void paint(Graphics g) {
    50. Random r = new Random();
    51. if (shape.equals(RECT_SHAPE)){
    52. //绘制矩形
    53. g.setColor(Color.BLACK);
    54. g.drawRect(r.nextInt(200),r.nextInt(100),40,60);
    55. }
    56. if(shape.equals(OVAL_SHAPE)){
    57. //绘制椭圆
    58. g.setColor(Color.RED);
    59. g.drawOval(r.nextInt(200),r.nextInt(100),60,40);
    60. }
    61. }
    62. }
    63. }

    Java也可用于开发一些动画。所谓动画,就是间隔一定的时间(通常小于0 . 1秒 )重新绘制新的图像,两次绘制的图像之间差异较小,肉眼看起来就成了所谓的动画 。

    为了实现间隔一定的时间就重新调用组件的 repaint()方法,可以借助于 Swing 提供的Timer类,Timer类是一个定时器, 它有如下一个构造器 :Timer(int delay, ActionListener listener): 每间隔 delay 毫秒,系统自动触发 ActionListener 监听器里的事件处理器方法,在方法内部我们就可以调用组件的repaint方法,完成组件重绘。

    案例2:

    使用AWT画图技术及Timer定时器,完成下图中弹球小游戏。

    演示代码2:

    1. package awt_swimg.day03;
    2. import awt_swimg.day01.Utils;
    3. import javax.swing.*;
    4. import java.awt.*;
    5. import java.awt.event.*;
    6. public class PinBall {
    7. //桌面宽度
    8. private final int TABLE_WIDTH = 300;
    9. //桌面高度
    10. private final int TABLE_HEIGHT = 400;
    11. //球拍的高度和宽度
    12. private final int RACKET_WIDTH = 60;
    13. private final int RACKET_HEIGHT = 20;
    14. //小球的大小
    15. private final int BALL_SIZE = 16;
    16. //定义小球纵向运行速度
    17. private int ySpeed = 10;
    18. //小球横向运行速度
    19. private int xSpeed = 5;
    20. //定义小球的初始坐标
    21. private int ballX = 120;
    22. private int ballY = 20;
    23. //定义球拍的初始坐标,x坐标会发生变化,y坐标不会发生变化
    24. private int RACKET_X = 120;
    25. private final int RACKET_Y = 340;
    26. //声明定时器
    27. private Timer timer;
    28. private JFrame frame=new JFrame("弹球游戏");
    29. private MyCanvas canvas=new MyCanvas();
    30. //定义游戏结束的标记
    31. private boolean isLose = false;
    32. private KeyListener event = new KeyAdapter() {
    33. @Override
    34. public void keyPressed(KeyEvent e) {
    35. int keyCode = e.getKeyCode();
    36. if (keyCode == KeyEvent.VK_LEFT) {
    37. if (RACKET_X > 0) {
    38. RACKET_X -= 10;
    39. }
    40. }
    41. if (keyCode == KeyEvent.VK_RIGHT) {
    42. if (RACKET_X < TABLE_WIDTH - RACKET_WIDTH) {
    43. RACKET_X += 10;
    44. }
    45. }
    46. }
    47. };
    48. private ActionListener timerTask=new ActionListener() {
    49. @Override
    50. public void actionPerformed(ActionEvent e) {
    51. if (ballX<=0||ballX>=TABLE_WIDTH-BALL_SIZE) {
    52. xSpeed=-xSpeed;
    53. }
    54. if (ballY<=0||ballY>=RACKET_Y-BALL_SIZE&&ballX>= RACKET_X &&ballX<= RACKET_X +RACKET_WIDTH) {
    55. ySpeed = -ySpeed;
    56. }
    57. if (ballY>RACKET_Y&&(ballXRACKET_X+RACKET_WIDTH)) {
    58. timer.stop();
    59. isLose=true;
    60. canvas.repaint();
    61. }
    62. ballX += xSpeed;
    63. ballY += ySpeed;
    64. canvas.repaint();
    65. }
    66. };
    67. private MenuBar menuBar=new MenuBar();
    68. private Menu option=new Menu("选项");
    69. private MenuItem reStart=new MenuItem("重新开始");
    70. private MenuItem exit=new MenuItem("退出");
    71. public void init(){
    72. frame.add(canvas);
    73. frame.setMenuBar(menuBar);
    74. menuBar.add(option);
    75. option.add(reStart);
    76. option.add(exit);
    77. exit.addActionListener(e -> System.exit(0));
    78. reStart.addActionListener(e -> {
    79. isLose=false;
    80. ballX = 120;
    81. ballY = 20;
    82. RACKET_X = 120;
    83. canvas.repaint();
    84. timer.start();
    85. });
    86. canvas.setPreferredSize(new Dimension(TABLE_WIDTH,TABLE_HEIGHT));
    87. canvas.addKeyListener(event);
    88. frame.addKeyListener(event);
    89. timer=new Timer(50,timerTask);
    90. timer.start();
    91. Utils.setJFrame(frame);
    92. }
    93. public static void main(String[] args) {
    94. new PinBall().init();
    95. }
    96. public class MyCanvas extends Canvas{
    97. @Override
    98. public void paint(Graphics g) {
    99. if (isLose) {
    100. g.setColor(Color.BLUE);
    101. g.setFont(new Font("Times",Font.BOLD,30));
    102. g.drawString("游戏结束!",80,200);
    103. }else{
    104. g.setColor(Color.red);
    105. g.fillOval(ballX, ballY, BALL_SIZE, BALL_SIZE);
    106. g.setColor(Color.green);
    107. g.fillRect(RACKET_X, RACKET_Y, RACKET_WIDTH, RACKET_HEIGHT);
    108. }
    109. }
    110. }
    111. }

  • 相关阅读:
    滴滴可观测平台 Metrics 指标实时计算如何实现了又准又省?
    css解决uniapp使用image标签图片无法撑满全屏问题
    Hadoop+Hive数据分析综合案例
    AS/NZS 1859.3:2017 木基装饰板检测
    【算法】一类支持向量机OC-SVM(2)
    PC_输入输出系统/设备_I/O系统(IO接口)基础
    BathchData数据分批处理
    JDK21中虚拟线程到底是什么?看完便知
    数据库及ADO.NET学习(三)
    go 反射
  • 原文地址:https://blog.csdn.net/m0_73843666/article/details/132845633