Android手机中的2048游戏Demo开发

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

1.游戏中的几个关键点

1)界面

2048游戏的操作界面就是一个4X4的方格。如下图所示:

游戏首先要绘制出该界面。

@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将数字显示出来。

整体界面效果如下所示:

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    大家可以下载学习。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-10 05:50:24

Android手机中的2048游戏Demo开发的相关文章

基于C/S模式的android手机与PC机通信系统的开发

原文链接: http://blog.csdn.net/nupt123456789/article/details/8213486 基于C/S模式的android手机与PC机通信系统的开发 作者:郑海波 单位:南京邮电大学 通信与信息工程学院 信号与信息处理 6班 学号:1012010638 邮箱:[email protected] -----------------------------------------------------------------------------------

快捷地安装apk文件到android手机中

在pc中,在没有安装各种手机助手的情况下,android程序员如何快捷地(对apk文件双击,即可自动安装,不用手动输命令)安装apk文件到android手机中? 可以使用以下方法:使用批处理文件 + Quick Batch File (De)Compiler 步骤: 1.编写以下dos命令,并保存为apk.bat @echo off echo 正在连接手机... adb wait-for-device echo. rem 获取双击apk文件的绝对路径 set apk=%* echo 正在安装:%

如何从android手机中把自己的数据库给COPY出来

============问题描述============ 自己写个APK,安装在android手机,程序运行时会创建一个SQLITE的数据库: 用eclipse,可以看到数据库的位置,我把手机插入电脑,打USB连接后,却不能在手机中找到数据库文件(APK绝对是安装在SD卡上的),有人说要有ROOT的权限.不知如何实现,如果要写一个程序来实现,请高手指点思想,列出相关重点函数,谢谢 ============解决方案1============ 自己的应用复制自己的数据库,无需root,直接文件复制就

命令行从Android手机中导出已安装APK的方法调研

一.背景 二.步骤 一.背景 很多时候,APK文件只存在于应用市场,在PC上无法直接下载.用手机下载下来后就直接安装了,也不能保存原始的APK文件. APK安装到手机后,Android系统会保存一份和原始APK一模一样的拷贝,位于data/app目录,文件名为“APK的包名-1.apk”或者“APK的包名-2.apk”.这里的包名即 package name,形如 com.xxx.xxx. data/app这个目录在非root的情况下,是无法直接查看的.但幸运的是,这个目录下所有的APK文件,是

用ADT的FileExplorer查看android手机中的数据库

在这之前首先手机要打开ROOT权限,可以借助安卓刷机精灵等一键ROOT软件 其次像魅族.小米等手机拿到ROOT以后不能执行su命令,所以无法给手机中的文件授权,需要下载一个SuperSU权限管理器 有了他们我们就可以开始下面的步骤了: 1.window->show view->other 2. 输入 file 查找 3. 出来了吧 4. 可惜啊,data文件夹死活打不开啊, 看这个办法 当然在这之前需要把SDK配置到环境变量里面去,这里不再赘述,大家可以去搜索如何配置 On rooted de

Android手机摇一摇之传感器开发

[声明]转载请注明出处,此文出自指尖飞落的博客:http://blog.csdn.net/huntersnail --尊重作者,知识无价,交流无限! 一.手机摇晃计算 1.手机摇晃的动作 2.一个点三个轴X.Y.Z ①计算从a--b的增量:a点到b点各个轴相减之和 假设a(x1,y1,z1).b(x2,y2,z2) 增量ab=(x2-x1)+(y2-y1)+(z2-z1) ②将所有的增量进行汇总,得到一个大的增量,假设是N.并进行判断: 如果N>=设定的域值M,则确定在摇晃手机. 说明:N=ab

从root的android手机中导出app的db文件

前提:手机已经root: 1.手机连接电脑,打开Cmd,运行命令 adb shell;//因为android用的Linux内核,很多linux的命令,在Android也可以用 2.使用root权限, su:如果没有root,会提示 3.给文件添加权限,db文件存放的路径是:,要逐级给每个文件夹都添加权限, chmod 777 /data; chmod 777 /data/data/ ... chmod 777 /data/data/packname/databases/db_file 4.把db

ionic ng-src 在网页显示,但是导出apk在android手机中运行不显示图片

解决方法参照: http://stackoverflow.com/questions/29896158/load-image-using-ng-src-in-android-ionic-aplication 步骤: (1)安装 cordova-plugin-whitelist [email protected]:myapp1$ cordova plugins add cordova-plugin-whitelist (2)确保config.xml配置文件 <access origin="*

Android实战技巧之十八:adb取出安装在手机中的apk

场景: 朋友看见你Android手机中的游戏或应用很好玩,也想装一个此程序,但限于网络条件不能从网上下载.那么最简单的办法就是直接从你手机中将此apk扣出来给他安装上. pm命令 第一步,找到程序的包名 借助adb shell pm命令,将安装的所有应用包名列出来: $ adb shell pm list packages package:android package:cn.wps.moffice package:com.android.backupconfirm package:com.an