短语3的真实指南:或者,我如何学会停止担心和爱枪,第1部分

如果您像我一样-并且如果您正在阅读本文,那么我想您至少在某种程度上-多年来您可能已经挖掘出许多游戏制作框架,并且至少浏览了它们的框架内部。 再次,假设您像我一样,您已经使那些遭遇沮丧而有些受挫,如果有的话,在文档中留下了隐喻的血迹。 您遇到的大多数教程可能都是针对与自己项目无关的游戏类型,因此没有太多交叉,或者远远超出或低于自己的水平,因此您很想撕毁自己的如果挫败感达到了发烧的程度,那么就把头发拔出来,或者也许是别人的头发。

最近,我把自己扔到了Phaser 3的岩石上,Phaser 3是经典的Phaser.io的一个可爱但几乎没有文献记载的新版本,并且在这个洞穴的另一端还活着。 因此,我认为我会尽力确保未来的旅行者在这条特殊的道路上不必对吸引我的低矮钟乳石act之以鼻。 因此,请为以下各项做好准备:

短语三的包装

首先是第一件事。

外语:

你们中的某些人可能曾经使用过Phaser 2。 如果您阅读并认为“就是我!”,则可以安全地跳过此部分。 如果没有,继续前进我的好马!

在开始之前,我将为您定义一些术语!

游戏 :这就是您正在制作的所有内容! 您只需在索引文件中声明一次,然后仅在需要访问的配置中有某些内容时才调用它。 我们可以将这个“游戏”视为一系列……

场景 :基本上,每当屏幕变黑一毫秒并以完全不同的方式重新出现时,即为“场景”。 标题屏幕将是一个场景,选项屏幕将是另一个场景,游戏中的每个“关卡”或“房间”或“区域”将是它们自己的场景(尽管在某种程度上取决于您决定设计它的方式!)。 这意味着,如果您要制作一个无限的跑步者,那么只有一个“关卡”,因此您的整个游戏可以包含在一个场景中!

如果您打算制作带有过场动画的游戏,那么每次剪辑都会是一个新场景。

世界:您的“世界”是角色在给定场景中可以访问的任何区域。 在无限跑步者的例子中,游戏世界就是一切! 如果您想将游戏分为“房间”,那么每个房间的大小就是“世界”。 但是,您必须设置世界的大小! 默认情况下,您的角色可以从房间的两侧跑进热情的黑暗中。

物理 :这是您决定使用的任何物理引擎。 在Phaser 3中,默认情况下有三个引擎:Arcade,Ninja和P2物理引擎。 您通常可以启用或禁用这些引擎,针对特定区域对其进行更改,也可以根据自己的想法为场景或对象打开或关闭特定的物理定律。

Sprite :屏幕上某物的图像。 可以动画。 加载需要花费更多时间,并且要花费更多的精力从处理器进行渲染,因此Phaser建议您将不需要动画的任何东西都使用…

图片 :除了没有动画功能外,它与精灵几乎完全相同。

商店 :使用过Redux或其他状态管理器的任何人都可以识别。 这就是您的游戏状态所在! 如果您要制作一个简单的单场景游戏(例如Mario关卡),则可能不需要使用它。 您可以在场景的构造函数中或游戏中其他对象和角色的构造函数中保留游戏的大多数状态。 大多数需要持久存储的东西都将放在这里。 实际上,Phaser.io有一个内置的状态管理器,但是如果您喜欢Redux或Fluxable之类的东西,请随意使用它。

如果最后一个定义让您大力摇头以将混乱和痛苦的眼泪扔到虚空中,请不要害怕! 稍后,如有必要,我将对此进行更详细的介绍。

好了,既然您已经赶上了(或者您已经成功跳过了定义部分),那么让我们开始吧!

没有戏就没有场面

首先,首先要做一个样板。 我建议仅从Phaser 3示例样板开始。

  git clone https://github.com/photonstorm/phaser3-project-template.git 

并没有很多,但是它确实带来了一些使您的生活更轻松的事情,例如Webpack配置(对于不熟悉的用户,这会将您的文件捆绑在一起,使它们更易于浏览器访问)并为您提供了开发服务器当您运行npm start时,它将构建,运行并查看您的文件。

完成后,您应该会在屏幕上看到“ Phaser”徽标跳动。 如果您这样做,那就太好了! 您已准备好继续前进。 现在,让我们看一下index.html。

物理学宣言!

因此,例如,您可能具有:

 配置{ 
物理学:{
默认值:忍者,
忍者: {
调试:true
}
}
}

然后,我们使用一个很好的实例实例化我们的游戏:

  const game = new Phaser.Game(config) 

无论如何,这只是将我们编写的配置传递到了Phaser模块中包含的Game构造函数中。

您可能已经注意到场景配置中属性的名称与下面的方法名称匹配。 好眼睛! 它们也是一些非常普通的英语单词! 带我到…

生活圈子

对于那些不是Java语言专家但只想弄清楚如何制作游戏的人,我们将在这里进行一些概念上的介绍。 拥有Thaumaturgical Javascript中的高级形而上学学位的人可以直接跳至标题为“ preload”的部分。

对于任何响应式前端框架,要掌握的关键概念之一是LIFE CYCLE。

组件的生命周期就像有机体的生命周期一样。 它出生,生存,死亡。 每个场景都有生命周期。 您的类,类的实例,以及基本上所有您想在页面上呈现的内容,都一样。

在Phaser中,主要有以下生命周期方法:

*预载

* 创建

*更新

尽管Phaser也运行一些destroy方法,但是这些方法是埋在Phaser原型中的只读方法,因此您无法对其进行任何处理。 但是,您可以运行检查以查看update方法中“ destroyPhase”标志是否设置为“ true”,然后运行您需要运行的所有任务!

所有这些方法都可以在大多数组件上使用,但是您可能会发现它们在场景中最有用

预载()

您将要在“预加载”方法中调用所需的任何外部资源。 例如:

这不会将它们添加到您的场景中:只是使这些资产用于该特定场景。 您有食材,但还没有煮过。

第一个参数是用作该图像关键点的字符串,因此您可以在需要的任何地方将其拍入场景!

或者,如果您有很多事情想要一次预加载,则可以创建一个整个场景,除了预加载文件外什么也不做,并且可以渲染加载屏幕!

创建()

这是您开始使用购买的所有食材烹饪的时候,也是隐喻开始分解的地方,因为通常我在制作食物后就不会更新食物。

尽管如此,让我们还是举几个例子。

 让背景= this.physics.add.staticGroup(); 
this.NPC = this.physics.add.staticGroup();

在这里您可以看到我使用了两种不同的技术向场景中添加东西 。 NPC明确将NPC设置为场景的属性,而让background将其设置为场景范围内的变量,因此,如果您需要从场景或组件外部访问正在制作的东西,请使用“ this”,以便您可以通过调用myScene.NPCs进行引用。 如果您不希望从组件外部访问该属性,请使用一个变量。

至于staticGroup,它使您可以将sprite或图像添加到场景,并立即对类别的所有内容设置一堆规则,而无需d。 如果事物不会移动或不受重力影响,则创建一个staticGroup; 如果确实要移动这些项目,则可以使用this.physics.add.group()做同样的事情。

因此,您要告诉场景,将至少有一个但可能很多背景组件,以及至少一个但可能很多NPC。 它告诉物理学家不要在这些物体上工作,因此当您的主角撞到NPC时,它不会开始在屏幕外滑动,如果不这样做,那将会发生!

让我们来看一下将项目实际添加到组中的过程:

  this.groundLayer = background.create(500,300,'bedroom') 

500和300以像素为单位设置,它们确定了放置项目的位置。 它从对象的中心到左上角进行测量。 如果将其设置为(0,0),则您的项目将在左上角以打点方式结束。

“卧室”字符串是我们之前设置的便捷键之一!

您可以使用此方法做更多的事情,稍后会介绍。

更新()

实际上,更新方法包含您要多次运行的任何内容! 如果您想了解它的实质,它包含了将根据用户输入/状态更改而更改的任何方法或声明。 但是,一旦您告诉Phaser您希望在构造函数或create方法中使用它们,许多基本检查器和其他方法就会在后台自动运行,

让我们看一下放入更新方法中方便的事情,打开箱子!

  //在“胸部”类的更新方法中 
  this.scene.physics.add.collider(this,this.scene.groundLayer); 
  this.scene.physics.overlap(this,this.scene.link,this.openChest); 

首先,这会为胸部创建一个碰撞器,以防止其从地面掉落并进入一个无情的宇宙的无限深处。 您会注意到两个参数-“ this”(指所讨论的箱子的实例)以及this.scene.groundlayer或包含箱子的场景的地面层。 (它不必称为底层;如果它坐在云上,也许您将其称为场景中的松饼-再次,我不在这里判断)。 首先检查第一个参数是否存在碰撞,然后自然检查第二个参数。 实际上,通常走到哪里都没有关系。 如果您发现自己的游戏开发过程很重要,那么您可能已经超出了本教程的范围,应该在注释中分享您的智慧。

其次,它创建了另一种交互方式,这次是在胸部和Link之间-特别是该场景中存在的Link实例。 这不是碰撞:这是“重叠”,意味着胸部不会阻止Link的运动,但是一旦它们的身体重叠(“ body”是Phaser的术语,通常相当于“命中框”,它会触发“重叠”事件。

您会注意到重叠方法中的第三个参数。 这是回调方法,一旦触发相关事件,就会调用该方法。 在这种情况下,一旦Link与胸部重叠,胸部就会打开,并且大概会播放动画,它将为您选择一个好项目来移交,Link会在他的眼睛中看到星星,然后该项目最终以链接的清单,您将恢复正常的游戏状态,并且每个人都很高兴。

现在您知道最重要的生命周期方法! 恭喜,您可以顺利制作第一个Phaser游戏!

创建一个场景

现在让我们谈谈创建场景。

首先,我强烈建议创建一个名为GameScene的场景或类似的场景作为您的“基础”场景,其中包含一堆方法,例如键绑定或您真正想继承到所有场景的任何其他方法没有太大的变化。 考虑到这一点,让我们创建一个默认的GameScene!

 从“ phaser”导入{Scene}; 
 导出默认类GameScene扩展了场景{ 
构造函数(config){
超级(配置);
}
}

使用React的任何人都会熟悉此语法。 Scene是Phaser的组件,您可以扩展这个坏孩子,以便可以使用Scene原型中的everythinggg。 通常,这将是各种各样的方法,但是它也赋予了场景必要的场景外观,使您可以进行诸如……的便捷操作。

开始一个新场景

假设您有第一个场景正在工作。 万岁! 但是,也许它并没有做很多事情,而您想继续前进。 或者,也许您正在一个小组中工作,并且您不希望每个人的代码都重叠,所以您真的想一次处理多个不同的场景,但是您想知道如何从一个场景过渡到另一个场景。 不要害怕! 以其最基本的形式,这是一个简单的工作。

  this.input.keyboard.once('keydown',(event)=> { 
theme.stop();
this.sound.add('select')。play();
this.scene.start('VictoryLap');
});

旁注,您可能已经注意到的一件事是,Phaser确实非常喜欢其方法链。 他们真的很擅长。 这意味着,如果您想向场景中添加声音并立即播放,您要做的就是将这些方法一个接一个地链接。

但是回到三明治的肉上。

这只是意味着,只要您按一个键(在这种情况下为任何键),它将发出一个事件(很幸运,Phaser具有本机事件发射器/处理程序),然后将触发一连串的反应,最后一个反应开始一个名为VictoryLap的场景。

您可能会说:“但是等等!” “这是我的眼睛吗?”

是的,我亲爱的同胞,是的。

“您没有指示我从其他位置导入场景,也没有在范围内声明此新场景吗?”

不,朋友,我没有! 我们不需要做任何一件事情。 自定义(和必要性)指示我们改为在游戏中注册场景! 您还记得我们在开心的小日子刚开始时提到的Index.js吗? 我们还没有完成它。

因此,在该文件中,我们的游戏实例下面,我们必须添加:

 让游戏=新的Phaser.Game(config); 
  game.scene.add('GameScene',GameScene); 
game.scene.add('VictoryLap',VictoryLap);

所有这些我们都将在文件顶部导入,如下所示:

 从'phaser'导入Phaser; 
从'./scenes/GameScene'导入GameScene;
从'./scenes/VictoryLap'导入VictoryLap;

而且,瞧! 我们的场景已注册,我们的按键回调,并且我们可以像专家一样从一个场景移到另一个场景。

到此为止,今天的《通缉令3》结束了。敬请期待更多更新! 它们可能随时发生!

下一集,在DragonBall Z上:

大多数Phaser教程没有涵盖的更多内容:创建类! 实例化场景中的课程! Hitboxs! 补间动画,但不是暮光之城首映的那种! 对象互动! 并加载更多您不想错过的动作!

再见!