首页 > 编程语言 >Java GUI编程(包括awt,event)弹球小游戏功能扩充。

Java GUI编程(包括awt,event)弹球小游戏功能扩充。

时间:2023-03-04 15:47:05浏览次数:48  
标签:Java 弹球 awt 小球 private public Wdith new PX

原网址https://gitee.com/EdsionKXXX/pinball-game-demo

源代码:

  1 package AWT_GameDemo;
  2 
  3 
  4 import javax.swing.*;
  5 import java.awt.*;
  6 import java.awt.event.*;
  7 
  8 
  9 public class GameingDemo {
 10 
 11     // 创建窗口对象
 12     Frame s = new Frame("BallGame");
 13     //设置窗口高度宽度
 14     private final int W_Height = 400;
 15     private final int W_Wdith = 300;
 16     //球拍高宽
 17     private final int P_Height = 20;
 18     private final int P_Wdith = 60;
 19     //球拍坐标
 20     private int PX = 130;
 21     private final int PY = 340;
 22 
 23     //小球高宽
 24     private final int B_SIZE = 16;
 25     //小球坐标
 26     private int BX = 120;
 27     private int BY = 20;
 28     //小球速度
 29     private int BXV = 10;
 30     private int BYV = 5;
 31     //判断游戏是否结束变量
 32     private boolean isover = false;
 33 
 34     //定义一个定时器(刷新画面用)
 35     private Timer timer;
 36 
 37     //创建绘画组件
 38     public class MyCanvas extends Canvas {
 39         @Override
 40         public void paint(Graphics g) {
 41 //绘制画面
 42 //游戏结束内容
 43             if (isover) {
 44                 g.setColor(Color.RED);
 45                 g.setFont(new Font("times", Font.BOLD, 30));
 46                 g.drawString("GAME OVER", 20, 200);
 47 
 48             } else {
 49 
 50 
 51 //游戏中内容
 52                 //绘制小球
 53                 g.setColor(Color.RED);
 54                 g.fillOval(BX, BY, B_SIZE, B_SIZE);
 55                 //绘制球拍
 56                 g.setColor(Color.PINK);
 57                 g.fillRect(PX, PY, P_Wdith, P_Height);
 58 
 59             }
 60         }
 61     }
 62 
 63     MyCanvas myc = new MyCanvas();
 64 
 65     public void mix() {
 66         //球拍坐标处理逻辑
 67         KeyListener k = new KeyAdapter() {
 68             @Override
 69             public void keyPressed(KeyEvent e) {
 70                 //获取当前按下按钮
 71                 int kc = e.getKeyCode();
 72                 if (kc == KeyEvent.VK_LEFT) {
 73                     if (PX > 0) {
 74                         PX -= 10;
 75                     }
 76                 } else if (kc == KeyEvent.VK_RIGHT) {
 77                     if (PX < (W_Wdith - P_Wdith)) {
 78                         PX += 10;
 79                     }
 80                 }
 81             }
 82         };
 83         //给frame 和画布注册监听
 84         s.addKeyListener(k);
 85         myc.addKeyListener(k);
 86         //小球处理逻辑
 87         ActionListener task = new ActionListener() {
 88             @Override
 89             public void actionPerformed(ActionEvent e) {
 90                 //修正速度
 91                 if (BX <= 0 || BX > W_Wdith - B_SIZE) {
 92                     BXV = -BXV;
 93                 }
 94                 if (BY <= 0 || (BY > PY - B_SIZE && BX > PX && BX < PX + P_Wdith)) {
 95                     BYV = -BYV;
 96                 }
 97                 //游戏状态修正
 98                 if (BY + B_SIZE > PY && (BX < PX || BX > PX + P_Wdith)) {
 99                     timer.stop();
100                     isover = true;
101                     myc.repaint();
102                 }
103 
104                 //更新小球坐标重汇界面
105                 BX += BXV;
106                 BY += BYV;
107                 myc.repaint();
108             }
109         };
110         timer = new Timer(100, task);
111         timer.start();
112         myc.setPreferredSize(new Dimension(W_Wdith, W_Height));
113         s.add(myc);
114         s.pack();
115         s.setVisible(true);
116         s.addWindowListener(new WindowAdapter() {
117             @Override
118             public void windowClosing(WindowEvent e) {
119                 System.exit(0);
120             }
121         });
122     }
123 
124 
125     public static void main(String[] args) {
126         GameingDemo G = new GameingDemo();
127         G.mix();
128 
129     }
130 }

界面演示:游戏中:

 

 

 游戏结束:

 

 

 功能描述:利用awt包中的Frame类创建窗口,Canvas类创建画布,利用抽象类Graphics的画笔功能实现对小球和球拍的不断重绘来实现游戏动态效果,其中swing组件中的Timer类来实现小球和球拍的定时重绘和处理逻辑,处理逻辑为:小球在触及窗口的左,右,上和球拍时反弹,越过球拍的y坐标游戏结束。该程序包含的和窗口大小,小球大小和球拍大小等长宽数值,小球运动速度等皆为该类的成员变量。

1.部分修正:

(1)窗口位置调整:

s.pack();//s为Frame类实例对象

pack()是window类中的方法,可以根据添加的组件和设置的布局来自动设置窗口的位置和大小,但该窗口大小已设置,所以将位置调整为当前屏幕正中心附近为最佳,所以将原代码改为:

s.setBounds(500,200,W_Wdith,W_Height);//后两个参数为窗口高度宽度

 或者:

s.pack();
s.setLocation(500,200);

(2)判定修正:

先来阅读源代码中的游戏结束判定:

            if (BY + B_SIZE > PY && (BX < PX || BX > PX + P_Wdith)) {
 99                     timer.stop();
100                     isover = true;
101                     myc.repaint();
102                 }


 


            if (isover) {
 44                 g.setColor(Color.RED);
 45                 g.setFont(new Font("times", Font.BOLD, 30));
 46                 g.drawString("GAME OVER", 20, 200);
47          }

 /*

 *BY:小球Y坐标位置,BX:小球X坐标位置,B_SIZE:小球直径,PX:球拍X坐标位置,P_Wdith(也许原作者拼错了):球拍宽度。

 *timer:Timer类实例化对象,myc:Canvas类的自定义子类 MyCanvas实例化对象,g:Graphics类实例化画笔对象。isover:判定游戏是否结束的布尔类型对象

 */

 

阅读源代码的判定条件时,可知当小球的Y坐标加上小球直径,也就是小球的下边界超过球拍的Y坐标(球拍的上边界)时,并且小球的X坐标位置脱离球拍的X坐标位置时,游戏结束。但对于我们玩过弹球游戏的玩家来说,该判定条件下结束游戏有些突兀,应该在小球出现在球拍下边界以下时,玩家知道已经失败的时候结束游戏才显得比较正常,所以将原来的代码改为:

if (BY + B_SIZE > PY + P_Height + 10 && (BX < PX || BX > PX + P_Wdith))        

在小球的下边界越过球拍下边界的10个像素单位时结束游戏。

或者改为:

if (BY  > PY + P_Height  && (BX < PX || BX > PX + P_Wdith))

在小球的上边界越过球拍下边界时结束游戏

2.功能扩充:

  (1):键位添加

      源代码利用键位监听实现了球拍的左右移动,根据大部分游戏玩家的习惯,WASD移动模式已经深入玩家的心中,所以将键位A和键位D也作为左右移动的键位,源代码改为:

if (kc == KeyEvent.VK_LEFT || kc == KeyEvent.VK_A) {
                    if (PX > 0) {
                        PX -= 10;
                    }
                } else if (kc == KeyEvent.VK_RIGHT || kc == KeyEvent.VK_D) {
                    if (PX < (W_Wdith - P_Wdith)) {
                        PX += 10;
//kc为获取的当前按键,键位监听在第67行

  (2):积分功能

      有了积分的功能才知道自己有多厉害!ヽ(´•ω•`)、,源代码改为:

      

 if (isover) {
                g.setColor(Color.RED);
                g.setFont(new Font("times", Font.BOLD, 30));
                g.drawString("GAME OVER", 60, 200);
                g.setColor(Color.pink);
                g.setFont(new Font("times", Font.BOLD, 20));
                g.drawString("得分:"+Score/2,110,250);
            } 

 


 

 if (BY <= 0 || (BY > PY - B_SIZE && BX > PX && BX < PX + P_Wdith)) {
  BYV = -BYV;
  ++Score;
   }

private int Score = 0;//新增成员变量


  (3)暂停功能:

    单机游戏都会提供暂停游戏的功能,来为玩家提供方便,新添代码:

      if(kc == KeyEvent.VK_SPACE){
                    if(isPause){
                        isPause = false;
                        timer.restart();
                    }else{
                        isPause = true;
                        timer.stop();
                    }
private boolean isPause = false;//新增成员变量


  (4)菜单选项:

    利用Menu相关的组件为该游戏添加菜单,可以为玩家提供部分自定义功能,新添代码如下:

    

  MenuBar mb = new MenuBar();
    Menu menu = new Menu("选项");
   ......
s.setMenuBar(mb);
   mb.add(menu);

  4.1:设置背景颜色:

    玩家可自行设置背景颜色,注意不要与小球和球拍重色。

    

(成员变量)     
Menu m1 = new Menu("背景颜色"); MenuItem m11 = new MenuItem("黑色"); MenuItem m12 = new MenuItem("蓝色"); MenuItem m13 = new MenuItem("绿色"); MenuItem m14 = new MenuItem("黄色");

(组装)

menu.add(m1);
m1.add(m11);
m1.add(m12);
m1.add(m13);
m1.add(m14);

(设置监听器)
m11.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
myc.setBackground(Color.black);
}
});
m12.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
myc.setBackground(Color.blue);
}
});
m13.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
myc.setBackground(Color.green);
}
});
m14.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
myc.setBackground(Color.YELLOW);
}
});
 

       4.2:设置小球速度

    玩家也许想挑战更快速度的小球,可以提供小球速度修改的功能。

    

Menu m2 = new Menu("修改速度");
.........
 MenuItem m21 = new MenuItem("加快");
 MenuItem m22 = new MenuItem("减慢");
.........
(组装)
menu.add(m2);
m2.add(m21);
m2.add(m22);
(设置监听器)

m21.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
BYV *= 1.5;
BXV *= 1.5;
}
});
m22.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
//速度不允许低于一定值
if (BYV <= 5 || BXV <= 10) {
BYV = 5;
BXV = 10;
} else {
BYV /= 1.5;
BXV /= 1.5;
}
}
});

  这里要注意的是,X方向和Y方向的速度的增幅和减幅要一致,不然会导致小球速度的轨迹改变,所以采用乘除运算符,确保速度为线性变化。

 

总结:

  本次的程序改进和扩充应用的主要技术就是Java AWT 中的内容,通过自身的想象力和创造力,利用GUI编程还可以做出更多东西,若本文有错误欢迎指正,本人也只是小白,希望能进一步学习到更多内容。本文添加代码皆为原创,如有雷同纯属巧合。

 

改后源代码:

  

  1 package AWT_GameDemo;
  2 
  3 
  4 import javax.swing.*;
  5 import java.awt.*;
  6 import java.awt.event.*;
  7 
  8 
  9 public class GameingDemo {
 10 
 11     // 创建窗口对象
 12     Frame s = new Frame("BallGame");
 13     private int Score = 0;
 14     private boolean isPause = false;
 15     MenuBar mb = new MenuBar();
 16     Menu menu = new Menu("选项");
 17     Menu m1 = new Menu("背景颜色");
 18     Menu m2 = new Menu("修改速度");
 19     MenuItem m11 = new MenuItem("黑色");
 20     MenuItem m12 = new MenuItem("蓝色");
 21     MenuItem m13 = new MenuItem("绿色");
 22     MenuItem m14 = new MenuItem("黄色");
 23     MenuItem m21 = new MenuItem("加快");
 24     MenuItem m22 = new MenuItem("减慢");
 25     //设置窗口高度宽度
 26     private final int W_Height = 400;
 27     private final int W_Wdith = 300;
 28     //球拍高宽
 29     private final int P_Height = 20;
 30     private final int P_Wdith = 60;
 31     //球拍坐标
 32     private int PX = 130;
 33     private final int PY = 340;
 34 
 35     //小球高宽
 36     private final int B_SIZE = 16;
 37     //小球坐标
 38     private int BX = 120;
 39     private int BY = 20;
 40     //小球速度
 41     private int BXV = 10;
 42     private int BYV = 5;
 43     //判断游戏是否结束变量
 44     private boolean isover = false;
 45 
 46     //定义一个定时器(刷新画面用)
 47     private Timer timer;
 48 
 49     //创建绘画组件
 50     public class MyCanvas extends Canvas {
 51         @Override
 52         public void paint(Graphics g) {
 53 //绘制画面
 54 //游戏结束内容
 55             if (isover) {
 56                 g.setColor(Color.RED);
 57                 g.setFont(new Font("times", Font.BOLD, 30));
 58                 g.drawString("GAME OVER", 60, 200);
 59                 g.setColor(Color.pink);
 60                 g.setFont(new Font("times", Font.BOLD, 20));
 61                 g.drawString("得分:" + Score / 2, 110, 250);
 62             } else {
 63 
 64 
 65 //游戏中内容
 66                 //绘制小球
 67                 g.setColor(Color.RED);
 68                 g.fillOval(BX, BY, B_SIZE, B_SIZE);
 69                 //绘制球拍
 70                 g.setColor(Color.PINK);
 71                 g.fillRect(PX, PY, P_Wdith, P_Height);
 72 
 73             }
 74         }
 75     }
 76 
 77     MyCanvas myc = new MyCanvas();
 78 
 79     public void mix() {
 80         //球拍坐标处理逻辑
 81         KeyListener k = new KeyAdapter() {
 82             @Override
 83             public void keyPressed(KeyEvent e) {
 84                 //获取当前按下按钮
 85                 int kc = e.getKeyCode();
 86                 if (kc == KeyEvent.VK_LEFT || kc == KeyEvent.VK_A) {
 87                     if (PX > 0) {
 88                         PX -= 10;
 89                     }
 90                 } else if (kc == KeyEvent.VK_RIGHT || kc == KeyEvent.VK_D) {
 91                     if (PX < (W_Wdith - P_Wdith)) {
 92                         PX += 10;
 93                     }
 94                 }
 95                 if (kc == KeyEvent.VK_SPACE) {
 96                     if (isPause) {
 97                         isPause = false;
 98                         timer.restart();
 99                     } else {
100                         isPause = true;
101                         timer.stop();
102                     }
103                 }
104             }
105         };
106         //给frame 和画布注册监听
107         s.addKeyListener(k);
108         myc.addKeyListener(k);
109         //小球处理逻辑
110         ActionListener task = new ActionListener() {
111             @Override
112             public void actionPerformed(ActionEvent e) {
113                 //修正速度
114                 if (BX <= 0 || BX > W_Wdith - B_SIZE) {
115                     BXV = -BXV;
116                 }
117                 if (BY <= 0 || (BY > PY - B_SIZE && BX > PX && BX < PX + P_Wdith)) {
118                     BYV = -BYV;
119                     ++Score;
120                 }
121                 //游戏状态修正
122                 if (BY > PY + P_Height && (BX < PX || BX > PX + P_Wdith)) {
123                     timer.stop();
124                     isover = true;
125                     myc.repaint();
126                 }
127 
128                 //更新小球坐标重汇界面
129                 BX += BXV;
130                 BY += BYV;
131                 myc.repaint();
132             }
133         };
134         timer = new Timer(100, task);
135         timer.start();
136         myc.setPreferredSize(new Dimension(W_Wdith, W_Height));
137         s.add(myc);
138         s.setMenuBar(mb);
139         mb.add(menu);
140         menu.add(m1);
141         m1.add(m11);
142         m1.add(m12);
143         m1.add(m13);
144         m1.add(m14);
145         menu.add(m2);
146         m2.add(m21);
147         m2.add(m22);
148         m11.addActionListener(new ActionListener() {
149             @Override
150             public void actionPerformed(ActionEvent e) {
151                 myc.setBackground(Color.black);
152             }
153         });
154         m12.addActionListener(new ActionListener() {
155             @Override
156             public void actionPerformed(ActionEvent e) {
157                 myc.setBackground(Color.blue);
158             }
159         });
160         m13.addActionListener(new ActionListener() {
161             @Override
162             public void actionPerformed(ActionEvent e) {
163                 myc.setBackground(Color.green);
164             }
165         });
166         m14.addActionListener(new ActionListener() {
167             @Override
168             public void actionPerformed(ActionEvent e) {
169                 myc.setBackground(Color.YELLOW);
170             }
171         });
172         m21.addActionListener(new ActionListener() {
173             @Override
174             public void actionPerformed(ActionEvent e) {
175                 BYV *= 1.5;
176                 BXV *= 1.5;
177             }
178         });
179         m22.addActionListener(new ActionListener() {
180             @Override
181             public void actionPerformed(ActionEvent e) {
182                 //速度不允许低于一定值
183                 if (BYV <= 5 || BXV <= 10) {
184                     BYV = 5;
185                     BXV = 10;
186                 } else {
187                     BYV /= 1.5;
188                     BXV /= 1.5;
189                 }
190             }
191         });
192         s.pack();
193         s.setLocation(500, 200);
194         s.setVisible(true);
195         s.addWindowListener(new WindowAdapter() {
196             @Override
197             public void windowClosing(WindowEvent e) {
198                 System.exit(0);
199             }
200         });
201     }
202 
203 
204     public static void main(String[] args) {
205         GameingDemo G = new GameingDemo();
206         G.mix();
207 
208     }
209 }

 

部分效果展示:

    

 

 

 

 

 

 

 

  

标签:Java,弹球,awt,小球,private,public,Wdith,new,PX
From: https://www.cnblogs.com/lplpok/p/17177776.html

相关文章

  • java 线程同步
    多种方式可以完成线程同步,传统方法是关键字synchronized完成的,可以是同步方法也可以是同步代码块同步方法@Data@AllArgsConstructor@NoArgsConstructorclassMyThea......
  • java 创建线程
    继承ThreadclassMyThread1extendsThread{@Overridepublicvoidrun(){System.out.println("继承Thread...");}}publicclassTest1{......
  • java 线程状态
    线程状态java.lang.Thread.State里明确了线程的各个状态以及怎么进入和退出各个状态publicenumState{//初始化状态,线程创建之后的状态,newThread()之后进......
  • Java集合LinkedList源码中 实现 List 接口 却没有 在 LinkedList实现全部的 List接口
    Java集合LinkedList源码中实现List接口却没有在LinkedList实现全部的List接口方法普通类实现接口,应该实现接口中全部的抽象方法。难道是源码实现接口有什么特殊的......
  • Java 需要快速读出和写入的框架架构
    //对标牛客竞赛小白月赛109a题//importjava.util.*;importjava.io.*;publicclassMain{staticlongn;staticBufferedReaderbf=newBufferedReader(n......
  • java中 += 的作用
    编程语言中数据类型之间的区别,大的数据类型转换给小的会无法转换,所以在一些小的数据类型运算的时候一般会默认使用int以上的数据类型运算,当你使用byte,short,char类型运算......
  • java——spring boot集成RabbitMQ——高级特效——死信代码示例
    首先,消息成为死信的条件:       首先看消息生产者,生产者和之前的一样,没什么变化(注意:后面统一把nomal改为normal了):          消费......
  • java HashSet 原理
    其实就是HashMap,明白了HashMap就会明白HashSet原理创建HashSet底层就是创建了一个HashMapHashSet添加一个元素就是往HashMap添加一个元素HashSet获取元素,......
  • 3.理解JavaScript的执行上下文、执行上下文栈,可以应用堆栈信息快速定位问题
    1.执行上下文执行上下文就是当前JavaScript代码被解析和执行时所在环境的抽象概念,JavaScript中运行任何的代码都是在执行上下文中运行1.执行上下文的类型全局执行......
  • 2.理解JavaScript的作用域和作用域链
    什么是作用域Javascript中的作用域说的是变量的可访问性和可见性。也就是说整个程序中哪些部分可以访问这个变量,或者说这个变量都在哪些地方可见。作用域的类型全局作......