1. 用户交互
用户交互,指的是用户可以借助鼠标或键盘参与到Canvas动画中去,来实现一些互动的效果。这节主要基于鼠标事件来实现一些用户交互功能。
1.1 捕获物体
1.1.1 矩形的捕获
可以通过获取鼠标点击时的坐标来判断是否捕获了矩形。如果鼠标点击坐标落在矩形上,则说明捕获了这个矩形;如果鼠标点击坐标没有落在矩形上,则说明没有捕获到这个矩形。
语法:
代码语言:javascript复制if(mouse.x > rect.x &&
mouse.x < rect.x rect.width &&
mouse.y > rect.y &&
mouse.y < rect.y rect.height
){
//...
}
1.1.2 圆的捕获
在Canvas中,对于圆来说,可以根据鼠标与圆心之间的距离来判断圆的捕获。如果距离小于圆的半径,说明鼠标落在了圆上面;如果距离大于等于圆的半径,说明鼠标落在了圆外面。
语法:
代码语言:javascript复制dx = mouse.x - ball.x;
dy = mouse.y - ball.y;
distance = Math.sqrt(dx * dx dy * dy);
if(distance < ball.radius){
//...
}
1.2 拖拽物体
在Canvas中,如果想要拖拽一个物体,一般情况下需要三个步骤:
1)捕获物体:在鼠标按下(mousedown)时,判断鼠标坐标是否落在物体上面,如果落在,就添加两个事件(mousemove和mouseup);
2)移动物体:在鼠标移动(mousemove)中,更新物体坐标为鼠标坐标;
3)松开物体:在鼠标松开(mouseup)时,移除mouseup事件和mousemove事件。
语法:
代码语言:javascript复制cnv.addEventListener('mousedown', () => {
document.addEventListener('mousemove', onMouseMove);
document.addEventListener('mouseup', onMouseUp);
})
1.3 抛掷物体
在拖拽物体时,它会在每一帧中拥有一个新的位置,用“新的位置坐标”减去“旧的位置坐标”就得到每一帧中物体的移动速度。
以小球来说,我们用oldX和oldY分别表示小球旧的位置坐标,新的位置坐标是ball.x和ball.y,可以得到:
代码语言:javascript复制vx = ball.x - oldX;
vy = ball.y - oldY;
示例:抛掷小球
代码语言:javascript复制//tools.js
Ball.prototype = {
...
checkMouse(mouse){
let dx = mouse.x - this.x;
let dy = mouse.y - this.y;
let distance = Math.sqrt(dx * dx dy * dy);
return distance < this.radius ? true : false;
}
}
代码语言:javascript复制//my-canvas.js
methods: {
...
// 捕获/拖拽/抛掷小球
captureBall(cxt, cnv){
//鼠标是否按下
let isMouseDown = false;
//偏移量
let dx = 0, dy = 0;
//重力和反弹消耗
let gravity = 0.5, bounce = -0.5;
//鼠标位置,小球旧的坐标
let mouse, oldX, oldY;
//生成-3~3的随机速度
let vx = (Math.random() * 2 - 1) * 3;
let vy = (Math.random() * 2 - 1) * 3;
let ball = new Ball(0, 0, 20);
(function drawFrame(){
requestAnimationFrame(drawFrame);
cxt.clearRect(0, 0, cnv.width, cnv.height);
if(isMouseDown){
vx = ball.x - oldX;
vy = ball.y - oldY;
oldX = ball.x;
oldY = ball.y;
}else {
vy = gravity;
ball.x = vx;
ball.y = vy;
}
//边界反弹
if(ball.x < ball.radius){
ball.x = ball.radius;
vx = vx * bounce;
}else if(ball.x > cnv.width - ball.radius){
ball.x = cnv.width - ball.radius;
vx = vx * bounce;
}
if(ball.y < ball.radius){
ball.y = ball.radius;
vy = vy * bounce;
}else if(ball.y > cnv.height - ball.radius){
ball.y = cnv.height - ball.radius;
vy = vy * bounce;
}
ball.draw(cxt, 'fill');
})();
//获取鼠标位置
tools.listenMousePosition(cnv, obj => {
mouse = obj;
});
function onMouseMove(){
ball.x = mouse.x - dx;
ball.y = mouse.y - dy;
}
function onMouseUp(){
isMouseDown = false;
document.removeEventListener('mouseup', onMouseUp);
document.removeEventListener('mousemove', onMouseMove);
}
cnv.addEventListener('mousedown', () => {
if(ball.checkMouse(mouse)){
isMouseDown = true;
oldX = ball.x;
oldY = ball.y;
dx = mouse.x - ball.x;
dy = mouse.y - ball.y;
document.addEventListener('mousemove', onMouseMove);
document.addEventListener('mouseup', onMouseUp);
}
})
},
}
示例效果:
2. 高级动画
2.1 缓动动画
缓动动画,指的是带有一定缓冲效果的动画,在动画过程中,物体在某一段时间会“渐进加速”或“渐进减速”,从而让物体运动看起来更为自然而逼真。
在Canvas中,实现缓动动画,一般需要五个步骤:
1)定义一个0~1之间的缓动系数easing;
2)计算出物体与终点之间的距离;
3)计算出当前速度,其中当前速度 = 距离 * 缓动系数;
4)计算新的位置,其中新的位置 = 当前位置 当前速度;
5)重复执行2~4步,直到物体达到目标。
语法:
代码语言:javascript复制//targetX、targetY:表示目标的横坐标和纵坐标
//easing:表示缓动系数
//vx、vy:表示物体在x轴方向和y轴方向上的速度
let targetX = 任意位置;
let targetY = 任意位置;
//动画循环
let vx = (targetX - object.x) * easing;
let vy = (targetY - object.y) * easing;
示例:缓动的小球
代码语言:javascript复制//my-canvas.js
methods: {
...
//缓动动画
slowActionAnimation(cxt, cnv){
let ball = new Ball(0, 0);
let targetX = cnv.width * 3 / 4;
let targetY = cnv.width / 2;
let easing = 0.05;
(function frame() {
requestAnimationFrame(frame);
cxt.clearRect(0, 0, cnv.width, cnv.height);
let vx = (targetX - ball.x) * easing;
let vy = (targetY - ball.y) * easing;
ball.x = vx;
ball.y = vy;
ball.draw(cxt, 'fill');
})()
}
}
示例效果:
在Canvas中,缓动动画不仅可以用于物体的运动,还可以应用于物体的其他各种属性,包括大小、颜色、透明度以及旋转等。
不管缓动动画应用于哪些方面,其实现思路是一样的,主要是以下两个步骤:
1)当前速度 = (最终值 - 当前值)* 缓动系数;
2)新的值 = 当前值 当前速度。
2.2 弹性动画
在缓动动画中,物体滑动到终点就停下来了,在弹性动画中,物体滑动到终点后还会来回反弹一会,直至停止。
从技术上来说,缓动动画和弹性动画有以下几个共同点:
1)需要设置一个终点;
2)需要确定物体到终点的距离;
3)运动和距离是成正比的。
两者的不同在于“运动和距离是成正比的”这一点的实现方式不一样:
1)在缓动动画中,跟距离成正比的是“速度”;
2)在弹性动画中,跟距离成正比的是“加速度”。
语法:
代码语言:javascript复制let targetX = 任意位置;
let targetY = 任意位置;
let ax = (targetX - object.x) * spring;
let ay = (targetY - object.y) * spring;
let vx = ax;
let vy = ay;
vx *= friction;
vy *= friction;
object.x = vx;
object.y = vy;
示例:绳球运动
代码语言:javascript复制//my-canvas.vue
methods: {
//绳球运动
ropeBallMove(cxt, cnv){
let mouse;
let vx = 0, vy = 0;
let spring = 0.02, friction = 0.95;
let bounce = -0.5, gravity = 1;
let ball = new Ball(cnv.width / 2, cnv.height / 2);
tools.listenMousePosition(cnv, val => {
mouse = val;
});
(function frame(){
requestAnimationFrame(frame);
cxt.clearRect(0, 0, cnv.width, cnv.height);
if(mouse){
let ax = (mouse.x - ball.x) * spring;
let ay = (mouse.y - ball.y) * spring;
vx = ax;
vy = ay;
}
vy = gravity;
vx *= friction;
vy *= friction;
ball.x = vx;
ball.y = vy;
//边界反弹
if(ball.x < ball.radius){
ball.x = ball.radius;
vx = vx * bounce;
}else if(ball.x > cnv.width - ball.radius){
ball.x = cnv.width - ball.radius;
vx = vx * bounce;
}
if(ball.y < ball.radius){
ball.y = ball.radius;
vy = vy * bounce;
}else if(ball.y > cnv.height - ball.radius){
ball.y = cnv.height - ball.radius;
vy = vy * bounce;
}
ball.draw(cxt, 'fill');
if(mouse){
cxt.beginPath();
cxt.moveTo(ball.x, ball.y);
cxt.lineTo(mouse.x, mouse.y);
cxt.stroke();
}
})()
},
}
示例效果:
3. 游戏开发
3.1 Box2D
Box2D是暴雪工程师Erin catto使用C 编写的一个非常优秀的物理引擎,在Box2D这个物理引擎里,可以模拟真实世界的运动情况,其中物体的运动、旋转和碰撞反应等都会遵循牛顿运动三大定律。
Box2D最初是C 编写的,由于它开发非常方便,极大提高了游戏开发效率,因此后来又衍生出了Flash、Java、Object-C和JavaScript等多种语言版本。
在Box2D中,集成了大量的物理力学和运动学的计算,我们只需要调用Box2D引擎中相应的对象或函数,就可以模拟现实生活中的匀速、减速、摩擦力、碰撞反弹等各种真实的物理运动。
JavaScript版本的Box2D有两个,一个是BoxDJS(已停止更新),另一个是Box2DWeb。如果我们想要使用Box2DWeb,只需要引入Box2D.js或Box2D.min.js就可以使用了。
3.2 HTML5游戏引擎
游戏引擎,就是可以为开发者提供编写游戏所需的各种工具,能够让我们非常容易和快速地开发一款游戏,而不需要从零开始。
3.2.1 Cocos2d-JS
Cocos2d-JS是Cocos2d-x的JavaScript版本,真正跨全平台的游戏引擎,采用原生JavaScript语言,可以发布到包括Web平台、iOS、Android、Windows Phone8、Mac、Windows等平台。
Cocos2d-JS具有易于使用、高效、灵活、免费、社区支持等特点。
3.2.2 Egret
Egret是国内一个非常流行的基于TypeScript语言开发的HTML5游戏引擎,遵循HTML5标准的2D、3D引擎,解决了HTML5性能问题及碎片化问题,灵活地满足开发者开发2D或3D游戏的需求,并有着极强的跨平台运行能力。
3.2.3 LayaAir
LayaAir相对前两者而言,性能最佳,号称“H5游戏引擎性能之王”。LayaAir裸跑性能堪比APP,支持2D、3D、VR开发,支持多语言开发,包括JavaScript、ActionScript、TypeScript,它的工具链成熟丰富,应用领域广泛。
3.2.4 Lufylegend
Lufylegend是国内一位资深游戏开发工程师个人独立开发的一个HTML5开源框架,不需要很多复杂的配置,直接引用js文件即可使用。