首页 > 其他分享 >麦田物语第十四天

麦田物语第十四天

时间:2024-07-27 12:26:54浏览次数:9  
标签:麦田 动画 PartType public 第十四天 物语 物品 我们 Animator

系列文章目录

麦田物语第十四天


文章目录


前言

昨天制作了人物的移动(利用混合树),然后发现人物移动时的动画出问题了,所以今天先查找出问题的原因,我先把Arm和Body的动画重新做了一遍,结果发现还是相同的问题,最后问了大佬发现原来是混合树的Parameters设置错了,都给设置成InputX了,改正后就开始了今天的项目总结。


一、实现选中物品触发举起动画

本小节我们想要实现的功能是点击背包中的物品人物就会举起物品,并且学习了这个方法之后我们也可以实现人物使用工具,更换衣服等功能。
因为我们要举起物体,因此在Player下创建一个空物体HoldItem并添加Sprite Renderer组件,同时调整渲染方式(Sprite Sort Point)为Povit,渲染层级(Sorting Layer)为Instance,并更改层级顺序(Order In Layer)为2,避免头发出现在该物体的前面;接着调整该物体到合适位置,最后禁用其Sprite Renderer组件。
当我们举起物品时,只需要实现的是手臂动画的切换,所以我们通过代码来实现Animator Override的更换:
首先创建Scripts-> Player -> AnimatorOverride脚本,在这个脚本中需要拿到所有的 Animator 组件和 HoldItem的Sprite Renderer组件;并在Awake方法中获取Animators,我们就可以返回Unity进行拖拽赋值了。
因为我们想要实现手臂动画的切换,那么需要制作出来当玩家举起物体时的手臂动画,也上节一样,我们需要创建Animator Override Controller,并将Base Controller赋值给它,接着将需要的动画添加上去即可(这些动画都在文件夹中,也可自己制作)。
接下来我们就要实现切换动画的逻辑了。
首先我们需要实现的就是通过点击物品的类型实现相应的逻辑从而实现动画切换,那我们需要实现字典的方式是Player身体的各个部位的Animator匹配想要的部件和物品的ID等相关的信息。
接下来我们需要创建一些新的枚举类型,首先是PartType,表示这个物体的功能类型是什么;

PartType的枚举代码如下:

public enum PartType
{
    None,Carry,Hoe,Break
}

接下来需要创建的是PartName,枚举出我们身体的各个位置;

PartName的枚举代码如下:

public enum PartName
{
    Body,Hair,Arm,Tool
}

相信看到这个我们就能发现这些类型的作用了,我们根据物品的类型从而切换身体的不同部分的动画,然后我们来具体看看代码怎么写:
我们刚才所说的逻辑需要存储下来,因此返回DataCollection脚本,编写一个新的类型AnimatorType,记得需要序列化,在该类型中我们首先需要PartType类型的变量来存储物品功能,PartName类型的变量来存储身体部位,以及最重要的需要使用的Animator Override Controller,表名要切换那个Animator。

DataCollection脚本的AnimatorType类型代码如下:

[System.Serializable]
public class AnimatorType
{
    public PartType partType;
    public PartName partName;
    public AnimatorOverrideController overrideController;
}

接着我们就可以回到AnimatorOverride脚本中定义AnimatorType列表,返回Unity对其进行赋值,大致如下:
在这里插入图片描述
我们还需要编写字典来存储身体的每个部位对应的Animator,将Animator的名字和Animator本身存入这个字典中。那么怎么生成这个字典呢,我们只需要遍历一遍animators数组,然后将其名字和本身存入字典即可。
当我们点击Slot_UI上的物品时,才会进行这个切换,在切换时我们需要传递物品的信息从而对HoldItem的Sprite Renderer组件赋值,所以我们仍然采取呼叫的方式来编写这个方法。(单击选中,再次单击取消选中)

EventHandler脚本的ItemSelectEvent代码如下

public static event Action<ItemDetails, bool> ItemSelectedEvent;
    public static void CallItemSelectedEvent(ItemDetails itemDetails, bool isSelected)
    {
        ItemSelectedEvent?.Invoke(itemDetails, isSelected);
    }

接下来我们在点选物品的方法OnPointerClick中发送这个呼叫,并且只有在背包中点选物品时才会发送(在商店中的物品我们无法使用)。

SlotUI的OnPointerClick方法如下:

public void OnPointerClick(PointerEventData eventData)
        {
            if (itemAmount == 0) return;
            isSelected = !isSelected;
            inventoryUI.UpdateSlotHightlight(slotIndex);

            if (slotType == SlotType.Bag)
            {
                //通知物品被选中的状态和信息
                EventHandler.CallItemSelectedEvent(itemDetails, isSelected);
            }
        }

接下来返回AnimatorOverride脚本中,编写OnEnable和OnDisable方法,即添加和取消了OnItemSelectedEvent方法,首先我们通过语法糖来实现当前物品类型(ItemDetails)对应的PartType的什么类型currentType。我们目前想要实现的是将商品和种子视为可举起的类型,那么就先只编写这两个,剩下的之后在写即可(当我们添加新的工具之后一定会有新的动画,此时我们就需要将这个语法糖补充完整)。然后我们编写新的方法SwitchAnimator通过currentType实现动画的切换,在SwitchAnimator方法中我们先要遍历AnimatorType列表,如果某一项的PartType刚好等于currentType,此时我们就要切换动画,那么我们怎么切换动画嘞?
还记得当时定义的字典嘛,我们可以使用AnimatorType列表中的PartName匹配到字典中的Animator组件,并切换该组件的AnimatorController为AnimatorType列表中的override Controller。
我们还需要调用这个方法,但是调用这个方法前我们还需要对是否选择了该物体的bool值进行判断,如果该物体没有被选择,将currentType赋值为PartType.None,并且将holdItem设置为未激活状态;如果该物体被选择的话,那么将ItemDetails的itemOnWorldSprite赋值给holdItem的Sprite Renderer,同时激活HoldItem即可。

AnimatorOverride脚本代码如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class AnimatorOverride : MonoBehaviour
{
private Animator[] animators;
public SpriteRenderer holdItem;

[Header("各部分动画列表")]
public List<AnimatorType> animatorTypes;

private Dictionary<string, Animator> animatorNameDict = new Dictionary<string, Animator>();

private void Awake()
{
    animators = GetComponentsInChildren<Animator>();

    foreach (var anim in animators)
    {
        animatorNameDict.Add(anim.name, anim);
    }
}

private void OnEnable()
{
    EventHandler.ItemSelectedEvent += OnItemSelectedEvent;
}


private void OnDisable()
{
    EventHandler.ItemSelectedEvent -= OnItemSelectedEvent;
}

private void OnItemSelectedEvent(ItemDetails itemDetails, bool isSelected)
{
    //WORKFLOW:不同的工具返回不同的动画在这里补全
    //语法糖
    PartType currentType = itemDetails.itemType switch
    {
        ItemType.Seed => PartType.Carry,
        ItemType.Commodity => PartType.Carry,
        _=> PartType.None
    };

    if (isSelected == false)
    {
        currentType = PartType.None;
        holdItem.enabled = false;
    }
    else
    {
        if (currentType == PartType.Carry)
        {
            holdItem.sprite = itemDetails.itemOnWorldSprite;
            holdItem.enabled = true;
        }
    }

    SwitchAnimator(currentType);
}

private void SwitchAnimator(PartType partType)
{
    foreach(var item in animatorTypes)
    {
        if (item.partType == partType)
        {
            animatorNameDict[item.partName.ToString()].runtimeAnimatorController = item.overrideController;
        }
    }
}

}

二、绘制房子和可以被砍伐的树

本小节我们将我们的场景丰富一些。
首先先进行房子的绘制(绘制步骤我忘了,所以返回之前的文章重新复习了一遍)。过程如下:首先点击Tile Palette,然后创建新的Palette(TileMaps文件夹-> Palettes),接着将房子的图片拖入新建的Palette,这些图片存放在TileMap文件夹->Tiles中,然后选择除了房顶外的部分并且选择Active Tilemap为Ground Top,然后在地图中进行绘制,接着将房顶绘制在Front1层中,这样就会完全遮盖Player。
接着我们要为房子画上碰撞体,切换至Collision的Palette,然后选择Active Tilemap为Collision,并将01.Field场景中的Collision物体身上的Tilemap Renderer激活,这样我们绘制的碰撞体就可以在地图上看到了,方便绘制(我们绘制完成后关闭即可)。

我绘制的房子碰撞体如下

在这里插入图片描述
接着我们制作可以被砍倒的树,首先需在M_Studio->Art->Items->Tree01和Tree02,我们制作一个,另一个同理即可。
首先将Tree01_Bottom拖入场景,然后更改其渲染方式为Povit,更改层级为Instance,同理也将Tree01_Top也拖入场景,将其层级也改为Instance,同时层序为1,这样确保了树叶可以在树根上面显示,接着创建一个空物体改名为Tree01,然后将其位置与Buttom位置设置为相同的,并将Bottom和Top拖入作为其子物体,接着给该空物体添加Sorting Group组件,将其层级也设置为Instance,再添加Box Collider 2D,设置其大小,勾选Is Trigger,给其子物体都添加ItemFade脚本,最后在给Bottom添加Box Collider 2D并设置其大小。
最后将树拖拽至Prefab->Tree文件夹中作为预制体。

Tree的Box Collider 2D的大小设置如下:

在这里插入图片描述

标签:麦田,动画,PartType,public,第十四天,物语,物品,我们,Animator
From: https://blog.csdn.net/qq_52276934/article/details/140662953

相关文章

  • 麦田物语第十五天
    系列文章目录麦田物语第十五天文章目录系列文章目录一、构建游戏的时间系统二、时间系统UI制作总结一、构建游戏的时间系统在该游戏中我们要构建年月日天时分秒等时间的概念,从而实现季节的更替,昼夜的更替等(不同的季节可以播种不同的种子)。首先在PersistentSce......
  • 学习c语言第十四天(调试+练习)
    一、调试所有发生的事情都一定有迹可循,如果问心无愧,就不需要掩盖也就没有迹象了,如果问心有愧就必然需要掩盖,那就一定会有迹象,迹象越多就越容易顺藤而上,这就是推理的途径。顺着这条途径顺流而下就是犯罪,逆流而上,就是真相。1.什么是调试调试(英语:Debugging/Debug),又称除错,......
  • steam休闲游戏推荐:《Mimpi Dreams》《Pizza Possum》《洞窟物语》
    对于想要放松娱乐的时刻,Steam平台上有一些非常受欢迎的休闲游戏,这里推荐三款:1、《Mimpi Dreams》《Mimpi Dreams》中文名为《米皮大冒险:梦境》,是一款由 Silicon Jelly 开发的冒险解谜游戏。该游戏的故事承接前作,小狗米皮在成功找到主人并一同回家后,某天夜晚受到梦魇的......
  • 第十四天笔记(外键)
    数据库之外键==========================、一、外键的介绍1、外键的定义让一张表记录的数据不要太过于冗余,在数据库中对表的关系进行解耦,尽量让表的数据单一化。2、外键的作用保持数据的一致性和完整性3、msyql数据库中的存储引擎?myisam(默认)innodb(外键需要用到inno......
  • 打卡第十四天!!(明天去看电影)
    重写重写都是方法的重写,和属性无关父类的引用指向了子类方法的调用之和定义的数据类型有关(左边)静态的方法和非静态方法区别很大1.有static时,b调用了B类的方法,因为b是用B类定义的2.没有static是,b调用的是对象的方法,而b使用A类new的Aa=newA();a.test();​......
  • 「代码随想录算法训练营」第十四天 | 二叉树 part4
    513.找树左下角的值题目链接:https://leetcode.cn/problems/find-bottom-left-tree-value/题目难度:中等文章讲解:https://programmercarl.com/0513.找树左下角的值.html视频讲解:https://www.bilibili.com/video/BV1424y1Z7pn题目状态:有点思路,但未通过,最后在ChatGPT的帮助下理......
  • 代码随想录算法训练营第十四天 | 226.翻转二叉树、101. 对称二叉树、 104.二叉树的最
    226.翻转二叉树题目:.-力扣(LeetCode)思路:前序遍历代码:classSolution{public:TreeNode*invertTree(TreeNode*root){if(root!=NULL){swap(root->left,root->right);invertTree(root->left);invertTree(root->right);}......
  • 代码随想录算法训练营第十四天| 226.翻转二叉树 、101. 对称二叉树、104.二叉树的最大
    二叉树学习2226题翻转二叉树,改一下前序递归遍历,每次遍历的时候都调换一下左右结点即可。classSolution{public:voidpreorder(TreeNode*root){if(root==nullptr){return;}TreeNode*tmp;tmp=root->left;......
  • 代码随想录算法训练营第十四天 | 226.翻转二叉树 101.对称二叉树 104.二叉树的最大深
    226.翻转二叉树题目:给你一棵二叉树的根节点root,翻转这棵二叉树,并返回其根节点。解题:思路:遍历的过程中交换每个节点的左右孩子。选择哪种遍历方式?中序不行,左中右,左边子节点交换完,处理中间交换了左节点和右节点,再处理右节点去交换时这个右节点就是原来的左节点,所以有一边就一......
  • 代码随想录算法训练营第十四天|二叉树递归遍历、迭代遍历、统一迭代
    二叉树遍历二叉树主要有两种遍历方式:深度优先遍历:先往深走,遇到叶子节点再往回走。深度优先遍历又分:前序遍历(中、左、右)中序遍历(左、中、右)后序遍历(左、右、中)广度优先遍历:一层一层的去遍历。(后面讲)递归遍历递归三要素确定递归函数的参数和返回值:确定哪些参数是递......