1、Unity3D项目学习笔记(1)- 2D Roguelike Tutorial

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Ma_Start/article/details/76385421

游戏介绍:玩家控制一个2D帧动画人物在地图上行走,目标是到达出口,进入下一关。途中会有食物、敌人和障碍物。玩家每进行一个动作都会销耗食物,靠近敌人会攻击玩家,可以摧毁障碍物。食物耗尽时游戏结束。

1、游戏组件

1.1、帧动画 Animation

这个游戏是简单的帧动画,美术资源已按固定大小准备好每一帧的动画。

  • 选中动画的所有帧,拖动到GameObject中会生成相应的Animation文件和配套的AnimationController。
  • Animation包括闲置动画、攻击动画和被攻击动画(Idle、Attack、Damage)

    • 当Trigger.Attack触发时,Idle立即转为Attack,Attack播放完后回到Idle。
    • 当Trigger.Damage触发时,Idle立即转为Damage,Damager播放完后回到Idle
  • 通过Override Controller使不同的敌人共用一个AnimationController,但播放不同的动画。


1.2 渲染层 SpriteRenderer.SortingLayer

游戏中渲染层有Background、Items、Units(可以自己添加)。渲染层低的物体绘制比较晚,所以会遮挡渲染层高的物体。

  • Backgound 放置背景(Floot、OutWall)等无需交互的物体。
  • Items 放置物品(Food、Suda)等需要交互的物体。
  • Units 放置角色(Player、Enemy)等会行动的角色。

1.3 行走和碰撞检测 Rigidbody and BoxCollider

添加BlockLayer层,为Player、Enemy、Wall等所有碰撞检测(BoxCollider)都将在这个层中进行。

  • Player和Enemy等需要运动的角色,设置为Kinematic Rigidbody,即可以通过物理系统移动,但不会收到环境力影响。
  • 将Player和Enemy等需要和环境交互的单位,其碰撞器尺寸(BoxCollider.size)设置为0.9,防止角色移动时与周围环境发生不必要的碰撞。
  • 将Exit和Food等物体设置为触发器模式(IsTrigger),不会产生物理碰撞效果。

1.4 界面(UI)

界面包括DayImage和FoodText

  • DayImage显示当前天数,只在玩家进入每个关卡前出现,1秒后消失。
  • FoodText显示玩家当前食物数量,并在每次食物变化时出现改变的值(停留0.5秒)。

1.5 声音(AudioSource)

背景音乐循环播放。
音效包含玩家移动、攻击、受伤、拾取食物和死亡,敌人攻击等。通过AudioManager脚本统一控制。


2、代码结构

2.1 游戏管理类

2.1.1 GameManager(游戏管理类)

单例模式 Singleto

    - 通过DontDestoryOnLoad(this),使自己不会在关卡开始时被销毁、重置。
    - 在Awake()中进行游戏的初始化(包括重新生成地图)
    - 在MainCamera上的脚本中建立Singleto。

初始化游戏 InitGame()

    - 调用MapManager.InitMap()随机生成地图。
    - 重新初始化当前UI。
    - 清空上一关卡中的敌人List。

管理敌人 EnemyList

    - 在敌人生成后加入EnemyList统一管理。
    - 协程EnemyMove()让敌人按一定顺序移动。

管理地图

  • OnLevelWasLoaded(int level)已停用,用OnSceneLoad(Scene scene, LoadSceneMode sceneMode)代替。
  • 删除Awake()中的InitGame(),InitGame()仅在OnSceneLoad()中使用。

    private void OnDisable() {
        SceneManager.sceneLoaded -= OnSceneLoaded;
    }
    
    private void OnEnable() {
        SceneManager.sceneLoaded += OnSceneLoaded;
    }
    
    void OnSceneLoaded(Scene scene, LoadSceneMode mode) {
        level++;
        InitGame();
        Debug.Log("当前第" + level + "天");
        Debug.Log("饥饿:" + hunger);
    }

    2.1 MapManager(地图管理类)

    //生成地图范围
    for (int x = 2; x < cols - 2; x++) {
        for (int y = 2; y < rows - 2; y++) {
            positionList.Add(new Vector2(x, y));
        }
    }
    //随机生成一个游戏交互物
    private void RandomInstantatePrefab(GameObject[] prefabs) {
        //随机生成位置
        int positionIndex = Random.Range(0, positionList.Count);
        Vector2 position = positionList[positionIndex];
        positionList.RemoveAt(positionIndex);//该位置已存在物体(即将),移除该位置
        //根据位置,随机生成一个一个物体
        int index = Random.Range(0, prefabs.Length);
        GameObject gameObject = Instantiate(prefabs[index], position, Quaternion.identity) as GameObject;
        gameObject.transform.SetParent(mapHolder);
    }

2.2 角色类

Player和Enemy类使用,通过RaycastHit2D检测前方的物体。

//移动
mRigidbody.MovePosition(Vector2.Lerp(transform.position, mTargetPosition, speed * Time.deltaTime)); 、

//...

mCollider.enabled = false;//防止射线击中自己
RaycastHit2D hit = Physics2D.Linecast(transform.position, mTargetPosition + new Vector2(h, v));//发射射线检测
mCollider.enabled = true;

if(hit.transform == null) { //说明前方无障碍物
    //前进
} else {
     switch (hit.collider.tag) {
         case  "Wall"://前方是障碍物
            //攻击
             break;
         //...
     }
}

2.3 其他类

  1. Wall类

    
     public Sprite damageSprite;//受到攻击后的图片
     //通过替换图片来达到显示破损状态
     GetComponent<SpriteRenderer>().sprite = damageSprite;//收到攻击后,替换图片
阅读更多
换一批

没有更多推荐了,返回首页