实现效果
先说下我们想要实现的效果,一开始图中的粒子在左后方移动,感觉就像是在骑单车时路面的效果。然后我们按住刹车的时候,图中的粒子停止,会有一个回弹的效果。
前置知识点
PIXI 的基本使用
- 创建应用
// 创建一个PIXI应用
this.app = new PIXI.Application(params)
// 插入到 DOM
document.querySelector(selector).appendChild(this.app.view)
- 资源加载
/ 创建一个Loader用来加载资源
this.loader = new PIXI.Loader()
// 添加资源
this.loader.add('btn.png',"images/btn.png");
// 加载资源
this.loader.load()
// 监听加载完成
this.loader.onComplete.add(()=>{
console.log('complete');
})
- 将资源添加到场景中
// 通过Sprite生成一个可渲染对象
let btnImage = new PIXI.Sprite(this.loader.resources["btn.png"].texture);
// 把渲染后的图片添加到场景中
this.app.stage.addChild(btnImage)
- 创建容器
// 创建一个容器,可以统一调整容器内的元素
let actionButton = new PIXI.Container()
// 对容器内的元素进行缩放
actionButton.scale.x = actionButton.scale.y = .6
// 往容器添加元素
let btnImage = new PIXI.Sprite(this.loader.resources["btn.png"].texture);
let btnCircle = new PIXI.Sprite(this.loader.resources["btn_circle.png"].texture);
actionButton.addChild(btnImage)
actionButton.addChild(btnCircle)
代码实现
1.代码初始化
index.html
<html>
<head>
<title>猿创营</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,minimum-scale=1.0,user-scalable=no">
<style type="text/css">
html,
body {
margin: 0;
padding: 0;
}
div {
width: 100%;
}
</style>
<script src="https://pixijs.download/release/pixi.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.10.4/gsap.min.js"></script>
<script src="./js/brakebanner.js"></script>
<script>
window.onload = init;
function init() {
let banner = new BrakeBanner("#brakebanner");
}
</script>
</head>
<body>
<div id="brakebanner"></div>
</body>
</html>
brakebanner.js
class BrakeBanner{
constructor(selector){
this.app = new PIXI.Application({
width:window.innerWidth,
height:window.innerHeight,
backgroundColor:0x000000,
resizeTo:window // 跟随窗口调整
})
document.querySelector(selector).appendChild(this.app.view)
this.loader = new PIXI.Loader()
this.stage = this.app.stage
// 添加资源
this.loader.add('btn.png',"images/btn.png");
this.loader.add('btn_circle.png',"images/btn_circle.png");
this.loader.add('brake_bike.png',"images/brake_bike.png");
this.loader.add('brake_handlerbar.png',"images/brake_handlerbar.png");
this.loader.add('brake_lever.png',"images/brake_lever.png");
this.loader.add('line.jpg',"images/line.jpg");
// 加载资源
this.loader.load()
// 添加监听器
this.loader.onComplete.add(()=>{
console.log('complete');
this.show()
})
}
show(){}
}
2.创建动效按钮
我们先来看下要实现的效果
思路:整个按钮的动效由三部分组成,一个按钮图片和两个圆圈图片,一个圆圈在做放大隐藏的动效。所以,可以把这三个图片加入到一个容器中,然后通过pivot调整它们的圆心位置,最后通过gsap对圆圈添加放大隐藏的动效。
代码如下:
show(){
const actionButton = this.createActionButton()
// 调整按钮的位置
actionButton.x = actionButton.y = 400
// 把按钮添加到场景中
this.stage.addChild(actionButton)
}
createActionButton(){
// 创建一个容器,可以统一调整容器内的元素
let actionButton = new PIXI.Container()
let btnImage = new PIXI.Sprite(this.loader.resources["btn.png"].texture);
let btnCircle = new PIXI.Sprite(this.loader.resources["btn_circle.png"].texture);
let btnCircle2 = new PIXI.Sprite(this.loader.resources["btn_circle.png"].texture);
actionButton.addChild(btnImage)
actionButton.addChild(btnCircle)
actionButton.addChild(btnCircle2)
// 改变轴心
btnImage.pivot.x = btnImage.pivot.y = btnImage.width/2
btnCircle.pivot.x = btnCircle.pivot.y = btnCircle.width/2
btnCircle2.pivot.x = btnCircle2.pivot.y = btnCircle2.width/2
// 使用 GSAP 添加动效
btnCircle.scale.x = btnCircle.scale.y = 0.8
// 放大动效
gsap.to(btnCircle.scale,{duration:1, x:1.2, y:1.2, repeat:-1});
// 透明动效
gsap.to(btnCircle,{duration:1,alpha:0,repeat:-1})
return actionButton
}
3.把自行车添加到场景中
show(){
// 创建一个自行车容器
const bikeContainer = new PIXI.Container()
const bikeImage = new PIXI.Sprite(this.loader.resources['brake_bike.png'].texture)
const bikeHandlerImage = new PIXI.Sprite(this.loader.resources['brake_handlerbar.png'].texture)
const bikeLeverImage = new PIXI.Sprite(this.loader.resources['brake_lever.png'].texture)
// 把自行车图片添加到容器中
bikeContainer.addChild(bikeLeverImage)
bikeContainer.addChild(bikeImage)
bikeContainer.addChild(bikeHandlerImage)
// 调整刹车的位置
bikeLeverImage.pivot.x = bikeLeverImage.pivot.y = 455
bikeLeverImage.x = 722
bikeLeverImage.y = 900
this.stage.addChild(bikeContainer)
// 调整缩放比例
bikeContainer.scale.x = bikeContainer.scale.y = 0.3
const actionButton = this.createActionButton()
// 调整按钮的位置
actionButton.x = 722
actionButton.y = 900
bikeContainer.addChild(actionButton)
}
4.实现粒子向左后方移动的效果
思路:
- 创建一个粒子容器,生成10个粒子,随机分布到容器中
- 让所有的粒子从上到下移动
- 对粒子容器进行旋转,实现粒子向左后方移动的效果
代码:
show(){
...
// 创建粒子容器
const particleContainer = new PIXI.Container()
this.stage.addChild(particleContainer)
// 调整圆心和角度
particleContainer.rotation = 35 * Math.PI /180
particleContainer.pivot.x = window.innerWidth/2
particleContainer.pivot.y = window.innerHeight/2
particleContainer.x = window.innerWidth/2
particleContainer.y = window.innerHeight/2
// 创建粒子
let particles = []
const colors = [0xf1cf54,0xb5cea8, 0xf1cf54, 0x818181, 0x000000];
for(let i=0;i<10;i++){
// 创建一个图形
let gr = new PIXI.Graphics()
gr.beginFill(colors[Math.floor(Math.random()*colors.length)])
gr.drawCircle(0,0,6)
gr.endFill()
let pItem = {
sx:Math.random()* window.innerWidth,
sy:Math.random()* window.innerHeight,
gr,
}
gr.x = pItem.sx
gr.y = pItem.sy
particleContainer.addChild(gr)
particles.push(pItem)
}
// 设置初始速度
let speed = 0
function loop(){
speed+=0.5
// 设置最大速度
speed = Math.min(speed,20)
lineImage.y += speed
if(lineImage.y>= window.innerHeight){
lineImage.y = -lineImage.height
}
for(let i=0;i<particles.length;i++){
let pItem = particles[i]
pItem.gr.y +=speed
if(speed>=20){
pItem.gr.scale.y = 20
pItem.gr.scale.x = 0.03
}
if(pItem.gr.y>=window.innerHeight){
pItem.gr.y = 0
}
}
}
loop()
}
5.添加按钮的交互
show(){
...
// 添加交互
actionButton.interactive = true
actionButton.buttonMode = true
actionButton.on('mousedown',()=>{
// 对刹车图片进行旋转
gsap.to(bikeLeverImage,{duration:.6, rotation:Math.PI/180*-30})
pause()
})
actionButton.on('mouseup',()=>{
gsap.to(bikeLeverImage,{duration:.6, rotation:0})
start()
})
function start(){
speed=0
gsap.ticker.add(loop)
}
function pause(){
gsap.ticker.remove(loop)
// 粒子还原
for(let i=0;i<particles.length;i++){
let pItem = particles[i]
pItem.gr.scale.x = pItem.gr.scale.y = 1
gsap.to(pItem.gr, {duration:.6,x:pItem.sx, y:pItem.sy, ease:'elastic.out'})
}
}
start()
}
源码地址
附上全部代码地址,如果对你有帮助,麻烦给个star哈
总结
说实在的,如果是以前,让我去实现这种动效,我完全没思路,但在看了大帅老猿的视频后,才发现实现这种动效原来也没想象中的那么难。大家如果看了文章之后,对一些原理不是很清楚,欢迎去看视频,视频里对原理会讲的比较细。
最后,在 「公众号」 里搜 大帅老猿,在他这里可以学到很多东西!快来和我一起学习!
我正在参与掘金技术社区创作者签约计划招募活动,点击链接报名投稿。