http://git.oschina.net/scimence/sci_2048/wikis/home
package com.example.sci_2048;
import java.util.Random;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.graphics.Color;
import android.os.Bundle;
import android.view.Gravity;
import android.view.Menu;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.WindowManager;
import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.ScaleAnimation;
import android.widget.Button;
import android.widget.RelativeLayout;
import android.widget.TextView;
public class MainActivity extends Activity implements OnTouchListener, android.view.View.OnClickListener
{
TextView maxView, scoreView; //当前最大数值, 累积得分值 显示文本框
int maxInt=0, scoreInt=0; //最大数值, 累积得分 数值形式
TextView cell[][] = new TextView[4][4]; //以文本框的形式创建游戏的16个单元格
int num[][] = new int[4][4]; //存储16个单元格对应的数值
int count = 0; //统计当前16个单元格中大于0的数值数目
Button again; //重新开始
public enum Direction { LEFT, RIGHT, UP, DOWN; }//方向
Direction direction = null; //标记屏幕的滑动方向
float x1=-1, y1=-1, x2=-1, y2=-1; //标志触摸按下和触摸释放时的坐标
int cellWidth; //设置游戏中方格的大小
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
View main = creatMainView(); //创建游戏主视图
setContentView(main); //设置为游戏视图
main.setOnTouchListener(this); //添加触摸事件监听,用于响应触摸滑动事件
again.setOnClickListener(this); //重新开始按钮添加事件响应,响应按钮的点击
RandomSite(); //随机在空位置处生成数值2
RandomSite();
refresh(); //刷新界面显示值
}
//创建游戏的主视图,包含3部分:顶部信息、中部4*4方格、底部按钮
@SuppressWarnings("deprecation")
public View creatMainView()
{
//获取屏幕的宽度和高度
WindowManager wm = this.getWindowManager();
int screenWidth = wm.getDefaultDisplay().getWidth();
int screenHeight = wm.getDefaultDisplay().getHeight();
//根据屏幕宽度设置游戏中方格的大小,在屏幕宽度大于高度时,按宽高比重新分配比例,使得高大于宽
cellWidth = screenWidth <= screenHeight ? (screenWidth-10)/4 : (screenHeight*screenHeight/screenWidth-10)/4;
float rat = screenWidth <= screenHeight ? screenWidth / 480 : screenWidth / 480 * screenHeight/screenWidth; //相对于480屏幕大小比例值
int size1 = (int)(28*rat), size2 = (int)(42*rat), size3 = (int)(22*rat);
RelativeLayout main = new RelativeLayout(this);
//游戏信息显示部分
RelativeLayout info = new RelativeLayout(this);
info.setBackgroundColor(0xff074747);
//最值和得分的显示信息,前两个为标签后两个部分用于显示数值
TextView label[] = new TextView[4];
String LText[] = new String[]{"最值", "得分", "0", "0" };
RelativeLayout.LayoutParams paramsL[] = new RelativeLayout.LayoutParams[4];
int ParamsNum[][] = new int[][] //四个文本框的布局参数
{
{RelativeLayout.ALIGN_PARENT_TOP, RelativeLayout.ALIGN_PARENT_LEFT}, {RelativeLayout.ALIGN_PARENT_TOP, RelativeLayout.ALIGN_PARENT_RIGHT},
{RelativeLayout.ALIGN_PARENT_BOTTOM, RelativeLayout.ALIGN_PARENT_LEFT}, {RelativeLayout.ALIGN_PARENT_BOTTOM, RelativeLayout.ALIGN_PARENT_RIGHT}
};
//设置显示信息的布局
for(int i=0; i<4; i++)
{
label[i] = new TextView(this);
label[i].setText(LText[i]);
label[i].setTextSize(size1);
label[i].setTextColor(Color.WHITE);
label[i].setGravity(Gravity.CENTER);
paramsL[i] = new RelativeLayout.LayoutParams((int)(cellWidth*1.1), (int)(cellWidth*0.4));
paramsL[i].addRule(ParamsNum[i][0]);
paramsL[i].addRule(ParamsNum[i][1], RelativeLayout.TRUE);
info.addView(label[i], paramsL[i]);
}
maxView = label[2]; //映射最值到全局变量,便于下次访问
scoreView = label[3];
//游戏主体4*4方格部分
RelativeLayout body = new RelativeLayout(this); //创建一个相对布局的视图
body.setBackgroundColor(Color.BLACK); //为其设置背景色
for(int i=0; i<4; i++)
for(int j=0; j<4; j++)
{
cell[i][j] = new TextView(this); //创建
num[i][j] = 0; //初始时,每个方格中的数值均为0
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(cellWidth, cellWidth);
int left = 2 + j * (2 + cellWidth), top = 2 + i * (2 + cellWidth), right = left + cellWidth, bottom = top + cellWidth; //top属性值由行位置i决定,left由列位置j决定
params.setMargins(left, top, right, bottom); //设置各个方格的布局位置
body.addView(cell[i][j], params); //将表示方格的文本框添加到窗体
cell[i][j].setTextSize(size2); //设置字体大小
cell[i][j].setGravity(Gravity.CENTER); //设置文本布局方式
}
//添加信息显示部分到主界面
RelativeLayout.LayoutParams paramsInfo = new RelativeLayout.LayoutParams((int)(cellWidth*2.2), (int)(cellWidth*0.8));
int right = (int)(screenWidth/2 + (cellWidth*4+10)/2), left = right-(int)(cellWidth*2.2), top = 0, bottom = (int)(cellWidth*0.8);
paramsInfo.setMargins(left, top, right, bottom);
// paramsInfo.addRule(RelativeLayout.ALIGN_PARENT_TOP);
// paramsInfo.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, RelativeLayout.TRUE);
main.addView(info, paramsInfo);
//添加游戏主体部分到主界面
RelativeLayout.LayoutParams paramsBody = new RelativeLayout.LayoutParams(cellWidth*4+10, cellWidth*4+10);
paramsBody.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE);
main.addView(body, paramsBody);
//添加重新开始按钮到主界面
RelativeLayout.LayoutParams paramsAgain = new RelativeLayout.LayoutParams((int)(cellWidth * 1.2), (int)(cellWidth * 0.6));
paramsAgain.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
paramsAgain.addRule(RelativeLayout.CENTER_HORIZONTAL, RelativeLayout.TRUE);
Button btnAgain = new Button(this); //重新开始
btnAgain.setText("重新开始");
btnAgain.setTextSize(size3); //设置字体大小
main.addView(btnAgain, paramsAgain);
again = btnAgain; //映射该按钮到全局变量
return main;
}
//在游戏的空格位置处,随机生成数值2
public void RandomSite()
{
if(count<16) //当16个方格未被数值填满时
{
Random rnd = new Random();
int n = rnd.nextInt(16-count), cN=0; //根据空位置数随机生成一个 数值
for(int i=0; i<4; i++) //将随机数位置转换为在4*4方格中的对应位置
for(int j=0; j<4; j++)
{
if(num[i][j] == 0)
{
if(cN == n)
{
num[i][j] = 2;
count++; //4*4方格中大于0的数目统计
aniScale(cell[i][j]); //设置动画效果
return;
}
else cN++;
}
}
}
}
//消息框
public void messageBox(String str)
{
new AlertDialog.Builder(this)
.setMessage(str)
.setPositiveButton("确定", null)
.show();
}
//当游戏界面被数值填满时,判断是否可以朝某方向合并
public boolean canBeAdd()
{ //分别判定垂直的两个方向是否有相邻数值可以合并即可
if(canBeAdd(Direction.RIGHT))return true;
else return canBeAdd(Direction.DOWN);
}
//当游戏界面被数值填满时,判断是否可以朝指定方向合并,若不可以则游戏结束
public boolean canBeAdd(Direction direction)
{
if(count<16)return true; //未被填满时,可以继续操作
int startN=0, addX=0, addY=0; //起始值、结束值、步增值, x、y方向增量
if(direction == Direction.RIGHT){ startN=3; addX=0; addY=1; }
else if(direction == Direction.LEFT){ startN=0; addX=0; addY=-1; }
else if(direction == Direction.DOWN){ startN=3; addX=1; addY=0; }
else if(direction == Direction.UP){ startN=0; addX=-1; addY=0; }
for(int x=0; x<=3; x++) //对每一行或每一列执行
{
int y=startN;
int i=0, j=0;
if(direction == Direction.RIGHT || direction == Direction.LEFT){ i=x; j=y; }
else { i=y; j=x; }
for(int k = 0; k<3; k++) //4个位置,从某个方向开始对每两个连续位置进行比对,相同则合并,合并顺序为direction的逆序
{
int i1 = i-k*addX, j1 = j-k*addY, i2 = i1-addX, j2 = j1-addY;
if(num[i1][j1]==num[i2][j2] && num[i1][j1]!=0)
{
return true;
}
}
}
return false;
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onTouch(View v, MotionEvent event)
{
//获取触摸拖动起点和终点的坐标,以便于判断触摸移动方向
switch (event.getAction())
{
case MotionEvent.ACTION_DOWN: //触摸屏幕后记录坐标
x1 = event.getX(); //按下点坐标
y1 = event.getY();
break;
case MotionEvent.ACTION_MOVE: //触摸移动
break;
case MotionEvent.ACTION_UP:
x2 = event.getX(); //移动点坐标
y2 = event.getY();
break;
case MotionEvent.ACTION_CANCEL:
}
//进行触摸处理,要求触摸按下和释放点的坐标都存在,且不同,另外我们要求触摸移动的距离大于等于一个方格宽度
if((x1!=-1 && x2!=-1) && (x1!=x2|| y1!=y2)&& (Math.abs(x1 - x2) >= cellWidth || Math.abs(y1 - y2) >= cellWidth))
{
if (x2 - x1 > Math.abs(y2 - y1)) direction = Direction.RIGHT;
else if (x1 - x2 > Math.abs(y2 - y1)) direction = Direction.LEFT;
else if (y2 - y1 > Math.abs(x2 - x1)) direction = Direction.DOWN;
else if (y1 - y2 > Math.abs(x2 - x1)) direction = Direction.UP;
gameProcess(direction); //游戏内部数值处理
refresh(); //根据数组中的数据,刷新显示到界面中
x2 = x1 = -1 ; y2 = y1 = -1; //此句保证每次触摸移动仅处理一次
}
return true;
}
//游戏内部数值处理过程实现,分为3步:朝一个方向叠加、相同数值合并、再次朝该方向叠加
public void gameProcess(Direction direction)
{
boolean flag = false; //标志是否有数值可以下落,或者可以合并
if(Gravaty(direction))flag = true; //控制4*4方格中的数值朝一个方向坠落,叠加
if(add(direction))
{
flag = true;
Gravaty(direction); //数值合并后, 如果有数值合并了,逻辑上方的数值下落
}
if(flag)RandomSite(); //如果有数值下落了或合并了,则随机在一个空位置处生成2
if(count==16 && !canBeAdd()) messageBox("抱歉,此次未能通关");//16个方格都被填满时,判断是否可以朝某个方向合并数值,不能则给出提示信息
}
//控制游戏中数值的坠落方向,该函数实现数值的坠落与叠起,相同数值不合并
public boolean Gravaty(Direction direction)
{
int startN=0, endN=0, step=0, addX=0, addY=0; //起始值、结束值、步增值, x、y方向增量
boolean haveDroped = false; //标志是否有数值下落
if(direction == Direction.RIGHT){ startN=3; endN=0; step=-1; addX=0; addY=1; }
else if(direction == Direction.LEFT){ startN=0; endN=3; step=1; addX=0; addY=-1; }
else if(direction == Direction.DOWN){ startN=3; endN=0; step=-1; addX=1; addY=0; }
else if(direction == Direction.UP){ startN=0; endN=3; step=1; addX=-1; addY=0; }
for(int x=0; x<=3; x++) //对每一行或每一列执行
{
for(int y=startN; (step<0 && y>=endN) || (step>0 && y<=endN); y+=step)
{
int i=0, j=0, i2=-1, j2=-1;
if(direction == Direction.RIGHT || direction == Direction.LEFT){ i=x; j=y; }
else { i=y; j=x; }
i2=i;
j2=j;
//当前方格中的数值不为0,其移动方向一侧的空位置在区域内,其数值为0
while(num[i][j] != 0 && inArea(i2+addX, j2+addY) && num[i2+addX][j2+addY] == 0)
{ //计算该坐标方向的最后一个可用数值为0的位置
i2 += addX;
j2 += addY;
}
if(inArea(i2, j2) && (i!=i2 || j!=j2)) //将坐标处的数值落到最后的空位置
{
num[i2][j2] = num[i][j];
num[i][j] = 0;
haveDroped = true; //有数值下落
}
}
}
return haveDroped;
}
//为视图v添加动画效果,尺寸变化
public void aniScale(View v)
{
v.bringToFront(); //前端显示
AnimationSet aniSet = new AnimationSet(true);
//设置尺寸从0.5倍变化到1.1倍
ScaleAnimation scaleAni = new ScaleAnimation(0.89f, 1.15f, 0.89f, 1.15f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
scaleAni.setDuration(400); //设置动画效果时间
aniSet.addAnimation(scaleAni); //将动画效果添加到动画集中
v.startAnimation(aniSet); //视图v开始动画效果
}
//在Gravaty()处理的基础上,控制相同数值朝指定方向合并
public boolean add(Direction direction)
{
int startN=0, addX=0, addY=0; //起始值、结束值、步增值, x、y方向增量
boolean combined = false; //标记是否有数值合并了
if(direction == Direction.RIGHT){ startN=3; addX=0; addY=1; }
else if(direction == Direction.LEFT){ startN=0; addX=0; addY=-1; }
else if(direction == Direction.DOWN){ startN=3; addX=1; addY=0; }
else if(direction == Direction.UP){ startN=0; addX=-1; addY=0; }
for(int x=0; x<=3; x++) //对每一行或每一列执行
{
int y=startN;
int i=0, j=0;
if(direction == Direction.RIGHT || direction == Direction.LEFT){ i=x; j=y; }
else { i=y; j=x; }
for(int k = 0; k<3; k++) //4个位置,从某个方向开始对每两个连续位置进行比对,相同则合并,合并顺序为direction的逆序
{
int i1 = i-k*addX, j1 = j-k*addY, i2 = i1-addX, j2 = j1-addY;
if(num[i1][j1]==num[i2][j2] && num[i1][j1]!=0)
{
scoreInt += num[i2][j2];//累积分值
num[i1][j1] *= 2;
num[i2][j2] = 0;
combined = true;
count--; //数值合并后,大于0的数值减1
aniScale(cell[i1][j1]); //设置动画效果
if(num[i1][j1] == 2048) messageBox("恭喜,你赢了!");
// if(num[i1][j1] == 2048) Toast.makeText(this, "恭喜,你赢了!", Toast.LENGTH_SHORT).show();
}
}
}
return combined;
}
//判断n1和n2是否均在0到3之间,保证坐标n1,n2在4*4方格范围
public boolean inArea(int n1, int n2)
{
return 0 <= n1 && n1<=3 && 0 <= n2 && n2<=3 ;
}
//刷新游戏方格中的显示值,将4*4数组中的值显示到cell中
public void refresh()
{
for(int i=0; i<4; i++)
for(int j=0; j<4; j++)
{
if( num[i][j]==0 )cell[i][j].setText(""); //数值为0时,清空显示
else cell[i][j].setText(String.valueOf(num[i][j])); //大于0时在方格中显示对应的数值
cell[i][j].setBackgroundColor(getBacColor(num[i][j])); //设置背景色
if( num[i][j]==2 || num[i][j]==4) cell[i][j].setTextColor(0xff776E65);
else cell[i][j].setTextColor(0xfff9f6f2); //设置字体颜色
if(maxInt < num[i][j]) maxInt = num[i][j]; //记录最大数值
}
maxView.setText(String.valueOf(maxInt)); //显示最大值
scoreView.setText(String.valueOf(scoreInt)); //显示分值
}
//获取各数值对应的背景颜色
public int getBacColor(int num)
{
int color[] = new int[]{0xff074747, 0xff999999, 0xffede0c8, 0xfff2b179, 0xfff59563, 0xfff67c5f, 0xfff65e3b, 0xffedcf72, 0xffedcc61, 0xffedc850, 0xffedc53f, 0xffedc22e};
int i=0; //标记颜色数组的下标位置,分别对应数值0、2、4、8、16……
while(num>1)
{
i++;
num/=2;
}
return color[i]; //返回对应颜色值
}
@Override
public void onClick(View v) //重新开始按钮的事件响应
{
new AlertDialog.Builder(this)
// .setTitle("")
.setMessage("确定要重新开始本局吗?")
.setPositiveButton("确定", new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialoginterface, int i)
{
rePlay();
}
})
.setNegativeButton("取消", null)
.show();
}
//重玩游戏,清空游戏数据信息
public void rePlay()
{
//清空数据
maxInt = 0;
scoreInt = 0;
count = 0;
for(int i=0; i<4; i++)
for(int j=0; j<4; j++)
{
num[i][j] = 0;
}
//生成两个随机位置
RandomSite();
RandomSite();
refresh(); //刷新显示
}
}
附件下载:http://git.oschina.net/scimence/sci_2048/attach_files
package com.game.sci_2048;
import java.util.Locale;
import java.util.Random;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.graphics.Color;
import android.os.Bundle;
import android.view.Gravity;
import android.view.Menu;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.WindowManager;
import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.ScaleAnimation;
import android.widget.Button;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.example.sci_2048.R;
public class MainActivity extends Activity implements OnTouchListener, android.view.View.OnClickListener
{
TextView maxView, scoreView; //当前最大数值, 累积得分值 显示文本框
int maxInt=0, scoreInt=0; //最大数值, 累积得分 数值形式
TextView cell[][] = new TextView[4][4]; //以文本框的形式创建游戏的16个单元格
int num[][] = new int[4][4]; //存储16个单元格对应的数值
int count = 0; //统计当前16个单元格中大于0的数值数目
Button again; //重新开始
public enum Direction { LEFT, RIGHT, UP, DOWN; }//方向
Direction direction = null; //标记屏幕的滑动方向
float x1=-1, y1=-1, x2=-1, y2=-1; //标志触摸按下和触摸释放时的坐标
boolean dragProcess = false; //标志是否正在进行拖动处理
int cellWidth; //设置游戏中方格的大小
int screenWidth, screenHeight; //记录屏幕的分辨率
boolean chinese = true; //当前语言环境是否为中文
Random rnd = new Random(); //用于游戏中随机数的生成
boolean flagmin = false; //标记是否取最小值为生成值
int[] minNum = {1, 1}; //初始值,分别表示最小值和次小值
int preminNum = 1; //前一个最小值
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
View main = creatMainView(); //创建游戏主视图
setContentView(main); //设置为游戏视图
main.setOnTouchListener(this); //添加触摸事件监听,用于响应触摸滑动事件
again.setOnClickListener(this); //重新开始按钮添加事件响应,响应按钮的点击
RandomSite(); //随机在空位置处生成数值2
RandomSite();
refresh(); //刷新界面显示值
messageBox((chinese ? "屏幕分辨率为:":"Screen resolution:") + screenWidth + "x" + screenHeight); //显示屏幕的分辨率
}
//创建游戏的主视图,包含3部分:顶部信息、中部4*4方格、底部按钮
@SuppressWarnings("deprecation")
public View creatMainView()
{
String str = Locale.getDefault().getLanguage(); //获取当前的语言环境
if(!str.equals("zh")) chinese = false;
//获取屏幕的宽度和高度
WindowManager wm = this.getWindowManager();
screenWidth = wm.getDefaultDisplay().getWidth();
screenHeight = wm.getDefaultDisplay().getHeight();
//根据屏幕宽度设置游戏中方格的大小,在屏幕宽度大于高度时,按宽高比重新分配比例,使得高大于宽
cellWidth = screenWidth <= screenHeight ? (screenWidth-10)/4 : (screenHeight*screenHeight/screenWidth-10)/4;
float rat = screenWidth <= screenHeight ? screenWidth / 480 : screenWidth / 480 * screenHeight/screenWidth; //相对于480屏幕大小比例值
int size1 = (int)(22*rat), size2 = (int)(28*rat), size3 = (int)(22*rat);
RelativeLayout main = new RelativeLayout(this);
//游戏信息显示部分
RelativeLayout info = new RelativeLayout(this);
info.setBackgroundColor(getBacColor(0));
//最值和得分的显示信息,前两个为标签后两个部分用于显示数值
TextView label[] = new TextView[4];
String LText[] = chinese ? new String[]{"最值", "得分", "0", "0" } : new String[]{"Max", "Score", "0", "0" };
RelativeLayout.LayoutParams paramsL[] = new RelativeLayout.LayoutParams[4];
int ParamsNum[][] = new int[][] //四个文本框的布局参数
{
{RelativeLayout.ALIGN_PARENT_TOP, RelativeLayout.ALIGN_PARENT_LEFT}, {RelativeLayout.ALIGN_PARENT_TOP, RelativeLayout.ALIGN_PARENT_RIGHT},
{RelativeLayout.ALIGN_PARENT_BOTTOM, RelativeLayout.ALIGN_PARENT_LEFT}, {RelativeLayout.ALIGN_PARENT_BOTTOM, RelativeLayout.ALIGN_PARENT_RIGHT}
};
//设置显示信息的布局
for(int i=0; i<4; i++)
{
label[i] = new TextView(this);
label[i].setText(LText[i]);
label[i].setTextSize(size1);
label[i].setTextColor(Color.WHITE);
label[i].setGravity(Gravity.CENTER);
paramsL[i] = new RelativeLayout.LayoutParams((int)(cellWidth*1.1), (int)(cellWidth*0.4));
paramsL[i].addRule(ParamsNum[i][0]);
paramsL[i].addRule(ParamsNum[i][1], RelativeLayout.TRUE);
info.addView(label[i], paramsL[i]);
}
maxView = label[2]; //映射最值到全局变量,便于下次访问
scoreView = label[3];
//游戏主体4*4方格部分
RelativeLayout body = new RelativeLayout(this); //创建一个相对布局的视图
body.setBackgroundColor(Color.BLACK); //为其设置背景色
for(int i=0; i<4; i++)
for(int j=0; j<4; j++)
{
cell[i][j] = new TextView(this); //创建
num[i][j] = 0; //初始时,每个方格中的数值均为0
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(cellWidth, cellWidth);
int left = 2 + j * (2 + cellWidth), top = 2 + i * (2 + cellWidth), right = left + cellWidth, bottom = top + cellWidth; //top属性值由行位置i决定,left由列位置j决定
params.setMargins(left, top, right, bottom); //设置各个方格的布局位置
body.addView(cell[i][j], params); //将表示方格的文本框添加到窗体
cell[i][j].setTextSize(size2); //设置字体大小
cell[i][j].setGravity(Gravity.CENTER); //设置文本布局方式
}
//添加信息显示部分到主界面
RelativeLayout.LayoutParams paramsInfo = new RelativeLayout.LayoutParams((int)(cellWidth*2.2), (int)(cellWidth*0.8));
int right = (int)(screenWidth/2 + (cellWidth*4+10)/2), left = right-(int)(cellWidth*2.2), top = 0, bottom = (int)(cellWidth*0.8);
paramsInfo.setMargins(left, top, right, bottom);
// paramsInfo.addRule(RelativeLayout.ALIGN_PARENT_TOP);
// paramsInfo.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, RelativeLayout.TRUE);
main.addView(info, paramsInfo);
//添加游戏主体部分到主界面
RelativeLayout.LayoutParams paramsBody = new RelativeLayout.LayoutParams(cellWidth*4+10, cellWidth*4+10);
paramsBody.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE);
main.addView(body, paramsBody);
//添加重新开始按钮到主界面
RelativeLayout.LayoutParams paramsAgain = new RelativeLayout.LayoutParams((int)(cellWidth * 1.7), (int)(cellWidth * 0.8));
paramsAgain.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
paramsAgain.addRule(RelativeLayout.CENTER_HORIZONTAL, RelativeLayout.TRUE);
Button btnAgain = new Button(this); //重新开始
btnAgain.setText(chinese ? "重新开始" : "Play Again");
btnAgain.setTextSize(size3); //设置字体大小
main.addView(btnAgain, paramsAgain);
again = btnAgain; //映射该按钮到全局变量
return main;
}
//在游戏的空格位置处,随机生成数值2
public void RandomSite()
{
if(count<16) //当16个方格未被数值填满时
{
rnd.setSeed(rnd.nextLong()); //随机数进一步随机化
int n = rnd.nextInt(16-count), cN=0; //根据空位置数随机生成一个 数值
for(int i=0; i<4; i++) //将随机数位置转换为在4*4方格中的对应位置
for(int j=0; j<4; j++)
{
if(num[i][j] == 0)
{
if(cN == n)
{
flagmin = !flagmin; //取反
num[i][j] = flagmin ? minNum[0] : minNum[1];//设置新生成的数
count++; //4*4方格中大于0的数目统计
aniScale(cell[i][j]); //设置动画效果
minNum = getMinNum(); //动态获取新的最小值和次小值
if(preminNum != minNum[0])
{
preminNum = minNum[0]; //新的最小值
Toast.makeText(this, (chinese ? "恭喜,最小值进阶": "Congratulations, the minimum advanced to ")+ preminNum, Toast.LENGTH_SHORT).show();
}
return;
}
else cN++;
}
}
}
}
//取得最小值和次小值,默认最小值1
private int[] getMinNum()
{
int minNum = 2048, bigerNum = 2048; //最小值、次最小值
for(int i=0; i<4; i++)
for(int j=0; j<4; j++)
{
if(num[i][j] != 0) //0值不算在内
{
if(num[i][j]= cellWidth || Math.abs(y1 - y2) >= cellWidth))
{
dragProcess = true;
if (x2 - x1 > Math.abs(y2 - y1)) direction = Direction.RIGHT;
else if (x1 - x2 > Math.abs(y2 - y1)) direction = Direction.LEFT;
else if (y2 - y1 > Math.abs(x2 - x1)) direction = Direction.DOWN;
else if (y1 - y2 > Math.abs(x2 - x1)) direction = Direction.UP;
gameProcess(direction); //游戏内部数值处理
refresh(); //根据数组中的数据,刷新显示到界面中
x2 = x1 = -1 ; y2 = y1 = -1; //此句保证每次触摸移动仅处理一次
dragProcess = false;
}
return true;
}
//游戏内部数值处理过程实现,分为3步:朝一个方向叠加、相同数值合并、再次朝该方向叠加
public void gameProcess(Direction direction)
{
boolean flag = false; //标志是否有数值可以下落,或者可以合并
if(Gravaty(direction))flag = true; //控制4*4方格中的数值朝一个方向坠落,叠加
if(add(direction))
{
flag = true;
Gravaty(direction); //数值合并后, 如果有数值合并了,逻辑上方的数值下落
}
if(flag)RandomSite(); //如果有数值下落了或合并了,则随机在一个空位置处生成2
if(count==16 && !canBeAdd()) messageBox(chinese ? "抱歉,此次未能通关": "Sorry, Failed to pass");//16个方格都被填满时,判断是否可以朝某个方向合并数值,不能则给出提示信息
}
//控制游戏中数值的坠落方向,该函数实现数值的坠落与叠起,相同数值不合并
public boolean Gravaty(Direction direction)
{
int startN=0, endN=0, step=0, addX=0, addY=0; //起始值、结束值、步增值, x、y方向增量
boolean haveDroped = false; //标志是否有数值下落
if(direction == Direction.RIGHT){ startN=3; endN=0; step=-1; addX=0; addY=1; }
else if(direction == Direction.LEFT){ startN=0; endN=3; step=1; addX=0; addY=-1; }
else if(direction == Direction.DOWN){ startN=3; endN=0; step=-1; addX=1; addY=0; }
else if(direction == Direction.UP){ startN=0; endN=3; step=1; addX=-1; addY=0; }
for(int x=0; x<=3; x++) //对每一行或每一列执行
{
for(int y=startN; (step<0 && y>=endN) || (step>0 && y<=endN); y+=step)
{
int i=0, j=0, i2=-1, j2=-1;
if(direction == Direction.RIGHT || direction == Direction.LEFT){ i=x; j=y; }
else { i=y; j=x; }
i2=i;
j2=j;
//当前方格中的数值不为0,其移动方向一侧的空位置在区域内,其数值为0
while(num[i][j] != 0 && inArea(i2+addX, j2+addY) && num[i2+addX][j2+addY] == 0)
{ //计算该坐标方向的最后一个可用数值为0的位置
i2 += addX;
j2 += addY;
}
if(inArea(i2, j2) && (i!=i2 || j!=j2)) //将坐标处的数值落到最后的空位置
{
num[i2][j2] = num[i][j];
num[i][j] = 0;
haveDroped = true; //有数值下落
}
}
}
return haveDroped;
}
//为视图v添加动画效果,尺寸变化
public void aniScale(View v)
{
v.bringToFront(); //前端显示
AnimationSet aniSet = new AnimationSet(true);
//设置尺寸从0.5倍变化到1.1倍
ScaleAnimation scaleAni = new ScaleAnimation(0.89f, 1.15f, 0.89f, 1.15f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
scaleAni.setDuration(400); //设置动画效果时间
aniSet.addAnimation(scaleAni); //将动画效果添加到动画集中
v.startAnimation(aniSet); //视图v开始动画效果
}
//在Gravaty()处理的基础上,控制相同数值朝指定方向合并
public boolean add(Direction direction)
{
int startN=0, addX=0, addY=0; //起始值、结束值、步增值, x、y方向增量
boolean combined = false; //标记是否有数值合并了
if(direction == Direction.RIGHT){ startN=3; addX=0; addY=1; }
else if(direction == Direction.LEFT){ startN=0; addX=0; addY=-1; }
else if(direction == Direction.DOWN){ startN=3; addX=1; addY=0; }
else if(direction == Direction.UP){ startN=0; addX=-1; addY=0; }
for(int x=0; x<=3; x++) //对每一行或每一列执行
{
int y=startN;
int i=0, j=0;
if(direction == Direction.RIGHT || direction == Direction.LEFT){ i=x; j=y; }
else { i=y; j=x; }
for(int k = 0; k<3; k++) //4个位置,从某个方向开始对每两个连续位置进行比对,相同则合并,合并顺序为direction的逆序
{
int i1 = i-k*addX, j1 = j-k*addY, i2 = i1-addX, j2 = j1-addY;
if(num[i1][j1]==num[i2][j2] && num[i1][j1]!=0)
{
scoreInt += num[i2][j2];//累积分值
num[i1][j1] *= 2;
num[i2][j2] = 0;
combined = true;
count--; //数值合并后,大于0的数值减1
if(k==2 && num[i1+addX][j1+addY]==0) //判断前一处是否为空
aniScale(cell[i1+addX][j1+addY]); //如果0与1位置已合并,则在2与3合并时 在1处设置动画
else aniScale(cell[i1][j1]); //设置动画效果
if(num[i1][j1] == 2048) messageBox(chinese ? "恭喜,你赢了!":"Congratulations, you win.");
// if(num[i1][j1] == 2048) Toast.makeText(this, "恭喜,你赢了!", Toast.LENGTH_SHORT).show();
}
}
}
return combined;
}
//判断n1和n2是否均在0到3之间,保证坐标n1,n2在4*4方格范围
public boolean inArea(int n1, int n2)
{
return 0 <= n1 && n1<=3 && 0 <= n2 && n2<=3 ;
}
//刷新游戏方格中的显示值,将4*4数组中的值显示到cell中
public void refresh()
{
for(int i=0; i<4; i++)
for(int j=0; j<4; j++)
{
if( num[i][j]==0 )cell[i][j].setText(""); //数值为0时,清空显示
else cell[i][j].setText(String.valueOf(num[i][j])); //大于0时在方格中显示对应的数值
cell[i][j].setBackgroundColor(getBacColor(num[i][j])); //设置背景色
if(num[i][j]<=32) cell[i][j].setTextColor(0xff000000);
else cell[i][j].setTextColor(0xffffffff); //设置字体颜色
if(maxInt < num[i][j]) maxInt = num[i][j]; //记录最大数值
}
maxView.setText(String.valueOf(maxInt)); //显示最大值
scoreView.setText(String.valueOf(scoreInt)); //显示分值
}
//获取各数值对应的背景颜色
public int getBacColor(int num)
{
// int color[] = new int[]{0xff074747, 0xff999999, 0xffede0c8, 0xfff2b179, 0xfff59563, 0xfff67c5f, 0xfff65e3b, 0xffedcf72, 0xffedcc61, 0xffedc850, 0xffedc53f, 0xffedc22e, 0xffB3CDE6};
int color[] = new int[]{0xff074747, 0xffb2b6bb, 0xffd6c198, 0xfffacc76, 0xfff3ca45, 0xffffab3a, 0xffffa863, 0xffffa58c, 0xffee6668, 0xffbf2128, 0xffb93240, 0xff9e2e44, 0xff832a48};
int i=0; //标记颜色数组的下标位置,分别对应数值0、1、2、4、8、16……
while(num>=1)
{
i++;
num/=2;
}
return color[i]; //返回对应颜色值
}
@Override
public void onClick(View v) //重新开始按钮的事件响应
{
new AlertDialog.Builder(this)
// .setTitle("")
.setMessage(chinese ? "确定要重新开始本局吗?":"Sure you want to start again?")
.setPositiveButton(chinese ? "确定" : "Yes", new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialoginterface, int i)
{
rePlay();
}
})
.setNegativeButton(chinese ? "取消": "No", null)
.show();
}
//重玩游戏,清空游戏数据信息
public void rePlay()
{
//清空数据
maxInt = 0;
scoreInt = 0;
count = 0;
flagmin = false; //标记是否取最小值为生成值
minNum = new int[]{1, 1}; //初始值,分别表示最小值和次小值
preminNum = 1; //前一个最小值
for(int i=0; i<4; i++)
for(int j=0; j<4; j++)
num[i][j] = 0;
//生成两个随机位置
RandomSite();
RandomSite();
refresh(); //刷新显示
}
////重玩游戏,清空游戏数据信息
// public void rePlay()
// {
// //清空数据
// maxInt = 0;
// scoreInt = 0;
//// count = 0;
// count = 11;
//
// flagmin = false; //标记是否取最小值为生成值
// minNum = new int[]{1, 1}; //初始值,分别表示最小值和次小值
// preminNum = 1; //前一个最小值
//
// int[][] tmp =
// {
// {1,0,0,32},
// {2,0,16,256},
// {0,8,128,1024},
// {4,64,512,2048}
// };
//
// for(int i=0; i<4; i++)
// for(int j=0; j<4; j++)
// {
//// num[i][j] = 0;
// num[i][j] = tmp[i][j];
// }
//
// //生成两个随机位置
//// RandomSite();
//// RandomSite();
//
// refresh(); //刷新显示
// }
}