绘图(一)弹球小游戏

news2025/1/13 13:58:31

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);
            }

        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1016799.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C语言进阶指针(3) ——qsort的实现

大家好&#xff0c;我们今天来学习回调函数qsort的实现。 首先让我们打开cplusplus.com找到qsort函数。 我们看到这个函数就可以看到它的头文件和参数信息。 #include<stdlib.h> void qsort (void* base, size_t num, size_t size, int (*compar)(const void*,const voi…

前后端跨域请求问题解决方法

如图&#xff1a; 1.在config配置包中创建一个CorsConfig配置类 2.将下面代码复制到这个类中即可 import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.cors.CorsConfigurati…

[字符串和内存函数]strcmp和strncmp以及memcmp的区别

CPlus中对strcmp的介绍 #include <stdio.h> #include <string.h>int main () {char key[] "apple";char buffer[80];do {printf ("Guess my favorite fruit? ");fflush (stdout);scanf ("%79s",buffer);} while (strcmp (key,buf…

MySQL 约束与复杂查询

当涉及到数据库管理系统&#xff08;DBMS&#xff09;的高级主题时&#xff0c;包括数据库的约束、表的设计以及各种类型的查询&#xff0c;特别是聚合查询、联合查询和合并查询&#xff0c;是非常重要的。这些主题可以帮助我们更好地理解数据库的内部工作机制以及如何有效地操…

[maven] 创建 spring boot 项目及使用 Jenkins 运行 maven

[maven] 创建 spring boot 项目及使用 Jenkins 运行 maven 本篇笔记走一下用 maven 创建 spring boot 项目和利用 Jenkins 管理 maven 流程 使用 maven 创建 spring boot 项目 根据官方文档说&#xff0c;现在使用 boot 需要 java 17&#xff0c;Gradle 7.5/Maven 3.5 spri…

idea无法通过vpn 连接到数据库或者kafka

本地navicate 等sql客户端 &#xff0c;通过vpn&#xff0c;可以连接到数据库&#xff0c;&#xff0c;xshell也可以通过vpn连接到远程机器&#xff0c;但是&#xff0c;idea开发时&#xff0c;报连接超时错误&#xff0c;解决方法&#xff1a; 项目中 VM这一栏加上-Djava.net…

区块链:去中心化革命下的创新与发展!

区块链作为一项重要的技术实验&#xff0c;确实具有重大的影响力。它代表了一场去中心化的运动&#xff0c;吸引了许多研究人员、工程师、建设者和用户的参与&#xff0c;创造了我们目前所见到的一些最有趣的技术。 区块链的透明特性赋予了用户对于数据和交易的控制权&#xff…

来看看Python __all__变量的用法

​ 事实上&#xff0c;当我们向文件导入某个模块时&#xff0c;导入的是该模块中那些名称不以下划线&#xff08;单下划线“_”或者双下划线“__”&#xff09;开头的变量、函数和类。因此&#xff0c;如果我们不想模块文件中的某个成员被引入到其它文件中使用&#xff0c;可以…

展示日志log4.properties

log4.properties 1.log4.properties 此时文件主要用于展示日志的输出的级别的信息。 # Set root category priority to INFO and its only appender to CONSOLE. #log4j.rootCategoryINFO, CONSOLE debug info warn error fatal log4j.rootCategoryinfo, CONSO…

本地事务与分布式事务

目录 一、本地事务 1、事务的基本性质 2、事务的隔离级别 3、事务的传播行为 4、SpringBoot 事务关键点 二、分布式事务 1、为什么有分布式事务 2、CAP 定理与 BASE 理论 3、分布式事务几种方案 一、本地事务 1、事务的基本性质 数据库事务的几个特性&#xff1a;原…

PhpStorm 2023年下载、安装教程和好用插件,保姆级教程

PhpStorm 2023年下载、安装教程和好用插件&#xff0c;保姆级教程 文章目录 PhpStorm 2023年下载、安装教程和好用插件&#xff0c;保姆级教程前言一、安装PhpStorm二、好用的插件简体中文包Chinese(Simplified)Language Pack 三、卸载插件CTRLN 查找类CTRLSHIFTN 全局搜索文件…

Scala编程语言

Scala编程语言 一、Scala引入1、学习Scala的目的2、Scala的基本概念 二、Scala环境搭建1、安装步骤2、配置环境变量3、测试Scala4、Scala与idea的集成5、关联源码6、 class 和 object 说明 三、常用语法、变量和数据类型1、 注释2、变量和常量3 、标识符的命名规范4、字符串输出…

一阶低通滤波器滞后补偿算法

一阶低通滤波器的推导过程和双线性变换算法请查看下面文章链接: PLC算法系列之数字低通滤波器(离散化方法:双线性变换)_双线性离散化_RXXW_Dor的博客-CSDN博客PLC信号处理系列之一阶低通(RC)滤波器算法_RXXW_Dor的博客-CSDN博客_rc滤波电路的优缺点1、先看看RC滤波的优缺点…

matlab EL image绘制

利用光谱仪测试的结果可以得到image&#xff0c;输出为csv文件&#xff0c;包括640X512的矩阵&#xff0c;这个矩阵将会反映器件发光的位置和强度&#xff0c;算是一个灰度图。 在matlab中&#xff0c;可以用imagesc函数来进行绘图。 imagesc函数的用法 clear; clc; close a…

Linux从root账号切换到普通账号并执行shell脚本

背景&#xff1a;最近自己在用的中间件只能运行在 普通账号下&#xff0c;现在每次重启之后都要切换到 普通账号 然后去执行启动脚本。一次两次还能接受……反正现在接受不了了…… 写一个脚本让它帮我起吧 先贴目录 新建文件 start_es.sh, 用于root账号下调用 #!/bin/bash e…

计算机组成原理——基础入门总结(一)

本帖更新一些关于计算机组成原理的重点内容。由于博主考研时并不会考这门课&#xff0c;但是考虑到操作系统中又很多重要晦涩的概念涉及很多诸如内存、存储器、磁盘、cpu乃至各种寄存器的知识&#xff0c;此处挑选一些核心的内容总结复盘一遍——实现声明&#xff1a;本帖的内容…

【CCF】第30次csp认证——202305-1重复局面

202305-1重复局面&#xff1a; 问题描述 国际象棋每一个局面可以用大小为 88 的字符数组来表示&#xff0c;其中每一位对应棋盘上的一个格子。六种棋子王、后、车、象、马、兵分别用字母 k、q、r、b、n、p 表示&#xff0c;其中大写字母对应白方、小写字母对应黑方。棋盘上无…

[ESP32 IDF+Vscode]蓝牙配网后采用上传温湿度数据至阿里云(MQTT协议)

阿里云平台的设置 参考文章&#xff1a; http://t.csdn.cn/RzLGqhttp://t.csdn.cn/RzLGq Blufi配网 1.简介 BluFi 是一款基于蓝牙通道的 Wi-Fi 网络配置功能&#xff0c;适用于 ESP32。它通过安全协议将 Wi-Fi 配置和证书传输到 ESP32&#xff0c;然后 ESP32 可基于这些信…

OpenGL超级宝典(第五版)疑难点汇总解析

《OpenGL超级宝典(第五版&#xff09;》如下&#xff1a; 1. 在该书的第1章的Block例子中用到了平面阴影投射矩阵&#xff0c;关于该矩阵的推导&#xff0c;参见&#xff1a; OpenGL: 平面阴影投射矩阵的推导 2. 在该书的第8章的pix_buffs例子中用到了正交投影矩阵的推导过程…

腾讯mini项目-【指标监控服务重构】2023-08-23

今日已办 进度和问题汇总 请求合并 feature/venus tracefeature/venus metricfeature/profile-otel-baserunner-stylebugfix/profile-logger-Syncfeature/profile_otelclient_enable_config 完成otel 开关 trace-采样metrice-reader 已经都在各自服务器运行&#xff0c;并接入…