素材来源于 Unity Assets 商店

完整项目github链接

https://github.com/1520386112/Sokoban

运行效果

动画状态机

因为该项目对应的动画逻辑是按一下键播放一次移动动画,所以实际代码中并没有通过设置参数来控制动画,而是通过 anim.Player("")方法直接播放移动动画,然后自动过渡到对应的待机状态。

代码

MapContainer

using System.Collections;
using System.Collections.Generic;
using UnityEngine;/// <summary>
/// 存放地图信息
/// </summary>
public class MapContainer : MonoBehaviour
{public static int[,] snapshoot = {{ 1, 1, 1, 1, 1, 1, 0, 0, 0},{ 1, 0, 0, 0, 5, 1, 1, 0, 0},{ 1, 2, 0, 0, 0, 0, 1, 0, 0},{ 1, 0, 1, 0, 1, 1, 1, 1, 1},{ 1, 0, 1, 0, 1, 0, 0, 5, 1},{ 1, 0, 1, 0, 0, 3, 0, 1, 1},{ 1, 0, 0, 0, 1, 3, 0, 1, 0},{ 1, 0, 0, 0, 0, 0, 0, 1, 0},{ 1, 1, 1, 1, 1, 1, 1, 1, 0}};
}

Player

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using static GameController;/// <summary>
/// 挂载在 player 上,主要用于控制动画的播放
/// </summary>
public class Player : MonoBehaviour
{private Animator animator;public string anim_down = "WalkDown";public string anim_left = "WalkLeft";public string anim_right = "WalkRight";public string anim_up = "WalkUp";private void Start(){animator = GetComponent<Animator>();}/// <summary>/// 根据 GameController 传入的输入方向来播放对应动画/// </summary>public void PlayPlayerAnimation(Direction dir){switch (dir){case Direction.DOWN:animator.Play(anim_down);break;case Direction.UP:animator.Play(anim_up);break;case Direction.LEFT:animator.Play(anim_left);break;case Direction.RIGHT:animator.Play(anim_right);break;}}
}

Box

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Box : MonoBehaviour
{public Sprite normalSprite;public Sprite onTargetSprite;private SpriteRenderer spriteRenderer;private void Start(){spriteRenderer = GetComponent<SpriteRenderer>();}public void SetSpriteToNormal(){spriteRenderer.sprite = normalSprite;}public void SetSpriteToOnTargetSprite(){spriteRenderer.sprite = onTargetSprite;}
}

GameController

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using static MapContainer;/// <summary>
/// 游戏逻辑核心类
/// </summary>
public class GameController : MonoBehaviour
{//初始化地图时根据 prefab 生成物体public GameObject playerPrefab;public GameObject boxPrefab;public GameObject targetPrefab;public GameObject wallPrefab;public GameObject gameWinText;/// <summary>/// 记录游戏是否胜利,胜利后取消监测玩家输入/// </summary>private bool gameWin;// 记录 Player 当前在 snapshoot 数组中的下标private int playerIndX;private int playerIndY;private Player player;/// <summary>/// 存储某个位置对应的箱子,方便根据位置拿到该处箱子/// </summary>private Box[,] boxes;/// <summary>/// 目标点数目,用于判断游戏是否结束/// </summary>private int targetNum;/// <summary>/// 目前已经完成的目标点数目/// </summary>private int currentCompleteNum;private enum TileType { NULL = 0, WALL = 1, PLAYER = 2, BOX = 3, TARGET = 5, PLAYER_TARGET = 7, BOX_TARGET = 8}/// <summary>/// direction 数组四个方向对应的下标/// </summary>public enum Direction {DOWN, UP, LEFT, RIGHT}private int[,] direction = { {1, 0}, {-1, 0}, {0, -1},{0, 1} };private void Start(){boxes = new Box[9, 9];InitMap();}private void Update(){if (!gameWin){DetectInput();}}void InitMap(){for(int i = 0; i < 9; ++i){for(int j = 0; j < 9; ++j){GameObject go = null;switch (snapshoot[i,j]){case (int)TileType.WALL:go = CreateGameObject(wallPrefab, i, j);go.name = "Wall" + i + "_" + j;break;case (int)TileType.PLAYER:go = CreateGameObject(playerPrefab, i, j);go.name = "Player";player = go.GetComponent<Player>();playerIndX = i;playerIndY = j;break;case (int)TileType.BOX:go = CreateGameObject(boxPrefab, i, j);go.name = "Block";boxes[i, j] = go.GetComponent<Box>();break;case (int)TileType.TARGET:go = CreateGameObject(targetPrefab, i, j);go.name = "Target";targetNum++;break;}}}}/// <summary>/// 监测玩家输入/// </summary>private void DetectInput(){if (Input.GetKeyDown(KeyCode.DownArrow)){Move(Direction.DOWN);}else if (Input.GetKeyDown(KeyCode.UpArrow)){Move(Direction.UP);}else if (Input.GetKeyDown(KeyCode.LeftArrow)){Move(Direction.LEFT);}else if (Input.GetKeyDown(KeyCode.RightArrow)){Move(Direction.RIGHT);}}private void Move(Direction dir){//播放角色动画player.PlayPlayerAnimation(dir);int aimPosX = playerIndX + direction[(int)dir, 0];int aimPosY = playerIndY + direction[(int)dir, 1];switch (snapshoot[aimPosX, aimPosY]){//目标点为空或者是目标点,直接将玩家移动过去即可case (int)TileType.NULL:case (int)TileType.TARGET:MoveTile(playerIndX, playerIndY, aimPosX, aimPosY, TileType.PLAYER);break;//目标点是箱子case (int)TileType.BOX:case (int)TileType.BOX_TARGET:int nextNextX = aimPosX + direction[(int)dir, 0];int nextNextY = aimPosY + direction[(int)dir, 1];             switch (snapshoot[nextNextX, nextNextY]){//目标方向的下下块没有阻挡物时,方可移动case (int)TileType.NULL:case (int)TileType.TARGET:MoveTile(playerIndX, playerIndY, aimPosX, aimPosY, TileType.PLAYER);MoveTile(aimPosX, aimPosY, nextNextX, nextNextY, TileType.BOX);break;}break;}}/// <summary>/// 移动某个Tile,更新地图快照以及物体位置/// <param name="tileType">需要移动的块类型</param>/// </summary>private void MoveTile(int originX, int originY, int aimX, int aimY, TileType tileType){//在目标点的箱子被推动,当前完成数减一if(snapshoot[originX, originY] == (int)TileType.BOX_TARGET){currentCompleteNum--;}/* 直接将目标点处的信息数字加上移动的块对应的数即可* TileType 枚举的特殊数字就是为了如此操作而设计的*/snapshoot[aimX, aimY] += (int)tileType;snapshoot[originX, originY] -= (int)tileType;//推动一个箱子到目标点,当前完成数加一if(snapshoot[aimX, aimY] == (int)TileType.BOX_TARGET){currentCompleteNum++;if(currentCompleteNum == targetNum){GameWin();}}switch (tileType){case TileType.PLAYER:case TileType.PLAYER_TARGET:player.transform.position = new Vector2(aimY, -aimX);playerIndX = aimX;playerIndY = aimY;break;case TileType.BOX:case TileType.BOX_TARGET:boxes[aimX, aimY] = boxes[originX, originY];boxes[originX, originY] = null;boxes[aimX, aimY].transform.position = new Vector2(aimY, -aimX);//移动后根据箱子是否在目标点上修改箱子的Spriteif(snapshoot[aimX, aimY] == (int)TileType.BOX_TARGET)boxes[aimX, aimY].SetSpriteToOnTargetSprite();elseboxes[aimX, aimY].SetSpriteToNormal();break;}}GameObject CreateGameObject(GameObject go, int row, int col){return Instantiate(go, new Vector3(col, -row), Quaternion.identity);}private void GameWin(){gameWin = true;gameWinText.SetActive(true);Debug.Log("游戏胜利");}
}

Unity3D 初级案例 推箱子 完整项目 带详细注释相关推荐

  1. ★C语言期末课程设计★——学生成绩管理系统(完整项目+源代码+详细注释)

    学生成绩管理系统 目录 学生成绩管理系统 一.描述 二.设计目的 三.系统分析

  2. 【综合评价分析】topsis评价 原理+完整MATLAB代码+详细注释+操作实列

    [综合评价分析]topsis评价 原理+完整MATLAB代码+详细注释+操作实列 文章目录 1.TOPSIS法的原理 2.TOPSIS法案例分析 3.建立模型并求解 3.1数据预处理 3.2代码实现数 ...

  3. 【综合评价分析】熵权算法确定权重 原理+完整MATLAB代码+详细注释+操作实列

    [综合评价分析]熵权算法确定权重 原理+完整MATLAB代码+详细注释+操作实列 文章目录 1. 熵权法确定指标权重 (1)构造评价矩阵 Ymn (2)评价矩阵标准化处理 (3)计算指标信息熵值 Mj ...

  4. C语言图形化推箱子完整代码

    写了三关带界面的推箱子 开发环境:Visual Studio2013 运行环境:Visual Studio2013-2022 以下为详细代码: // TUITUI.cpp : 定义应用程序的入口点. ...

  5. c++实现推箱子游戏(带链表)

    目录 1.判断操作有效性 2.移动操作 3.绘图 4.撤回操作 5.主要函数 6.源码 推箱子游戏的本质就是坐标的移动.我们假设人物当前的坐标是(x,y),那么向上移动后的位置就是(x-1,y),向下 ...

  6. 推箱子完整c语言程序,C语言实现推箱子游戏

    每天学习一点点,每天容易一点点.一个简单的C语言程序,用来复习c语言,代码通俗易懂.有什么问题望各位不吝赐教. 本文用最简单的C语言语句写个推箱子的程序,分享给大家: /*************** ...

  7. Spark Core项目实战(1) | 准备数据与计算Top10 热门品类(附完整项目代码及注释)

      大家好,我是不温卜火,是一名计算机学院大数据专业大二的学生,昵称来源于成语-不温不火,本意是希望自己性情温和.作为一名互联网行业的小白,博主写博客一方面是为了记录自己的学习过程,另一方面是总结自己 ...

  8. unity3d 导弹跟踪代码(含完整项目制作过程)

    项目下载地址:https://download.csdn.net/download/zslsir/10689449 unity3d 游戏项目中常常会遇到我方发出一个导弹,自动跟踪敌方目标. 我在网上查 ...

  9. python3 Flask 多人答题(完整项目带源码与使用)

    TopQB答题系统 2020/01/05 @pingfan 功能:     1.多人同时答题系统     2.在线查看个人得分与答题情况(解析)     3.载入题库,随机抽取题目支持[单选题,多选题 ...

最新文章

  1. Apress水果大餐——移动开发
  2. 《Arduino开发实战指南:机器人卷》一3.3 直流电机驱动电路原理
  3. html右键禁用和web页面中添加加入qq群的方式
  4. DetNAS ThunderNet
  5. URAL 1993 This cheeseburger you don't need
  6. FCKeditor使用详解
  7. python爬虫不错的文章
  8. java dexclassloader_DexClassLoader加载apk
  9. Jmeter+ant运行脚本,得到HTML报告
  10. 工作329:uni-数据为空不显示
  11. jquery+ajax+ashx
  12. Amazon发布可持续性数据集,可用于多个领域的数据分析
  13. java8 朗姆表达式,java同步数据库时间问题[问题点数:20分,结帖人vtison]
  14. Java编程--如何突破程序员思维
  15. 操作系统实验报告 lab6
  16. html 表格输出excel,html中导出excel表格
  17. Java学习笔记:案例:标准体重计算器
  18. Ubuntu 开机自动运行命令
  19. 荣耀笔记本锐龙版和linux,在家办公的最佳利器:荣耀笔记本14锐龙版体验
  20. 一脸懵逼学习Hadoop-HA机制(以及HA机制的配置文件,测试)

热门文章

  1. 物联网技术概论:第6章
  2. 转载:Notepad++的64位HexEditor
  3. 瓜分BAT的流量红利:头条向左,小米向右
  4. 【day1】谷粒商城-人人开源前后端联调准备工作
  5. 提词器是用来干嘛的?好用的提词器软件分享
  6. 文档翻译什么软件好?试试这些翻译软件
  7. 新春特辑 | 新基建专题合辑 报告下载
  8. Azure Key Vault(3):Key和Secret的区别
  9. goLang 操作windows注册表
  10. 要被抖音笑死了,打开个网页就算黑客?