当前位置:网站首页>Farm Game

Farm Game

2022-06-22 01:41:00 Sunny summer.

Environment settings

stay package manager Deleting useless packages in can make the speed faster .

Find... In the material :

In order to make other material pictures follow this way , You can create a preset with the current settings .

Then you can select multiple objects at the same time , Let them apply the same preset .

How to cut pictures :

Next, cut the character animation in the same way :

When cutting, because the animation is 8 frame , Select cut 8 individual , The anchor point is selected on the sole of the foot to achieve a correct occlusion effect . 

Next, create a character ,

  Select the bottom of the character's anchor here

Create a character :

In order to prevent some parts of the character from blocking other objects , produce “ Separation ” The phenomenon of , Add one sorting group

Add a... To the parent object sorting group You can make parent and child objects render together

Then create a new layer , Set several sub objects to

 

Next, we hope to achieve this effect ( Because it's a game of looking down )( When the character walks in front of the grass, he will cover the grass ( This goes to the front and back not through z Axis , But through y Axis )):

But in 2d Under the circumstances , The occlusion relationship before and after rendering at the same level is through z Axis implementation . We hope to pass y Axis to achieve , Then modify as follows :

( Note that the anchor point of the object should be set at the bottom )

  Character movement code

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

public class Player : MonoBehaviour
{
    public float speed = 5;
    Rigidbody2D rb;
    private float inputX;
    private float inputY;
    private Vector2 movementInput;

    private void Awake()
    {
        rb = GetComponent<Rigidbody2D>();
    }

    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        // use update Function accepts data , Instead of changing the rigid body of the object 
        PlayerInput();   
    }

    private void FixedUpdate()
    {
        // For changing the motion of a rigid body , Use fixupdate To achieve 
        Movement();
    }

    private void PlayerInput()
    {
        inputX = Input.GetAxisRaw("Horizontal");
        inputY = Input.GetAxisRaw("Vertical");
        if (inputX != 0 && inputY != 0)
        {
            inputX *= 0.6f;
            inputY *= 0.6f;
        }
        movementInput = new Vector2(inputX, inputY);
    }


    private void Movement()
    {
        rb.MovePosition(rb.position + movementInput * speed * Time.deltaTime);
    }
}

In order to better interact with the environment , Create a series of tile maps , It is in different sorting layer On :

 

  • Create tile information for rules

Then according to the rules you want to set , You can draw a regular map

Notice that there is such a gap between tile maps :

resolvent :

Create a Sprite Altas, This atlas will pack all the materials together , Ignore the atlas when referencing .

take Maps And other map materials that need to be packaged in this folder , That is to say .

Adding this camera makes  

  • Collisional layer

To produce a collision effect , And the collision is a whole , Add these three components and set them as follows :

Next, draw the air wall :

You can modify the collision volume of the triangle , Manually adjust... In the following way :

  The collision volume changes ​​​

​​​​

Next, draw the collision body according to the map :

Create the tree and its corresponding animation :

  • Add camera boundaries

Create a boundary , add to polygon coiilder And set the boundary range :

Next, we want to read different scenes , The camera will read the boundary of the scene and set the boundary :

For the... Added above polygon collider add to tag.

Then add the following code for the virtual camera :

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

public class SwitchBounds : MonoBehaviour
{

    private void Start()
    {
        SwitchConfinerShape();
    }
    private void SwitchConfinerShape()
    {
        PolygonCollider2D confinerShape = GameObject.FindGameObjectWithTag("BoundsConfiner").GetComponent<PolygonCollider2D>();

        CinemachineConfiner confiner = GetComponent<CinemachineConfiner>();

        confiner.m_BoundingShape2D = confinerShape;

        //Call this if the bounding shape's points change at runtime
        confiner.InvalidatePathCache();
    }
}

  • Semi occlusion and transparency of landscape

Simply put, walk behind the tree , Trees become translucent .

The method of making the tree gradient can be triggered trigger Function using a coroutine , Let the tree α Value slowly from 1 become 0.

Use here DOTween.

Call idea : Mount a script on the tree called ItemFader, This script has fade in and fade out functions :

using UnityEngine;
using DG.Tweening;


[RequireComponent(typeof(SpriteRenderer))]
public class ItemFader : MonoBehaviour
{
    private SpriteRenderer spriteRenderer;


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

    public void FadeIn()
    {
        Color targetColor = new Color(1, 1, 1, 1);
        spriteRenderer.DOColor(targetColor, Settings.fadeDuration);
    }

    public void FadeOut()
    {
        Color targetColor = new Color(1, 1, 1, Settings.targetAlpha);
        spriteRenderer.DOColor(targetColor, Settings.fadeDuration);
    }

}

To facilitate the subsequent search for changed data , Build a setting Scripts are used to store constants :

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

public class Settings
{
    public const float fadeDuration = 0.35f;

    public const float targetAlpha = 0.45f;

}

When the player triggers trigger Function time , Get all the sub objects of the collision body ItemFader Script , Then call the fade in and fade out functions .

The effect is as follows :

Backpack system

Backpack data initialization

use MVC The pattern of , Will control 、 data 、 Separate from the display one by one , adopt inventory manager To manage data , And call through it UI Display content of .

Create a DataCollection, We will put all our classes in this file , Convenient for centralized management , Find and modify .


using UnityEngine;

[System.Serializable]
// Used to store item details  
public class ItemDetails
{
    public int itemID;
    public string name;

    public ItemType itemType;

    public Sprite itemIcon;
    public Sprite itemOnWorldSprite;

    public string itemDescription;
    public int itemUseRadius;

    public bool canPickedup;
    public bool canDropped;
    public bool canCarried;
    public int itemPrice;

    [Range(0, 1)]
    public float sellPercentage;
}

  • Enums establish ItemType Item type

public enum ItemType
{
    Seed,Commodity,Furniture,
    HoeTool,ChopTool,BreakTool,ReapTool,WaterTool,CollectTool,
    ReapableScenery
}

  • Generate ItemDetailsList_SO The file is used as the object management database of the whole game

Create a SO menu bar , Their corresponding SO Contains many items , So it's using List<ItemDetails> Data structure of .

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


[CreateAssetMenu(fileName ="ItemDataList_SO",menuName ="Inventory/ItemDataList")]

public class ItemDataList_SO : ScriptableObject
{
    public List<ItemDetails> itemDetailsList;
}

Create a folder to manage data , And create an example SO.

(Editor) Use UI Toolkit and UI Builder Make an item editor

  • Write it yourself ItemDataLis_SO

The goal is to design it like this

UIToolKit You can edit it visually Customer Editor, stay runtime You can also use .

Create a Editor Folder :(Editor Folders are not packed when they are packed )

Create this  

Three files will be generated :

After making the editor , Add the following items :

establish InventoryManager

Singleton mode code


using UnityEngine;

public class Singleton<T> : MonoBehaviour where T : Singleton<T>
{
    private static T instance;

    public static T Instance
    {
        get => instance;
    }

    protected virtual void Awake()
    {
        if (instance != null)
            Destroy(gameObject);
        else instance = (T)this;
    }


    protected virtual void OnDestroy()
    {
        if (instance != this)
            instance = null;
    }

}

  by inventory manager Add namespace , Easy to manage data , Avoid the coupling of random calls to each other .

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

namespace MFarm.Inventory
{
    public class InventoryManager : Singleton<InventoryManager>
    {
        public ItemDataList_SO ItemDataList_SO;
    }

}

After adding a namespace , Want to use... In other code inventoryManager, should using This namespace .

Add a pass to it ID Find the complete code after the function :

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

namespace MFarm.Inventory
{
    public class InventoryManager : Singleton<InventoryManager>
    {
        public ItemDataList_SO ItemDataList_SO;


        /// <summary>
        /// 
        /// adopt ID Return item information 
        /// </summary>
        /// <param name="ID"></param>
        /// <returns></returns>
        public ItemDetails GetItemDetails(int ID)
        {
            // Find some itemDetails, its ID Equal to the given ID
            return ItemDataList_SO.itemDetailsList.Find(i => i.itemID == ID);
        }

    }



}

Add this in the main scene and bind SO, Because it's in the main scene , So this does not need to be changed during scene switching . 

Realize the display of items in the database on the map

Create a itemBase, Its effect is , When some items are generated in the scene , For example, cutting down trees will produce wood , And fruit blossoms to produce seeds . We hope that in these cases , You can use code to inventoryManager Get... Inside ID Corresponding item details .

Add a collider to it , The function is, for example, when the player touches , Just add it to your backpack .

Next, the code will be used to determine the ID Show different items , The idea is simple , It is through ID Go to the database to get the corresponding pictures and display them . Different pictures have different sizes , Therefore, modify the volume of the collision body according to the size of the image .

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

namespace MFarm.Inventory
{


    public class Item : MonoBehaviour
    {
        public int itemID;

        private SpriteRenderer spriteRenderer;
        private BoxCollider2D coll;
        private ItemDetails itemDetails;

        private void Awake()
        {
            spriteRenderer = GetComponentInChildren<SpriteRenderer>();
            coll = GetComponent<BoxCollider2D>();
        }

        private void Start()
        {
            if (itemID != 0)
            {
                Init(itemID);
            }
        }

        public void Init(int ID)
        {
            itemID = ID;

            //Inventory Get current data 
            itemDetails = InventoryManager.Instance.GetItemDetails(itemID);

            // Because the returned result may be empty , If the picture is displayed when it is not empty 
            if (itemDetails != null)
            {
                spriteRenderer.sprite = itemDetails.itemOnWorldSprite != null ? itemDetails.itemOnWorldSprite : itemDetails.itemIcon;

                // Modify the collider size , Make it correspond to different pictures one by one 
                Vector2 newSize = new Vector2(spriteRenderer.sprite.bounds.size.x, spriteRenderer.sprite.bounds.size.y);
                coll.size = newSize;
                coll.offset = new Vector2(0, spriteRenderer.sprite.bounds.center.y);
            }
        }

    }

}

  • Pick up items

The logic of picking up items is as follows , Add a script for players to pick up items , When triggered trigger when , Get the... Of the object item Components , And then if there is item Components , Then call the database InventoryManager Medium AddItem function , Add items to your backpack .

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

namespace MFarm.Inventory
{
    public class ItemPickUp : MonoBehaviour
    {
        private void OnTriggerEnter(Collider other)
        {
            Item item = other.GetComponent<Item>();

            if (item != null)
            {
                if (item.itemDetails.canPickedup)
                {
                    InventoryManager.Instance.AddItem(item, true);
                }
            }


        }
    }
}

stay InventoryManager Add the following code to :

        /// <summary>
        ///  Add items to Player In the backpack 
        /// </summary>
        /// <param name="item"></param>
        /// <param name="toDestory"> Do you want to destroy items </param>
        public void AddItem(Item item, bool toDestory)
        {
            Debug.Log(GetItemDetails(item.itemID).itemID + "Name: " + GetItemDetails(item.itemID).itemName);
            if (toDestory)
            {
                Destroy(item.gameObject);
            }
        }

Backpack system

It's a backpack SO Code :

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


[CreateAssetMenu(fileName ="InventoryBag_SO",menuName ="Inventory/InventoryBag_SO")]
public class InventoryBag_SO : ScriptableObject
{
    public List<InventoryItem> itemList;
}

This backpack is suitable for everything , In addition to the player's own backpack , It can also be npc The store .

 

You need to think about adding an object , Whether the backpack is full , Whether there is this item , All these need to be in AddItem To implement inside .

stay InventoryManager This function can be realized by adding the following code in :

        /// <summary>
        ///  Add items to Player In the backpack 
        /// </summary>
        /// <param name="item"></param>
        /// <param name="toDestory"> Do you want to destroy items </param>
        public void AddItem(Item item, bool toDestory)
        {

            var index = GetItemIndexInBag(item.itemID);
            AddItemAtIndex(item.itemID,index,1);


            // You need to think about adding an object , Whether the backpack is full , Whether there is this item 
            Debug.Log(GetItemDetails(item.itemID).itemID + "Name: " + GetItemDetails(item.itemID).itemName);
            if (toDestory)
            {
                Destroy(item.gameObject);
            }
        }


        /// <summary>
        ///  Check if the backpack is empty 
        /// </summary>
        /// <returns></returns>
        private bool CheckBagCapacity()
        {
            for(int i = 0; i < playerBag.itemList.Count;i++)
            {
                if (playerBag.itemList[i].itemID == 0)
                {
                    return true;
                }
            }
            return false;
        }

        /// <summary>
        ///  according to ID Find out if there is this thing in the bag 
        /// </summary>
        /// <param name="ID"></param>
        /// <returns></returns>
        private int GetItemIndexInBag(int ID)
        {
            for (int i = 0; i < playerBag.itemList.Count; i++)
            {
                if (playerBag.itemList[i].itemID == ID)
                {
                    return i;
                }
            }
            return -1;
        }


        private void AddItemAtIndex(int ID,int index,int amount)
        {

            if (index == -1&&CheckBagCapacity())
            {
                var item = new InventoryItem { itemID = ID, itemAmount = amount };

                for (int i = 0; i < playerBag.itemList.Count; i++)
                {
                    if (playerBag.itemList[i].itemID == 0)
                    {
                        playerBag.itemList[i] = item;
                        break;
                    }
                }
            }
            else
            {
                int currentAmount = playerBag.itemList[index].itemAmount + amount;

                var item = new InventoryItem { itemID = ID, itemAmount = currentAmount };

                playerBag.itemList[index] = item;
            }
        }

    }


 

原网站

版权声明
本文为[Sunny summer.]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/173/202206212304243683.html