现在我们要实现一个2048的游戏,那么开始吧~
首先我们先来把布局给实现了~2048是一个4*4的平面游戏,那么就要用到GridLayout,我们先写将其嵌入在一个LinearLayout中,请看代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<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:textAppearance="?android:attr/textAppearanceLarge"
android:text="@string/Score" />
<TextView
android:id="@+id/tvScore"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textAppearance="?android:attr/textAppearanceLarge"/>
<Button
android:id="@+id/my_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/newGame"
android:textAppearance="?android:attr/textAppearanceLarge"
/>
</LinearLayout>
<com.example.game2048.GameView
android:id="@+id/gameView"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1" >
</com.example.game2048.GameView>
</LinearLayout>
创建一个游戏类GameView,其继承自布局GridLayout,并这个类绑定在activity_main.xml的GridLayout上,具体操作如下
1:鼠标移至GameView处,其自动浮现类的路径,复制
2:替换关键字GridLayout
GameView的代码,要向AndroidMainfest.xml的activity添加属性 android:screenOrientation="portrait"
public class GameView extends GridLayout {
private Card[][] cardsMap=new Card[4][4];
private List<Point> emptyPoints=new ArrayList<Point>();
// 保险起见,把三个构造函数全部都添加了
public GameView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initGameView();
}// 构造函数1
public GameView(Context context, AttributeSet attrs) {
super(context, attrs);
initGameView();
}// 构造函数2
public GameView(Context context) {
super(context);
initGameView();
}// 构造函数3
private void initGameView(){//启动游戏
setColumnCount(4);//设置为4列
setBackgroundColor(0xffbbada0);//设置游戏背景颜色
setOnTouchListener(new View.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();//获得起始的x坐标
startY=event.getY();//获得起始的y坐标
break;
case MotionEvent.ACTION_UP://手指触碰后
offsetX=event.getX()-startX;//获得偏移的x坐标
offsetY=event.getY()-startY;//获得偏移的y坐标
if(Math.abs(offsetX)>Math.abs(offsetY)){//水平位移大于竖直位移,说明是在水平方向上动的
if(offsetX<-5){
swipeLeft();
}else if(offsetX>5){
swipeRight();
}
}
else{
if(offsetY<-5){
swipeUp();
}else if(offsetY>5){
swipeDown();
}
}
break;
}
return true;//返回true事件发生
}
});
}
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||//如果一个格子不为0并且它上下左右有跟它相等的数,则游戏不结束
(x>1&&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){
new AlertDialog.Builder(getContext()).setTitle("Hello").setMessage("游戏结束 ").setPositiveButton("重来 ", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
startGame();
}
}).show();
}
}
@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 cardHeight,int cardWidth){
Card c;
for(int y=0;y<4;y++){
for(int x=0;x<4;x++){
c=new Card(getContext());
c.setNum(0);
addView(c, cardWidth, cardHeight);
cardsMap[x][y]=c;
}
}
}
public void startGame(){
MainActivity.getMainActivity().clearScore();//分数清零
for(int y=0;y<4;y++){//原先可能不为0,所以要先清0
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);//2生成的概率是4的9倍
}
private void swipeLeft() {
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++){//从当前位置往右遍历,只遍历3列
if(cardsMap[x1][y].getNum()>0){//找到一个当前格子大于0的
if(cardsMap[x][y].getNum()<=0){//与当前格同一行的,且在其前面的(列方向),是空白的
cardsMap[x][y].setNum(cardsMap[x1][y].getNum());//将当前格子的数字移到空白格处
cardsMap[x1][y].setNum(0);//当前格清零
x--;
merge=true;
}else if(cardsMap[x][y].equals(cardsMap[x1][y])){//如果当前格和同行某一格数值相等,则合并
cardsMap[x][y].setNum(cardsMap[x][y].getNum()*2);
cardsMap[x1][y].setNum(0);
MainActivity.getMainActivity().addScore(cardsMap[x][y].getNum());//计分
merge=true;
}
break;
}
}
}
}
if(merge){
addRandomNum();
checkComplete();
}
}
private void swipeRight() {
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--){//从当前位置往右遍历,只遍历3列
if(cardsMap[x1][y].getNum()>0){//找到一个当前格子大于0的
if(cardsMap[x][y].getNum()<=0){//与当前格同一行的,且在其前面的(列方向),是空白的
cardsMap[x][y].setNum(cardsMap[x1][y].getNum());//将当前格子的数字移到空白格处
cardsMap[x1][y].setNum(0);//当前格清零
x++;
merge=true;
}else if(cardsMap[x][y].equals(cardsMap[x1][y])){//如果当前格和同行某一格数值相等,则合并
cardsMap[x][y].setNum(cardsMap[x][y].getNum()*2);
cardsMap[x1][y].setNum(0);
MainActivity.getMainActivity().addScore(cardsMap[x][y].getNum());//计分
merge=true;
}
break;
}
}
}
}
if(merge){
addRandomNum();
checkComplete();
}
}
private void swipeUp() {
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++){//从当前位置往右遍历,只遍历3列
if(cardsMap[x][y1].getNum()>0){//找到一个当前格子大于0的
if(cardsMap[x][y].getNum()<=0){//与当前格同一行的,且在其前面的(列方向),是空白的
cardsMap[x][y].setNum(cardsMap[x][y1].getNum());//将当前格子的数字移到空白格处
cardsMap[x][y1].setNum(0);//当前格清零
y--;
merge=true;
}else if(cardsMap[x][y].equals(cardsMap[x][y1])){//如果当前格和同行某一格数值相等,则合并
cardsMap[x][y].setNum(cardsMap[x][y].getNum()*2);
cardsMap[x][y1].setNum(0);
MainActivity.getMainActivity().addScore(cardsMap[x][y].getNum());//计分
merge=true;
}
break;
}
}
}
}
if(merge){
addRandomNum();
checkComplete();
}
}
private void swipeDown() {
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--){//从当前位置往右遍历,只遍历3列
if(cardsMap[x][y1].getNum()>0){//找到一个当前格子大于0的
if(cardsMap[x][y].getNum()<=0){//与当前格同一行的,且在其前面的(列方向),是空白的
cardsMap[x][y].setNum(cardsMap[x][y1].getNum());//将当前格子的数字移到空白格处
cardsMap[x][y1].setNum(0);//当前格清零
y++;
}else if(cardsMap[x][y].equals(cardsMap[x][y1])){//如果当前格和同行某一格数值相等,则合并
cardsMap[x][y].setNum(cardsMap[x][y].getNum()*2);
cardsMap[x][y1].setNum(0);
MainActivity.getMainActivity().addScore(cardsMap[x][y].getNum());//计分
}
break;
}
}
}
}
if(merge){
addRandomNum();
checkComplete();
}
}
}
接下来要创建一个纸牌类,来创建卡片,类名为Card
public class Card extends FrameLayout {
private int num=0;
private TextView label;
private View background;
public Card(Context context) {
super(context);
LayoutParams lp = null;
lp = new LayoutParams(-1, -1);//填满父容器
lp.setMargins(10, 10, 0, 0);//设置每个文本之间的距离
background = new View(getContext());
background.setBackgroundColor(0x33ffffff);//设置第二层的背景颜色
addView(background, lp);//加入布局中
label = new TextView(getContext());
label.setTextSize(28);
label.setGravity(Gravity.CENTER);//使数字居中
lp = new LayoutParams(-1, -1);//第三层背景
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("");//如果数小于等于0,设置空字符
}else{
String s=Integer.toString(num);
label.setText(s);
}
switch (num) {//设置相应数字对应的颜色
case 0:
label.setBackgroundColor(0x00000000);
break;
case 2:
label.setBackgroundColor(0xffeee4da);
break;
case 4:
label.setBackgroundColor(0xffede0c8);
break;
case 8:
label.setBackgroundColor(0xfff2b179);
break;
case 16:
label.setBackgroundColor(0xfff59563);
break;
case 32:
label.setBackgroundColor(0xfff67c5f);
break;
case 64:
label.setBackgroundColor(0xfff65e3b);
break;
case 128:
label.setBackgroundColor(0xffedcf72);
break;
case 256:
label.setBackgroundColor(0xffedcc61);
break;
case 512:
label.setBackgroundColor(0xffedc850);
break;
case 1024:
label.setBackgroundColor(0xffedc53f);
break;
case 2048:
label.setBackgroundColor(0xffedc22e);
break;
default:
label.setBackgroundColor(0xff3c3a32);
break;
}
}
public boolean equals(Card o){
return getNum()==o.getNum();//判断卡片的内容是否相等
}
}
最后是MainActivity的实现
public class MainActivity extends Activity {
private TextView tvScore;
private static MainActivity mainActivity=null;//构造一个MainActivity实例变量,可以方便获取
private int score=0;
private Button my_button;
private GameView gameView;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_game);
tvScore=(TextView) findViewById(R.id.tvScore);
gameView=(GameView) findViewById(R.id.gameView);
my_button=(Button) findViewById(R.id.my_button);
my_button.setOnClickListener(new OnClickListener() {//重新开始
@Override
public void onClick(View v) {
gameView.startGame();
}
});
}
public MainActivity(){
mainActivity=this;
}
public static MainActivity getMainActivity() {
return mainActivity;
}
public void clearScore(){//清零
score=0;
showScore();
}
public void showScore(){//显示分数
tvScore.setText(score+"");
}
public void addScore(int s){//加分
score+=s;
showScore();
}
}
最后来一些游戏截图吧~
----------------------------晴天_1993----------------------------