吃了 1000+ 个月饼

玩法规则:

  • 用手指按住飞行的兔子进行左右移动。
  • 碰到五仁的月饼则游戏结束。

你好,我是悟空。

一、背景

中秋节快到了,想做一个关于中秋的小游戏,然后将小游戏发布到公网上,这样大家就都可以玩了,独乐了不如众乐乐,说干就干。

体验地址:game.passjava.cn

二、功能实现

2.1 需求

  • 控制小兔子吃月饼。
  • 如果吃到了五仁月饼则游戏结束。
  • 如果吃到了其他月饼则得分。
  • 将游戏部署到网站上。
  • 可以分享游戏地址给其他小伙伴。

先看效果图:

玩法规则:

  • 用手指按住飞行的兔子进行左右移动。
  • 碰到五仁的月饼则游戏结束。
  • 碰到其他月饼 1 次则得 1 分。

三、代码说明

3.1 初始化

ini 复制代码
function Ship(ctx){
  gameMonitor.im.loadImage(['static/img/player.png']);
  this.width = 80;
  this.height = 80;
  this.left = gameMonitor.w/2 - this.width/2;
  this.top = gameMonitor.h - 2*this.height;
  this.player = gameMonitor.im.createImage('static/img/player.png');
​
  this.paint = function(){
    ctx.drawImage(this.player, this.left, this.top, this.width, this.height);
  }
​
  this.setPosition = function(event){
    if(gameMonitor.isMobile()){
      var tarL = event.changedTouches[0].clientX;
      var tarT = event.changedTouches[0].clientY;
    }
    else{
      var tarL = event.offsetX;
      var tarT = event.offsetY;
    }
    this.left = tarL - this.width/2 - 16;
    this.top = tarT - this.height/2;
    if(this.left<0){
      this.left = 0;
    }
    if(this.left>320-this.width){
      this.left = 320-this.width;
    }
    if(this.top<0){
      this.top = 0;
    }
    if(this.top>gameMonitor.h - this.height){
      this.top = gameMonitor.h - this.height;
    }
    this.paint();
  }
​
  this.controll = function(){
    var _this = this;
    var stage = $('#gamepanel');
    var currentX = this.left,
      currentY = this.top,
      move = false;
    stage.on(gameMonitor.eventType.start, function(event){
      _this.setPosition(event);
      move = true;
    }).on(gameMonitor.eventType.end, function(){
      move = false;
    }).on(gameMonitor.eventType.move, function(event){
      event.preventDefault();
      if(move){
        _this.setPosition(event); 
      }
      
    });
  }
​
  this.eat = function(foodlist){
    for(var i=foodlist.length-1; i>=0; i--){
      var f = foodlist[i];
      if(f){
        var l1 = this.top+this.height/2 - (f.top+f.height/2);
        var l2 = this.left+this.width/2 - (f.left+f.width/2);
        var l3 = Math.sqrt(l1*l1 + l2*l2);
        if(l3<=this.height/2 + f.height/2){
          foodlist[f.id] = null;
          if(f.type==0){
            gameMonitor.stop();
            $('#gameoverPanel').show();
​
            setTimeout(function(){
              $('#gameoverPanel').hide();
              $('#resultPanel').show();
              gameMonitor.getScore();
            }, 2000);
          }
          else{
            $('#score').text(++gameMonitor.score);
            $('.heart').removeClass('hearthot').addClass('hearthot');
            setTimeout(function() {
              $('.heart').removeClass('hearthot')
            }, 200);
          }
        }
      }
      
    }
  }
}

这段代码是一个简单的 HTML5 游戏的前端代码,使用了Canvas元素来创建游戏画布和动画。游戏的主要功能包括玩家控制一个飞船抢月饼,吃到不同类型的月饼得分,并且在一定条件下游戏结束。以下是对代码的主要部分进行的解释:

  1. function Ship(ctx):这是一个构造函数,用于创建飞船对象。它接受一个上下文对象 ctx 作为参数,用于绘制飞船。
  2. function Food(type, left, id):这是另一个构造函数,用于创建月饼对象。它接受三个参数:type 表示月饼的类型(0 或 1),left 表示月饼的水平位置,id 表示月饼的唯一标识。
  3. function ImageMonitor():这是一个用于管理图片加载的对象,包括创建和预加载图片。
  4. var gameMonitor 对象:这是游戏主控制对象,包括游戏的各种属性和方法。它负责初始化游戏,管理游戏的状态,绘制背景、飞船、月饼等元素,以及处理用户输入。

这段代码的主要功能是创建一个基于Canvas的小游戏,其中玩家通过触摸或鼠标控制飞船来抢夺不同类型的月饼,吃到月饼会得分,但如果吃到某种特殊类型的月饼,游戏将结束。

游戏主要流程如下:

  • 初始化游戏画布和事件监听。
  • 绘制背景图。
  • 创建飞船对象,并通过玩家的输入来控制飞船的位置。
  • 生成月饼对象,并让它们下落。
  • 检测飞船是否吃到月饼,根据月饼类型进行得分或结束游戏。
  • 循环运行游戏,不断更新画面。

这段代码还包含了一些事件处理函数,以及一些用于加载和显示分数的逻辑。此外,还包括一些用于在不同设备上设置触摸和鼠标事件的条件判断。

3.2 创建和管理图像资源

kotlin 复制代码
function Food(type, left, id){
  this.speedUpTime = 300;
  this.id = id;
  this.type = type;
  this.width = 50;
  this.height = 50;
  this.left = left;
  this.top = -50;
  this.speed = 0.04 * Math.pow(1.2, Math.floor(gameMonitor.time/this.speedUpTime));
  this.loop = 0;
​
  var p = this.type == 0 ? 'static/img/food1.png' : 'static/img/food2.png';
  this.pic = gameMonitor.im.createImage(p);
}
Food.prototype.paint = function(ctx){
  ctx.drawImage(this.pic, this.left, this.top, this.width, this.height);
}
Food.prototype.move = function(ctx){
  if(gameMonitor.time % this.speedUpTime == 0){
    this.speed *= 1.2;
  }
  this.top += ++this.loop * this.speed;
  if(this.top>gameMonitor.h){
    gameMonitor.foodList[this.id] = null;
  }
  else{
    this.paint(ctx);
  }
}

这段代码定义了一个名为 Food 的 JavaScript 构造函数和两个原型方法 paintmove,用于创建和管理游戏中的月饼对象。让我逐步解释这些代码:

  1. Food 构造函数:

    • 接受三个参数:type 表示月饼的类型(0 或 1),left 表示月饼的水平位置,id 表示月饼的唯一标识。

    • 设置了月饼对象的各种属性,包括:

      • speedUpTime:加速时间间隔,以毫秒为单位,用于控制月饼下落速度的加速。
      • id:月饼的唯一标识。
      • type:月饼的类型,通常用于区分不同种类的月饼。
      • widthheight:月饼的宽度和高度。
      • lefttop:月饼的初始位置,left 表示水平位置,top 表示垂直位置。
      • speed:月饼下落的速度,初始值基于时间的函数。
      • loop:一个计数器,用于控制月饼下落的速度。
    • 根据 type 的不同选择加载不同的月饼图片,将图片对象存储在 pic 属性中。

  2. Food.prototype.paint 方法:

    • 这是一个原型方法,用于在 Canvas 上绘制月饼图像。
    • 接受一个 ctx 参数,表示绘图上下文,通常是一个 Canvas 上下文对象。
    • 使用 ctx.drawImage 方法绘制月饼图像,以 pic 属性表示的图片为源图像,绘制到指定的位置 (this.left, this.top),并指定宽度和高度为 this.widththis.height
  3. Food.prototype.move 方法:

    • 这是另一个原型方法,用于更新月饼的位置,模拟月饼下落的动画效果。
    • 首先检查是否达到了加速时间间隔(speedUpTime)的整数倍,如果是,就将 speed 值乘以 1.2,以加速月饼的下落速度。
    • 更新 top 属性,使月饼沿垂直方向下落,速度由 speed 控制。
    • 如果月饼超出游戏界面底部(top 大于游戏界面的高度 gameMonitor.h),则将该月饼对象从游戏中移除(通过将 gameMonitor.foodList[this.id] 设置为 null),否则调用 paint 方法绘制月饼。

这些代码片段通常用于游戏开发中,用于创建并控制游戏中的物体行为,如月饼下落和绘制。这个构造函数和方法是一个月饼对象的蓝图,可以用于创建多个月饼实例,每个实例具有不同的属性和行为。

3.3 管理和加载图像资源

ini 复制代码
function ImageMonitor(){
  var imgArray = [];
  return {
    createImage : function(src){
      return typeof imgArray[src] != 'undefined' ? imgArray[src] : (imgArray[src] = new Image(), imgArray[src].src = src, imgArray[src])
    },
    loadImage : function(arr, callback){
      for(var i=0,l=arr.length; i<l; i++){
        var img = arr[i];
        imgArray[img] = new Image();
        imgArray[img].onload = function(){
          if(i==l-1 && typeof callback=='function'){
            callback();
          }
        }
        imgArray[img].src = img
      }
    }
  }
}

这段代码定义了一个名为 ImageMonitor 的对象,用于管理和加载图像资源。以下是代码的主要功能解释:

  1. ImageMonitor 对象是一个工具,用于加载和缓存图像资源,以提高游戏或应用程序中的性能和效率。

  2. imgArray 是一个空数组,用于存储已加载的图像,以便之后可以快速地重用它们,避免不必要的网络请求。

  3. createImage(src) 方法是 ImageMonitor 对象的一个属性,用于创建图像对象,并在 imgArray 中缓存它们。它接受一个图像的路径 src 作为参数。

    • 首先,它检查 imgArray 数组中是否已经存在具有相同路径 src 的图像。如果存在,它直接返回缓存的图像对象。
    • 如果图像不存在于缓存中,它创建一个新的 Image 对象,将指定路径 src 赋值给它,然后将新的图像对象存储在 imgArray[src] 中,并返回它。
  4. loadImage(arr, callback) 方法也是 ImageMonitor 对象的一个属性,用于预加载图像资源。它接受两个参数:

    • arr 是一个包含图像路径的数组,表示需要加载的图像资源。
    • callback 是一个回调函数,用于在所有图像加载完成后执行。
    • 方法通过遍历 arr 数组中的图像路径,为每个图像路径创建一个新的 Image 对象,并设置加载完成后的回调函数 imgArray[img].onload
    • 如果在遍历结束后(即所有图像都已加载)且提供了有效的 callback 函数时,执行该回调函数。

这个 ImageMonitor 对象的主要目的是优化图像资源的加载,以确保游戏或应用程序在运行时可以快速访问这些资源,而无需多次下载相同的图像。这对于提高性能和用户体验非常有用,特别是在需要大量图像资源的应用中,如游戏。

3.4 绘制月饼

这个 genorateFood 函数是一个用于在游戏中生成月饼的功能。生成月饼的频率由 genRate 控制,随机生成月饼的类型和位置,然后将月饼对象添加到一个数组中。

ini 复制代码
genorateFood : function(){
    var genRate = 50; //产生月饼的频率
    var random = Math.random();
    if(random*genRate>genRate-1){
      var left = Math.random()*(this.w - 50);
      var type = Math.floor(left)%2 == 0 ? 0 : 1;
      var id = this.foodList.length;
      var f = new Food(type, left, id);
      this.foodList.push(f);
    }
  },

四、环境部署

如果要部署到自己的网站,需要添加 Nginx 配置,做一个静态代理。

这是一个 Nginx 服务器的配置文件片段,用于配置一个虚拟主机,将域名 game.passjava.cn 映射到服务器上的指定目录。这个配置文件的关键部分:

  1. server 块:定义了一个服务器块,用于配置虚拟主机。这个服务器块监听端口 80,表示通过 HTTP 协议访问。

  2. listen 80;:指定服务器监听的端口号,这里是 80,表示通过 HTTP 默认端口访问。

  3. server_name game.passjava.cn;:指定了这个虚拟主机的域名为 game.passjava.cn。当用户访问这个域名时,Nginx 将使用这个服务器块来处理请求。

  4. location / 块:定义了一个请求匹配规则,对所有请求都生效。这是一个根目录位置块,它配置了如何处理位于根目录的请求。

    • root /home/ubuntu/jay/game/moon;:指定了服务器上的根目录路径,即请求的文件应该在哪个目录中查找。在这里,根目录路径是 /home/ubuntu/jay/game/moon
    • index index.html;:指定了默认的索引文件为 index.html。如果用户请求的是一个目录而不是具体的文件,Nginx 将尝试查找并返回该目录下的 index.html 文件。

这个配置文件的效果是将 game.passjava.cn 域名映射到 /home/ubuntu/jay/game/moon 目录,并默认返回 index.html 文件。这通常用于托管静态网站或 Web 应用程序。请确保 Nginx 正确配置,以便处理这个虚拟主机的请求。

然后再添加一个域名解析:

就可以在线访问了,快来试下吧~

game.passjava.cn

相关推荐
好多吃的啊25 分钟前
css 控制虚线刻度尺寸
前端·css
Pluto & Ethereal36 分钟前
uni-app生命周期
前端·uni-app
QGC二次开发1 小时前
Vue3:mitt实现组件通信
前端·javascript·vue.js·vue
Fightting882 小时前
Openpyxl 插入数据添加数据
前端·windows·python
only-lucky2 小时前
QT之QML从入门到精通(第三章)
前端·javascript·qt
anyup_前端梦工厂2 小时前
探秘 Web Bluetooth API:连接蓝牙设备的新利器
前端·javascript·html
anyup_前端梦工厂2 小时前
深入理解 JavaScript 三大作用域:全局作用域、函数作用域、块级作用域
前端·javascript·html
等你许久_孟然3 小时前
【webpack4系列】设计可维护的webpack4.x+vue构建配置(终极篇)
前端·javascript·vue.js
我的运维人生3 小时前
Nginx:高性能Web服务器与反向代理的深度解析
服务器·前端·nginx·运维开发·技术共享
小白小白从不日白4 小时前
react hooks--useMemo
前端·javascript·react.js