最近新学了图形界面,写了一个弹球游戏,拿出来让大家指正。

  1 package org.xn.chapter11.practice;
  2
  3 /**
  4  * 课后习题2:做一个弹球游戏,在书中程序的基础上将所有的组件换成图片显得更美观和实用
  5  * 程序分解:
  6  * 1、图形界面:
  7  *         球桌、弹球、球杆、障碍物
  8  * 2、动画核心:
  9  *         定时器,每隔100ms绘制一次图形
 10  *         JPanel组件,这里要使用JPanel而不是Canvas,因为使用Canvas会产生闪烁
 11  *         键盘监听类,用于左右键来控制球杆的运动
 12  *         JPanel组件的监听类,用于检测小球是否碰壁或者是否游戏结束
 13  * 3、扩展
 14  *         自己新增了一个计数器,一个玩家可以有3条命,用完了游戏结束
 15  * 4、已知bug:
 16  *         a、在某些地方会出现无法反弹的问题
 17  *         b、每损失一条命,小球的速度会越来越快
 18  *
 19  * 5、联系方式:
 20  *         QQ:1037784758
 21  *
 22  * 6、最后一次修改日期:
 23  *         2015.7.20
 24  * */
 25
 26 import java.awt.Color;
 27 import java.awt.Dimension;
 28 import java.awt.Font;
 29 import java.awt.Graphics;
 30 import java.awt.event.ActionEvent;
 31 import java.awt.event.ActionListener;
 32 import java.awt.event.KeyAdapter;
 33 import java.awt.event.KeyEvent;
 34 import java.awt.event.WindowAdapter;
 35 import java.awt.event.WindowEvent;
 36 import java.awt.image.BufferedImage;
 37 import java.io.File;
 38 import java.util.Random;
 39
 40 import javax.imageio.ImageIO;
 41 import javax.swing.JFrame;
 42 import javax.swing.JPanel;
 43 import javax.swing.Timer;
 44
 45 public class PinBallImage {
 46     //定义球桌的尺寸
 47     private final int TABLE_WIDTH = 400;//桌面宽度
 48     private final int TABLE_HEIGHT = 600;//桌面高度
 49     //定义球拍的尺寸(此处是图片的尺寸),是为了后面的判断小球是否出界时使用
 50     private final int RACKET_WIDTH = 200;
 51     private final int RACKET_HEIGHT = 30;
 52     //定义小球的尺寸(此处是图片的尺寸),是为了后面的判断小球是否出界时使用
 53     private final int BALL_SIZE = 32;
 54     //定义障碍物的尺寸(此处是图片的尺寸),是为了后面的判断小球是否碰壁时使用
 55     private final int BLOCK_WIDTH = 50;
 56     private final int BLOCK_HEIGHT = 30;
 57     //定义1个障碍物的位置,这里我们将障碍物固定不动,时间有限没有定义更多的障碍物
 58     private final int blockX = 200;
 59     private final int blockY = 200;
 60     //定义一个剩余生命值图片的位置
 61     private final int lifeX = 50;
 62     private final int lifeY = 50;
 63     //定义剩余的生命值,初始值为3
 64     private int lifeNum = 3;
 65
 66     //定义一个随机数
 67     Random rand = new Random();
 68     //定义小球的x轴和y轴的速度,其中y轴速度值是固定的,
 69     //x轴的速度值是在y轴的基础之上乘以一个随机的比率得来,这个比率必须是在正负之间
 70     //小球会固定一个方向弹走,
 71     private double xyRate = rand.nextDouble()-0.5;
 72     private int speedY = 10;
 73     private int speedX = (int)(speedY*xyRate*2);
 74     //定义小球和球拍的位置为随机
 75     private int ballX = rand.nextInt(200)+20;//小球的x坐标(20~~220)
 76     private int ballY = rand.nextInt(10)+20;//小球的y坐标(20~~30)
 77     private int racketX = rand.nextInt(200);//代表球拍的水平位置
 78     private int RACKET_Y = 500;//球拍的垂直位置是不变的
 79
 80     //---------------------------------------------------------
 81     /**
 82      * 为游戏增加如下的新特性:将小球、球拍、球桌由图形换成位图
 83      * 并在球桌上增加了障碍物,同时还新增了一个显示剩余生命值的区域,默认生命值为3个球
 84      * */
 85     private BufferedImage table;
 86     private BufferedImage ball;
 87     private BufferedImage stick;
 88     private BufferedImage block;
 89     private BufferedImage life;
 90     //------------------------------------------------------------------
 91
 92     private JFrame jf = new JFrame("弹球游戏");
 93     private MyCanvas tableArea = new MyCanvas();
 94     Timer t ;
 95     private boolean isLose = false;//标记位判断是否出界
 96
 97     public void init()throws Exception{
 98         // 定义图片的位置,使用ImageIO从磁盘中读取位图文件
 99         table = ImageIO.read(new File("x:\\gamesImage\\table.jpg"));
100         ball = ImageIO.read(new File("x:\\gamesImage\\ball.png"));
101         stick = ImageIO.read(new File("x:\\gamesImage\\stick.jpg"));
102         block = ImageIO.read(new File("x:\\gamesImage\\block.jpg"));
103         life =  ImageIO.read(new File("x:\\gamesImage\\life.png"));
104
105         //定义键盘的监听器,每按一次左(右)键,向左(右)移动10px
106         KeyAdapter key = new KeyAdapter(){
107             public void keyPressed(KeyEvent e){
108                 if(e.getKeyCode()==KeyEvent.VK_LEFT){
109                     if(racketX>0){
110                         racketX -= 10;
111                     }
112                 }
113                 if(e.getKeyCode()==KeyEvent.VK_RIGHT){
114                     if(racketX<TABLE_WIDTH-RACKET_WIDTH){
115                         racketX += 10;
116                     }
117                 }
118             }
119         };
120
121         //实现监听事件,每次触发该事件,用来检查小球是否碰壁,如果碰壁则将小球队的速度求反。
122         ActionListener go = new ActionListener(){
123             public void actionPerformed(ActionEvent e){
124                 //由于增加了障碍物,判断的复制程度又提高了,这里新增对碰撞障碍物的判断
125                 //障碍物的判断又分为障碍物左边和右边两种情况,要区别对待
126                 //检查左右方向上是否碰壁
127                 if(ballX<=0||
128                         (ballY>=blockY&&ballY<=(blockY+BLOCK_HEIGHT)&&ballX<=blockX&&ballX>=blockX-BALL_SIZE)||
129                         (ballY>=blockY&&ballY<=(blockY+BLOCK_HEIGHT)&&ballX<=(blockX+BLOCK_WIDTH)&&ballX>=(TABLE_WIDTH-(blockX+BLOCK_WIDTH)))||
130                         ballX>=TABLE_WIDTH-BALL_SIZE){
131                     System.out.println("水平方向碰壁"+",坐标:x="+ballX+" ,y="+ballY+ballY+",速度:x="+speedX+",y="+speedY);
132                     speedX = -speedX;
133                 }
134                 //检查上下方向上是否碰壁和小球是否出界,但是要先检查出界,再检查碰壁
135                 if(ballY >= RACKET_Y - BALL_SIZE &&
136                 (ballX < racketX || ballX > racketX + RACKET_WIDTH)){
137                     if(!isLose&&lifeNum>1){
138                         again();
139                     }else{
140                         isLose = true;//小球出界,游戏结束
141                         t.stop();//关闭计时器
142                         tableArea.repaint();
143                     }
144                 }else if(ballY<=0||//这里对障碍物垂直方向的碰撞的判断,也分为障碍物上面和障碍物下面
145                         (ballY>=RACKET_Y-BALL_SIZE&&racketX<=ballX&&ballX<=racketX+RACKET_WIDTH)||
146                         (ballX>=blockX&&ballX<=(blockX+BLOCK_WIDTH)&&ballY>=blockY-BALL_SIZE&&ballY<=blockY)||
147                         (ballX>=blockX&&ballX<=(blockX+BLOCK_WIDTH)&&ballY<=blockY+BALL_SIZE&&ballY>=blockY)){
148                     System.out.println("垂直方向碰壁"+",坐标:x="+ballX+" ,y="+ballY+",速度:x="+speedX+",y="+speedY);
149                     speedY = -speedY;
150                 }
151                 //小球的x轴和y轴的坐标增加或减少来实现移动
152                 ballY += speedY;
153                 ballX += speedX;
154                 tableArea.repaint();
155             }
156         };
157
158         jf.addWindowListener(new WindowAdapter(){
159             public void windowClosing(WindowEvent e){
160                 System.exit(0);
161             }
162         });
163         //设置画布的固定尺寸
164         tableArea.setPreferredSize(new Dimension(TABLE_WIDTH,TABLE_HEIGHT));
165         tableArea.addKeyListener(key);
166
167         t = new Timer(100,go);//定义计时器
168         t.start();//打开计时器
169         jf.addKeyListener(key);
170         jf.add(tableArea);
171         jf.setLocation(50,50);
172         jf.setResizable(false);
173         jf.pack();
174         jf.setVisible(true);
175     }
176
177     class MyCanvas extends JPanel{
178         private static final long serialVersionUID = 1L;
179
180         //覆写Canvas的paint方法,实现绘图
181         public void paint(Graphics g){
182             if(isLose){
183                 g.setColor(new Color(255,0,0));
184                 g.setFont(new Font("Times",100,50));
185                 g.drawString("游戏已结束!", 50, 400);
186             }else{
187                 g.drawImage(table,0,0,null);
188                 g.drawImage(ball,ballX,ballY,null);
189                 g.drawImage(stick,racketX,RACKET_Y,null);
190                 g.drawImage(block,blockX,blockY,null);
191                 g.drawImage(life,lifeX,lifeY,null);
192                 g.setColor(new Color(255,0,0));
193                 g.setFont(new Font("Times",100,18));
194                 g.drawString("X"+lifeNum, 65, 65);
195             }
196         }
197     }
198
199     //再来一次游戏
200     public void again() {
201         //定义小球和球拍的位置为随机
202         ballX = rand.nextInt(200)+20;//小球的x坐标(20~~220)
203         ballY = rand.nextInt(10)+20;//小球的y坐标(20~~30)
204         racketX = rand.nextInt(200);//代表球拍的水平位置
205         RACKET_Y = 500;//球拍的垂直位置是不变的
206         speedY = 10;//将速度恢复初始值
207         speedX = (int)(speedY*xyRate*2);
208         try {
209             init();
210         } catch (Exception e) {
211             e.printStackTrace();
212         }
213         --lifeNum;
214     }
215
216     //构造方法
217     public PinBallImage(){}
218
219     public static void main(String[] args) throws Exception{
220         new PinBallImage().init();
221     }
222 }

时间: 2024-11-07 21:13:04

最近新学了图形界面,写了一个弹球游戏,拿出来让大家指正。的相关文章

java图形界面写个小桌面,内置简单小软件

一.做个这样的效果,双击图标打开相应的应用 二.主界面类,使用JavaSwing的JDesktopPane类创建这个桌面 package com.swing; import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.Graphics2D; import java.awt.Rectangle; import java.awt.Toolkit; import java.awt.event.MouseAdapte

刚学玩原生JS,自己写了一个小游戏,希望在以后能不断地进步加以改善

<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>冒险岛</title></head><style type="text/css"> body{ -moz-user-select: none; -khtml-user-select: none; user-select

在学会循环结构语句时就可以写的一个猜拳游戏小项目

package com.etc.for2; import java.util.Scanner; /** * 猜拳游戏规则: * 人或机器可以随机出石头.剪刀.布, * 若一方出石头,另一方出剪刀,则输出打印出石头方获胜, * 若一方出石头,另一方出布,则输出打印出布方获胜, * 若一方出布,另一方出剪刀,则输出打印出剪刀方获胜, * */ public class TestCaiQuan { public static void main(String[] args) { Scanner sc=

JS写的一个猜拳游戏

const readline = require("readline-sync"); console.log("欢迎来到猜拳游戏:"); console.log("输入 1 为 剪刀\n输入 2 为石头\n输入 3 为布\n"); //电脑随机 function computer() { let computer = parseInt(Math.random() * 3 + 1); switch (computer) { case 1: cons

用Python写一个带图形界面的文件压缩软件

文件压缩和解压我们在日常工作学习中会经常用到,比如winrar.快压.好压等压缩软件 打开之后的界面长这个样子: 压缩完成后是这个样子: 解压完成后是这个样子: 大家在学python的时候肯定会遇到很多难题,以及对于新技术的追求,这里推荐一下我们的Python学习扣qun:784758214,这里是python学习者聚集地!!同时,自己是一名高级python开发工程师,从基础的python脚本到web开发.爬虫.django.数据挖掘等,零基础到项目实战的资料都有整理.送给每一位python的小

第二章 图形界面还是命令窗口

第二章 图形界面还是命令窗口 对于linux的应用,我想大多数都是用在服务器领域,对于服务器来讲真的没有必要跑一个图形界面.所以我们平时安装linux操作系统时往往是不安装图形界面的.说到这里也许你会有疑问,图形界面还能选择装或者不装? 是的,虽然linux和微软的windows一样同位操作系统,但是它们有一个很大的区别就是windows操作系统的图形界面是和内核一体的,俗称微内核,而linux操作系统图形界面就像一个软件一样,和内核并不是一体的.所以linux你可以选择不安装图形界面,这样不仅

Linux入门教程-第二章 图形界面还是命令窗口

对于linux的应用,我想大多数都是用在服务器领域,对于服务器来讲真的没有必要跑一个图形界面.所以我们平时安装linux操作系统时往往是不安装图形界面的.说到这里也许你会有疑问,图形界面还能选择装或者不装? 是的,虽然linux和微软的windows一样同位操作系统,但是它们有一个很大的区别就是windows操作系统的图形界面是和内核一体的,俗称微内核,而linux操作系统图形界面就像一个软件一样,和内核并不是一体的.所以linux你可以选择不安装图形界面,这样不仅不影响服务器的正常使用还可以节

Windows后登陆没有图形界面只有cmd,explorer.exe不能启动

Windows 系统 登陆没有图形界面,只有一个dos窗口: 1,从状态看,比较像桌面程序没启动,尝试启动explorer.exe 试试 发现explorer.exe无法执行 2,看下文件 C:\Windows\explorer.exe 是否存在 没有查询到,说明explorer.exe 文件不存在. 处理办法:此时可以执行如下命令安装图形界面.耐心等待,时间较长.Dism /online /enable-feature /all /featurename:Server-Gui-Mgmt /fe

DirectX游戏开发——从一个小游戏开始

本系列文章由birdlove1987编写,转载请注明出处. 文章链接: http://blog.csdn.net/zhurui_idea/article/details/26364129 写在前面:自己对DirectX挺感兴趣的,加上自己目前在研究3D重建方面的东西,所以利用课余时间学习一下.看了一段时间的书,感觉还是靠动手编写一些小例子来学习,进步的更快体会的更深.所以从我自己写的一个小游戏开始吧,把自己学习心得和自己的一些想法写下来.更是欢迎有兴趣的童鞋来和我交流. 首先:先把我的小例子分享