This commit is contained in:
Nicky Case 2019-04-18 07:40:22 -04:00
parent 8095c0ed48
commit d5d9414630
25 changed files with 961 additions and 224 deletions

4
TODOS Normal file
View File

@ -0,0 +1,4 @@
- Why's there a long pause between scene transitions?
- black out, then show END SCREEN (for newsletter, patreon, in meantime my other games)

View File

@ -24,6 +24,7 @@
</html>
<!-- SCRIPTS -->
<script src="scripts/lib/helpers.js"></script>
<script src="scripts/lib/rsvp.min.js"></script>
<script src="scripts/lib/minpubsub.min.js"></script>
@ -32,6 +33,7 @@
<script src="scripts/game/Sprite.js"></script>
<script src="scripts/game/HP.js"></script>
<script src="scripts/game/BG_Anxiety.js"></script>
<script src="scripts/game/Character.js"></script>
<script src="scripts/intro/Intro_SceneSetup.js"></script>
<script src="scripts/intro/Intro_BG.js"></script>
@ -39,5 +41,6 @@
<script src="scripts/act1/Act1_SceneSetup.js"></script>
<script src="scripts/act1/Act1_Hong.js"></script>
<script src="scripts/act1/Act1_Beebee.js"></script>
<script src="scripts/act1/Act1_Outro_BG.js"></script>
<script src="scripts/main.js"></script>

View File

@ -1,3 +1,25 @@
# intro
`SceneSetup.intro();`
`SceneSetup.intro();`
# intro-play-button
[Play!](#intro-start)
[GAHHHH!](#meow)
[GAHHHHHHH!](#meow)
# intro-start
`publish("intro-to-game-1")`
n: THIS IS A HUMAN
(...600)
`clearText()`
(...300)
`publish("intro-to-game-2")`

47
scenes/test-outro.md Normal file
View File

@ -0,0 +1,47 @@
# act1i
n: *FINISH THEM*
[&lt; FIGHT: Destroy your phone! &gt;](#act1i_phone) `Game.OVERRIDE_CHOICE_LINE=true`
[&lt; FLIGHT: Curl up in a ball and cry! &gt;](#act1i_cry) `Game.OVERRIDE_CHOICE_LINE=true`
# act1i_phone
b: Your phone's giving you a panic attack!
`Game.OVERRIDE_TEXT_SPEED = 1.5;`
b: Punish it! Destroy your phone! Kill it!
```
Game.OVERRIDE_TEXT_SPEED = 2.5;
bb({body:"flail"});
_.act1_ending = "fight";
```
b: KILL IT KILL IT KILL IT KILL IT KILL IT KILL IT KILL IT KILL IT KILL IT KILL IT KILL IT KILL IT KILL I--
(#act1j)
# act1i_cry
b: The whole world is filled with danger!
`Game.OVERRIDE_TEXT_SPEED = 1.5;`
b: Do like the armadillo! Curl up into a ball for self-defense!
```
Game.OVERRIDE_TEXT_SPEED = 2.5;
bb({body:"flail"});
_.act1_ending = "flight";
```
b: CURL UP AND CRY CURL UP AND CRY CURL UP AND CRY CURL UP AND CRY CURL UP AND CRY CURL UP AND CRY CURL UP AND CR--
(#act1j)
# act1j
`SceneSetup.act1_outro()`

View File

@ -1,35 +1,31 @@
# act1
`SceneSetup.act1();`
`SceneSetup.act1()`
`publish("scene", ["add_beebee"])`
(...300)
n: QUICK, WARN THEM!
n: AND THIS IS YOU, THAT HUMAN'S ANXIETY
[You're eating alone for lunch! Again!](#act1a_alone)
[You're not studying while eating!](#act1a_study)
[That white bread's bad for you!](#act1a_bread)
# act1a_alone
b: DIEEEEEEEEEEEEEEEEEEE
`publish("hp_show")`
`HP.attackHong("20p", "alone")`
`Game.clearText()`
(...2000)
`bb("normal", "normal", "normal")`
`_.fifteencigs = true`
`attack("20p", "alone")`
n: YOU USED *FEAR OF BEING UNLOVED*
(#act1b)
# act1b
n: IT'S SUPER EFFECTIVE
`bb({eyes:"narrow", mouth:"normal"})`
b: I am best protector!
n: GOOD LUCK
n: GOOD LUCK
`hong({eyes:"annoyed", mouth:"smile"}, 0.05)`

View File

@ -1,11 +0,0 @@
/*****************************
Draw the parallax...
and also have the Anxiety Battle Background in it?
*****************************/
function BG_Act1(){
//
}

View File

@ -6,7 +6,7 @@ function Act1_Beebee(){
var self = this;
// Sprite!
// SPRITE CONFIG!
var spriteConfig = {
image: Library.images.act1_beebee,
grid:{
@ -29,10 +29,10 @@ function Act1_Beebee(){
"body_point_heart",
"body_point_sing",
"head_normal",
"head_normal_2",
"head_small",
"head_small_2",
"mouth_normal",
"mouth_normal_talk",
"mouth_small",
"mouth_small_talk",
"eyes_normal",
"eyes_normal_right",
@ -44,25 +44,63 @@ function Act1_Beebee(){
"eyes_pretty",
"eyes_wat",
"blank",
"body_panic*",
"body_panic_2*",
"body_scream_anger*",
"body_scream_anger_2*",
"body_scream*",
"body_scream_2*",
"body_panic",
"body_panic_2",
"body_scream_anger",
"body_scream_anger_2",
"body_scream",
"body_scream_2",
"body_flail*",
"body_flail2*",
"body_flail3*",
"body_flail4*",
"body_flail",
"body_flail_2",
"body_flail_3",
"body_flail_4",
// TODO: SMILE! "That's me!"
],
x: 270,
y: 390
x: 270-7.5,
y: 390+4.5
};
// ANIM LOOPS
var animLoops = [
{ target:"body", ifOnFrame:"flail*", wait:0.05, thenGoToFrame:"flail2*" },
{ target:"body", ifOnFrame:"flail2*", wait:0.05, thenGoToFrame:"flail3*" },
{ target:"body", ifOnFrame:"flail3*", wait:0.05, thenGoToFrame:"flail4*" },
{ target:"body", ifOnFrame:"flail4*", wait:0.05, thenGoToFrame:"flail*" }
];
// Inherit from Character!
Character.apply(self, [spriteConfig, animLoops]);
// Go To Frames!
self.gotoFrames({
body: "normal",
mouth: "small",
eyes: "wat",
});
var _subscriptions = [];
_subscriptions.push( subscribe("bb", self.gotoFrames) );
// Draw! Same as earlier except a lot of vibration
var ticker = 0;
var _oldDraw = self.draw;
self.characterSpeakerID = "b";
self.bounceHookes = 0.25; // loose
self.bounceDamp = 0.9; // loose
self.draw = function(ctx){
// Vibration!
ticker += 1/60;
self.characterSquash = 1 + Math.sin(ticker*Math.TAU*7)*0.01; // seven vibes per second
// Old Draw
_oldDraw.apply(self, arguments);
};
/*
self.body = new Sprite(spriteConfig);
self.head = new Sprite(spriteConfig);
self.eyes = new Sprite(spriteConfig);
@ -89,12 +127,6 @@ function Act1_Beebee(){
self.gotoFrames(bodyName, headName, eyesName);
});
/**
bb("point_heart", "normal_talk", "pretty")
**/
// First frame
// self.sprite.gotoFrameByName("normal");
@ -178,7 +210,6 @@ function Act1_Beebee(){
// Draw me!
self.sprite.draw(ctx);
*/
};
@ -193,12 +224,21 @@ function Act1_Beebee(){
}
if(fname=="scream"){
self.sprite.bounce = 1.6;
}*/
}
});
// Kill
self.kill = function(){
};*/
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
// Kill!
self.kill = function(){
_subscriptions.forEach(unsubscribe);
};
}

View File

@ -1,19 +1,13 @@
Loader.addImages([
{ id:"act1_hong", src:"sprites/act1/act1_hong.png" },
{ id:"fear_harm", src:"sprites/ui/fear_harm.png" },
{ id:"fear_alone", src:"sprites/ui/fear_alone.png" },
{ id:"fear_bad", src:"sprites/ui/fear_bad.png" }
{ id:"act1_hong", src:"sprites/act1/act1_hong.png" }
]);
function Act1_Hong(){
var self = this;
// Sprite!
self.sprite = new Sprite({
// SPRITE CONFIG!
var spriteConfig = {
image: Library.images.act1_hong,
grid:{
width: 4,
@ -29,18 +23,18 @@ function Act1_Hong(){
},
frameNames:[
"0_body_sammich_no_outline",
"0_body_sammich",
"0_eyes_neutral",
"0_eyes_concerned",
"0_eyes_shock",
"0_mouth_neutral",
"0_mouth_chew1",
"0_mouth_chew2",
"0_mouth_neutral_talk",
"0_mouth_shock",
"body_0_sammich_no_outline",
"body_0_sammich",
"eyes_0_neutral",
"eyes_0_concerned",
"eyes_0_shock",
"mouth_0_neutral",
"mouth_0_chew1",
"mouth_0_chew2",
"mouth_0_neutral_talk",
"mouth_0_shock",
"body_putaway",
"body_putaway*",
"body_phone1",
"body_phone2",
"eyes_neutral",
@ -60,48 +54,46 @@ function Act1_Hong(){
"mouth_anger",
"mouth_anger_talk",
"2_body_tired",
"2_body_fuck",
"2_body_you",
"2_body_sammich_eat",
"2_body_sammich_eaten",
"body_2_tired*",
"body_2_fuck*",
"body_2_you*",
"body_2_sammich_eat*",
"body_2_sammich_eaten",
"3_body_defeated1",
"3_body_defeated2",
"3_body_defeated3",
"3_body_defeated3_no_outline"
"body_3_defeated1*",
"body_3_defeated2*",
"body_3_defeated3*",
"body_3_defeated3_no_outline*"
],
x: 65,
y: 385
y: 385+14
};
// ANIM LOOPS
var animLoops = [
{ target:"body", ifOnFrame:"phone1", wait:0.5, thenGoToFrame:"phone2" },
{ target:"body", ifOnFrame:"phone2", wait:0.5, thenGoToFrame:"phone1" }
];
// Inherit from Character!
Character.apply(self, [spriteConfig, animLoops]);
// Go To Frames!
self.gotoFrames({
body: "phone1",
mouth: "neutral",
eyes: "neutral",
});
var _subscriptions = [];
_subscriptions.push( subscribe("hong", self.gotoFrames) );
_subscriptions.push( subscribe("attack_hong", self.showAttackedIcon) );
// Breathe normally
//self.sprite.breatheSpeed = 0.017;
//self.sprite.breatheAmp = 0.014;
// Draw
self.bounceHookes = 0.2; // stiff
self.bounceDamp = 0.8; // stiff
// Bounce slow
//self.sprite.bounceHookes = 0.1;
//self.sprite.bounceDamp = 0.9;
// First frame
self.sprite.gotoFrameByName("normal");
// Attack sprites
self.fears = {};
["harm","alone","bad"].forEach( function(fearName){
self.fears[fearName] = new Sprite({
image: Library.images["fear_"+fearName],
grid:{ width:1, height:1 },
frame:{ width:200, height:200 },
anchor:{ x:100/2, y:100/2 },
scale:0.75
});
} );
// HACK: frames
var _mouth_frame = "mouth_smile";
var _eyes_frame = "eyes_surprise";
/*
// Draw
var ticker = 0;
@ -111,16 +103,16 @@ function Act1_Hong(){
// Draw body FIRST
ticker++;
var bod_frame = (Math.floor(ticker/30)%2 == 0) ? "body_phone1" : "body_phone2"; // phone flickering
self.sprite.gotoFrameByName(bod_frame);
//var bod_frame = (Math.floor(ticker/30)%2 == 0) ? "body_phone1" : "body_phone2"; // phone flickering
self.sprite.gotoFrameByName("0_body_sammich");
self.sprite.draw(ctx);
// Draw mouth next
self.sprite.gotoFrameByName(_mouth_frame);
self.sprite.gotoFrameByName("0_mouth_neutral");
self.sprite.draw(ctx);
// Draw eyes finally
self.sprite.gotoFrameByName(_eyes_frame);
self.sprite.gotoFrameByName("0_eyes_neutral");
self.sprite.draw(ctx);
// Draw attacked icon
@ -189,4 +181,15 @@ function Act1_Hong(){
self.kill = function(){
};
*/
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
// Kill!
self.kill = function(){
_subscriptions.forEach(unsubscribe);
};
}

View File

@ -0,0 +1,299 @@
Loader.addImages([
{ id:"act1_end", src:"sprites/act1/act1_end.png" }
]);
function BG_Act1_Outro(){
var self = this;
// Sprites!
self.logoSprite = new Sprite({
image: Library.images.intro_logo,
grid:{ width:1, height:1 },
frame:{ width:720, height:900 },
});
var spriteConfig = {
image: Library.images.intro_bg,
grid:{
width: 2,
height: 3
},
frame:{
width: 1200,
height: 900
},
anchor:{
x: 0,
y: 0
},
frameNames:[
"sky",
"clouds",
"buildings",
"grass",
"stump",
"blackout"
],
x: 0,
y: 0
};
self.layers = [];
["sky","clouds","buildings","grass","stump","blackout"].forEach(function(layerName){
var sprite = new Sprite(spriteConfig);
sprite.gotoFrameByName(layerName);
self.layers.push(sprite);
});
// HONG
var hongSpriteConfig = {
image: Library.images.act1_end,
grid:{
width: 4,
height: 12
},
frame:{
width: 1100,
height: 480
},
anchor:{
x: 560/2,
y: 370/2
},
x: 560/2,
y: 370/2
};
var craterSprite = new Sprite(hongSpriteConfig);
self.layers.push(craterSprite);
var hongSprite = new Sprite(hongSpriteConfig);
self.layers.push(hongSprite);
// DRAW
var BG_WIDTH = 360;
var BG_HEIGHT = 450;
var PARALLAXES = [
0, // sky
0.1, // clouds
0.25, // buildings
0.48, // grass
1.0, // stump
0, // blackout
1.0, // crater
1.0, // HONG
];
var OFFSETS = [
0,
0, // clouds
0,
0,
20,
0,
20,
20
];
////////////////////////////////
// WHICH ANIM CYCLE TO USE? ////
////////////////////////////////
var ANIM_TO_USE = _.act1_ending || "fight";
var ticker = 0;
var frameTicker = ticker;
var parallaxTicker = 1;
self.draw = function(ctx){
// TICKER
ticker += 1/60;
// CLOUD OFFSET
OFFSETS[1] = -80 + ticker*3;
// PARALLAX
var parallax = 0;
if(GAME_TRANSITION==0){
parallaxTicker -= 2/60; // 1 to 0 in 1/2 second
if(parallaxTicker<0) parallaxTicker = 0;
self.layers[5].alpha = parallaxTicker; // blackout alpha
// 0 to -180 in one second, smoothed
var t = Math.cos(parallaxTicker*Math.TAU/2); // 1 to -1
t = (1-t)/2; // 0 to 1
parallax = -t*215;
}
// Smoking crater & Hong frame
frameTicker += 1/60;
if(ANIM_TO_USE == "fight"){
var frame = findFrameOnTicker(SMOKING_CRATER, frameTicker);
craterSprite.gotoFrame(frame);
var frame = findFrameOnTicker(HONG_FRAMES_FIGHT, frameTicker);
hongSprite.gotoFrame(frame);
}else{
craterSprite.visible = false;
var frame = findFrameOnTicker(HONG_FRAMES_FLIGHT, frameTicker);
hongSprite.gotoFrame(frame);
}
// If pre frameTicker=90/30, Hong is shaking like Beebee!
if(frameTicker<90/30){
hongSprite.squash = 1 + Math.sin(ticker*Math.TAU*7)*0.01; // seven vibes per second
}else{
hongSprite.squash = 1;
}
// Draw all!
for(var i=0; i<self.layers.length; i++){
var layer = self.layers[i];
layer.x = PARALLAXES[i] * parallax - OFFSETS[i];
if(i>=6){ // the HONG & SMOKING layer
layer.x += 560/2 + 20; // Hack, don't know why.
layer.y = 210 + 370/2;
}
layer.draw(ctx);
}
// NEXT SCENE?
/*if(frame==26){
Game.goto("act1");
}*/
};
var GAME_TRANSITION = 0;
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
// Find it!
var findFrameOnTicker = function(frameArray, ticker){
var lastFrame;
for(var i=0; i<frameArray.length; i++){
var f = frameArray[i];
if(f[1]<=ticker) lastFrame = f[0];
}
return lastFrame;
};
var convertFrames = function(frameArray){
return frameArray.map(function(frame){
var f = frame.split("-");
return [parseInt(f[0])-1, parseInt(f[1])/30]; // subtract 1 from frame, convert to seconds
});
};
var addLoop = function(frameArray, startF, startS, frameLength, interval){
var f = startF-1;
var s = startS/30;
var frameStart = f;
for(var i=0; i<200; i++){ // 200 just in case
frameArray.push([f,s]);
f = ((f-frameStart)+1)%frameLength + frameStart; // swap frame
s += interval/30;
}
};
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
// ANIMATE HONG, THE FRAMES!
var HONG_FRAMES_FIGHT = [
"1-0",
"2-3",
"3-5",
"4-7",
"30-90",
"31-120",
"32-135",
"33-137",
"34-139",
"35-142",
"36-145",
"37-170",
"38-185",
//"37-200", // LOOP every 15
];
HONG_FRAMES_FIGHT = convertFrames(HONG_FRAMES_FIGHT);
addLoop(HONG_FRAMES_FIGHT, 37, 185+15, 2, 15); // add in the loop
var HONG_FRAMES_FLIGHT = [
"1-0",
"2-3",
"3-5",
"4-7",
"5-90",
"6-120",
"7-122",
"8-124",
"9-126",
"10-129",
"11-132",
"12-134",
"13-136",
"14-138",
"15-140",
"16-143",
"17-145",
"18-147",
"19-149",
"20-151",
"21-153",
"22-155",
"23-157",
"21-159",
"22-161",
"23-163",
"21-165",
"22-167",
"23-169",
"21-171",
"22-173",
"23-175",
"21-177",
"22-179",
"23-181",
"24-183",
"25-185",
"26-187",
"27-189",
"28-191",
"29-193"
];
HONG_FRAMES_FLIGHT = convertFrames(HONG_FRAMES_FLIGHT);
addLoop(HONG_FRAMES_FLIGHT, 27, 193+2, 3, 2); // add in the loop
var SMOKING_CRATER = [
"46-0", // BLANK
"39-135", // BAM
"40-137",
"41-142",
"42-147",
"43-152",
"44-157"
];
SMOKING_CRATER = convertFrames(SMOKING_CRATER);
addLoop(SMOKING_CRATER, 40, 157+5, 5, 5); // add in loop
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
// Kill!
self.kill = function(){
_subscriptions.forEach(unsubscribe);
};
}

View File

@ -12,12 +12,16 @@ SceneSetup.act1 = function(){
// Beebee
var beebee = new Act1_Beebee();
subscribe("scene", function(command){
switch(command){
case "add_beebee":
Game.scene.children.push(beebee);
break;
}
});
Game.scene.children.push(beebee);
};
SceneSetup.act1_outro = function(){
clearText();
Game.resetScene();
// Background
var bg = new BG_Act1_Outro();
Game.scene.children.push(bg);
};

View File

@ -89,19 +89,26 @@ function BG_Anxiety(){
self.boxes.push(box);
}
var allBoxAlpha = 0;
self.draw = function(ctx){
// A big ol' black box
ctx.fillStyle = "#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.updateBox(box);
});
self.boxes.forEach(function(box){
self.drawBox(box, ctx);
});
ctx.globalAlpha = 1;
};

218
scripts/game/Character.js Normal file
View File

@ -0,0 +1,218 @@
/********************************
Character Architecture:
* Layers: Body + Mouth + Eyes
* Can animate each layer independently
* Alternate mouth when talking
* Short animation loops
* [star] in body means show no eyes/mouth
*********************************/
Loader.addImages([
{ id:"fear_harm", src:"sprites/ui/fear_harm.png" },
{ id:"fear_alone", src:"sprites/ui/fear_alone.png" },
{ id:"fear_bad", src:"sprites/ui/fear_bad.png" }
]);
function Character(spriteConfig, animLoops){
var self = this;
self.spriteConfig = spriteConfig;
self.animLoops = animLoops || [];
// Sprite!
self.layers = {};
["body","mouth","eyes"].forEach(function(layerName){
self.layers[layerName] = new Sprite(spriteConfig);
});
// Attack sprites (Hong only, really)
self.fears = {};
["harm","alone","bad"].forEach( function(fearName){
self.fears[fearName] = new Sprite({
image: Library.images["fear_"+fearName],
grid:{ width:1, height:1 },
frame:{ width:200, height:200 },
anchor:{ x:100/2, y:100/2 },
scale:0.75
});
} );
// Go To Frames
self.bounce = 1;
self.bounceVel = 0;
self.bounceHookes = 0.2;
self.bounceDamp = 0.8;
self.characterFrames = {};
self.gotoFrames = function(args, bounce){
// Bounce?
if(bounce!==undefined){
self.bounce += bounce;
}
// Gimme those args
if(args.body){
if(!self.layers.body.doesFrameNameExist("body_"+args.body)) args.body+="*"; // add * if missing
self.characterFrames.body = args.body;
}
if(args.mouth) self.characterFrames.mouth = args.mouth;
if(args.eyes) self.characterFrames.eyes = args.eyes;
if(args.body){
var bodyName = "body_"+args.body;
self.layers.body.gotoFrameByName(bodyName);
self.characterFrames.body = args.body;
}
if(args.mouth){
var mouthName = "mouth_"+args.mouth;
self.layers.mouth.gotoFrameByName(mouthName);
}
if(args.eyes){
var eyesName = "eyes_"+args.eyes;
self.layers.eyes.gotoFrameByName(eyesName);
}
// Go go go
var l = self.layers;
var c = self.characterFrames;
l.body.gotoFrameByName( "body_"+c.body );
l.mouth.gotoFrameByName( "mouth_"+c.mouth );
l.eyes.gotoFrameByName( "eyes_"+c.eyes );
};
// Draw
self.characterSpeakerID = "derp";
self.characterSquash = 1;
self.draw = function(ctx){
var fname;
var l = self.layers;
var c = self.characterFrames;
// Attacked? SHAKE WHOLE CONTEXT
ctx.save();
if(IVE_BEEN_ATTACKED){
var shakeDuration = 0.6;
if(attackedTimer<shakeDuration){
var shakeAmp = (shakeDuration-attackedTimer)/shakeDuration;
var shakeX = Math.sin(attackedTimer*Math.TAU*10)*shakeAmp*10;
ctx.translate(shakeX, 0);
}
}
// GLOBAL PARAMS: SQUASH * BOUNCE
self.bounce += self.bounceVel;
self.bounceVel += (1-self.bounce)*self.bounceHookes;
self.bounceVel *= self.bounceDamp;
var totalSquash = self.characterSquash * self.bounce;
l.body.squash = l.mouth.squash = l.eyes.squash = totalSquash;
// Anim Loop rules!
self.runAnimLoopRules();
// Body
l.body.draw(ctx);
// If body is NOT on a "*" frame...
if(l.body.currentFrameName.indexOf("*")<0){
// Mouth
if(Game.WHO_IS_SPEAKING==self.characterSpeakerID){
// If I'm talking, switch to a talking mouth!
var mouthTalkFrame = "mouth_"+c.mouth+"_talk";
if( l.mouth.doesFrameNameExist(mouthTalkFrame) ){
l.mouth.gotoFrameByName(mouthTalkFrame);
}
}else{
// If I'm not talking & my mouth is in the talk position, switch it back!
var isMyMouthTalking = (l.mouth.currentFrameName.indexOf("_talk")>=0);
if(isMyMouthTalking){
l.mouth.gotoFrameByName( "mouth_"+c.mouth );
}
}
l.mouth.draw(ctx);
// Eyes
l.eyes.draw(ctx);
}
// Draw attacked icon
if(IVE_BEEN_ATTACKED){
var icon = self.fears[attackedIconShown];
icon.draw(ctx);
attackedTimer += 1/60;
if(attackedTimer>1.5){ // 1s
icon.y -= 1;
icon.alpha -= 1/15;
if(icon.alpha<0){
attackedIconShown = null;
IVE_BEEN_ATTACKED = false;
}
}
}
ctx.restore();
};
// Anim Loop logic!
self.animLoops.forEach(function(rule){
rule.active = false;
rule.countdown = -1;
});
self.runAnimLoopRules = function(){
for(var i=0; i<self.animLoops.length; i++){
// Find target
var rule = self.animLoops[i];
var target = self.layers[rule.target];
// Activate rule if not already
if(target.currentFrameName == rule.target+"_"+rule.ifOnFrame){
if(!rule.active){
rule.active = true;
rule.countdown = rule.wait;
}
}else{
rule.active = false;
}
// Countdown... and ACTIVATE!
if(rule.active){
rule.countdown -= 1/60;
if(rule.countdown<=0){
target.gotoFrameByName(rule.target+"_"+rule.thenGoToFrame);
rule.active = false;
return; // DONE! No more.
}
}
}
};
// Show attacked icon!
var IVE_BEEN_ATTACKED = false;
var attackedIconShown = null;
var attackedTimer = 0;
self.showAttackedIcon = function(type){
IVE_BEEN_ATTACKED = true;
attackedIconShown = type;
var icon = self.fears[attackedIconShown];
icon.x = 82;
icon.y = 230;
icon.alpha = 1;
attackedTimer = 0;
};
}

View File

@ -2,26 +2,28 @@ window._ = {};
window.Game = {};
Game.sections = {};
Game.startSectionID = null;
Game.dom = document.querySelector("#game_container");
Game.wordsDOM = document.querySelector("#game_words");
Game.choicesDOM = document.querySelector("#game_choices");
Game.canvas = document.querySelector("#game_canvas");
Game.startSectionID = null;
Game.queue = [];
window.SceneSetup = {}; // A big ol' singleton class that just makes it easy to create scenes.
Game.dom = $("#game_container");
Game.wordsDOM = $("#game_words");
Game.choicesDOM = $("#game_choices");
Game.canvas = $("#game_canvas");
// HACK TODO
window.attack = function(){};
window.miss = function(){};
window.SceneSetup = {}; // A big ol' singleton class that just makes it easy to create scenes.
// HELPER FUNCS
window.bb = function(){
publish("bb", arguments);
};
window.hong = function(){
publish("hong", arguments);
};
window.attack = function(damage, type){
publish("attack", ["hong", damage, type]);
};
window.attackBB = function(damage, type){
publish("attack", ["bb", damage, type]);
};
// Init
Game.init = function(){
@ -64,9 +66,6 @@ Game.parseSceneMarkdown = function(md){
id: id,
lines: lines
};
if(!Game.startSectionID){
Game.startSectionID = id;
}
});
@ -78,7 +77,6 @@ Game.parseSceneMarkdown = function(md){
Game.start = function(){
window._ = {}; // global var, reset
Game.goto(Game.startSectionID);
};
Game.update = function(){
@ -109,7 +107,7 @@ Game.update = function(){
// PAUSING THE GAME
Game.paused = false;
Game.pausedDOM = document.querySelector("#paused");
Game.pausedDOM = $("#paused");
Game.pause = function(){
Game.paused = true;
Game.pausedDOM.style.display = "block";
@ -239,9 +237,10 @@ Game.updateText = function(){
Game.clearText = function(){
Game.wordsDOM.innerHTML = ""; // TODO HACK make prettier
};
window.clearText = Game.clearText;
// Execute text! Just add it to text DOM.
Game.TEXT_SPEED = 60;
Game.TEXT_SPEED = 70;
Game.OVERRIDE_TEXT_SPEED = 1;
Game.WHO_IS_SPEAKING = null; // "h", "b", "n" etc...
Game.CURRENT_SPEAKING_SPEED = 1;
@ -456,10 +455,17 @@ Game.executeChoice = function(line){
};
// Add choice, animated!
div.style.top = "150px";
Game.choicesDOM.appendChild(div);
setTimeout(function(){
div.style.top = "0px";
},0);
// Return immediate promise
return Game.immediatePromise();
// Wait a bit before adding new line
return new RSVP.Promise(function(resolve){
Game.setTimeout(resolve, 100);
});
}
@ -584,9 +590,21 @@ Game.canvas.style.height = Game.canvas.height/2 + "px";
Game.context = Game.canvas.getContext("2d");
// A blank scene
Game.scene = null;
Game.resetScene = function(){
// Kill all of previous scene
if(Game.scene){
Game.scene.children.forEach(function(child){
if(child.kill) child.kill();
});
if(Game.scene.kill) Game.scene.kill();
}
// New scene!
Game.scene = {};
Game.scene.children = [];
};
Game.resetScene();

View File

@ -8,7 +8,7 @@ function HitPoints(){
var self = this;
// My DOM & canvas
self.dom = document.querySelector("#game_hp");
self.dom = $("#game_hp");
self.canvas = document.createElement("canvas");
self.canvas.width = 360 * 2;
self.canvas.height = 100 * 2;
@ -27,6 +27,16 @@ function HitPoints(){
};
self.reset();
// Show/hide
self.show = function(){
self.dom.style.top = "0px";
};
self.hide = function(){
self.dom.style.top = "-100px";
};
subscribe("hp_show", self.show);
subscribe("hp_hide", self.hide);
// Attack!
self.doDamage = function(str, target){
@ -46,16 +56,18 @@ function HitPoints(){
}
};
// TODO: SHAKING BASED ON AMOUNT OF ABSOLUTE DAMAGE.
self.attackHong = function(str,type){
self.doDamage(str, "hong");
self.leftShake = 30;
publish("hong",["attacked",type]);
};
self.attackBeebee = function(str){
self.doDamage(str, "beebee");
self.rightShake = 30;
};
// Who's been attacked?
subscribe("attack", function(target, damage, type){
if(target=="hong"){
self.doDamage(damage, "hong");
self.leftShake = 30;
publish("attack_hong",[type]);
}else{
self.doDamage(damage, "beebee");
self.rightShake = 30;
}
});
// Draw
self.leftShake = 0;

View File

@ -41,6 +41,7 @@ function Sprite(config){
// Sprite anchor
self.anchor = {};
config.anchor = config.anchor || {};
self.anchor.x = config.anchor.x || 0;
self.anchor.y = config.anchor.y || 0;
@ -56,6 +57,9 @@ function Sprite(config){
var index = self.frameNames.indexOf(name);
self.gotoFrame(index);
};
self.doesFrameNameExist = function(name){
return self.frameNames.indexOf(name)>=0;
};
self.gotoFrame(0);
// Other transformations
@ -65,44 +69,15 @@ function Sprite(config){
self.scale = config.scale || 1;
self.squash = config.squash || 1;
self.alpha = config.alpha || 1;
// Visible at all?
self.visible = true;
// Helpers
self.breathe = 0;
self.breatheSpeed = 0;
self.breatheAmp = 0;
self.bounce = 1;
self.bounceVel = 0;
self.bounceDamp = 0.8;
self.bounceHookes = 0.4;
self.shake = 0;
self.shakeAmp = 0;
self.shakeSpeed = 0;
self.shakeTimer = 0;
// Update breath/bounce, all that jazz.
self.update = function(){
// Breathe
self.breathe += self.breatheSpeed;
// Bounce
self.bounce += self.bounceVel;
self.bounceVel -= (self.bounce-1) * self.bounceHookes;
self.bounceVel *= self.bounceDamp;
// Shake
self.shakeTimer -= 1/60;
if(self.shakeTimer>0){
self.shake = Math.sin(self.shakeTimer*self.shakeSpeed*Math.PI*2) * self.shakeAmp;
}else{
self.shake = 0;
}
};
// Draw frame!
self.draw = function(ctx){
if(!self.visible) return; // nah
ctx.save();
// Which part of image to draw?
@ -112,15 +87,13 @@ function Sprite(config){
var fh = self.frame.height;
// Translate...
var dx = self.x + self.shake;
var dx = self.x;
var dy = self.y;
ctx.translate(dx, dy);
// Scale
var breatheSquash = 1 + Math.sin(self.breathe)*self.breatheAmp;
var totalSquash = self.squash * breatheSquash * self.bounce;
var scaleX = self.scale * totalSquash;
var scaleY = self.scale / totalSquash;
var scaleX = self.scale * self.squash;
var scaleY = self.scale / self.squash;
ctx.scale(scaleX, scaleY);
// Alpha

View File

@ -1,4 +1,5 @@
Loader.addImages([
{ id:"intro_logo", src:"sprites/intro/intro_logo.png" },
{ id:"intro_bg", src:"sprites/intro/intro_bg.png" },
{ id:"intro_anim", src:"sprites/intro/intro_anim.png" }
]);
@ -7,7 +8,12 @@ function BG_Intro(){
var self = this;
// Sprite!
// Sprites!
self.logoSprite = new Sprite({
image: Library.images.intro_logo,
grid:{ width:1, height:1 },
frame:{ width:720, height:900 },
});
var spriteConfig = {
image: Library.images.intro_bg,
grid:{
@ -28,17 +34,18 @@ function BG_Intro(){
"buildings",
"grass",
"stump",
"bag"
"blackout"
],
x: 0,
y: 0
};
self.layers = [];
["sky","clouds","buildings","grass","stump"].forEach(function(layerName){
["sky","clouds","buildings","grass","stump","blackout"].forEach(function(layerName){
var sprite = new Sprite(spriteConfig);
sprite.gotoFrameByName(layerName);
self.layers.push(sprite);
});
self.layers[5].alpha = 0; // blackout alpha is ZERO at start.
// HONG
var hongSpriteConfig = {
@ -68,8 +75,9 @@ function BG_Intro(){
0, // sky
0.1, // clouds
0.25, // buildings
0.5, // grass
0.48, // grass
1.0, // stump
0, // blackout
1.0, // HONG
];
var OFFSETS = [
@ -78,31 +86,92 @@ function BG_Intro(){
0,
0,
20,
0,
20
]
// TODO: CLOUDS MOVE BY SELF
var ticker = 0;
var ticker = 0; //16;//0;
var frameTicker = ticker;
var parallaxTicker = 0;
var SHOWN_PLAY_BUTTON = false;
var SHOWN_LOGO = false;
self.draw = function(ctx){
var parallax = 0; //= -(1+Math.sin(ticker))*90;
// TICKER
ticker += 1/60;
// CLOUD OFFSET
OFFSETS[1] = -80 + ticker*3
OFFSETS[1] = -80 + ticker*3;
// Animate Hong: Which frame?
var parallax = 0;
frameTicker += 1/60;
if(GAME_TRANSITION==0 || GAME_TRANSITION==1){
if(frameTicker>590/30){
if(GAME_TRANSITION==0) frameTicker = 381/30; // LOOP to NOM.
if(GAME_TRANSITION==1) frameTicker = 590/30; // STOP.
}
}
if(GAME_TRANSITION==2){
parallaxTicker += 1/60; // 0 to 1 in one second
if(parallaxTicker>1) parallaxTicker = 1;
self.layers[5].alpha = parallaxTicker; // blackout alpha
// 0 to -180 in one second, smoothed
var t = Math.cos(parallaxTicker*Math.TAU/2); // 1 to -1
t = (1-t)/2; // 0 to 1
parallax = -t*215;
}
// Hong frame
var frame = findFrameOnTicker(frameTicker);
hongSprite.gotoFrame(frame);
// Draw all!
for(var i=0; i<self.layers.length; i++){
var layer = self.layers[i];
layer.x = PARALLAXES[i] * parallax - OFFSETS[i];
layer.draw(ctx);
}
if(!SHOWN_LOGO && ticker>=530/30){
SHOWN_LOGO = true;
}
if(GAME_TRANSITION==0 && SHOWN_LOGO){
self.logoSprite.draw(ctx);
}
// Animate Hong
var frame = findFrameOnTicker(ticker);
hongSprite.gotoFrame(frame);
// Show Play Button
if(!SHOWN_PLAY_BUTTON && ticker>=590/30){
SHOWN_PLAY_BUTTON = true;
Game.goto("intro-play-button");
}
// NEXT SCENE?
if(frame==26){
Game.goto("act1");
}
};
////////////////////////////////////////////////////////
var GAME_TRANSITION = 0;
var _subscriptions = [];
_subscriptions.push(
subscribe("intro-to-game-1", function(){
GAME_TRANSITION = 1; // STOP LOOPING
})
);
_subscriptions.push(
subscribe("intro-to-game-2", function(){
frameTicker = 600/30;
GAME_TRANSITION = 2; // START PARALLAXING
})
);
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
// ANIMATE HONG, THE FRAMES!
@ -129,7 +198,18 @@ function BG_Intro(){
"15-430",
"14-440",
"15-450",
"16-470"
"16-470",
"17-600",
"18-603",
"19-606",
"20-609",
"21-612",
"22-615",
"23-618",
"24-621",
"25-624",
"26-627"
];
HONG_FRAMES = HONG_FRAMES.map(function(frame){
var f = frame.split("-");
@ -146,5 +226,14 @@ function BG_Intro(){
return lastFrame;
};
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
// Kill!
self.kill = function(){
_subscriptions.forEach(unsubscribe);
};
}

View File

@ -6,18 +6,4 @@ SceneSetup.intro = function(){
var bg = new BG_Intro();
Game.scene.children.push(bg);
// Hong
/*var hong = new Act1_Hong();
Game.scene.children.push(hong);
// Beebee
var beebee = new Act1_Beebee();
subscribe("scene", function(command){
switch(command){
case "add_beebee":
Game.scene.children.push(beebee);
break;
}
});*/
};

7
scripts/lib/helpers.js Normal file
View File

@ -0,0 +1,7 @@
// I'm twice the number you'll ever be
Math.TAU = Math.PI*2;
// The poor man's jQuery
function $(query){
return document.querySelector(query);
}

View File

@ -1,2 +0,0 @@
(function(e){function g(h){return"function"==typeof h}function k(h){"undefined"!=typeof setImmediate?setImmediate(h):"undefined"!=typeof process&&process.nextTick?process.nextTick(h):setTimeout(h,0)}e[0][e[1]]=function n(f){function a(a,g){null==b&&null!=a&&(b=a,l=g,c.length&&k(function(){for(var a=0;a<c.length;a++)c[a]()}));return b}var b,l=[],c=[];a.then=function(a,e){function m(){try{var c=b?a:e;if(g(c)){var f=function(a){var c,b=0;try{if(a&&("object"==typeof a||g(a))&&g(c=a.then)){if(a===d)throw new TypeError;
c.call(a,function(){b++||f.apply(void 0,arguments)},function(a){b++||d(!1,[a])})}else d(!0,arguments)}catch(e){b++||d(!1,[e])}};f(c.apply(void 0,l||[]))}else d(b,l)}catch(k){d(!1,[k])}}var d=n(f);null!=b?k(m):c.push(m);return d};f&&(a=f(a));return a}})("undefined"==typeof module?[window,"pinkySwear"]:[module,"exports"]);

View File

@ -1,9 +1,15 @@
// Load assets
Loader.addScenes([
//"scenes/intro.md"
"scenes/test.md"
"scenes/intro.md",
"scenes/test.md",
"scenes/test-outro.md"
]);
Loader.load().then(function(){
Game.init();
Game.start();
// Outro
SceneSetup.act1();
Game.goto("act1i");
});

Binary file not shown.

Before

Width:  |  Height:  |  Size: 250 KiB

After

Width:  |  Height:  |  Size: 244 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 362 KiB

After

Width:  |  Height:  |  Size: 463 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 155 KiB

After

Width:  |  Height:  |  Size: 156 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

View File

@ -197,6 +197,20 @@ body{
#game_choices > div{
padding: 0.25em 0;
cursor: pointer;
position: relative;
/* 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 */
}
#game_choices > div:hover{
background: rgba(255,255,255,0.25);
@ -218,5 +232,7 @@ canvas{
position: absolute;
width: 360px;
height: 100px;
top:0; left:0;
top:-100px;
left:0;
transition: top 0.5s ease-in-out;
}