热门标签 | HotTags
当前位置:  开发笔记 > Android > 正文

Android实现2048小游戏

这篇文章主要为大家介绍了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&#63;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);
  }

}

最后主布局文件如下


  
    
  

  

    
    
    

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


推荐阅读
  • Android 九宫格布局详解及实现:人人网应用示例
    本文深入探讨了人人网Android应用中独特的九宫格布局设计,解析其背后的GridView实现原理,并提供详细的代码示例。这种布局方式不仅美观大方,而且在现代Android应用中较为少见,值得开发者借鉴。 ... [详细]
  • 优化ListView性能
    本文深入探讨了如何通过多种技术手段优化ListView的性能,包括视图复用、ViewHolder模式、分批加载数据、图片优化及内存管理等。这些方法能够显著提升应用的响应速度和用户体验。 ... [详细]
  • Android LED 数字字体的应用与实现
    本文介绍了一种适用于 Android 应用的 LED 数字字体(digital font),并详细描述了其在 UI 设计中的应用场景及其实现方法。这种字体常用于视频、广告倒计时等场景,能够增强视觉效果。 ... [详细]
  • RecyclerView初步学习(一)
    RecyclerView初步学习(一)ReCyclerView提供了一种插件式的编程模式,除了提供ViewHolder缓存模式,还可以自定义动画,分割符,布局样式,相比于传统的ListVi ... [详细]
  • 2023 ARM嵌入式系统全国技术巡讲旨在分享ARM公司在半导体知识产权(IP)领域的最新进展。作为全球领先的IP提供商,ARM在嵌入式处理器市场占据主导地位,其产品广泛应用于90%以上的嵌入式设备中。此次巡讲将邀请来自ARM、飞思卡尔以及华清远见教育集团的行业专家,共同探讨当前嵌入式系统的前沿技术和应用。 ... [详细]
  • 本文探讨了 RESTful API 和传统接口之间的关键差异,解释了为什么 RESTful API 在设计和实现上具有独特的优势。 ... [详细]
  • 本文详细介绍了如何使用Spring Boot进行高效开发,涵盖了配置、实例化容器以及核心注解的使用方法。 ... [详细]
  • 本文详细介绍了Java编程语言中的核心概念和常见面试问题,包括集合类、数据结构、线程处理、Java虚拟机(JVM)、HTTP协议以及Git操作等方面的内容。通过深入分析每个主题,帮助读者更好地理解Java的关键特性和最佳实践。 ... [详细]
  • Python自动化处理:从Word文档提取内容并生成带水印的PDF
    本文介绍如何利用Python实现从特定网站下载Word文档,去除水印并添加自定义水印,最终将文档转换为PDF格式。该方法适用于批量处理和自动化需求。 ... [详细]
  • 在当前众多持久层框架中,MyBatis(前身为iBatis)凭借其轻量级、易用性和对SQL的直接支持,成为许多开发者的首选。本文将详细探讨MyBatis的核心概念、设计理念及其优势。 ... [详细]
  • 将Web服务部署到Tomcat
    本文介绍了如何在JDeveloper 12c中创建一个Java项目,并将其打包为Web服务,然后部署到Tomcat服务器。内容涵盖从项目创建、编写Web服务代码、配置相关XML文件到最终的本地部署和验证。 ... [详细]
  • XNA 3.0 游戏编程:从 XML 文件加载数据
    本文介绍如何在 XNA 3.0 游戏项目中从 XML 文件加载数据。我们将探讨如何将 XML 数据序列化为二进制文件,并通过内容管道加载到游戏中。此外,还会涉及自定义类型读取器和写入器的实现。 ... [详细]
  • 本文介绍如何在 Unity 的 XML 配置文件中,将参数传递给自定义生命周期管理器的构造函数。我们将详细探讨 CustomLifetimeManager 类的实现及其配置方法。 ... [详细]
  • 本文详细介绍了 Java 中 org.apache.xmlbeans.SchemaType 类的 getBaseEnumType() 方法,提供了多个代码示例,并解释了其在不同场景下的使用方法。 ... [详细]
  • 本文详细介绍了如何解决MyBatis中常见的BindingException错误,提供了多种排查和修复方法,确保Mapper接口与XML文件的正确配置。 ... [详细]
author-avatar
智慧与财富的拥有者_678
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有