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

  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 }
View Code

 

转载于:https://www.cnblogs.com/xn6517/p/4660980.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值