# 关键点
- 1 定义怪物属性:坐标
{x,y}
及速度{vx,vy}
,每个都是一个对象,存于数组中 - 2 canvas绘制
- 3 requestAnimationFrame 重复绘制每帧画面
- 4 边界检测,反向运动
- 5 点击检测
- 6 显示对话,长大动画
- 7 关卡入场动画
- 8 游戏数据的维护和绘制
# 拆解
为了更好的理解1-4,做了个简化的demo如下
//喷射点坐标
sx = w / 2;
sy = h / 2;
//放置圆点对象的数组
var circles = [];
//初始速度
var vel = 10;
//创建新的圆点并加入数组
function createCircle() {
circles.push({
x: sx,
y: sy,
v: {
x: vel * Math.random(),
y: vel * Math.random()
}
});
}
//清除画布内容
function clear() {
$.fillStyle = 'black';
$.fillRect(0,0,w,h);
}
//画圆点
function drawCircle() {
clear();
for (var i in circles) {
if (circles[i].x < 5 || w - circles[i].x < 5) {
circles[i].v.x *= -1;
circles[i].v.y -= 1;
}
if (circles[i].y < 5 || h - circles[i].y < 5) {
circles[i].v.y *= -1;
circles[i].v.x -= 1;
}
circles[i].x += circles[i].v.x;
circles[i].y += circles[i].v.y;
$.fillStyle = 'red';
$.beginPath();
$.arc(circles[i].x, circles[i].y, 20, 0, Math.PI * 2, true);
$.closePath();
$.fill();
}
}
//设置动画的回调函数,使动画持续播放
function updateCanvas() {
requestAnimationFrame(updateCanvas),
drawCircle();
}
window.addEventListener('mousedown',createCircle);
//页面载入后自行产生一个圆点
createCircle();
//触发循环回调,动画即可持续进行
updateCanvas();
# 5点击检测
//点击检测
can.addEventListener('mousedown',pickHandle)
function pickHandle(ev){
//console.log(ev.clientX,ev.clientY)
!data.gameOver && pool.forEach(function(e,i){
var rules = ev.clientX - e.x < spriteSize
&& ev.clientX - e.x >0 && ev.clientY - e.y >0 && ev.clientY - e.y < spriteSize;
if(rules && e.silent== undefined){
e.showDialogue = true;//显示对话
}
if(rules && e.silent==true){
//alert('被你找到了')
e.v.x = 0;
e.v.y = 0;
e.toSize = 80;
nextPassTimeOut = setTimeout(function(){
gameReset();//下一关
},500)
}
})
}
其中pool是怪物的数组池,检测方法是根据坐标判断,通过鼠标坐标和数组池坐标匹配。
如上rules成立的前提是绘制怪物以xy为左上角为原点绘制,0 < 点击位置-怪物位置 < 怪物尺寸
# 6显示对话,长大动画
这两个功能需要在绘制时处理。
function draw(){
//运动
for(var i in pool){
if(pool[i].x < 5 || WIDTH - pool[i].x < 5){
pool[i].v.x *= -1;
};
if(pool[i].y < 5 || HEIGHT - pool[i].y < 5){
pool[i].v.y *= -1;
};
pool[i].x += pool[i].v.x;
pool[i].y += pool[i].v.y;
//增长动画
if(pool[i].toSize){
if( pool[i].growingSize == pool[i].toSize){
pool[i].growingSize = pool[i].toSize;
}else{
pool[i].growingSize+=1;
}
ctx.drawImage(img, pool[i].x, pool[i].y, pool[i].growingSize, pool[i].growingSize);
}else{
ctx.drawImage(img, pool[i].x, pool[i].y, spriteSize, spriteSize);
}
//显示会话
if(pool[i].showDialogue){
ctx.save();
ctx.font = '14px Verdana';
ctx.fillText(pool[i].dialogue, pool[i].x, pool[i].y);
ctx.restore();
//dialogueTime时间后,对话消失
pool[i].dialogueTime<=0 ? pool[i].showDialogue = false : pool[i].dialogueTime-= deltaTime;
}
}
}
# 7关卡入场动画
//开场拉开帷幕动画
var Curtain = function(){
this.width = WIDTH;
this.height = HEIGHT;
this.alpha = 1;
}
Curtain.prototype.play = function(){
if(this.width>0 || this.alpha > 0){
this.width < 0 ? 0 : this.width -=15;
this.alpha < 0.1 ? 0 : this.alpha -=0.002;
ctx.save();
ctx.fillStyle = 'rgba(0,0,0,'+ this.alpha+')';
ctx.fillRect(0, 0, this.width, this.height);
ctx.restore();
}
}
function loop(){
curtain = new Curtain();
curtain.play();
}
# 8游戏数据的维护和绘制 同理
← m选n组合算法 数学集合方式实现sku →