[U3D Learning Note] Unity C# Survival Guide (9) -- Classes

Classes for Behaviours

  • MonoBehaviours: allow us the ability to attach the scripts to the GameObjects.

Custom Classes

KEY:

  • Declare a class and create a obj
  • Use Constructor(the name same as the class name)
public class WeaponStat{
	public string name;
	public float fireRate;
	public int ammoCount;

	// Constructor
    public WeaponStat(){}
    public WeaponStat(string name, float fireRate, int ammoCount){
        // initialize things here
        this.name = name;
        this.fireRate = fireRate;
        this.ammoCount = ammoCount;
    }
}

public class Weapon : MonoBehaviour
{
    
    public WeaponStat blasters;
    public WeaponStat rocket;
    // Start is called before the first frame update
    void Start()
    {
        blasters = new WeaponStat();
		blasters.name = "Blasters";
        blasters.fireRate = 0.5f;
        blasters.ammoCount = 50;

        rocket = new WeaponStat("Rocket", 50f, 5);
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

注意一下构造函数那边名字对应的参数 this指向该类的
在这里插入图片描述

  • 重载(overload):可以注意到我们写了两种构造函数,一种有输入参数一种没有。**对于同一函数有不同输入参数的情况我们叫它重载。**当我们在调用函数时,会自动选择匹配的那一种进行操作。
  • [System.Serializable]: serialize data allow unity to read it through the Inspector. We can use it to serialize a custom class. custom class无法出现在Inspector面板上是因为它不是继承MonoBehavior的类 所以要通过序列化让它出现
  • 然后要说的一个是 RPG中会有很多角色道具 但我们不能声明啊什么的全部堆在一个cs文件中 一是容易混乱 另一个是不容易找bug 我们可以一个有一个专门创建类的文件 和一个创建角色道具和管理的文件(database) 像下面这样
/* RPGItem.cs*/
[System.Serializable]
public class RPGItem
{
    public string name;
    public int id;
    public string desctiption;

    public RPGItem(){}
    public RPGItem(string name, int id, string description){
        this.name = name;
        this.id = id;
        this.desctiption = description;
    }
}

/* ItemDatabase.cs */
public class ItemDatabase : MonoBehaviour
{
    [SerializeField]
    RPGItem sword; 
    RPGItem[] items = new RPGItem[3]; 
    // Start is called before the first frame update
    void Start()
    {
        sword  = new RPGItem("sword", 1122, "this is sword");
        items[0] = new RPGItem("bread", 1032, "this is bread");
    }
    // Update is called once per frame
    void Update()
    {   
    }
}

Challenge: Customer Database

PROBLEM:
在这里插入图片描述
(代码不扔了 和上一节无差

Custom Class - RPG Spell System Presentation

这一节是一个小小的案例(顺便学点英语 啊我感觉我英语能力直线下降
假设我们一个RPG游戏 我们的角色是巫师(Wizard) 我们的技能就是魔法攻击 咒术(Spell) 那么咒术我们肯定有好多种啊 什么火球术啊水球术啊甚至光之魔法啊(你在胡言乱语啥 那我们就需要建立一个类来记录这些咒语 就像魔法书一样我们要有内容(x 一个咒术我们要有名字 要有等级需求(不然lv1的废柴能发动击败终极boss的咒术就奇怪了 或许还有道具需求比如某些属性的符啊晶核啊 以及我们发动后增长的经验值(有了经验值我们才能不断升级 或许还有攻击力啊什么的就先不写了 对于所有咒术他们发动后(Casting the spell)都会有一个同一逻辑的效果 比如会有一些很酷炫的动效 那我们就再给这个类一个统一的函数Cast() 来表示 整个魔法书框架的代码如下

[System.Serializable]
public class Spell
{
    public string name;
    public int levelRequired;
    public int itemIdRequired;
    public int expGained;

    public Spell(){}
    
    public Spell(string name, int levelRequired, int itemIdRequired, int exp){
        this.name = name;
        this.levelRequired = levelRequired;
        this.itemIdRequired = itemIdRequired;
        this.expGained = exp;
    }

    public void Cast(){
        Debug.Log("Casting: " + this.name);
        // maybe have some effect show up, damage dealt
    }
}

有了魔法书 我们肯定就要有使用它的人啦 巫师就该登场了 我们先不管巫师的生命值等其他属性 先想想和咒术最最关联的属性有什么 比如巫师的等级 经验值 以及他拥有的咒术 我们还希望在游戏过程中按下空格键他就可以施法 lv1时可以施法火球术 lv2就是冰属性攻击 施法后经验值会增加 这边按照教程方式用数组作为魔法书的容器 但我感觉用hash表可能查找速度更快 因为有可能我们的巫师除了基础的咒术能力还会有一些通过机遇得到的咒术 这些咒术可能有相同的需求等级 这样的话数组可能不是一个很好的存储方式(这个有待验证

public class Wizard : MonoBehaviour
{
    public Spell[] spells = new Spell[5]; 
    //public Spell fireBlast;
    public int level = 1;
    public int exp;
    // Start is called before the first frame update
    void Start()
    {
        spells[0] = new Spell("Fire Blast", 1, 27, 35);
        spells[1] = new Spell("Ice Blast", 2, 28, 45);
    }

    // Update is called once per frame
    void Update()
    {
        if(Input.GetKeyDown(KeyCode.Space)){
            //fireBlast.Cast();
            //exp += fireBlast.expGained;

            // iterate through the spell list and compare to my current level
            // once find that cast spell
            foreach (var spell in spells){
                if(spell.levelRequired == level){
                    spell.Cast();
                    exp += spell.expGained;
                }
            }
        }  
    }
}

Class Inheritence

KEY:

  • Inheritance(继承): in OOP, inheritance enables new objects to take on the properties of existing objects. 在RPG中我们有很多道具嘛 比如有些是消耗性的 像回复药水啊什么的 有些道具是带有攻击性的比如武器 它们的共同特点都是有名字啊id什么的 但是会有微小差别 回复药水是对自身的生命值进行回复 那它就会有个专属函数来做这件事 武器是进行攻击的 那它也会有个专属函数来做攻击这件事情 他们都属于物品的一个子类 Item这个类存储的是它们的共同属性 那这些子类就会继承父类的属性 我们不用在子类再单独声明这些属性
public class Item
{
	public string name;
	public int itemID;
	public Sprite icon;
}
public class Consumable : Item
{
	public int addedHealth;
	public bool poison;
}
public class Weapon : Item
{
	public int attackBonus;
	public int prayerBonus;
	public int strengthBonus;
	public int mageBonus;
}

(这节有个Bank System的例子 建议直接看视频(反反复复看了两遍(x

Prodected Data Members

KEY:
先复习一下public和private
public: 任何类都可以获取并改变它
private: 任何类都不能获取它
protected: only inherited members can access the upper management or base class info(只有继承它的类才能获取
在这里插入图片描述

Virtual Methods and Overriding(虚拟函数和重写)

假设我们现在有两个类 父类Pet和子类Duck 我们想要再子类中对父类的一个函数进行重写 但是会出现以下情况 因为这个函数已经出现在父类里了
在这里插入图片描述
如果我们想要重写这个函数 我们就要用到虚拟函数 在父类中 把这个函数设置为

//Pet.cs
public class Pet : MonoBehaviour{
	protected virtual void Speak(){}
	private void Start(){
		Speak()
	}
}

这个操作允许它的子类对该函数进行一个重写

public class Duck : Pet
{
    protected override void Speak()
    {}
}

我们在Pet这个类里面游戏开始时调用Speak()这一函数, 因为这个是虚拟的, 所以他会检查所有子类是否有进行重写, 如果有的话就会调用重写的函数 比如附着了Duck这个类的脚本就会输出重写的函数而不是Pet里的同名函数
(虚拟函数就是虚函数吧???之前面试时被问虚函数有没有了解时我一脸懵

Q&A on Using MonoBehaviour Custom Classes

Q: When and why do I not use a MonoBehaviour Class if I can still use Class Inheritance
A: It make sense to use MonoBehaviour when you’re creating game logic feature and behaviours.以enemy为例,我们会有很多不同怪的类型,这些就要继承MonoBehaviour,因为他们是物理意义上的GameObject,就是会在游戏中有主动行为的。但他们手上拿着的武器就不是要继承MonoBehaviour的。Custom Class通常是作为蓝图,或者说是框架出现在游戏设计中。

Structs, Memory Management, and Value vs. Reference Types

KEY:

  • Structs: often referred to as performance enhancement and replacements to classes. 使用场景: fewer than 4 fields.
    cf. classes & structs

    • Classes可以继承, Structs不可以, Structs是不可变对象(Immutable)
    • Class is reference type, while struct is value type(这个就是和Memory Management相关了 我们要知道两个问题 How this data is stored and How this data is passed around
  • cf.Value types & reference type

    • How it is stored: Value types are stored in stack(栈), while reference types are stored in heap(堆). A data type is value type if it holds a data value within its own memory space, which means variables of these data types directly contain their values. Unlike Value type store the variables directly, Reference type store the address where the value being stored. In other words of reference type contains a pointer to another memory location that holds that data.

      int age = 25; // value type
      // bool, bytes, char, doubles, float, int, long, structs are value types
      
      string myName = "Mizuki"; //reference type
      // strings, all arrays, class and delegates are reference types
      
    • How it is passed around: If we pass a value type to a function, it will clone this value but could not change the original value (也就是值传递). If we pass a referece type, we maintain a reference to that object and we can modify it (引用传递). (还记得前面有一章提到了数组作为参数传递这件事 就直接用这个解释

(啊这几天因为要回大陆忙各种手续就没怎么读 但至少每天会读一两节 呜呜呜呜呜等隔离了我就可以勤快学习了(刚刚抢到了核酸就很快乐

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值