added progress bar
This commit is contained in:
parent
bd6d9f3399
commit
daef55781e
8 changed files with 148 additions and 5 deletions
|
@ -26,4 +26,5 @@ ${modSource}
|
||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
|
|
||||||
fs.writeSync(1, outputCode.join('\n'));
|
fs.writeSync(1, outputCode.map(a => a.trim()).join('\n'));
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
<link rel="favicon" href="favicon.ico">
|
<link rel="favicon" href="favicon.ico">
|
||||||
<link rel="stylesheet" href="css/snek.css">
|
<link rel="stylesheet" href="css/snek.css">
|
||||||
<script src="js/snek.js"></script>
|
<script src="js/snek.js"></script>
|
||||||
|
<script>window.addEventListener('load', () => require('assets'));</script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<header>
|
<header>
|
||||||
|
|
79
src/js/assets.js
Normal file
79
src/js/assets.js
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
const ProgressBar=require('progress');
|
||||||
|
|
||||||
|
const assetSpecs=[
|
||||||
|
{ name: 'fruit', filename: 'apple32.png', type: 'image' },
|
||||||
|
{ name: 'wall', filename: 'wall32.png', type: 'image' },
|
||||||
|
{ name: 'snake', filename: 'snake.json', type: 'json' }
|
||||||
|
];
|
||||||
|
|
||||||
|
const cvs=document.createElement('canvas');
|
||||||
|
cvs.width=400;
|
||||||
|
cvs.height=50;
|
||||||
|
cvs.classList.add('progressBar');
|
||||||
|
cvs.classList.add('hiddenBottom');
|
||||||
|
|
||||||
|
const bar=new ProgressBar(assetSpecs.length*2);
|
||||||
|
bar.addUpdateListener(() => bar.draw(cvs));
|
||||||
|
bar.draw(cvs);
|
||||||
|
|
||||||
|
document.body.appendChild(cvs);
|
||||||
|
setTimeout(() => cvs.classList.remove('hiddenBottom'), 0);
|
||||||
|
|
||||||
|
bar.addReadyListener(() => {
|
||||||
|
cvs.classList.add('hiddenBottom');
|
||||||
|
setTimeout(() => document.body.removeChild(cvs), 1000);
|
||||||
|
});
|
||||||
|
|
||||||
|
//XXX purposefully slow down asset loading
|
||||||
|
const sleep=(ms) => new Promise(ok => setTimeout(ok, ms));
|
||||||
|
|
||||||
|
const loadAsset=async (asset) => {
|
||||||
|
const response=await fetch('assets/'+asset.filename);
|
||||||
|
await sleep(1000*Math.random());
|
||||||
|
bar.update();
|
||||||
|
let result;
|
||||||
|
switch(asset.type) {
|
||||||
|
case 'json':
|
||||||
|
result=await response.json();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'image':
|
||||||
|
result=await createImageBitmap(await response.blob());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
await sleep(1000*Math.random());
|
||||||
|
bar.update();
|
||||||
|
return [asset.name, result];
|
||||||
|
};
|
||||||
|
|
||||||
|
let assets=Object.create(null);
|
||||||
|
let ready=false;
|
||||||
|
let readyListeners=[];
|
||||||
|
|
||||||
|
Promise
|
||||||
|
.all(
|
||||||
|
assetSpecs.map(a => loadAsset(a))
|
||||||
|
).then(arr => {
|
||||||
|
arr.forEach(([name, value]) => {
|
||||||
|
assets[name]=value;
|
||||||
|
});
|
||||||
|
ready=true;
|
||||||
|
readyListeners.forEach(fn => fn.bind(fn)());
|
||||||
|
readyListeners=null;
|
||||||
|
});
|
||||||
|
|
||||||
|
const onReady=(fn) => {
|
||||||
|
if(ready) fn.bind(fn)();
|
||||||
|
else readyListeners.push(ready);
|
||||||
|
};
|
||||||
|
|
||||||
|
const get=(name) => {
|
||||||
|
let asset=assets[name];
|
||||||
|
if(!asset) throw new Error("Unknown asset: "+name);
|
||||||
|
return asset;
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
onReady, get
|
||||||
|
};
|
||||||
|
|
44
src/js/progress.js
Normal file
44
src/js/progress.js
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
class ProgressBar {
|
||||||
|
constructor(taskCount) {
|
||||||
|
this.taskCount=taskCount;
|
||||||
|
this.completeCount=0;
|
||||||
|
this.updateListeneres=[];
|
||||||
|
}
|
||||||
|
|
||||||
|
get percent() {
|
||||||
|
return Math.floor(this.completeCount/this.taskCount*100);
|
||||||
|
}
|
||||||
|
|
||||||
|
get ready() {
|
||||||
|
return this.completeCount==this.taskCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
addUpdateListener(fn) {
|
||||||
|
this.updateListeneres.push(fn.bind(this));
|
||||||
|
}
|
||||||
|
addReadyListener(fn) {
|
||||||
|
this.updateListeneres.push(() => {
|
||||||
|
if(this.ready) fn.bind(this)();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
update() {
|
||||||
|
this.completeCount++;
|
||||||
|
this.updateListeneres.forEach(l => l(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
draw(canvas, bgColor='red', textColor='black') {
|
||||||
|
let ctx=canvas.getContext('2d');
|
||||||
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||||
|
ctx.fillStyle=bgColor;
|
||||||
|
ctx.fillRect(0, 0, canvas.width*this.completeCount/this.taskCount, canvas.height);
|
||||||
|
ctx.fillStyle=textColor;
|
||||||
|
ctx.textAlign='center';
|
||||||
|
ctx.textBaseline='center';
|
||||||
|
ctx.font=`${canvas.height/2}px 'Fira Code'`;
|
||||||
|
ctx.fillText(this.percent+'%', canvas.width/2, canvas.height/2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ProgressBar;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
const Assets=require('assets');
|
const assets=require('assets');
|
||||||
|
|
||||||
const [EMPTY, FOOD, WALL, SNAKE]=Array(4).keys();
|
const [EMPTY, FOOD, WALL, SNAKE]=Array(4).keys();
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ class SnekGame {
|
||||||
const offsetY=(this.canvas.height-cellSize*this.dimensions[1])/2;
|
const offsetY=(this.canvas.height-cellSize*this.dimensions[1])/2;
|
||||||
|
|
||||||
// draw our walls
|
// draw our walls
|
||||||
const wall=Assets.get('wall');
|
const wall=assets.get('wall');
|
||||||
for(let x=0; x<this.dimensions[0]; x++) {
|
for(let x=0; x<this.dimensions[0]; x++) {
|
||||||
for(let y=0; x<this.dimensions[1]; y++) {
|
for(let y=0; x<this.dimensions[1]; y++) {
|
||||||
switch(this.world[x][y]) {
|
switch(this.world[x][y]) {
|
||||||
|
@ -65,7 +65,7 @@ class SnekGame {
|
||||||
}
|
}
|
||||||
|
|
||||||
// draw our snake
|
// draw our snake
|
||||||
const snake=Assets.get('snake');
|
const snake=assets.get('snake');
|
||||||
this.ctx.fillStyle=snake.color;
|
this.ctx.fillStyle=snake.color;
|
||||||
this.ctx.strokeStyle=snake.color;
|
this.ctx.strokeStyle=snake.color;
|
||||||
this.ctx.lineCap=snake.cap;
|
this.ctx.lineCap=snake.cap;
|
||||||
|
@ -96,7 +96,7 @@ class SnekGame {
|
||||||
// our fruit has a nice animation to it between .8 and 1.2 scale
|
// our fruit has a nice animation to it between .8 and 1.2 scale
|
||||||
const ms=Date.now();
|
const ms=Date.now();
|
||||||
const fruitScale=Math.sin(ms/1000*Math.PI)*.2+1
|
const fruitScale=Math.sin(ms/1000*Math.PI)*.2+1
|
||||||
const fruit=Assets.get('fruit');
|
const fruit=assets.get('fruit');
|
||||||
this.fruits.forEach(([x, y]) => {
|
this.fruits.forEach(([x, y]) => {
|
||||||
this.ctx.drawImage(
|
this.ctx.drawImage(
|
||||||
fruit,
|
fruit,
|
||||||
|
|
15
src/less/progressBar.less
Normal file
15
src/less/progressBar.less
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
.progressBar {
|
||||||
|
position: fixed;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
background: white;
|
||||||
|
box-shadow: black 0 0 2rem;
|
||||||
|
border-radius: 100vh;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
transition: top .5s ease-in-out;
|
||||||
|
|
||||||
|
&.hiddenBottom {
|
||||||
|
top: 200vh;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -79,3 +79,6 @@ h2 {
|
||||||
p {
|
p {
|
||||||
font-size: 1.6rem;
|
font-size: 1.6rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// setup the progress bar
|
||||||
|
@import 'progressBar';
|
||||||
|
|
Loading…
Reference in a new issue