开心消消乐小游戏
·
开心消消乐
消消乐游戏需求
- 所参与的角色:熊、鸟、狐狸、青蛙
- 功能:
- 由系统随机长成元素并显示在窗口中(8行6列),保证不能有可消元素
- 选中两个元素,若相邻则交换,而后判断:
- 若不可消(不连3),则换回去
- 若可消(连3及以上),则:
- 爆破后删除元素
- 重新生成新的元素,若还是可消则重复2.2步骤,直到没有可消元素为止
游戏展示
初始界面
爆炸展示
代码实现
熊类
public class Bear extends Element{
public Bear(int x, int y) {
super(x, y);
}
@Override
public ImageIcon getImage() {
return Images.bear;
}
}
鸟类
public class Bird extends Element{
public Bird(int x, int y) {
super(x, y);
}
@Override
public ImageIcon getImage() {
return Images.bird;
}
}
狐狸类
public class Fox extends Element {
public Fox(int x, int y) {
super(x, y);
}
@Override
public ImageIcon getImage() {
return Images.fox;
}
}
青蛙类
public class Frog extends Element {
public Frog(int x, int y) {
super(x, y);
}
@Override
public ImageIcon getImage() {
return Images.frog;
}
}
元素类
public abstract class Element {
private int x, y; //x, y 坐标
private boolean selected; //是否选中
private boolean eliminated; //是否可消除
private int eliminatedIndex; //爆炸动画图片起始下标
public Element(int x, int y) {
this.x = x;
this.y = y;
this.selected = false;
this.eliminated = false;
this.eliminatedIndex = 0;
}
/**
* 获取图片
*
* @return
*/
public abstract ImageIcon getImage();
public void paintElement(Graphics g) {
if (isSelected()) {
g.setColor(Color.GREEN);
g.fillRect(x, y, World.ELEMENT_SIZE, World.ELEMENT_SIZE);
this.getImage().paintIcon(null, g, this.x, this.y);
} else if (isEliminated()) {
//若没到最后一张爆炸图
if (eliminatedIndex < Images.bombs.length) {
Images.bombs[eliminatedIndex++].paintIcon(null, g, x, y);
}
} else {
this.getImage().paintIcon(null, g, this.x, this.y);
}
}
/**
* 是否选中
*
* @return
*/
boolean isSelected() {
return selected;
}
public void setSelected(boolean selected) {
this.selected = selected;
}
/**
* 是否消除
*
* @return
*/
boolean isEliminated() {
return eliminated;
}
public void setEliminated(boolean eliminated) {
this.eliminated = eliminated;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public void setX(int x) {
this.x = x;
}
public void setY(int y) {
this.y = y;
}
}
图片类
public class Images {
public static ImageIcon background; //背景图
public static ImageIcon bird;
public static ImageIcon bear;
public static ImageIcon fox;
public static ImageIcon frog;
public static ImageIcon[] bombs;
static {
background = new ImageIcon("HappyEliminate/src/com/liner/img/background.png");
bird = new ImageIcon("HappyEliminate/src/com/liner/img/bird.png");
bear = new ImageIcon("HappyEliminate/src/com/liner/img/bear.png");
fox = new ImageIcon("HappyEliminate/src/com/liner/img/fox.png");
frog = new ImageIcon("HappyEliminate/src/com/liner/img/frog.png");
bombs = new ImageIcon[4];
for (int i = 0; i < bombs.length; i++) {
bombs[i] = new ImageIcon("HappyEliminate/src/com/liner/img/bom" + (i + 1) + ".png");
}
}
public static void main(String[] args) {
System.out.println(background.getImageLoadStatus()); //返回8表示成功
System.out.println(bird.getImageLoadStatus()); //返回8表示成功
System.out.println(frog.getImageLoadStatus()); //返回8表示成功
System.out.println(fox.getImageLoadStatus()); //返回8表示成功
System.out.println(bear.getImageLoadStatus()); //返回8表示成功
for (int i = 0; i < bombs.length ; i++) {
System.out.println(bombs[i].getImageLoadStatus());
}
}
}
游戏窗口
public class World extends JPanel {
public static final int WIDTH = 429; //窗口的宽
public static final int HEIGHT = 570; //窗口的高
public static final int ROWS = 8; //8行
public static final int COLS = 6; //6列
public static final int ELEMENT_SIZE = 60; //元素大小
public static final int OFFSET = 30; //偏移量(第一个元素距离窗口左、上边的距离)
private Element[][] elements = new Element[ROWS][COLS]; //元素数组 8行6列
private boolean canInteractive = true; //可交互状态(默认可交互)
private int selectedNumber = 0; //已经选中的元素个数
private int firstRow = 0; //第一个选中的元素的ROW
private int firstCol = 0; //第一个选中的元素的COL
private int secondRow = 0; //第二个选中的元素的ROW
private int secondCol = 0; //第二个选中的元素的COL
public static void main(String[] args) {
JFrame jFrame = new JFrame();
World world = new World();
world.setFocusable(true);
jFrame.add(world);
jFrame.setTitle("开心消消乐");
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jFrame.setSize(WIDTH, HEIGHT + 17);
jFrame.setVisible(true);
world.start();
}
/**
* 程序启动
*/
private void start() {
//游戏启动填充所有元素
fillAllElement();
//鼠标监听
MouseAdapter mouseAdapter = new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
//重写鼠标点击事件
if (!canInteractive) { //不可交互时,不响应鼠标事件
return;
}
canInteractive = false; //只要选中元素,就先将状态修改为不可交互
int row = (e.getY() - OFFSET) / ELEMENT_SIZE; //获取选中元素的ROW
int col = (e.getX() - OFFSET) / ELEMENT_SIZE; //获取选中元素的COL
selectedNumber++; //选中的元素增1
if (selectedNumber == 1) {
//第一次选中
firstRow = row;
firstCol = col;
elements[firstRow][firstCol].setSelected(true); //设置选中状态
canInteractive = true; //可交互
} else if (selectedNumber == 2) {
//第二次选中
secondRow = row;
secondCol = col;
elements[secondRow][secondCol].setSelected(true); //设置选中状态
//判断两次选中是否相邻
if (isAdjacent()) {
//若相邻则 移动、交换、消除
new Thread(() -> {
elements[firstRow][firstCol].setSelected(false); //取消选中状态
elements[secondRow][secondCol].setSelected(false); //取消选中状态
//移动、交换、消除
moveElement(); //移动两个元素
exchangeElement(); //交换两个元素
if (eliminateElement()) { //若有可消元素,并消除
//下落元素
do {
dropElement();
try {
Thread.sleep(10);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}while (eliminateElement()); //持续扫描
} else {
//交换回去
moveElement(); //移动两个元素
exchangeElement(); //交换两个元素
}
canInteractive = true; //可交互
}).start();
} else {
elements[firstRow][firstCol].setSelected(false); //取消选中状态
elements[secondRow][secondCol].setSelected(false); //取消选中状态
canInteractive = true;//可交互
}
canInteractive = true;//在某种条件下可交互
selectedNumber = 0; //选中个数归零
}
repaint(); //重画
}
};
this.addMouseListener(mouseAdapter); //添加鼠标监听器
}
/**
* 下落元素
*/
private void dropElement() {
for (int row = ROWS - 1; row >= 0; row--) {
//只要有null 元素就将它上面的元素落下
while (true) {
int[] nullCols = {}; //当前行为null的列号
for (int col = COLS - 1; col >= 0; col--) {
Element element = elements[row][col];
if (element == null) {
nullCols = Arrays.copyOf(nullCols, nullCols.length + 1);
nullCols[nullCols.length - 1] = col;
}
}
//查找null 列
if (nullCols.length > 0) {
//移动下落元素
for (int count = 0; count < 15; count++) {
// 向下落一下
for (int i = 0; i < nullCols.length; i++) {
int nullCol = nullCols[i];
for (int dr = row - 1; dr >= 0; dr--) {
Element element = elements[dr][nullCol];
if (element != null) {
element.setY(element.getY() + 4);
}
}
}
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
repaint();
}
//真正让数组上面的元素向下移动
for (int i = 0; i < nullCols.length; i++) {
int nullCol = nullCols[i];
for (int nr = row; nr > 0; nr--) {
elements[nr][nullCol] = elements[nr - 1][nullCol];
}
//生成新元素
elements[0][nullCol] = createElement(0,nullCol);
}
} else {
break;
}
}
}
}
/**
* 扫描并删除元素
*/
private boolean eliminateElement() {
boolean haveEliminated = false;
for (int row = ROWS - 1; row >= 0; row--) {
for (int col = COLS - 1; col >= 0; col--) {
Element element = elements[row][col];
if (element == null) { //若元素为null 则跳过
continue;
}
//查找一行内当前元素前面的连续个数, 查找一列内当前元素前面的连续个数
int colRepeat = 0; //行不变,列相邻,与当前元素相邻的行元素连续重复个数
for (int pc = col - 1; pc >= 0; pc--) {
if (elements[row][pc] == null) {
//若当前元素为null 则break 直接退出
break;
}
//若遍历元素与当前元素类型相同,重复个数增1,否则 break
if (elements[row][pc].getClass() == element.getClass()) {
colRepeat++;
} else {
break; //只要右一个不同,后续不需比较
}
}
int rowRepeat = 0; //列不变,行相邻,与当前元素相邻的列元素连续重复个数
for (int pr = row - 1; pr >= 0; pr--) {
if (elements[pr][col] == null) {
//若当前元素为null 则break 直接退出
break;
}
//若遍历元素与当前元素类型相同,重复个数增1,否则 break
if (elements[pr][col].getClass() == element.getClass()) {
rowRepeat++;
} else {
break; //只要右一个不同,后续不需比较
}
}
//将可消除元素设计为可消除状态
if (colRepeat >= 2) {
//行不变,列相邻
elements[row][col].setEliminated(true); //设置当前元素可消除
for (int i = 1; i <= colRepeat; i++) {
//遍历连续个数次
elements[row][col - i].setEliminated(true); //行不变,列前元素设置为可消
}
}
if (rowRepeat >= 2) {
//列不变,行相邻
elements[row][col].setEliminated(true); //设置当前元素可消除
for (int i = 1; i <= rowRepeat; i++) {
//遍历连续个数次
elements[row - i][col].setEliminated(true); //列不变,行前元素设置为可消
}
}
//将可消除状态元素绘制成爆炸动画
if (colRepeat >= 2 || rowRepeat >= 2) {
for (int i = 0; i < Images.bombs.length; i++) {
repaint();
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//将可消除状态元素设置为null 等待其他元素下落
if (colRepeat >= 2) {
elements[row][col] = null; //设置当前元素null
for (int i = 1; i <= colRepeat; i++) {
//遍历连续个数次
elements[row][col - i] = null; //行不变,列前元素设置为null
}
haveEliminated = true; //有可消元素被消除
}
if (rowRepeat >= 2) {
elements[row][col] = null; //设置当前元素null
for (int i = 1; i <= rowRepeat; i++) {
//遍历连续个数次
elements[row - i][col] = null; //列不变,行前元素设置为null
}
haveEliminated = true; //有可消元素被消除
}
}
}
return haveEliminated;
}
/**
* 交换两个元素
*/
private void exchangeElement() {
Element element1 = elements[firstRow][firstCol];
Element element2 = elements[secondRow][secondCol];
elements[firstRow][firstCol] = element2;
elements[secondRow][secondCol] = element1;
}
/**
* 移动两个元素
*/
private void moveElement() {
if (firstRow == secondRow) {
//若行号相同,表示左右移动
int firstX = OFFSET + firstCol * ELEMENT_SIZE;
int secondX = OFFSET + secondCol * ELEMENT_SIZE;
int step = firstX < secondX ? 4 : -4; //设置步长
for (int i = 0; i < 15; i++) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
firstX += step;
secondX -= step;
//修改元素坐标
elements[firstRow][firstCol].setX(firstX);
elements[secondRow][secondCol].setX(secondX);
repaint();
}
}
if (firstCol == secondCol) {
//若列号相同,表示上下移动
int firstY = OFFSET + firstRow * ELEMENT_SIZE;
int secondY = OFFSET + secondRow * ELEMENT_SIZE;
int step = firstY < secondY ? 4 : -4; //设置步长
for (int i = 0; i < 15; i++) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
firstY += step;
secondY -= step;
//修改元素坐标
elements[firstRow][firstCol].setY(firstY);
elements[secondRow][secondCol].setY(secondY);
repaint();
}
}
}
public static final int ELEMENT_TYPE_BEAR = 0; //熊
public static final int ELEMENT_TYPE_BIRD = 1; //鸟
public static final int ELEMENT_TYPE_FOX = 2; //狐狸
public static final int ELEMENT_TYPE_FROG = 3; //青蛙
public static final int ELIMINATE_NONE = 0; //元素不可消
public static final int ELIMINATE_ROW = 1; //元素行可消
public static final int ELIMINATE_COL = 2; //元素列可消
/**
* 检测元素是否可消
*/
public int canEliminate(int row, int col) {
Element element = elements[row][col]; //获取当前元素
//判断纵向
if (row >= 2) {
Element element1 = elements[row - 1][col]; //获取当前元素上面第1个元素
Element element2 = elements[row - 2][col]; //获取当前元素上面第2个元素
if (element1 != null && element2 != null && element != null) {
//若元素都不为null
if (element.getClass().equals(element1.getClass()) && element.getClass().equals(element2.getClass())) {
return ELIMINATE_COL; //表示列可消除
}
}
}
//判断横向
if (col >= 2) {
Element element1 = elements[row][col - 1]; //获取当前元素前面第1个元素
Element element2 = elements[row][col - 2]; //获取当前元素前面第2个元素
if (element1 != null && element2 != null && element != null) {
//若元素都不为null
if (element.getClass().equals(element1.getClass()) && element.getClass().equals(element2.getClass())) {
return ELIMINATE_ROW; //表示行可消除
}
}
}
return ELIMINATE_NONE; //表示不能消除
}
/**
* 判断两元素是否能交换
*/
public boolean isAdjacent() {
//若行相邻且列相等 或 列相邻且行相等
if ((Math.abs(firstRow - secondRow) == 1 && firstCol == secondCol) || (Math.abs(firstCol - secondCol) == 1 && firstRow == secondRow)) {
return true; //相邻
} else {
return false; //不相邻
}
}
/**
* 返回元素
*/
public Element createElement(int row, int col) {
int x = OFFSET + col * ELEMENT_SIZE; //列col的值控制x坐标
int y = OFFSET + row * ELEMENT_SIZE; //行row的值控制y坐标
Random random = new Random();
int type = random.nextInt(4);
switch (type) {
case ELEMENT_TYPE_BEAR:
return new Bear(x, y);
case ELEMENT_TYPE_BIRD:
return new Bird(x, y);
case ELEMENT_TYPE_FOX:
return new Fox(x, y);
default:
return new Frog(x, y);
}
}
/**
* 填充所有元素
*/
public void fillAllElement() {
for (int row = 0; row < ROWS; row++) {
for (int col = 0; col < COLS; col++) {
//判断行消列消
do {
Element element = createElement(row, col);
elements[row][col] = element; //将元素填充到 elements数组中
} while (canEliminate(row, col) != ELIMINATE_NONE); //若可消则重新生成元素
}
}
}
@Override
public void paint(Graphics g) {
Images.background.paintIcon(null, g, 0, 0);
for (int row = 0; row < ROWS; row++) {
for (int col = 0; col < COLS; col++) {
Element element = elements[row][col];
if (element != null) {
element.paintElement(g);
}
}
}
}
}
更多推荐
已为社区贡献2条内容
所有评论(0)