stage-js
Version:
2D HTML5 Rendering and Layout
1,497 lines (1,292 loc) • 33.6 kB
JavaScript
import Stage from "../../src";
import Pool from "../common/pool";
import Randomize from "../common/randomize";
import "./textures";
const DEBUG = true;
let TOP = 0;
const PLAYFUL_COLORS = [
"#f2f2f2",
"#e1e1e1",
"#ff5a82",
"#ff5555",
"#db4cf4",
"#ff4edc",
"#7d7de8",
"#a163ff",
"#5ba2dd",
"#00b2de",
"#56dc8b",
"#62d962",
"#a0f667",
"#d6ff36",
"#ecff24",
"#fffe34",
"#ffda3e",
"#ffb843",
];
let Conf = {};
Conf.width = 240;
Conf.height = 120;
Conf.max = Conf.height * 0.47;
Conf.min = -Conf.max;
Conf.itemSpace = 20;
Conf.dotSpace = 6;
Conf.speed = 0.11;
Conf.acceleration = 0.0008 / 1000;
Conf.ups = ["power", "energy", "speed", "pull", "push", "slow"];
Conf.radius = {
Player: 6,
Dot: 1,
Power: 4,
Enemy: 5,
Coin: 6,
};
Conf.pull = {
Dot: 1,
Power: 0.1,
};
Conf.push = {
Enemy: 1,
};
Conf.coinsScale = {
1: 0.7,
2: 0.75,
5: 0.8,
10: 0.9,
20: 0.95,
50: 1,
100: 1.1,
};
let Format = {};
Format.coin = function (num) {
num = num || 0;
if (num < 10000) {
} else if (num < 1000000) {
num = ((num / 100) | 0) / 10 + "k";
} else {
num = ((num / 10000) | 0) / 100 + "M";
}
return "$" + num;
};
Format.k = function (num) {
num = num ? (num / 10) | 0 : 0;
if (num < 10000) {
} else if (num < 1000000) {
num = ((num / 100) | 0) / 10 + "k";
} else {
num = ((num / 10000) | 0) / 100 + "M";
}
return num;
};
let Data = {
key: "data",
};
Data.load = function () {
let key = Data.key;
DEBUG && console.log("game load", key);
try {
let data = localStorage.getItem(key);
DEBUG && console.log("game load", key, data);
return (data && JSON.parse(data)) || {};
} catch (e) {
console.log(e);
}
return {};
};
Data.save = function (data) {
let key = Data.key;
DEBUG && console.log("game save", key);
try {
data = JSON.stringify(data);
DEBUG && console.log("game save", key, data);
localStorage.setItem(key, data);
return true;
} catch (e) {
console.log(e);
}
return false;
};
let Sound = {};
Sound.play = function (name) {
// play sound here
};
function Game() {
let math = Stage.math;
let game = this;
this.data = Data.load();
let upgrades = this.data.upgrades || (this.data.upgrades = {});
for (let i = 0; i < Conf.ups.length; i++) {
let name = Conf.ups[i];
upgrades[name] = upgrades[name] || 0;
}
upgrades.flags = math.max(upgrades.flags || 0, 2);
let stats = (this.data.stats = this.data.stats || {});
stats.coins = stats.coins || 0;
stats.dist = stats.dist || 0;
let flags = (this.data.flags = this.data.flags || []);
this.upgrade = function (name) {
let price = this.price(name);
DEBUG && console.log("upgrade: " + name + " at " + price);
if (price > 0 && price <= stats.coins) {
stats.coins -= price;
upgrades[name] += 1;
Data.save(this.data);
}
this.uiUpgrade();
};
this.price = function (name) {
return math.pow(10, (upgrades[name] || 0) + 2);
};
let objects = [];
let inserted = [];
let pointer = {};
let time = 0;
let lastItem = 0;
let lastDot = 0;
this.player = null;
this.coins = 0;
this.speed = 0;
this.power = 0;
this.energy = 0;
this.dist = 0;
this.tick = function (t) {
t = math.min(t, 100);
for (let i = inserted.length - 1; i >= 0; i--) {
let obj = inserted[i];
if (obj.x + (obj.radius || 0) < this.dist + Conf.width) {
inserted.splice(i, 1);
obj.uiEnter();
objects.push(obj);
}
}
if (this.speed <= 0) {
return;
}
let d, obj, px, py, x, y, dx, dy, dxy, i, f;
d = t * this.speed;
time += t;
this.dist += d;
this.power -= d;
this.speed = Conf.speed + this.dist * Conf.acceleration * this.player.slow;
this.energy -= d * this.player.energy;
this.uiEnergy(this.energy);
px = this.player.x;
py = this.player.y;
// this.player.setPower(this.power, this.player.power);
for (i = objects.length - 1; i >= 0 && this.speed > 0; i--) {
obj = objects[i];
if (obj.x - (obj.radius || 0) < this.dist) {
obj.remove();
objects.splice(i, 1);
continue;
}
dx = obj.x - px;
dy = obj.y - py;
dxy = math.length(dx, dy);
if (this.player.pull && obj.pull) {
f = this.player.pull * obj.pull;
f = (f * 5000) / dxy / dxy / dxy;
r = math.min(1, (f * t) / 1000);
obj.x -= dx * r;
obj.y -= dy * r;
}
if (this.player.push && obj.push) {
f = this.player.push * obj.push;
f = (f * 0.3) / (1 + math.pow(1.1, dxy - 10 * (f + 1)));
r = math.min(1, (f * t) / 1000);
obj.x += dx * r;
obj.y += dy * r;
}
dx = obj.x - px;
dy = obj.y - py;
dxy = math.length(dx, dy);
if (dxy < obj.radius + this.player.radius && obj.collide && obj.collide()) {
obj.remove();
objects.splice(i, 1);
continue;
}
if (this.speed <= 0) {
return;
}
obj.setPower && obj.setPower(this.power, this.player.power);
obj.vx && (obj.x += t * obj.vx);
obj.vy && (obj.y += t * obj.vy);
obj.uiXY();
}
if (this.energy > 0) {
if (pointer.fresh) {
dx = pointer.x - px;
dy = pointer.y - py;
dxy = math.length(dx, dy);
if (dxy < 0.1) {
pointer.fresh = false;
}
dxy = math.max(1, dxy / this.player.speed / t);
px += dx / dxy;
py += dy / dxy;
}
pointer.x += d;
px += d;
this.player.x = px;
this.player.y = py;
this.player.uiXY();
this.setDist(this.dist);
} else if (px < this.dist - Conf.width / 2) {
this.end(false);
}
while (lastDot + Conf.dotSpace <= this.dist) {
lastDot += Conf.dotSpace;
let pattern = randomPattern.test() && randomPattern.random();
if (pattern) {
let added = pattern.call(randomPattern, lastDot + Conf.width);
added = added * (1 + this.dist * 0.00002 * math.random(0.8, 1.25));
randomPattern.test(-added);
}
}
while (lastItem + Conf.itemSpace <= this.dist) {
lastItem += Conf.itemSpace;
let enemy = randomEnemy.test() && randomEnemy.random();
let coin = randomCoin.test() && randomCoin.random();
if (enemy) {
enemy.call(randomEnemy, lastItem + Conf.width, math.random(Conf.min, Conf.max));
} else if (coin) {
coin.call(randomCoin, lastItem + Conf.width, math.random(Conf.min, Conf.max));
}
}
this.uiMove(this.dist, time, d, t);
};
this.startFrom = function (flag) {
if (flag < 0) {
this.startDist = 0;
this.startFlag = -1;
return true;
} else if (flag <= upgrades.flags && flags[flag]) {
this.startDist = flags[flag];
this.startFlag = flag;
return true;
}
return false;
};
this.start = function () {
DEBUG && console.log("game start");
this.clear();
this.coins = 0;
this.speed = Conf.speed;
this.power = 0;
this.energy = 1;
this.dist = this.startDist || 0;
pointer = {
x: Conf.width / 5 + this.dist,
y: 0,
};
time = 0;
lastItem = this.dist;
lastDot = this.dist;
randomPattern.reset();
randomPower.reset();
randomEnemy.reset();
randomCoin.reset();
this.uiCoins(this.coins);
this.uiEnergy(this.energy);
this.uiStart();
this.player = this.player || new Player();
this.player.x = pointer.x;
this.player.y = pointer.y;
this.player.uiXY();
this.player.upgrade(upgrades);
this.player.uiLive();
};
this.end = function (die) {
DEBUG && console.log("game end");
if (this.speed <= 0) {
return;
}
this.speed = 0;
let endFlag = this.startFlag + 1;
if (endFlag < upgrades.flags) {
while (endFlag < flags.length && flags[endFlag] <= this.dist) {
flags.splice(endFlag, 1);
}
if (endFlag >= flags.length && flags.length <= upgrades.flags) {
flags.splice(endFlag, 0, this.dist | 0);
}
}
if (this.dist > stats.dist) {
stats.dist = this.dist | 0;
}
stats.coins += this.coins;
Data.save(this.data);
this.player.uiDie(die, this.uiEnd.bind(this.ui));
};
this.clear = function () {
DEBUG && console.log("game clear");
for (let i = 0; i < objects.length; i++) {
objects[i].remove();
}
objects.length = 0;
for (let i = 0; i < inserted.length; i++) {
inserted[i].remove();
}
inserted.length = 0;
};
this.pointer = function (x, y) {
pointer.x = x;
pointer.y = y;
pointer.fresh = true;
return this.speed > 0;
};
this.move = function (x, y) {
pointer.x += x * x * Conf.width * (x < 0 ? -1 : 1) * 3;
pointer.y += y * y * Conf.height * (y < 0 ? -1 : 1) * 3;
pointer.fresh = true;
return this.speed > 0;
};
this.insert = function (obj, dot) {
inserted.push(obj);
if (dot && randomPower.test()) {
obj = randomPower.random();
obj(dot.x, dot.y);
}
};
let dotspool = new Pool()
.create(function () {
return new Dot();
})
.exit(function (obj) {
obj.onCheckOut();
})
.enter(function (obj) {
obj.onCheckIn();
})
.discard(function (obj) {
obj.uiRemove();
})
.max(127);
function Player() {
this.radius = Conf.radius.Player;
this.name = "player";
game.uiNewPlayer(this);
}
Player.prototype.upgrade = function (ups) {
this.power = 500 + ups.power * 250;
this.energy = 0.0008 * (1 - ups.energy / 8);
this.speed = 0.2 + ups.speed * 0.02;
this.pull = ups.pull;
this.push = ups.push;
this.slow = 1 / (ups.slow * 0.2 + 1);
};
this.newDot = function (x, y) {
let obj = dotspool.checkOut();
obj.x = x;
obj.y = y;
obj.vx = 0;
obj.vy = 0;
obj.uiXY();
this.insert(obj, obj);
return obj;
};
function Dot() {
this.radius = Conf.radius.Dot;
this.pull = Conf.pull.Dot;
game.uiNewDot(this);
}
Dot.prototype.collide = function () {
game.energy = math.min(1.5, game.energy + 0.01);
game.uiEnergy(game.energy);
this.uiEat();
return true;
};
Dot.prototype.remove = function () {
dotspool.checkIn(this);
};
this.newPower = function (x, y) {
let obj = new Power();
obj.x = x;
obj.y = y;
obj.uiXY();
this.insert(obj);
return obj;
};
function Power() {
this.radius = Conf.radius.Power;
this.pull = Conf.pull.Power;
game.uiNewPower(this);
}
Power.prototype.collide = function () {
game.power = math.max(game.player.power, game.power);
this.uiEat();
return true;
};
Power.prototype.remove = function () {
this.uiRemove();
};
this.newEnemy = function (name, x, y, vx, vy) {
let obj = new Enemy(name);
obj.x = x;
obj.y = y;
obj.vx = vx || 0;
obj.vy = vy || 0;
obj.uiXY();
this.insert(obj);
return obj;
};
function Enemy(name) {
this.radius = Conf.radius.Enemy;
this.push = Conf.push.Enemy;
this.name = name;
game.uiNewEnemy(this);
}
Enemy.prototype.setPower = function (power, max) {
if (this.dead) {
return;
}
if (power <= 0) {
if (this.weak != 0) {
this.push = Conf.push.Enemy;
this.weak = 0;
this.uiMode(0);
}
} else if (power < max / 10) {
if (this.weak != 1) {
this.push = Conf.push.Enemy;
this.weak = 1;
this.uiMode(0);
}
} else if (power < max / 4) {
if (this.weak != 2) {
this.push = 0;
this.weak = 2;
this.uiMode(0.5);
}
} else {
if (this.weak != 3) {
this.push = 0;
this.weak = 3;
this.uiMode(1);
}
}
};
Enemy.prototype.collide = function () {
if (this.dead) {
} else if (this.weak == 0) {
game.end(true);
} else if (this.weak > 0) {
this.push = 0;
this.uiMode(-1);
this.dead = true;
this.vx = this.vy = 0;
this.uiEat();
}
return false;
};
Enemy.prototype.remove = function () {
this.uiRemove();
};
this.newCoin = function (value, x, y) {
let obj = new Coin(value);
obj.x = x;
obj.y = y;
obj.uiXY();
this.insert(obj);
return obj;
};
function Coin(value) {
this.radius = Conf.radius.Coin;
this.value = value;
game.uiNewCoin(this);
}
Coin.prototype.collide = function () {
game.coins += this.value;
game.uiCoins(game.coins);
this.uiEat();
return true;
};
Coin.prototype.remove = function () {
this.uiRemove();
};
// randomize
let randomEnemy = new Randomize().spacing(function () {
return (math.random(5, 50) / Conf.itemSpace) * 10;
});
randomEnemy.add(function (x) {
let y = math.random(-1, 1) * (Conf.height / 2 - 10);
return game.newEnemy("box", x, y);
});
randomEnemy.add(function (x) {
let d = math.random() >= 0.5 ? 1 : -1;
let y = (d * Conf.height) / 2;
let vy = ((-d * game.speed) / 2) * math.random(0.7, 1.4);
return game.newEnemy("tri", x + 400 * game.speed, y - 400 * vy, 0, vy);
});
let randomCoin = new Randomize().spacing(function () {
return (math.random(20, 100) / Conf.itemSpace) * 10;
});
randomCoin.add(
function (x, y) {
return game.newCoin(1, x, y);
},
function () {
return 1;
},
);
randomCoin.add(
function (x, y) {
return game.newCoin(2, x, y);
},
function () {
return game.dist > 1000 ? 1 : 0;
},
);
randomCoin.add(
function (x, y) {
return game.newCoin(5, x, y);
},
function () {
return game.dist > 2000 ? 2 : 0;
},
);
randomCoin.add(
function (x, y) {
return game.newCoin(10, x, y);
},
function () {
return game.dist > 5000 ? 4 : 0;
},
);
randomCoin.add(
function (x, y) {
return game.newCoin(20, x, y);
},
function () {
return game.dist > 10000 ? 8 : 0;
},
);
randomCoin.add(
function (x, y) {
return game.newCoin(50, x, y);
},
function () {
return game.dist > 20000 ? 16 : 0;
},
);
randomCoin.add(
function (x, y) {
return game.newCoin(100, x, y);
},
function () {
return game.dist > 50000 ? 32 : 0;
},
);
randomCoin.add(
function (x, y) {
return game.newCoin(1000, x, y);
},
function () {
return game.dist > 50000 ? (4 * game.dist) / 100000 : 0;
},
);
randomCoin.add(
function (x, y) {
return game.newCoin(10000, x, y);
},
function () {
return game.dist > 50000 ? game.dist / 100000 : 0;
},
);
let randomPower = new Randomize().spacing(function () {
return math.random(100, 400);
});
randomPower.add(function (x, y) {
return game.newPower(x, y);
});
let randomPattern = new Randomize().spacing(function () {
return 1;
});
randomPattern.range = function (min, max) {
let h = math.random(min, max) * (Conf.max - Conf.min);
let c = math.random(Conf.min + h / 2, Conf.max - h / 2);
h *= math.random() >= 0.5 ? 1 : -1;
let a = c - h / 2,
b = c + h / 2;
return {
a: a,
b: b,
h: h,
c: c,
};
};
// straight
randomPattern.add(
function (x) {
let n = math.random(40, 50);
let y = math.random(Conf.min, Conf.max);
let added = 0;
for (let i = 0; i < n; i++) {
added++;
game.newDot(x + i * Conf.dotSpace, y);
}
return (this.__lastadded = added);
},
function () {
return 1;
},
);
// step
randomPattern.add(
function (x) {
let n = math.random(20, 40) | 0;
let ab = randomPattern.range(0.2, 0.7);
let added = 0;
for (let i = 0; i < n; i++) {
added++;
game.newDot(x + i * Conf.dotSpace, ab.a + (i * ab.h) / n);
}
return (this.__lastadded = added);
},
function () {
return game.dist < 1000 ? 0 : 1;
},
);
// stairs
randomPattern.add(
function (x) {
let p = math.random(3, 6) | 0;
let q = math.random(5, 15) | 0;
let n = p * q;
let ab = randomPattern.range(0.3, 0.7);
let m = ab.h / p;
let added = 0;
for (let i = 0; i < n; i++) {
added++;
game.newDot(x + i * Conf.dotSpace, ab.a + (((i * ab.h) / n / m) | 0) * m);
}
return (this.__lastadded = added);
},
function () {
return game.dist < 5000 ? 0 : 1;
},
);
// saw
randomPattern.add(
function (x) {
let p = math.random(2, 6) | 0;
let q = math.random(7, 13) | 0;
let n = p * q;
let ab = randomPattern.range(0.1, 0.6);
let m = ab.h;
let added = 0;
for (let i = 0; i < n; i++) {
added++;
game.newDot(x + i * Conf.dotSpace, ab.a + (((-i * ab.h) / q / m) | 0) * m + (i * ab.h) / q);
}
return (this.__lastadded = added);
},
function () {
return game.dist < 20000 ? 0 : 1;
},
);
// wave
randomPattern.add(
function (x) {
let n = math.random(40, 60);
let a = Conf.dotSpace / math.random(10, 30);
let b = math.random(10, 30);
let y = math.random(Conf.min + b, Conf.max - b);
let added = 0;
for (let i = 0; i < n; i++) {
added++;
game.newDot(x + i * Conf.dotSpace, y + b * math.sin(i * a));
}
return (this.__lastadded = added);
},
function () {
return game.dist < 10000 ? 0 : 2;
},
);
// wave xy
randomPattern.add(
function (x) {
let n = math.random(40, 60);
let a = Conf.dotSpace / math.random(10, 40);
let b = math.random(10, 30);
let c = Conf.dotSpace / math.random(10, 40);
let d = math.random(10, 30);
let y = math.random(Conf.min + b, Conf.max - b);
let added = 0;
for (let i = 0; i < n; i++) {
added++;
game.newDot(x + i * Conf.dotSpace + d * math.cos(i * c), y + b * math.sin(i * a));
}
return (this.__lastadded = added);
},
function () {
return game.dist < 25000 ? 0 : game.dist < 15000 ? 1 : 2;
},
);
// zigzag
randomPattern.add(
function (x) {
let n = math.random(40, 60);
let a = Conf.dotSpace / math.random(10, 40);
let b = math.random(10, 30);
let y = math.random(Conf.min + b, Conf.max - b);
let added = 0;
for (let i = 0; i < n; i++) {
added++;
game.newDot(x + i * Conf.dotSpace, y + b * zigzag(i * a));
}
return (this.__lastadded = added);
},
function () {
return game.dist < 15000 ? 0 : 2;
},
);
// zigzag xy
randomPattern.add(
function (x) {
let n = math.random(40, 60);
let a = Conf.dotSpace / math.random(10, 40);
let b = math.random(10, 30);
let c = Conf.dotSpace / math.random(10, 40);
let d = math.random(10, 30);
let y = math.random(Conf.min + b, Conf.max - b);
let added = 0;
for (let i = 0; i < n; i++) {
added++;
game.newDot(x + i * Conf.dotSpace + d * zagzig(i * c), y + b * zigzag(i * a));
}
return (this.__lastadded = added);
},
function () {
return game.dist < 30000 ? 0 : game.dist < 17500 ? 1 : 2;
},
);
// rect
randomPattern.add(
function (x) {
let n = math.random(3, 8);
let m = n;
let y = math.random(Conf.min, Conf.max - m * Conf.dotSpace);
let added = 0;
for (let i = 0; i < n; i++) {
for (let j = 0; j < m; j++) {
added++;
game.newDot(x + i * Conf.dotSpace, y + j * Conf.dotSpace);
}
}
return (this.__lastadded = added);
},
function () {
return game.dist < 70000 ? 0 : 1;
},
);
// spray
randomPattern.add(
function (x) {
let n = math.random(40, 60);
let max = math.min(1, game.dist / 100000);
let min = math.min(1, game.dist / 200000);
let ab = randomPattern.range(min * 0.5, max * 0.7);
let added = 0;
for (let i = 0; i < n; i++) {
added++;
game.newDot(x + i * Conf.dotSpace, math.random(ab.a, ab.b));
}
return (this.__lastadded = added);
},
function () {
return game.dist < 50000 ? 0 : game.dist < 75000 ? 1 : 2;
},
);
// flower
randomPattern.add(
function (x) {
let n = math.random(40, 60);
let f = math.random(0.2, 0.9) * math.PI;
let c = 5;
let added = 0;
for (let i = 0; i < n; i++) {
added++;
game.newDot(
x + c * math.sqrt(i + 1) * math.sin(i * f),
c * math.sqrt(i + 1) * math.cos(i * f),
);
}
return (this.__lastadded = added);
},
function () {
return game.dist < 100000 ? 0 : 1;
},
);
function zigzag(t) {
t = (math.wrap(t, -math.PI, math.PI) / math.PI) * 2;
if (t > 1) {
t = 2 - t;
} else if (t < -1) {
t = -2 - t;
}
return t;
}
function zagzig(t) {
return zigzag(t + math.PI / 2);
}
}
// UI
let stage = Stage.mount();
let game = new Game();
stage.on("viewport", function (viewport) {
this.pin({
width: Conf.width,
height: Conf.height * 1.2,
scaleMode: "in-pad",
scaleWidth: viewport.width,
scaleHeight: viewport.height - TOP,
offsetY: TOP,
});
});
const screens = {};
let activeScreen = null;
function setActiveScreen(view) {
if (typeof view == "string") {
view = screens[view];
}
if (activeScreen === view) {
return;
}
activeScreen && activeScreen.trigger("screen-close");
activeScreen = view.trigger("screen-open");
}
function createHomeScreen() {
// home screen
let homeScreen = Stage.component().label("HomeScreen").appendTo(stage).hide().pin({
align: 0.5,
});
screens.home = homeScreen;
homeScreen.on("viewport", function () {
this.pin({
width: this.parent().pin("width"),
height: this.parent().pin("height"),
});
bg.pin({
scaleMode: "out",
scaleWidth: this.pin("width"),
scaleHeight: this.pin("height"),
});
});
game.uiUpgrade = function () {
refresh();
};
homeScreen.on("screen-open", function () {
refresh();
this.pin("alpha", 0).show().tween(200).pin("alpha", 1);
});
homeScreen.on("screen-close", function () {
this.tween(200).pin("alpha", 0).hide();
});
let bg = Stage.sprite("homebg").appendTo(homeScreen).pin("align", 0.5);
let menu = Stage.column(0).appendTo(homeScreen).pin("align", 0.5).spacing(4);
let tombstone = Stage.sprite("tombstone").appendTo(menu);
let row1 = Stage.row().appendTo(menu).spacing(4);
let flags = [];
for (let i = 0; i < 6; i++) {
let flag = Stage.sprite("play")
.appendTo(row1)
.on(Stage.POINTER_CLICK, startFrom(i - 1));
flags.push(flag);
}
function startFrom(flag) {
return function () {
if (flag == game.data.upgrades.flags) {
game.upgrade("flags");
} else if (game.startFrom(flag)) {
setActiveScreen("play");
}
return true;
};
return null;
}
let row2 = Stage.row().appendTo(menu).spacing(4);
let upgrades = {};
for (let i = 0; i < Conf.ups.length; i++) {
let name = Conf.ups[i];
upgrades[name] = Stage.sprite("option")
.appendTo(row2)
.attr("name", name)
.on(Stage.POINTER_CLICK, function () {
game.upgrade(this.attr("name"));
});
}
function refresh() {
for (let i = 0; i < flags.length; i++) {
let button = flags[i].empty().pin("alpha", 0.9);
if (i <= game.data.upgrades.flags) {
let value = Format.k(game.data.flags[i - 1]);
value = i > 0 ? value || "-" : 0;
Stage.monotype("d")
.appendTo(button)
.pin({
alignY: 0.5,
alignX: 0.45,
handle: 0.5,
scale: 0.8,
})
.value(value);
continue;
}
let price = game.price("flags");
if (i == game.data.upgrades.flags + 1) {
Stage.monotype("d")
.value(Format.coin(price))
.pin({
alignY: 0.5,
alignX: 0.4,
handle: 0.5,
alpha: 0.8,
scale: 0.6,
})
.appendTo(button);
}
for (let child = button.first(); child; child = child.next()) {
child.pin("alpha", price <= game.data.stats.coins ? 1 : 0.5);
}
}
tombstone.empty();
Stage.monotype("d")
.appendTo(tombstone)
.pin({
alignX: 0.5,
alignY: 1,
offsetX: -2,
offsetY: -6,
alpha: 0.6,
scale: 0.8,
})
.value(0 + "-" + Format.k(game.data.stats.dist));
Stage.monotype("d")
.appendTo(tombstone)
.pin({
alignX: 0.5,
alignY: 0,
offsetX: -4,
offsetY: 10.5,
alpha: 0.5,
scale: 0.7,
})
.value(Format.coin(game.data.stats.coins));
for (let i = 0; i < Conf.ups.length; i++) {
let name = Conf.ups[i];
let price = game.price(name);
let level = game.data.upgrades[name] || 0;
let button = upgrades[name].empty().pin("alpha", 0.9);
// sprite
Stage.sprite("up_" + name)
.pin("align", 0.5)
.appendTo(button);
// price
Stage.monotype("d")
.value(Format.coin(price))
.pin({
align: 1,
offsetX: -1.6,
offsetY: -1.4,
alpha: 0.8,
scale: 0.6,
})
.appendTo(button);
// level
if (level <= 6) {
Stage.monotype("up")
.pin({
alignX: 0,
alignY: 0,
offsetX: 1.6,
offsetY: 1.4,
alpha: 0.8,
scale: 0.6,
})
.appendTo(button)
.value(level);
}
for (let child = button.first(); child; child = child.next()) {
child.pin("alpha", price <= game.data.stats.coins ? 1 : 0.5);
}
}
}
}
function createPlayScreen() {
// play screen
let playScreen = Stage.component().label("PlayScreen").appendTo(stage).hide().pin({
align: 0.5,
});
screens.play = playScreen;
playScreen.on("viewport", function () {
this.pin({
width: this.parent().pin("width"),
height: this.parent().pin("height"),
});
bg.pin({
scaleMode: "out",
scaleWidth: this.pin("width"),
scaleHeight: this.pin("height"),
});
let toph = TOP / this.pin("scaleX") / this.parent().pin("scaleX");
top.pin({
width: this.pin("width"),
height: toph,
offsetY: -toph,
});
});
playScreen.on("screen-open", function () {
stage.dom.style && (stage.dom.style.cursor = "none");
game.start();
this.pin("alpha", 0).show().tween(200).pin("alpha", 1);
});
playScreen.on("screen-close", function () {
stage.dom.style && (stage.dom.style.cursor = "");
game.end();
this.tween(200).pin("alpha", 0).hide();
});
playScreen.tick(function (t) {
game.tick(t);
}, true);
let bg = Stage.sprite("playbg").appendTo(playScreen).pin("align", 0.5);
let border = Stage.sprite("border").stretch().appendTo(playScreen).pin({
width: Conf.width,
height: Conf.height,
align: 0.5,
alpha: 0.5,
});
let top = Stage.sprite("shadow").stretch().appendTo(playScreen);
let field = Stage.component().appendTo(playScreen).attr("spy", true).pin({
width: Conf.width,
height: Conf.height,
alignX: 0.5,
alignY: 0.5,
handleY: 0,
});
let energy = Stage.sprite("energy").stretch().appendTo(playScreen).pin({
alignX: 0,
alignY: 0,
offsetX: 3,
offsetY: 2,
});
let dist = Stage.monotype("d").appendTo(playScreen).pin({
alignX: 0,
alignY: 0,
offsetX: 3,
offsetY: 9,
});
let coins = Stage.monotype("d").appendTo(playScreen).pin({
alignX: 1,
alignY: 0,
offsetX: -3,
offsetY: 3,
});
let lastCoin = Stage.column(0.5)
.appendTo(playScreen)
.pin({
alignX: 0.5,
alignY: 0,
offsetX: 10,
offsetY: 2,
})
.append(Stage.sprite(), Stage.monotype("d").pin("scale", 0.8))
.hide();
let lastCoinTimeout = null;
function setLastCoin(value, scale) {
lastCoin
.first()
.texture("coin_" + value)
.pin("scale", scale || 1);
lastCoin
.last()
.value(Format.coin(value))
.visible(value > 100);
lastCoin.show();
clearTimeout(lastCoinTimeout);
lastCoinTimeout = setTimeout(function () {
lastCoin.hide();
}, 1000);
}
let cursor = Stage.sprite("cursor").pin("handle", 0.5).appendTo(field).hide();
let l1 = Stage.component().appendTo(field);
let l2 = Stage.component().appendTo(field);
let l3 = Stage.component().appendTo(field);
function setCursor(point) {
if (!Number.isFinite(point.x) || !Number.isFinite(point.y)) {
console.log(point.x, point.y);
console.trace();
return;
}
const isActive = game.pointer(point.x, point.y);
cursor.offset(point);
cursor.visible(isActive);
}
field.on(Stage.POINTER_START, setCursor);
field.on(Stage.POINTER_MOVE, setCursor);
let bgcolors = randomizeArray(PLAYFUL_COLORS);
game.uiStart = function () {
DEBUG && console.log("app start");
stage.background(bgcolors());
};
game.uiMove = function (dist, time, d, t) {
let x = cursor.pin("offsetX");
cursor.pin("offsetX", x + d);
field.pin("offsetX", -dist);
};
game.uiEnd = function () {
DEBUG && console.log("app end");
setTimeout(function () {
setActiveScreen("home");
stage.background("#000");
}, 1000);
};
game.setDist = function (d) {
dist.value(Format.k(d));
};
game.uiEnergy = function (e) {
energy.pin("width", (((Math.max(0, e) * 100) | 0) / 100) * 40);
};
game.uiCoins = function (n) {
coins.value(Format.coin(n));
};
game.uiNewPlayer = function (player) {
DEBUG && console.log("player create");
player.ui = Stage.anim(player.name).pin("handle", 0.5).appendTo(l3);
player.uiXY = function () {
this.ui.offset(this);
};
player.uiLive = function (anim, callback, freeze) {
DEBUG && console.log("player live");
this.freeze = !!freeze;
!this.freeze && Sound.play("start");
// cursor.show();
this.ui.frames(this.name).show();
!this.freeze && this.ui.play();
callback && callback();
};
player.uiDie = function (anim, callback) {
DEBUG && console.log("player die");
if (anim) {
!this.freeze && Sound.play("die");
cursor.hide();
this.ui.frames("die").play().repeat(1, callback);
} else {
callback && callback();
}
};
};
game.uiNewDot = function (obj) {
obj.ui = Stage.sprite("dot").pin("handle", 0.5).appendTo(l1).hide();
obj.uiEnter = function () {
this.ui.show();
};
obj.uiXY = function () {
this.ui.offset(this);
};
obj.onCheckOut = function () {};
obj.onCheckIn = function () {
this.ui.hide();
};
obj.uiRemove = function () {
this.ui.remove();
this.ui = null;
};
obj.uiEat = function (e) {
Sound.play("dot");
};
};
game.uiNewPower = function (obj) {
obj.ui = Stage.sprite("power").pin("handle", 0.5).appendTo(l2).hide();
obj.uiEnter = function () {
this.ui.show();
};
obj.uiXY = function () {
this.ui.offset(this);
};
obj.uiEat = function () {
Sound.play("power");
};
obj.uiRemove = function () {
this.ui.remove();
this.ui = null;
};
};
game.uiNewEnemy = function (obj) {
obj.ui = Stage.anim(obj.name + "_live")
.pin("handle", 0.5)
.appendTo(l2)
.hide();
obj.uiEnter = function () {
this.ui.show();
};
obj.uiMode = function (weak) {
if (weak == 0) {
this.ui.frames(this.name + "_live").play();
} else if (weak == -1) {
this.ui
.frames(this.name + "_dead")
.gotoFrame(0)
.pin({
alpha: 0.8,
rotation: 0,
});
} else if (weak == 1) {
this.ui.frames(this.name + "_weak").play();
} else {
this.ui.frames(this.name + "_mix").play();
}
};
obj.uiXY = function () {
this.ui.offset(this);
if (this.vx || this.vy) {
this.ui.pin("rotation", Math.atan2(this.vx, this.vy) - Math.PI / 2);
}
};
obj.uiRemove = function () {
this.ui.remove();
this.ui = null;
};
obj.uiEat = function () {
Sound.play("enemy");
};
};
game.uiNewCoin = function (obj) {
obj.scale = Conf.coinsScale[obj.value] || 1;
obj.ui = Stage.sprite("coin_" + obj.value)
.pin("handle", 0.5)
.appendTo(l2)
.pin("scale", obj.scale)
.hide();
obj.uiEnter = function () {
this.ui.show();
};
obj.uiXY = function () {
this.ui.offset(this);
};
obj.uiRemove = function () {
this.ui.remove();
this.ui = null;
};
obj.uiEat = function () {
setLastCoin(this.value, this.scale);
Sound.play("coin");
};
};
}
createHomeScreen();
createPlayScreen();
setActiveScreen("home");
function randomizeArray(list) {
// shuffle
for (let i = list.length - 1; i > 0; i--) {
let j = Math.floor(Math.random() * (i + 1));
let temp = list[i];
list[i] = list[j];
list[j] = temp;
}
let i = 0;
return function () {
return list[i++ % list.length];
};
}