Unity编程-中级篇

一.创建属性

创建一个属性,在属性后的括号内创建访问器

using UnityEngine;
using System.Collections;

public class Player
{
    //成员变量可以称为
    //字段。
    private int experience;

    //Experience 是一个基本属性
    public int Experience
    {
        //访问属性的值
        get
        {
            //其他一些代码
            return experience;
        }
        //设置属性的值
        set
        {
            //其他一些代码
            experience = value;
        }
    }

    //Level 是一个将经验值自动转换为
    //玩家等级的属性
    public int Level
    {
        get
        {
            return experience / 1000;
        }
        set
        {
            experience = value * 1000;
        }
    }

    //这是一个自动实现的属性的
    //示例
    public int Health{ get; set;}
}

在另一个文件中创建Game类:

Player中的属性,在Game中可以当成变量使用

using UnityEngine;
using System.Collections;

public class Game : MonoBehaviour 
{
    void Start () 
    {
        Player myPlayer = new Player();

        //属性可以像变量一样使用
        myPlayer.Experience = 5;
        int x = myPlayer.Experience;
    }
}

为什么在有public和private的情况下,仍然建议使用属性呢?

因为使用属性可以使类内部封装的数据得以安全的被访问和修改。比如我们不希望类内部数据受到类外部的随意修改,使用了private,但是有时外部的代码又需要用到类内部的数据,这时通过设置属性,就可以为外部代码提供一个安全,合理的访问途径。

通俗点说就是,A可以让B进自己家里,但是B必须遵循A的命令,拿什么,怎么拿,都得听A的,而不是放B进来随意胡闹,也不是完全禁止B进来。

二.静态(static)

1.静态变量

一般来说,一个类的各个对象拥有相同变量,但是每个变量有自己的值。对于静态变量,类中的每个对象拥有相同的变量和相同的值。

比如想知道此类创建了多少个对象:

using UnityEngine;
using System.Collections;

public class Enemy
{
    //静态变量是在类的所有实例之间
    //共享的变量。
    public static int enemyCount = 0;

    public Enemy()
    {
        //通过递增静态变量了解
        //已创建此类的多少个对象。
        enemyCount++;
    }
}

2.静态类

在静态类中编写的方法,可以在另一个类中通过静态类的类名和点运算符来调用

静态类:

using UnityEngine;
using System.Collections;

public static class Utilities 
{
    //可以在没有类对象的情况下调用
    //静态方法。请注意,静态方法无法访问
    //非静态成员变量。
    public static int Add(int num1, int num2)
    {
        return num1 + num2;
    }
}

在非静态类中调用静态类中的方法:

using UnityEngine;
using System.Collections;

public class UtilitiesExample : MonoBehaviour 
{
    void Start()
    {
        //可以使用类名和点运算符
        //来访问静态方法。
        int x = Utilities.Add (5, 6);
    }
}

三.覆盖

若子类存在与父类同名方法,则调用此方法时,将调用父类的版本。因为是父类的声明,子类隐式向外转换为父类。

爷类

using UnityEngine;
using System.Collections;

public class Humanoid
{
    //Yell 方法的基版本
    public void Yell()
    {
        Debug.Log ("Humanoid version of the Yell() method");
    }
}

父类

using UnityEngine;
using System.Collections;

public class Enemy : Humanoid
{
    //这会隐藏 Humanoid 版本。
    new public void Yell()
    {
        Debug.Log ("Enemy version of the Yell() method");
    }
}

子类

using UnityEngine;
using System.Collections;

public class Orc : Enemy
{
    //这会隐藏 Enemy 版本。
    new public void Yell()
    {
        Debug.Log ("Orc version of the Yell() method");
    }
}

以父类声明的形式实例化,并调用这些方法:

using UnityEngine;
using System.Collections;

public class WarBand : MonoBehaviour 
{
    void Start () 
    {
        Humanoid human = new Humanoid();
        Humanoid enemy = new Enemy();
        Humanoid orc = new Orc();

        //注意每个 Humanoid 变量如何包含
        //对继承层级视图中
        //不同类的引用,但每个变量都
        //调用 Humanoid Yell() 方法。
        human.Yell();
        enemy.Yell();
        orc.Yell();
    }
}

四.接口

一个类只能继承一个父类,但是可以实现多个接口。接口可以跨多个互不相关的类来定义通用功能。

实现接口:

using UnityEngine;
using System.Collections;

//这是只有一个必需方法的基本接口
public interface IKillable
{
    void Kill();
}

//这是一个通用接口,其中 T 是将由实现类提供的数据类型的占位符。
public interface IDamageable<T>
{
    void Damage(T damageTaken);
}

实现接口中的方法:

using UnityEngine;
using System.Collections;

//这是只有一个必需方法的基本接口
public interface IKillable
{
    void Kill();
}

//这是一个通用接口,其中 T 是将由实现类提供的数据类型的占位符。
public interface IDamageable<T>
{
    void Damage(T damageTaken);
}

五.扩展方法

假如我们希望通过一个函数就可以重置Transform中的各个参数,这个函数最理想的位置就是在Transform类中,但是由于我们无法访问Unity内置的Transform的源代码,所以我们可以为其创建扩展。

注意,扩展方法必须放在非泛型,静态类中,扩展方法本身也声明为静态方法。一般会专门创建一个类来包含它们。

using UnityEngine;
using System.Collections;

//创建一个包含所有扩展方法的类是很常见的做法
//此类必须是静态类
public static class ExtensionMethods
{
    //扩展方法即使像普通方法一样使用,也必须声明为静态
    //注意,第一个参数具有“this”关键字,后跟一个 Transform变量
    //此变量表示扩展方法会成为哪个类的一部分
    public static void ResetTransformation(this Transform trans)
    {
        //编写重置Transform的代码
        trans.position = Vector3.zero;
        trans.localRotation = Quaternion.identity;
        trans.localScale = new Vector3(1, 1, 1);
    }
}

需要注意的是,尽管扩展方法声明具有参数,但是调用这个函数时不会传递任何参数。调用此方法的Transform对象会自动作为第一个参数传入。

using UnityEngine;
using System.Collections;

public class SomeClass : MonoBehaviour 
{
    void Start () {
        //请注意,即使方法声明中
        //有一个参数,也不会将任何参数传递给
        //此扩展方法。调用此方法的
        //Transform 对象会自动作为
        //第一个参数传入。
        transform.ResetTransformation();
    }
}

五.协程

协程函数可以看成,按时间间隔执行的函数。协程函数通常与yield语句搭配使用。协程函数每次执行都会从上一次停止的地方开始。使用协程可以不用像Update那样每帧都执行一次,提高了效率。

yield语句:

yield return null;

在下一帧执行后续代码

yield break;

结束协程

yield return new WaitForSeconds(0.5f);

等待固定时间后执行后续代码

using UnityEngine;
using System.Collections;

public class CoroutinesExample : MonoBehaviour
{
    public float smoothing = 1f;
    public Transform target;


    void Start ()
    {
    	//开启协程
        StartCoroutine(MyCoroutine(target));
    }

	//返回类型为IEnumerator
	//表示函数可以返回实现IEnumerator接口的任意内容
    IEnumerator MyCoroutine (Transform target)
    {
        while(Vector3.Distance(transform.position, target.position) > 0.05f)
        {
            transform.position = Vector3.Lerp(transform.position, target.position, smoothing * Time.deltaTime);

            yield return null;
        }

        print("Reached the target.");

        yield return new WaitForSeconds(3f);

        print("MyCoroutine is now finished.");
    }
}

猜你喜欢

转载自blog.csdn.net/m0_63673681/article/details/128702721