绘图(一)弹球小游戏

2023-09-13 09:36:01

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,完成下图效果

演示代码:

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;

public class SimpleDraw {

    private final String RECT_SHAPE="rect";
    private final String OVAL_SHAPE="oval";

    private Frame frame = new Frame("这里测试绘图");

    private Button drawRectBtn = new Button("绘制矩形");
    private Button drawOvalBtn = new Button("绘制椭圆");

    //用来保存当前用户需要绘制什么样的图形
    private String shape="";

    private MyCanvas drawArea = new MyCanvas();




    public void init(){

        //为按钮添加点击事件
        drawRectBtn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                shape = RECT_SHAPE;
                drawArea.repaint();
            }
        });

        drawOvalBtn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                shape = OVAL_SHAPE;
                drawArea.repaint();
            }
        });

        //定义一个Panel,装载两个按钮
        Panel p = new Panel();
        p.add(drawRectBtn);
        p.add(drawOvalBtn);

        //把panel添加到frame底部
        frame.add(p,BorderLayout.SOUTH);

        //设置画布的大小
        drawArea.setPreferredSize(new Dimension(300,200));
        //把画布添加到frame中

        frame.add(drawArea);

        frame.pack();
        frame.setVisible(true);


    }

    public static void main(String[] args) {
        new SimpleDraw().init();
    }


    //1.自定义类,继承Canvas类,重写paint方法

    private class MyCanvas extends Canvas{
        @Override
        public void paint(Graphics g) {
            Random r = new Random();

            if (shape.equals(RECT_SHAPE)){
                //绘制矩形
                g.setColor(Color.BLACK);
                g.drawRect(r.nextInt(200),r.nextInt(100),40,60);
            }

            if(shape.equals(OVAL_SHAPE)){
                //绘制椭圆
                g.setColor(Color.RED);
                g.drawOval(r.nextInt(200),r.nextInt(100),60,40);
            }

        }
    }
}

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

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

案例2:

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

演示代码2:

package awt_swimg.day03;

import awt_swimg.day01.Utils;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class PinBall {
    //桌面宽度
    private final int TABLE_WIDTH = 300;
    //桌面高度
    private final int TABLE_HEIGHT = 400;


    //球拍的高度和宽度
    private final int RACKET_WIDTH = 60;
    private final int RACKET_HEIGHT = 20;

    //小球的大小
    private final int BALL_SIZE = 16;

    //定义小球纵向运行速度
    private int ySpeed = 10;
    //小球横向运行速度
    private int xSpeed = 5;

    //定义小球的初始坐标
    private int ballX = 120;
    private int ballY = 20;

    //定义球拍的初始坐标,x坐标会发生变化,y坐标不会发生变化
    private int RACKET_X = 120;
    private final int RACKET_Y = 340;

    //声明定时器
    private Timer timer;
    private JFrame frame=new JFrame("弹球游戏");
    private MyCanvas canvas=new MyCanvas();
    //定义游戏结束的标记
    private boolean isLose = false;

    private KeyListener event = new KeyAdapter() {
        @Override
        public void keyPressed(KeyEvent e) {
            int keyCode = e.getKeyCode();
            if (keyCode == KeyEvent.VK_LEFT) {
                if (RACKET_X > 0) {
                    RACKET_X -= 10;
                }
            }
            if (keyCode == KeyEvent.VK_RIGHT) {
                if (RACKET_X < TABLE_WIDTH - RACKET_WIDTH) {
                    RACKET_X += 10;
                }
            }
        }
    };
    private ActionListener timerTask=new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            if (ballX<=0||ballX>=TABLE_WIDTH-BALL_SIZE) {
                xSpeed=-xSpeed;
            }
            if (ballY<=0||ballY>=RACKET_Y-BALL_SIZE&&ballX>= RACKET_X &&ballX<= RACKET_X +RACKET_WIDTH) {
                ySpeed = -ySpeed;
            }
            if (ballY>RACKET_Y&&(ballX<RACKET_X||ballX>RACKET_X+RACKET_WIDTH)) {
                timer.stop();
                isLose=true;
                canvas.repaint();
            }

            ballX += xSpeed;
            ballY += ySpeed;
            canvas.repaint();
        }
    };

    private MenuBar menuBar=new MenuBar();
    private Menu option=new Menu("选项");
    private MenuItem reStart=new MenuItem("重新开始");
    private MenuItem exit=new MenuItem("退出");
    public void init(){
        frame.add(canvas);
        frame.setMenuBar(menuBar);
        menuBar.add(option);
        option.add(reStart);
        option.add(exit);
        exit.addActionListener(e -> System.exit(0));
        reStart.addActionListener(e -> {
            isLose=false;
            ballX = 120;
            ballY = 20;
            RACKET_X = 120;
            canvas.repaint();
            timer.start();
        });
        canvas.setPreferredSize(new Dimension(TABLE_WIDTH,TABLE_HEIGHT));

        canvas.addKeyListener(event);
        frame.addKeyListener(event);
        timer=new Timer(50,timerTask);
        timer.start();

        Utils.setJFrame(frame);
    }

    public static void main(String[] args) {
        new PinBall().init();
    }
    public class MyCanvas extends Canvas{
        @Override
        public void paint(Graphics g) {
            if (isLose) {
                g.setColor(Color.BLUE);
                g.setFont(new Font("Times",Font.BOLD,30));
                g.drawString("游戏结束!",80,200);
            }else{
                g.setColor(Color.red);
                g.fillOval(ballX, ballY, BALL_SIZE, BALL_SIZE);
                g.setColor(Color.green);
                g.fillRect(RACKET_X, RACKET_Y, RACKET_WIDTH, RACKET_HEIGHT);
            }

        }
    }
}

更多推荐

讲解socket 网络编程的 5 大隐患

1.忽略返回状态第一个隐患很明显,但它是开发新手最容易犯的一个错误。如果您忽略函数的返回状态,当它们失败或部分成功的时候,您也许会迷失。反过来,这可能传播错误,使定位问题的源头变得困难。捕获并检查每一个返回状态,而不是忽略它们。考虑清单1显示的例子,一个套接字send函数。清单1.忽略API函数返回状态intstatu

【C#】FileInfo类 对文件进行操作

提示:使用FileInfo类时,要引用System.IO命名空间。usingSystem.IO;FileInfo类生成文件删除文件移动文件复制文件获取文件名判断文件是否存在属性列表其它常用方法生成文件Create():在指定路径上创建文件。FileInfomyFile=newFileInfo(@"E:\vsspace\

VUE路由与nodeJS环境搭建

VUE路由Vue路由是Vue.js提供的路由管理工具,它允许我们在应用程序中实现页面之间的导航,从而使单页面应用程序的开发更加方便。通过Vue路由,我们可以轻松地创建和管理多个视图,并在这些视图之间导航。Vue路由使用HTML5的HistoryAPI来实现无刷新页面的切换效果,同时还提供了很多高级特性,例如路由嵌套、路

PWA建快应用,小程序建超级App?

小程序在特定的平台生态系统中崭露头角,为开发者提供了更深度的集成和用户接触点。通过应用商店的分发和推广机制,小程序能够迅速扩大用户基础,为企业和品牌提供了直接触达用户的机会。尤其是在社交媒体平台上,小程序的分享和使用已成为用户互动和交流的一种重要方式。PWA代表“渐进式网络应用”(ProgressiveWebAppli

MySQL常考知识点

MySQL常考知识点索引的基本原理索引设计的原则事务的基本特性和隔离级别什么是MVCC简述MyISAM和InnoDB的区别Explain语句结果中各个字段分表表示什么索引覆盖是什么最左前缀原则是什么B树和B+树的区别,为什么Mysql使⽤B+树Mysql锁有哪些,如何理解Mysql慢查询该如何优化?索引的基本原理索引⽤

blender怎么设置中文界面

你们知道Blender软件是什么吗?你知道blender怎么设置中文界面吗?Blender是个GNU的3D绘图软件,建模、算图、动画等功能都相当的完整,可以说已经具有了一般商业软件的规模。Blender大部分的功能都有热键,操作起来相当地轻快;而由于几乎所有的功能按钮鼠标移上去一段时间都会出现详细说明,也多少弥补了操作

Blender Morph Targets

推荐:用NSDT编辑器快速搭建可编程3D场景在Blender中,MorphTarget被称为ShapeKey,即形状键,是将网格从一种形状变形为另一种形状的工具。每个对象都被分配了一个基本形状,然后可以有许多可以变形的形状键。形状键通常用于面部动画和肌肉,但在动画中也有很多用途。本文包含了你需要了解的有关Blender

基于协同过滤算法的旅游推荐系统

博主主页:猫头鹰源码博主简介:Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万+、专注Java技术领域和毕业设计项目实战主要内容:毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询文末联系获取项目介绍:该系统基于springboot技术,数据层为MyBatis,mysql

python-爬虫-requests

安装模块pipinstallrequests在jupyternotebook里使用Shift+Tab查看requestsrequests库的主要方法方法解释requests.requset()构造一个请求,支持以下各种方法requests.get()获取HTML的主要方法requests.head()获取HTML头部信

ffmpeg 特效 转场 放大缩小

案例ffmpeg\-iinput.mp4\-iimage1.png\-iimage2.png\-filter_complex\[1:v]scale=100:100[img1];\[2:v]scale=1280:720[img2];\[0:v][img1]overlay=(main_w-overlay_w)/2:(mai

A Span-based Multi-Modal Attention Network for joint entity-relationextraction

原文链接:https://www.sciencedirect.com/science/article/pii/S0950705122013247?via%3DihubKnowledge-BasedSystems2023介绍作者认为当前基于span的关系提取方法都太关注于span内部的语义,忽略了span与span之间以

热文推荐