Unity—— #18 抽象类别


  在上节实现了手柄输入之后,提到过这节将会把两种输入方式的共通点抽象出来,写成一个抽象基类,而两种输入方式成为其的子类。
  首先我们可以来找找两种输入方式有什么共通点。在人物移动上,key string name两者对应的按钮不一样,肯定不用考虑。在移动信息处理上,虽然两者的处理方式不一样,但都需要变量来存储相关信息,可以把变量提取出来。这些都是两者都有的变量:

    [Header("===== Move =====")]
    private float targetUp;    //键入按钮直接转1跟0
    private float targetRight;

    private float curVelocityDup;    //平滑处理函数要用到的引用参数
    private float curVelocityDright;

    public float Dup;    //平滑处理
    public float Dright;

    public float Dmag;    //记录移动速度
    public Vector3 Dvec;  //记录移动方向

  在相机移动上,也有类似的变量是两者都有的:

    [Header("===== Camera Move =====")]
    public float CUp;  //相机移动方向
    public float CRight;

  还有3个动作的信号(跑、跳、滚)也是两者都有的变量:

    [Header("===== State =====")]
    public bool run;
    public bool jump;
    public bool attack;

  最后我们之前说过,两者都是需要椭圆映射法来解决斜向1.414的问题,所以都需要我们自己定义的SquareToCircle(Vector2 temp)函数:

    Vector2 SquareToCircle(Vector2 temp){
        Vector2 output = Vector2.zero;
        output.x = temp.x * Mathf.Sqrt (1 - (temp.y * temp.y) / 2);
        output.y = temp.y * Mathf.Sqrt (1 - (temp.x * temp.x) / 2);
        return output;
    }

  至此两者的共同点都基本找完了,其实都是两者都会用到的变量和函数。现在需要我们去新建一个抽象类,把这些通通都灌进去了。
  在这里我想先讨论一下为什么选择抽象类而不是接口。接口里面是不允许定义函数,只允许声明函数,实现部分是留给子类去解决的;而抽象类则允许定义函数在里面。因为现在这两个输入方式用到的椭圆映射法的函数是同一实现,并无区别的,所以使用抽象类更好一点。
  在project视窗,右键create→C# Script新建C#脚本文件,命名为IUserInput(前缀为I表明它是一个抽象类or接口):把刚才列出来的代码通通塞进去:

public abstract class IUserInput : MonoBehaviour {

    public bool InputEnabled=true;

    [Header("===== Move =====")]
    public float Dup;
    public float Dright;

    protected float curVelocityDup;
    protected float curVelocityDright;

    protected float targetUp;
    protected float targetRight;

    public float Dmag;
    public Vector3 Dvec;

    [Header("===== Camera Move =====")]
    public float CUp;
    public float CRight;

    [Header("===== State =====")]
    public bool run;
    public bool jump;
    public bool attack;


    protected Vector2 SquareToCircle(Vector2 temp){
        Vector2 output = Vector2.zero;
        output.x = temp.x * Mathf.Sqrt (1 - (temp.y * temp.y) / 2);
        output.y = temp.y * Mathf.Sqrt (1 - (temp.x * temp.x) / 2);
        return output;
    }   
}

  要注意的是,为了能让子类用上父类的变量和函数,要把原本修饰符是private的变量和函数改为protected,这样这些就只能子类去使用了,其他类是用不了的。基类就这样完事了,现在要考虑的就是两个子类和涉及到这两个子类的其他组件的修改。
  把PlayerInout和JoystrickInput的父类改为IUserInput,并把父类已经有的东西给删除掉。
public class JoystickInput : IUserInputpublic class PlayerInput : IUserInput。诶有人可能会问:这里继承了IUserInput,那原本它们继承的MonoBehaviour现在没得继承了,岂不是很多函数都用不了了?非也,因为它们的父类IUserInput已经继承了MonoBehaviour了,所以它们自己也会继承MonoBehaviour的。
  现在要对一些涉及了输入类型变量的组件进行修改,在这里就有两个:ActorController.cs和CameraController.cs,在没有实现手柄输入前,这两个都声明了PlayerInput类型的变量pi,用来获取输入的相关信息。现在要把它们改为IUserInput:

    public IUserInput pi;

  在获取组件方面,不能用GetComponent<>(),因为对于IUserInput,其真正实现是两个子类,如果想实现两种输入方式都检测得到的话,要用GetComponents<>(),否则Unity只会按组件顺序优先取第一个组件,无论其是否被勾上,像这样:


  如果你用的是GetComponent<>(),那么无论你PlayerInput是否勾上,它都只会获取这个组件而忽略JoystickInput。所以我们应该用GetComponents<>()获取一个组件数组,然后逐个侦测看哪个组件被勾上,就选取该组件作为输入方式。
  在ActorController.cs里,我们是使用enabled属性去获知哪个输入方式是被勾上的:

    void Awake(){
        IUserInput[] temp =  GetComponents<IUserInput>();
            foreach (var item in temp){
            if (item.enabled == true) {
                pi = item;
            }
        }
    ...
    }

  而对于CameraController.cs,之前获取PlayerInput的做法是把这个变量曝露出去,然后在外面把PlayerInput组件直接灌进来。这次我通过原本已有的PlayerHandle变量去获得IUserInput,因为在PlayerInpupt的ActorController.cs里面(如上)已经为我们选好了能用的输入方式,所以在这直接把它拿过来用就是了,没必要再来筛选一遍了。

void Awake () {
        cameraHandle = transform.parent.gameObject;     //负责垂直旋转
        playerHandle = cameraHandle.transform.parent.gameObject;        //负责水平旋转
        //pi = playerHandle.GetComponent<ActorController>().pi;
        model = playerHandle.GetComponent<ActorController>().model;     //获取模型
        camera = Camera.main.gameObject;        //获取主要摄像头(Tag为MainCamera)
        tempEuler = 20.0f;
    }

    void Start(){
        pi = playerHandle.GetComponent<ActorController> ().pi;
    }

  不过要注意的是,这里pi的初始化是不能放在Awake()阶段的,因为pi初始化所需要的playerHandle变量也是在Awake()阶段才被初始化,所以是要到它被初始化后(Awake()函数执行完毕),才能去初始化pi。因此要把它的初始化放在Start()阶段。
  至此,整个抽象类别就完成了。现在可以来看看效果:


  可以看到现在是用手柄输入的,且各项功能正常。下一节我们将开始讨论防御的实现。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343

推荐阅读更多精彩内容

  • 一、基础知识:1、JVM、JRE和JDK的区别:JVM(Java Virtual Machine):java虚拟机...
    杀小贼阅读 2,365评论 0 4
  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,085评论 1 32
  • 1.import static是Java 5增加的功能,就是将Import类中的静态方法,可以作为本类的静态方法来...
    XLsn0w阅读 1,211评论 0 2
  • 傍晚的风,有时来得有些蛮横,有时又来得有些轻狂。来的时候,直冲直撞就过来,收的时候,就突然嘎然而止,又劲力不足,也...
    七月风阅读 252评论 0 3
  • 说来正巧,码哥这两天在尝试早起跑步,虽失败N次仍不忘初心。大家都知道21习惯养成理论,于是乎,我也就上appsto...
    12345qwert阅读 687评论 1 3