heck yeah it works
This commit is contained in:
commit
6f93162c78
61
index.html
61
index.html
|
@ -3,7 +3,7 @@
|
|||
<head>
|
||||
|
||||
<!-- THE BIG META -->
|
||||
<title>Adventures With Anxiety! [BETA, DO NOT SHARE YET]</title>
|
||||
<title>Adventures With Anxiety!</title>
|
||||
<meta name="description" content="A story-game about a human and their anxiety. You play as the anxiety." />
|
||||
<link rel="icon" type="image/png" href="favicon.png">
|
||||
|
||||
|
@ -29,24 +29,7 @@
|
|||
|
||||
<!-- Styles -->
|
||||
<link rel="stylesheet" type="text/css" href="styles/game.css">
|
||||
|
||||
<!-- Mobile -->
|
||||
<meta name="viewport" content="width=360, user-scalable=no" id="my_viewport">
|
||||
<script>
|
||||
window.addEventListener("load", function(){
|
||||
var resizeViewport = function(){
|
||||
var ratio = window.innerWidth/window.innerHeight;
|
||||
var mvp = document.getElementById('my_viewport');
|
||||
if(ratio > 360/600){
|
||||
mvp.setAttribute('content', 'width='+Math.round(ratio*600)+', height=600, user-scalable=no');
|
||||
}else{
|
||||
mvp.setAttribute('content', "width=360, user-scalable=no");
|
||||
}
|
||||
};
|
||||
setInterval(resizeViewport,2000);
|
||||
resizeViewport();
|
||||
});
|
||||
</script>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
</head>
|
||||
<body>
|
||||
|
@ -194,8 +177,14 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Dialogue position debugging elements -->
|
||||
<div class='debug' style='position: absolute; width: 5px; height: 250px; background: red;'></div>
|
||||
<div class='debug' style='position: absolute; width: 5px; height: 80px; background: white;'></div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="debug" id="section_debug_list"></div>
|
||||
|
||||
<!-- - - - - - - - - - - - - - - - - - -->
|
||||
<!-- SHTUFF IN THE CORNER - - - - - - - -->
|
||||
<!-- - - - - - - - - - - - - - - - - - -->
|
||||
|
@ -248,11 +237,14 @@ Share on an anxiety-app:
|
|||
(for educators who want to avoid an awkward PTA meeting)
|
||||
</span>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
<!-- SCRIPTS -->
|
||||
<script src="scripts/lib/createImageBitmap.js"></script>
|
||||
<script src="scripts/lib/tickable_observer.js"></script>
|
||||
<script src="scripts/lib/helpers.js"></script>
|
||||
<script src="scripts/lib/rsvp.min.js"></script>
|
||||
<script src="scripts/lib/minpubsub.min.js"></script>
|
||||
|
@ -305,32 +297,5 @@ Share on an anxiety-app:
|
|||
<script src="scripts/intermission/Intermission_SceneSetup.js"></script>
|
||||
<script src="scripts/intermission/Intermission_BG.js"></script>
|
||||
|
||||
<!-- LET'S GO! -->
|
||||
<script src="scripts/main.js"></script>
|
||||
|
||||
<!--
|
||||
<div class="about_padding">
|
||||
Help me keep making free games?
|
||||
</div>
|
||||
<a href="https://www.patreon.com/ncase" target="_blank" class="no_deco">
|
||||
<div id="patreon"></div>
|
||||
</a>
|
||||
|
||||
<div class="about_padding">
|
||||
A share on an anxiety-app helps too!
|
||||
</div>
|
||||
<div id="share">
|
||||
|
||||
</div>
|
||||
|
||||
<div style="clear:both" class="about_padding"></div>
|
||||
|
||||
Above all, thank you for playing! <3
|
||||
<br>
|
||||
<a href="https://ncase.me/" target="_blank">
|
||||
my other games
|
||||
</a>
|
||||
·
|
||||
<a href="https://twitter.com/ncasenmare" target="_blank">
|
||||
my twitter
|
||||
</a>
|
||||
-->
|
|
@ -0,0 +1,126 @@
|
|||
# intro
|
||||
|
||||
`SceneSetup.intro();`
|
||||
|
||||
# intro-play-button
|
||||
|
||||
(...51)
|
||||
|
||||
[PLAY!](#intro-start) `publish("intro-to-game-1"); Game.OVERRIDE_CHOICE_LINE=true;`
|
||||
|
||||
# intro-start
|
||||
|
||||
(...500)
|
||||
|
||||
`clearText()`
|
||||
|
||||
n3: So before we start, how would *you* like to read?
|
||||
|
||||
`publish("show_options_bottom")`
|
||||
|
||||
# intro-start-2
|
||||
|
||||
n3: Now, let's begin our story...
|
||||
|
||||
```
|
||||
publish("hide_tabs");
|
||||
clearText();
|
||||
```
|
||||
|
||||
(...1000)
|
||||
|
||||
`publish("intro-to-game-2")`
|
||||
|
||||
n2: THIS IS A HUMAN
|
||||
|
||||
(...600)
|
||||
|
||||
`clearText()`
|
||||
|
||||
(...300)
|
||||
|
||||
`publish("intro-to-game-3")`
|
||||
|
||||
# act1
|
||||
|
||||
```
|
||||
SceneSetup.act1();
|
||||
publish("hide_tabs");
|
||||
music('battle', {volume:0.5});
|
||||
```
|
||||
|
||||
(...300)
|
||||
|
||||
n: AND THIS IS THE HUMAN'S ANXIETY
|
||||
|
||||
n: _YOU_ ARE THE ANXIETY
|
||||
|
||||
(#act1_normal)
|
||||
|
||||
|
||||
# act1_normal
|
||||
|
||||
```
|
||||
hong({body:"putaway"});
|
||||
sfx("rustle");
|
||||
Game.OVERRIDE_TEXT_SPEED = 1.5;
|
||||
```
|
||||
|
||||
h: Nope. No, nope, not listening. Gonna check my phone.
|
||||
|
||||
```
|
||||
sfx("rustle2");
|
||||
hong({body:"phone1", mouth:"neutral", eyes:"neutral"})
|
||||
```
|
||||
|
||||
n: YOUR JOB IS TO PROTECT YOUR HUMAN FROM *DANGER*
|
||||
|
||||
`bb({eyes:"look", mouth:"small_lock", body:"fear"})`
|
||||
|
||||
b: Gasp! You're scrolling your life away on Twitter! Again!
|
||||
|
||||
```
|
||||
bb({eyes:"normal", mouth:"normal", body:"normal"});
|
||||
hong({eyes:"annoyed"});
|
||||
```
|
||||
|
||||
h: Yeah I wonder why I don't just sit and listen to my thoughts more often.
|
||||
|
||||
`hong({eyes:"neutral"});`
|
||||
|
||||
n: QUICK, WARN THEM ABOUT A *DANGER!*
|
||||
|
||||
```
|
||||
bb({eyes:"look"});
|
||||
```
|
||||
|
||||
[Oh no, look at that horrible news story!](#act1d_news)
|
||||
|
||||
[Oh no, is that tweet secretly about *us?*](#act1d_subtweet)
|
||||
|
||||
[Hey, a GIF of a cat drinking milk](#act1d_milk)
|
||||
|
||||
# act1d_milk
|
||||
|
||||
`hong({mouth:"smile", eyes:"surprise"});`
|
||||
|
||||
h: Heh ya that's cute, I--
|
||||
|
||||
```
|
||||
hong({mouth:"shock", eyes:"shock"});
|
||||
bb({body:"scream"});
|
||||
Game.OVERRIDE_TEXT_SPEED = 1.8;
|
||||
```
|
||||
|
||||
b: CATS CAN'T DIGEST MILK AND WE'RE TERRIBLE PEOPLE FOR ENJOYING ANIMAL ABUSE
|
||||
|
||||
(...200)
|
||||
|
||||
```
|
||||
bb({body:"normal", mouth:"normal", eyes:"fear"});
|
||||
attack("20p", "bad");
|
||||
publish("hp_show");
|
||||
```
|
||||
|
||||
|
||||
|
|
@ -318,7 +318,7 @@ function BG_Party(){
|
|||
|
||||
self.draw = function(ctx, delta){
|
||||
|
||||
ctx.save();
|
||||
var oldAlpha = ctx.globalAlpha;
|
||||
|
||||
for(var i=0; i<self.layers.length; i++){
|
||||
var layer = self.layers[i];
|
||||
|
@ -329,7 +329,7 @@ function BG_Party(){
|
|||
}
|
||||
}
|
||||
|
||||
ctx.restore();
|
||||
ctx.globalAlpha = oldAlpha;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -294,7 +294,7 @@ function BG_Rooftop(){
|
|||
var vibrateTicker = 0;
|
||||
self.draw = function(ctx, delta){
|
||||
|
||||
ctx.save();
|
||||
var oldAlpha = ctx.globalAlpha;
|
||||
|
||||
if(!self.hospitalSprite.visible){
|
||||
|
||||
|
@ -319,7 +319,7 @@ function BG_Rooftop(){
|
|||
|
||||
}
|
||||
|
||||
ctx.restore();
|
||||
ctx.globalAlpha = oldAlpha;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -521,7 +521,7 @@ function BG_Act4(){
|
|||
|
||||
/////////////////////////////////////////
|
||||
|
||||
ctx.save();
|
||||
var oldAlpha = ctx.globalAlpha;
|
||||
|
||||
for(var i=0; i<self.layers.length; i++){
|
||||
|
||||
|
@ -538,7 +538,7 @@ function BG_Act4(){
|
|||
}
|
||||
}
|
||||
|
||||
ctx.restore();
|
||||
ctx.globalAlpha = oldAlpha;
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -62,61 +62,56 @@ function BG_Anxiety(whiteMode){
|
|||
}
|
||||
|
||||
};
|
||||
|
||||
self.isBoxOutOfSight = function(box){
|
||||
if(box.x<-box.w) return true;
|
||||
if(box.y<-box.h) return true;
|
||||
if(box.x>BG_WIDTH) return true;
|
||||
if(box.y>BG_HEIGHT) return true;
|
||||
if(box.x < -box.w) return true;
|
||||
if(box.y < -box.h) return true;
|
||||
if(box.x > BG_WIDTH) return true;
|
||||
if(box.y > BG_HEIGHT) return true;
|
||||
return false;
|
||||
};
|
||||
|
||||
self.updateBox = function(box, delta){
|
||||
|
||||
// Move it
|
||||
box.x += box.velX * delta/(1/60);
|
||||
box.y += box.velY * delta/(1/60);
|
||||
const speedMultiplier = 60;
|
||||
box.x += box.velX * delta * speedMultiplier;
|
||||
box.y += box.velY * delta * speedMultiplier;
|
||||
|
||||
// If it's out of sight, reset it
|
||||
if(self.isBoxOutOfSight(box)){
|
||||
self.resetBox(box);
|
||||
}
|
||||
|
||||
if(self.isBoxOutOfSight(box)) self.resetBox(box);
|
||||
};
|
||||
|
||||
var boxLayerAlpha = 1;
|
||||
self.updateAlpha = function(alpha){
|
||||
boxLayerAlpha = alpha;
|
||||
};
|
||||
|
||||
self.update = function(delta){
|
||||
for(const box of self.boxes) self.updateBox(box, delta);
|
||||
};
|
||||
|
||||
self.drawBox = function(box, ctx){
|
||||
ctx.fillStyle = self.whiteMode ? "rgba(255,255,255,0.1)" : "rgba(255,255,255,0.03)";
|
||||
ctx.fillRect(box.x, box.y, box.w, box.h);
|
||||
};
|
||||
for(var i=0; i<40; i++){
|
||||
var box = {};
|
||||
self.resetBox(box, true);
|
||||
self.boxes.push(box);
|
||||
}
|
||||
|
||||
var allBoxAlpha = 1;
|
||||
self.updateAlpha = function(alpha){
|
||||
allBoxAlpha = alpha;
|
||||
};
|
||||
self.update = function(delta){
|
||||
self.boxes.forEach(function(box){
|
||||
self.updateBox(box, delta);
|
||||
});
|
||||
};
|
||||
self.draw = function(ctx){
|
||||
|
||||
// A big ol' black box
|
||||
ctx.fillStyle = self.whiteMode ? "#dddddd" : "#111111";
|
||||
ctx.fillRect(0,0, BG_WIDTH, BG_HEIGHT);
|
||||
|
||||
// All-box alpha
|
||||
// allBoxAlpha += 1/30;
|
||||
// if(allBoxAlpha>1) allBoxAlpha=1;
|
||||
|
||||
// Moving white boxes
|
||||
ctx.globalAlpha = allBoxAlpha;
|
||||
self.boxes.forEach(function(box){
|
||||
self.drawBox(box, ctx);
|
||||
});
|
||||
ctx.globalAlpha = boxLayerAlpha * (self.whiteMode ? 0.1 : 0.03);
|
||||
ctx.fillStyle = "#fff";
|
||||
for(const box of self.boxes) self.drawBox(box, ctx);
|
||||
ctx.globalAlpha = 1;
|
||||
|
||||
};
|
||||
|
||||
for(var i=0; i<40; i++){
|
||||
var box = {};
|
||||
self.resetBox(box, true);
|
||||
self.boxes.push(box);
|
||||
}
|
||||
|
||||
}
|
|
@ -138,9 +138,10 @@ function Character(spriteConfig, animLoops){
|
|||
var c = self.characterFrames;
|
||||
|
||||
// ALLOW PARALLAX???
|
||||
ctx.save();
|
||||
var xMoved = 0;
|
||||
if(self.ALLOW_PARALLAX){
|
||||
ctx.translate(self.x, 0);
|
||||
xMoved += self.x;
|
||||
}
|
||||
|
||||
// Attacked? SHAKE WHOLE CONTEXT
|
||||
|
@ -150,6 +151,7 @@ function Character(spriteConfig, animLoops){
|
|||
var shakeAmp = (shakeDuration-attackedTimer)/shakeDuration;
|
||||
var shakeX = Math.sin(attackedTimer*Math.TAU*10)*shakeAmp*10;
|
||||
ctx.translate(shakeX, 0);
|
||||
xMoved += shakeX;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -253,7 +255,9 @@ function Character(spriteConfig, animLoops){
|
|||
}
|
||||
|
||||
}
|
||||
ctx.restore();
|
||||
|
||||
// Instead of save / restore, just move back the amount that we moved!
|
||||
ctx.translate(-xMoved, 0);
|
||||
|
||||
};
|
||||
var iconAlpha_HACK = 0;
|
||||
|
|
|
@ -29,12 +29,22 @@ window.attackBB = function(damage, type){
|
|||
// Init
|
||||
Game.init = function(){
|
||||
|
||||
// Create the section debug menu
|
||||
Object.keys(Game.sections).forEach(function(key){
|
||||
const link = document.createElement('div');
|
||||
link.className = "section_link";
|
||||
link.innerText = key;
|
||||
link.addEventListener('click', function() {
|
||||
Game.goto(key);
|
||||
});
|
||||
document.getElementById("section_debug_list").appendChild(link);
|
||||
})
|
||||
|
||||
// HP!
|
||||
window.HP = new HitPoints();
|
||||
|
||||
// Animation!
|
||||
console.log("init");
|
||||
Game.wordsDOM.style.top = "80px";
|
||||
var animloop = function(){
|
||||
Game.update();
|
||||
requestAnimationFrame(animloop);
|
||||
|
@ -43,11 +53,16 @@ Game.init = function(){
|
|||
|
||||
};
|
||||
|
||||
// Call to toggle debug rendering
|
||||
Game.debug = function(){
|
||||
document.body.classList.toggle('show_debug');
|
||||
}
|
||||
|
||||
// Parse scene markdown!
|
||||
Game.parseSceneMarkdown = function(md){
|
||||
|
||||
// Split into sections...
|
||||
md = md.trim();
|
||||
md = md.trim().replace(/\r/g, "");
|
||||
md = "\n" + md;
|
||||
var sections = md.split(/\n\#\s*/);
|
||||
sections.shift();
|
||||
|
@ -81,35 +96,33 @@ Game.start = function(){
|
|||
window._ = {}; // global var, reset
|
||||
};
|
||||
|
||||
var LAST_TIME = (new Date()).getTime();
|
||||
var last_frame = Date.now();
|
||||
Game.update = function(){
|
||||
|
||||
// TIME
|
||||
var NOW = (new Date()).getTime();
|
||||
var DELTA = (NOW - LAST_TIME)/1000;
|
||||
DELTA = Math.min(DELTA, 1/20); // no slower than 20fps
|
||||
LAST_TIME = NOW;
|
||||
const now = Date.now();
|
||||
const delta = (now - last_frame) / 1000;
|
||||
last_frame = now;
|
||||
|
||||
// Removing this till I can see why it's needed...
|
||||
// Reshaping the passing of time will come back to haunt you! [Spacie]
|
||||
// DELTA = Math.min(DELTA, 1/20); // no slower than 20fps
|
||||
|
||||
if(!Game.paused){
|
||||
|
||||
// Timeout callbacks...
|
||||
for(var i=0; i<Game.timeoutCallbacks.length; i++){
|
||||
var tc = Game.timeoutCallbacks[i];
|
||||
tc.timeLeft -= 1000*DELTA;
|
||||
if(tc.timeLeft<=0){
|
||||
tc.callback();
|
||||
Game.timeoutCallbacks.splice(i,1); // delete that one
|
||||
i -= 1; // set index back one
|
||||
}
|
||||
}
|
||||
Game.timeoutCallbacks.forEach(tc => {
|
||||
tc.timeLeft -= 1000 * delta;
|
||||
if(tc.timeLeft <= 0) tc.callback();
|
||||
});
|
||||
Game.timeoutCallbacks = Game.timeoutCallbacks.filter(tc => tc.timeLeft > 0);
|
||||
|
||||
// The interface
|
||||
Game.updateText();
|
||||
Game.updateCanvas(DELTA);
|
||||
Game.updateCanvas(delta);
|
||||
|
||||
// Ayyy
|
||||
publish("update");
|
||||
|
||||
}
|
||||
|
||||
// Options update
|
||||
|
@ -293,26 +306,48 @@ Game.immediatePromise = function(){
|
|||
|
||||
// Move the text DOM to latest
|
||||
Game.FORCE_TEXT_Y = -1;
|
||||
Game.WORDS_HEIGHT_BOTTOM = 250;
|
||||
Game.updateText = function(instant){
|
||||
if(Game.WORDS_HEIGHT_BOTTOM<0) Game.WORDS_HEIGHT_BOTTOM=250; // back to default
|
||||
if(Game.FORCE_TEXT_Y<0){
|
||||
var wordsHeight = 80 + Game.wordsDOM.getBoundingClientRect().height;
|
||||
var currentY = Game.wordsDOM.style.top=="" ? 80 : parseFloat(Game.wordsDOM.style.top);
|
||||
var gotoY = (wordsHeight<Game.WORDS_HEIGHT_BOTTOM) ? 0 : wordsHeight-Game.WORDS_HEIGHT_BOTTOM;
|
||||
gotoY = 80 - gotoY;
|
||||
var nextY = instant ? gotoY : currentY*0.9 + gotoY*0.1;
|
||||
Game.wordsDOM.style.top = (Math.round(nextY*10)/10)+"px";
|
||||
}else{
|
||||
Game.wordsDOM.style.top = Game.FORCE_TEXT_Y+"px";
|
||||
}
|
||||
};
|
||||
Game.WORDS_HEIGHT_BOTTOM = -1;
|
||||
(function(){
|
||||
const wordsObserver = new TickableObserver(() => {
|
||||
const offset = 80
|
||||
if(Game.WORDS_HEIGHT_BOTTOM < 0) Game.WORDS_HEIGHT_BOTTOM = 250;
|
||||
let advanceTextPosition = 0
|
||||
|
||||
// Either force the text somewhere...
|
||||
if(Game.FORCE_TEXT_Y != -1){
|
||||
Game.wordsDOM.style.transform = `translateY(${Game.FORCE_TEXT_Y}px)`;
|
||||
advanceTextPosition = Game.wordsDOM.clientHeight + Game.FORCE_TEXT_Y + 5
|
||||
}
|
||||
// Or calculate its position based on a window...
|
||||
else {
|
||||
const wordsHeight = Game.wordsDOM.clientHeight;
|
||||
let diff = wordsHeight - (Game.WORDS_HEIGHT_BOTTOM - offset)
|
||||
if(diff < 0) diff = 0
|
||||
Game.wordsDOM.style.transform = `translateY(${offset - diff}px)`;
|
||||
advanceTextPosition = offset - diff + wordsHeight + 5
|
||||
}
|
||||
|
||||
// "Instant mode" was only used for clearing... so lets just do it when it's clear?
|
||||
if(Game.wordsDOM.children.length == 0) flushElementTransitions(Game.wordsDOM);
|
||||
|
||||
// Also, move the click_to_advance DOM
|
||||
$('#click_to_advance').style.transform = `translateY(${Math.round(advanceTextPosition)}px)`;
|
||||
});
|
||||
|
||||
// The words UI depends on these things:
|
||||
wordsObserver.watch(() => Game.FORCE_TEXT_Y);
|
||||
wordsObserver.watch(() => Game.WORDS_HEIGHT_BOTTOM);
|
||||
wordsObserver.watch(() => Game.wordsDOM.children.length);
|
||||
Game.updateText = () => wordsObserver.tick();
|
||||
|
||||
})()
|
||||
|
||||
// CLEAR TEXT
|
||||
Game.clearText = function(){
|
||||
Game.wordsDOM.innerHTML = "";
|
||||
Game.updateText(true);
|
||||
Game.updateText();
|
||||
};
|
||||
|
||||
Game.clearAll = function(){
|
||||
Game.clearText();
|
||||
Game.resetScene();
|
||||
|
@ -623,7 +658,8 @@ Game.executeText = function(line){
|
|||
span.innerHTML = "";
|
||||
span.style.display = "block";
|
||||
var iconName = word.slice(1,-1)
|
||||
var icon = Library.images["fear_"+iconName];
|
||||
var icon = new Image();
|
||||
icon.src = Library.images["fear_"+iconName].hackSrc;
|
||||
div.children[i].appendChild(icon);
|
||||
icon.style.display = "block";
|
||||
if(speaker!="i"){
|
||||
|
@ -771,12 +807,12 @@ Game.executeChoice = function(line){
|
|||
}
|
||||
|
||||
// Add choice, animated!
|
||||
div.style.top = "150px";
|
||||
div.classList.add("hidden");
|
||||
Game.choicesDOM.appendChild(div);
|
||||
setTimeout(function(){
|
||||
div.style.top = "0px";
|
||||
requestAnimationFrame(function(){
|
||||
div.classList.remove("hidden");
|
||||
sfx("ui_show_choice", {volume:0.4});
|
||||
},10);
|
||||
});
|
||||
|
||||
// Or... FORCE
|
||||
if(Game.OVERRIDE_FONT_SIZE){
|
||||
|
@ -1019,24 +1055,29 @@ Game.resetScene = function(){
|
|||
Game.resetScene();
|
||||
|
||||
// Update & draw all the kids!
|
||||
Game.updateCanvas = function(DELTA){
|
||||
Game.updateCanvas = function(delta){
|
||||
|
||||
// UPDATING:
|
||||
// -------------------------------------------------------------
|
||||
for(const child of Game.scene.children) {
|
||||
if(child.update) child.update(delta);
|
||||
}
|
||||
|
||||
// RENDERING:
|
||||
// -------------------------------------------------------------
|
||||
|
||||
// For retina
|
||||
var ctx = Game.context;
|
||||
ctx.clearRect(0,0,ctx.canvas.width,ctx.canvas.height);
|
||||
ctx.save();
|
||||
ctx.scale(2,2);
|
||||
ctx.scale(2, 2);
|
||||
|
||||
// Update/Draw all kids
|
||||
Game.scene.children.forEach(function(child){
|
||||
if(child.update) child.update(DELTA);
|
||||
});
|
||||
Game.scene.children.forEach(function(child){
|
||||
child.draw(ctx, DELTA);
|
||||
});
|
||||
|
||||
for(const child of Game.scene.children) child.draw(ctx, delta);
|
||||
|
||||
|
||||
// Restore
|
||||
ctx.restore();
|
||||
ctx.scale(0.5, 0.5);
|
||||
|
||||
// Draw HP
|
||||
HP.draw();
|
||||
|
|
|
@ -38,16 +38,11 @@ function HitPoints(){
|
|||
|
||||
// Show/hide
|
||||
self.show = function(){
|
||||
self.dom.style.top = "0px";
|
||||
self.dom.classList.add('show');
|
||||
};
|
||||
self.hide = function(instant){
|
||||
if(instant){
|
||||
self.dom.style.display = "none";
|
||||
setTimeout(function(){
|
||||
self.dom.style.display = "block";
|
||||
},2000);
|
||||
}
|
||||
self.dom.style.top = "-100px";
|
||||
self.dom.classList.remove('show');
|
||||
if(instant) flushElementTransitions(self.dom);
|
||||
};
|
||||
subscribe("hp_show", self.show);
|
||||
subscribe("hp_hide", self.hide);
|
||||
|
@ -106,7 +101,8 @@ function HitPoints(){
|
|||
self.rightRed = self.rightWhite = 1;
|
||||
self.drawHalf = function(ctx, isRight){
|
||||
|
||||
ctx.save();
|
||||
var movedY = 0;
|
||||
let oldCompositeOp = ctx.globalCompositeOperation;
|
||||
|
||||
// Which side?
|
||||
var side = isRight ? "right" : "left";
|
||||
|
@ -120,6 +116,7 @@ function HitPoints(){
|
|||
var amp = self[side+"Shake"]/7;
|
||||
var shakeY = Math.sin(self[side+"Shake"]*1.3)*amp;
|
||||
ctx.translate(0,shakeY);
|
||||
movedY += shakeY;
|
||||
self[side+"Shake"]--;
|
||||
}
|
||||
|
||||
|
@ -174,14 +171,14 @@ function HitPoints(){
|
|||
}
|
||||
|
||||
// Restore
|
||||
ctx.restore();
|
||||
ctx.translate(0, -movedY);
|
||||
ctx.globalCompositeOperation = oldCompositeOp;
|
||||
|
||||
};
|
||||
self.draw = function(){
|
||||
|
||||
var ctx = self.context;
|
||||
ctx.clearRect(0,0,ctx.canvas.width,ctx.canvas.height);
|
||||
ctx.save();
|
||||
ctx.scale(2,2);
|
||||
|
||||
// Draw Left & Right Sides
|
||||
|
@ -198,7 +195,7 @@ function HitPoints(){
|
|||
var sx=0, sy=200*3, sw=720, sh=200;
|
||||
ctx.drawImage(self.image, sx,sy,sw,sh, 0,0,sw/2,sh/2);
|
||||
|
||||
ctx.restore();
|
||||
ctx.scale(0.5, 0.5);
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -48,14 +48,16 @@ Loader.addImages = function(imageConfigs){
|
|||
};
|
||||
Loader.loadImage = function(imageConfig){
|
||||
return new RSVP.Promise(function(resolve){
|
||||
var img = new Image();
|
||||
var id = imageConfig.id;
|
||||
Library.images[id] = img; // ADD TO LIBRARY
|
||||
img.onload = function(){
|
||||
publish("assetLoaded");
|
||||
resolve();
|
||||
}
|
||||
img.src = imageConfig.src;
|
||||
const id = imageConfig.id;
|
||||
fetch(imageConfig.src)
|
||||
.then(response => response.blob())
|
||||
.then(blobData => createImageBitmap(blobData))
|
||||
.then(bitmap => {
|
||||
bitmap.hackSrc = imageConfig.src;
|
||||
Library.images[id] = bitmap;
|
||||
publish("assetLoaded");
|
||||
resolve();
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
@ -111,11 +111,6 @@ Loader.addSounds([
|
|||
}
|
||||
}
|
||||
|
||||
// Also, move click_to_advance DOM
|
||||
var wordsTop = parseInt($("#game_words").style.top);
|
||||
var wordsHeight = $("#game_words").getBoundingClientRect().height;
|
||||
click_to_advance.style.top = Math.round(wordsTop+wordsHeight+5) + "px";
|
||||
|
||||
};
|
||||
|
||||
var _timeoutCallbacks = [];
|
||||
|
|
|
@ -82,8 +82,6 @@ function Sprite(config){
|
|||
if(!self.visible) return; // nah
|
||||
if(self.alpha==0) return; // also nah
|
||||
|
||||
ctx.save();
|
||||
|
||||
// Which part of image to draw?
|
||||
var sx = self.currentFrame % self.grid.width;
|
||||
var sy = Math.floor((self.currentFrame - sx)/self.grid.width);
|
||||
|
@ -104,6 +102,7 @@ function Sprite(config){
|
|||
ctx.rotate(self.rotation);
|
||||
|
||||
// Alpha
|
||||
var oldAlpha = ctx.globalAlpha;
|
||||
ctx.globalAlpha = self.alpha;
|
||||
|
||||
// Draw it!
|
||||
|
@ -113,7 +112,10 @@ function Sprite(config){
|
|||
-self.anchor.x, -self.anchor.y, fw/2, fh/2
|
||||
);
|
||||
|
||||
ctx.restore();
|
||||
ctx.rotate(-self.rotation);
|
||||
ctx.scale(1 / scaleX, 1 / scaleY);
|
||||
ctx.translate(-dx, -dy);
|
||||
ctx.globalAlpha = oldAlpha;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -35,11 +35,9 @@ function BG_Intermission(STAGE){
|
|||
};
|
||||
|
||||
self.draw = function(ctx){
|
||||
ctx.save();
|
||||
self.bgSprite.draw(ctx);
|
||||
self.youwinSprite.draw(ctx);
|
||||
self.bbSprite.draw(ctx);
|
||||
ctx.restore();
|
||||
};
|
||||
|
||||
var _subscriptions = [];
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Safari and Edge polyfill for createImageBitmap
|
||||
* https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/createImageBitmap
|
||||
*
|
||||
* Support source image types Blob and ImageData.
|
||||
*
|
||||
* From: https://dev.to/nektro/createimagebitmap-polyfill-for-safari-and-edge-228
|
||||
* Updated by Yoan Tournade <yoan@ytotech.com>
|
||||
*/
|
||||
if (!('createImageBitmap' in window)) {
|
||||
window.createImageBitmap = async function (data) {
|
||||
return new Promise((resolve,reject) => {
|
||||
let dataURL;
|
||||
if (data instanceof Blob) {
|
||||
dataURL = URL.createObjectURL(data);
|
||||
} else if (data instanceof ImageData) {
|
||||
const canvas = document.createElement('canvas');
|
||||
const ctx = canvas.getContext('2d');
|
||||
canvas.width = data.width;
|
||||
canvas.height = data.height;
|
||||
ctx.putImageData(data,0,0);
|
||||
dataURL = canvas.toDataURL();
|
||||
} else {
|
||||
throw new Error('createImageBitmap does not handle the provided image source type');
|
||||
}
|
||||
const img = document.createElement('img');
|
||||
img.addEventListener('load',function () {
|
||||
resolve(this);
|
||||
});
|
||||
img.src = dataURL;
|
||||
});
|
||||
};
|
||||
}
|
|
@ -4,4 +4,12 @@ Math.TAU = Math.PI*2;
|
|||
// The poor man's jQuery
|
||||
function $(query){
|
||||
return document.querySelector(query);
|
||||
}
|
||||
|
||||
// Flush an element's transitions
|
||||
function flushElementTransitions(element){
|
||||
if(typeof element == "string") element = $(element);
|
||||
element.classList.add('clear_transition')
|
||||
element.clientHeight;
|
||||
element.classList.remove('clear_transition');
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
|
||||
/*
|
||||
Lots of things in this game were written to happen every frame, but they often don't need to!
|
||||
|
||||
Here's something I call a `Tickable Obersver`, it lets you (every frame) check if some values
|
||||
have changed, and only then run the expensive code!
|
||||
|
||||
It's kinda like an observable, but it's tiny and runs on a frame-by-frame basis!
|
||||
- Spacie
|
||||
*/
|
||||
|
||||
class TickableObserver {
|
||||
|
||||
constructor(event){
|
||||
this.depCount = 0;
|
||||
this.previousValues = [];
|
||||
this.watchers = [];
|
||||
this.event = event;
|
||||
}
|
||||
|
||||
tick(){
|
||||
for(let i = 0; i < this.depCount; i++){
|
||||
if(this.watchers[i]() != this.previousValues[i]){
|
||||
this.previousValues[i] = this.watchers[i]();
|
||||
if(this.event != null) return this.event();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
watch(watcher){
|
||||
this.depCount++;
|
||||
this.watchers.push(watcher);
|
||||
this.previousValues.push(null);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
// Load assets
|
||||
Loader.addScenes([
|
||||
|
||||
//"scenes/PROMO.md",
|
||||
"scenes/intro.md",
|
||||
"scenes/act1.md",
|
||||
"scenes/intermission.md",
|
||||
|
|
113
styles/game.css
113
styles/game.css
|
@ -1,11 +1,53 @@
|
|||
html,body{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
* {
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
body{
|
||||
|
||||
body {
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
overflow: hidden;
|
||||
margin:0;
|
||||
background: #111;
|
||||
font-size: 20px;
|
||||
font-family: Helvetica, Arial, sans-serif;
|
||||
font-weight: 100;
|
||||
line-height: 1.3em;
|
||||
}
|
||||
|
||||
/******************************************************************************************************
|
||||
|
||||
DEBUGGING
|
||||
|
||||
******************************************************************************************************/
|
||||
|
||||
body:not(.show_debug) .debug {
|
||||
display: none;
|
||||
}
|
||||
|
||||
body.show_debug #game_container * {
|
||||
outline: 1px solid red;
|
||||
}
|
||||
|
||||
#section_debug_list {
|
||||
position: absolute;
|
||||
background: #fff;
|
||||
padding: 20px;
|
||||
height: 500px;
|
||||
overflow-y: scroll;
|
||||
transition: all 0.2s;
|
||||
font-family: monospace;
|
||||
opacity: 0.2;
|
||||
transform: translateX(-95%);
|
||||
}
|
||||
|
||||
#section_debug_list:hover {
|
||||
transform: none;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/******************************************************************************************************
|
||||
|
@ -14,36 +56,25 @@ MAIN GAME
|
|||
|
||||
******************************************************************************************************/
|
||||
|
||||
div{ /*, #game_words, #game_choices, #paused, #options, #loading, #gear, #about, #click_to_advance{*/
|
||||
-webkit-user-select: none; /* Safari 3.1+ */
|
||||
-moz-user-select: none; /* Firefox 2+ */
|
||||
-ms-user-select: none; /* IE 10+ */
|
||||
user-select: none; /* Standard syntax */
|
||||
.clear_transition, .clear_transition * {
|
||||
transition: none !important;
|
||||
}
|
||||
|
||||
#game_container{
|
||||
|
||||
position: absolute;
|
||||
top:0; left:0; bottom:0; right:0;
|
||||
margin: auto;
|
||||
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 360px;
|
||||
height: 600px;
|
||||
background: #000;
|
||||
|
||||
font-size: 20px;
|
||||
font-family: Helvetica, Arial, sans-serif;
|
||||
font-weight: 100;
|
||||
line-height: 1.3em;
|
||||
|
||||
overflow: hidden;
|
||||
|
||||
}
|
||||
|
||||
#game_words{
|
||||
width: auto;
|
||||
position: relative;
|
||||
top: 80px;
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
overflow: hidden;
|
||||
transition: transform 0.5s;
|
||||
}
|
||||
|
||||
#game_words, #game_hp, #click_to_advance{
|
||||
|
@ -438,7 +469,6 @@ OPTIONS
|
|||
position: absolute;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
top: 254px;
|
||||
color:#fff;
|
||||
}
|
||||
|
||||
|
@ -848,7 +878,7 @@ DIALOGUEZ
|
|||
text-align: center;
|
||||
|
||||
}
|
||||
#game_choices > div{
|
||||
#game_choices > div {
|
||||
|
||||
width: 310px;
|
||||
margin: 0 auto 5px auto;
|
||||
|
@ -858,19 +888,14 @@ DIALOGUEZ
|
|||
position: relative;
|
||||
|
||||
border-radius: 20px;
|
||||
opacity: 1;
|
||||
|
||||
/* Spring OUT only */
|
||||
-webkit-transition: top 500ms cubic-bezier(0.350, 0.005, 0.370, 1); /* older webkit */
|
||||
-webkit-transition: top 500ms cubic-bezier(0.350, 0.005, 0.370, 1.390);
|
||||
-moz-transition: top 500ms cubic-bezier(0.350, 0.005, 0.370, 1.390);
|
||||
-o-transition: top 500ms cubic-bezier(0.350, 0.005, 0.370, 1.390);
|
||||
transition: top 500ms cubic-bezier(0.350, 0.005, 0.370, 1.390); /* custom */
|
||||
|
||||
-webkit-transition-timing-function: cubic-bezier(0.350, 0.005, 0.370, 1); /* older webkit */
|
||||
-webkit-transition-timing-function: cubic-bezier(0.350, 0.005, 0.370, 1.390);
|
||||
-moz-transition-timing-function: cubic-bezier(0.350, 0.005, 0.370, 1.390);
|
||||
-o-transition-timing-function: cubic-bezier(0.350, 0.005, 0.370, 1.390);
|
||||
transition-timing-function: cubic-bezier(0.350, 0.005, 0.370, 1.390); /* custom */
|
||||
/* TODO: Add vendor prefixes again, just removed them while working on css animation stuff [Spacie] */
|
||||
transition: transform 500ms cubic-bezier(0.350, 0.005, 0.370, 1.390), opacity 300ms ease-in-out;
|
||||
}
|
||||
#game_choices > div.hidden {
|
||||
transform: translateY(150px);
|
||||
opacity: 0;
|
||||
}
|
||||
#game_choices > div > * {
|
||||
pointer-events: none; /* so italics and stuff doesn't trigger sound */
|
||||
|
@ -942,13 +967,15 @@ canvas{
|
|||
top:0; left:0;
|
||||
}
|
||||
|
||||
#game_hp{
|
||||
#game_hp {
|
||||
position: absolute;
|
||||
width: 360px;
|
||||
height: 100px;
|
||||
top:-100px;
|
||||
left:0;
|
||||
transition: top 0.5s ease-in-out;
|
||||
transition: transform 0.5s ease-in-out;
|
||||
transform: translateY(-100px);
|
||||
}
|
||||
#game_hp.show {
|
||||
transform: none;
|
||||
}
|
||||
|
||||
/******************************************************************************************************
|
||||
|
@ -1027,4 +1054,4 @@ CORNER TEXT
|
|||
.corner-text {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue