C#程序员整理的Unity 3D笔记(七):接口、虚函数使用之个人见解

接口、虚函数使用之个人见解

最近在封装重构太空大战的代码,结合原来C#的知识点发现很多有意思的地方,此文主要介绍下接口和虚函数的使用,但对于接口和虚函数的区别这里不在描述(自行百度、谷歌)。

虚函数的使用:

定义一个Enemy的基类,它具有所有的敌人的共有属性及行为。而它的派生类会有较多的属性及特有/变种行。例如以下代码,Enemy具有生命、速度属性,有死亡、复活的行为,所有派生类也都具有这些属性及行为,把该类中的初始化方法,死亡、复活方法定义为虚方法,方便在派生类中有特殊逻辑可以在相应的重载函数中实现。

代码如下:

public class Enemy : MonoBehaviour {

public Transform m_transform;

///生命属性

public float m_life

{

get;

set;

}

///速度

public float m_speed

{

get;

set;

}

// Use this for initialization

void Start () {

Init();

m_transform = this.transform;

}

//初始化

protected virtual void Init()

{

m_speed = 1;

m_life = 5;

}

//移动轨迹

protected virtual void EnemyMove()

{

Move.Instance.MoveToDir(m_transform, CustomerMoveDirection.line,-m_speed);

}

//死亡

public virtual void Dead()

{

m_transform.position = Move.Instance.HidePosition;

m_transform.gameObject.SetActive(false);

}

//复活

public virtual void Revive(Vector3 position, Quaternion rotation)

{

m_transform.gameObject.SetActive(true);

m_transform.position = position;

m_transform.rotation = rotation;

}

}

派生类:

public class EnemyLevel1 : Enemy {

private float m_timer = 5f;

//生命及速度重写

protected override void Init()

{

m_life = 10;

m_speed = 0.5f;

}

//移动轨迹重写

protected override void EnemyMove()

{

#region 水平方向 z轴 1.5左右来回移动

if (m_timer > 0)

{

m_timer -= Time.deltaTime;

Move.Instance.MoveToDir(m_transform, CustomerMoveDirection.sign, m_speed);

}

else

{

Move.Instance.MoveToDir(m_transform, CustomerMoveDirection.sign,-m_speed);

if (m_transform.position.z > 4)

m_timer = 5f;

}

#endregion

}

public override void Dead()

{

//如果有特殊逻辑,可以在此处完成

base.Dead();

}

public override void Revive(Vector3 position, Quaternion rotation)

{

//如果 有特殊逻辑,可以再此处完成

base.Revive(position, rotation);

}

}

接口的使用:

定义IEnemy接口

public interface IEnemy

{

float m_life { get; set; }

float m_speed{get;set;}

void Dead();

void Revive(Vector3 position, Quaternion rotation);

}

类Enemy和EnemyLevel1 分别继承该接口(别忘了继承MonoBehaviour这个类),并在各自类中按各自的业务逻辑实现(当然公共部分可以抽出封装起来),此部分不贴代码(可以百度、谷歌 “C#接口实现”).

对比以上两种实现方式,个人感觉单就这个游戏的例子而言虚函数的使用要比接口方便,派生类中只需要在有特殊处理的方法中完善代码即可,但接口就需要在每个继承接口的类中去写实现。但如果要实现多继承的话,接口反而是最好的选择。

以上是个人在使用过程中的理解,有不对的地方欢迎大家指正、拍砖。 :)

C#程序员整理的Unity 3D笔记(二)

学习Unity快一个月了,中间磕磕碰碰遇到了不少问题,好在是有几个小伙伴一起做,有讨论、分享的机会,不至于抓耳挠腮埋头苦做,废话不说了总结下这段时间的感悟。

关注:从去年Roger给我们几个介绍unity,自己也有意关注了些微信公众号、新闻之类的,猛然觉得c#还是能做好多东西,大家也不至于纠结C#前景不好,是否需转其他语言或平台等等。

动手:今年10月份开始真正动手,百度了一个别人做移动小车的例子,然后动手敲了一遍code,然后遇见了各种头大的事,比如transform是做什么的?Input怎么获取的变量?脚本怎么运行的?菜单在哪?别人的代码提供的不完整,有不知道缺失的是什么等等一系列问题。后面虽通过百度或其他途径解决了这些问题,总的感觉是自己太急功近利,反而是在走弯路,还是回到起点从基础知识看起,稳打稳扎的来,后面按yogi分享的打砖块例子,自己比葫芦画瓢也做了一个,感觉还是挺爽。

知识点

1.Camera :场景中包含多个camera时,想在预览时优先呈现某个视角时,把该camera的depth属性值设置为较大值(大于其他camera)

2.skybox:一种是全场景应用,一种是挂在camera上,随camera而变化,类似大家在同一个地图打怪,个人可以设置自己特有的背景画面

3.系统自带方法解释

void Awake () –初始化函数,在游戏开始时系统自动调用。一般用来创建变量之类的东西。

void Start() –初始化函数,在所有Awake函数运行完之后(一般是这样,但不一定),在所有Update函数前系统自动条用。一般用来给变量赋值。

void Update() –刷新函数,在游戏的每一帧都会调用。

void FixedUpdate() –以固定的频率,系统自动调用。

void LateUpdate() –在Update函数之后调用。

4.Instantiate生成物体方法中的第一个参数(物体对象),必须要在Inspector上指定,否则报一个空对象的错误

5.上周讨论时记录的几个问题,网上查阅的结果

/// 镜头离目标的距离

/// </summary>

public float Distance = 30.0f;

/// <summary>

/// 鼠标滚轮拉近拉远速度系数

/// </summary>

public float ScrollFactor = 10.0f;

//滚轮向前:拉近距离;滚轮向后:拉远距离

var scrollAmount = Input.GetAxis(GameSetting.MouseScrollWheel);

Distance -= scrollAmount * ScrollFactor;

 

//在攻击范围内:面朝玩家

var lookRotation = Quaternion.LookRotation(mTargetTransform.position – transform.position);

transform.rotation = Quaternion.Slerp(transform.rotation, lookRotation, RotateSpeed * Time.deltaTime);

6.VS2010/12不能挂脚本调试—原因之一建立的工程中未导入VS的资源包或reference中未设置为VS为调试工具