译林军 宿学龙|2014-04-10 08:56|9007次浏览|Unity(377)0

枚举和标志

今天的主题是枚举,它是C#语言中的一个很有帮助的工具,可以增强代码的清晰度以及准确性。

枚举一系列值

C#中最经常使用枚举的地方就是用来定义一系列可能值的时候。例如在制作一个角色类游戏中,角色有多个不同的状态效果。可以用一些基本的方式来定义玩家可能的状态效果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
using UnityEngine;
  
public class Player : MonoBehaviour
{
    public string status;
  
    void Update()
    {
        if (status == "Poison")
        {
            //Apply poison effect
        }
        else if (status == "Slow")
        {
            //Apply slow effect
        }
        else if (status == "Mute")
        {
            //Apply mute effect
        }
    }
}

此处我们用一个简单的if-else检测来查看应用的是哪个状态效果,哪个运行良好。但是如果你想应用一个状态效果,但是突然写成这样:

1
2
//Oops, I spelled "Poison" wrong!
status = "Pioson";

突然,就不会有什么状态效果了。我们会利用if-else栈检测来查看我们的变量是否被设置成一个非法值,但是如果使用枚举,则是一种更好的方式:

定义一个枚举

这次我们使用一个枚举来编写我们的状态效果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
using UnityEngine;
  
public class Player : MonoBehaviour
{
    //This is the "set" of all possible status effects
    public enum StatusEffect
    {
        None,
        Poison,
        Slow,
        Mute
    }
  
    //Now we can make a variable using that set as its type!
    public StatusEffect status;
  
    void Update()
    {
        if (status == StatusEffect.Poison)
        {
            //Apply poison effect
        }
        else if (status == StatusEffect.Slow)
        {
            //Apply slow effect
        }
        else if (status == StatusEffect.Mute)
        {
            //Apply mute effect
        }
    }
}

这里我们定义了一个叫StatusEffect的枚举,通过给状态赋值,我们强制编译器只等于StatusEffect中的一个值,如果还像之前赋值:

1
2
//This type doesn't even exist, ERROR TIME!
status = StatusEffect.Pioson;

游戏就不可能运行,编辑器会抛出一个错误,告诉你正在使用一个非法的枚举值,并指出你需要修复的确切的代码行。

在上述代码中,我没有制定状态的默认值,通常来说,一个枚举都是指定集合中的第一个值作为默认值的,因此在此例中,我已经说过,StatusEffect变量的任意默认值都是StatusEffect.None。

如果你发现Unity中有专门为UI自定义的枚举,那就更好了,当我打开Player组件的查看器时,看看发生什么了。

一个干净整洁的下拉菜单用来选择定义的类型!

枚举位标志

StatusEffect枚举,如下:

1
2
3
4
5
6
7
8
[System.Flags]
public enum StatusEffect
{
    None    = 1,
    Poison    = 2,
    Slow    = 4,
    Mute    = 8
}

通过如此,我们告知编译器将此枚举看做是位标记,表示每个不同的枚举值代表一个不同的位。这意味着我们必须通过给它们用2的幂来赋值,以此告知每个枚举值。另一种就是通过获取两个值的幂,然后通过移位来实现:

1
2
3
4
5
6
7
8
[System.Flags]
public enum StatusEffect
{
    None   = 1 << 0, // 1
    Poison = 1 << 1, // 2
    Slow   = 1 << 2, // 4
    Mute   = 1 << 3  // 8
}

现在可以通过平常的位操作来控制这些枚举域了。如果你对位操作不熟悉,我会简单讲解下如何使用。

枚举标志和位操作符

现在我们的枚举值是通过System.Flags标记的,我们可以像之前一样,如下来做:

1
2
//Character is poisoned!
status = StatusEffect.Poison;

但如果玩家中毒或者行动缓慢怎么办?我们可以使用或|操作符来将多个状态值合并一起:

1
2
3
4
5
6
7
8
9
//Now we are poisoned *and* slowed!
status = StatusEffect.Poison | StatusEffect.Slow;
  
//We could also do this:
//First we are poisoned, like so
status = StatusEffect.Poison;
  
//Then we become *also* slowed later
status |= StatusEffect.Slow;

如果我们想移除一个状态效果,我们可以使用&操作符和取反~。

1
2
3
4
5
//First, we are poisoned and muted
status = StatusEffect.Poison | StatusEffect.Mute;
  
//But now we want to remove just the poison, and leave him mute!
status &= ~StatusEffect.Poison;

最后如果我们检测发现如果一个玩家在if语句中,我们可以使用&操作符来查看一个特定的位值:

1
2
3
4
5
//Let's check if we are poisoned:
if ((status & StatusEffect.Poison) == StatusEffect.Poison)
{
    //Yep, definitely poisoned!
}

扩展阅读

我不想此文全讲解位标志和位操作,因此我只是简要解释了下。但是如果你不了解位操作,我强烈建议你弄懂它们并制定如何使用。

我个人喜欢维基百科的这个网页:

http://en.wikipedia.org/wiki/Bitwise_operation

同时,System.Flags标记的枚举不会直接在Unity的查看其中正确显示,它们不会让你选择设置某个标记的,之后以非标记的枚举类型显示。但庆幸的是,你可以自己写一个自定义的属性着色器来解决,之后我会在此文追加的!

https://docs.unity3d.com/Documentation/ScriptReference/PropertyDrawer.html

快乐编码!

原文链接:Enums and Flags

Unity中的枚举和标志的更多相关文章

  1. 【《Effective C#》提炼总结】提高Unity中C#代码质量的21条准则

    作者:Williammao, 腾讯移动客户端开发工程师 商业转载请联系腾讯WeTest获得授权,非商业转载请注明出处. 原文链接:http://wetest.qq.com/lab/view/290.h ...

  2. 【《Effective C#》提炼总结】提高Unity中C#代码质量的22条准则

    引言 原则1尽可能地使用属性而不是可直接访问的数据成员 原则2偏向于使用运行时常量而不是编译时常量 原则3 推荐使用is 或as操作符而不是强制类型转换 原则4 推荐使用条件属性而不是if条件编译 原 ...

  3. 【转】Effective C#观后感之提高Unity中C#代码质量的21条准则

    转自:http://blog.csdn.net/swj524152416/article/details/75418162 我们知道,在C++领域,作为进阶阅读材料,必看的书是<Effectiv ...

  4. NGUI研究院之在Unity中使用贝塞尔曲线(六)[转]

    鼎鼎大名的贝塞尔曲线相信大家都耳熟能详.这两天因为工作的原因需要将贝塞尔曲线加在工程中,那么MOMO迅速的研究了一下成果就分享给大家了哦.贝塞尔曲线的原理是由两个点构成的任意角度的曲线,这两个点一个是 ...

  5. .NET中的枚举(Enum)

    摘要:.NET中的枚举分为简单枚举和标志枚举,这次主要总结一下标志枚举适用条件,以及它的使用方法,并在文章的最后列举枚举使用的一些规范. 在刚接触.NET的枚举时,只用简单的枚举,对于标记枚举,只知道 ...

  6. Unity中的协程(一)

    这篇文章很不错的问题,推荐阅读英文原版: Introduction to Coroutines Scripting with Coroutines   这篇文章转自:http://blog.csdn. ...

  7. 在Unity中使用贝塞尔曲线(转)

    鼎鼎大名的贝塞尔曲线相信大家都耳熟能详.这两天因为工作的原因需要将贝塞尔曲线加在工程中,那么MOMO迅速的研究了一下成果就分享给大家了哦.贝塞尔曲线的原理是由两个点构成的任意角度的曲线,这两个点一个是 ...

  8. Unity中2D和UGUI图集的理解与使用

    图集 什么是图集? 在使用3D技术开发2D游戏或制作UI时(即使用GPU绘制),都会使用到图集,而使用CPU渲染的2D游戏和UI则不存在图集这个概念(比如Flash的原生显示列表),那么什么是图集呢? ...

  9. c#中[Flags] 枚举类型定义问题_百度知道

    [Flags]的微软解释是“指示可以将枚举作为位域(即一组标志)处理.”其实就是在编写枚举类型时,上面附上Flags特性后,用该枚举变量是既可以象整数一样进行按位的“|”或者按位的“&”操作了 ...

随机推荐

  1. day11.函数的全局变量和局部变量

    一.定义 """ 局部变量 : 在函数内部定义的变量(局部命名空间) 全局变量 : 在函数外部定义的或者使用global在函数内部定义(全局命名空间) 作用域: 作用的范 ...

  2. 深入学习JDK源码系列之、ArrayList

    前言 JDK源码解析系列文章,都是基于JDK8分析的,虽然JDK15马上要出来了,但是JDK8我还不会,我... 类图 实现了RandomAccess接口,可以随机访问 实现了Cloneable接口, ...

  3. Centos7下安装一个或多个tomcat7完整

    Tomcat是Apache 软件基金会(Apache Software Foundation)的Jakarta 项目中的一个核心项目,在运用中也占有大部分的市场. 根据系统下载对应的版,在线的下载地址 ...

  4. Android html5和Android之间的交互

    今天补充了会昨天的问题,然后搞半天又出现莫名其妙的问题. 今天讲的是交互,先说html5在Android的调用. 上面的hello world上面的部分都是安卓里的布局 然后按这些布局自动生成代码. ...

  5. Android ViewPager进行碎片(Fragment)的分页操作

    今天讲的是ViewPager 这个东西就是 假设你写了Fragment和Fragment1两个界面,用这个控件就可以实现两个界面之间的滑动,而不用Intent去跳转: 注意: 在布局中定义控件的时候, ...

  6. Python爬虫开发:反爬虫措施以及爬虫编写注意事项

  7. 【工具】之002-Mac下常用工具

    写在前面 我很懒,,,不想敲一个命令一个命令敲... "偷懒是有前提的,不是之前,就是之后." 常用命令 测试端口是否畅通 nc -z 10.254.3.86 30003 查看端口 ...

  8. VMware Workstation pro无法在Windows上运行,检查可在Windows上运行的此应用的更新版本

    我的Windows版本是win10-1903,VMware版本比较老旧是VMware-10:国庆节后微软推送了一个新的更新补丁,更新之后发现VMware无法打开(未更新前正常). 更新补丁详情如下: ...

  9. Vue Vuex 严格模式+实例解析+dispatch/commit + state/getter

    1.严格模式 import getters from './getters' import mutations from './mutations' import actions from './ac ...

  10. Promise.then返回的是什么?

    console.log((function cook(){ console.log('开始做饭.'); var p = new Promise(function(resolve, reject){ / ...