初次使用PIXI+GSAP仿写vanmoof刹车动效 【 | 猿创营】

922 阅读3分钟

初次使用PIXI+GSAP来做动画效果还不错,之前很少做比较复杂的动画类的东西,这次学习了

  1. 这是PIXI的官网 pixijs.com/
  2. 这是GSAP的官网 greensock.com/docs/v3/GSA…

官网因为是英文的 可能不太友好,中文的官网没有,但是有些辅助的资料,大家可以看一下,但是最终还是要自己多去写demo练一练才能熟练起来

这是实现之后的效果

2022-07-10 181847.gif

我们边学边熟悉一下PIXI的api和GSAP的api

首先我们需要用PIXI创建一块画布

 this.app = new PIXI.Application({
	width: window.innerWidth, // 这是画布的宽
	height: window.innerHeight, // 画布的高
	backgroundColor: 0xffffff // 画布的底色
 })

我先介绍一下我们这次会用到的api

this.stage = this.app.stage // 是相当于页面 我们需要把我们画的图片、图形全部挂到上面才能显示出来
this.loader = new PIXI.Loader() // 是一个加载器,是加载解析图片的一些信息,方便我们去使用
this.loader.add("btn.png", 'images/btn.png') // 这是把需要加载图片添加到里面进行解析 第一个参数是key,第两个参数是图片地址,
this.loader.load() // 对添加的图片进行解析
this.loader.onComplete.add(()=>{
  show()
}) // 图片解析完进行的回调函数
new PIXI.Container() // 新建一个容器 可以把你认为是一组的写在里面
this.loader.resources['btn.png'].texture // 图片加载解析完成,当我们需要对应的key的信息的时候就需要使用这种方式,texture属性里是图片的信息
let btn= new PIXI.Sprite(this.loader.resources['btn.png'].texture) // 新建一个精灵 只有通过这个画出来的图片才能添加到stage上,并且显示出来 第一次参数是图片的信息,有个图片信息精灵就可以画出来了
this.stage.addChild(btn) // 这个方法是把容器或者 新创建的精灵添加到 stage 显示
btn.pivot.x和y 是设置这个图片的圆心点坐标的
btn.x和y 是设置距离的
btn.interactive = true 让相对应的图可以添加监听事件

show方法

	show() {
		let { bikeLeverImage } = this.createbike()
		let actionButton = this.createActionBtn()
		let { start,pause } = this.createl()

		actionButton.on('mousedown', () => {
			gsap.to(bikeLeverImage, { duration: 0.6, rotation: Math.PI / 180 * -30 })
		    pause() 
		})
		actionButton.on('mouseup', () => {
			// bikeLeverImage.rotation = Math.PI / 180 * 0
			gsap.to(bikeLeverImage, { duration: 0.6, rotation: Math.PI / 180 * 0 })
            start()
		})
	}

对上面实现的效果进行分解 按键应该是一起的

这是实现按键的方法

难点主要是需要实现按键的波纹动画效果

createActionBtn() {
  		// 这个这两个图片是一起的 所以应该放到一个容器里 进行统一管理
		let actionButton = new PIXI.Container()
		this.stage.addChild(actionButton)
		let btnImage = new PIXI.Sprite(this.loader.resources['btn.png'].texture)
		actionButton.addChild(btnImage)
		let circle = new PIXI.Sprite(this.loader.resources['btn_circle'].texture)
		actionButton.addChild(circle)
		let circle2 = new PIXI.Sprite(this.loader.resources['btn_circle'].texture)
		actionButton.addChild(circle2)
		btnImage.pivot.x = btnImage.pivot.y = btnImage.width / 2
		circle.pivot.x = circle.pivot.y = circle.width / 2
		circle2.pivot.x = circle2.pivot.y = circle2.width / 2
		actionButton.x = actionButton.y = 300
		circle.scale.x = circle.scale.y = 0.8
		// gsas是动画效果的插件 repeat: -1 是循环 
                // 这个动画是实现按键的波纹效果的
		gsap.to(circle.scale, { duration: 1, x: 1.3, y: 1.3, repeat: -1 })  // 
		gsap.to(circle, { duration: 1, alpha: 0, repeat: -1 })

		// 可以添加监听事件
		actionButton.interactive = true
		
		actionButton.buttonMode = true
		return actionButton

}

建立一个自行车方法

	createbike() {
		// 新建一个车架容器
		let bikeContainer = new PIXI.Container()
		bikeContainer.scale.x = bikeContainer.scale.y = 0.3
		this.stage.addChild(bikeContainer)
		let bikeImage = new PIXI.Sprite(this.loader.resources['brake_bike'].texture)
		bikeContainer.addChild(bikeImage)
		// 把手
		let bikeLeverImage = new PIXI.Sprite(this.loader.resources['brake_lever'].texture)
		bikeContainer.addChild(bikeLeverImage)
		bikeLeverImage.pivot.x = 455
		bikeLeverImage.pivot.y = 455
		
		bikeLeverImage.x = 722
		bikeLeverImage.y = 900
		
		let brakeHandlerbar = new PIXI.Sprite(this.loader.resources['brake_handlerbar'].texture)
		bikeContainer.addChild(brakeHandlerbar)
		return { bikeImage, bikeLeverImage, brakeHandlerbar }
	}

第二步需要建立车架及车把 难点主要是 刹车效果

// 按键的事件卸载了show方法里

createbike() {
		// 新建一个车架容器
		let bikeContainer = new PIXI.Container()
		bikeContainer.scale.x = bikeContainer.scale.y = 0.3
		this.stage.addChild(bikeContainer)
		let bikeImage = new PIXI.Sprite(this.loader.resources['brake_bike'].texture)
		bikeContainer.addChild(bikeImage)
		let bikeLeverImage = new PIXI.Sprite(this.loader.resources['brake_lever'].texture)
		bikeContainer.addChild(bikeLeverImage)
		bikeLeverImage.pivot.x = 455
		bikeLeverImage.pivot.y = 455
		bikeLeverImage.x = 722
		bikeLeverImage.y = 900
		let brakeHandlerbar = new PIXI.Sprite(this.loader.resources['brake_handlerbar'].texture)
		bikeContainer.addChild(brakeHandlerbar)

		return { bikeImage, bikeLeverImage, brakeHandlerbar }
	}

第三步 我们需要建立粒子 并且粒子需要向30度移动

	createl() {
                 这是我们画粒子的思路
          	// 向某一个角度持续移动
		// gsap.ticker.add(loop) // gsap添加了一个监听事件
		// 超出边界后回到顶部继续移动
		// 按住鼠标停止移动
		// 停止有回弹效果
		// 松开鼠标继续
        
		// 创建粒子
		let particleContainer = new PIXI.Container();
		this.stage.addChild(particleContainer)
		// 修改圆心坐标
		particleContainer.pivot.x = window.innerWidth / 2
		particleContainer.pivot.y = window.innerHeight / 2
		// 旋转粒子容器
		particleContainer.rotation = 30 * Math.PI / 180
		let particles = []
		// 粒子有多个颜色
		let colors = [0xf1cf54, 0xb5cea8, 0xf1cf54, 0x818f54, 0xb5cea8]
		for (let i = 0; i < 10; i++) {
			let gr = new PIXI.Graphics(); // 相当于canvas的getContext("2d") 就是一个画笔
			gr.beginFill(colors[Math.floor(Math.random() * colors.length)])
			gr.drawCircle(0, 0, 6)
			gr.endFill()
			let aitem = {
				sx: Math.random() * window.innerWidth,
				sy: Math.random() * window.innerHeight,
				gr: gr,
			}
			gr.x = aitem.sx
			gr.y = aitem.sy
			particleContainer.addChild(gr)
			particles.push(aitem)
		}
		let speed = 0
		// 用gsap创建一个循环
		function loop() {
			speed += .5
			Math.min(speed, 20)
			for (let i = 0; i < particles.length; i++) {
				let pItem = particles[i]
				pItem.gr.y += speed
				if (speed>=20) {
					pItem.gr.scale.y = 40
					pItem.gr.scale.x = 0.04
				}
				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:1,x: pItem.sx,y: pItem.sy,ease: "elastic" })
			}
		}
		start()
		return {
			start,pause
		}
	}

上面动态图就是实现的效果

公众号里搜 大帅老猿,在他这里可以学到很多东西