00:00
好,那么蛇这个类我们也已经给它处理完,就是初步处理完了,那么往下再做的话,其实你会发现我们写了这么多类,写了三个类啊,一个是food,还有我们这个score panel,还有我们这个snake,写了这么三个类,三个类都写完了,但是其实你也能发现,这三个类实际上他们都是去互相的去独立的啊,当然我还要落下一件事,我还得把这蛇是不是作为模块给它暴露出去啊,Export default,我们直接来一个snake啊,给他暴露出去,那现在的话,我们这三个类他们都是相互的去独立的,那我们最终的话,其实这些类我们需要一个总的类,要把这三个类给它整合起来,然后我们的游戏才真的能实现这个效果,所以这里边的话,我们在这个ma,哎,Modus下边,我们创建一个新的class,这个新的类啊,新的TS文件,我们叫做什么呢?叫做一个game game叫做一个C。哎,Contoll game control这个类的话,这个是我们的一个核心的一个类,是我们这个什么呢?哎,是用来控制我们这个整个这个游戏里边的所有的东西的啊这个什么呢?诶,这个是我们的游戏的一个这个控制器啊,它控制什么呢?诶控制我们这个其他的所有类。
01:18
控制我们其他的这个所有类,也就是我所有的类啊,你调用方法也好,创建对象也好,都是在我们这个game controlr里边去完成的,包括这个snake,包括food,包括scoreel,都是它里边的类,我要在里边去用这些东西,所以那既然要在它这里边用,我们先要引入什么呢?诶引入我们这个其他的这个类,先要引入他们,我们直接iport iport谁呢?一个个来吧,Iport来一个snake,诶诶你看很聪明是吧,自动给我补上了,再来一个iport的,我们来一个这个叫做一个这个,诶负的负的,诶再来一个iport的,我们叫做一个score个panel,这个是我们分牌,把这三个类都引入进来以后,在这我们是不是就可以用了,然后最后的话,我也把它暴露出去,Ex的一个defult,我们叫一个control啊,把game control这个类也向外去暴露,剩下的工作我们就要去写这个control这个类了,Game control的话,我们要写的话,那我们首先说了。
02:19
啊,我们game CR是我们游戏的控制器,它是整个控制我们游戏的所有核心的逻辑的,那这里边它肯定需要,是不是先要需要这三个呀,诶需要把这哥仨先给它去整出来,所以呢,在这里我先定义三个属性来,先定义什么呢?诶定义我们这个三个属性,哪三个属性,第一个是我们的蛇,蛇的话我们就叫snake s snake snake,它的类型呢,也是一个snake,然后呢,第二一个,第二一个是我们的这个food,啊food类型呢,就是这个food,第三一个是我们这个score sc score,一个panel。类型呢,也是叫做一个score的一个panel,然后在这里面我们在构造函数里做一件事儿,来创建他们三个的实例,z.snake等于一个new,一个snake,再点一个food,诶等于一个new,一个food,然后呢再点一个scorell panel等于一个new,一个一个panel,我们就把这三个类就都定义完了,然后剩下的事儿在我们的这个控制器里面,我们就可以对这个三个类进行各种各样的一个操作。
03:29
好,那这个一个基本结构我们就整完了啊,Cos这这这多了一个L啊,各种这种基本的配置我们就给它整完了,然后下边我们就要考虑我们这个game control里边我们需要去整什么这个方法,当然这个东西啊,我们说了,现在这东西压根就没用,这个东西压根就不会执行,为什么不会执行呢?因为我们这个核心的文件,我们的入口文件是不是叫index.ts呀,而在index.ts里,他压根是不是就不知道我这个gamer这个类啊,哎,所以呢,在index ts当中,我把这些没用的啊,我先都给它注掉,我在这指干嘛呢?只来iport谁呢?Iport我们叫做一个game control,把这个类引入进来,然后的话,我要想让它生效,我直接在这调一个new,一个game ctrl,我直接1NEW,那就表示我的游戏开始了,游戏开始我这里边是不是就可以去运行了,哎,运行了,当然现在还不行,现在。
04:29
你这写完了以后,它实际上在这儿是没有任何变化的,因为我们这个game ctrl里边现在是不是还没有去写这些,还没有去写这些方法呀,啊好,那现在我们就想一下,我们需要在这个game control这个类当中去给它添加一些这个方法,那我们就想啊,我们现在需要什么方法。需要什么方法诶,也就是说我我的这个游戏啊,我把把这注数写上,这是我们这个实物实物啊,这个呢,Score panel是我们这个记分牌。
05:01
积分盘,那现在的话,我们需要做的一件事就是我需要让我的游戏可以开始,也就是对我们的游戏进行初始化,所以在这里边我们添加一个方法,叫做一个音译,这个音译它是干嘛呢?这个是我们游戏的一个游戏的初始化方法,调用后我们游戏界开始。游戏开始,所以的话,我可以啊,直接在我这个constructor里边,我调一个z.in初始化游戏让它开始,或者呢,我也可以在index里边去调一下也行,但是我就省点事了,我直接在这里边调,也就是你创建完我这个对象,我这个游戏就直接开始了啊直接开始了,好,那游戏直接开始,游戏一开始我们的第一件事儿是干嘛,第一件事是干嘛。第一件事儿我们想一下,哎,第一件事儿我是不是得让我这个舌头能动啊,哎,也就是当我的这个键盘上的上下左右这个方向键按下去的时候,我的舌是可以跟随我的鼠标去移动的,所以这个里边我们就需要先给我们的整个这个网页是不是绑定一个这个键按键按下的事件呀,诶所以在in里边我们要做的第一件事儿啊,是什么呢?诶来绑定我们这个键盘的这个按键按下的一个事件,这个事件呢,我们叫做一个document,点一个I的in one listener,我们直接来一个,这叫做什么呀?叫做一个key档,Key档里边我们是不是需要传一个回调函数啊,哎,回调函数那注意了啊,我们现在既然是用我们TS写了,用这个面向对象的这个方式去写了,那这个时候我们再去传这个回调函数的时候。
06:49
最好的话,不要通过这种形式去传,因为这种形式去传的话,等于我这函数在这儿又给它写直接写的函数的字面呢,我们不便于这个后边的维护,不好找,有的时候因为你这个如果业务逻辑过多的话,这非常的乱啊,非常的乱,所以这里边的话,我们在这个外边我们创建一个什么呢?创建一个我们这个键盘这个按下的一个响应函数,也就是我把这个响应函数呢,我直接设置成我们这个类的方法,这个东西我们叫什么呢?叫做一个key down的一个handler。
07:25
Handle德ler啊,也就是我们的一个么,一个这么一函数,一般这种事件的响应函数我们叫一个handle德ler叫做一个什么聚丙函数,大概这么一个意思啊,创建完了以后,那既然这个函数我们是要把它作为事件的响应函数去用的,那这个时候我们是不是需要给它有一个这个回调函数,有一个这个参数啊,所以我们这来一个这个event,既然是键盘事件,它的这个事件对象应该是一个这个key keyboard event啊event,所以我们要想绑定这个,我们就在这儿直接传一个Z点一个key档handleler,也就是当我的这个事件触发的时候,我会调用这个函数啊,会调用这个函数,诶,那这样的话,你看这个结构是不是就能清晰一些啊,清晰一些,那现在我们其实关心的是什么?就是当我们按下按键以后,我希望能知道我用户按的是哪个按键,所以在这里边我们直接来一个,诶来一个什么呢?Event点一个key,这个的作用是用来获取我们当前用户获按的。
08:25
这个按键的这个名字,哎,我们来看看效果啊,那现在的话等于说我们当这个new,这个game controlr1设置完了以后,我们这个事件就已经绑定好了,绑定好了我现在按这个按键,这是不是应该就有反应了,哎来看一下cancel现在还没摁呢啊来我这上,诶你看a row up下a row down左是a row left的,右是a row,诶a row left你看这是不是它给我返回的这几个值啊,哎,我给它复制一下啊,复制一下粘过来,如果你之前用过这个事件,这东西你会很清楚,但是如果你没用过,我需要简单的去说一下啊,它返回的是一个这个字符串啊,它返回字符串当我摁上的时候返回的是AR up,当我摁下的时候返回的是一个arrow a down啊是这么一个流程,那这里边我们这个按键就已经有了啊,按键有了,但是呢,注意啊注意。
09:20
它有个问题,这也是我们这个GS这个这个do里边的一个遗留问题,什么问题呢?就是这个值啊,它在IE里跟在这个Chrome里啊,它的结果不一样,我们来看看啊,我们来看看啊。打开这个IE。直接点击我们这个检查元素看一下控制台。哎上哎呀哎呀呀。清空一下啊上up下down,诶诶这个左是left,又是一个right,也就是在IE里的话,它实际上只有谁呢上呢,就是up。
10:05
下呢就是一个就是一个大,然后左呢是left,然后这个右呢是一个right,哎你要注意,所以你要兼容IE的话,那这两种情况你都需要考虑啊,他们都是字符串,它们都是字符串,哎,那待会儿我们来说怎么去处理这个东西啊,怎么去处理东西,那现在也就是我们现在这个键按键按下的事件是不是就已经绑定好了,诶我们也就能知道我们这个,诶鼠标你到底按的是什么方向啊,什么方向了,那这里边的话,我们就需要有一个东西干嘛呢?这个东西我需要用它来帮我去存储,用户按的这个按键的一个方向怎么存储,在这里面,我们创建一个属性,创建一个属性来干嘛呢?哎,来存储我们,哎这个暗。这个叫什么呀,蛇的这个移动方向,也就是什么呢?也就是也就是我们这个按键的一个方向。
11:08
按键的一个方向,那这里边的话,我们直接写一个,直接写一个叫direction direction的值的话,我们让它是一个string string默认值,我给它一个默认值,我给它是一个空串,也就是一上来这个值是是一个空串啊,是一个空,那么我什么时候我去改这个值呢?什么时候去改这个值呢?当我用户的按键按下的时候,也就是当我这个函数触发的时候,我是不是要修改这个值啊,哎,也就是我在这儿要修改这个Di direction这个属性,那我们最简单的方式,直接一个this,点一个direction,等于一个event,点一个keep,也就是当我的用户去按下这个按键的时候,我把这个按键的值存到这个direction里面啊,存到direction里面,这应该能看懂,你说老师你存它干嘛呀,别着急,这个值待会儿我们要用,待会我们要用。
12:08
哎,先给我记住了啊,先给我记住了,现在的话,当我用户按下以后,我这值是不是就存到这个z.direction里边了,存没存进进来,现在有没有问题,我们先看效果啊,先看效果,我们看看这运行的时候,它现在会不会报错,我摁着一个这个上下左右,你看是不是没有任何的报错啊,哎,没有任何的报错,但是问题也来了,那我这个值它到底存没存进去呢?我们这样啊,我们来做一个小实验,在这儿呢,我把这个值啊,我整一个变量啊,Com,我们叫做一个GC等于它啊,GC等于它,诶GC,这个GCGC小写吧,Game ctrl啊,Game ctrl,然后呢,在这儿呢,我们设置一个啊,我来一个这个定时调用啊,Set in。Set,我们来一个定时调用干啥呢?我让他呀,每一秒执行一次,去给我打印这个game CR的一个这个direction属性,我要干嘛,我要看看这个属性,它到底有没有给我复值上去啊,到底有没有给我复制上去,我们来看一下效果啊,这里边我们先给它打开这啊来回到这儿来,我这一刷新。
13:19
诶,等会儿啊,他还在进行重新编译啊,我们不着急,会不会是成功呢,会不会成功呢?诶,你会发现这已经开始打印了,你看这打印的一直都是什么,一直都是空啊,一直都是空,是不是没有打印出我们什么a row up arrow down啊,AR life的AR这些东西,是不是没有打印出这些值啊,哎,没有打印出这些值,诶这又是。为什么呢?这又是为什么呢?哎,注意啊,注意这个问题,注意我们现在我是把这个z.K到handler以参数的形式传到了这个A的event listener里,也就是当我们这个函数调用的时候,当我们这个事件啊,Key down这个事件触发的时候,它是不是就在调用我这个handler,我这个函数去处理,去响应这个事件呀,那这个时候注意我们之前如果你学过GS,我们会知道GS里的Z函数中的Z,这个Z它到底它是谁呀。
14:22
我们说了Z是谁,这是我们GS里一个非常非常恶心的这么一个东西,它很乱,它很乱,但是简单来说,那就是谁调用这个Z呢,就是谁,但是注意我们在这儿是把这个函数作为参数传给了a event listener,但是我们这个函数最终的调用方式是由谁决定,是不是在这个函数里去决定的,所以这个时候注意这个里边的Z,这个里边的Z啊,当我们这个事件执行的时候,它的Z还是不是我们的这个game control这个对象了,还是不是我们来看看啊,我们来看看在这儿的话,我们来打印一下这个ZZ点一个log。
15:07
哎,Log,我们这个Z打印一下,我们看看这个Z他是谁,很明显它肯定不是我们这个game control,如果是game control的话,这已经我们就就应该这个成功了,对吧,没成功就证明一定不是摁一下看他是谁,这里的Z是不是给我返回的是document啊返回的是document,为什么是document,哎,因为我们的这个事件是不是给document绑定的,哎,所以这个时候这个Z就是document,那这个的话,它是我们的这个。怎么说呢,叫做我们这个GS一个特性事件给谁绑定的,它里面的Z它就是谁,但是这个时候啊,就给我们带来一个问题,OK,这次是document,但是我是不是想给这个GC这个对象里game control这个对里,我是不是要修改它的属性啊,那你这次是document,我这是不是就改不了了,哎,改不了了,哎呀,烦死了是吧。
16:08
哎呀,这要怎么办?我希望它里面的这次是那个game control那个对象,这样的话我改的时候我就好改了,我直我直接通过这次我是不是往里加属性了,但是现在它的Z次是do怎么办呢?我们在这儿呢,我们可以调一下BB到里面,我们传一个这个Z啊,传一个Z,那这样做的什么效果,Band的话,Band的作用实际上它的作用是创建一个新函数,所以在这我们直接调一个z.handle点,实际上是创建了一新的函数,然后把这个Z绑定成这个函数的Z,那这样设置完了以后,无论这个函数你是怎么调用的,这个Z总是你当初绑定那个这个Z是不是就表示的是我们当前对象啊,所以这个时候我们这个函数里面的所有的this就都表示的是我们这个game control这个对象,就没有这个问题了,你再看一刷新。
17:07
做一个。哎,还是等一下,还是它在进行这个重新的一个编译啊,重新编译来,我们来看一下上,诶你看a row up是不是就有了,诶左再看a row left是不是有了,来一个右a row right是不是有了,来一个这个下我们这个a down是不是也有了,哎,那现在等于我们这个现在的一个按的按键的一个方向就已经存储到了我们的什么呢?我们的这个对象里,所以啊这里边。这里边这里边所涉及到的知识点,主要是一个是我们这个ZZ到底是谁,你如果你不懂的话,你说老师这Z我没看明白,你可以往前边去捋捋,我们这儿就不再花时间去讲了,第一个问题,第二个问题半的作用是什么,你也去看一下,如果不懂的话啊,这样看懂了就明白了,所以我们这里边写的话,我们通常的处理方式就这样啊,我们把这次绑定,就是我们想让它是谁就是谁,不会因为你的这个诶绑定给谁,这个Z次就是谁,这是我们通常的一个做法啊好,那这绑定完了,这个cancel log我们可以去掉了,那现在的话,我们等于这个按键,我们现在已经可以知道了,到底是这个谁,你看a row life的aodown就已经就已经有了啊,已经有了,但是呢,还有一个问题,还有一个问题,我们这个这次点一个direction,我们是用来存储,我们这个叫叫这叫叫这什么呀,是我们的这个按键的这个。
18:38
实际实际上就是蛇的一个移动方向啊,实际上存的就是一个蛇的一个移动方向,那这个时候注意了,我现在是直接把这个K赋值给了,那如果你用户摁的是上。哎,下。左右是不是当然没问题啊,但是用户如果N的是B呢?如果N的是H呢?如果N的是I呢?如果N的是J呢?是不是就出问题了,为什么?因为这个不是我们方向的范围,我们的方向只有这么几个值,A row up AO down a left a right,还有up down left right,是不是只有这么几种值啊,而这些值就是一个非法值,那我说了,如果用户按了HH往哪走,如果用户按了接接往哪走啊?我们这儿是不是没有办法去判断呀?所以这个时候我们还需要做一件事儿,就是我们不能直接去给这个direction去赋值,赋值之前我们需要干嘛呢?我们需要检查一下我们这个方向啊,这个this.direction或者叫做event.k的值是否合法。
19:52
是否合法,也就是用户是否按了这个正确的这个按键啊,用户是否按了正确的按键,什么叫正确的按键,只有我这四个方向键,也就是只有这八种值是正确的,其他的值是不是都不对呀,诶都不对,这样如果你要不这么设计设置的话,如果你要不设置的话,待会你可以试试,如果你不设置,我们摁上下左右,诶我这舌还可以移动,但是如果我按了上下左右以外的键,比如说摁个A,你会发现啊咔蛇就停在那儿啊,蛇就停在那儿了,这样啊,我们先把这个问题呀,留在这儿啊,先把这个问题留在这儿,待会儿我们再做到那步的时候,我们再去演示这个问题,你可能看的会更明显一些,先把这个问题留在这儿啊,好,那么现在的话,我们把index里边这个我先给它注掉啊,我现在不需要去打印这个direction了,那我们这个game control的话,我们这个类完成了一部分啊,完成了一部分已经给我们这。
20:52
这个诶,Document绑定好了这个按键,这个键盘按下的一个事件了,但是现在的话,我们的蛇呢,还没有没有动啊,没有动,那下一步我们是不是要让这个蛇去动起来呀,怎么让蛇动起来,让蛇动起来我们要依据什么,蛇到底是往左走,往右走,往上走,往下走,还是往什么方向走,我们怎么办?那蛇要往什么方向走,我们这是不是已经有了蛇往哪个方向走,Direction是rap就往左走,Direction是rap就往右走,是up就往上走,是down就往下走,也就是说它决定了我们蛇的一个运动的一个方向,那下边的问题是我们怎么让动起来呀?哎,那当然我们需要在game control里边,我们要再加一个方法,什么方法别着急,停一下,我们待会儿接着说。
我来说两句