参考效果:
参考资料:
PixiJS官方手册
PixiJS教程通俗易懂(日语)
PixiJS教程通俗易懂(翻译)
实战教程(带demo)
TweenMax官方手册
(使用TwwenJS代替TweenMax也行)
PixiJS & TweenMax 的CDN
<script src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/4.5.1/pixi.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/2.0.1/TweenMax.min.js"> </script>
- 基本的实现步骤
//1 、 以可视区域大小创建渲染器
var renderer = PIXI.autoDetectRenderer(window.innerWidth,window.innerHeight);
//2 、 将舞台添加到,页面中
document.body.appendChild(renderer.view);
//3 、 创建元素容器,类似 ‘组’概念,Container可以嵌套Container
var stageBox = new PIXI.Container();
/*
4 、
使用加载器预加载图片。& 监听加载成功事件 ‘progress’ 多次触发 ,target.progress 返回加载成功百分比
加载完成 触发load 里面的 setup函数 。
*/
PIXI.loader.add([
'./img/test1.png'
]).on("progress", function(target, resource){
console.log(~~target.progress);
}).load(setup);
function setup(){
var test1= new PIXI.Sprite(//普通精灵
PIXI.loader.resources["./img/test1.png"].texture
);
animate();
}
//以每秒60fps渲染
function animate(){
renderer.render(stageBox);
requestAnimationFrame(animate);
}
模仿【一部40年的生活演变史】
- 其中js部分有很多可以封装的地方,自己没有做封装
- 只做了部分效果(后半部分大同小异)
- 设计稿在这里,bg1.psd
- 对应设计稿还原场景
//根据设计稿 还原场景
spriteBox.bg1.position.set(0,0);
spriteBox.bg2.position.set(0,3000);
spriteBox.bg3.position.set(0,3000*2);
spriteBox.bg4.position.set(0,3000*3);
spriteBox.bg5.position.set(0,3000*4);
spriteBox.bd.position.set(270,967);
...
- 设置场景中需要动画的元素
//设置动画
tm.to(stageBox,10,{y:-(stageBox.height-window.innerHeight),ease:Bounce.Linear},0);
tm.to(spriteBox.bd,0.3,{y:spriteBox.bd.y+50,ease:Bounce.Linear},0.05);
tm.to(spriteBox.text1.scale,0.15,{x:1,y:1,ease:Bounce.Linear},0.00);
...
- 里面有很多地方用到了帧动画,使用pixijs 的 AnimatedSprite(动画精灵)实现
var cj_arr = [];
for(let i=1;i<5;i++){
cj_arr.push('./images/cj'+i+'.png')
}
spriteBox.cj = new PIXI.extras.AnimatedSprite.fromImages(cj_arr);
spriteBox.cj.animationSpeed = -0.08;
spriteBox.cj.play();
-
其中用到了俩个时间轴,因为整体动画中存在循环播放的动画(按钮放大缩小效果)。一个时间轴控制播放到不同时间播放不同的动画,另一个时间轴控制循环动画(按钮缩放动画)
var tm = new TimelineLite({paused:true});
var tm2 = new TimelineLite();
- range() 函数判断 在不同时间 播放不同的背景声音以及帧动画的跳转暂停。
document.querySelector('#music0').play();
spriteBox.bd.gotoAndStop(timeline/60);
- 场景滑动缓动事件,以及缓动效果。
document.addEventListener('touchstart',function(e){
clearInterval(setTime);
touchstart = true;
touchstartY = e.changedTouches[0].clientY;
});
document.addEventListener('touchmove',function(e){
if(!touchstart){return;}
var touchmoveY = e.changedTouches[0].clientY;
steptime = -(touchmoveY-touchstartY)/1000;
var time = timeline+=steptime;
if(time < 0) timeline = 0;
if(time >= 10) timeline = 10;//这里的10是外层总容器(stageBox)的动画时长
range();
tm.seek(timeline);//跳转到对应时间
renderer.render(stageBox);//渲染场景
touchstartY = touchmoveY;
})
document.addEventListener('touchend',function(){
touchstart = false;
setTime = setInterval(() => {
steptime*=0.95;
if(Math.abs(steptime)<1/1000){
clearInterval(setTime)
}
var time = timeline+=steptime;
if(time < 0) timeline = 0;
if(time >= 10) timeline = 10;
range();
tm.seek(timeline);
renderer.render(stageBox);
},10);
})
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/4.5.1/pixi.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/2.0.1/TweenMax.min.js"> </script>
<style>
*{
padding: 0;
margin: 0;
}
html,body{width: 100%;height: 100%;overflow: hidden;}
</style>
</head>
<body>
<audio hidden="" id="music0" src="media/0.mp3" loop></audio>
<audio hidden="" id="music1" src="media/wd.mp3" loop></audio>
<audio hidden="" id="music2" src="media/1.mp3" loop></audio>
<script>
var type = "WebGL";
if(!PIXI.utils.isWebGLSupported()){
type = "canvas"
}
PIXI.utils.sayHello(type);
var renderer = PIXI.autoDetectRenderer(window.innerWidth,window.innerHeight);
document.body.appendChild(renderer.view);
var draftWidth = 640,draftHeight = 14949;
var stageBox = new PIXI.Container();
var tm = new TimelineLite({paused:true});
var tm2 = new TimelineLite();
var spriteBox = {};
PIXI.loader.add([
'./images/bg1.jpg',
'./images/bg2.jpg',
'./images/bg3.jpg',
'./images/bg4.jpg',
'./images/bg5.jpg',
'./images/bd1.png',
'./images/bd2.png',
'./images/cj1.png',
'./images/cj2.png',
'./images/cj3.png',
'./images/cj4.png',
'./images/lb1.png',
'./images/lb2.png',
'./images/lb3.png',
'./images/lb4.png',
'./images/text1.png',
'./images/text4.png',
'./images/tz.png',
'./images/rgm1.png',
'./images/rgm2.png',
'./images/rgm3.png',
'./images/rgm4.png',
'./images/rgm5.png',
'./images/pz.png',
'./images/btn.png',
'./images/tw1.png',
'./images/tw2.png',
'./images/tw3.png',
'./images/tw4.png',
'./images/tw5.png',
]).on("progress", function(target, resource){
console.log(~~target.progress);
}).load(setup);
function setup(){
spriteBox.bg1 = new PIXI.Sprite(PIXI.loader.resources['./images/bg1.jpg'].texture);
spriteBox.bg2 = new PIXI.Sprite(PIXI.loader.resources['./images/bg2.jpg'].texture);
spriteBox.bg3 = new PIXI.Sprite(PIXI.loader.resources['./images/bg3.jpg'].texture);
spriteBox.bg4 = new PIXI.Sprite(PIXI.loader.resources['./images/bg4.jpg'].texture);
spriteBox.bg5 = new PIXI.Sprite(PIXI.loader.resources['./images/bg5.jpg'].texture);
var bd_arr = [];
for(let i=1;i<3;i++){
bd_arr.push('./images/bd'+i+'.png')
}
spriteBox.bd = new PIXI.extras.AnimatedSprite.fromImages(bd_arr);
spriteBox.bd.animationSpeed = -0.05;//序列帧放映速度
spriteBox.text1 = new PIXI.Sprite(PIXI.loader.resources['./images/text1.png'].texture);
var cj_arr = [];
for(let i=1;i<5;i++){
cj_arr.push('./images/cj'+i+'.png')
}
spriteBox.cj = new PIXI.extras.AnimatedSprite.fromImages(cj_arr);
spriteBox.cj.animationSpeed = -0.08;
spriteBox.cj.play();
var lb_arr = [];
for(let i=1;i<5;i++){
lb_arr.push('./images/lb'+i+'.png')
}
spriteBox.lb = new PIXI.extras.AnimatedSprite.fromImages(lb_arr);
spriteBox.lb.animationSpeed = -0.08;
spriteBox.lb.play();
spriteBox.text4 = new PIXI.Sprite(PIXI.loader.resources['./images/text4.png'].texture);
var rgm_arr = [];
for(let i=1;i<=5;i++){
rgm_arr.push('./images/rgm'+i+'.png')
}
spriteBox.rgm = new PIXI.extras.AnimatedSprite.fromImages(rgm_arr);
spriteBox.rgm.animationSpeed = -0.065;
spriteBox.rgm.play();
spriteBox.tz = new PIXI.Sprite(PIXI.loader.resources['./images/tz.png'].texture);
spriteBox.pz = new PIXI.Sprite(PIXI.loader.resources['./images/pz.png'].texture);
var tw_arr = [];
for(let i=1;i<=5;i++){
tw_arr.push('./images/tw'+i+'.png')
}
spriteBox.tw = new PIXI.extras.AnimatedSprite.fromImages(tw_arr);
spriteBox.tw.animationSpeed = -0.05;
spriteBox.tw.play();
spriteBox.btn1 = new PIXI.Sprite(PIXI.loader.resources['./images/btn.png'].texture);
spriteBox.btn1.on('tap',function(){//绑定事件
console.log('点击');
})
//根据设计稿 还原场景
spriteBox.bg1.position.set(0,0);
spriteBox.bg2.position.set(0,3000);
spriteBox.bg3.position.set(0,3000*2);
spriteBox.bg4.position.set(0,3000*3);
spriteBox.bg5.position.set(0,3000*4);
spriteBox.bd.position.set(270,967);
spriteBox.text1.position.set(332,993);
spriteBox.text1.anchor.x = 0;
spriteBox.text1.anchor.y = 1;
spriteBox.text1.scale.set(0);
spriteBox.lb.position.set(462,1522);
spriteBox.cj.position.set(522,1530);
spriteBox.text4.position.set(489,1524);
spriteBox.text4.anchor.x = 1;
spriteBox.text4.anchor.y = 1;
spriteBox.text4.scale.set(0);
spriteBox.rgm.position.set(438,2242);
spriteBox.tz.position.set(419,2253);
spriteBox.pz.position.set(0,2634);
spriteBox.tw.position.set(430,2808);
spriteBox.btn1.position.set(580,2766);
spriteBox.btn1.scale.set(1);
spriteBox.btn1.anchor.set(0.5,0.5);
spriteBox.btn1.buttonMode = true;//按钮模式
spriteBox.btn1.interactive = true;//启用事件
for(let key in spriteBox){
stageBox.addChild(spriteBox[key]);//精灵 添加进 容器
}
stageBox.scale.set(window.innerWidth/draftWidth);//容器根据设计稿 计算缩放
//设置动画
tm.to(stageBox,10,{y:-(stageBox.height-window.innerHeight),ease:Bounce.Linear},0);
tm.to(spriteBox.bd,0.3,{y:spriteBox.bd.y+50,ease:Bounce.Linear},0.05);
tm.to(spriteBox.text1.scale,0.15,{x:1,y:1,ease:Bounce.Linear},0.00);
tm.to(spriteBox.text4.scale,0.15,{x:1,y:1,ease:Bounce.Linear},0.1);
tm2.to(spriteBox.btn1.scale,1,{x:1.3,y:1.3,ease:Bounce.Linear,yoyo:true,repeat:-1},0);
tm2.play();
animate();
}
var touchstart = false,
steptime=0,
touchstartY = 0;
timeline = 0
setTime=null;
document.addEventListener('touchstart',function(e){
clearInterval(setTime);
touchstart = true;
touchstartY = e.changedTouches[0].clientY;
});
document.addEventListener('touchmove',function(e){
if(!touchstart){return;}
var touchmoveY = e.changedTouches[0].clientY;
steptime = -(touchmoveY-touchstartY)/1000;
var time = timeline+=steptime;
if(time < 0) timeline = 0;
if(time >= 10) timeline = 10;//这里的10是外层总容器(stageBox)的动画时长
range();
tm.seek(timeline);//跳转到对应时间
renderer.render(stageBox);//渲染场景
touchstartY = touchmoveY;
})
document.addEventListener('touchend',function(){
touchstart = false;
setTime = setInterval(() => {
steptime*=0.95;
if(Math.abs(steptime)<1/1000){
clearInterval(setTime)
}
var time = timeline+=steptime;
if(time < 0) timeline = 0;
if(time >= 10) timeline = 10;
range();
tm.seek(timeline);
renderer.render(stageBox);
},10);
})
function range(){
if(timeline >0.001 && timeline <= 0.313){
document.querySelector('#music0').play();
spriteBox.bd.gotoAndStop(timeline*14);
}else{
document.querySelector('#music0').pause();
document.querySelector('#music0').currentTime=0;
}
if(timeline>0.413 && timeline<=0.670){
document.querySelector('#music1').play();
}else{
document.querySelector('#music1').pause();
document.querySelector('#music1').currentTime=0;
}
if(timeline>0.670 && timeline<=1.301){
document.querySelector('#music2').play();
}else{
document.querySelector('#music2').pause();
document.querySelector('#music2').currentTime=0;
}
}
function animate(){
renderer.render(stageBox);
requestAnimationFrame(animate);
}
</script>
</body>
</html>