Android开发简单的2048游戏

时间:2021-02-07 03:24:54

作为一名android渣渣第一次用android写了个简单的小游戏还是模仿网上的视频写的,,哎,,


视频教程链接


写在前面:这里我用的IDE是eclipse,所以对与 Android studio 的来说可能会有点那个,,,

但是主要的代码应该没问题的哈,,


界面和实现的逻辑:    

1,activity_main.xml

这是游戏的主界面(layout),游戏界面 整体采用线性布局,然后嵌套一个计分器面板也是线性布局,

中间用了两个textView一个显示Score字体一个显示分数然后下面的游戏界面用个类绑定,类继承

格子布局,然后游戏的主要布局就在那个类中实现

2,card.java 类

这是2048游戏中的抽象出来的卡片,这里我们来定义一些卡片的性质和一些接口供我们只用,我们用

个lable组件来表示卡片,大小为32*32显示的数字为num,如果是0就是空 ,颜色会根据数字的不同而

不同,布局用layoutparms 来控制,边距为10,即格子与格子之间的距离为10

3,GameView.java 类

这里是游戏界面的布局和游戏逻辑的控制,首先通过构造函数来初始化游戏initGameView()这里面设置

界面布局的列为4列,背景颜色为0xffbbada0然后 写个监听事件,监听触摸事件,setOnTouchListener,

首先这里我们定义startX,startY,offsetX,offsetY,当触摸时startX = even.getX(),startY = even.getY()当触

摸结束时,offsetX = even.getX ()- startX offsetY = even.getY ()- startY  有了这些变量我们就可以判断

手指滑动的方向了,如果如果abs(offsetX)>abs(offsetY)则滑动的方向定义为水平移动,然后我们定义

如果offset X<-5则为向左,这里取了个相对值,其他的同理可得,然后我们重载 onSizeChanged方法,

即,如果窗口大改变是就执行这个方法,一开始打开时窗口大小方式改变,这里要在配置文件里配置

屏幕为竖屏,然后就执行这个方法,所以我们可以在这里记录卡片的长宽 = (min(w,h)  -10)/4,然后

addCard(); startGame();在addCard中我们首先定义了个card的二维数组来保存界面上的4*4的卡片,

然后初始值为0,这里就初始了界面的4*4的卡片,然后就是随机添加两个卡片这里写个随机生成卡片

的方法,首先我们用个集合把所有空的卡片的点存进去,然后从中随机生成个,然后在随机生成个

数,这里2:4 = 9:1 ,所以我们就可以判断生成0-1的数与0.1比较,然后就实现了这个1:9,接下来就

是移动的操作,我们分别写四个方法实现上下左右的操作,对于一种操作我们用三层循环去遍历,

这里我们假设向右,我们外层循环遍历x,y从1-4,然后内存循环遍历4到y+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 {


public MainActivity() {
// TODO Auto-generated constructor stub
setMainActivity(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 showScore(){
tvScore.setText(score+"");
}

public void addScore(int s){
score+=s;
showScore();
}

public static MainActivity getMainActivity() {
return mainActivity;
}

public static void setMainActivity(MainActivity mainActivity) {
MainActivity.mainActivity = mainActivity;
}
private int score = 0;
private TextView tvScore;
private static MainActivity mainActivity = null;


}



activity_main.xml

<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:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:orientation="vertical"
tools:context=".MainActivity" >



<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:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/tvScore"/>


</LinearLayout>

<com.example.game2048.GameView
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:id="@+id/gameView">

</com.example.game2048.GameView>

</LinearLayout>




card.java

package com.example.game2048;

import android.R.color;
import android.content.Context;
import android.content.pm.LabeledIntent;
import android.graphics.Color;
import android.view.Gravity;
import android.widget.FrameLayout;
import android.widget.TextView;

public class Card extends FrameLayout {


// 记录卡片的颜色

private int [] cardColor = new int[30];


//初始化卡片的颜色
public void setColor(){
cardColor[0] =Color.BLUE;
cardColor[1] = Color.CYAN;
cardColor[8] = Color.DKGRAY;
cardColor[5] = Color.GRAY;
cardColor[4] = Color.GREEN;
cardColor[3] = Color.RED;
cardColor[6] = Color.LTGRAY;
cardColor[7] = Color.MAGENTA;
cardColor[2]= Color.YELLOW;
cardColor[9] = Color.WHITE;
cardColor[10] = Color.TRANSPARENT;
}


//构造方法
public Card(Context context) {
super(context);

setColor();
lable = new TextView(getContext());
lable.setTextSize(32);//设置大小
lable.setBackgroundColor(0x33ffffff); //背景颜色
lable.setGravity(Gravity.CENTER);//布局为居中

LayoutParams lp = new LayoutParams(-1,-1);
lp.setMargins(10, 10, 0, 0);//边距为10
addView(lable, lp);
setNum(0);

}
private int num = 0;


//获取数字
public int getNum() {
return num;
}

//设置数字
public void setNum(int num) {
this.num = num;
if(num<=0){
lable.setBackgroundColor(0x33ffffff);
lable.setText("");
}else {
//取log得到x设置颜色
int x =(int) (Math.log((double)num));
x%=11;
lable.setBackgroundColor(cardColor[x]);
lable.setText(num+"");
}

}

//卡片的lable组件
private TextView lable;


//判断是否相等
public boolean equals(Card o) {
// TODO Auto-generated method stub
return num==o.getNum();
}


}



GameView.java


package com.example.game2048;

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

import android.R.bool;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Point;
import android.provider.ContactsContract.CommonDataKinds.Event;
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, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
initGameView();
}

public GameView(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
initGameView();
}

public GameView(Context context) {
super(context);
// TODO Auto-generated constructor stub
initGameView();
}


//初始化游戏
private void initGameView(){

setColumnCount(4); //设置列为4
setBackgroundColor(0xffbbada0); //设置背景色

//监听触摸事件
setOnTouchListener(new OnTouchListener() {

private float startX,startY,offsetX,offsetY; //四个变量记录初始位置和偏移量

@Override
public boolean onTouch(View arg0, MotionEvent even) {
// TODO Auto-generated method stub
switch(even.getAction()){
case MotionEvent.ACTION_DOWN: //记录初始位置
startX = even.getX();
startY = even.getY();
break;
case MotionEvent.ACTION_UP: //记录偏移量
offsetX = even.getX()-startX;
offsetY = even.getY() -startY;


if(Math.abs(offsetX)>Math.abs(offsetY)){ //X的偏移量大于Y的偏移量
if(offsetX<-5){
swipeLeft();//向左的操作
}else {
swipeRight();//向右的操作
}
}else {
if(offsetY<-5){
swipeUp();//向上的操作
}else{
swipeDown();//向下的操作
}
}

break;

}

return true;
}
});
}


//重载方法,窗口大小改变使执行
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
// TODO Auto-generated method stub
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 card;
//4*4
for(int i=0;i<4;i++){
for(int j=0;j<4;j++){
card = new Card(getContext()); //初始化卡片对象
card.setNum(0);//初始值为0
addView(card,cardWidth,cardHeight);//添加
cardsMap[i][j] = card;//将卡片与cardMap绑定
}
}
}

//添加随机卡片
private void addRandomNum(){

//记录空卡片的点的集合
emptyPoints.clear();
for(int i=0;i<4;i++){
for(int j=0;j<4;j++){
if(cardsMap[j][i].getNum()<=0){
emptyPoints.add(new Point(j,i)); //添加所有空卡片
}
}
}
Point point = emptyPoints.remove((int)(Math.random()*emptyPoints.size())); //从空卡片中随机一个卡片
cardsMap[point.x][point.y].setNum(Math.random()>0.1?2:4);//随机生成一个数 2:4 = 1:9
}

//开始游戏方法
private void startGame(){
//分数清零
MainActivity.getMainActivity().clearScore();
for(int i=0;i<4;i++){
for(int j=0;j<4;j++){
cardsMap[j][i].setNum(0); //初始化为0
}
}
//随机生成两个卡片
addRandomNum();
addRandomNum();
}


//向左移动的方法
private void swipeLeft(){
boolean flag = 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);
y--;//向前移动
flag = 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()); //分数增加
flag = true;
}

break;
}
}
}
}
if(flag){
//如果有有效移动则随机一张卡片并且判断是否结束
addRandomNum();
checkComplete();
}
}

//同上 向右移动的操作
private void swipeRight(){
boolean flag = 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);
y++;
flag = 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());
flag = true;
}

break;
}
}
}
}
if(flag){
addRandomNum();
checkComplete();
}
}
//同上,向上移动的操作
private void swipeUp(){
boolean flag = 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);
x--;
flag = 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());
flag = true;
}

break;
}
}
}
}
if(flag){
addRandomNum();
checkComplete();
}

}
//同上,向下移动的操作
private void swipeDown(){

boolean flag = 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);
x++;
flag = 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());
flag = true;
}
break;
}
}
}
}

if(flag){
addRandomNum();
checkComplete();
}
}


//判断是否结束游戏
private void checkComplete(){
boolean complete = true;
All:
for(int x = 0;x<4;x++){
for(int y=0;y<4;y++){
//判断有空或上下左右有相同的卡片则没结束
if(cardsMap[x][y].getNum()==0||
(x-1>=0&&cardsMap[x][y].equals(cardsMap[x-1][y]))||
(x+1<4&&cardsMap[x][y].equals(cardsMap[x+1][y]))||
(y-1>=0&&cardsMap[x][y].equals(cardsMap[x][y-1]))||
(y+1<4&&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();
}

}

//记录4*4卡片的数组
private Card [][] cardsMap = new Card[4][4];
//记录空卡片的集合
private List<Point> emptyPoints = new ArrayList<Point>();

}