diff --git a/art/base.svg b/art/base.svg new file mode 100644 index 0000000..b68e363 --- /dev/null +++ b/art/base.svg @@ -0,0 +1,1829 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1 + 2 + 5 + 10 + + + + + + + + + 20 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 50 + + 100 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + M + + diff --git a/src/app.js b/src/app.js new file mode 100644 index 0000000..19b6d4c --- /dev/null +++ b/src/app.js @@ -0,0 +1,1411 @@ +TOP = typeof TOP === 'number' ? TOP : 0; + +var M = Cut.Math; + +var Conf = {}; + +Conf.width = 240; +Conf.height = 120; +Conf.max = Conf.height * 0.47; +Conf.min = -Conf.max; +Conf.objSpace = 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.$ = 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; +}; + +Conf.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; +}; + +Conf.coinsScale = { + c1 : 0.70, + c2 : 0.75, + c5 : 0.80, + c10 : 0.90, + c20 : 0.95, + c50 : 1, + c100 : 1.1 +}; + +Conf.saveKey = "data"; + +Conf.loadData = function() { + var key = Conf.saveKey; + DEBUG && console.log("game load", key); + try { + var data = localStorage.getItem(key); + DEBUG && console.log("game load", key, data); + return (data && JSON.parse(data)) || {}; + } catch (e) { + console.log(e); + } + return {}; +}; + +Conf.saveData = function(data) { + var key = Conf.saveKey; + 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; +}; + +function Game() { + + this.data = Conf.loadData(); + + var upgrades = this.data.upgrades || (this.data.upgrades = {}); + + for (var i = 0; i < Conf.ups.length; i++) { + var name = Conf.ups[i]; + upgrades[name] = upgrades[name] || 0; + } + + upgrades.flags = Math.max(upgrades.flags || 0, 2); + + var stats = this.data.stats = this.data.stats || {}; + stats.coins = stats.coins || 0; + stats.dist = stats.dist || 0; + + var flags = this.data.flags = this.data.flags || []; + + this.upgrade = function(name) { + var price = this.price(name); + DEBUG && console.log("upgrade: " + name + " at " + price); + if (price > 0 && price <= stats.coins) { + stats.coins -= price; + upgrades[name] += 1; + Conf.saveData(this.data); + } + this.uiUpgrade(); + }; + + this.price = function(name) { + return Math.pow(10, (upgrades[name] || 0) + 2); + }; + + var objects = []; + var inserted = []; + var pointer = {}; + + var time = 0; + var lastTime = 0; + var lastObj = 0; + var lastDot = 0; + var pattern = 0; + + this.player = null; + + this.coins = 0; + this.speed = 0; + this.power = 0; + this.energy = 0; + this.dist = 0; + + this.tick = function() { + for (i = inserted.length - 1; i >= 0; i--) { + 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; + } + + var t, d, obj, px, py, x, y, dx, dy, dxy, i, f; + t = lastTime || +new Date(); + lastTime = +new Date(); + t = Math.min(lastTime - t, 100); + 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 = M.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 = M.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 && pointer.fresh) { + dx = pointer.x - px; + dy = pointer.y - py; + dxy = M.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; + if (--pattern < 0) { + (pattern = Conf.randomPattern.random(this)) + && (pattern = pattern(this, lastDot + Conf.width) + + M.random(this.dist) / 7500); + } + } + + while (lastObj + Conf.objSpace <= this.dist) { + lastObj += Conf.objSpace; + obj = Conf.randomCoin.random(this) || Conf.randomEnemy.random(this); + if (obj) { + x = lastObj + Conf.width; + y = M.random(Conf.min, Conf.max); + obj(this, x, y); + } + } + + 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 = {}; + + time = 0; + lastTime = 0; + lastObj = this.dist; + lastDot = this.dist; + pattern = 0; + + Conf.randomPattern.reset(); + Conf.randomPower.reset(); + Conf.randomCoin.reset(); + Conf.randomEnemy.reset(); + + this.uiCoins(this.coins); + this.uiEnergy(this.energy); + + this.uiStart(); + + this.player = this.player || new Player(this); + this.player.x = Conf.width / 5 + this.dist; + this.player.y = 0; + 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; + + var 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; + + Conf.saveData(this.data); + + this.player.uiDie(die, this.uiEnd.bind(this.ui)); + }; + + this.clear = function() { + DEBUG && console.log("game clear"); + + for (var i = 0; i < objects.length; i++) { + objects[i].remove(); + } + objects.length = 0; + + for (var 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.insert = function(obj, dot) { + inserted.push(obj); + if (dot && (obj = Conf.randomPower.random(this))) { + obj(this, dot.x, dot.y); + } + }; + + this.dots = new Pool(function() { + return new Dot(this); + }.bind(this), function(obj) { + obj.onCheckOut(); + }, function(obj) { + obj.onCheckIn(); + }, function(obj) { + obj.uiRemove(); + }).max(127); + +}; + +function Player(game) { + this.radius = Conf.radius.Player; + this.game = game; + this.name = "player"; + game.uiNewPlayer(this); +} + +Player.prototype.upgrade = function(ups) { + this.power = 500 + ups.power * 250; + this.energy = (1 - ups.energy / 16) / 1000; + this.speed = 0.2 + ups.speed * 0.02; + this.pull = ups.pull; + this.push = ups.push; + this.slow = 1 / (ups.slow * 0.2 + 1); +}; + +Game.prototype.newDot = function(x, y) { + var obj = this.dots.checkOut(); + obj.x = x, obj.y = y; + obj.vx = 0, obj.vy = 0; + obj.uiXY(); + this.insert(obj, obj); + return obj; +}; + +function Dot(game) { + this.radius = Conf.radius.Dot; + this.pull = Conf.pull.Dot; + this.game = game; + game.uiNewDot(this); +} + +Dot.prototype.collide = function() { + this.game.energy = Math.min(1.5, this.game.energy + 0.01); + this.game.uiEnergy(this.game.energy); + this.uiEat(); + return true; +}; + +Dot.prototype.remove = function() { + this.game.dots.checkIn(this); +}; + +Game.prototype.newPower = function(x, y) { + var obj = new Power(this); + obj.x = x, obj.y = y; + obj.uiXY(); + this.insert(obj); + return obj; +}; + +function Power(game) { + this.radius = Conf.radius.Power; + this.pull = Conf.pull.Power; + this.game = game; + game.uiNewPower(this); +} + +Power.prototype.collide = function() { + this.game.power = Math.max(this.game.player.power, this.game.power); + this.uiEat(); + return true; +}; + +Power.prototype.remove = function() { + this.uiRemove(); +}; + +Game.prototype.newEnemy = function(name, x, y, vx, vy) { + var obj = new Enemy(this, name); + obj.x = x, obj.y = y; + obj.vx = vx || 0, obj.vy = vy || 0; + obj.uiXY(); + this.insert(obj); + return obj; +}; + +function Enemy(game, name) { + this.radius = Conf.radius.Enemy; + this.push = Conf.push.Enemy; + this.game = game; + 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) { + this.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(); +}; + +Game.prototype.newCoin = function(value, x, y) { + var obj = new Coin(this, value); + obj.x = x, obj.y = y; + obj.uiXY(); + this.insert(obj); + return obj; +}; + +function Coin(game, value) { + this.radius = Conf.radius.Coin; + this.game = game; + this.value = value; + game.uiNewCoin(this); +} + +Coin.prototype.collide = function(game) { + this.game.coins += this.value; + this.game.uiCoins(this.game.coins); + this.uiEat(); + return true; +}; + +Coin.prototype.remove = function() { + this.uiRemove(); +}; + +Cut.Anim.FPS = 11; + +Cut.Loader.load(function(root, elem) { + Cut.Mouse.subscribe(root, elem, true); + return new App(elem).appendTo(root); +}); + +function App(elem) { + App.prototype._super.apply(this, arguments); + this.spy(true); + this.elem = elem; + + this.game = new Game(); + + this.sound = {}; + this.sound.play = function(name) { + // play sound here + }; + + this.home = new Home(this).appendTo(this).hide().spy(true).pin({ + align : 0.5 + }); + this.play = new Play(this).appendTo(this).hide().spy(true).pin({ + align : 0.5 + }); + + this.open("home"); + + this.listen("resize", function(width, height) { + this.pin({ + width : App.width, + height : App.height, + resizeMode : "in", + resizeWidth : width, + resizeHeight : height - TOP, + offsetY : TOP + }); + return true; + }); + +} + +App.prototype = new Cut(Cut.Proto); +App.prototype._super = Cut; +App.prototype.constructor = App; + +App.width = Conf.width; +App.height = Conf.height * 1.2; + +App.prototype.open = function(name) { + var open = name; + if (typeof open == "string") { + open = this[open]; + } + if (this.opened === open) { + return; + } + if (this.opened) { + this.opened.publish("close") || this.opened.hide(); + } + (this.opened = open).publish("open"); + this.opened.show(); + + // this.fs.visible(open === this.home); +}; + +function Home(app) { + Home.prototype._super.apply(this, arguments); + + var game = app.game; + + this.listen("resize", function(width, height) { + this.pin({ + width : this.parent().pin("width"), + height : this.parent().pin("height") + }); + + bg.pin({ + scaleMode : "out", + scaleWidth : this.pin("width"), + scaleHeight : this.pin("height") + }); + }); + + this.listen("open", game.uiUpgrade = function() { + refresh(); + }); + + this.listen("close", function() { + this.hide(); + }); + + var bg = Cut.image("base:homebg").appendTo(this).pin("align", 0.5); + + var menu = Cut.column(0).appendTo(this).pin("align", 0.5).spacing(4); + + var tombstone = Cut.image("base:tombstone").appendTo(menu); + + var row = Cut.row().appendTo(menu).spacing(4); + var flags = []; + for (var i = 0; i < 6; i++) { + var flag = Cut.image("base:play").appendTo(row).listen(Cut.Mouse.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)) { + app.open("play"); + } + return true; + }; + return null; + } + + var row = Cut.row().appendTo(menu).spacing(4); + + var upgrades = {}; + + for (var i = 0; i < Conf.ups.length; i++) { + var name = Conf.ups[i]; + upgrades[name] = Cut.image("base:option").appendTo(row).attr("name", name) + .listen(Cut.Mouse.CLICK, function() { + game.upgrade(this.attr("name")); + }); + } + + function refresh() { + for (var i = 0; i < flags.length; i++) { + var button = flags[i].empty(); + button.pin("alpha", 1).pinChildren({ + alpha : 1 + }); + if (i <= game.data.upgrades.flags) { + var value = Conf.k(game.data.flags[i - 1]); + value = i > 0 ? (value || "-") : 0; + Cut.string("base:d_").appendTo(button).pin({ + alignY : 0.5, + alignX : 0.45, + handle : 0.5, + scale : 0.8, + }).setValue(value); + continue; + } + var price = game.price("flags"); + button.pin("alpha", 0.9).pinChildren({ + alpha : price <= game.data.stats.coins ? 1 : 0.5 + }); + if (i == game.data.upgrades.flags + 1) { + Cut.string("base:d_").setValue(Conf.$(price)).pin({ + alignY : 0.5, + alignX : 0.4, + handle : 0.5, + alpha : 0.8, + scale : 0.6 + }).appendTo(button); + } + } + + tombstone.empty(); + Cut.string("base:d_").appendTo(tombstone).pin({ + alignX : 0.5, + alignY : 1, + offsetX : -2, + offsetY : -6, + alpha : 0.6, + scale : 0.8 + }).setValue(0 + "-" + Conf.k(game.data.stats.dist)); + + Cut.string("base:d_").appendTo(tombstone).pin({ + alignX : 0.5, + alignY : 0, + offsetX : -4, + offsetY : 10.5, + alpha : 0.5, + scale : 0.7 + }).setValue(Conf.$(game.data.stats.coins)); + + for (var i = 0; i < Conf.ups.length; i++) { + var name = Conf.ups[i]; + var button = upgrades[name].empty(); + var price = game.price(name); + var level = game.data.upgrades[name] || 0; + button.pin("alpha", 0.9).pinChildren({ + alpha : price <= game.data.stats.coins ? 1 : 0.5 + }); + // image + Cut.image("base:up_" + name).pin("align", 0.5).appendTo(button); + // price + Cut.string("base:d_").setValue(Conf.$(price)).pin({ + align : 1, + offsetX : -1.6, + offsetY : -1.4, + alpha : 0.8, + scale : 0.6 + }).appendTo(button); + // level + if (level <= 6) { + Cut.image("base:up_" + level).pin({ + alignX : 0, + alignY : 0, + offsetX : 1.6, + offsetY : 1.4, + alpha : 0.8, + scale : 0.6 + }).appendTo(button); + } + } + } +} + +Home.prototype = new Cut(Cut.Proto); +Home.prototype._super = Cut; +Home.prototype.constructor = Home; + +function Play(app) { + Play.prototype._super.apply(this, arguments); + + var game = app.game; + + this.listen("resize", function(width, height) { + this.pin({ + width : this.parent().pin("width"), + height : this.parent().pin("height") + }); + + bg.pin({ + scaleMode : "out", + scaleWidth : this.pin("width"), + scaleHeight : this.pin("height") + }); + + var toph = TOP / this.pin("scaleX") / this.parent().pin("scaleX"); + top.pin({ + width : this.pin("width"), + height : toph, + offsetY : -toph + }); + }); + + this.listen("open", function() { + app.elem.style && (app.elem.style.cursor = "none"); + game.start(); + }); + + this.listen("close", function() { + app.elem.style && (app.elem.style.cursor = ""); + game.end(); + this.hide(); + }); + + this.tick(function() { + game.tick(); + }, true); + + var bg = Cut.image("base:playbg").appendTo(this).pin("align", 0.5); + var bgcolor = Cut.anim("base:c_").appendTo(bg).pin({ + alpha : 0.6, + align : 0.5, + scale : 3 + }); + + var border = Cut.image("base:border").stretch().appendTo(this).pin({ + width : Conf.width, + height : Conf.height, + align : 0.5, + alpha : 0.5 + }); + + var top = Cut.image("base:shadow").stretch().appendTo(this); + + var field = Cut.create().appendTo(this).spy(true).pin({ + width : Conf.width, + height : Conf.height, + alignX : 0.5, + alignY : 0.5, + handleY : 0 + }); + + var energy = Cut.image("base:energy").stretch().appendTo(this).pin({ + alignX : 0, + alignY : 0, + offsetX : 3, + offsetY : 2 + }); + + var dist = Cut.string("base:d_").appendTo(this).pin({ + alignX : 0, + alignY : 0, + offsetX : 3, + offsetY : 9 + }); + + var coins = Cut.string("base:d_").appendTo(this).pin({ + alignX : 1, + alignY : 0, + offsetX : -3, + offsetY : 3 + }); + + var lastCoin = Cut.column(0.5).appendTo(this).pin({ + alignX : 0.5, + alignY : 0, + offsetX : 10, + offsetY : 2 + }).append(Cut.anim("base:coin_"), Cut.string("base:d_").pin("scale", 0.8)) + .hide(); + + var lastCoinTimeout = null; + + function setLastCoin(value, scale) { + lastCoin.first().gotoLabel("coin_" + value + "_").pin("scale", scale || 1); + lastCoin.last().setValue(Conf.$(value)).visible(value > 100); + + lastCoin.show(); + clearTimeout(lastCoinTimeout); + lastCoinTimeout = setTimeout(function() { + lastCoin.hide(); + }, 1000); + } + + var cursor = Cut.image("base:cursor").pin("handle", 0.5).appendTo(field) + .hide(); + + var l1 = Cut.create().appendTo(field); + var l2 = Cut.create().appendTo(field); + var l3 = Cut.create().appendTo(field); + + field.listen( [ Cut.Mouse.MOVE, Cut.Mouse.START ], function(ev, point) { + cursor.xy(point.x, point.y).visible(game.pointer(point.x, point.y)); + }); + + var colors = { + list : randomList(bgcolor._frames.length), + i : 0, + next : function() { + return this.list[(this.i++) % this.list.length]; + } + }; + + function randomList(size) { + var list = []; + for (var i = 0; i < size; i++) { + list[i] = i; + } + for (var i = 0; i < size; i++) { + var j = Math.floor(Math.random() * (size - i)) + i; + var temp = list[i]; + list[i] = list[j]; + list[j] = temp; + } + return list; + } + + game.uiStart = function() { + DEBUG && console.log("app start"); + bgcolor.gotoFrame(colors.next()); + }; + + game.uiMove = function(dist, time, d, t) { + cursor.x(cursor.x() + d); + field.x(-dist); + }; + + game.uiEnd = function() { + DEBUG && console.log("app end"); + setTimeout(function() { + app.open("home"); + }, 1000); + }; + + game.setDist = function(d) { + dist.setValue(Conf.k(d)); + }; + + game.uiEnergy = function(e) { + energy.pin("width", Math.max(0, e) * 40); + }; + + game.uiCoins = function(n) { + coins.setValue(Conf.$(n)); + }; + + game.uiNewPlayer = function(obj) { + DEBUG && console.log("player create"); + obj.ui = Cut.anim("base:" + obj.name + "_").pin("handle", 0.5).appendTo(l3); + obj.uiXY = function() { + this.ui.xy(this.x, this.y); + }; + obj.uiLive = function(anim, callback, freeze) { + DEBUG && console.log("player live"); + this.freeze = !!freeze; + !this.freeze && app.sound.play("start"); + // cursor.show(); + this.ui.setFrames("base:" + this.name + "_").show(); + !this.freeze && this.ui.play(); + callback && callback(); + }; + obj.uiDie = function(anim, callback) { + DEBUG && console.log("player die"); + if (anim) { + !this.freeze && app.sound.play("die"); + cursor.hide(); + this.ui.setFrames("base:die").play().repeat(1, callback); + } else { + callback && callback(); + } + }; + }; + + game.uiNewDot = function(obj) { + obj.ui = Cut.image("base:dot").pin("handle", 0.5).appendTo(l1).hide(); + obj.uiEnter = function() { + this.ui.show(); + }; + obj.uiXY = function() { + this.ui.xy(this.x, this.y); + }; + obj.onCheckOut = function() { + }; + obj.onCheckIn = function() { + this.ui.hide(); + }; + obj.uiRemove = function() { + this.ui.remove(); + this.ui = null; + }; + obj.uiEat = function(e) { + app.sound.play("dot"); + }; + }; + + game.uiNewPower = function(obj) { + obj.ui = Cut.image("base:power").pin("handle", 0.5).appendTo(l2).hide(); + obj.uiEnter = function() { + this.ui.show(); + }; + obj.uiXY = function() { + this.ui.xy(this.x, this.y); + }; + obj.uiEat = function() { + app.sound.play("power"); + }; + obj.uiRemove = function() { + this.ui.remove(); + this.ui = null; + }; + }; + + game.uiNewEnemy = function(obj) { + obj.ui = Cut.anim("base:" + obj.name).pin("handle", 0.5).appendTo(l2) + .hide(); + obj.uiEnter = function() { + this.ui.show(); + }; + obj.uiMode = function(weak) { + if (weak == 0) { + this.ui.setFrames("base:" + this.name + "_").play(); + } else if (weak == -1) { + this.ui.setFrames("base:un" + this.name).gotoFrame(0).pin({ + "alpha" : 0.8, + "rotation" : 0 + }); + } else if (weak == 1) { + this.ui.setFrames("base:" + this.name + "z_").play(); + } else { + this.ui.setFrames("base:" + this.name + "").play(); + } + }; + obj.uiXY = function() { + this.ui.xy(this.x, this.y); + 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() { + app.sound.play("enemy"); + }; + }; + + game.uiNewCoin = function(obj) { + obj.scale = Conf.coinsScale["c" + obj.value] || 1; + obj.ui = Cut.anim("base: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.xy(this.x, this.y); + }; + obj.uiRemove = function() { + this.ui.remove(); + this.ui = null; + }; + obj.uiEat = function() { + setLastCoin(this.value, this.scale); + app.sound.play("coin"); + }; + }; +} + +Play.prototype = new Cut(Cut.Proto); +Play.prototype._super = Cut; +Play.prototype.constructor = Play; + +Conf.randomEnemy = new Randomize().spacing(function(game) { + return M.random(5, 50) / Conf.objSpace * 10; +}); + +Conf.randomEnemy.add(function(game, x) { + var y = M.random(-1, 1) * (Conf.height / 2 - 10); + return game.newEnemy("box", x, y); +}); + +Conf.randomEnemy.add(function(game, x) { + var d = M.random() >= 0.5 ? 1 : -1; + var y = d * Conf.height / 2; + var vy = -d * game.speed / 2 * M.random(0.7, 1.4); + return game.newEnemy("tri", x + 400 * game.speed, y - 400 * vy, 0, vy); +}); + +Conf.randomCoin = new Randomize().spacing(function(game) { + return M.random(20, 100) / Conf.objSpace * 10; +}); + +Conf.randomCoin.add(function(game, x, y) { + return game.newCoin(1, x, y); +}, function(game) { + return 1; +}); + +Conf.randomCoin.add(function(game, x, y) { + return game.newCoin(2, x, y); +}, function(game) { + return (game.dist > 2000) ? 1 : 0; +}); + +Conf.randomCoin.add(function(game, x, y) { + return game.newCoin(5, x, y); +}, function(game) { + return (game.dist > 5000) ? 2 : 0; +}); + +Conf.randomCoin.add(function(game, x, y) { + return game.newCoin(10, x, y); +}, function(game) { + return (game.dist > 10000) ? 4 : 0; +}); + +Conf.randomCoin.add(function(game, x, y) { + return game.newCoin(20, x, y); +}, function(game) { + return (game.dist > 20000) ? 8 : 0; +}); + +Conf.randomCoin.add(function(game, x, y) { + return game.newCoin(50, x, y); +}, function(game) { + return (game.dist > 50000) ? 16 : 0; +}); + +Conf.randomCoin.add(function(game, x, y) { + return game.newCoin(100, x, y); +}, function(game) { + return (game.dist > 100000) ? 32 : 0; +}); + +Conf.randomCoin.add(function(game, x, y) { + return game.newCoin(1000, x, y); +}, function(game) { + return (game.dist > 100000) ? 4 * game.dist / 100000 : 0; +}); + +Conf.randomCoin.add(function(game, x, y) { + return game.newCoin(10000, x, y); +}, function(game) { + return (game.dist > 100000) ? game.dist / 100000 : 0; +}); + +Conf.randomPower = new Randomize().spacing(function(game) { + return M.random(100, 400); +}); + +Conf.randomPower.add(function(game, x, y) { + return game.newPower(x, y); +}); + +Conf.randomPattern = new Randomize().spacing(function(game) { + return M.random(20, 40) / Conf.objSpace * 10; +}); + +Conf.randomPattern.range = function(min, max) { + var h = M.random(min, max) * (Conf.max - Conf.min); + var c = M.random(Conf.min + h / 2, Conf.max - h / 2); + h *= (Math.random() >= 0.5 ? 1 : -1); + var a = c - h / 2, b = c + h / 2; + return { + a : a, + b : b, + h : h, + c : c + }; +}; + +// straight +Conf.randomPattern.add(function(game, x) { + var n = M.random(40, 50); + var y = M.random(Conf.min, Conf.max); + + var added = 0; + for (var i = 0; i < n; i++) { + added++; + game.newDot(x + i * Conf.dotSpace, y); + } + return added; + +}, function(game) { + return 1; +}); + +// step +Conf.randomPattern.add(function(game, x) { + var n = M.random(20, 40) | 0; + var ab = Conf.randomPattern.range(0.2, 0.7); + + var added = 0; + for (var i = 0; i < n; i++) { + added++; + game.newDot(x + i * Conf.dotSpace, ab.a + i * ab.h / n); + } + return added; + +}, function(game) { + return game.dist < 1000 ? 0 : 1; +}); + +// stairs +Conf.randomPattern.add(function(game, x) { + var p = M.random(3, 6) | 0; + var q = M.random(5, 15) | 0; + var n = p * q; + var ab = Conf.randomPattern.range(0.3, 0.7); + + var m = ab.h / p; + + var added = 0; + for (var i = 0; i < n; i++) { + added++; + game.newDot(x + i * Conf.dotSpace, ab.a + ((i * ab.h / n) / m | 0) * m); + } + return added; + +}, function(game) { + return game.dist < 5000 ? 0 : 1; +}); + +// saw +Conf.randomPattern.add(function(game, x) { + var p = M.random(2, 6) | 0; + var q = M.random(7, 13) | 0; + var n = p * q; + var ab = Conf.randomPattern.range(0.1, 0.6); + + var m = ab.h; + + var added = 0; + for (var 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 added; + +}, function(game) { + return game.dist < 20000 ? 0 : 1; +}); + +// wave +Conf.randomPattern.add(function(game, x) { + var n = M.random(40, 60); + var a = Conf.dotSpace / M.random(10, 30), b = M.random(10, 30); + var y = M.random(Conf.min + b, Conf.max - b); + + var added = 0; + for (var i = 0; i < n; i++) { + added++; + game.newDot(x + i * Conf.dotSpace, y + b * Math.sin(i * a)); + } + return added; + +}, function(game) { + return game.dist < 10000 ? 0 : 2; +}); + +// wave xy +Conf.randomPattern.add(function(game, x) { + var n = M.random(40, 60); + var a = Conf.dotSpace / M.random(10, 40), b = M.random(10, 30); + var c = Conf.dotSpace / M.random(10, 40), d = M.random(10, 30); + var y = M.random(Conf.min + b, Conf.max - b); + + var added = 0; + for (var i = 0; i < n; i++) { + added++; + game.newDot(x + i * Conf.dotSpace + d * Math.cos(i * c), y + b + * Math.sin(i * a)); + } + return added; + +}, function(game) { + return game.dist < 25000 ? 0 : game.dist < 15000 ? 1 : 2; +}); + +// zigzag +Conf.randomPattern.add(function(game, x) { + var n = M.random(40, 60); + var a = Conf.dotSpace / M.random(10, 40), b = M.random(10, 30); + var y = M.random(Conf.min + b, Conf.max - b); + + var added = 0; + for (var i = 0; i < n; i++) { + added++; + game.newDot(x + i * Conf.dotSpace, y + b * M.zigzag(i * a)); + } + return added; + +}, function(game) { + return game.dist < 15000 ? 0 : 2; +}); + +// zigzag xy +Conf.randomPattern.add(function(game, x) { + var n = M.random(40, 60); + var a = Conf.dotSpace / M.random(10, 40), b = M.random(10, 30); + var c = Conf.dotSpace / M.random(10, 40), d = M.random(10, 30); + var y = M.random(Conf.min + b, Conf.max - b); + + var added = 0; + for (var i = 0; i < n; i++) { + added++; + game.newDot(x + i * Conf.dotSpace + d * M.zagzig(i * c), y + b + * M.zigzag(i * a)); + } + return added; + +}, function(game) { + return game.dist < 30000 ? 0 : game.dist < 17500 ? 1 : 2; +}); + +// rect +Conf.randomPattern.add(function(game, x) { + var n = M.random(3, 8), m = n; + var y = M.random(Conf.min, Conf.max - m * Conf.dotSpace); + + var added = 0; + for (var i = 0; i < n; i++) { + for (var j = 0; j < m; j++) { + added++; + game.newDot(x + i * Conf.dotSpace, y + j * Conf.dotSpace); + } + } + return added; + +}, function(game) { + return game.dist < 70000 ? 0 : 1; +}); + +// spray +Conf.randomPattern.add(function(game, x) { + var n = M.random(40, 60); + var max = Math.min(1, game.dist / 100000); + var min = Math.min(1, game.dist / 200000); + var ab = Conf.randomPattern.range(min * 0.5, max * 0.7); + + var added = 0; + for (var i = 0; i < n; i++) { + added++; + game.newDot(x + i * Conf.dotSpace, M.random(ab.a, ab.b)); + } + return added; + +}, function(game) { + return game.dist < 50000 ? 0 : game.dist < 75000 ? 1 : 2; +}); + +// flower +Conf.randomPattern.add(function(game, x) { + var n = M.random(40, 60); + var f = M.random(0.2, 0.9) * Math.PI; + var c = 5; + + var added = 0; + for (var 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 added; + +}, function(game) { + return game.dist < 100000 ? 0 : 1; +}); + +Cut.Math.zigzag = function(t) { + t = Cut.Math.rotate(t, -Math.PI, Math.PI) / Math.PI * 2; + if (t > 1) { + t = 2 - t; + } else if (t < -1) { + t = -2 - t; + } + return t; +}; + +Cut.Math.zagzig = function(t) { + return Cut.Math.zigzag(t + Math.PI / 2); +}; + +Array.prototype.at = function(i) { + i = this.length > 1 ? i % this.length : 0; + i = i < 0 ? i + this.length : i; + return this[i]; +}; + +Cut.prototype.xy = function(x, y) { + this.pin({ + offsetX : x, + offsetY : y + }); + return this; +}; + +Cut.prototype.x = function(x) { + if (!arguments.length) { + return this.pin("offsetX"); + } + this.pin("offsetX", x); + return this; +}; + +Cut.prototype.y = function(y) { + if (!arguments.length) { + return this.pin("offsetY"); + } + this.pin("offsetY", y); + return this; +}; diff --git a/src/bower.json b/src/bower.json new file mode 100644 index 0000000..d0af640 --- /dev/null +++ b/src/bower.json @@ -0,0 +1,7 @@ +{ + "name": "game-o", + "dependencies": { + "cutjs": "*", + "extrajs": "*" + } +} \ No newline at end of file diff --git a/src/index.html b/src/index.html new file mode 100644 index 0000000..4f9566c --- /dev/null +++ b/src/index.html @@ -0,0 +1,43 @@ + + + O! - Piqnt + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/media/base.png b/src/media/base.png new file mode 100644 index 0000000..0afe246 Binary files /dev/null and b/src/media/base.png differ diff --git a/src/polyfills.js b/src/polyfills.js new file mode 100644 index 0000000..019d1c0 --- /dev/null +++ b/src/polyfills.js @@ -0,0 +1,21 @@ +// Function.bind +// source: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/bind +if (!Function.prototype.bind) { + Function.prototype.bind = function(obj) { + if (typeof this !== "function") { + // closest thing possible to the ECMAScript 5 internal IsCallable function + throw new TypeError( + "Function.prototype.bind - what is trying to be bound is not callable"); + } + + var self = this, args = Array.prototype.slice.call(arguments, 1), type = function() { + }, bound = function() { + return self.apply(this instanceof type && obj ? this : obj, args + .concat(Array.prototype.slice.call(arguments))); + }; + type.prototype = this.prototype; + bound.prototype = new type(); + + return bound; + }; +} \ No newline at end of file diff --git a/src/textures.js b/src/textures.js new file mode 100644 index 0000000..a9ccfc9 --- /dev/null +++ b/src/textures.js @@ -0,0 +1,156 @@ +Cut.addTexture({ + name : "base", + imagePath : "media/base.png", + imageRatio : 8, + ratio : 16, + filter : function(cut) { + cut.y = 8 - (cut.y + cut.h); + return cut; + }, + sprites : [ + { name : "coin_1_", x : 0, y : 5, w : 1, h : 1 }, + { name : "coin_2_", x : 1, y : 5, w : 1, h : 1 }, + { name : "coin_5_", x : 2, y : 5, w : 1, h : 1 }, + { name : "coin_10_", x : 3, y : 5, w : 1, h : 1 }, + { name : "coin_20_", x : 4, y : 5, w : 1, h : 1 }, + { name : "coin_50_", x : 5, y : 5, w : 1, h : 1 }, + { name : "coin_100_", x : 6, y : 5, w : 1, h : 1 }, + { name : "coin_1000_",x : 7, y : 5, w : 1, h : 1 }, + { name : "coin_10000_",x : 8, y : 5, w : 1, h : 1 }, + + { name : "player_", x : 0, y : 1, w : 1, h : 1 }, + { name : "player_", x : 1, y : 1, w : 1, h : 1 }, + { name : "player_", x : 2, y : 1, w : 1, h : 1 }, + { name : "player_", x : 3, y : 1, w : 1, h : 1 }, + { name : "player_", x : 4, y : 1, w : 1, h : 1 }, + { name : "player_", x : 3, y : 1, w : 1, h : 1 }, + { name : "player_", x : 2, y : 1, w : 1, h : 1 }, + { name : "player_", x : 1, y : 1, w : 1, h : 1 }, + + { name : "cursor", x : 1, y : 0, w : 1, h : 1 }, + + { name : "tombstone", x :12+3/8,y :4+3/8, w : 4-3/8, h : 4-3/8 }, + + { name : "energy", x : 2, y : 0.4, w : 2, h : 0.3, left: 0.125, right: 0.125 }, + { name : "dot", x : 4, y : 0, w : 1, h : 1 }, + { name : "power", x : 5, y : 0, w : 1, h : 1 }, + + { name : "up_power", x : 6, y : 4, w : 1, h : 1 }, + { name : "up_energy", x : 7, y : 4, w : 1, h : 1 }, + { name : "up_speed", x : 8, y : 4, w : 1, h : 1 }, + { name : "up_pull", x : 9, y : 4, w : 1, h : 1 }, + { name : "up_push", x : 10, y : 4, w : 1, h : 1 }, + { name : "up_slow", x : 11, y : 4, w : 1, h : 1 }, + + { name : "up_0", x : 9.50, y : 1.35, w : 1, h : 0.3 }, + { name : "up_1", x : 9.25, y : 1.35, w : 1, h : 0.3 }, + { name : "up_2", x : 9.00, y : 1.35, w : 1, h : 0.3 }, + { name : "up_3", x : 8.75, y : 1.35, w : 1, h : 0.3 }, + { name : "up_4", x : 8.50, y : 1.35, w : 1.25, h : 0.3 }, + { name : "up_5", x : 8.25, y : 1.35, w : 1.50, h : 0.3 }, + { name : "up_6", x : 8.00, y : 1.35, w : 1.50, h : 0.3 }, + + { name : "maximize", x : 11, y : 1, w : 1, h : 1 }, + + { name : "die_", x : 2, y : 1, w : 1, h : 1 }, + { name : "die_", x : 6, y : 1, w : 1, h : 1 }, + { name : "die_", x : 5, y : 1, w : 1, h : 1 }, + { name : "die_", x : 2, y : 1, w : 1, h : 1 }, + { name : "die_", x : 6, y : 1, w : 1, h : 1 }, + { name : "die_", x : 5, y : 1, w : 1, h : 1 }, + { name : "die_", x : 2, y : 1, w : 1, h : 1 }, + { name : "die_", x : 6, y : 1, w : 1, h : 1 }, + { name : "die_", x : 5, y : 1, w : 1, h : 1 }, + { name : "die_", x : 5, y : 1, w : 1, h : 1 }, + + { name : "unbox", x : 5, y: 2, w : 1, h : 1 }, + + { name : "box_", x : 1, y: 2, w : 1, h : 1 }, + { name : "box_", x : 0, y: 2, w : 1, h : 1 }, + { name : "box_", x : 0, y: 2, w : 1, h : 1 }, + { name : "box_", x : 1, y: 2, w : 1, h : 1 }, + { name : "box_", x : 2, y: 2, w : 1, h : 1 }, + + { name : "boxz_", x : 6, y: 2, w : 1, h : 1 }, + { name : "boxz_", x : 7, y: 2, w : 1, h : 1 }, + { name : "boxz_", x : 8, y: 2, w : 1, h : 1 }, + + { name : "box_", x : 3, y: 2, w : 1, h : 1 }, + { name : "box_", x : 4, y: 2, w : 1, h : 1 }, + { name : "box_", x : 4, y: 2, w : 1, h : 1 }, + { name : "box_", x : 3, y: 2, w : 1, h : 1 }, + { name : "box_", x : 2, y: 2, w : 1, h : 1 }, + + { name : "boxz_", x : 9, y: 2, w : 1, h : 1 }, + { name : "boxz_", x : 10, y: 2, w : 1, h : 1 }, + { name : "boxz_", x : 11, y: 2, w : 1, h : 1 }, + + { name : "untri", x : 5, y : 3, w : 1, h : 1 }, + + { name : "tri_", x : 1, y : 3, w : 1, h : 1 }, + { name : "tri_", x : 0, y : 3, w : 1, h : 1 }, + { name : "tri_", x : 1, y : 3, w : 1, h : 1 }, + { name : "tri_", x : 2, y : 3, w : 1, h : 1 }, + + { name : "triz_", x : 6, y : 3, w : 1, h : 1 }, + { name : "triz_", x : 7, y : 3, w : 1, h : 1 }, + { name : "triz_", x : 8, y : 3, w : 1, h : 1 }, + + { name : "tri_", x : 3, y : 3, w : 1, h : 1 }, + { name : "tri_", x : 4, y : 3, w : 1, h : 1 }, + { name : "tri_", x : 3, y : 3, w : 1, h : 1 }, + { name : "tri_", x : 2, y : 3, w : 1, h : 1 }, + + { name : "triz_", x : 9, y : 3, w : 1, h : 1 }, + { name : "triz_", x : 10, y : 3, w : 1, h : 1 }, + { name : "triz_", x : 11, y : 3, w : 1, h : 1 }, + + { name : "d_0", x : 6+0* 0.5, y : 0.3, w : (1+3.7)/16, h : 0.4 }, + { name : "d_1", x : 6+1* 0.5, y : 0.3, w : (1+2.1)/16, h : 0.4 }, + { name : "d_2", x : 6+2* 0.5, y : 0.3, w : (1+3.5)/16, h : 0.4 }, + { name : "d_3", x : 6+3* 0.5, y : 0.3, w : (1+3.3)/16, h : 0.4 }, + { name : "d_4", x : 6+4* 0.5, y : 0.3, w : (1+4.0)/16, h : 0.4 }, + { name : "d_5", x : 6+5* 0.5, y : 0.3, w : (1+3.4)/16, h : 0.4 }, + { name : "d_6", x : 6+6* 0.5, y : 0.3, w : (1+3.7)/16, h : 0.4 }, + { name : "d_7", x : 6+7* 0.5, y : 0.3, w : (1+3.5)/16, h : 0.4 }, + { name : "d_8", x : 6+8* 0.5, y : 0.3, w : (1+3.8)/16, h : 0.4 }, + { name : "d_9", x : 6+9* 0.5, y : 0.3, w : (1+3.8)/16, h : 0.4 }, + { name : "d_-", x : 6+10*0.5, y : 0.3, w : (1+2.0)/16, h : 0.4 }, + { name : "d_.", x : 6+11*0.5, y : 0.3, w : (1+1.0)/16, h : 0.4 }, + { name : "d_k", x : 6+12*0.5, y : 0.3, w : (1+3.0)/16, h : 0.4 }, + { name : "d_M", x : 6+13*0.5, y : 0.3, w : (1+6.0)/16, h : 0.4 }, + { name : "d_$", x : 6+14*0.5, y : 0.3, w : (1+5.0)/16, h : 0.4 }, + { name : "d_ ", x : 6+15*0.5, y : 0.3, w : (1+4.0)/16, h : 0.4 }, + + { name : "playbg", x : 0.1, y : 7.1, w : 0.8, h : 0.8 }, + { name : "homebg", x : 1.1, y : 7.1, w : 0.8, h : 0.8 }, + + { name : "c_10", x : 2.1, y : 7.1, w : 0.3, h : 0.3 }, + { name : "c_20", x : 2.1, y : 7.6, w : 0.3, h : 0.3 }, + + { name : "c_11", x : 2.6, y : 7.1, w : 0.3, h : 0.3 }, + { name : "c_12", x : 3.1, y : 7.1, w : 0.3, h : 0.3 }, + { name : "c_13", x : 3.6, y : 7.1, w : 0.3, h : 0.3 }, + { name : "c_14", x : 4.1, y : 7.1, w : 0.3, h : 0.3 }, + { name : "c_15", x : 4.6, y : 7.1, w : 0.3, h : 0.3 }, + { name : "c_16", x : 5.1, y : 7.1, w : 0.3, h : 0.3 }, + { name : "c_17", x : 5.6, y : 7.1, w : 0.3, h : 0.3 }, + { name : "c_18", x : 6.1, y : 7.1, w : 0.3, h : 0.3 }, + + { name : "c_21", x : 2.6, y : 7.6, w : 0.3, h : 0.3 }, + { name : "c_22", x : 3.1, y : 7.6, w : 0.3, h : 0.3 }, + { name : "c_23", x : 3.6, y : 7.6, w : 0.3, h : 0.3 }, + { name : "c_24", x : 4.1, y : 7.6, w : 0.3, h : 0.3 }, + { name : "c_25", x : 4.6, y : 7.6, w : 0.3, h : 0.3 }, + { name : "c_26", x : 5.1, y : 7.6, w : 0.3, h : 0.3 }, + { name : "c_27", x : 5.6, y : 7.6, w : 0.3, h : 0.3 }, + { name : "c_28", x : 6.1, y : 7.6, w : 0.3, h : 0.3 }, + + { name : "shadow", x : 6.6, y : 7.9, w : 0.3, h : 0.1 }, + + { name : "option", x : 9.5, y : 6.25, w : 1.5, h : 1.5 }, + { name : "play", x : 7.5, y : 6.25, w : 1.5, h : 1.5 }, + + { name : "border", x : 0, y : 6, w : 1, h : 1 , top: 1/8, bottom: 1/8, left: 1/8, right: 1/8} + ] +}); \ No newline at end of file