管理场景流和数据&面向对象

 

管理场景流和数据

面向对象

  • 抽象
public class 00PTest : MonoBehaviour
{
    class Animal
    {

        public string name;
        public virtual string shout()
//virtual代表虚方法可重写,此父类方法已经被子类重写,所以在此父类方法中返回什么没有意义
        {
            return this.name;
        }


     class Cat : Animal//继承 Animal类,父类里的方法属性等 子类可以用
    {
        public override string shout()//override重写父类方法
        {
             return this.name +",喵喵";
        }
   
    }
    class Dog : Animal
     {
        public override string shout()
        {
             return this.name +",汪汪";
        }
   
    }
    void Start()
    {
        Cat cat1 = new Cat();
        cat1.name ="咪咪";
        Debug.Log(cat1.shout());

        Dog dog1 = new Dog();
        dog1.name ="旺财";
        Debug.Log(dog1.shout());
    }
}
public class 00PTest : MonoBehaviour
{
    abstract class Animal
//abstract代表抽象类,抽象类不一定非要有抽象方法,抽象类不能用,不能new
//当需要一个类不能实例化时,用到抽象类
    {

        public string name;
        public abstract string shout();//抽象方法没有方法体
//定义为抽象方法,所在的类必须也为抽象类,此方法需被重写才有意义

//只要有一个抽象方法 所在类必须是抽象类
     class Cat : Animal//继承 Animal类,父类里的方法属性等 子类可以用
    {
        public override string shout()//override重写父类方法
        {
             return this.name +",喵喵";
        }
   
    }
    class Dog : Animal
     {
        public override string shout()
        {
             return this.name +",汪汪";
        }
   
    }
    void Start()
    {
        Cat cat1 = new Cat();
        cat1.name ="咪咪";
        Debug.Log(cat1.shout());

        Dog dog1 = new Dog();
        dog1.name ="旺财";
        Debug.Log(dog1.shout());
        
         //多态:多种形态,声明变量时使用的是父类,new变量时使用的是子类
        Animal a1=new Cat();
//如果定义时用的父类定义
//a1调用的方法也只能是父类有的方法调用不出来子类Cat的自己的方法(父类没有的方法),
//当我们要实现多个子类来回切换时(需要new不同的子类),需要用父类定义,
//防止调用了子类自己独特的方法,导致出错
        Debug.Log(a1.shout);//喵喵
        a1=new Dog();
        Debug.Log(a1.shout);//汪汪

       // IList l1=new ArrayList();
       // l1.Add(11);
       // l1.Add(22);
    }
}
  • 重写和重载

重写是将父类方法重写,重载是方法相同参数不同(virtual) 

  • 私有变量与可见性
pubulic class Rabbit:MonoBehaviour
{
    //防止被而已更改并且也能在检查器中显示
    [SerializaField]//序列化 暴露私有属性到inspector中,
    private Color furColor;

    public static Rabbit Instance{get;};//虽然是公有变量,但其他地方只能得到不能修改
    //{get;set;}外部能修改能得到 {get;private set;}只有内部能修改 外部能得到不能修改

}

    public float m_ProductionSpeed = 0.5f;
    public float ProductionSpeed//一旦被修改就会触发set里的内容,无论在内部还是在外部,这时会进入死循环
    {//此时需要再定义一个变量值m_ProductionSpeed,赋值0.5,外部获取时将m_ProductionSpeed返回,一旦内外设置ProductionSpeed变量时即触发set更改m_ProductionSpeed值
        //如果依然用ProductionSpeed进行get中的返回和set中的改值,set中的赋值操作会一直触发进入死循环
        get { return m_ProductionSpeed; }
        set {
            if (value < 0f)//value为要赋的值
            {
                Debug.Log("报错");
            }
            else
            {
                m_ProductionSpeed = value;
            }
        }
    }

源码

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


// Base class for all Unit. It will handle movement order given through the UserControl script.
// It require a NavMeshAgent to navigate the scene.
[RequireComponent(typeof(NavMeshAgent))]
public abstract class Unit : MonoBehaviour,
    UIMainScene.IUIInfoContent
{
    public float Speed = 3;

    protected NavMeshAgent m_Agent;
    protected Building m_Target;

    protected void Awake()
    {
        m_Agent = GetComponent<NavMeshAgent>();
        m_Agent.speed = Speed;
        m_Agent.acceleration = 999;
        m_Agent.angularSpeed = 999;
    }

    private void Start()
    {
        if (MainManager.Instance != null)
        {
            SetColor(MainManager.Instance.TeamColor);
        }
    }

    void SetColor(Color c)
    {
        var colorHandler = GetComponentInChildren<ColorHandler>();
        if (colorHandler != null)
        {
            colorHandler.SetColor(c);
        }
    }

    private void Update()
    {
        if (m_Target != null)
        {
            float distance = Vector3.Distance(m_Target.transform.position, transform.position);
            if (distance < 2.0f)
            {
                m_Agent.isStopped = true;
                BuildingInRange();
            }
        }
    }

    public virtual void GoTo(Building target)
    {
        m_Target = target;

        if (m_Target != null)
        {
            m_Agent.SetDestination(m_Target.transform.position);
            m_Agent.isStopped = false;
        }
    }

    public virtual void GoTo(Vector3 position)
    {
        //we don't have a target anymore if we order to go to a random point.
        m_Target = null;
        m_Agent.SetDestination(position);
        m_Agent.isStopped = false;
    }


    /// <summary>
    /// Override this function to implement what should happen when in range of its target.
    /// Note that this is called every frame the current target is in range, not only the first time we get in range! 
    /// </summary>
    protected abstract void BuildingInRange();//子类可以访问,其他不可

    //Implementing the IUIInfoContent interface so the UI know it should display the UI when this is clicked on.
    //Implementation of all the functions are empty as default, but they are set as virtual so subclass units can
    //override them to offer their own data to it.
    public virtual string GetName()
    {
        return "Unit";
    }

    public virtual string GetData()
    {
        return "";
    }

    public virtual void GetContent(ref List<Building.InventoryEntry> content)
    {
        
    }
}
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;

public class MainManager : MonoBehaviour
{
    //单例模式 设置为静态后整个程序Instance只有一个,实现传数据,防止从Main回到Menu的时候Menu会再加载一遍,在生成一个是不对的,因为需要来回传数据
    public static MainManager Instance { get; private set; }//静态变量名字首字母大写,属性
    public Color TeamColor;//字段
    
    private void Awake()//Awake-》Start->Update
    {
        if (Instance != null)
        {//gameObject省略了this.,this.gameObject
            Destroy(this.gameObject);//销毁从Main回到Menu后在一次加载Menu生成的MainManager游戏对象
            return;
        }
        Instance = this;//游戏启动,组件等都会加载,将当前的MainManager对象赋值给Instance
        DontDestroyOnLoad(gameObject);//this和gameObject不是一个对象,gameObject场景中MainManager游戏对象,而this是MainManager类对象
        //MainManager将被缓存不会被销毁,为了传给Main场景
        LoadColor();//不点击Load按钮无所谓,因为直接自动调用了,如果没有此句则需要运行后再点击才能取出磁盘文件的内容
    }
    //private void Start()
    //{
    //    if (MainManager.Instance != null)
    //    {
    //        SetColor(MainManager.Instance.TeamColor);
    //    }
    //}
    [System.Serializable]//SaveData可被序列化
    class SaveData//未加public默认为private
    {//如果不用这个内部类,直接在MainManager主类前面加[System.Serializable],
     //运行后也会生成savefile.json文件,但选择了颜色但文件内的颜色值全是0,未赋值存储成功
     //是因为如果是上述情况会需要新new MainManager(),和之前的MainManager(游戏运行时刚加载时编辑器帮new的)不是一个
     //如果不new MainManager(),而是string json = JsonUtility.ToJson(this);将当前的MainManager类传进去,这种方法是可以将颜色值存储的,
     //但如果MainManager中含有其他属性和对应的值也会一同存储进磁盘文件,而这些不一定是我们需要的,所以要创建内部类来实现
        public Color TeamColor;
    }

    public void SaveColor()//将数据存入磁盘文件中(序列化)
    {
        SaveData data = new SaveData();
        data.TeamColor = TeamColor;

        string json = JsonUtility.ToJson(data);//将data转换成json形式(磁盘文件 文本格式就是字符串形式)
        //File.WriteAllText(Application.persistentDataPath + "/savefile.json", json);//将文件存储到C盘某目录
        File.WriteAllText(Application.dataPath + "/savefile.json", json);//将文件存储到当前文件根目录某目录
        //存入savefile.json文件
    }

    public void LoadColor()//将磁盘文件中的数据拿出(反序列化)
    {
        //string path = Application.persistentDataPath + "/savefile.json";
        string path = Application.dataPath + "/savefile.json";

        if (File.Exists(path))//如果文件存在
        {
            string json = File.ReadAllText(path);//读出
            SaveData data = JsonUtility.FromJson<SaveData>(json);//反序列化取出数据

            TeamColor = data.TeamColor;
        }
    }
}

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEngine.SceneManagement;
#if UNITY_EDITOR
using UnityEditor;
#endif



// Sets the script to be executed later than all default scripts
// This is helpful for UI, since other things may need to be initialized before setting the UI
[DefaultExecutionOrder(1000)]//给其关联的游戏对象的脚本排序
public class MenuUIHandler : MonoBehaviour
{
    public ColorPicker ColorPicker;

    public void NewColorSelected(Color color)
    {
        // add code here to handle when a color is selected
        MainManager.Instance.TeamColor = color;
        //TeamColor不是静态变量(属性),所以不能直接用MainManager.TeamColor
    }

    private void Start()
    {
        ColorPicker.Init();
        //this will call the NewColorSelected function when the color picker have a color button clicked.
        ColorPicker.onColorChanged += NewColorSelected;//将NewColorSelected此函数行为赋值给ColorPicker.onColorChanged 
        ColorPicker.SelectColor(MainManager.Instance.TeamColor);
    }
    public void StartNew()
    {
        SceneManager.LoadScene(1);//生成设置 1 是里面的场景序号
    }
    public void Exit()
    {
        MainManager.Instance.SaveColor();

#if UNITY_EDITOR//如果是Unity编辑器
        EditorApplication.ExitPlaymode();//编辑器运行环境的终止
#else//不是Unity编辑器
        Application.Quit();//程序退出,适用于打包完后程序文件,再运行时会成功退出
#endif
    }
    
    public void SaveColorClicked()
    {
        MainManager.Instance.SaveColor();
    }

    public void LoadColorClicked()
    {
        MainManager.Instance.LoadColor();
        ColorPicker.SelectColor(MainManager.Instance.TeamColor);
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ProductivityUnit : Unit
{
    //定义m_CurrentPile为ResourcePile(物品堆)类型,本项目中一共有两种类型的物品堆,初值为null
    private ResourcePile m_CurrentPile = null;//点中哪个物品堆
    //定义资源生产速度应该提高多少
    public float ProductivityMultiplier = 2;
    protected override void BuildingInRange()//重写父类方法
    {
        //判断是否选择物品堆 防止生产速度会一直提高
        if(m_CurrentPile == null)
        {
            ResourcePile pile = m_Target as ResourcePile;//m_Target是Building类型,看你点击的是否是那两个物品堆中的某一个,并将其赋值,每点击赋值null
            if (pile != null)
            {
                m_CurrentPile = pile;
                m_CurrentPile.ProductionSpeed *= ProductivityMultiplier;
                //提高生产速度加倍
            }

        }
    }
    void ResetProductivity()//当小人离开生产速度恢复原值
    {
        if (m_CurrentPile != null)
        {
            m_CurrentPile.ProductionSpeed /= ProductivityMultiplier;
            m_CurrentPile = null;
        }
    }
    public override void GoTo(Building target)
    {
        ResetProductivity();//调用你的新方法 重置速度
        base.GoTo(target);//调用父类中的GoTo方法
    }

    public override void GoTo(Vector3 position)
    {
        ResetProductivity();
        base.GoTo(position);
    }
}
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// A subclass of Building that produce resource at a constant rate.
/// </summary>
public class ResourcePile : Building
{
    public ResourceItem Item;
    public float m_ProductionSpeed = 0.5f;
    public float ProductionSpeed//一旦被修改就会触发set里的内容,无论在内部还是在外部,这时会进入死循环
    {//此时需要再定义一个变量值m_ProductionSpeed,赋值0.5,外部获取时将m_ProductionSpeed返回,一旦内外设置ProductionSpeed变量时即触发set更改m_ProductionSpeed值
        //如果依然用ProductionSpeed进行get中的返回和set中的改值,set中的赋值操作会一直触发进入死循环
        get { return m_ProductionSpeed; }
        set {
            if (value < 0f)//value为要赋的值
            {
                Debug.Log("报错");
            }
            else
            {
                m_ProductionSpeed = value;
            }
        }
    }

    private float m_CurrentProduction = 0.0f;

    private void Update()
    {
        if (m_CurrentProduction > 1.0f)
        {
            int amountToAdd = Mathf.FloorToInt(m_CurrentProduction);
            int leftOver = AddItem(Item.Id, amountToAdd);

            m_CurrentProduction = m_CurrentProduction - amountToAdd + leftOver;
        }
        
        if (m_CurrentProduction < 1.0f)
        {
            m_CurrentProduction += m_ProductionSpeed * Time.deltaTime;
        }
    }

    public override string GetData()
    {
        return $"Producing at the speed of {m_ProductionSpeed}/s";
        
    }
    
    
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// Subclass of Unit that will transport resource from a Resource Pile back to Base.
/// </summary>
public class TransporterUnit : Unit
{
    public int MaxAmountTransported = 1;

    private Building m_CurrentTransportTarget;
    private Building.InventoryEntry m_Transporting = new Building.InventoryEntry();

    // We override the GoTo function to remove the current transport target, as any go to order will cancel the transport
    public override void GoTo(Vector3 position)
    {
        base.GoTo(position);
        m_CurrentTransportTarget = null;
    }
    
    protected override void BuildingInRange()
    {
        if (m_Target == Base.Instance)
        {
            //we arrive at the base, unload!
            if (m_Transporting.Count > 0)
                m_Target.AddItem(m_Transporting.ResourceId, m_Transporting.Count);

            //we go back to the building we came from
            GoTo(m_CurrentTransportTarget);
            m_Transporting.Count = 0;
            m_Transporting.ResourceId = "";
        }
        else
        {
            if (m_Target.Inventory.Count > 0)
            {
                m_Transporting.ResourceId = m_Target.Inventory[0].ResourceId;
                m_Transporting.Count = m_Target.GetItem(m_Transporting.ResourceId, MaxAmountTransported);
                m_CurrentTransportTarget = m_Target;
                GoTo(Base.Instance);
            }
        }
    }
    
    //Override all the UI function to give a new name and display what it is currently transporting
    public override string GetName()
    {
        return "Transporter";
    }

    public override string GetData()
    {
        return $"Can transport up to {MaxAmountTransported}";
    }

    public override void GetContent(ref List<Building.InventoryEntry> content)
    {
        if (m_Transporting.Count > 0)
            content.Add(m_Transporting);
    }
}
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// This script handle all the control code, so detecting when the users click on a unit or building and selecting those
/// If a unit is selected it will give the order to go to the clicked point or building when right clicking.
/// </summary>
public class UserControl : MonoBehaviour
{
    public Camera GameCamera;
    public float PanSpeed = 10.0f;
    public GameObject Marker;
    
    private Unit m_Selected = null;//声明的是Unit类

    private void Start()
    {
        Marker.SetActive(false);
    }

    private void Update()
    {
        Vector2 move = new Vector2(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical"));
        GameCamera.transform.position = GameCamera.transform.position + new Vector3(move.y, 0, -move.x) * PanSpeed * Time.deltaTime;

        if (Input.GetMouseButtonDown(0))
        {//GameCamera.ScreenPointToRay(Input.mousePosition)鼠标点击位置与照相机之间形成一条射线,返回Ray射线类型
            var ray = GameCamera.ScreenPointToRay(Input.mousePosition);
            RaycastHit hit;//得到射线碰上的物体
            if (Physics.Raycast(ray, out hit))// out hit,hit为引用,这里会给hit赋值,检测射线ray命中某个物体
            {
                //the collider could be children of the unit, so we make sure to check in the parent
                var unit = hit.collider.GetComponentInParent<Unit>();//利用多态,找射线命中的物体,找组件Unit,从本身开始一直往上找,自己没有Unit就继续找父亲,找离它最近的有Unit的节点
                m_Selected = unit;//如果找到的是继承Unit类的子类组件对象,则返回的是子类,多态


                //check if the hit object have a IUIInfoContent to display in the UI
                //if there is none, this will be null, so this will hid the panel if it was displayed
                var uiInfo = hit.collider.GetComponentInParent<UIMainScene.IUIInfoContent>();//命中的物体找含有此接口UIMainScene.IUIInfoContent这个组件(类)取出其中的信息,因为IUIInfoContent是UIMainScene内部接口
                UIMainScene.Instance.SetNewInfoContent(uiInfo);//把信息uiInfo传入
            }
        }
        else if (m_Selected != null && Input.GetMouseButtonDown(1))
        {//right click give order to the unit
            var ray = GameCamera.ScreenPointToRay(Input.mousePosition);
            RaycastHit hit;
            if (Physics.Raycast(ray, out hit))
            {
                var building = hit.collider.GetComponentInParent<Building>();
                
                if (building != null)
                {
                    m_Selected.GoTo(building);
                }
                else
                {
                    m_Selected.GoTo(hit.point);
                }
            }
        }

        MarkerHandling();
    }
    
    // Handle displaying the marker above the unit that is currently selected (or hiding it if no unit is selected)
    void MarkerHandling()
    {
        if (m_Selected == null && Marker.activeInHierarchy)
        {
            Marker.SetActive(false);
            Marker.transform.SetParent(null);
        }
        else if (m_Selected != null && Marker.transform.parent != m_Selected.transform)
        {
            Marker.SetActive(true);
            Marker.transform.SetParent(m_Selected.transform, false);
            Marker.transform.localPosition = Vector3.zero;
        }    
    }
}
using System;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// Base class for building on the map that hold a Resource inventory and that can be interacted with by Unit.
/// This Base class handle modifying the inventory of resources.
/// </summary>
public abstract class Building : MonoBehaviour,
    UIMainScene.IUIInfoContent
{
    //need to be serializable for the save system, so maybe added the attribute just when doing the save system
    [System.Serializable]
    public class InventoryEntry
    {
        public string ResourceId;
        public int Count;
    }

    [Tooltip("-1 is infinite")]
    public int InventorySpace = -1;
    
    protected List<InventoryEntry> m_Inventory = new List<InventoryEntry>();
    public List<InventoryEntry> Inventory => m_Inventory;

    protected int m_CurrentAmount = 0;

    //return 0 if everything fit in the inventory, otherwise return the left over amount
    public int AddItem(string resourceId, int amount)
    {
        //as we use the shortcut -1 = infinite amount, we need to actually set it to max value for computation following
        int maxInventorySpace = InventorySpace == -1 ? Int32.MaxValue : InventorySpace;
        
        if (m_CurrentAmount == maxInventorySpace)
            return amount;

        int found = m_Inventory.FindIndex(item => item.ResourceId == resourceId);
        int addedAmount = Mathf.Min(maxInventorySpace - m_CurrentAmount, amount);
        
        //couldn't find an entry for that resource id so we add a new one.
        if (found == -1)
        {
            m_Inventory.Add(new InventoryEntry()
            {
                Count = addedAmount,
                ResourceId = resourceId
            });
        }
        else
        {
            m_Inventory[found].Count += addedAmount;
        }

        m_CurrentAmount += addedAmount;
        return amount - addedAmount;
    }

    //return how much was actually removed, will be 0 if couldn't get any.
    public int GetItem(string resourceId, int requestAmount)
    {
        int found = m_Inventory.FindIndex(item => item.ResourceId == resourceId);
        
        //couldn't find an entry for that resource id so we add a new one.
        if (found != -1)
        {
            int amount = Mathf.Min(requestAmount, m_Inventory[found].Count);
            m_Inventory[found].Count -= amount;

            if (m_Inventory[found].Count == 0)
            {//no more of that resources, so we remove it
                m_Inventory.RemoveAt(found);
            }

            m_CurrentAmount -= amount;

            return amount;
        }

        return 0;
    }

    public virtual string GetName()
    {
        return gameObject.name;
    }

    public virtual string GetData()
    {
        return "";
    }

    public void GetContent(ref List<InventoryEntry> content)
    {
        content.AddRange(m_Inventory);
    }
}
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// A special building that hold a static reference so it can be found by other script easily (e.g. for Unit to go back
/// to it)
/// </summary>
public class Base : Building
{ 
    public static Base Instance { get; private set; }

    private void Awake()
    {
        Instance = this;
    }
}

 UI源码

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

public class ContentEntry : MonoBehaviour
{
    public Image Icone;
    public Text Count;
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class InfoPopup : MonoBehaviour
{
    public Text Name;
    public Text Data;
    public RectTransform ContentTransform;

    public ContentEntry EntryPrefab;

    public void ClearContent()
    {
        foreach (Transform child in ContentTransform)
        {
            Destroy(child.gameObject);
        }
    }
    
    public void AddToContent(int count, Sprite Icone)
    {
        var newEntry = Instantiate(EntryPrefab, ContentTransform);

        newEntry.Count.text = count.ToString();
        newEntry.Icone.sprite = Icone;
    }
}
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;

public class UIMainScene : MonoBehaviour
{
    public static UIMainScene Instance { get; private set; }
    
    public interface IUIInfoContent//interface接口,不能new
    {//接口是用来实现的,里面的方法都是抽象的,需要被子类重写来实现
        //接口的主要作用是用来约束行为(方法)一个需要的方法定义一个接口,需要的类就实现它,低耦合高聚合,自顶而下
        //继承属于强耦合,自底而上,很多子类有公共部分就可以抽象一个父类去继承
        /*例如 c#中一个类只能继承一个父类,单继承多实现(可实现多个接口)
        class Aa : SomeInterface,ISomeInterface{}//c#中,和继承没办法区分所以一般接口开头有I
        interface SomeInterface{void Methhod1();void Methhod1();}
        class Bb extends Cc implements SomeInterface{}//Java中
        */
        string GetName();//获取Main场景中点击物体的信息
        string GetData();
        void GetContent(ref List<Building.InventoryEntry> content);
    }
    
    public InfoPopup InfoPopup;
    public ResourceDatabase ResourceDB;

    protected IUIInfoContent m_CurrentContent;
    protected List<Building.InventoryEntry> m_ContentBuffer = new List<Building.InventoryEntry>();


    private void Awake()
    {
        Instance = this;
        InfoPopup.gameObject.SetActive(false);
        ResourceDB.Init();
    }

    private void OnDestroy()
    {
        Instance = null;
    }

    private void Update()
    {
        if (m_CurrentContent == null)
            return;
        
        //This is not the most efficient, as we reconstruct everything every time. A more efficient way would check if
        //there was some change since last time (could be made through a IsDirty function in the interface) or smarter
        //update (match an entry content ta type and just update the count) but simplicity in this tutorial we do that
        //every time, this won't be a bottleneck here. 

        InfoPopup.Data.text = m_CurrentContent.GetData();
        
        InfoPopup.ClearContent();//先将左上角信息表清空
        m_ContentBuffer.Clear();
        
        m_CurrentContent.GetContent(ref m_ContentBuffer);
        foreach (var entry in m_ContentBuffer)//取图标
        {
            Sprite icon = null;
            if (ResourceDB != null)
                icon = ResourceDB.GetItem(entry.ResourceId)?.Icone;
            
            InfoPopup.AddToContent(entry.Count, icon);
        }
    }

    public void SetNewInfoContent(IUIInfoContent content)//多态,传过来的是实现接口的类,把点击的物体显示的信息到左上角
    {
        if (content == null)//此类未实现此接口
        {
            InfoPopup.gameObject.SetActive(false);//左上角不显示信息
        }
        else
        {
            InfoPopup.gameObject.SetActive(true);
            m_CurrentContent = content;
            InfoPopup.Name.text = content.GetName();//打开的是点击物体对应组件(类)中实现接口的方法,如果没重写接口中的方法就去继承的父类(实现接口方法)实现的方法
        }
    }
    public void BackToMenuScene()
    {
        SceneManager.LoadScene(0);//0为Menu场景,回到Menu场景,将Menu场景在一次加载一遍
    }
}

Helpers文档

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

public class AnimatorHandler : MonoBehaviour
{
    private Animator m_Animator;
    private NavMeshAgent m_Agent;
    
    // Start is called before the first frame update
    void Start()
    {
        m_Agent = GetComponentInParent<NavMeshAgent>();
        m_Animator = GetComponentInChildren<Animator>();
    }

    // Update is called once per frame
    void Update()
    {
        if (m_Agent != null && m_Animator != null)
        {
            m_Animator.SetFloat("Speed", m_Agent.velocity.magnitude / m_Agent.speed);
        }
    }
}
using UnityEngine;


// Handles setting a color to a given renderer and material slot. Used to simplify coloring our Unit.
// (This can be added on the visual prefab and the Unit code can just query oif that component exists to set color)
public class ColorHandler : MonoBehaviour
{
    public Renderer TintRenderer;
    public int TintMaterialSlot;
    
    public void SetColor(Color c)
    {
        var prop = new MaterialPropertyBlock();
        prop.SetColor("_BaseColor", c);
        TintRenderer.SetPropertyBlock(prop, TintMaterialSlot);
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class ColorPicker : MonoBehaviour
{
    public Color[] AvailableColors;
    public Button ColorButtonPrefab;
    
    public Color SelectedColor { get; private set; }
    public System.Action<Color> onColorChanged;//添加某种行为,在MenuUIHandler中添加过来的行为

    List<Button> m_ColorButtons = new List<Button>();
    
    // Start is called before the first frame update
    public void Init()
    {
        foreach (var color in AvailableColors)//var不确定AvailableColors是什么类型用var,自己会推断
        {
            var newButton = Instantiate(ColorButtonPrefab, transform);//克隆出来一个新的按钮放在自己的下边
            newButton.GetComponent<Image>().color = color;//按钮赋值颜色
            
            newButton.onClick.AddListener(() =>//给按钮绑定点击事件,只有点击时才会执行里面的东西
            {
                SelectedColor = color;
                foreach (var button in m_ColorButtons)
                {
                    button.interactable = true;//按钮交互,当鼠标划到颜色按钮身上,颜色会加深
                }

                newButton.interactable = false;//点击后的按钮,关闭交互
                
                onColorChanged.Invoke(SelectedColor);//触发NewColorSelected行为,并将SelectedColor传到NewColorSelected中
                //等同于MainManager.Instance.TeamColor=SelectedColor,但上述代码是将你用的颜色给你,但具体干什么可以写在调用的函数中
            });
            //回调,整体生成按钮 绑定事件 赋值按钮 瞬间完成,只有点击时才会回到上面代码进入里面执行foreach
            m_ColorButtons.Add(newButton);//按钮扔到按钮列表中
        }
    }

    public void SelectColor(Color color)
    {
        for (int i = 0; i < AvailableColors.Length; ++i)
        {
            if (AvailableColors[i] == color)
            {
                m_ColorButtons[i].onClick.Invoke();//设置的颜色作为下一次运行时菜单默认的颜色,自动触发点击函数
            }
        }
    }
}
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[CreateAssetMenu(fileName = "ResourcesDatabase", menuName = "Tutorial/Resources Database")]
public class ResourceDatabase : ScriptableObject
{
    public List<ResourceItem> ResourceTypes = new List<ResourceItem>();

    private Dictionary<string, ResourceItem> m_Database;
    
    public void Init()
    {
        m_Database = new Dictionary<string, ResourceItem>();
        foreach (var resourceItem in ResourceTypes)
        {
            m_Database.Add(resourceItem.Id, resourceItem);
        }
    }

    public ResourceItem GetItem(string uniqueId)
    {
        m_Database.TryGetValue(uniqueId, out ResourceItem type);
        return type;
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;


[CreateAssetMenu(fileName = "ResourceItem", menuName = "Tutorial/Resource Item")]
public class ResourceItem : ScriptableObject
{
    public string Name;
    public string Id;
    public Sprite Icone;
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值