Calmer的文章

  • 首页
  • 文章归档
  • 关于页面

  • 搜索
体验游戏 笔记 推荐 工具链 工具使用 小游戏 插件 UI 软件 教程

游戏开发_小游戏开发(2048)(上)

发表于 2020-04-02 | 分类于 游戏开发 | 0 | 阅读次数 1189

前言

此前特别喜欢玩2048,于是所幸就想了想便复刻了一个。还能扩展原先的游戏玩法性。

PS:玩到2048实在太简单了(😉)


游戏规则(游戏需求)

1.界面是有4x4个方格
2.开始随机两个方格生成数字
2048Start.jpg
3.生成的数字10%是4,90%是2(可自定义)
4.玩家可以上下左右四个方向进行操作
5.玩家进行的每个方向的操作,如果相邻是同样的数字则会合并(空方格可以忽略,即两个相同的数字,如果中间有空方格,是能够合并的)
6.玩家每完成一次操作,并且有方块进行了移动或合并,则会在空方格中随机一个方格生成数字
胜利条件:方格中出现有2048数字
失败条件:所有方格都被占满,且上下左右操作都不能再合并数字。


分解需求

  • 产生4x4的矩阵 int[,] map 并初始化InitGame()
  • 生成数字的规则 GenerateNum()
  • 挑选空方格生成数字
    • 统计矩阵中空方格位置 CalEmpty struct MapPos List emptyList
    • 随机一个位置生成数字 GenerateNumInEmpty()
  • 玩家的操作
    • PlayerOp:Up,Down,Left,Right
    • Move LeftMove RightMove UpMove DownMove
  • 数字合并,变化则生成新数字
    • 分为四个方向的合并,主要以Left为例,然后其余情况可以调整输入数字即可完成
    • Merge()
      • 移除空格子 RemoveEmpty()
      • 相邻合并
      • 移除空格子
    • 回填
    • 合并或移动前后是否有变化,有变化则生成新数字
  • 胜利判断方法
  • 失败判断方法

创建项目(Unity3d版本:2018.4.18f1)

  • 项目命名:2048MiniGame
  • 创建完成后在Assets目录创建GameRes,Resources,Scripts目录
  • 导入相关资源与DoTween插件
    2048资源和DoTween插件
    将2048资源解压后放到GameRes中,DoTween插件解压后放到Assets目录下,然后进行安装即可。

完成后目录结构如下:
2048Folder.jpg

Scenes目录是创建项目后自动创建的目录,其中有一个SampleScene场景文件。


编写(游戏核心) GameCore.cs

根据分解的需求,一部一部完成核心逻辑

using System;
using System.Collections;
using System.Collections.Generic;

//存储4x4方格位置的结构体
public struct MapPos
{
    public int x;
    public int y;
    public MapPos(int i,int j)
    {
        x = i;
        y = j;
    }
}

//玩家操作方向的枚举
public enum PlayerOp
{
    Up,
    Down,
    Left,
    Right
}

public class GameCore
{
    private int[,] map;
    private Random random;
    private int row;
    private int column;
    private List<MapPos> emptyList;
    private int[,] moveBeforeMap;

    public GameCore()
    {
        row = 4;
        column = 4;
        map = new int[row, column];
        moveBeforeMap = new int[row, column];
        random = new Random();
        emptyList = new List<MapPos>();
        InitGame();
    }


    private void InitGame()
    {
        for (int i = 0; i < row; i++)
        {
            for (int j = 0; j < column; j++)
                map[i, j] = 0;
        }
    }

    /// <summary>
    /// 90%生成2,10%生成4
    /// </summary>
    /// <returns></returns>
    private int GenerateNum()
    {
        int result = random.Next(0, 10);
        if (result < 9)
        {
            return 2;
        }
        else
        {
            return 4;
        }
    }

    /// <summary>
    /// 计算空格子
    /// </summary>
    private void CalEmpty()
    {
        emptyList.Clear();
        for (int i = 0; i < row; i++)
        {
            for (int j = 0; j < column; j++)
            {
                if (map[i, j] == 0)
                {
                    emptyList.Add(new MapPos(i, j));
                }
            }
        }
    }

    /// <summary>
    /// 在空格子处生成数字
    /// </summary>
    private void GenerateNumInEmpty()
    {
        CalEmpty();
        int pos = random.Next(0, emptyList.Count);
        MapPos mapPos = emptyList[pos];
        map[mapPos.x, mapPos.y] = GenerateNum();
    }

    

    public void StartGame()
    {
        //随机寻找两个空白格子生成两个数字
        GenerateNumInEmpty();
        GenerateNumInEmpty();
    }

    public bool IsChange()
    {
        bool isChanage = false;
        for(int i=0;i<row;i++)
        {
            for(int j=0;j<column;j++)
            {
                if(map[i,j]!=moveBeforeMap[i,j])
                {
                    isChanage = true;
                    return isChanage;
                }
            }
        }
        return isChanage;
    }

    public void Move(PlayerOp op)
    {
        Array.Copy(map, moveBeforeMap, map.Length);
        switch(op)
        {
            case PlayerOp.Left:
                LeftMove();
                break;
            case PlayerOp.Right:
                RightMove();
                break;
            case PlayerOp.Up:
                UpMove();
                break;
            case PlayerOp.Down:
                DownMove();
                break;
        }
        if(IsChange())
        {
            GenerateNumInEmpty();
        }
    }

    private void LeftMove()
    {
        for(int i=0;i<row;i++)
        {
            int[] tempArray = new int[column];
            for(int j=0;j<column;j++)
            {
                tempArray[j] = map[i, j];
            }
            Merge(tempArray);
            for(int j=0;j<column;j++)
            {
                map[i, j] = tempArray[j];
            }
        }
    }

    private void RightMove()
    {
        for (int i = 0; i < row; i++)
        {
            int[] tempArray = new int[column];
            for (int j = 0; j < column; j++)
            {
                tempArray[column- 1-j] = map[i, j];
            }
            Merge(tempArray);
            for (int j = 0; j < column; j++)
            {
                map[i, j] = tempArray[column - 1 - j];
            }
        }
    }

    private void UpMove()
    {
        for (int i = 0; i < column; i++)
        {
            int[] tempArray = new int[row];
            for (int j = 0; j < row; j++)
            {
                tempArray[j] = map[j, i];
            }
            Merge(tempArray);
            for (int j = 0; j < row; j++)
            {
                map[j, i] = tempArray[j];
            }
        }
    }

    private void DownMove()
    {
        for (int i = 0; i < column; i++)
        {
            int[] tempArray = new int[row];
            for (int j = 0; j < row; j++)
            {
                tempArray[row-1-j] = map[j, i];
            }
            Merge(tempArray);
            for (int j = 0; j < row; j++)
            {
                map[j, i] = tempArray[row - 1 - j];
            }
        }
    }


    private void Merge(int[] array)
    {
        //移除空格
        RemoveEmpty(array);
        //合并
        for(int i=0;i<array.Length-1;i++)
        {
            if(array[i]!=0 && array[i]==array[i+1])
            {
                array[i] *= 2;
                array[i + 1] = 0;
            }
        }
        //移除空格
        RemoveEmpty(array);
    }

    private void RemoveEmpty(int[] array)
    {
        int curEmptyIndex = 0;
        for (int i = 0; i < array.Length; i++)
        {
            if (array[i] != 0)
            {
                if (curEmptyIndex != i)
                {
                    array[curEmptyIndex] = array[i];
                    array[i] = 0;
                }
                curEmptyIndex++;
            }
        }
    }

    public string PrintMap()
    {
        string str = "";
        for(int i=0;i<row;i++)
        {
            for(int j=0;j<column;j++)
            {
                str += map[i, j].ToString() + " ";       
            }
            str += "\n";
        }
        return str;
    }

}


玩家控制

  • 创建GameController.cs
    using UnityEngine.UI;
    using UnityEngine.EventSystems;
  • 完成玩家的操作控制 (键盘和滑动)

滑动

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
public class GameController : MonoBehaviour, IPointerDownHandler, IDragHandler
{

    private Vector2 downPoint;
    private bool isDown = false;
    public void OnPointerDown(PointerEventData eventData)
    {
        downPoint = eventData.position;
        isDown = true;
    }

    public void OnDrag(PointerEventData eventData)
    {
        if (!isDown)
            return;

        Vector2 offset = eventData.position - downPoint;
        float x = Mathf.Abs(offset.x);
        float y = Mathf.Abs(offset.y);

        PlayerOp? dir = null;

        if(x>y &&x>50)
        {
            dir = offset.x > 0 ? PlayerOp.Right : PlayerOp.Left;
        }
        else if(x<y && y>50)
        {
            dir = offset.y > 0 ? PlayerOp.Up : PlayerOp.Down;
        }

        if(dir!=null)
        {
            //游戏核心类完成相应的移动
            //core.Move(dir);
        }

        isDown = false;

    }
}

键盘控制

private float time = 0.0f;
private void Update()
{
    time += Time.deltaTime;
    if(time>0.2f)
    {
        KeyBordControl();
    }     
}
private void KeyBordControl()
{
    float x = Input.GetAxis("Horizontal");
    float y = Input.GetAxis("Vertical");
    time = 0.0f;
    if (x>0)
    {
        core.Move(PlayerOp.Right);
        Debug.Log(core.PrintMap());
    }
    else if(x<0)
    {
        core.Move(PlayerOp.Left);
        Debug.Log(core.PrintMap());
    }
    else if(y>0)
    {
        core.Move(PlayerOp.Up);
        Debug.Log(core.PrintMap());
    }
    else if(y<0)
    {
        core.Move(PlayerOp.Down);
        Debug.Log(core.PrintMap());
    }
}

总结

  • 本篇主要讲述了项目的创建
  • 分析需求,并分解需求,然后在书写游戏核心类
  • 加入玩家的控制(包括键盘输入和手势滑动)
  • 基本完成游戏能够在控制台游玩

扩展:如何创建出游戏相应的UI?
如何使用DoTween给UI加上动画,丰富游戏感受?

  • 本文作者: Calmer
  • 本文链接: https://mytechplayer.com/archives/游戏开发小游戏开发2048
  • 版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明出处!
# 小游戏
TimerUtils工具(时间、定时器、间隔执行)
游戏开发_小游戏开发(2048)(下)
  • 文章目录
  • 站点概览
Calmer

Calmer

88 日志
7 分类
10 标签
RSS
Creative Commons
0%
© 2020 — 2025 Calmer
由 Halo 强力驱动
蜀ICP备20010026号-1川公网安备51019002006543
Copyright © 2020-2025 Calmer的文章