背景
没动手之前总觉得做这类炫酷的效果很难,不知道从哪里下手。
这次终于在老帅的鞭策(其实是诱惑)下动手了。
看完===学会
如果觉得还错,点个赞给予鼓励吧
技术背景
- 据说是在2D渲染方面,PixiJS是最快的。
- 运行web服务,否则Pixi将无法工作
pixi的基本概念
先基本了解一下PIXI的基础内容,做到心中有数。
stage 舞台
即一个特殊的Pixi对象叫做stage(舞台)。
通过 app.view获取舞台
//Create a Pixi Application
let app = new PIXI.Application({width: 256, height: 256});
document.body.appendChild(app.view);
sprites 精灵
sprite(精灵)是一种的特殊图像对象。您可以控制它们的位置、大小和其他属性。类似于舞台上的演员,他们有可以有自己的位置和特征。
1. 定位 :根据 x、y轴 控制定位
x=10
y=20
// 缩写
position.set(x, y)
2. 大小 :根据width 和 height控制大小
3. 缩放:sacale ,scale.x和scale.y
值表示纹理尺寸的百分比,从0到1(0%到100%)。
scale.x =0.5
scale.y = 0.5
// 缩写
scale.set(0.5, 0.5);
4. 旋转:rotation
rotation = 0.5
// 正常角度转换 π/180*deg
5. 锚点:anchoranchor.x和anchor.y
值表示纹理尺寸的百分比,从0到1(0%到100%)。
anchor.x =0.5
anchor.y = 0.5
// 缩写
anchor.set(0.5, 0.5);
6.轴心点:pivot设置精灵的原点。
pivot.x和pivot.y 按像素计算。 类似于锚点
pivot.x =30
pivot.y = 30
// 缩写
pivot.set(30, 30);
可以利用纹理texture(纹理),使用Pixi的Sprite类创建精灵
loader 加载器
PIXI.loader
.add("images/anyImage.png")
.load(setup);
function setup() {
let sprite = new PIXI.Sprite(
PIXI.loader.resources["images/anyImage.png"].texture
);
}
精灵分组 Container
new PIXI.Container() 创建容器,再 使用addChild 加入精灵
let container = new PIXI.Container();
container.addChild(sprite1);
container.addChild(sprite2);
粒子容器 ParticleContaine
任何在ParticleContainer中的精灵渲染速度都比在常规容器中快2到5倍
let superFastSprites = new PIXI.particles.ParticleContainer();
如果想在ParticleContainer中更改子画面的rotation,scale,tint或uvs,则必须将这些属性设置为true,如下所示:
let superFastSprites = new ParticleContainer(
size,
{
rotation: true,
alphaAndtint: true,
scale: true,
uvs: true
}
);
图形绘制
- 需创建Pixi的
Graphics类(Pixi.Graphics)的实例 - 填充颜色:
beginFill - 外边框:
lineStyle - 绘制图形:
drawRect、drawCircle、drawEllipse、drawRoundedRect、drawPolygon - 结束绘制:
endFilldrawRect
let rectangle = new Graphics();
rectangle.lineStyle(4, 0xFF3300, 1);
rectangle.beginFill(0x66CCFF);
rectangle.drawRect(0, 0, 64, 64);
rectangle.endFill();
rectangle.x = 170;
rectangle.y = 170;
app.stage.addChild(rectangle);
动手实战
需求分析
- 刹车动效制作
- 刹车按钮动画制作
- 下雨动画制作
- 刹车效果和下雨动画同步
上代码
导入所有元素
- 创建容器
- 加载所有图片
- 绑定加载后事件 (展示动画)
class BrakeBanner {
constructor(selector) {
this.app = new PIXI.Application({
width: window.innerWidth,
height: window.innerHeight,
backgroundColor: 0xffffff,
resizeTo: window,
});
document.querySelector(selector).appendChild(this.app.view);
this.stage = this.app.stage;
this.loader = new PIXI.Loader();
this.loader
.add("btn_circle.png", "images/btn_circle.png")
.add("brake_bike.png", "images/brake_bike.png")
.add("brake_handlerbar.png", "images/brake_handlerbar.png")
.add("brake_lever.png", "images/brake_lever.png")
.add("btn.png", "images/btn.png");
this.loader.load();
this.loader.onComplete.add(() => {
this.show(); // 动画操作
});
}
展示动画。 细分模块 : 自行车模块、按钮模块、下雨动画模块
show() {
this.showBrake();
this.showPoint();
this.showBtn();
}
1、 自行车模块
- 加入自行车所有元素
- 调整所有图片的位置
- 绑定窗口变化事件,自适应
- 将需要用于动画的元素挂载到根实例,用于与按钮联动效果制作
showBrake() {
const bikeContainer = new PIXI.Container();
bikeContainer.scale.set(0.3, 0.3);
this.stage.addChild(bikeContainer);
let brake_bike = new PIXI.Sprite(
this.loader.resources["brake_bike.png"].texture
);
let brake_handlerbar = new PIXI.Sprite(
this.loader.resources["brake_handlerbar.png"].texture
);
let brake_lever = new PIXI.Sprite(
this.loader.resources["brake_lever.png"].texture
);
brake_lever.pivot.set(455, 455);
brake_lever.position.set(722, 900);
this.brake_lever = brake_lever;
this.bikeContainer = bikeContainer;
bikeContainer.addChild(brake_bike, brake_lever, brake_handlerbar);
let resize = () => {
bikeContainer.position.set(
window.innerWidth - bikeContainer.width,
window.innerHeight - bikeContainer.height
);
};
window.addEventListener("resize", resize);
resize();
}
}
2、下雨模块
- 创建例子容及粒子
- 将粒子容器倾斜
- 制作粒子动画(加速粒子变形、速度由慢变快)
- 将动画开始和暂定事件 绑定在跟容器
showPoint() {
let pointContainer = new PIXI.Container();
pointContainer.rotation = (35 * Math.PI) / 180;
pointContainer.pivot.set(window.innerWidth / 2, window.innerHeight / 2);
pointContainer.position.set(window.innerWidth / 2, window.innerHeight / 2);
this.stage.addChild(pointContainer);
let particles = [];
let colors = [0xf1cf54, 0xb5cea8, 0xf1cf54, 0x818181, 0x000000];
for (let i = 0; i <= 20; i++) {
let rectangle = new PIXI.Graphics();
rectangle.beginFill(colors[Math.floor(Math.random() * colors.length)]);
rectangle.drawCircle(0, 0, 3);
rectangle.endFill();
pointContainer.addChild(rectangle);
let x = Math.random() * window.innerWidth;
let y = Math.random() * window.innerHeight;
rectangle.position.set(x, y);
particles.push({ gr: rectangle, sx: x, sy: y });
}
let speed = 10;
function loop() {
speed += 0.5;
speed = Math.min(20, speed);
particles.forEach((pItem) => {
pItem.gr.y += speed;
if (speed >= 20) {
pItem.gr.scale.set(0.03, 40);
}
if (pItem.gr.y >= window.innerHeight) {
pItem.gr.y = pItem.sy;
}
});
}
function start() {
gsap.ticker.add(loop);
}
function pause() {
gsap.ticker.remove(loop);
particles.forEach((pItem) => {
pItem.gr.scale.set(1, 1);
gsap.to(pItem.gr, {
duration: 0.6,
x: pItem.sx,
y: pItem.sy,
ease: "elastic.out",
});
});
}
start();
this.pause = pause;
this.start = start;
}
3、按钮模块
- 加载按钮元素
- 设置按钮位置
- 绑定按钮点击事件(下雨效果及刹车动效)
- 将按钮容器挂载到根实例,用于后期动画同步
showBtn() {
let actionButton = new PIXI.Container();
actionButton.position.set(900, 800);
actionButton.scale.set(2, 2);
this.bikeContainer.addChild(actionButton);
let btn = new PIXI.Sprite(this.loader.resources["btn.png"].texture);
let btn_circle = new PIXI.Sprite(
this.loader.resources["btn_circle.png"].texture
);
let btn_circle2 = new PIXI.Sprite(
this.loader.resources["btn_circle.png"].texture
);
actionButton.addChild(btn, btn_circle, btn_circle2);
btn.pivot.set(btn.width / 2, btn.width / 2);
btn_circle.anchor.set(0.5, 0.5);
btn_circle2.anchor.set(0.5, 0.5);
gsap.to(btn_circle2.scale, { duration: 1, x: 1.2, y: 1.2, repeat: -1 });
gsap.to(btn_circle2, { duration: 1, alpha: 0, repeat: -1 });
actionButton.interactive = true;
actionButton.buttonMode = true;
actionButton.on("mousedown", () => {
gsap.to(this.brake_lever, {
duration: 0.6,
rotation: (Math.PI / 180) * -30,
});
this.pause();
// this.brake_lever.rotation = (Math.PI / 180) * -30;
});
actionButton.on("mouseup", () => {
gsap.to(this.brake_lever, {
duration: 0.6,
rotation: 0,
});
this.start();
// this.brake_lever.rotation = 0;
});
this.actionButton = actionButton;
}
最后
在公众号里搜 大帅老猿,在他这里可以学到很多东西!