前言
近期猿创营在分享一期仿写vanmoof刹车动效的活动, 下面我们来看看整个刹车特效的实现过程, 这个项目使用到了PIXI和GSAP两个库,可以提前了解一下
搭建环境
- 当前项目需要加载两个库PIXI 和 GSAP
<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>
- 启动一个本地web服务器,我这里使用的serve, 当然大家使用自己熟悉的就行, vscode开发的话推荐使用lib preview
本项目使用到了一些素材,可以在我的github上下载
开发
创建PIXI应用
new PIXI.Application({
width: window.innerWidth,
height: window.innerHeight,
backgroundColor: 0xffffff,
})
document.querySelector(selector).appendChild(this.app.view)
加载图片资源
const loader = new PIXI.Loader()
loader.add('btn.png', 'images/btn.png')
loader.add('brake_bike.png', 'images/brake_bike.png')
loader.add('brake_handlerbar.png', 'images/brake_handlerbar.png')
loader.add('brake_lever.png', 'images/brake_lever.png')
loader.add('btn_circle.png', 'images/btn_circle.png')
loader.load()
loader.onComplete.add(() => {
setup()
})
创建按钮图片精灵
function loaderButton() {
const buttonContainer = new PIXI.Container()
const buttonImg = new PIXI.Sprite(this.loader.resources['btn.png'].texture)
const buttonCircleImage = new PIXI.Sprite(this.loader.resources['btn_circle.png'].texture)
const buttonCircleImage2 = new PIXI.Sprite(this.loader.resources['btn_circle.png'].texture)
buttonContainer.addChild(buttonImg)
buttonContainer.addChild(buttonCircleImage)
buttonContainer.addChild(buttonCircleImage2)
// 设置
buttonImg.pivot.y = buttonImg.pivot.x = buttonImg.width / 2
buttonCircleImage.pivot.y = buttonCircleImage.pivot.x = buttonCircleImage.width / 2
buttonCircleImage2.pivot.y = buttonCircleImage2.pivot.x = buttonCircleImage2.width / 2
// 设置波纹初始缩放比例
buttonCircleImage2.scale.x = buttonCircleImage2.scale.y = 0.8
// 添加动画
gsap.to(buttonCircleImage2.scale, { duration: 1, x: 1.2, y: 1.2, repeat: -1 })
gsap.to(buttonCircleImage2, { duration: 1, alpha: 0, repeat: -1 })
// 设置按钮容器大小
buttonContainer.width = this.buttonConfig.width
buttonContainer.height = this.buttonConfig.height
// 默认定位到左上角
buttonContainer.x = this.buttonConfig.width / 2
buttonContainer.y = this.buttonConfig.height / 2
// 添加按钮到舞台
this.app.stage.addChild(buttonContainer)
return buttonContainer
}
设置把手、车身
const brakeHandlerbar = new PIXI.Sprite(this.loader.resources['brake_handlerbar.png'].texture)
bikeContainer.addChild(brakeHandlerbar)
const bikeBrakeImage = new PIXI.Sprite(this.loader.resources['brake_bike.png'].texture)
bikeContainer.addChild(bikeBrakeImage)
// 把手
const bikeLeverImage = new PIXI.Sprite(this.loader.resources['brake_lever.png'].texture)
bikeContainer.addChild(bikeLeverImage)
bikeLeverImage.pivot.x = 455
bikeLeverImage.pivot.y = 455
bikeLeverImage.x = 722
bikeLeverImage.y = 900
// bikeLeverImage.rotation = (Math.PI / 180) * -30
const actionButton = this.createActionButton()
actionButton.x = actionButton.y = 400
this.app.stage.addChild(actionButton)
actionButton.interactive = true
actionButton.buttonMode = true
actionButton.on('mousedown', () => {
// bikeLeverImage.rotation = (Math.PI / 180) * -30
gsap.to(bikeLeverImage, { duration: 0.6, rotation: (Math.PI / 180) * -30 })
pause()
})
actionButton.on('mouseup', () => {
// bikeLeverImage.rotation = 0
gsap.to(bikeLeverImage, { duration: 0.6, rotation: 0 })
start()
})
const resize = () => {
bikeContainer.x = window.innerWidth - bikeContainer.width
bikeContainer.y = window.innerHeight - bikeContainer.height
}
window.addEventListener('resize', resize)
resize()
创建雨滴动画
// 创建粒子
const particleContainer = new PIXI.Container()
particleContainer.rotation = (Math.PI / 180) * 35
particleContainer.pivot.x = window.innerWidth / 2
particleContainer.pivot.y = window.innerHeight / 2
particleContainer.x = window.innerWidth / 2
particleContainer.y = window.innerHeight / 2
// particleContainer.fill = 0xff0000
this.app.stage.addChild(particleContainer)
const particles = []
const colors = [0xf1cf54, 0xb5cea8, 0xf1cf54, 0xff0000]
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()
const pItem = {
sx: Math.random() * window.innerWidth,
sy: Math.random() * window.innerHeight,
gr: 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, 30)
for (let i = 0; i < particles.length; i++) {
let pItem = particles[i]
pItem.gr.y += speed
if (speed >= 20) {
pItem.gr.scale.y = 50
pItem.gr.scale.x = 0.05
}
if (pItem.gr.y > window.innerHeight) {
pItem.gr.y = 0
}
}
}
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.y = 1
pItem.gr.scale.x = 1
gsap.to(pItem.gr, { duration: 0.6, x: pItem.sx, y: pItem.sy, ease: 'elastic.out' })
}
}
start()
最后
在公众号里搜 大帅老猿,在他这里可以学到很多东西!