麦田物语第二十二天

系列文章目录

麦田物语第二十二天



一、制作可以扔出来的物品

上节课我们制作了丢弃物品的功能,今天我们制作可以扔出来的物品,使其视觉效果上看起来更好。
我们首先将之前制作的预制体ItemBase拖入场景中,并解除其与预制体的联系(Unpack Competely),我们为这个物体添加方法使这个物体实现飞出去的效果(通过阴影等实现俯视角的视觉差)。
首先我们将这个物体的子物体添加图片,使其可以更好的显示,并为其更改名称为BounceItemBase,我们在其下方再添加空物体Shadow并添加Sprite Renderer组件,Shadow所显示的图片是我们子物体sprite的图片,但是我们将其颜色调成黑色并更改Alpha值为半透明,最后切记一定要将其Additional Settings的Sorting Layer设置为Instance。
我们要通过代码实现Shadow直接移动到指定区域(鼠标点按的位置),而Sprite下落到指定区域即可,那么我们现在就进行代码的编写吧!
首先我们需要的是阴影自动获取自己图片的代码,即我们丢弃物品时物品图片虽然已经选择好了,但是阴影图片我们需要重新获得,接着我们创建Scripts->Item->ItemShadow脚本并添加到Shadow上,首先将其添加到Inventory的命名空间,并且这个脚本必须需要SpriteRenderer组件,然后我们声明变量,一个是我们物体的SpriteRenderer,一个是阴影的SpriteRenderer,我们在Awake方法中获取阴影的SpriteRenderer,并在Unity中对物体的SpriteRenderer进行拖拽赋值,在游戏开始时(Start方法中)获取阴影的图片,即物体的图片,并且将其颜色更改为指定颜色(黑色半透明)。

ItemShadow脚本的代码如下:

namespace MFarm.Inventory
{
    [RequireComponent(typeof(SpriteRenderer))]
    public class ItemShadow : MonoBehaviour
    {
        public SpriteRenderer itemSprite;
        private SpriteRenderer shadowSprite;

        private void Awake()
        {
            shadowSprite = GetComponent<SpriteRenderer>();
        }

        private void Start()
        {
            shadowSprite.sprite = itemSprite.sprite;
            shadowSprite.color = new Color(0, 0, 0, 0.3f);
        }
    }
}

接着我们创建Scripts->Item->ItemBounce脚本,这个脚本的目的是为了实现物体和阴影的不同飞行路径,将这个脚本挂载在BounceItemBase上,接着来编写这个脚本,首先我们需要声明Sprite的Transform变量spriteTrans,并在Awake方法中获取,同时游戏物体时从人物身上开始飞的,我们就要在其扔出去的过程中关闭其碰撞体防止碰撞,所以我们也要声明物体的碰撞体coll,在Awake方法中获取并关闭其碰撞体,还要进行一些变量的声明,例如我们需要声明物体下落的力gravity(自己定义的重力),物体下落到下面的标志(bool)isGround,物体运动的距离distance,物体运动的方向(Vector2)direction以及物体运动的目标位置(Vector3)targetPos,最后的这两个变量是用来存储传过来鼠标点击的位置,并在Update方法持续执行。
然后我们编写InitBounceItem方法,在这个方法中将碰撞体设置为不可用,并对direction,targetPos,distance,spriteTrans进行赋值,这些赋值方法需要重点说明一下:distance应该是两个向量之间的距离,即目标向量和当前物品向量的距离,这个物体位置也是初始化好的,因此我们在Awake方法中调用这个方法,最后我们将spriteTrans的位置进行更改,刚好放在人物头顶的位置。
接着我们在编写Bounce方法,用于丢弃的过程制作,首先我们要进行isGround方法的判断(spriteTrans的位置小于等于物体当前的位置),接着我们if判断该物体的位置是否到达目标位置,如果未到达,那么就一直进行移动,使得物品的位置在其方向上以一个基于距离的力(其实就是距离)在乘以(-重力)和Time.deltaTime,这样就实现了物品的水平的移动;接着我们要实现垂直方向的移动,如果物体未落地,类似于上面代码的使物品的位置向下,如果物品落地,那么将物品的位置和阴影的位置进行重合(此处用的是空物体的位置),并且开启其碰撞体的碰撞设置。

ItemBounce脚本的代码如下:

namespace MFarm.Inventory
{
    public class ItemBounce : MonoBehaviour
    {
        private Transform spriteTrans;
        private BoxCollider2D coll;
        public float gravity = -3.5f;
        private bool isGround;
        private float distance;
        private Vector2 direction;
        private Vector3 targetPos;

        private void Awake()
        {
            spriteTrans = transform.GetChild(0);
            coll = GetComponent<BoxCollider2D>();
            coll.enabled = false;
        }

        private void Update()
        {
            Bounce();
        }

        public void InitBounceItem(Vector3 target, Vector2 dir)
        {
            coll.enabled = false;
            direction = dir;
            targetPos = target;
            distance = Vector3.Distance(target, transform.position);

            spriteTrans.position += Vector3.up * 1.5f;
        }

        private void Bounce()
        {
            isGround = spriteTrans.position.y <= transform.position.y;

            //物品的位置未到达目标的位置
            if (Vector3.Distance(transform.position, targetPos) > 0.1f)
            {
                transform.position += (Vector3)direction * distance * -gravity * Time.deltaTime;
            }

            if (!isGround)
            {
                spriteTrans.position += Vector3.up * gravity * Time.deltaTime;
            }
            else
            {
                spriteTrans.position = transform.position;
                coll.enabled = true;
            }
        }
    }
}

最后我们返回ItemManager脚本,在脚本中添加变量bounceItemPrefab,返回Unity为其赋值,同时我们希望物品生成的位置在人物的脚底位置,因此我们需要声明人物的位置playerTransform并获取,然后在OnDropItem方法中更改Instantiate的生成物体为bounceItemPrefab,并且生成的位置也更改成playerTransform;接下来我们定义方向(即鼠标位置减去人物位置并进行归一化),并且调用新生成的物体身上的InitBounceItem方法,返回Unity运行即可。

ItemManager脚本的新添加的代码如下:

namespace MFarm.Inventory
{
    public class ItemManager : MonoBehaviour
    {
        public Item bounceItemPrefab;
        private Transform playerTrans => FindObjectOfType<Player>().transform;
      
        private void OnDropItemEvent(int ID, Vector3 mousePos)
        {
            //TODO:扔东西的效果
            var item = Instantiate(bounceItemPrefab, playerTrans.position, Quaternion.identity, itemParent);
            item.itemID = ID;
            var dir = (mousePos - playerTrans.position).normalized;
            item.GetComponent<ItemBounce>().InitBounceItem(mousePos, dir);
        }

    }
}

二、实现挖坑和浇水的地图更改变化

当我们鼠标选择锄头后,我们点击可挖掘的位置,可以实现挖坑的效果,同时在挖坑之后的位置点击水壶之后可以进行浇水,那么我们这节课就来实现这个功能。
我们当时在01.Field场景中制作了可挖坑的Tilemap,现在我们希望实现下图的效果,就想我们当时绘制草地的时候一样,按照一定的规则生成,于是我们创建Tilemap->Rule Tiles->Dig Tile和Water Tile。挖坑的规则如下(浇水的瓦片与它相似,这里就不展示了):
在这里插入图片描述
挖坑的规则瓦片信息

那么我们怎么在游戏运行的情况下来切换这个瓦片嘞?我们可以使用Tilemap的SetTile方法,这个可以去查阅代码手册查看其使用方法,我们已经知道了用什么方法,现在就是需要编写代码,通过鼠标点击进行挖坑和浇水。
我们首先给01.Field场景的Dig和Water添加标签Dig和Water,然后我们返回GridMapManager脚本中,添加新的变量,例如Dig和Water的Tilemap(通过标签在OnAfterSceneLoadedEvent方法中获取)和Rule Tile(在Unity中直接赋值);接着编写浇水和挖坑的方法SetWaterGround和SetDigGround,我们以SetDigGround为例,因为我们调用SetTile方法时需要一个Vector3Int类型的变量,所有我们需要将该方法的参数转变为需要的变量,接着调用该方法,在相应的位置绘制该瓦片即可。我们编写完这个方法后,就可以在OnExecuteActionAfterAnimation中调用了,当物品类型为锄头时,我们调用SetDigGround方法,并且将该位置的瓦片的daySceneDug,canDig,canDropItem都进行修改,同理当物品类型为水壶时,我们调用SetWaterGround方法,并更改其属性daysSinceWatered。

GridMapManager脚本的新增代码如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.Tilemaps;

namespace MFarm.Map
{
    public class GridMapManager : Singleton<GridMapManager>
    {

        [Header("种地瓦片切换信息")]
        public RuleTile digTile;
        public RuleTile waterTile;
        private Tilemap digTilemap;
        private Tilemap waterTilemap;

        private void OnAfterSceneLoadEvent()
        {
            currentGrid = FindObjectOfType<Grid>();
            digTilemap = GameObject.FindWithTag("Dig").GetComponent<Tilemap>();
            waterTilemap = GameObject.FindWithTag("Water").GetComponent<Tilemap>();
        }

        /// <summary>
        /// 在世界地图上执行实际工具或者物品功能
        /// </summary>
        /// <param name="mouseWorldPos">鼠标坐标</param>
        /// <param name="itemDetails">物品信息</param>
        private void OnExecuteActionAfterAnimator(Vector3 mouseWorldPos, ItemDetails itemDetails)
        {
            var mouseGridPos = currentGrid.WorldToCell(mouseWorldPos);
            var currentTile = GetTileDetailsOnMousePosition(mouseGridPos);

            if (currentTile != null)
            {
                //WORKFLOW:物品使用实际功能
                switch (itemDetails.itemType)
                {
                    case ItemType.Commodity:
                        EventHandler.CallDropItemEvent(itemDetails.itemID, mouseWorldPos);
                        break;
                    case ItemType.HoeTool:
                        SetDigGround(currentTile);
                        currentTile.daySceneDug = 0;
                        currentTile.canDig = false;
                        currentTile.canDropItem = false;
                        //设置音效
                        break;
                    case ItemType.WaterTool:
                        SetWaterGround(currentTile);
                        currentTile.daysSinceWatered = 0;
                        //设置音效
                        break;
                }
            }
        }

        /// <summary>
        /// 显示挖坑信息
        /// </summary>
        /// <param name="tile"></param>
        private void SetDigGround(TileDetails tile)
        {
            Vector3Int pos = new Vector3Int(tile.gridX, tile.gridY, 0);
            if (digTilemap != null)
                digTilemap.SetTile(pos, digTile);
        }

        /// <summary>
        /// 显示浇水信息
        /// </summary>
        /// <param name="tile"></param>
        private void SetWaterGround(TileDetails tile)
        {
            Vector3Int pos = new Vector3Int(tile.gridX, tile.gridY, 0);
            if (waterTilemap != null)
                waterTilemap.SetTile(pos, waterTile);
        }
    }
}

接着我们需要完善其他的代码,返回CursorManager脚本的CheckCursorValid方法,我们也需要补全这两个物品的判断类型,当当前的网格可以挖坑时,鼠标设置为有效状态,反之无效状态;浇水的判断也是同理,当前网格如果已经被挖坑,那么将鼠标设置为有效状态,反之设置为无效状态。

CursorManager脚本的CheckCursorValid方法代码如下:

private void CheckCursorValid()
    {
        mouseWorldPos = mainCamera.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y,-mainCamera.transform.position.z));
        mouseGridPos = currentGrid.WorldToCell(mouseWorldPos);

        var playerGridPos = currentGrid.WorldToCell(playerTransform.position);

        //判断是否在适用范围内
        if (Mathf.Abs(mouseGridPos.x - playerGridPos.x) > currentItem.itemUseRadius || Mathf.Abs(mouseGridPos.y - playerGridPos.y) > currentItem.itemUseRadius)
        {
            SetCursorInVaild();
            return;
        }

        //Debug.Log(mouseGridPos);
        TileDetails currentTile = GridMapManager.Instance.GetTileDetailsOnMousePosition(mouseGridPos);

        if (currentTile != null)
        {
            switch (currentItem.itemType)
            {
                case ItemType.Commodity:
                    if (currentTile.canDropItem && currentItem.canDropped) SetCursorVaild(); else SetCursorInVaild();
                    break;
                case ItemType.HoeTool:
                    if (currentTile.canDig) SetCursorVaild(); else SetCursorInVaild();
                    break;
                case ItemType.WaterTool:
                    if (currentTile.daySceneDug > -1 && currentTile.daysSinceWatered == -1) SetCursorVaild(); else SetCursorInVaild();
                    break;
            }
        }
        else
        {
            SetCursorInVaild();
        }
	}

返回Unity将锄头,水壶添加进入背包,并且尝试可不可以实现之前的方法嘞!!!
(我的现在还是有点问题,就是我的挖坑的位置总是偏移了一段距离)
两天后…
我终于知道为啥了,因为我刚开始的没有将Dig层的坐标归零,导致最后出现了x为-2,y为0.44的偏移,现在明白了坐标归零的重要性~~~(狗头)。
在这里插入图片描述

  • 16
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
麦田里的守望者》是美国作家J.D. Salinger所著的小说,该小说于1951年出版。该小说以第一人称叙述的方式,讲述了一位名叫霍尔顿·考尔菲尔德的十六岁男孩的故事,他在美国东部的一所寄宿学校度过了一个寒假。小说通过霍尔顿的视角,描绘了他的思想、情感和经历,反映了他对社会、人性和成长的认识与探索。 在近年来的研究中,学者们主要从以下几个方面对《麦田里的守望者》进行了文献综述: 1. 霍尔顿的反叛心理。许多学者探讨了霍尔顿的反叛心理,认为他的反叛是对社会价值观的质疑和对现实生活的不满。他试图保持自己的纯真和真实,而对于社会的虚伪和不公,他感到无法接受。 2. 霍尔顿的孤独与心理问题。一些学者认为,霍尔顿的孤独和心理问题是导致他反叛的原因之一。他对周围的人和事都持怀疑态度,感到难以融入社会。同时,他也存在着一些心理问题,如焦虑、抑郁等,这些问题影响着他的生活和行为。 3. 霍尔顿的成长与人性观。还有一些学者认为,霍尔顿的故事是一种成长与人性探索的过程。他在寻找自己的价值观和人生意义的过程中,经历了一系列的挫折和成长。他逐渐认识到人性的复杂性和社会的不完美性,也逐渐接受了自己的缺点和弱点。 4. 《麦田里的守望者》的文学价值。这部小说被认为是现代文学的经典之作,因为它深入地揭示了人类内心的复杂性和社会的种种问题。它的语言简洁、生动,情节紧凑,给人留下了深刻的印象。 综上所述,《麦田里的守望者》是一部充满探索与思考的小说,它通过一个十六岁男孩的视角,反映了现代社会中普遍存在的问题,也引发了人们对于成长、人性和社会的深入思考。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值