当前位置:   article > 正文

机器学习:让机器学会打游戏之陨石坠落_如何写个游戏让机器玩起来

如何写个游戏让机器玩起来

陨石坠落画面

这是一个系列课程,我们将会用不同的机器学习算法,让机器学会玩不同的游戏。

今天要让机器玩的游戏是:陨石坠落(点击试玩)。

课程概述

课程中,我们将围绕陨石坠落点预测问题,建立机器学习模型。

我们将会用到线性回归、梯度下降、Z-Score数据标准化等机器学习算法。

课程中,我们将使用Javascript作为开发语言,游戏构建在我自己写的一个简单的H5游戏引擎上。

你可以直接登陆我的网站,进行开发,无需安装开发软件和配置开发环境。

打开地址 http://www.insideai.cn/lesson_game1.html 就可以开发了。

 课程会分成两个部分:

1. 游戏制作  这部分你将用H5亲手制作一款简单的游戏

2.机器学习建模  这部分你将从零开始,构建一个机器学习模型,并动手实践出来

下面我们就先说下,如何用H5制作一款简单的游戏。

游戏制作

游戏故事背景

公元4096年,狮子座M1024星发生爆炸,大量陨石向地球飞来。如果陨石撞上地球,将会对地球造成毁灭性的冲击。所幸神盾局已经研制出能抵抗陨石冲击的神盾,但神盾没有办法自动锁定陨石。

因此神盾局找到了你,你是个计算机高手,能为神盾注入灵魂。可以让神盾具有预测能力。 为了配合你的工作,神盾局会实时检测陨石的位置,并将陨石数据告知给你。 

你需要利用这些数据,给神盾建立机器学习模型,在陨石坠落到安全线之前,预测出陨石的坠落点,并移动至陨石的坠落。

注:陨石坠落的位置、速度和方向都是随机的,每一颗陨石都不一样。

游戏镜头制作

游戏主要包含三个分镜头

1. 游戏引导镜头 主要介绍故事背景和引导玩家开始游戏。

 引导镜头
2. 游戏主体镜头 为游戏的主体部分,完成游戏的交互逻辑。

游戏主体镜头 
3. 游戏结束镜头 游戏的结束画面和引导玩家重新开始游戏。 

游戏结束镜头

创建游戏场景

在制作镜头之前,我们需要先把游戏场景制作出来。游戏场景类似于游戏舞台,有了游戏场景后,游戏镜头才能播放出来。游戏场景的创建和初始化代码如下:

  1. var scene = new DMScene("gameContainer");
  2. scene.init();

注:上述代码是基于我写的H5游戏开发引擎编写的,因此需要登陆我的网站上进行开发,打开开发页面

下面我们就逐一把这些分镜头制作出来。

游戏引导镜头制作

游戏引导镜头中,包含背景图片和引导文字,因此文字会开启逐字打印效果,因此我们还需要播放打字音效。

  1. //DMImage为图片对象,参数分别是:游戏场景、图片地址、横坐标、纵坐标、图片宽度和图片高度
  2. var guideImg = new DMImage(scene, "fall.jpg", 0, 0, scene.gwidth, scene.gheight);
  3. var guideStr = "公元4096年,狮子座M1024星发生爆炸,大量陨石向地球飞来。如果陨石撞上地球,将会对地球造成毁灭性的冲击。" +
  4. "所幸神盾局已经研制出能抵抗陨石冲击的神盾,但神盾没有办法自动锁定陨石。" +
  5. "因此需要为神盾注入灵魂,让它自己锁定陨石,并移至降落点。"+
  6. "经过千挑万选,最终发现只有你能胜任这个任务。" +
  7. "点击任意区域,开始拯救地球吧!!!";
  8. //DMTxt为文本对象,参数分别为:游戏场景、文本内容、横坐标、纵坐标、字体样式、
  9. //字体颜色、行间距,是否开启逐字打印
  10. var guideTxt = new DMTxt(scene, guideStr, 60, 80, "bold 36px '微软雅黑','宋体'"
  11. ,"white", 64, true);
  12. //DMAudio为音频对象,参选分别为:音频地址,加载完成回调函数,是否循环播放
  13. var writeMic = new DMAudio("write.mp3", null, "loop");
  14. //游戏引导镜头
  15. function guideGame(){
  16. //将镜头中的元素添加到场景中
  17. guideImg.addToScene();
  18. guideTxt.addToScene();
  19. //播放打字音效
  20. writeMic.play();
  21. //15秒后,暂停打字音效
  22. setTimeout(function(){writeMic.pause();}, 15000);
  23. }

游戏引导镜头制作完成后,调用函数guideGame,游戏场景中,就会播放引导镜头画面啦。

注:游戏中的图片和音频资源均来自于搜索引擎,如有侵权,请告知。游戏中,用到的图片和音频,我已放到我的网站上了。打开开发页面

引导镜头逐字打印

游戏主体镜头制作

游戏主体镜头中,包含陨石、神盾、得分文本和背景图片,此外我们还会循环播放游戏背景音乐。

  1. var yunshi = new DMBox(scene,100,100, 10,10,"white");
  2. //安全线位置,在屏幕的3/4处
  3. var safeHeight = scene.gheight*0.75;
  4. var shendun = new DMBox(scene, 0, safeHeight, 100, 30, "gray");
  5. var earthImg = new DMImage(scene,"earth.jpg", 0, safeHeight-30, scene.gwidth,
  6. scene.gwidth/4);
  7. var score = 0;
  8. var scoreTxt = new DMTxt(scene, "得分: " + score + " ", scene.gwidth - 120, 60,
  9. "bold 24px '微软雅黑','宋体'", "red");
  10. var bgMic = new DMAudio("bg.mp3", null, "loop");
  11. function startGame(){
  12. //清空游戏场景,清除上一个镜头中的元素
  13. scene.clear();
  14. //暂停上一个镜头中的音效
  15. writeMic.pause();
  16. earthImg.addToScene();
  17. yunshi.addToScene();
  18. shendun.addToScene();
  19. scoreTxt.addToScene();
  20. bgMic.play();
  21. }

游戏主体镜头制作完成后,调用startGame就可以在游戏场景中,播放主体镜头了。

游戏结束镜头制作

游戏结束镜头中,包括重玩引导文本和背景图片,其中重玩文本会开启逐字打印效果,因此需要播放打字音效。

  1. var overImg = new DMImage(scene,"over.jpg",0,0,scene.gwidth,scene.gheight);
  2. var overStr = "很遗憾,因为您的算法不当,陨石撞上了地球,地球发生了爆炸。不服!"
  3. + "点击任意区域,让时光倒退,重新开始!!!";
  4. var overTxt = new DMTxt(scene, overStr, 60, 80, "bold 36px '微软雅黑','宋体'",
  5. "white", 64, true);
  6. function gameOver(){
  7. scene.clear();
  8. bgMic.pause();
  9. overImg.addToScene();
  10. //设置逐字打印的起始字符
  11. overTxt.charAt = 0;
  12. //设置逐字打印速度
  13. overTxt.writeSpeed=10;
  14. overTxt.addToScene();
  15. writeMic.play();
  16. setTimeout(function(){writeMic.pause();}, 10000);
  17. }
  18. gameOver();

好了,三个游戏镜头制作完成了,接下来,我们要已经玩家的交互行为,实现交互效果了。

游戏交互开发

陨石坠落特效

目前为止,所有的元素都是静止的,下面我们就陨石动起来。这一节,我们实现陨石坠落特效。

陨石坠落的位置、速度和方向都是随机的,因此陨石的初始坐标和速度都要随机产生。

此外,为了提升游戏体验,陨石需要拖着尾巴,逐渐变亮,形成燃烧的效果,并播放坠落音效。

  1. //使用线性过渡颜色,模拟陨石逐渐变亮
  2. yunshi.useGrad("black","white",100, scene.gheight*0.6);
  3. //陨石坠落音效
  4. var fallMic = new DMAudio("fall.mp3");
  5. function fall(){
  6. //在游戏场景的中间80%区域随机产生横坐标
  7. yunshi.x = Math.random()*scene.gwidth*0.8 + scene.gwidth*0.1;
  8. yunshi.y = 0;
  9. //水平方向的速度随机产生,可正可负,与场景宽度相关
  10. yunshi.xSpeed = (Math.random() - 0.5)*scene.gwidth/80;
  11. //竖直方向的速度随机产生,为正数,与场景高度相关
  12. yunshi.ySpeed = Math.random()*scene.gheight/160 + scene.gheight/160;
  13. //在陨石运动的反方向加上音频,模拟尾巴
  14. yunshi.useShadow(20, "yellow", -1*yunshi.xSpeed, -1*yunshi.ySpeed);
  15. fallMic.play();
  16. }

这么复杂的效果,使用游戏引擎后,几句代码就完成了。打开开发页面

串联各个分镜头,处理用户点击行为

下面我们就把各个镜头串联起来,依据游戏逻辑,进行镜头切换。

在游戏引导镜头,用户点击时,进入游戏主体镜头,在游戏主体镜头,用户点击时,依据游戏状态,播放或暂停游戏。

在主体镜头中,如果陨石坠落到安全线以下,则认为游戏撞上了地球,游戏结束。

  1. //定义游戏镜头索引,1引导镜头,2主体镜头,3结束镜头
  2. var gameStatus = 1;
  3. //添加鼠标点击监听事件
  4. scene.setClickListener(function(){
  5. if(gameStatus == 1){
  6. startGame();
  7. fall();
  8. gameStatus = 2;
  9. }else if(gameStatus == 2){
  10. //如果有些正在进行,则暂停有些,否则播放游戏
  11. if(scene.isPlay){
  12. scene.pause();
  13. }else{
  14. scene.play();
  15. }
  16. }else if(gameStatus == 3){
  17. scene.clear();
  18. startGame();
  19. fall();
  20. gameStatus = 2;
  21. }
  22. });
  23. //游戏场景回调函数,绘制每一帧之前都会调用该函数
  24. function onDraw(){
  25. if(gameStatus != 2){
  26. return;
  27. }
  28. //判断陨石的纵坐标是否在安全线以下
  29. if(yunshi.y > safeHeight + shendun.height){
  30. gameOver();
  31. gameStatus = 3;
  32. }
  33. }
  34. //设置游戏场景的回调函数
  35. scene.onDraw = onDraw;

好了,现在游戏可以在各个镜头之间切换了,但是神盾还没有办法移动,因此陨石总是撞上地球。

用键盘控制神盾移动、砰撞检测和各种特效

我们先用键盘控制神盾移动,后面我们再说如何让机器预测陨石坠落点,让神盾自主移动。

可以移动神盾后,我们就需要检测神盾与陨石是否发生了砰撞,如果发生了砰撞,我们需要播放陨石爆炸特效,并让神盾发出保护光环,播放撞击音效,此外我们还需对玩家进行计分。

  1. //定义神盾移动速度
  2. var shendunSpeed = scene.gwidth/100;
  3. function goLeft(){
  4. shendun.moveTo(shendun.x - shendunSpeed, shendun.y);
  5. }
  6. function goRight(){
  7. shendun.moveTo(shendun.x + shendunSpeed, shendun.y);
  8. }
  9. //监听用户按键事件,如果是左箭头,则向左移动,如果是右箭头,则向右移动
  10. window.addEventListener("keydown",function(e){
  11. var keycode = scene.getKeyCode(e);
  12. if(keycode == 37){
  13. goLeft();
  14. }else if(keycode == 39){
  15. goRight();
  16. }
  17. }, false);
  18. //重写场景回调函数,增加砰撞检测和陨石爆炸特效
  19. function onDraw(){
  20. if(gameStatus != 2){
  21. return;
  22. }
  23. if(explordeTime > 0){
  24. explode();
  25. }else if(!yunshi.isInScene()){
  26. fall();
  27. }else if(yunshi.hitOnSprite(shendun)){
  28. hitOn();
  29. }else if(yunshi.y > safeHeight + shendun.height){
  30. gameOver();
  31. gameStatus = 3;
  32. }
  33. }
  34. //陨石爆炸持续时长
  35. var explordeTime = 0;
  36. //陨石爆炸函数
  37. function explode(){
  38. explordeTime--;
  39. yunshi.width = explordeTime;
  40. yunshi.height = explordeTime;
  41. if(explordeTime == 0){
  42. yunshi.width = 10;
  43. yunshi.height = 10;
  44. shendun.useShadow(0,"blue",0,0);
  45. fall();
  46. }
  47. }
  48. //陨石击中神盾音效
  49. var hitMic = new DMAudio("hit.mp3");
  50. //陨石击中神盾处理函数
  51. function hitOn(){
  52. score++;
  53. scoreTxt.txt = "得分: " + score;
  54. shendun.useShadow(20, "blue", 0, -5);
  55. hitMic.play();
  56. explordeTime = 20;
  57. yunshi.xSpeed = 0;
  58. yunshi.ySpeed = 0;
  59. }
  60. //更新场景回调函数
  61. scene.onDraw = onDraw;

好了,现在有些已经制作完成了,写了这么长事件代码,也有点小累了,玩会游戏吧。

下篇文章,我们将介绍如何针对游戏,进行机器学习建模,并利用机器学习模型,让神盾具有预测能力,自主移动到坠落点。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小舞很执着/article/detail/959418
推荐阅读
相关标签
  

闽ICP备14008679号