安卓2048小游戏源码

来源:互联网 发布:知乎 女生 打男朋友 编辑:程序博客网 时间:2024/06/07 01:14


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;    }@Overridepublic 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();//如果有数值下落了或合并了,则随机在一个空位置处生成2if(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,其移动方向一侧的空位置在区域内,其数值为0while(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的数值减1aniScale(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];//返回对应颜色值}@Overridepublic 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



2 0
原创粉丝点击