Android手机中的2048游戏Demo开发

时间:2022-12-22 03:34:08

Android中正火的2048游戏开发,赶紧开发一个自己的2048吧

1.游戏中的几个关键点

 1)界面

 2048游戏的操作界面就是一个4X4的方格。如下图所示: Android手机中的2048游戏Demo开发
游戏首先要绘制出该界面。

@1 界面布局文件 

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.example.game2048.MainActivity" >

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/score"/>
<TextView
android:id="@+id/tvScore"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>

</LinearLayout>

<com.example.game2048.GameView
android:id="@+id/gameView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">

</com.example.game2048.GameView>

</LinearLayout>
从布局文件中可以看出,总体采用线性布局的方式,最上面是计分板,下面为界面中主要的部分,是自定义的View--(GameView)。

@2 自定义组件GameView

<span style="font-size:14px;">package com.example.game2048;

import java.util.ArrayList;
import java.util.List;

import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Point;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.GridLayout;

public class GameView extends GridLayout {

public GameView(Context context) {
super(context);

initGameView();
}

public GameView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);

initGameView();
}

public GameView(Context context, AttributeSet attrs) {
super(context, attrs);

initGameView();

}

//初始化Game界面
private void initGameView(){
setColumnCount(4);
setBackgroundColor(0Xffbbada0);
setOnTouchListener(new OnTouchListener() {
// 定义变量
private float startX,startY,offsetX,offsetY;

@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
startX = event.getX();
startY = event.getY();
break;
case MotionEvent.ACTION_UP:
offsetX = event.getX() - startX;
offsetY = event.getY() - startY;

if(Math.abs(offsetX) > Math.abs(offsetY)){
if(offsetX < -5){
//System.out.println("left");
slipLeft();
}
else if(offsetX > 5){
//System.out.println("right");
slipRight();
}
}
else{
if(offsetY < -5){
//System.out.println("up");
slipUp();
}
else if(offsetY > 5){
//System.out.println("down");
slipDown();
}
}

break;

}
return true;
}
});

}

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);

int cardWidth = (Math.min(w, h)-10)/4;
addCards(cardWidth,cardWidth);

startGame();
}

private void addCards(int cardWidth, int cardHeight){
Card c;
for (int y = 0; y < 4; y++) {
for (int x = 0; x < 4; x++) {
c = new Card(getContext());
c.setNum(0);
cardsMap[x][y] = c;
addView(c, cardWidth, cardHeight);
}

}
}

private void startGame(){
MainActivity.getMainActivity().clearScore();
for (int y = 0; y < 4; y++) {
for (int x = 0; x < 4; x++) {
cardsMap[x][y].setNum(0);
}
}

addRandomNum();
addRandomNum();
}

//添加随机数
private void addRandomNum(){

emptyPoints.clear();

for (int y = 0; y < 4; y++) {
for (int x = 0; x < 4; x++) {
if(cardsMap[x][y].getNum() <= 0){
emptyPoints.add(new Point(x,y));
}

}

}

Point p = emptyPoints.remove((int)(Math.random()*emptyPoints.size()));//随机移除一个点
cardsMap[p.x][p.y].setNum(Math.random()>0.1?2:4);

}

private void checkComplete(){
boolean complete = true;

ALL:
for (int y = 0; y < 4; y++) {
for (int x = 0; x < 4; x++) {
if(cardsMap[x][y].getNum() == 0 ||
(x>0 && cardsMap[x][y].equals(cardsMap[x-1][y])) ||
(x<3 && cardsMap[x][y].equals(cardsMap[x+1][y])) ||
(y>0 && cardsMap[x][y].equals(cardsMap[x][y-1])) ||
(y<3 && cardsMap[x][y].equals(cardsMap[x][y+1]))){

complete = false;
break ALL;
}

}

}

if(complete){
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setTitle("哎呦,不好了").setMessage("游戏被你玩完了哦。");
builder.setPositiveButton(R.string.play_again, new DialogInterface.OnClickListener() {

@Override
public void onClick(DialogInterface dialog, int which) {
startGame();
}
});
builder.setNegativeButton(R.string.exit, new DialogInterface.OnClickListener() {

@Override
public void onClick(DialogInterface dialog, int which) {
MainActivity.getMainActivity().quitGame();
}
});
builder.create().show();
}
}

private void slipLeft(){
boolean merge = false;

for (int y = 0; y < 4; y++) {
for (int x = 0; x < 4; x++) {
for (int x1 = x+1; x1 < 4; x1++) { //横轴上比较
if(cardsMap[x1][y].getNum() > 0){ //只对有数的进行操作

if(cardsMap[x][y].getNum() <= 0){ //有空格,则把右边的放到左边来
cardsMap[x][y].setNum(cardsMap[x1][y].getNum());
cardsMap[x1][y].setNum(0);
merge = true;
x--;
}
else if(cardsMap[x][y].equals(cardsMap[x1][y])){ // 如果两个相等,则合并
cardsMap[x][y].setNum(cardsMap[x][y].getNum()*2);
cardsMap[x1][y].setNum(0);
merge = true;
MainActivity.getMainActivity().addScore(cardsMap[x][y].getNum());
}
break;
}

}
}

}
if(merge){
addRandomNum();
checkComplete();
}

}
private void slipRight(){
boolean merge = false;

for (int y = 0; y < 4; y++) {
for (int x = 3; x >= 0; x--) {
for (int x1 = x-1; x1 >= 0; x1--) {
if(cardsMap[x1][y].getNum() > 0){

if(cardsMap[x][y].getNum() <= 0){
cardsMap[x][y].setNum(cardsMap[x1][y].getNum());
cardsMap[x1][y].setNum(0);
merge = true;
x++;
}
else if(cardsMap[x][y].equals(cardsMap[x1][y])){
cardsMap[x][y].setNum(cardsMap[x][y].getNum()*2);
cardsMap[x1][y].setNum(0);
merge = true;
MainActivity.getMainActivity().addScore(cardsMap[x][y].getNum());
}
break;
}

}
}

}
if(merge){
addRandomNum();
checkComplete();
}

}
private void slipUp(){
boolean merge = false;

for (int x = 0; x < 4; x++) {
for (int y = 0; y < 4; y++) {
for (int y1 = y+1; y1 < 4; y1++) {
if(cardsMap[x][y1].getNum() > 0){

if(cardsMap[x][y].getNum() <= 0){
cardsMap[x][y].setNum(cardsMap[x][y1].getNum());
cardsMap[x][y1].setNum(0);
merge = true;
y--;
}
else if(cardsMap[x][y].equals(cardsMap[x][y1])){
cardsMap[x][y].setNum(cardsMap[x][y].getNum()*2);
cardsMap[x][y1].setNum(0);
merge = true;
MainActivity.getMainActivity().addScore(cardsMap[x][y].getNum());
}
break;
}

}
}

}
if(merge){
addRandomNum();
checkComplete();
}

}
private void slipDown(){
boolean merge = false;

for (int x = 0; x < 4; x++) {
for (int y = 3; y >= 0; y--) {
for (int y1 = y-1; y1 >=0; y1--) {
if(cardsMap[x][y1].getNum() > 0){

if(cardsMap[x][y].getNum() <= 0){
cardsMap[x][y].setNum(cardsMap[x][y1].getNum());
cardsMap[x][y1].setNum(0);
merge = true;
y++;
}
else if(cardsMap[x][y].equals(cardsMap[x][y1])){
cardsMap[x][y].setNum(cardsMap[x][y].getNum()*2);
cardsMap[x][y1].setNum(0);
merge = true;
MainActivity.getMainActivity().addScore(cardsMap[x][y].getNum());
}
break;
}

}
}

}
if(merge){
addRandomNum();
checkComplete();
}

}

private Card[][] cardsMap = new Card[4][4];
private List<Point> emptyPoints = new ArrayList<Point>();

}</span><span style="font-size:24px;">
</span>

从代码中可以看出,自定义的GameView组件继承自GridLayout,初始化时设置为4列,设置背景,设置手势监听。
注意:当第一次进入游戏的时候,会调用GamaView的onSizeChanged()方法。如果屏幕横竖切换也会调用,此处为了防止屏幕切换,在配置中添加  android:screenOrientation="portrait"。

2)格子元素


<span style="font-size:14px;">package com.example.game2048;

import android.content.Context;
import android.view.Gravity;
import android.widget.FrameLayout;
import android.widget.TextView;

public class Card extends FrameLayout {
private int num;
private TextView label;

public Card(Context context) {
super(context);

label = new TextView(getContext());
label.setTextSize(32);
label.setBackgroundColor(0X33ffffff);
label.setGravity(Gravity.CENTER);

LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
lp.setMargins(10, 10, 0, 0);
addView(label, lp);

setNum(0);
}

public int getNum() {
return num;
}

public void setNum(int num) {
this.num = num;
if(num <= 0){
label.setText("");
}
else{
label.setText(num+"");
}
}

public boolean equals(Card c){
return getNum() == c.getNum();
}



}
</span>

 格子负责显示数字,用TextView将数字显示出来。


 整体界面效果如下所示: Android手机中的2048游戏Demo开发

2. 游戏逻辑

1) 左右上下移动时,格子该怎么办?

<span style="font-size:14px;">private void slipLeft(){
boolean merge = false;

for (int y = 0; y < 4; y++) {
for (int x = 0; x < 4; x++) {
for (int x1 = x+1; x1 < 4; x1++) { //横轴上比较
if(cardsMap[x1][y].getNum() > 0){ //只对有数的进行操作

if(cardsMap[x][y].getNum() <= 0){ //有空格,则把右边的放到左边来
cardsMap[x][y].setNum(cardsMap[x1][y].getNum());
cardsMap[x1][y].setNum(0);
merge = true;
x--;
}
else if(cardsMap[x][y].equals(cardsMap[x1][y])){ // 如果两个相等,则合并
cardsMap[x][y].setNum(cardsMap[x][y].getNum()*2);
cardsMap[x1][y].setNum(0);
merge = true;
MainActivity.getMainActivity().addScore(cardsMap[x][y].getNum());
}
break;
}

}
}

}
if(merge){
addRandomNum();
checkComplete();
}

}</span>

 从左滑动代码可以看出:逐行检查,看是否有空格,有的话则向左覆盖;有相同的进行合并。右划、上划、下划与此类似。

 2) 随机产生一个2或4的格子添加到界面中

<span style="font-size:14px;">//添加随机数
private void addRandomNum(){

emptyPoints.clear();

for (int y = 0; y < 4; y++) {
for (int x = 0; x < 4; x++) {
if(cardsMap[x][y].getNum() <= 0){
emptyPoints.add(new Point(x,y));
}

}

}

Point p = emptyPoints.remove((int)(Math.random()*emptyPoints.size()));//随机移除一个点
cardsMap[p.x][p.y].setNum(Math.random()>0.1?2:4);

}</span>

 从代码可以看出: 要做到随机,首先是把所有的没有数字的空格放到一起,加入到ArrayList中,然后随机的从这个ArrayList中取出一个空格,按照百分比添加2或者4.

3) 什么情况下,要添加一个带数字的格子到游戏中

 游戏刚进入的时候,需要添加2个随机数,然后,每次当格子有移动,或者有合并,都需要添加一个新的随机数格子到游戏中。

3 游戏结束的判断

<span style="font-size:14px;">private void checkComplete(){
boolean complete = true;

ALL:
for (int y = 0; y < 4; y++) {
for (int x = 0; x < 4; x++) {
if(cardsMap[x][y].getNum() == 0 ||
(x>0 && cardsMap[x][y].equals(cardsMap[x-1][y])) ||
(x<3 && cardsMap[x][y].equals(cardsMap[x+1][y])) ||
(y>0 && cardsMap[x][y].equals(cardsMap[x][y-1])) ||
(y<3 && cardsMap[x][y].equals(cardsMap[x][y+1]))){

complete = false;
break ALL;
}

}

}

if(complete){
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setTitle("哎呦,不好了").setMessage("游戏被你玩完了哦。");
builder.setPositiveButton(R.string.play_again, new DialogInterface.OnClickListener() {

@Override
public void onClick(DialogInterface dialog, int which) {
startGame();
}
});
builder.setNegativeButton(R.string.exit, new DialogInterface.OnClickListener() {

@Override
public void onClick(DialogInterface dialog, int which) {
MainActivity.getMainActivity().quitGame();
}
});
builder.create().show();
}
}</span>

 从代码中可以看出:如果游戏中无空格,或者上下左右没有可以合并的格子,那么游戏结束,弹出提示框。


至此游戏的开发已经大体完成,后面需要润色完善。 本程序的代码如下:http://download.csdn.net/detail/adayabetter/8873769    大家可以下载学习。