在网上学习了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;
}
<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>
<?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>
结果图:
后续还有一些功能可以完善,再接再厉~