小球碰撞游戏
小球碰撞,首先需要创建一个窗体,相信大家都会创建窗体。然后从窗体上获取画布。紧接着大家都会想到也都会做的就是在 创建一个监听器然后画一个圆。接着我们就会考虑怎么让这个圆动起来,怎么重绘,怎么使圆看起来更漂亮,看起来像一个球一样,又怎么让小球碰在一起又弹开。然后大家会处理一些细节问题,如可以让球可以停下来,然后可以让球恢复过来,怎么加背景。(加动态背景在下篇博客中我将要再写)
首先创建窗体,我们会考虑到在窗体上加几个按钮,如有控制加小球的按钮,有控制小球停止的按钮,有恢复小球运动的按钮。在小球运动的时候显然小球会把按钮擦去。针对这个问题,我在窗体上加了3个JPanel。第一个面板可以直接加到窗体上,把面板1设置成borderlayout布局。然后将面板二加到面板上的North或者其他位置。把第三个面板加到第一个center位置。然后从面板3上获取画布。代码如下:
//在窗体上加一个面板,使窗体变成白色
jpl=new MyJpanel();
jpl.setBackground(Color.WHITE);
this.add(jpl);
//布置这个面板的布局便于让小球从撒小球这个按钮下面出来
jpl.setLayout(new BorderLayout());
//再在上一个面板的北方即上面加一个面板,使其更漂亮
jp2=new MyJpanel();
//设置就jp2的布局
jp2.setLayout(new FlowLayout());
jp2.setBackground(Color.WHITE);
jpl.add(jp2,BorderLayout.NORTH);
jb=new JButton("撒小球");
//把小球加到面板的上方
jp2.add(jb);
jb1=new JButton("暂停");
//把小球加到面板的上方
jp2.add(jb1);
jb2=new JButton("恢复");
//把小球加到面板的上方
jp2.add(jb2);
//在最底层的面板上中心位置再加一个面板
jp3=new MyJpanel();
jp3.setBackground(Color.white);
jpl.add(jp3,BorderLayout.CENTER);
接下来可以把面板一设置成流体布局,在上面加3个按钮,撒小球,暂停,恢复。在按钮上加上一个监听器,这个监听器继承接口ActionListener。获取按钮上的内容,如果获得按钮上的内容是撒小球时,则向下撒一个小球。要想实现每点击一下撒小球的按钮就出来一个球。则需要加一个创建一个小球范型。代码如下:
public static List<Ball> listballs = new ArrayList<Ball>();
String command = e.getActionCommand();
if (command.equals("撒小球")) {
Ball ball = new Ball(this.jp5,this.listballs);
ball.start();
listballs.add(ball);
}
这样就实现了每点击一下撒小球按钮就出现一个小球。接下来就要创建和写小球Ball类了。因为想要小球运动。这样的话我们就用到线程了。线程就是通过一个程序产生几个进程的效果。他是每隔一段时间就执行一下。因此就可以达到每隔一段时间小球到达一个位置,在这样连续下就可以看做小球的运动。怎么运用线程类呢?通过继承Thread类或继承Runable接口。调用他们的run方法并且重写run方法。代码如下:
// 运用线程
public void run() {
// 调用父类的run方法
super.run();
// 当判断一致成立时 ,也就是当判断为真时
while (true) {
if (!pauseflag) {
continue;
}
try {
//判断小球的碰撞
Thread.sleep(100);
move();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Thread.sleep(100);是指每隔0.1S就执行一下run方法中的内容。可以通过在run方法中改变球圆心(x,y)的坐标来改变球的位置。于是我在下面写了move函数。在该函数中可以写关于圆心坐标改变的表达式,也可以写关于小球碰撞的表达式。代码如下:
public void move(){
x+=stepx;
y+=stepy;
// 为什么把这个写到构造函数中就不可以了呢 构造函数只执行一次run方法是一直执行的
// 一般在run方法中是无限循环执行的
// 执行某项任务
if (x <= r) {
//System.out.println("1111");
stepx =Math.abs(stepx);
}
//很不理解为什么要在这里写成y <= r
if (y <= r) {
stepy = Math.abs(stepy);
}
if (x >= (jp4.getWidth() - r)) {
stepx = -Math.abs(stepx);
}
if (y >= (jp4.getHeight() - r)) {
stepy = -Math.abs(stepy);
}
在move函数中stepx,stepy是在x,y方向上的增量。如果想要小球从不同的方向出来,可以随机取得一个stepx的值这样在同一个点小球的出来方向不同。如果执行执行程序时,每隔0.1sx,y就变化一下。
if (x <= r) {
//System.out.println("1111");
stepx =Math.abs(stepx);
}
这句代码表示,当小球碰到面板3的左侧时,改变x的增量。使其方向改变,其他3个判断句读者可以举一反三。但是这样出来的小球运动会出现问题。小球前面的轨迹不能擦除。我们可以想出两个办法擦去原来的轨迹,第一,可以写一个Clear方法,在draw小球前把原来的位置用背景的颜色填充。我是用第二个方法。第二个方法就是用重绘的方法加上线程。代码如下:
new Thread(){
public void run(){
while(true){
//repaint会直接执行paint中的方法
jp3.repaint();
try{
Thread.sleep(10);
}catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}.start();
每个画布都有默认的paint方法。在这个线程里,每隔一段时间调用一下paint方法。而我是在paint方法中画的球。这样就每隔一段时间显示这个球在不同的位置。这样前面的痕迹就不会再出现了。就写到这里了,明天我将要续写,写上怎么把球画的有立体感,怎么把暂停,恢复怎么加动态背景。晚安,世界。