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="stylesheet" href="css/snek.css">
|
||||
<script src="js/snek.js"></script>
|
||||
<script>window.addEventListener('load', () => require('assets'));</script>
|
||||
</head>
|
||||
<body>
|
||||
<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();
|
||||
|
||||
|
@ -47,7 +47,7 @@ class SnekGame {
|
|||
const offsetY=(this.canvas.height-cellSize*this.dimensions[1])/2;
|
||||
|
||||
// draw our walls
|
||||
const wall=Assets.get('wall');
|
||||
const wall=assets.get('wall');
|
||||
for(let x=0; x<this.dimensions[0]; x++) {
|
||||
for(let y=0; x<this.dimensions[1]; y++) {
|
||||
switch(this.world[x][y]) {
|
||||
|
@ -65,7 +65,7 @@ class SnekGame {
|
|||
}
|
||||
|
||||
// draw our snake
|
||||
const snake=Assets.get('snake');
|
||||
const snake=assets.get('snake');
|
||||
this.ctx.fillStyle=snake.color;
|
||||
this.ctx.strokeStyle=snake.color;
|
||||
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
|
||||
const ms=Date.now();
|
||||
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.ctx.drawImage(
|
||||
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 {
|
||||
font-size: 1.6rem;
|
||||
}
|
||||
|
||||
// setup the progress bar
|
||||
@import 'progressBar';
|
||||
|
|
Loading…
Reference in a new issue