Unity3D仿星露谷物语开发45之收集农作物特效

发布于:2025-05-21 ⋅ 阅读:(18) ⋅ 点赞:(0)

1、目的

收集农作物的特效制作。

2、动画制作

(1)已有动画系统

在Assets -> Animation -> Crop -> Standard下有Crop的动画信息。

harvestleft/harvestright:比如防风草收获时的动效

usetoolleft/usetoolright:需要借助工具才能收获的动销,比如使用斧头砍树,树会左右晃动

点击CropPickedLeft的Animation Clip,选择Unity Model,点击播放,没有任何反应。我们需要根据这个Clip进行定制。

在Animation界面中,CropHarvestLeft使用了CropPickedLeft动画,CropHarvestRight使用了CropPickedRight动画,但是都使用了同一个Sprite游戏对象。

我们需要修改标准预制作物(Prefabs下的CropStandard),在其中增加一些额外的东西,同时符合原有的动画结构。

(2)修改Prefab

Assets -> Prefabs -> Crop,给CropSprite添加动画器组件。

我们需要一个子游戏对象,在这个游戏对象的根级别下面,创建新物体命名为CropHarvestedSprite,这个游戏对象就是Animator要操纵的游戏物体。

添加Sprite Renderer组件,并且修改Sorting Layer为Instances。

3、修改Crop.cs脚本

[Tooltip("This should be populated from child gameobject")]
[SerializeField] private SpriteRenderer cropHarvestedSpriteRenderer = null;

接下来就是用代码来触发动画特效。

添加其他修改后,完整的代码如下:
 

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

public class Crop : MonoBehaviour
{
    [HideInInspector]
    public Vector2Int cropGridPosition;

    [Tooltip("This should be populated from child gameobject")]
    [SerializeField] private SpriteRenderer cropHarvestedSpriteRenderer = null;

    private int harvestActionCount = 0;

    public void ProcessToolAction(ItemDetails equippedItemDetails, bool isToolRight, bool isToolLeft, bool isToolDown, bool isToolUp)
    {
        // Get grid property details
        GridPropertyDetails gridPropertyDetails = GridPropertiesManager.Instance.GetGridPropertyDetails(cropGridPosition.x, cropGridPosition.y);

        if (gridPropertyDetails == null)
            return;

        // Get seed item details
        ItemDetails seedItemDetails = InventoryManager.Instance.GetItemDetails(gridPropertyDetails.seedItemCode);
        if(seedItemDetails == null) return;

        // Get crop details
        CropDetails cropDetails = GridPropertiesManager.Instance.GetCropDetails(seedItemDetails.itemCode);
        if (cropDetails == null) return;

        // Get animator for crop if present
        Animator animator = GetComponentInChildren<Animator>();

        // Trigger tool animation
        if(animator != null)
        {
            if(isToolRight || isToolUp)
            {
                animator.SetTrigger("usetoolright");
            }
            else if(isToolLeft || isToolDown)
            {
                animator.SetTrigger("usetoolleft");
            }
        }

        // Get required harvest actions for tool(收获此农作物所需的操作次数)
        int requiredHarvestActions = cropDetails.RequiredHarvestActionsForTool(equippedItemDetails.itemCode);
        if (requiredHarvestActions == -1) return;

        // Increment harvest action count
        harvestActionCount++;

        // Check if required harvest actions made
        if (harvestActionCount >= requiredHarvestActions)
            HarvestCrop(isToolRight, isToolUp, cropDetails, gridPropertyDetails, animator);

    }


    private void HarvestCrop(bool isUsingToolRight, bool isUsingToolUp, CropDetails cropDetails, GridPropertyDetails gridPropertyDetails, Animator animator)
    {
        // Is there a harvested animation
        if(cropDetails.isHarvestedAnimation && animator != null)
        {
            // if harvest sprite then add to sprite renderer
            if(cropDetails.harvestedSprite != null)
            {
                if(cropHarvestedSpriteRenderer != null)
                {
                    cropHarvestedSpriteRenderer.sprite = cropDetails.harvestedSprite;  // 一张图片
                }
            }

            if(isUsingToolRight || isUsingToolUp)
            {
                animator.SetTrigger("harvestright");
            }
            else
            {
                animator.SetTrigger("harvestleft");
            }
        }



        // Delete crop from grid properties
        gridPropertyDetails.seedItemCode = -1;
        gridPropertyDetails.growthDays = -1;
        gridPropertyDetails.daysSinceLastHarvest = -1;
        gridPropertyDetails.daysSinceWatered = -1;

        // Should the crop be hidden before the harvested animation
        if (cropDetails.hideCropBeforeHarvestedAnimation)
        {
            GetComponentInChildren<SpriteRenderer>().enabled = false;
        }


        GridPropertiesManager.Instance.SetGridPropertyDetails(gridPropertyDetails.gridX, gridPropertyDetails.gridY, gridPropertyDetails);

        // Is there a harvested animation - Destory this crop game object after animation completed
        if(cropDetails.isHarvestedAnimation && animator != null)
        {
            StartCoroutine(ProcessHarvestedActionsAfterAnimation(cropDetails, gridPropertyDetails, animator));
        }
        else
        {
            HarvestActions(cropDetails, gridPropertyDetails);
        }
           
    }

    private IEnumerator ProcessHarvestedActionsAfterAnimation(CropDetails cropDetails, GridPropertyDetails gridPropertyDetails, Animator animator)
    {
        while (!animator.GetCurrentAnimatorStateInfo(0).IsName("Harvested"))
        {
            // 等待动画播放完毕
            yield return null;
        }

        HarvestActions(cropDetails, gridPropertyDetails);
    }




    private void HarvestActions(CropDetails cropDetails, GridPropertyDetails gridPropertyDetails)
    {
        SpawnHarvestedItems(cropDetails);

        Destroy(gameObject);  // destory当前Crop类所挂载的实例
    }

    private void SpawnHarvestedItems(CropDetails cropDetails)
    {
        // Spawn the item(s) to be produced
        for(int i = 0; i < cropDetails.cropProducedItemCode.Length; i++)
        {
            int cropsToProduce;

            // Calculate how many crops to produce
            if (cropDetails.cropProducedMinQuantity[i] == cropDetails.cropProducedMaxQuantity[i] ||
                cropDetails.cropProducedMaxQuantity[i] < cropDetails.cropProducedMinQuantity[i])
            {
                cropsToProduce = cropDetails.cropProducedMinQuantity[i];
            }
            else
            {
                cropsToProduce = Random.Range(cropDetails.cropProducedMinQuantity[i], cropDetails.cropProducedMaxQuantity[i] + 1);
            }

            for(int j = 0; j < cropsToProduce; j++)
            {
                Vector3 spawnPosition;
                if (cropDetails.spawnCropProducedAtPlayerPosition)
                {
                    // Add item to the players inventory
                    InventoryManager.Instance.AddItem(InventoryLocation.player, cropDetails.cropProducedItemCode[i]);
                }
                else
                {
                    // Random position
                    spawnPosition = new Vector3(transform.position.x + Random.Range(-1f, 1f), transform.position.y + Random.Range(-1f, 1f), 0f);
                    SceneItemsManager.Instance.InstantiateSceneItem(cropDetails.cropProducedItemCode[i], spawnPosition);
                }
            }
        }
    }

}

4、修改Player.cs脚本 

修改ProcessCropWithEquippedItemInPlayerDirection函数,根据ProcessToolAction的调整,相应增加4个参数如下:

5、修改CropStandard预制体信息

6、运行游戏

此时收集防风草,就看到了防风草升起来的动效了。

7、优化脚本

当种植防风草种子的时候,程序运行正常。

当种植其他中的时候,程序就会报错,报错信息如下:

这是因为我们的So_CropDetailsList只配置了10006这一个种子的信息,所以获取不到其他种子的信息。

(1)优化Play.cs脚本

针对PlantSeedAtCursor函数添加校验:

(2)优化GridPropertiesManager.cs脚本

针对DisplayPlantedCrop函数添加校验:

此时,种植橡木种子不会报错,当然也不会有任何效果。


网站公告

今日签到

点亮在社区的每一天
去签到