‫好吧, 我会的
‫因此, 在本讲座中, 您将学习多播､ 委派和事件｡
‫所以让我们先来探讨一下这个问题｡
‫想象一下, 我们正在从头开始开发一款视频游戏｡
‫我们的代码是图形和音频库以及播放器逻辑的组合｡
‫所以我们开始编写代码吧｡
‫请考虑以下简单类｡
‫首先, 我们有一个渲染类, 在游戏开始时,
‫我们要启用渲染引擎并开始绘制视觉效果｡
‫它会进行渲染, 然后开始绘制视觉效果｡
‫当游戏结束时, 我们希望停止渲染引擎｡
‫所以我们有这个game over方法, 它会停止渲染引擎｡
‫所以这里我只使用控制台右行语句｡
‫这当然会是一个更复杂的代码, 然后它会做一些事情｡
‫在我们的例子中, 我们只是试图理解多播委托和事件的概念｡
‫这就是为什么我们要通过控制台上的红线语句来显示它｡
‫这就是我们的渲染类｡
‫现在, 我们来看一下音频系统类｡
‫在音频系统中, 我们还有一种飞镖游戏方法, 它只需启动音频系统并播放一些音频｡
‫然后我们有游戏结束的方法, 这将基本上停止音频系统｡
‫最后我们有一个玩家, 这个玩家有一个玩家名, 我们有一个简单的构造函数,
‫我们根据传递给创建的对象的内容来设置这个名字｡
‫这里我们也有开始博弈和结束博弈的方法.
‫这个程序将生成一个ID为的玩家, 这个程序将删除指定为玩家名的ID为的玩家.
‫这是我们的三个类, 我会尽量简单的讲.
‫所以让我们继续看主方法｡
‫在main方法中, 我们将创建这些系统的对象.
‫首先是音频系统, 然后是渲染引擎, 非常简单, 这里只是简单的对象｡
‫然后我们用ID创建两个参与者｡
‫我们有一号参与人CAO, 还有二号参与人De Silva.
‫因此, 我们需要启动渲染引擎､ 音频系统, 并通过从每个类调用start
‫game方法来生成播放器｡
‫所以我们就这么做吧｡
‫我会这样做｡
‫所以我只想说音频系统, 启动游戏渲染引擎, 而不是启动游戏玩家一和玩家开始游戏每个｡
‫然后我们说游戏正在运行, 按任意键结束游戏｡
‫所以我们现在要做的是, 一旦玩家按下按钮, 游戏就结束了.
‫所以这当然要复杂得多｡
‫假设玩家按下选项菜单中的所有for或｡
‫他关闭游戏, 然后下一个代码就会运行｡
‫因此, 下一个代码当然是调用音频系统game over方法､ 渲染引擎game over方法以及参与者1和参与者2
‫game over方法｡
‫所以我们来解决这个问题吧｡
‫让我们把它也加进去｡
‫顺便说一下, 我们需要一个read语句, 否则它会直接关闭它｡
‫所以让我在这里快速添加一个read语句, 这样我们就可以手动按下一个键, 然后关闭所有程序,
‫游戏就结束了｡
‫让我们快速运行一下看看会发生什么｡
‫我们看到音频系统启动, 音频播放, 渲染引擎启动, 我们现在看到视觉效果,
‫然后播放器出现｡
‫所以一号和二号参与人都是衍生出来的｡
‫现在游戏正在运行, 我们可以玩它｡
‫一旦我们想完成它, 我们就按下一个键｡
‫所以我要按下一个键｡
‫你可以看到渲染引擎停止了, 音频系统停止了, 我们删除了两个播放器｡
‫所以这是一个相当大的努力来设置这个｡
‫现在我想我们必须用更多的东西来做这件事, 可能会有几件事出错, 对吗？
‫假设我们添加了更多的系统, 那么这就变得更加复杂了, 所以我们很容易忘记调用start game或者game
‫over方法｡
‫或者更糟的是, 我们可能会两次调用其中一个方法, 这可能会导致各种问题,
‫并要求我们放置大量保护性代码｡
‫所以我们必须确定, 这个物体是活的吗？
‫它是否调用了这个方法, 或者它是否调用了这个方法等等, 太复杂了｡
‫而这正是多播委托派上用场的地方｡
‫多播委托是一个作为列表工作的委托, 它可以在列表中存储对多个方法的引用, 基本上就是这样｡
‫好吧, 这听起来相当复杂, 但让我们构建它, 然后它可能会更有意义｡
‫因此, 让我们创建一个名为Game Event Manager的静态类｡
‫是这样｡
‫好吧, 我会的
‫因此, 让我们继续创建一个新的｡
‫班在这里｡
‫我将把这个称为游戏事件管理器｡
‫好吧, 我会的
‫因此, 这个游戏事件管理器现在将有一个委托｡
‫因此, 我将创建一个名为Game Event的新委托｡
‫所以它不会返回任何东西, 但是它是委托类型的, 并且是公共的,
‫所以我们可以在这个类之外使用它.
‫我们已经了解了委托的一般工作方式, 现在我们将使用这个委托来允许我们向它添加多个事件｡
‫现在让我们创建两个变量, 分别叫on game start和on game end, 它们的类型是game event.
‫所以他们将我们委托的类型去掉｡
‫所以这是一个游戏事件委托, 这是一个游戏事件委托.
‫我们现在可以使用这两个委托变量｡
‫回到我们的三门课｡
‫让我们将start game和game over方法添加到on game start和on game over代理中｡
‫此外, 这些方法不需要是公共的｡
‫现在让我们转到音频系统,
‫将这两个方法设置为私有, 因为我们不需要公开它们, 因为我们将使用音频系统的构造函数来添加或订阅事件｡
‫因此, 在这里, 将我们的方法添加到游戏管理器委托的最佳位置是从构造函数本身内部｡
‫这就是我们要做的｡
‫当一个对象被创建时, 它的方法将自动被添加到委托中, 或者换句话说,
‫它们将订阅它们｡
‫现在要做的是, 我们的start game和game
‫over方法将被添加到game start委托的game事件管理器中｡
‫我们在这里使用加号等于号来表示, 好的, 我们想把这个方法添加到那个多播委托中｡
‫因此, 基本上我们订阅了它, 并等待该事件被触发, 因为一旦该事件被触发,
‫我们的方法将被调用｡
‫最酷的是我们现在可以对渲染引擎类和播放器类做同样的事情｡
‫所以这里重要的是我用的是加等号而不仅仅是等号, 所以我没有赋值｡
‫我们稍后会看到一个签名意味着什么, 它将为我们做什么｡
‫但在这里我们只是增加了另一个｡
‫方法可以说是我们的事件收集器, 或者说是我们的事件管理器｡
‫所以它收集所有应该执行的事件或方法｡
‫因此, 这是一个多播委托｡
‫现在, 让我们对渲染引擎做同样的事情｡
‫我想让你自己做｡
‫因此, 请真实的暂停视频, 并尝试分配相同的代码或构建相同的代码, 就像我们在音频系统中所做的那样｡
‫首先, 我确保我的方法是私有的因为我们不需要再公开它们了｡
‫因为这不是必须的, 所以我们不会在这个类之外调用它们｡
‫这就是为什么把它们保密总是一个很好的做法｡
‫但是我们可以调用的是构造函数, 对吧？
‫因此, 我们可以创建一个呈现引擎的对象, 因为它是公共的｡
‫所以现在我们可以继续, 并将start game方法添加到游戏事件管理器的on game start中｡
‫游戏结束也是一样｡
‫所以这里我们也用了加等于｡
‫所以我们说, 我们订阅的游戏开始和游戏结束事件｡
‫所以我们基本上是说一旦游戏开始事件将被触发｡
‫也叫我们开始游戏的方法｡
‫-我不知道
‫我们的意思是渲染引擎启动游戏的方法｡
‫所以它会接着呼叫这个方法｡
‫当然如果博弈结束了, 那么博弈结束的方法就叫做这个.
‫这就是我们如何使用这种方法｡
‫现在给你一个小小的挑战｡
‫请在播放器类中做同样的事情｡
‫好吧, 我会的
‫所以首先, 我希望你通过了｡
‫我也不会保证这两个方法是私有的因为没有人可以从外部调用start和game over方法.
‫但是我们已经有了一个构造函数, 我将使用这个构造函数, 来订阅on game start和on
‫game over方法, 给on game start事件和on game over事件.
‫所以现在在我们的游戏事件管理器中｡
‫让我们添加两个公共静态方法来触发main方法中的事件｡
‫所以我们可以在这里｡
‫调用, 基本上就是执行这个事件, 因为现在,
‫在创建了所有这些渲染引擎､ 音频系统和播放器之后, 一旦触发这个事件, 它就会执行一些操作｡
‫但我们还没有真正说如果发生这种情况会发生什么｡
‫所以如果那个事件要被触发｡
‫因此, 让我们创建一个静态方法, 在游戏开始时触发｡
‫因此, 这个方法首先会检查on game start事件是否不为空,
‫这意味着其他方法已经订阅了它, 一旦我们创建了渲染引擎, 基本上就是这种情况｡
‫例如, 如果执行了此处的代码, 或者创建了音频系统并执行了此代码,
‫或者创建了播放器并执行了此代码, 则此处的语句将为真｡
‫所以on game start event游戏事件不会为空, 也就是说不会为null｡
‫然后这里的代码将被执行｡
‫所以它现在要做的就是说游戏已经开始了然后调用on game start.
‫它将触发订阅此事件的所有方法｡
‫也就是说一旦我们在这里调用了这个方法, 那么这个博弈事件, 也就是说, 一旦我们调用了这个方法,
‫就会在这里执行.
‫这个方法会被执行, 这个方法也会被执行, 我们稍后也会看到.
‫这就是触发增益开始｡
‫这就是我们要触发它的方法｡
‫通过调用这个方法, 你会看到我们把它变成了静态的, 就像我们对游戏事件本身所做的那样,
‫因为我们不需要创建一个游戏事件管理器来调用这些方法｡
‫这就是我们想要实现的, 也是我们将其设置为静态的原因｡
‫所以你不需要为了调用这些方法而创建一个对象, 然后让我们为自己的游戏创建另一个静态方法｡
‫我建议你暂停视频, 你试着快速地建立自己｡
‫好吧, 我会的
‫所以我希望你通过了｡
‫基本上和我们之前做的是一样的, 但现在我们要做的是结束博弈.
‫所以我有一个public static void触发的game over方法, 如果on game over不为null, 就会触发这个事件｡
‫所以如果有方法订阅了这个事件, 那么它就不会是假的, 基本上是真的, 这意味着这个代码将被执行,
‫并且game
‫over将被执行, 这将调用所有的game over方法, 或者所有分配或订阅了这个game
‫over事件的方法, 这意味着这里的这个方法, 还有这个方法, 最后当然是这个方法｡
‫现在, 如果我们要创建一个新的引擎, 那么现在我们有了渲染引擎和音频引擎｡
‫假设我们创建了第三个引擎, 那么我们就不需要再手动调用这些东西了, 但是我们已经发送了它, 我们可以直接在引擎中设置它,
‫在引擎中, 我们说我们想要订阅那个事件, 一旦我们触发了那个事件,
‫方法就会自动被调用｡
‫好吧, 我会的
‫现在让我们看一下main方法中的代码, 因为这里有很多内容｡
‫所以现在你可以看到所有这些代码都不起作用了, 当然, 因为所有这些开始游戏的方法,
‫它们以前都是公共的, 但是现在它们不再是了｡
‫所以现在他们是｡
‫会的｡
‫因为是私人的所以关门了｡
‫现在让我们继续, 确保我们真的触发了这个博弈事件.
‫这里我们有一个游戏事件管理器, 我们启动了这个触发游戏, 因为这就是我们现在要做的, 对吧？
‫所以, 一旦所有的玩家和所有的系统和一切都准备好了, 我们就可以开始运行它了｡
‫现在我们可以用博弈论的方法来做同样的事情｡
‫让我们在这里触发博弈结束事件｡
‫因此, 现在将发生的是, 它将允许我们确保我们基本上有一个非常简单和干净的代码｡
‫所以它只是确保我们的代码将完美地工作｡
‫现在我们再加一个玩家｡
‫我们不需要考虑和调用所有这些方法｡
‫对, 调用start game方法, 调用game over方法等等｡
‫我们可以继续创建这个新的播放器, 它会自动调用相应的方法｡
‫所以你在这里看到的游戏已经开始音频系统, 并开始播放音频渲染,
‫引擎绘图, 视觉效果, 然后产卵的球员仍然称为切换银和龙码头.
‫现在让我们按下一个按钮｡
‫你可以看到游戏结束了｡
‫音频系统停止｡
‫渲染引擎停止, 我们删除了所有播放器｡
‫这就是多点传送委派的真正功能｡
‫超级, 超级有用, 非常强大｡
‫我们可以看到, 第三个对象参与者自动调用了start game和game over方法,
‫因为当on game start和on game over事件被触发时, 我们的对象会得到通知｡
‫现在, 使用代理时, 有些事情可能会出错｡
‫让我们先来看看一些可能需要花费数小时来修复的错误｡
‫假设我们错误地, 我们, 不使用加号, 等号, 来订阅事件的方法, 例如,
‫让我们转到播放器的类, 而不使用加号, 等号.
‫我们本来是偶然的, 只是用了等号｡
‫所以编译器不会说这是错误的, 因为这不是错误的｡
‫您也可以只使用一个方法来覆写现有的事件｡
‫所以我们在这里所做的就是说, 无论此时订阅了什么, 我们都将覆盖它.
‫这就是这里发生的事情｡
‫因此, 我们将删除在on game start和on game
‫over事件中引用的所有方法, 并将播放器设置为最后一个播放器对象, 准确地说, 该对象是作为所有这些事件的唯一订阅而创建的｡
‫此外, 由于on game start和on game over实际上是公共的, 我们可以从任何地方直接调用它们｡
‫假设我们想从这里调用game start上的game事件管理器, 那么我们也可以这样做｡
‫现在我们运行代码, 您可以看到｡
‫体育选手, ID还是叫龙银龙冬｡
‫游戏已经开始产卵发挥与龙狗和龙dong｡
‫所以, 是的, 首先是由我们的程序Kes触发的, 然后是我们的最后一个玩家, 也就是我们的龙狗,
‫它又一次被称为On Game Start｡
‫这基本上就是这里发生的事情｡
‫所以我们真的要小心了｡
‫这是一个非常难以解决的问题｡
‫所以现在我们不能将事件标记为private, 因为我们需要它们是public, 以便在类构造函数中订阅它们｡
‫所以现在我们在讨论委托时使用了事件这个名字, 因为我们的委托实际上就像事件一样｡
‫但事实上, 有一种特殊类型的委托称为事件, 它是为了防止这类错误而产生的｡
‫好吧, 我会的
‫现在有一个漂亮的关键字可以帮助我们防止这个错误,
‫那就是event关键字, 因为基本上我们在这里的游戏事件管理器中创建的这个委托, 这个公共学习游戏事件是一个事件.
‫所以我们可以在这里使用event关键字, 这样就可以避免犯这个错误,
‫因为现在你可以看到, 它对我们所做的并不满意, 所以我们可以重写一个委托｡
‫但是当涉及到事件时, 我们只能订阅它们, 而不能直接调用这个事件｡
‫它将直接从游戏事件管理器触发, 因此我们不能再直接调用事件｡
‫由于Game Start现在是一个事件, 我们只能在创建它的类中调用它｡
‫它也迫使我们把它当作一个列表｡
‫因此不允许事件位于等号的左侧｡
‫所以像这样的事情, 正如我们所看到的, 是不允许的｡
‫好吧, 我现在, 如果我们再运行一次应用程序, 你会看到它工作得完美无缺｡
‫让我运行代码｡
‫一切都很顺利｡
‫这是一个非常简洁的示例, 因为我们在一个视频中研究了委托､ 多播委托和事件｡
‫但我希望这段视频清楚地说明了在与代表和活动合作时, 你有什么优势｡
‫最酷的是,
‫您现在已经了解了如何创建自己的委托和事件, 因为稍后在使用UI时, 我们将看到更多的事件｡
‫例如, 当你点击某个东西时, 就会触发一个事件, 多个东西都可以订阅｡
‫多个方法可以订阅触发的事件, 然后执行一次, 例如,
‫单击按钮或单击键盘上的任意键｡
‫好了, 现在让我们快速总结一下｡
‫事件是一种受限制的委托形式,
‫它的行为被强制为类似于一个列表, 因此我们只能在其中添加或删除方法, 这样我们就可以使用加号等号或减号等号（而不是等号）来订阅或取消订阅｡
‫委托允许通过我的委托等于我的方法直接赋值｡
‫这样做将替换以前添加到它的任何其他方法｡
‫所以在这里要小心｡
‫此外, 事件只能由从其类别外部定义它们的类别叫用｡
‫您只能向它们注册和取消注册方法｡
‫好的, 我希望大家喜欢这段视频, 这段视频让大家对活动和代表有了一个很好的了解, 我希望在下一段视频中能看到你们｡