android 2048 动画,Android实现2048小游戏

本文实例介绍了Android实现2048小游戏的相关代码,分享给大家供大家参考,具体内容如下

818231f88cb2545d4156a44df612871b.png

根据界面,主要实现4*4的格子方块比较麻烦,其他的都挺简单的.总体为实现4*4的格子,自定义GridLayout,并在其中添加触摸监听事件,进行一系列的操作,从而实现游戏的逻辑,最后再添加动画效果即可完成.

下面是设计思路:

一.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为四列,并且添加触摸事件监听.(监听方法还可以重写onTouchEvent(),返回值为true即可),判断触摸方向,主要是通过x轴和y轴的偏移量的比较

//初始化变量的方法

public void initView(){

//设置只有四列

setColumnCount(4);

//设置监听事件

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;

}

});

}

监听事件实现后先放在那里,接下来把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()函数,这个在程序打开的时候运行一次,通过他来动态设计卡片大小,并且添加卡片和开始游戏.

@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();

}

}

设计总体上框架就是上面说的那些.

二.动画效果

动画效果主要是创建,移动,合并这三个效果,因此重写个继承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 cards = new ArrayList();

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);

}

}

最后主布局文件如下

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">

android:layout_marginTop="15dp"

android:orientation="horizontal"

android:gravity="center"

android:layout_width="match_parent"

android:layout_height="wrap_content">

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:textColor="#ff776e65"

android:text="@string/title"

android:textSize="50sp"/>

android:layout_width="match_parent"

android:orientation="horizontal"

android:layout_marginTop="10dp"

android:layout_height="wrap_content">

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:textColor="#ff776e65"

android:layout_marginLeft="30dp"

android:textSize="35sp"

android:text="@string/Score"/>

android:id="@+id/tvscore"

android:layout_marginLeft="20dp"

android:textSize="25sp"

android:textColor="#ff776e65"

android:layout_width="70dp"

android:layout_height="37dp"

/>

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"/>

android:id="@+id/gameContainer"

android:layout_width="fill_parent"

android:layout_height="0dp"

android:layout_weight="1">

android:layout_marginTop="40dp"

android:id="@+id/Gridlayout"

android:layout_width="match_parent"

android:background="#ffbbada0"

android:layout_height="350dp">

android:id="@+id/animLayer"

android:layout_width="match_parent"

android:layout_height="match_parent">

以上就是本文的全部内容,希望对大家的学习有所帮助。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值