玩法规则:
- 用手指按住飞行的兔子进行左右移动。
- 碰到五仁的月饼则游戏结束。
你好,我是悟空。
一、背景
中秋节快到了,想做一个关于中秋的小游戏,然后将小游戏发布到公网上,这样大家就都可以玩了,独乐了不如众乐乐,说干就干。
体验地址: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元素来创建游戏画布和动画。游戏的主要功能包括玩家控制一个飞船抢月饼,吃到不同类型的月饼得分,并且在一定条件下游戏结束。以下是对代码的主要部分进行的解释:
function Ship(ctx)
:这是一个构造函数,用于创建飞船对象。它接受一个上下文对象ctx
作为参数,用于绘制飞船。function Food(type, left, id)
:这是另一个构造函数,用于创建月饼对象。它接受三个参数:type
表示月饼的类型(0 或 1),left
表示月饼的水平位置,id
表示月饼的唯一标识。function ImageMonitor()
:这是一个用于管理图片加载的对象,包括创建和预加载图片。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 构造函数和两个原型方法 paint
和 move
,用于创建和管理游戏中的月饼对象。让我逐步解释这些代码:
-
Food
构造函数:-
接受三个参数:
type
表示月饼的类型(0 或 1),left
表示月饼的水平位置,id
表示月饼的唯一标识。 -
设置了月饼对象的各种属性,包括:
speedUpTime
:加速时间间隔,以毫秒为单位,用于控制月饼下落速度的加速。id
:月饼的唯一标识。type
:月饼的类型,通常用于区分不同种类的月饼。width
和height
:月饼的宽度和高度。left
和top
:月饼的初始位置,left
表示水平位置,top
表示垂直位置。speed
:月饼下落的速度,初始值基于时间的函数。loop
:一个计数器,用于控制月饼下落的速度。
-
根据
type
的不同选择加载不同的月饼图片,将图片对象存储在pic
属性中。
-
-
Food.prototype.paint
方法:- 这是一个原型方法,用于在 Canvas 上绘制月饼图像。
- 接受一个
ctx
参数,表示绘图上下文,通常是一个 Canvas 上下文对象。 - 使用
ctx.drawImage
方法绘制月饼图像,以pic
属性表示的图片为源图像,绘制到指定的位置(this.left, this.top)
,并指定宽度和高度为this.width
和this.height
。
-
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
的对象,用于管理和加载图像资源。以下是代码的主要功能解释:
-
ImageMonitor
对象是一个工具,用于加载和缓存图像资源,以提高游戏或应用程序中的性能和效率。 -
imgArray
是一个空数组,用于存储已加载的图像,以便之后可以快速地重用它们,避免不必要的网络请求。 -
createImage(src)
方法是ImageMonitor
对象的一个属性,用于创建图像对象,并在imgArray
中缓存它们。它接受一个图像的路径src
作为参数。- 首先,它检查
imgArray
数组中是否已经存在具有相同路径src
的图像。如果存在,它直接返回缓存的图像对象。 - 如果图像不存在于缓存中,它创建一个新的
Image
对象,将指定路径src
赋值给它,然后将新的图像对象存储在imgArray[src]
中,并返回它。
- 首先,它检查
-
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
映射到服务器上的指定目录。这个配置文件的关键部分:
-
server
块:定义了一个服务器块,用于配置虚拟主机。这个服务器块监听端口 80,表示通过 HTTP 协议访问。 -
listen 80;
:指定服务器监听的端口号,这里是 80,表示通过 HTTP 默认端口访问。 -
server_name game.passjava.cn;
:指定了这个虚拟主机的域名为game.passjava.cn
。当用户访问这个域名时,Nginx 将使用这个服务器块来处理请求。 -
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 正确配置,以便处理这个虚拟主机的请求。
然后再添加一个域名解析:
就可以在线访问了,快来试下吧~