用Untiy制作2048-小白篇

一、前言

        2048休闲小游戏算是以前都接触过得小游戏,刚开始学完Unity做的第一个小Demo就是它,奈何有些判断算法没搞懂就一直落空了。最近也是看见自己电脑素材库里有2048的素材然后就打算重拾2048自己做。

二、主要UI界面和对象树

 三、核心代码

1.声明部分

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using Random = UnityEngine.Random;
using System.Threading;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
using TMPro;
using Unity.VisualScripting;
using static Unity.Burst.Intrinsics.X86.Avx;
using UnityEngine.SocialPlatforms.Impl;

public class GameManager : MonoBehaviour
{
   
    private SpriteRenderer[] Square_list;                                   //存格子
    private Sprite[] sprite2048 = new Sprite[12];          //存图片2,4,8
    private int move_state=0;                                              //1:上移 -1:下移 2:右移 -2:左移
    private int[] array16 = new int[16] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };   //存格子信息
    private bool gameover = false;                                  
    public GameObject gameOver;                                     
    public GameObject Win;
    int Score = 0;          //得分
    int BestScore;          //最高分
    public Text ScoreText;
    public Text BestScoreText;

    public AudioSource[] Musiclist;   //声音组件
private void Awake()
    {
        //加载sprite资源
        sprite2048 = Resources.LoadAll<Sprite>("2048");
        // 获取所有方格对象
        Square_list = GetComponentsInChildren<SpriteRenderer>();
    }
    void Start()
    {
        array16[0] = 1;                      //手动初始化
        Square_list[0].sprite = sprite2048[1];
        array16[10] = 1;
        Square_list[10].sprite = sprite2048[1];
        array16[11] = 1;
        Square_list[11].sprite = sprite2048[1];
        array16[12] = 1;
        Square_list[12].sprite = sprite2048[1];
                                            //获取本地存储的最大分数
        BestScoreText.text = PlayerPrefs.GetInt("BestScore").ToString();

    }

主要变量:

sprite2048(2,4,8图片,用 Resources获取资源)

Square_list(方格,获取本身子对象就行了)

array16[16](方格信息,其实就是字符数组存储16格子的信息)

2.移动判断(Press)

void Press()
    {
            //手机端
        if (Application.platform == RuntimePlatform.Android && Input.touchCount == 1 && Input.touches[0].phase == TouchPhase.Moved)
        {
            float s01 = Input.GetAxis("Mouse X");
            float s02 = Input.GetAxis("Mouse Y");
            float distence = 5f;
            if (s01 < -1 * distence && s02 > -1 * distence && s02 < distence)
            {
                move_state = -2;
            }
            else if (s01 > distence && s02 > -1 * distence && s02 < distence)
            {
                move_state = 2;
            }
            else if (s02 > distence && s01 > -1 * distence && s01 < distence)
            {
                move_state = 1;
            }
            else if (s02 < -1 * distence && s01 > -1 * distence && s02 < distence)
            {
                move_state = -1;
            }
        }
            //电脑端
        else if (Application.platform == RuntimePlatform.WindowsEditor)
        {
            if (Input.GetKeyDown(KeyCode.UpArrow))
                move_state = 1;
            else if (Input.GetKeyDown(KeyCode.DownArrow))
                move_state = -1;
            else if (Input.GetKeyDown(KeyCode.LeftArrow))
                move_state = -2;
            else if (Input.GetKeyDown(KeyCode.RightArrow))
                move_state = 2;
        }
        if (move_state != 0)
        {
           Merge_Grid();  //移动
        }
            
    }

该函数主要通过变量move_state来接收用户操作的方向(1上,-1下,-2左,2右),还用Application对操作平台进行了判断,在安卓端则通过鼠标Mouse X/Y的返回来判断方向,在Windous端则是通过键盘输入来判断方向(之后我也会想鼠标滑动方面优化的,偷懒--)。在接收完方向数据后再通过Merge_Grid来移动。

3.移动合并(Merge_Grid)

void Merge_Grid()
    {
        // 1=up, -1=down, 2=right, -2=left
        switch (move_state)
        {
            case 1:
                Debug.Log("up"); Musiclist[0].Play();  //播放声音
                for (int i = 0; i < 12; i++)
                {
                    //向上紧凑
                    int k = i;
                    for (int j = 1; i + j * 4 < 16; j++)  
                    {
                        //这段用来将空白格和数字格互换
                        if (array16[i + j * 4] == 0 && array16[k] != 0) k = i + j * 4;
                        if (array16[i + j * 4] != 0 && array16[k] == 0)
                        {
                            array16[k] = array16[i + j * 4];  
                            array16[i + j * 4] = 0;
                            k += 4;
                          
                        }
                    }

                    if (array16[i] == 0) continue;  //为0不合并
                    //合并
                    if (array16[i] == array16[i + 4])  //如果上下两数相同则合并
                    {
                        Score += (int)array16[i] + (int)array16[i+4];  //算得分
                       
                        RecordScore(Score);  //记录得分

                        array16[i]++;        //合并操作,实际就是提高一个档次
                        array16[i + 4] = 0;  //合并者归0
                        
                    }
                }
                break;
            case -1:
                Debug.Log("down"); Musiclist[0].Play();
                for (int i = 15; i > 3; i--)
                {
                    //向下紧凑
                    int k = i;
                    for (int j = 1; i - j * 4 >= 0; j++)
                    {
                        if (array16[i - j * 4] == 0 && array16[k] != 0) k = i - j * 4;
                        if (array16[i - j * 4] != 0 && array16[k] == 0)
                        {
                            array16[k] = array16[i - j * 4];
                            array16[i - j * 4] = 0;
                            k -= 4;
                        }
                    }
                    if (array16[i] == 0) continue;
                    //合并
                    if (array16[i] == array16[i - 4])
                    {
                        Score += (int)array16[i] + (int)array16[i - 4];
                        
                        RecordScore(Score);
                        array16[i]++;
                        array16[i - 4] = 0;
                    }
                }
                break;
            case 2:
                Debug.Log("right"); Musiclist[0].Play();
                for (int i = 15; i > 0; i -= 4)
                {
                    for (int x = 0; x < 3; x++)
                    {
                        //向right紧凑
                        int k = i - x;
                        for (int j = 1; x + j < 4; j++)
                        {
                            if (array16[i - j - x] == 0 && array16[k] != 0) k = i - j - x;
                            if (array16[i - j - x] != 0 && array16[k] == 0)
                            {
                                array16[k] = array16[i - j - x];
                                array16[i - j - x] = 0;
                                k--;
                            }
                        }
                        if (array16[i - x] == 0) continue;
                        //合并
                        if (array16[i - x] == array16[i - x - 1])
                        {
                            Score += (int)array16[i-x] + (int)array16[i-x-1];
                          
                            RecordScore(Score);
                            array16[i - x]++;
                            array16[i - x - 1] = 0;
                        }
                    }
                }
                break;
            case -2:
                Debug.Log("left"); Musiclist[0].Play();
                for (int i = 0; i < 13; i += 4)
                {
                    for (int x = 0; x < 3; x++)
                    {
                        //向left紧凑
                        int k = i + x;
                        for (int j = 1; x + j < 4; j++)
                        {
                            if (array16[i + j + x] == 0 && array16[k] != 0) k = i + j + x;
                            if (array16[i + j + x] != 0 && array16[k] == 0)
                            {
                                array16[k] = array16[i + j + x];
                                array16[i + j + x] = 0;
                                k++;
                            }
                        }
                        if (array16[i + x] == 0) continue;
                        //合并
                        if (array16[i + x] == array16[i + x + 1])
                        {
                            Score += (int)array16[i+x] + (int)array16[i + x+1];
                            
                            RecordScore(Score);
                            array16[i + x]++;
                            array16[i + x + 1] = 0;
                        }
                    }
                }
                break;
        }
        move_state = 0;
        Set_Cell();

        Creat_Num();
        gameover = Game_Over();
    }

void Set_Cell()
    {
        //遍历
        Debug.Log("set cell");
        for (int i = 0; i < 16; i++)
        {
            Square_list[i].sprite = sprite2048[array16[i]];
        }
    }

主要通过move_state的方向来决定操作内容,移动核心就是套的两层循环,外循环控制行列数,内循环遍历两组数做操作(靠边和合并)详细看第一段向上操作的注释就懂了。然后遍历换图合成的数据array16就实现了移动合并的步骤了。

4.创建新数据(Creat_Num)

void Creat_Num()
    {
       
        
        //出现的数字为几,2、4、8
        int tmp = 1;
        float random = Random.value;
        if (random < 0.33)
            tmp = 2;
        else if (random > 0.66)
           tmp = 3;
     
        
        //获取空格
        while (true) 
        {
            int change = (int)Random.Range(0,16);

            Debug.Log("随机数"+change);
            if (array16[change] == 0)   //该位置为空
            {
                array16[change] = tmp;        //给数
                Square_list[change].sprite = sprite2048[tmp];  //换图
                return;
            }
            else continue; //不然重新给随机数
        }

这段主要通过概率随机数来决定tmp的值(1-2,2-4,3-8),然后再给到array16中的空闲位置。

5.输赢判断(Game_Over)

bool Game_Over()
    {
        for (int i = 0; i < 16; i++)     //判断有没有2048,有则Win
        {
            if (array16[i] > 10)
            {
                
                Win.SetActive(true);
                Musiclist[2].Play();
                Time.timeScale = 0f;
                return true;
            }
        }
        for (int i = 0; i < 16; i++) 
        {
            if (array16[i] < 1) //判断有没有空白,有则继续游戏
            {
                return false;
            }
          
            if (i < 12 && array16[i] == array16[i + 4])  //上下有可合并的,继续游戏
            {
                return false;
            }
            if ((i + 1) % 4 != 0 && array16[i] == array16[i + 1])//左右有可合并的,继续游戏
            {
                return false;
            }
        }

        gameOver.SetActive(true);
        Musiclist[1].Play();
        Time.timeScale = 0f;
        return true;
    }

6.重新游戏和记录数据

 public void RestartGame()
    {
        ScoreText.text = "0";  //得分归0
        Score = 0;
        //重新读取场景
        SceneManager.LoadScene(SceneManager.GetActiveScene().name);
        //将最高分存本地
        PlayerPrefs.SetInt("BestScore", BestScore);
        //最高分本地读取
        BestScoreText.text = PlayerPrefs.GetInt("BestScore").ToString();
       
        Time.timeScale = 1;
    }
public void RecordScore(int score)
    {
        ScoreText.text = score.ToString();
        if(PlayerPrefs.GetInt("BestScore")!=0)
        {
            if(PlayerPrefs.GetInt("BestScore") > score)
                BestScore = PlayerPrefs.GetInt("BestScore");
            else
                BestScore = score;
        }
       else { BestScore = 0; }
        BestScoreText.text=BestScore.ToString();

    }

该段主要通过PlayrePrefs.SetInt/GetInt来保持游戏最高分和读取游戏最低分。

四、总结

难点:

1.项目的主要部分和难点在于对数据移动合并的判断最难,也是想了好久,查了好久资料才明白。

2.其次是后面加了个数据最高分存储问题,这个通过PlayerPrefs解决了。

3.判断输赢难点,什么时候赢(有2048这个图就赢),什么时候输(并排不能有相同的,字符数组存储的数据不能为空)

感悟:写了两天才写完,后面加最高分和声音耗了一下午。虽然游戏简单,这个游戏考虑的算法方面的比较多。逻辑结构方面也就那样。之后下面准备着手做一下3D方面的游戏。

猜你喜欢

转载自blog.csdn.net/qq_57250692/article/details/132368883