Android学习之2048游戏

在网上学习了2048的Android开发过程,大大提高了学习热情,今晚终于完成了基本功能,记录一下。


核心程序: 

MainActivity.java    程序的入口,分数的记录与显示

GameView.java   程序主界面的布局与背景,检测手势的方向,4*4方块的边长与显示,添加随机数,检测游戏结束

Card.java               每个块的间距、显示数字、背景


详细内容:

1、MainActivity.java

package com.example.game2048;

import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.widget.TextView;

public class MainActivity extends Activity {

	private int score = 0;
	private TextView tvScore;
	private static MainActivity mainActivity = null;
	
	
	public MainActivity() {
		mainActivity = this;
	}
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		tvScore = (TextView) findViewById(R.id.tvScore);
	}

	@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;
	}
	
	public void clearScore(){
		score = 0;
		showScore();
	}
	
	public void addScore(int s){
		score += s;
		showScore();
	}
	
	public void showScore(){
		tvScore.setText(score+"");
	}

	
	public static MainActivity getMainActivity(){
		return mainActivity;
	}
	

}

2、GameView.java

package com.example.game2048;

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

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

public class GameView extends GridLayout {

	public GameView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		initGameView();
	}

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

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

	}

	private Card[][] cardsMap = new Card[4][4];//记录卡片的二维数组 方便使用
	private List<Point> emptyPoints = new ArrayList<Point>();//把所有卡片
	
	private void initGameView(){
		
		setColumnCount(4);//设置gridLayout4列
		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();
					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){
							swipLeft();
						}else if(offsetX > 5){
							swipRight();
						}
					}else{
						
						if(offsetY < -5){
							swipUp();
						}else if(offsetY > 5){
							swipDown();
						}
						
					}
					
					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; //边缘留10像素的空白
		addCards(cardWidth,cardWidth);        //加入4*4的卡片
		startGame();
	}
	
	//4*4的卡片
	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);
				addView(c,cardWidth,cardHeight);
				
				cardsMap[x][y] = c;
			}
			
		}

	}
	
	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()));//随机移去一个点,和用get一样 random是0到1之间
		cardsMap[p.x][p.y].setNum(Math.random()>0.1?2:4);//出现2与4的比例为9:1
	}
	
	private void swipLeft(){
		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);//获取的卡片设为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 swipRight(){
		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);//获取的卡片设为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 swipUp(){
		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);//获取的卡片设为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 swipDown(){
		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);//获取的卡片设为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();
		}
		
		
	}
	
	//检查游戏结束,只要有0(即空卡片)或者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]))||  //往右判断 
<span style="white-space:pre">							</span>(y>0 && cardsMap[x][y].equals(cardsMap[x][y-1]))||
							(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("你好").setMessage("游戏结束").setPositiveButton("重来", new DialogInterface.OnClickListener() {
				
				@Override
				public void onClick(DialogInterface arg0, int arg1) {
					// TODO Auto-generated method stub
					startGame();
					
				}
			}).show();
			

		}
		
	}
	

}

3、Card.java

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 {

	public Card(Context context) {
		super(context);
		
		label = new TextView(getContext());
		label.setTextSize(32);
		label.setGravity(Gravity.CENTER);//设置文字居中
		label.setBackgroundColor(0x33ffffff);
		
		LayoutParams lp = new LayoutParams(-1, -1);//-1 -1 填充满
		lp.setMargins(10, 10, 0, 0);//设置卡片与卡片之间的间距 左10 上10 右0 下0
		addView(label,lp);
				
		setNum(0);
	}


	private int num = 0;
	
	public int getNum(){
		return num;
	}
	
	public void setNum(int num) {
		this.num = num;
		
		//出现0的数设为空字符串
		if(num <= 0)
		{
			label.setText("");
		}
		else{
			label.setText(num+"");//转化成 字符串 类型
		}
		
	}
	
	public boolean equals(Card o) {
		return getNum() == o.getNum();
		
	}
	
	private TextView label;
}


4、activity_main.xml

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

    <LinearLayout
        android:layout_width="fill_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="fill_parent"
        android:layout_height="0dp"
        android:layout_weight="1" >
    </com.example.game2048.GameView>

</LinearLayout>


5、AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.game2048"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="14"
        android:targetSdkVersion="14" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.game2048.MainActivity"
            android:label="@string/app_name" 
            android:screenOrientation="portrait">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

结果图:



后续还有一些功能可以完善,再接再厉~

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值