用JAVA实现一个简易的打砖块小游戏
作者:互联网
概述
利用java实现打砖块小游戏,游戏界面包括以下元素
- 顶部的各色砖块
- 底部的挡板
- 小球
- 游戏信息展示面板
- 玩法包括
使用鼠标或者键盘移动挡板
- 打掉砖块,得分
- 每一局有3次机会,挡板没有接到小球,机会减1
- 打掉黑色小球,会掉落道具,挡板接到道具,挡板会变长
- 可以选择游戏难度等级
功能实现
首先,整个Class继承自 GraphicsProgram, 程序启动后,先执行init() 方法,然后执行 run() 方法
public class Arkanoid extends GraphicsProgram
{
public void init()
{
// 进行初始化
}
public void run()
{
// 具体执行
}
}
然后,在 init() 中,进行游戏界面的创建。
创建砖块
创建砖块前,先准备一个存储颜色和颜色对应的分值的容器,这里用Map来实现,键保存Color对象,值保存分值
Map<Color,Integer> brickColors;
colors=new Color[]{
Color.BLACK,Color.BLUE,Color.CYAN,Color.DARK_GRAY,Color.GRAY,Color.GREEN,
Color.LIGHT_GRAY,Color.MAGENTA,Color.ORANGE,Color.PINK,Color.RED,Color.YELLOW
};
brickColors=new HashMap<>();
for(int i=0;i<colors.length;i++)
{
Color color=colors[i];
// 黑色砖块是特殊砖块,打掉不得分,但是可以掉落胶囊
if(color.getRGB() == Color.BLACK.getRGB())
{
brickColors.put(color,0);
}
else
{
brickColors.put(color,colors.length%(i+1)+1);
}
}
有了砖块颜色,接下来的就是创建指定行,列的砖块了,这里用 GRect 表示砖块。
需要注意的一点是,GRect 默认有1像素的边框,如果不去掉它,在计算砖块的宽度时,要考虑到这1像素。
final int ROWS=6;
final int COLUMNS=12;
// 砖块实心部分的宽,高
brickW=GAME_PANE_WIDTH/COLUMNS;
brickH=brickW/2;
for(int i=0;i<ROWS;i++)
{
for(int j=0;j<COLUMNS;j++)
{
GRect brick=new GRect(brickW,brickH);
brick.setFilled(true);
brick.setColor(colors[randomGenerator.nextInt(0,brickColors.size()-1)]);
brick.setLineWidth(0);
double x=j*brickW;
double y=i*brickH;
add(brick,x,y);
}
}
创建挡板和小球
创建挡板和小球,分别使用 GRect和GOval,然后将其添加到适合的位置即可。
创建游戏信息展示面板
在游戏信息展示面板中,可以根据游戏要实现的功能,添加一些面板来展示信息。
这里创建了包括【游戏机会】【得分】【游戏难度】【再来一局】等面板。
最外部使用JPanel创建,布局方式为GirdLayout,然后将每一项添加到其中即可。
使用鼠标或键盘操纵挡板移动
要想实现让挡板跟随鼠标移动的功能,需要为添加鼠标监听器,直接添加到游戏界面最外层组件上即可.
调用方法 addMouseListeners() 然后重写 mouseMoved(MouseEvent) 方法,在其中根据鼠标位置,设置挡板的位置即可。注意限制挡板的移动范围,不让其超出游戏界面。
addMouseListeners();
public void mouseMoved(MouseEvent e)
{
if(gameover) // 游戏结束,恢复挡板在底部正中央
{
paddle.setLocation(GAME_PANE_WIDTH/2.-paddle.getWidth()/2,GAME_PANE_HEIGHT-paddle.getHeight()-30);
}
else // 游戏运行中,动态改变挡板水平方向的位置
{
//paddle.setLocation(e.getX()-PADDLE_W/2,e.getY()-PADDLE_H/2);
// 限制挡板左侧和右侧不能超出游戏界面的范围
double x=e.getX()-paddle.getWidth()/2;
if(x<0)
{
x=0;
}
if(x>GAME_PANE_WIDTH-paddle.getWidth())
{
x=GAME_PANE_WIDTH-paddle.getWidth();
}
paddle.setLocation(x,paddle.getY());
}
}
与使用鼠标类似,使用键盘操作挡板的移动,也需要监听按键事件监听器。
addKeyListeners();
@Override
public void keyTyped(KeyEvent e)
{
double x=paddle.getX();
char keyChar=e.getKeyChar();
if(keyChar == '1') // 左移
{
x-=paddle.getWidth()*1.5;
if(x<=0)
{
x=0;
}
}
else if(keyChar == '2') // 右移
{
x+=paddle.getWidth()*1.5;
if(x>GAME_PANE_WIDTH-paddle.getWidth())
{
x=GAME_PANE_WIDTH-paddle.getWidth();
}
}
paddle.setLocation(x,paddle.getY());
}
移动小球
移动小球,只需要在一个循环中,只要游戏还未结束,就一直调用 move() 即可。
需要在游戏开始前,给小球一个初始移动速度,并且每次游戏的速度不同。
VELOCITY_X=3;
VELOCITY_Y=5;
boolean gameover=false;
public void init()
{
int offset=randomGenerator.nextInt(0,3);
vx=VELOCITY_X+offset; // 水平速度
vy=-(VELOCITY_Y+offset); // 竖直速度
}
public void run()
{
while(!gameover)
{
ball.move(vx,vy);
pause(DELAY);
}
}
检测小球是否撞到墙面
根据游戏界面的宽高和小球当前的坐标,判断小球是否接触到游戏界面的边框,以此来决定小球是否撞到了墙面。
如果小球撞到的上或下墙面,就取反y方向的速度,如果撞到左或右墙面,就取反x方向的速度
代码类似以下
if(hitBottomWall() || hitTopWall())
{
vy=-vy;
}
if(hitLeftWall() || hitRightWall())
{
vx=-vx;
}
小球撞到砖块反弹,砖块消失
首先,获取到小球撞到的砖块。
需要检测4个顶点,这里只给出示例代码
GObject getCollidingObject()
{
GObject element=getElementAt(x,y);
if(element!=null)
return element;
return null;
}
然后,根据撞到砖块的位置,改变小球的移动轨迹
1块砖块根据4条边延伸出去的线,可以将其周围分为8个区域:
- 正上,正下
- 正左,正右
- 左上,左下,右上,右下
如果小球球心处于正上或正下区域,只取反其y方向的速度即可;
如果小球球心处于正左或正右区域,只取反其x方向的速度即可;
如果小球球心处于其他区域,说明它撞到的正好是砖块的4个顶点,x,y方向的速度同时取反。
boolean changeX=false;
boolean changeY=false;
private void changeXY(GObject element,double center_x,double center_y)
{
double left_brick=element.getX();
double top_brick=element.getY();
double right_brick=left_brick+brickW;
double bottom_brick=top_brick+brickH;
if(center_y>top_brick && center_y<bottom_brick) // 小球在砖块的左侧,或右侧
{
changeX=true;
}
else if(center_x>left_brick && center_x<right_brick) // 小球在砖块的上侧,或xia侧
{
changeY=true;
}
else // 小球在砖块的4个顶点范围
{
changeX=true;
changeY=true;
}
}
最后,在run方法中,根据变量 changeX 和 changeY,改变vx 和 vy
GObject element=getCollidingObject();
if(element != null)
{
if(element == paddle) // 如果打到挡板,反弹
{
vy=-vy;
// 加一下速
if(vx>0)
vx+=va;
else
vx-=va;
if(vy>0)
vy+=va;
else
vy-=va;
continue;
}
else
{
if(changeX)
vx=-vx;
if(changeY)
vy=-vy;
remove(element);
}
}
得分
在打到砖块时,只需要根据砖块的颜色,获取到该颜色对应的分数,将其加到得分中即可
GObject element=getCollidingObject();
if(element != null)
{
Color color=element.getColor();
int point=brickColors.get(color);
score+=point;
scoreLabel_num.setText(""+score);
}
掉落道具,接到道具,挡板变长
打到黑色砖块,在砖块下边出现一个道具,竖直下落;如果在道具降到下边墙之前,使用挡板接到道具,挡板将变长。
首先定义一个数组列表,用于存储掉落的道具;
打到黑色砖块后,创建一个道具,将其添加到容器中;
最后,让容器中的道具“落下”;
如果挡板接到了道具,重新设置其尺寸。
ArrayList<GImage> falls;
if(color.getRGB() == Color.BLACK.getRGB())// 如果是黑砖块,落下道具
{
Toolkit toolkit=Toolkit.getDefaultToolkit();
Image image=toolkit.createImage("fall.png");
GImage fall=new GImage(image);
fall.setSize(PADDLE_W,PADDLE_W);
add(fall,element.getX(),element.getY());
falls.add(fall);
}
for(GImage fall:falls)
{
if(fall != null)
{
fall.move(0,5);
// 接到了道具
if(Math.abs(paddle.getY()-fall.getY()-fall.getHeight())<=0.1 && (Math.abs(fall.getX()-paddle.getX())<=paddle.getWidth()-0.1))
{
remove(fall);
double newWidth=paddle.getWidth()*1.5;
if(newWidth>=GAME_PANE_WIDTH)
{
newWidth=GAME_PANE_WIDTH;
}
paddle.setSize(newWidth,paddle.getHeight());
}
}
}
设置游戏难度等级
这里的难度,只是简单的在小球被挡板反弹时,增加其速度。根据所加速的幅度大小,分为
【简单】【一般】【困难】3个难度等级。
创建3个单选按钮,设置其监听器,在其选中时改变加速幅度
double va=0;
JRadioButton simpleBtn=new JRadioButton("简单",true);
JRadioButton middleBtn=new JRadioButton("一般");
JRadioButton diffcultyBtn=new JRadioButton("困难");
simpleBtn.addActionListener(e ->
{
va=0;
});
middleBtn.addActionListener(e ->
{
va=1;
});
diffcultyBtn.addActionListener(e ->
{
va=2;
});
然后,在run方法中,将加速加到vx,vy中
if(element == paddle) // 如果打到挡板,反弹
{
vy=-vy;
// 加一下速
if(vx>0)
vx+=va;
else
vx-=va;
if(vy>0)
vy+=va;
else
vy-=va;
}
标签:JAVA,Color,小球,paddle,小游戏,砖块,vy,挡板 来源: https://blog.csdn.net/weixin_52308504/article/details/113615281