Android实现2048小游戏
本文实例介绍了android实现2048小游戏的相关代码,分享给大家供大家参考,具体内容如下
根据界面,主要实现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<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>
以上就是本文的全部内容,希望对大家的学习有所帮助。