您的位置:首页 > 其它

场景转场动画的Canvas实现

2015-10-04 23:45 330 查看
废话不说,先上图



图1:转场前



图2:转场中(动画效果此处请看末尾链接)



图3:转场后

看完效果,我们来讲讲原理。

首先我们需要准备一张转场用的图。理论上所有图片都可以作为过渡图使用。

我使用的是一张带有天使翅膀图案的图片作为过渡图。

首先,将过渡图黑白化。

var pixs = context.getImageData(0, 0, context.canvas.width, context.canvas.height);
var data = pixs.data;
var len = data.length;
while(len -= 4){
var r = (data[len] + data[len + 1] + data[len + 2]) / 3;
data[len] = data[len + 1] = data[len + 2] = r;
}
context.putImageData(pixs, 0, 0);
(以上代码纯手写未测试,请注意)

在进行过渡之前,我们必须往屏幕上绘制一些内容,随便画什么都可以。

然后我们开始准备过渡了。

在过渡之前,我们需要定义一些变量。

// 用于保存旧的场景最后一帧
var oldSceneCanvas = document.createElement("canvas");

// 用于指示当前最多可用的不透明度值
var currentOffset = 255;

// 将过渡图绘制在后台canvas上,由于之前我们将它黑白化过,因此这里假定已经在canvas上
var transitionCanvas = ...;
完成上面的操作后,我们将当前可见画布中的内容绘制在 oldSceneCanvas 上。

然后假装正常的把新内容绘制在可见画布上。

之后我们将 oldSceneCanvas 的每个像素和 currentOffset进行比较,如果alpha通道大于currentOffset,则让其等于 currentOffset的值。

将oldSceneCanvas 最后绘制在可见画布上。

开启一个定时器,定时将currentOffset的值减小。动画效果就这么出现了……

最后放上我的实现代码,其中使用了几个其他的东东,你可以根据运行报错进行修改……

(function (window, document, Jyo, undefined) {

Jyo.Transition = function (renderer) {
/// <summary>转场动画</summary>
/// <param name="renderer" type="Jyo.Renderer">渲染器对象</param>

Jyo.Object.call(this);

this.renderer = renderer;

/*
设置过渡用画布
*/
var osCvs = document.createElement("canvas");
var tsCvs = document.createElement("canvas");

// 当前偏移量
this.currentOffset = 255;

// 是否正在执行
this.isRun = false;

// 是否允许更新
this.canUpdate = false;

/*
设置旧场景图画布
*/
this.oldScreenCanvas = new Jyo.Xnb();
this.oldScreenCanvas.object = osCvs;
this.oldScreenContext = osCvs.getContext("2d");
this.oldPixelData = null;

/*
设置过渡图画布
*/
this.transitionCanvas = tsCvs;
this.transitionContext = tsCvs.getContext("2d");

// 过渡Alpha数组
this.transitionAlphaArray = null;
};

Jyo.Transition.prototype = new Jyo.Object({
begin: function (img, time, delay) {
/// <summary>开始转场动画</summary>
/// <param name="img" type="Jyo.Xnb">图像Xnb对象</param>
/// <param name="time" type="Number">总时长(毫秒)</param>
/// <param name="delay" type="Number" optional="true">延迟时长(毫秒)</param>

var _this = this;
var renderer = this.renderer;
var osCvs = this.oldScreenCanvas.object;
var tsCvx = this.transitionCanvas;

this.oldPixelData = null;
this.transitionAlphaArray = null;

this.canUpdate = false;
this.currentOffset = 255;
this.isRun = true;
this.time = time;

// 设置画布大小
osCvs.width = tsCvx.width = renderer.width;
osCvs.height = tsCvx.height = renderer.height;

// 绘制预设图
this.oldScreenContext.drawImage(renderer.canvas, 0, 0);
this.transitionContext.drawImage(img, 0, 0, renderer.width, renderer.height);

/* 预先对过渡图进行灰度计算 */
var pix = this.transitionContext.getImageData(0, 0, renderer.width, renderer.height);
var iD = pix.data;
var i = iD.length;
while ((i -= 4) > 0) {
iD[i + 3] = iD[i] * 0.3 + iD[i + 1] * 0.59 + iD[i + 2] * 0.11;
}
_this.transitionAlphaArray = iD;

if (typeof delay != "undefined") {
setTimeout(function () {
_this.canUpdate = true;
}, delay);
} else {
_this.canUpdate = true;
}

setTimeout(function () {
_this.fireEvent("begin");
}, 0);
},
draw: function () {
/// <summary>绘制过渡动画</summary>

if (!this.isRun) return;

var renderer = this.renderer;

if (this.transitionAlphaArray) {
var osCtx = this.oldScreenContext;
var tArr = this.transitionAlphaArray;
var pix = this.oldPixelData;

if (!pix) {
this.oldPixelData = pix = osCtx.getImageData(0, 0, renderer.width, renderer.height);
}
var iD = pix.data;

var i = iD.length;
while ((i -= 4) > 0) {
if (tArr[i + 3] > this.currentOffset) {
iD[i + 3] = this.currentOffset;
}
}
osCtx.putImageData(pix, 0, 0);
}

renderer.drawImage(this.oldScreenCanvas, 0, 0);
},
update: function (currentTime) {
/// <summary>更新过渡动画</summary>
/// <param name="currentTime" type="Number">当前时间</param>

if (!this.isRun || !this.canUpdate) return;
if (!this.beginTime) {
this.beginTime = currentTime;
return;
}

var timeSpan = currentTime - this.beginTime;
if (timeSpan < this.time) {
this.currentOffset = 255 - (timeSpan / this.time * 255) | 0;
} else {
delete this.beginTime;
this.canUpdate = false;
this.isRun = false;

this.fireEvent("end");
}
}
});

})(window, document, Jyo);

演示地址:https://math3d.xyz/Avg/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: