Android實現2048小游戲
本文實例介紹了Android實現2048小游戲的相關代碼,分享給大家供大家參考,具體內容如下

根據界面,主要實現4*4的格子方塊比較麻煩,其他的都挺簡單的.總體為實現4*4的格子,自定義GridLayout,并在其中添加觸摸監(jiān)聽事件,進行一系列的操作,從而實現游戲的邏輯,最后再添加動畫效果即可完成.
下面是設計思路:
一.GameView的設計
首先自定義一個類,繼承GridLayout,添加兩個構造方法
public class GameView extends GridLayout {
//兩個必要的構造方法
public GameView(Context context) {
super(context);
initView();
}
public GameView(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
}
}
接下來在initView()中實現設置GridLayout為四列,并且添加觸摸事件監(jiān)聽.(監(jiān)聽方法還可以重寫onTouchEvent(),返回值為true即可),判斷觸摸方向,主要是通過x軸和y軸的偏移量的比較
//初始化變量的方法
public void initView(){
//設置只有四列
setColumnCount(4);
//設置監(jiān)聽事件
setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
setX = event.getX();
setY = event.getY();
break;
case MotionEvent.ACTION_UP:
offsetX = event.getX() - setX;
offsetY = event.getY() - setY;
//判斷滑動方向
if (Math.abs(offsetX) >= Math.abs(offsetY)) {
if (offsetX > 0) {
swipright();
} else if (offsetX < 0) {
swipleft();
}
} else {
if (offsetY > 0) {
swipdown();
} else if (offsetY < 0) {
swipup();
}
}
break;
}
return true;
}
});
}
監(jiān)聽事件實現后先放在那里,接下來把4*4的里面每個小格子設計成小卡片,每個卡片就是一個TextView,卡片設計很簡單,需要什么就添加什么,默認數字為0,這個時候代表是空值,也就是空卡片.
public class Card extends FrameLayout {
public Card(Context context) {
super(context);
tvCard = new TextView(getContext());
tvCard.setTextSize(40f);
tvCard.setGravity(Gravity.CENTER);
LayoutParams lp = new LayoutParams(-1,-1);
lp.setMargins(15,15,0,0);
addView(tvCard, lp);
}
//卡片上的數字
private int num;
private boolean is2048 = true;
private void judgeIs2048(int num){
if (is2048){
if (2048==num){
Toast.makeText(getContext(),"恭喜趙瑩達到2048",Toast.LENGTH_LONG).show();
is2048 = false;
}
}
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
if (num<=0){
tvCard.setText("");
}else {
//這里傳進去的是字符串因此需要加上空字符
tvCard.setText(num+"");
}
switch (num) {
case 0:
tvCard.setBackgroundColor(0x33ffffff);
break;
case 2:
tvCard.setBackgroundColor(0xffeee4da);
break;
case 4:
tvCard.setBackgroundColor(0xffede0c8);
break;
case 8:
tvCard.setBackgroundColor(0xfff2b179);
break;
case 16:
tvCard.setBackgroundColor(0xfff59563);
break;
case 32:
tvCard.setBackgroundColor(0xfff67c5f);
break;
case 64:
tvCard.setBackgroundColor(0xfff65e3b);
break;
case 128:
tvCard.setBackgroundColor(0xffedcf72);
break;
case 256:
tvCard.setBackgroundColor(0xffedcc61);
break;
case 512:
tvCard.setBackgroundColor(0xffedc850);
break;
case 1024:
tvCard.setBackgroundColor(0xffedc53f);
break;
case 2048:
tvCard.setBackgroundColor(0xffedc22e);
break;
default:
tvCard.setBackgroundColor(0xff3c3a32);
break;
}
judgeIs2048(num);
}
//判斷是否相等,用于合并
public boolean equals(Card o) {
return getNum()==o.getNum();
}
//用于顯示數字
private TextView tvCard;
public TextView getTvCard() {
return tvCard;
}
}
卡片設計就需要添加到GameView里面,這個時候重寫onSizeChanged()函數,這個在程序打開的時候運行一次,通過他來動態(tài)設計卡片大小,并且添加卡片和開始游戲.
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, w, oldw, oldh);
Config.CARD_WIDTH = (Math.min(w,h)-10)/4;
AddCard(Config.CARD_WIDTH);
StartGame();
}
添加卡片,一開始全設置為0,也就是全部添加空卡片
//添加卡片
private void AddCard(int CARD_WIDTH){
Card c;
for (int x = 0;x<4;x++){
for (int y = 0;y<4;y++){
c = new Card(getContext());
c.setNum(0);
addView(c, CARD_WIDTH, CARD_WIDTH);
cardMap[y][x] = c;
}
}
}
游戲開始需要隨機添加兩張卡片,數值2或者4,出現比率9:1
//開始游戲
public void StartGame(){
for (int y = 0;y<4;y++){
for (int x = 0;x<4;x++){
cardMap[y][x].setNum(0);
}
}
AddRandomCard();
AddRandomCard();
}
隨機添加卡片設計
//添加隨機卡片
private void AddRandomCard(){
CardPoint.clear();
for (int y = 0;y<4;y++){
for (int x = 0;x<4;x++){
if (cardMap[x][y].getNum()<=0){
CardPoint.add(new Point(x,y));
}
}
}
//把一張空卡片換成帶數字的
Point p = CardPoint.remove((int)(Math.random()*CardPoint.size()));
cardMap[p.x][p.y].setNum(Math.random()>0.1?2:4);
MainActivity.getMainActivity().getAnimLayer().createScaleTo1(cardMap[p.x][p.y]);
}
這樣大體框架就設計好了
接下來是滑動事件,這里只舉例左滑
private void swipleft(){
boolean status = false;
for (int y = 0; y < 4; y++) {
for (int x = 0; x < 4; x++) {
for (int x1 = x+1; x1 < 4; x1++) {
if (cardMap[x1][y].getNum()>0) {
if (cardMap[x][y].getNum()<=0) {
MainActivity.getMainActivity().getAnimLayer().createMoveAnim(cardMap[x1][y],cardMap[x][y], x1, x, y, y);
cardMap[x][y].setNum(cardMap[x1][y].getNum());
cardMap[x1][y].setNum(0);
x--;
status = true;
}else if (cardMap[x][y].equals(cardMap[x1][y])) {
MainActivity.getMainActivity().getAnimLayer().createMoveAnim(cardMap[x1][y], cardMap[x][y],x1, x, y, y);
cardMap[x][y].setNum(cardMap[x][y].getNum() * 2);
cardMap[x1][y].setNum(0);
MainActivity.getMainActivity().addScore(cardMap[x][y].getNum());
status = true;
}
break;
}
}
}
}
if (status){
AddRandomCard();
checkGame();
}
}
每次添加卡片還需要判斷是否結束游戲
//結束游戲
private void checkGame(){
boolean complete = true;
ALL:
for (int y = 0; y < 4; y++) {
for (int x = 0; x < 4; x++) {
if (cardMap[x][y].getNum()==0||
(x>0&&cardMap[x][y].equals(cardMap[x-1][y]))||
(x<3&&cardMap[x][y].equals(cardMap[x+1][y]))||
(y>0&&cardMap[x][y].equals(cardMap[x][y-1]))||
(y<3&&cardMap[x][y].equals(cardMap[x][y+1]))) {
complete = false;
break ALL;
}
}
}
if (complete) {
Toast.makeText(getContext(), "游戲結束" + MainActivity.getMainActivity().getScore(), Toast.LENGTH_LONG).show();
}
}
設計總體上框架就是上面說的那些.
二.動畫效果
動畫效果主要是創(chuàng)建,移動,合并這三個效果,因此重寫個繼承FrameLayout的class,覆蓋到游戲界面上,這樣的目的可以通過MainActivity中實例化當前這個類,然后可以操作其方法,然后通過滑動來設置動畫
public class AnimLayer extends FrameLayout {
public AnimLayer(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public AnimLayer(Context context, AttributeSet attrs) {
super(context, attrs);
}
public AnimLayer(Context context) {
super(context);
}
public void createMoveAnim(final Card from,final Card to,int fromX,int toX,int fromY,int toY){
final Card c = getCard(from.getNum());
LayoutParams lp = new LayoutParams(Config.CARD_WIDTH, Config.CARD_WIDTH);
lp.leftMargin = fromX*Config.CARD_WIDTH;
lp.topMargin = fromY*Config.CARD_WIDTH;
c.setLayoutParams(lp);
if (to.getNum()<=0) {
to.getTvCard().setVisibility(View.INVISIBLE);
}
TranslateAnimation ta = new TranslateAnimation(0, Config.CARD_WIDTH*(toX-fromX), 0, Config.CARD_WIDTH*(toY-fromY));
ta.setDuration(100);
ta.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {}
@Override
public void onAnimationRepeat(Animation animation) {}
@Override
public void onAnimationEnd(Animation animation) {
to.getTvCard().setVisibility(View.VISIBLE);
recycleCard(c);
}
});
c.startAnimation(ta);
}
private Card getCard(int num){
Card c;
if (cards.size()>0) {
c = cards.remove(0);
}else{
c = new Card(getContext());
addView(c);
}
c.setVisibility(View.VISIBLE);
c.setNum(num);
return c;
}
private void recycleCard(Card c){
c.setVisibility(View.INVISIBLE);
c.setAnimation(null);
cards.add(c);
}
private List<Card> cards = new ArrayList<Card>();
public void createScaleTo1(Card target){
ScaleAnimation sa = new ScaleAnimation(0.1f, 1, 0.1f, 1, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
sa.setDuration(100);
target.setAnimation(null);
target.getTvCard().startAnimation(sa);
}
}
最后主布局文件如下
<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:background="#fffaf8ef"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity">
<LinearLayout
android:layout_marginTop="15dp"
android:orientation="horizontal"
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#ff776e65"
android:text="@string/title"
android:textSize="50sp"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:orientation="horizontal"
android:layout_marginTop="10dp"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#ff776e65"
android:layout_marginLeft="30dp"
android:textSize="35sp"
android:text="@string/Score"/>
<TextView
android:id="@+id/tvscore"
android:layout_marginLeft="20dp"
android:textSize="25sp"
android:textColor="#ff776e65"
android:layout_width="70dp"
android:layout_height="37dp"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/startgame"
android:layout_marginLeft="40dp"
android:background="#ffbbada0"
android:textSize="15sp"
android:text="@string/start"/>
</LinearLayout>
<FrameLayout
android:id="@+id/gameContainer"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1">
<develop.niuli.com.game.GameView
android:layout_marginTop="40dp"
android:id="@+id/Gridlayout"
android:layout_width="match_parent"
android:background="#ffbbada0"
android:layout_height="350dp">
</develop.niuli.com.game.GameView>
<develop.niuli.com.game.AnimLayer
android:id="@+id/animLayer"
android:layout_width="match_parent"
android:layout_height="match_parent">
</develop.niuli.com.game.AnimLayer>
</FrameLayout>
</LinearLayout>
以上就是本文的全部內容,希望對大家的學習有所幫助。
相關文章
Android中Retrofit 2.0直接使用JSON進行數據交互
本篇文章主要介紹了Android中Retrofit 2.0直接使用JSON進行數據交互,具有一定的參考價值,有興趣的可以了解一下2017-08-08
Android App開發(fā)中Gradle構建過程的配置方法
這篇文章主要介紹了Android App開發(fā)中Gradle構建過程的配置方法,包括在Gradle中配置manifest的方法,需要的朋友可以參考下2016-06-06
Android基于PhotoView實現的頭像/圓形裁剪控件
這篇文章主要給大家介紹了關于Android基于PhotoView實現的頭像/圓形裁剪控件的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2018-07-07
Android編程實現兩個Activity之間共享數據及互相訪問的方法
這篇文章主要介紹了Android編程實現兩個Activity之間共享數據及互相訪問的方法,簡單分析了Android中Activity數據共享與訪問的相關技巧,具有一定參考借鑒價值,需要的朋友可以參考下2015-11-11

