benchmark/birds_fly.spritejs-1.16.1.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no" />
<title>Birds Flying</title>
<style>
*{
-webkit-touch-callout: auto; /* prevent callout to copy image, etc when tap to hold */
-webkit-text-size-adjust: none; /* prevent webkit from resizing text to fit */
-webkit-tap-highlight-color: rgba(0,0,0,0); /* make transparent link selection, adjust last value opacity 0 to 1.0 */
-webkit-user-select:none;
}
html,body {
width: 100%;
height: 100%;
padding: 0;
margin: 0;
max-width: 500px;
}
#paper {
position: relative;
overflow: hidden;
width: 100%;
padding-top: 100%;
height: 0px;
}
</style>
</head>
<body>
<div>fps: <span id="fps">--</span> | sprites: <span id="spriteCount">1</span></div>
<div id="paper"></div>
<script src="https://s2.ssl.qhres2.com/!87edaa34/animator-0.3.1.min.js"></script>
<script src="https://s0.ssl.qhres2.com/!cfaa644c/spritejs.min.js"></script>
<script>
const birdsJsonUrl = 'https://s5.ssl.qhres2.com/static/5f6911b7b91c88da.json';
const birdsRes = 'https://p.ssl.qhimg.com/d/inn/c886d09f/birds.png'
;(async function () {
const paper = spritejs.Paper2D('#paper');
paper.setResolution(800, 800); // 设置 Paper 的实际分辨率
const cacheMap = new Map();
window.cacheMap = cacheMap;
class Bird extends spritejs.Sprite {
constructor() {
super('bird1.png');
}
// 共用缓存,提高性能
get cache() {
const key = JSON.stringify(this.textures) + this.attr('scale');
if(cacheMap.has(key)) {
return cacheMap.get(key);
}
return null;
}
set cache(context) {
if(context == null) {
// cacheMap.clear()
return;
}
const key = JSON.stringify(this.textures) + this.attr('scale');
if(!cacheMap.has(key)) {
cacheMap.set(key, context);
}
}
}
await paper.preload(
[birdsRes, birdsJsonUrl] // 预加载资源,支持雪碧图
);
const bglayer = paper.layer('bg'), // 背景层
// 前景层
// 不代理事件,提升性能
fglayer = paper.layer('fg', {
handleEvent: false,
evaluateFPS: true,
renderMode: 'repaintAll',
});
const axisZero = [400, 400];
const circle = new spritejs.Sprite();
circle.attr({
anchor: [0.5, 0.5],
size: [800, 800],
pos: axisZero,
bgcolor: '#139',
opacity: 0.5,
borderRadius: 400,
});
bglayer.appendChild(circle);
function pointAdd(p1, p2 = [0, 0]) {
return [p1[0] + p2[0], p1[1] + p2[1]].map(Math.round);
}
function pointSub(p1, p2 = [0, 0]) {
return [p1[0] - p2[0], p1[1] - p2[1]].map(Math.round);
}
function sleep(time) {
return new Promise(resolve => setTimeout(resolve, time));
}
async function randomAnimate(bird) {
const birdPoint = bird.attr('pos');
const randomArc = Math.random() * 2 * Math.PI;
const randomPoint = pointAdd([350 * Math.cos(randomArc),
350 * Math.sin(randomArc)], axisZero);
const dist = pointSub(randomPoint, birdPoint);
const distance = Math.round(Math.sqrt(dist[0] * dist[0] + dist[1] * dist[1]));
const flip = dist[0] < 0 ? -1 : 1;
const duration = 5 * distance + 100;
bird.attr('scale', [flip, 1]); // scale 放在外面,触发缓存
const anim = new Animator(duration, ((p) => {
const pos = pointAdd(birdPoint, [p * dist[0], p * dist[1]]);
if(Number.isNaN(pos[0]) || Number.isNaN(pos[1])) {
console.log('p', duration, p);
}
bird.attr({
pos,
});
}));
await anim.animate();
await sleep(500);
}
let birdCount = 0;
async function addBird() {
spriteCount.innerHTML = ++birdCount;
const bird = new Bird();
bird.attr({
anchor: [0.5, 0.5],
pos: axisZero,
transform: {
rotate: 0,
},
size: [86, 60],
});
window.bird = bird;
fglayer.appendChild(bird);
let idx = 0;
setInterval(() => {
bird.textures = [`bird${++idx % 3 + 1}.png`];
}, 100);
window.bird = bird;
// noprotect
do {
await randomAnimate(bird);
} while(1);
}
addBird();
circle.on('click', (evt) => {
addBird();
});
const timer = setInterval(() => {
if(birdCount < 500) addBird();
else clearInterval(timer);
}, 16);
// 显示 fps ,注意,因为本框架采用的是非定时渲染,即只有 sprite 有更新时才渲染
// 所以所有精灵不运动的时候 fps 也会降下来
setInterval(() => {
fps.innerHTML = fglayer.fps;
}, 1000);
window.fglayer = fglayer;
window.paper = paper;
}());
</script>
</body>
</html>