持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第19天,点击查看活动详情
一、前言
今天上pixijs官网,突然看了一个很有意思的效果,是给一个场景加上黑幕,然后有个小亮圈跟随鼠标移动。
下面是官网的例子截图,可以看到背景是一整张草地,然后我们鼠标移上去就可以看到其中一部分草,类似局部被点亮的效果。
于是乎我的脑海里浮现出可以用这个filter属性给大家整点活的想法。
下面我们就来试试看吧。
二、过程
1、准备好基本的元素
写法基于vue3+ts
首先还是需要我们的pixi容器,我们先创建一个400x400的application容器
// 创建我们的pixi容器
let app = new PIXI.Application({
width: 400, // default: 800 宽度
height: 400, // default: 600 高度
antialias: true, // default: false 反锯齿
transparent: false, // default: false 透明度
resolution: 1 // default: 1 分辨率
})
有了容器,我们还需要一个场景容器Container,先声明一下,便于后续sprite的添加和管理。
如果只有一个场景,其实也可以跳过这一步,后面直接把sprite加到application容器里就行。
let Game = new PIXI.Container()
然后我们使用定时器(也可以其他方式),让执行顺序变为异步,因为此处需要等到网页标签元素加载好之后,才能将我们的application容器挂载到页面里的元素上去,并在之中用loader加载一下图片资源,图片我放在public文件下面,等图片资源加载完之后,再调用setup函数,往场景里添加sprite和开启动画循环。
// 使用定时器变成异步等待标签加载完毕
setTimeout(() => {
document.getElementById("pixijsjs")?.appendChild(app.view)
app.loader
.add([
"stagebg.jpeg"
])
.load(setup) // setup函数是关键
}, 400)
setup函数里,我们将场景容器Container加到application容器里,同时调用gameScene函数,来添加我们的主逻辑,还启用了循环函数,可以在play函数里,修改变量的值,达到动起来的效果。
let bg: PIXI.Sprite
let state: Function
function setup() {
// 加载完图片后
// 将场景加入到容器里
app.stage.addChild(Game)
// 游戏主场景的精灵
gameScene()
// 循环函数
state = play
app.ticker.add(delta => gameLoop(delta))
}
// 游戏循环函数
function gameLoop(delta: number){
state(delta)
}
// 游戏循环函数--具体处理逻辑 ----1秒调用60次左右
function play(delta: number) {
// 当status为true的时候,开启背景的旋转。
if(status) {
bg.rotation += 0.01
}
}
2、gameScene函数
首先我们创建一个背景,用我们之前导入的stagebg.jpeg作为sprite的图片,大小是400x400,刚好填充满我们的pixi容器。
// 设置背景
bg = new PIXI.Sprite(app.loader.resources["stagebg.jpeg"].texture)
bg.x = 0
bg.y = 0
bg.width = 400
bg.height = 400
Game.addChild(bg)
添加完之后是这样的效果。
然后是我们的重头戏filter属性
由于是光点,所以我们需要先设立一下半径和模糊大小
// 半径
const radius = 30
// 模糊大小
const blurSize = 10
接着我们用Graphics图层创建一个圆circles,这里的beginFill可以设置光点的背景色,但是经过filter之后,基本就是灯光的那种亮点,而没有本身的颜色。
const circle = new PIXI.Graphics()
.beginFill(0xFF0000) // 红色
.drawCircle(radius + blurSize, radius + blurSize, radius)
.endFill()
circle.filters = [new PIXI.filters.BlurFilter(blurSize)]
给上面的circles准备一个合适的矩形盒子,用这盒子+圆circles一起生成一个texture,用来作为聚焦(亮点)时的背景。
const bounds = new PIXI.Rectangle(0, 0, (radius + blurSize) * 2, (radius + blurSize) * 2);
const texture = app.renderer.generateTexture(circle, PIXI.SCALE_MODES.NEAREST, 1, bounds);
const focus = new PIXI.Sprite(texture)
上述的focus时,需要加入到容器中,还需要成为bg的mask,不然黑屏的位置挡不住背景。
app.stage.addChild(focus)
bg.mask = focus
之后允许容器开启交互功能,并且挂载一个mousemove鼠标移动事件。第一个点是传入的鼠标需要减去focus的宽高的一半,第二个点是我设立里一个范围,当亮点范围在这个小矩形里,移除focus,屏幕变回原来不黑屏的样子,同时开启bg的旋转。
// 开启容器的交互
app.stage.interactive = true;
app.stage.on('mousemove', pointerMove);
function pointerMove(event: { data: { global: { x: number; y: number; }; }; }) {
focus.position.x = event.data.global.x - focus.width / 2;
focus.position.y = event.data.global.y - focus.height / 2;
if(focus.position.x < 220 && focus.position.x > 180 && focus.position.y < 220 && focus.position.y > 180) {
bg.mask = null
app.stage.removeChild(focus)
status = true
}
}
3、来看下效果吧
可以看到原本的背景看不到了,鼠标划过的位置有小亮点,当我们的鼠标处于设立好的范围时,focus被移除,主背景开始旋转了起来。
三、小结
pixijs库有不少属性都很有趣,今天又体验了一个新的属性,大家伙可以去试试,相信一点点积累,一点点进步,大家最终都能成为大佬。
ps:我是地霊殿__三無,不想上班(狗头)。