/**** * Classes ****/ /** * config { * x : Number || 0, * y : Number || 0, * rotation : Number || 0, * } **/ var ConfigContainer = Container.expand(function (config) { var self = Container.call(this); config = config || {}; ; self.x = config.x || 0; self.y = config.y || 0; self.rotation = config.rotation || 0; ; return self; }); var Textbox = ConfigContainer.expand(function (message, config) { var self = ConfigContainer.call(this, config); config = config || {}; ; var background = self.addChild(new BorderedShape({ width: config.width, height: config.height, weight: 10, anchorY: 1 })); var textboxTail = self.attachAsset('textboxTail', { y: 1, x: 20 }); var logo = self.addChild(new BorderedSymbol('logo', { x: -20, y: 20, anchorX: 0, anchorY: 1, height: config.height + 40 })); var typedText = self.addChild(new TypedText(message, { x: logo.width, y: -config.height / 2, anchorY: 0.5, delay: 50 })); ; self.setText = setText; ; function setText(newText) { typedText.setText(newText); } ; return self; }); var Table = ConfigContainer.expand(function (config) { var self = ConfigContainer.call(this, config); ; var currentY = 0; var spawnPoints = []; var indices = []; for (var i = 0; i < TABLE_SLICES; i++) { var tableSliceId = 'tableSlice' + (i + 1); var tableSlice = self.attachAsset(tableSliceId, { x: 0, y: currentY, anchorX: 0.5, anchorY: 0 }); var scaleRatio = config.width / tableSlice.width; tableSlice.width = config.width; tableSlice.height *= scaleRatio; currentY += tableSlice.height; var holeCount = TABLE_HOLES[i]; var offset = TABLE_HOLE_GAP * (holeCount - 1) / 2; for (var j = 0; j < holeCount; j++) { indices.push(indices.length); spawnPoints.push(self.addChild(new ConfigContainer({ x: -offset + TABLE_HOLE_GAP * j, y: currentY }))); } } ; self.spawn = spawn; self.despawn = despawn; ; function spawn() { if (leaders.length > 0) { var slotIndex = indices.splice(Math.floor(Math.random() * indices.length), 1)[0]; var className = leaders.splice(Math.floor(Math.random() * leaders.length), 1)[0]; leaderList.push(spawnPoints[slotIndex].addChild(new className({ className: className, slotIndex: slotIndex }))); } } function despawn(slotIndex, className) { indices.push(slotIndex); leaders.push(className); } ; return self; }); var StartButton = ConfigContainer.expand(function (config) { var self = ConfigContainer.call(this, config); ; var startButtonAsset = self.attachAsset('startButton', { anchorX: 0.5, anchorY: 0.5 }); ; return self; }); // Create an instance of StartButton in the middle of the screen var Leader = ConfigContainer.expand(function (imageId, config) { var self = ConfigContainer.call(this, config); ; var countdownTime = LEADER_DURATION; var leaderAsset = self.attachAsset(imageId, { anchorX: 0.5, anchorY: 0 }); var censorAsset = self.addChild(new BorderedShape({ y: 45, anchorX: 0.5, anchorY: 0, width: 110, height: 25, fill: '#000000', border: '#FFFFFF' })); self.scale.set(Math.random() < 0.5 ? -1 : 1, 1); ; self.update = update; self.slotIndex = config.slotIndex; self.className = config.className; self.leaderAsset = leaderAsset; self.censorAsset = censorAsset; self.bonked = false; ; function update() { if (countdownTime === LEADER_DURATION) { if (self.y > -leaderAsset.height) { self.y = Math.max(-leaderAsset.height, self.y - leaderAsset.height / LEADER_SPAWN_TIME); } else { countdownTime--; } } else if (countdownTime > 0) { countdownTime--; } else { if (self.y < 0) { self.y += leaderAsset.height / LEADER_SPAWN_TIME; } else { return true; } } } function tryBonk() { if (!self.bonked) { // TODO: Check if collision before performing scoreText.setText(++score); self.countdown = 0; self.bonked = true; return true; } } ; return self; }); var LeaderTroll6 = Leader.expand(function (config) { var self = Leader.call(this, 'leaderTroll6', config); ; return self; }); var LeaderTroll5 = Leader.expand(function (config) { var self = Leader.call(this, 'leaderTroll5', config); ; self.censorAsset.y += 45; ; return self; }); var LeaderTroll4 = Leader.expand(function (config) { var self = Leader.call(this, 'leaderTroll4', config); ; self.censorAsset.y -= 5; ; return self; }); var LeaderTroll3 = Leader.expand(function (config) { var self = Leader.call(this, 'leaderTroll3', config); ; self.censorAsset.y += 8; ; return self; }); var LeaderTroll2 = Leader.expand(function (config) { var self = Leader.call(this, 'leaderTroll2', config); ; var leaderHat = self.attachAsset('leaderTrollHat', { anchorX: 0.5, anchorY: 0.25, rotation: -0.3 }); self.censorAsset.x += 20; self.censorAsset.y += 5; ; return self; }); var LeaderTroll1 = Leader.expand(function (config) { var self = Leader.call(this, 'leaderTroll1', config); ; self.censorAsset.x += 20; ; return self; }); var LeaderGreat1 = Leader.expand(function (config) { var self = Leader.call(this, 'leaderGreat1', config); ; return self; }); var ImpactParticle = ConfigContainer.expand(function (config) { var self = ConfigContainer.call(this, config); ; var elapsedTicks = 0; var selectedAsset = 'hammerParticle' + (1 + Math.floor(Math.random() * PARTICLE_HAMMER_ASSETS)); var particle = self.attachAsset(selectedAsset, { rotation: PARTICLE_HAMMER_ROTATION * (Math.random() - 0.5), anchorX: 0.5, anchorY: 0.5 }); ; self.update = update; ; function update() { elapsedTicks++; if (elapsedTicks <= PARTICLE_HAMMER_STAGE_2) { var scale = 1 + (PARTICLE_HAMMER_SCALE_MAX - 1) * elapsedTicks / PARTICLE_HAMMER_STAGE_2; particle.scale.set(scale, scale); } else if (elapsedTicks > PARTICLE_HAMMER_STAGE_2 && elapsedTicks <= PARTICLE_HAMMER_STAGE_2 + PARTICLE_HAMMER_STAGE_3) { var progress = 1 - (elapsedTicks - PARTICLE_HAMMER_STAGE_2) / PARTICLE_HAMMER_STAGE_3; var scale = PARTICLE_HAMMER_SCALE_MAX * progress; particle.alpha = progress; particle.scale.set(scale); } else { return true; } } ; return self; }); var HammerParticle = ConfigContainer.expand(function (config) { var self = ConfigContainer.call(this, config); config = config || {}; ; var xFlip = config.xFlip || 1; var stage = 1; var elapsedTicks = 0; var hammer = self.attachAsset('hammer', { anchorX: 0.75, anchorY: 0.75, scale: { x: xFlip, y: 1 } }); hammer.x = -xFlip * hammer.width * 0.6; ; self.update = update; ; function update() { elapsedTicks++; if (stage === 1) { if (elapsedTicks <= PARTICLE_HAMMER_STAGE_1) { hammer.rotation += xFlip * PARTICLE_HAMMER_SPIN / PARTICLE_HAMMER_STAGE_1; } else { elapsedTicks = 0; stage++; handleImpactPoint(self.x, self.y); particleList.push(midground.addChild(new ImpactParticle({ x: self.x, y: self.y }))); } } else if (stage === 2) { if (elapsedTicks <= PARTICLE_HAMMER_STAGE_2) { var alpha = 1 - elapsedTicks / PARTICLE_HAMMER_STAGE_2; hammer.alpha = alpha; } else { return true; } } } ; return self; }); /** * config { * x : Number || 0, // See: ConfigContainer * y : Number || 0, // See: ConfigContainer * rotation : Number || 0, // See: ConfigContainer * anchorX : Number || 0, * anchorY : Number || 1, * size : Number || TEXT_DEFAULT_SIZE, * weight : Number || TEXT_DEFAULT_WEIGHT, * font : String || TEXT_DEFAULT_FONT, * fill : String || TEXT_DEFAULT_FILL, * border : String || TEXT_DEFAULT_BORDER, * } **/ var BorderedText = ConfigContainer.expand(function (text, config) { var self = ConfigContainer.call(this, config); config = config || {}; ; var anchorX = config.anchorX !== undefined ? config.anchorX : 0; var anchorY = config.anchorY !== undefined ? config.anchorY : 1; var size = config.size !== undefined ? config.size : TEXT_DEFAULT_SIZE; var weight = config.weight !== undefined ? config.weight : TEXT_DEFAULT_WEIGHT; var font = config.font !== undefined ? config.font : TEXT_DEFAULT_FONT; var textFill = config.fill !== undefined ? config.fill : TEXT_DEFAULT_FILL; var borderFill = config.border !== undefined ? config.border : TEXT_DEFAULT_BORDER; var textAssets = []; var mainAsset; ; self.setText = setText; self.setFill = setFill; ; function setText(newText) { for (var i = 0; i < textAssets.length; i++) { textAssets[i].setText(newText); } } function setFill(newFill) { textFill = newFill; mainAsset.fill = newFill; } function buildTextAssets(newText) { for (var i = 0; i < TEXT_OFFSETS.length; i++) { var main = i === TEXT_OFFSETS.length - 1; var fill = main ? textFill : borderFill; var textAsset = textAssets[i]; if (textAsset) { textAsset.destroy(); } textAsset = self.addChild(new Text2(newText, { fill: fill, font: font, size: size })); textAsset.anchor = { x: anchorX, y: anchorY }; // NOTE: Cannot be set in config textAsset.x = TEXT_OFFSETS[i][0] * weight; // NOTE: Cannot be set in config textAsset.y = TEXT_OFFSETS[i][1] * weight; // NOTE: Cannot be set in config textAssets[i] = textAsset; } mainAsset = textAssets[TEXT_OFFSETS.length - 1]; } ; buildTextAssets(text); return self; }); var TypedText = BorderedText.expand(function (text, config) { var self = BorderedText.call(this, text, config); var baseSetText = self.setText; config = config || {}; ; var counter = 0; var delay = config.delay; var interval; ; self.setText = setText; self.completed = false; ; function setText(newText) { if (interval) { LK.clearInterval(interval); } self.completed = false; text = newText; counter = 0; interval = LK.setInterval(updateText, delay); updateText(); } function updateText() { var subText = text.substr(0, ++counter).replace(/#/g, ''); baseSetText(subText); if (counter === text.length) { LK.clearInterval(interval); self.completed = true; } } ; setText(text); return self; }); /** * var config = { * x : Number || 0, // See: ConfigContainer * y : Number || 0, // See: ConfigContainer * rotation : Number || 0, // See: ConfigContainer * anchorX : Number || .5, * anchorY : Number || .5, * scale : Number || undefined, * scaleX : Number || scale, * scaleY : Number || scale, * weight : Number || TEXT_DEFAULT_WEIGHT, * width : Number || undefined, // Auto-calculated if left undefined and height is set * height : Number || undefined, // Auto-calculated if left undefined and width is set * tint : String || 0xFFFFFF, // Not tinted by default * border : String || TEXT_DEFAULT_BORDER, * } **/ var BorderedSymbol = ConfigContainer.expand(function (symbol, config) { var self = ConfigContainer.call(this, config); config = config || {}; var width = config.width !== undefined ? config.width : undefined; var height = config.height !== undefined ? config.height : undefined; var scale = config.scale !== undefined ? config.scale : undefined; var scaleX = config.scaleX !== undefined ? config.scaleX : scale; var scaleY = config.scaleY !== undefined ? config.scaleX : scale; var weight = config.weight !== undefined ? config.weight : TEXT_DEFAULT_WEIGHT; var anchorX = config.anchorX !== undefined ? config.anchorX : .5; var anchorY = config.anchorY !== undefined ? config.anchorY : .5; var symbolTint = config.tint !== undefined ? config.tint : 0xFFFFFF; var borderTint = config.border !== undefined ? config.border : TEXT_DEFAULT_BORDER; var mainSymbol; var symbolAssets = []; ; self.setSymbol = buildSymbolAssets; self.setTint = setTint; ; function setTint(newTint) { // NOTE: Tinting is currently broken (cannot use string) // mainSymbol.tint = newTint; // symbolConfig.tint = newTint } function buildSymbolAssets(newSymbol) { for (var i = 0; i < TEXT_OFFSETS.length; i++) { var main = i === TEXT_OFFSETS.length - 1; var symbolAsset = symbolAssets[i]; if (symbolAsset) { symbolAsset.destroy(); } symbolAsset = self.attachAsset(newSymbol, { // tint: main ? symbolTint : borderTint, tint: main ? 0xFFFFFF : 0x000000, // NOTE: Tinting is currently broken (cannot use string) x: TEXT_OFFSETS[i][0] * weight, y: TEXT_OFFSETS[i][1] * weight, anchorX: anchorX, anchorY: anchorY }); if (width !== undefined && height === undefined) { height = symbolAsset.height * (width / symbolAsset.width); } else if (height !== undefined && width === undefined) { width = symbolAsset.width * (height / symbolAsset.height); } symbolAsset.width = width; symbolAsset.height = height; if (scaleX !== undefined && scaleY !== undefined) { symbolAsset.scale.set(scaleX, scaleY); } symbolAssets[i] = symbolAsset; } mainSymbol = symbolAssets[TEXT_OFFSETS.length - 1]; } ; buildSymbolAssets(symbol); return self; }); /** * config { * x : Number || 0, // See: ConfigContainer * y : Number || 0, // See: ConfigContainer * rotation : Number || 0, // See: ConfigContainer * anchorX : Number || 0, * anchorY : Number || 0, * width : Number || 100, * height : Number || 100, * weight : Number || TEXT_DEFAULT_WEIGHT, * shape : String || 'square', * fill : String || TEXT_DEFAULT_FILL, * border : String || TEXT_DEFAULT_BORDER, * } **/ var BorderedShape = ConfigContainer.expand(function (config) { var self = ConfigContainer.call(this, config); config = config || {}; ; var anchorX = config.anchorX !== undefined ? config.anchorX : 0; var anchorY = config.anchorY !== undefined ? config.anchorY : 0; var width = config.width !== undefined ? config.width : 100; var height = config.height !== undefined ? config.height : 100; var weight = config.weight !== undefined ? config.weight : TEXT_DEFAULT_WEIGHT; var shape = config.shape !== undefined ? config.shape : 'shapeRectangle'; var frontTint = hexToHex(config.fill !== undefined ? config.fill : TEXT_DEFAULT_FILL); var borderTint = hexToHex(config.border !== undefined ? config.border : TEXT_DEFAULT_BORDER); var background = self.attachAsset(shape, { x: weight * 2 * (anchorX - 0.5), y: weight * 2 * (anchorY - 0.5), tint: borderTint, width: width + 2 * weight, height: height + 2 * weight, anchorX: anchorX, anchorY: anchorY }); var foreground = self.attachAsset(shape, { tint: frontTint, width: width, height: height, anchorX: anchorX, anchorY: anchorY }); ; return self; }); /**** * Initialize Game ****/ // Assets will be automatically initialized based on usage in the code. var game = new LK.Game({ backgroundColor: 0xD3D3D3 // Init game with light grey background }); /**** * Game Code ****/ ; //============================================================================== // Global constants & settings //============================================================================== ; // Math constants / pre-calculations var MATH_2_PI = Math.PI * 2; var MATH_HALF_PI = Math.PI / 2; var MATH_QUARTER_PI = Math.PI / 4; var MATH_HALF_ROOT_3 = Math.sqrt(3) / 2; // Required by: TEXT_OFFSETS, BorderedText, BorderedSymbol, BorderedShape, SymbolText var MATH_APPROX_ZERO = 0.0000001; ; // Text settings var TEXT_OFFSETS = [[0, 1], [MATH_HALF_ROOT_3, 0.5], [MATH_HALF_ROOT_3, -0.5], [0, -1], [-MATH_HALF_ROOT_3, -0.5], [-MATH_HALF_ROOT_3, 0.5], [0, 0]]; // Required by: BorderedText, BorderedSymbol, BorderedShape, SymbolText var TEXT_DEFAULT_WEIGHT = 6; // Required by: BorderedText, BorderedSymbol, BorderedShape, SymbolText var TEXT_DEFAULT_BORDER = '#000000'; // Required by: BorderedText, BorderedSymbol, BorderedShape, SymbolText var TEXT_DEFAULT_FILL = '#FFFFFF'; // Required by: BorderedText, SymbolText var TEXT_DEFAULT_FONT = 'Arial'; // Required by: BorderedText, SymbolText var TEXT_DEFAULT_SIZE = 50; // Required by: BorderedText, SymbolText var TEXT_DEFAULT_MARGIN = 10; // Required by: SymbolText ; // Game constants var GAME_TICKS = 60; var GAME_WIDTH = 2048; var GAME_HEIGHT = 2732; ; // Particle settings var PARTICLE_HAMMER_SPIN = MATH_QUARTER_PI * 2.5; var PARTICLE_HAMMER_STAGE_1 = Math.round(0.075 * GAME_TICKS); var PARTICLE_HAMMER_STAGE_2 = Math.round(0.075 * GAME_TICKS); var PARTICLE_HAMMER_STAGE_3 = Math.round(0.4 * GAME_TICKS); var PARTICLE_HAMMER_ASSETS = 5; var PARTICLE_HAMMER_ROTATION = MATH_QUARTER_PI; var PARTICLE_HAMMER_SCALE_MAX = 2.0; // Leader settings var LEADER_DURATION = 1 * GAME_TICKS; var LEADER_SPAWN_MIN = 2 * GAME_TICKS; var LEADER_SPAWN_VAR = 1 * GAME_TICKS; var LEADER_SPAWN_FACTOR = 0.95; var LEADER_SPAWN_TIME = Math.round(0.075 * GAME_TICKS); // Table settings var TABLE_WIDTH = 2500; var TABLE_DEPTH = 1500; var TABLE_CENTER_Y = GAME_HEIGHT / 2 + 125; var TABLE_SLICES = 6; var TABLE_HOLES = [1, 2, 3, 2, 1, 0]; var TABLE_HOLE_WIDTH = 334; var TABLE_HOLE_GAP = 778; var TABLE_BUTTON_INDEX = 4; // Other settings var COUNTDOWN_GAME = 60 * GAME_TICKS; var HAMMER_RADIUS = 50; // Messages var MESSAGE_REFRESH = 5 * GAME_TICKS; var MESSAGE_INTRO = 'Blue Lizard Entertainment proudly presents: #####Whac-a-Mo...##########\n... Whac-a-##########Politician? Are we T###R###Y###I###N###G### to get sued.########## Again?'; var MESSAGE_START = 'And off you go... Good luck. You\'ll probably need it for this beta-mess.'; var MESSAGE_WRONG = ['Apparently you shouldn\'t bonk the Kiwi.', 'This isn\'t Kiwi Clicker.']; var MESSAGE_OUTRO = 'Well, that\'s all there is... Good job! Thanks for playing.'; var MESSAGE_EXTRA = 'That\'s a Sneaky one that... Good job! Thanks for playing.'; var MESSAGE_RANDO = []; MESSAGE_RANDO.push('Was this a "Bobby-proposal"?'); MESSAGE_RANDO.push('Oh, we are S###O###O###O### getting sued for this.'); MESSAGE_RANDO.push('These people are the pinnacle leaders of humanity, surely not?'); MESSAGE_RANDO.push('The Europeans leaders seem...########## Okay?########## For once.'); MESSAGE_RANDO.push('This game must be divine punishment for milking a bad M###M###O### for decades.'); MESSAGE_RANDO.push('I\'m just here as a distraction to keep you from beating the company highscores.'); MESSAGE_RANDO.push('Let\'s play spin the bottle on which game company is halving their workforce, again.'); ; //============================================================================== // Global variables //============================================================================== ; var started = false; var score = 0; var countdown = COUNTDOWN_GAME; var spawnTime = LEADER_SPAWN_MIN; var spawnTimer = spawnTime; var messageTimer = MESSAGE_REFRESH; var leaders = [LeaderGreat1, LeaderTroll1, LeaderTroll2, LeaderTroll3, LeaderTroll4, LeaderTroll5, LeaderTroll6]; var leaderList = []; var particleList = []; ; var background = game.addChild(new Container()); var midground = game.addChild(new Container()); var foreground = game.addChild(new Container()); var table = background.addChild(new Table({ x: GAME_WIDTH / 2, y: GAME_HEIGHT / 2 - 600, width: TABLE_WIDTH })); var startButton = midground.addChild(new StartButton({ x: GAME_WIDTH / 2, y: TABLE_CENTER_Y })); ; var textbox = game.addChild(new Textbox(MESSAGE_INTRO, { x: 100, y: GAME_HEIGHT - 100, width: GAME_WIDTH - 200, height: 200 })); var countdownText = LK.gui.top.addChild(new BorderedText(Math.ceil(countdown / GAME_TICKS), { anchorX: 0.5, anchorY: 0, size: 200 })); var scoreText = LK.gui.topRight.addChild(new BorderedText(score, { x: -20, anchorX: 1, anchorY: 0, size: 100 })); ; //============================================================================== // Game events //============================================================================== ; game.on('down', function (obj) { var event = obj.event; var pos = event.getLocalPosition(game); var dx = Math.abs(GAME_WIDTH / 2 - pos.x) / TABLE_WIDTH; var dy = Math.abs(TABLE_CENTER_Y - pos.y) / TABLE_DEPTH; if (dx + dy <= 0.5) { particleList.push(foreground.addChild(new HammerParticle({ xFlip: pos.x < GAME_WIDTH / 2 ? -1 : 1, x: pos.x, y: pos.y }))); } }); ; LK.on('tick', function () { if (started) { handleSpawnTimer(); handleMessageRefresh(); if (--countdown <= 0) { LK.showGameOver(); } countdownText.setText(Math.ceil(countdown / GAME_TICKS)); for (var i = leaderList.length - 1; i >= 0; i--) { var leader = leaderList[i]; if (leader.update()) { table.despawn(leader.slotIndex, leader.className); leader.destroy(); leaderList.splice(i, 1); } } } for (var i = particleList.length - 1; i >= 0; i--) { if (particleList[i].update()) { particleList[i].destroy(); particleList.splice(i, 1); } } }); ; //============================================================================== // Global functions //============================================================================== ; // Handlers ; function handleSpawnTimer() { if (--spawnTimer <= 0) { spawnTimer += spawnTime; spawnTime = spawnTime * LEADER_SPAWN_FACTOR; LK.setTimeout(table.spawn, Math.random() * LEADER_SPAWN_VAR); } } function handleMessageRefresh() { if (--messageTimer <= 0 && MESSAGE_RANDO.length) { textbox.setText(MESSAGE_RANDO.splice(Math.floor(Math.random() * MESSAGE_RANDO.length), 1)[0]); messageTimer = MESSAGE_REFRESH; } } function handleImpactPoint(x, y) { if (!started) { var dx = GAME_WIDTH / 2 - x; var dy = TABLE_CENTER_Y - y; if (pointWithinOval(dx, dy, startButton.width * 0.5, startButton.height * 0.5)) { started = true; startButton.destroy(); startButton = undefined; } } else { // TODO: Check bonk collisions } } ; // Library ; function hexToHex(input) { if (typeof input === 'string') { return parseInt(input.replace(/^#/, ''), 16); } else if (typeof input === 'number') { return '#' + input.toString(16).padStart(6, '0'); } return input; } function pointWithinOval(dx, dy, rx, ry) { return dx * dx / (rx * rx) + dy * dy / (ry * ry) <= 1; }
/****
* Classes
****/
/**
* config {
* x : Number || 0,
* y : Number || 0,
* rotation : Number || 0,
* }
**/
var ConfigContainer = Container.expand(function (config) {
var self = Container.call(this);
config = config || {};
;
self.x = config.x || 0;
self.y = config.y || 0;
self.rotation = config.rotation || 0;
;
return self;
});
var Textbox = ConfigContainer.expand(function (message, config) {
var self = ConfigContainer.call(this, config);
config = config || {};
;
var background = self.addChild(new BorderedShape({
width: config.width,
height: config.height,
weight: 10,
anchorY: 1
}));
var textboxTail = self.attachAsset('textboxTail', {
y: 1,
x: 20
});
var logo = self.addChild(new BorderedSymbol('logo', {
x: -20,
y: 20,
anchorX: 0,
anchorY: 1,
height: config.height + 40
}));
var typedText = self.addChild(new TypedText(message, {
x: logo.width,
y: -config.height / 2,
anchorY: 0.5,
delay: 50
}));
;
self.setText = setText;
;
function setText(newText) {
typedText.setText(newText);
}
;
return self;
});
var Table = ConfigContainer.expand(function (config) {
var self = ConfigContainer.call(this, config);
;
var currentY = 0;
var spawnPoints = [];
var indices = [];
for (var i = 0; i < TABLE_SLICES; i++) {
var tableSliceId = 'tableSlice' + (i + 1);
var tableSlice = self.attachAsset(tableSliceId, {
x: 0,
y: currentY,
anchorX: 0.5,
anchorY: 0
});
var scaleRatio = config.width / tableSlice.width;
tableSlice.width = config.width;
tableSlice.height *= scaleRatio;
currentY += tableSlice.height;
var holeCount = TABLE_HOLES[i];
var offset = TABLE_HOLE_GAP * (holeCount - 1) / 2;
for (var j = 0; j < holeCount; j++) {
indices.push(indices.length);
spawnPoints.push(self.addChild(new ConfigContainer({
x: -offset + TABLE_HOLE_GAP * j,
y: currentY
})));
}
}
;
self.spawn = spawn;
self.despawn = despawn;
;
function spawn() {
if (leaders.length > 0) {
var slotIndex = indices.splice(Math.floor(Math.random() * indices.length), 1)[0];
var className = leaders.splice(Math.floor(Math.random() * leaders.length), 1)[0];
leaderList.push(spawnPoints[slotIndex].addChild(new className({
className: className,
slotIndex: slotIndex
})));
}
}
function despawn(slotIndex, className) {
indices.push(slotIndex);
leaders.push(className);
}
;
return self;
});
var StartButton = ConfigContainer.expand(function (config) {
var self = ConfigContainer.call(this, config);
;
var startButtonAsset = self.attachAsset('startButton', {
anchorX: 0.5,
anchorY: 0.5
});
;
return self;
});
// Create an instance of StartButton in the middle of the screen
var Leader = ConfigContainer.expand(function (imageId, config) {
var self = ConfigContainer.call(this, config);
;
var countdownTime = LEADER_DURATION;
var leaderAsset = self.attachAsset(imageId, {
anchorX: 0.5,
anchorY: 0
});
var censorAsset = self.addChild(new BorderedShape({
y: 45,
anchorX: 0.5,
anchorY: 0,
width: 110,
height: 25,
fill: '#000000',
border: '#FFFFFF'
}));
self.scale.set(Math.random() < 0.5 ? -1 : 1, 1);
;
self.update = update;
self.slotIndex = config.slotIndex;
self.className = config.className;
self.leaderAsset = leaderAsset;
self.censorAsset = censorAsset;
self.bonked = false;
;
function update() {
if (countdownTime === LEADER_DURATION) {
if (self.y > -leaderAsset.height) {
self.y = Math.max(-leaderAsset.height, self.y - leaderAsset.height / LEADER_SPAWN_TIME);
} else {
countdownTime--;
}
} else if (countdownTime > 0) {
countdownTime--;
} else {
if (self.y < 0) {
self.y += leaderAsset.height / LEADER_SPAWN_TIME;
} else {
return true;
}
}
}
function tryBonk() {
if (!self.bonked) {
// TODO: Check if collision before performing
scoreText.setText(++score);
self.countdown = 0;
self.bonked = true;
return true;
}
}
;
return self;
});
var LeaderTroll6 = Leader.expand(function (config) {
var self = Leader.call(this, 'leaderTroll6', config);
;
return self;
});
var LeaderTroll5 = Leader.expand(function (config) {
var self = Leader.call(this, 'leaderTroll5', config);
;
self.censorAsset.y += 45;
;
return self;
});
var LeaderTroll4 = Leader.expand(function (config) {
var self = Leader.call(this, 'leaderTroll4', config);
;
self.censorAsset.y -= 5;
;
return self;
});
var LeaderTroll3 = Leader.expand(function (config) {
var self = Leader.call(this, 'leaderTroll3', config);
;
self.censorAsset.y += 8;
;
return self;
});
var LeaderTroll2 = Leader.expand(function (config) {
var self = Leader.call(this, 'leaderTroll2', config);
;
var leaderHat = self.attachAsset('leaderTrollHat', {
anchorX: 0.5,
anchorY: 0.25,
rotation: -0.3
});
self.censorAsset.x += 20;
self.censorAsset.y += 5;
;
return self;
});
var LeaderTroll1 = Leader.expand(function (config) {
var self = Leader.call(this, 'leaderTroll1', config);
;
self.censorAsset.x += 20;
;
return self;
});
var LeaderGreat1 = Leader.expand(function (config) {
var self = Leader.call(this, 'leaderGreat1', config);
;
return self;
});
var ImpactParticle = ConfigContainer.expand(function (config) {
var self = ConfigContainer.call(this, config);
;
var elapsedTicks = 0;
var selectedAsset = 'hammerParticle' + (1 + Math.floor(Math.random() * PARTICLE_HAMMER_ASSETS));
var particle = self.attachAsset(selectedAsset, {
rotation: PARTICLE_HAMMER_ROTATION * (Math.random() - 0.5),
anchorX: 0.5,
anchorY: 0.5
});
;
self.update = update;
;
function update() {
elapsedTicks++;
if (elapsedTicks <= PARTICLE_HAMMER_STAGE_2) {
var scale = 1 + (PARTICLE_HAMMER_SCALE_MAX - 1) * elapsedTicks / PARTICLE_HAMMER_STAGE_2;
particle.scale.set(scale, scale);
} else if (elapsedTicks > PARTICLE_HAMMER_STAGE_2 && elapsedTicks <= PARTICLE_HAMMER_STAGE_2 + PARTICLE_HAMMER_STAGE_3) {
var progress = 1 - (elapsedTicks - PARTICLE_HAMMER_STAGE_2) / PARTICLE_HAMMER_STAGE_3;
var scale = PARTICLE_HAMMER_SCALE_MAX * progress;
particle.alpha = progress;
particle.scale.set(scale);
} else {
return true;
}
}
;
return self;
});
var HammerParticle = ConfigContainer.expand(function (config) {
var self = ConfigContainer.call(this, config);
config = config || {};
;
var xFlip = config.xFlip || 1;
var stage = 1;
var elapsedTicks = 0;
var hammer = self.attachAsset('hammer', {
anchorX: 0.75,
anchorY: 0.75,
scale: {
x: xFlip,
y: 1
}
});
hammer.x = -xFlip * hammer.width * 0.6;
;
self.update = update;
;
function update() {
elapsedTicks++;
if (stage === 1) {
if (elapsedTicks <= PARTICLE_HAMMER_STAGE_1) {
hammer.rotation += xFlip * PARTICLE_HAMMER_SPIN / PARTICLE_HAMMER_STAGE_1;
} else {
elapsedTicks = 0;
stage++;
handleImpactPoint(self.x, self.y);
particleList.push(midground.addChild(new ImpactParticle({
x: self.x,
y: self.y
})));
}
} else if (stage === 2) {
if (elapsedTicks <= PARTICLE_HAMMER_STAGE_2) {
var alpha = 1 - elapsedTicks / PARTICLE_HAMMER_STAGE_2;
hammer.alpha = alpha;
} else {
return true;
}
}
}
;
return self;
});
/**
* config {
* x : Number || 0, // See: ConfigContainer
* y : Number || 0, // See: ConfigContainer
* rotation : Number || 0, // See: ConfigContainer
* anchorX : Number || 0,
* anchorY : Number || 1,
* size : Number || TEXT_DEFAULT_SIZE,
* weight : Number || TEXT_DEFAULT_WEIGHT,
* font : String || TEXT_DEFAULT_FONT,
* fill : String || TEXT_DEFAULT_FILL,
* border : String || TEXT_DEFAULT_BORDER,
* }
**/
var BorderedText = ConfigContainer.expand(function (text, config) {
var self = ConfigContainer.call(this, config);
config = config || {};
;
var anchorX = config.anchorX !== undefined ? config.anchorX : 0;
var anchorY = config.anchorY !== undefined ? config.anchorY : 1;
var size = config.size !== undefined ? config.size : TEXT_DEFAULT_SIZE;
var weight = config.weight !== undefined ? config.weight : TEXT_DEFAULT_WEIGHT;
var font = config.font !== undefined ? config.font : TEXT_DEFAULT_FONT;
var textFill = config.fill !== undefined ? config.fill : TEXT_DEFAULT_FILL;
var borderFill = config.border !== undefined ? config.border : TEXT_DEFAULT_BORDER;
var textAssets = [];
var mainAsset;
;
self.setText = setText;
self.setFill = setFill;
;
function setText(newText) {
for (var i = 0; i < textAssets.length; i++) {
textAssets[i].setText(newText);
}
}
function setFill(newFill) {
textFill = newFill;
mainAsset.fill = newFill;
}
function buildTextAssets(newText) {
for (var i = 0; i < TEXT_OFFSETS.length; i++) {
var main = i === TEXT_OFFSETS.length - 1;
var fill = main ? textFill : borderFill;
var textAsset = textAssets[i];
if (textAsset) {
textAsset.destroy();
}
textAsset = self.addChild(new Text2(newText, {
fill: fill,
font: font,
size: size
}));
textAsset.anchor = {
x: anchorX,
y: anchorY
}; // NOTE: Cannot be set in config
textAsset.x = TEXT_OFFSETS[i][0] * weight; // NOTE: Cannot be set in config
textAsset.y = TEXT_OFFSETS[i][1] * weight; // NOTE: Cannot be set in config
textAssets[i] = textAsset;
}
mainAsset = textAssets[TEXT_OFFSETS.length - 1];
}
;
buildTextAssets(text);
return self;
});
var TypedText = BorderedText.expand(function (text, config) {
var self = BorderedText.call(this, text, config);
var baseSetText = self.setText;
config = config || {};
;
var counter = 0;
var delay = config.delay;
var interval;
;
self.setText = setText;
self.completed = false;
;
function setText(newText) {
if (interval) {
LK.clearInterval(interval);
}
self.completed = false;
text = newText;
counter = 0;
interval = LK.setInterval(updateText, delay);
updateText();
}
function updateText() {
var subText = text.substr(0, ++counter).replace(/#/g, '');
baseSetText(subText);
if (counter === text.length) {
LK.clearInterval(interval);
self.completed = true;
}
}
;
setText(text);
return self;
});
/**
* var config = {
* x : Number || 0, // See: ConfigContainer
* y : Number || 0, // See: ConfigContainer
* rotation : Number || 0, // See: ConfigContainer
* anchorX : Number || .5,
* anchorY : Number || .5,
* scale : Number || undefined,
* scaleX : Number || scale,
* scaleY : Number || scale,
* weight : Number || TEXT_DEFAULT_WEIGHT,
* width : Number || undefined, // Auto-calculated if left undefined and height is set
* height : Number || undefined, // Auto-calculated if left undefined and width is set
* tint : String || 0xFFFFFF, // Not tinted by default
* border : String || TEXT_DEFAULT_BORDER,
* }
**/
var BorderedSymbol = ConfigContainer.expand(function (symbol, config) {
var self = ConfigContainer.call(this, config);
config = config || {};
var width = config.width !== undefined ? config.width : undefined;
var height = config.height !== undefined ? config.height : undefined;
var scale = config.scale !== undefined ? config.scale : undefined;
var scaleX = config.scaleX !== undefined ? config.scaleX : scale;
var scaleY = config.scaleY !== undefined ? config.scaleX : scale;
var weight = config.weight !== undefined ? config.weight : TEXT_DEFAULT_WEIGHT;
var anchorX = config.anchorX !== undefined ? config.anchorX : .5;
var anchorY = config.anchorY !== undefined ? config.anchorY : .5;
var symbolTint = config.tint !== undefined ? config.tint : 0xFFFFFF;
var borderTint = config.border !== undefined ? config.border : TEXT_DEFAULT_BORDER;
var mainSymbol;
var symbolAssets = [];
;
self.setSymbol = buildSymbolAssets;
self.setTint = setTint;
;
function setTint(newTint) {
// NOTE: Tinting is currently broken (cannot use string)
// mainSymbol.tint = newTint;
// symbolConfig.tint = newTint
}
function buildSymbolAssets(newSymbol) {
for (var i = 0; i < TEXT_OFFSETS.length; i++) {
var main = i === TEXT_OFFSETS.length - 1;
var symbolAsset = symbolAssets[i];
if (symbolAsset) {
symbolAsset.destroy();
}
symbolAsset = self.attachAsset(newSymbol, {
// tint: main ? symbolTint : borderTint,
tint: main ? 0xFFFFFF : 0x000000,
// NOTE: Tinting is currently broken (cannot use string)
x: TEXT_OFFSETS[i][0] * weight,
y: TEXT_OFFSETS[i][1] * weight,
anchorX: anchorX,
anchorY: anchorY
});
if (width !== undefined && height === undefined) {
height = symbolAsset.height * (width / symbolAsset.width);
} else if (height !== undefined && width === undefined) {
width = symbolAsset.width * (height / symbolAsset.height);
}
symbolAsset.width = width;
symbolAsset.height = height;
if (scaleX !== undefined && scaleY !== undefined) {
symbolAsset.scale.set(scaleX, scaleY);
}
symbolAssets[i] = symbolAsset;
}
mainSymbol = symbolAssets[TEXT_OFFSETS.length - 1];
}
;
buildSymbolAssets(symbol);
return self;
});
/**
* config {
* x : Number || 0, // See: ConfigContainer
* y : Number || 0, // See: ConfigContainer
* rotation : Number || 0, // See: ConfigContainer
* anchorX : Number || 0,
* anchorY : Number || 0,
* width : Number || 100,
* height : Number || 100,
* weight : Number || TEXT_DEFAULT_WEIGHT,
* shape : String || 'square',
* fill : String || TEXT_DEFAULT_FILL,
* border : String || TEXT_DEFAULT_BORDER,
* }
**/
var BorderedShape = ConfigContainer.expand(function (config) {
var self = ConfigContainer.call(this, config);
config = config || {};
;
var anchorX = config.anchorX !== undefined ? config.anchorX : 0;
var anchorY = config.anchorY !== undefined ? config.anchorY : 0;
var width = config.width !== undefined ? config.width : 100;
var height = config.height !== undefined ? config.height : 100;
var weight = config.weight !== undefined ? config.weight : TEXT_DEFAULT_WEIGHT;
var shape = config.shape !== undefined ? config.shape : 'shapeRectangle';
var frontTint = hexToHex(config.fill !== undefined ? config.fill : TEXT_DEFAULT_FILL);
var borderTint = hexToHex(config.border !== undefined ? config.border : TEXT_DEFAULT_BORDER);
var background = self.attachAsset(shape, {
x: weight * 2 * (anchorX - 0.5),
y: weight * 2 * (anchorY - 0.5),
tint: borderTint,
width: width + 2 * weight,
height: height + 2 * weight,
anchorX: anchorX,
anchorY: anchorY
});
var foreground = self.attachAsset(shape, {
tint: frontTint,
width: width,
height: height,
anchorX: anchorX,
anchorY: anchorY
});
;
return self;
});
/****
* Initialize Game
****/
// Assets will be automatically initialized based on usage in the code.
var game = new LK.Game({
backgroundColor: 0xD3D3D3 // Init game with light grey background
});
/****
* Game Code
****/
;
//==============================================================================
// Global constants & settings
//==============================================================================
;
// Math constants / pre-calculations
var MATH_2_PI = Math.PI * 2;
var MATH_HALF_PI = Math.PI / 2;
var MATH_QUARTER_PI = Math.PI / 4;
var MATH_HALF_ROOT_3 = Math.sqrt(3) / 2; // Required by: TEXT_OFFSETS, BorderedText, BorderedSymbol, BorderedShape, SymbolText
var MATH_APPROX_ZERO = 0.0000001;
;
// Text settings
var TEXT_OFFSETS = [[0, 1], [MATH_HALF_ROOT_3, 0.5], [MATH_HALF_ROOT_3, -0.5], [0, -1], [-MATH_HALF_ROOT_3, -0.5], [-MATH_HALF_ROOT_3, 0.5], [0, 0]]; // Required by: BorderedText, BorderedSymbol, BorderedShape, SymbolText
var TEXT_DEFAULT_WEIGHT = 6; // Required by: BorderedText, BorderedSymbol, BorderedShape, SymbolText
var TEXT_DEFAULT_BORDER = '#000000'; // Required by: BorderedText, BorderedSymbol, BorderedShape, SymbolText
var TEXT_DEFAULT_FILL = '#FFFFFF'; // Required by: BorderedText, SymbolText
var TEXT_DEFAULT_FONT = 'Arial'; // Required by: BorderedText, SymbolText
var TEXT_DEFAULT_SIZE = 50; // Required by: BorderedText, SymbolText
var TEXT_DEFAULT_MARGIN = 10; // Required by: SymbolText
;
// Game constants
var GAME_TICKS = 60;
var GAME_WIDTH = 2048;
var GAME_HEIGHT = 2732;
;
// Particle settings
var PARTICLE_HAMMER_SPIN = MATH_QUARTER_PI * 2.5;
var PARTICLE_HAMMER_STAGE_1 = Math.round(0.075 * GAME_TICKS);
var PARTICLE_HAMMER_STAGE_2 = Math.round(0.075 * GAME_TICKS);
var PARTICLE_HAMMER_STAGE_3 = Math.round(0.4 * GAME_TICKS);
var PARTICLE_HAMMER_ASSETS = 5;
var PARTICLE_HAMMER_ROTATION = MATH_QUARTER_PI;
var PARTICLE_HAMMER_SCALE_MAX = 2.0;
// Leader settings
var LEADER_DURATION = 1 * GAME_TICKS;
var LEADER_SPAWN_MIN = 2 * GAME_TICKS;
var LEADER_SPAWN_VAR = 1 * GAME_TICKS;
var LEADER_SPAWN_FACTOR = 0.95;
var LEADER_SPAWN_TIME = Math.round(0.075 * GAME_TICKS);
// Table settings
var TABLE_WIDTH = 2500;
var TABLE_DEPTH = 1500;
var TABLE_CENTER_Y = GAME_HEIGHT / 2 + 125;
var TABLE_SLICES = 6;
var TABLE_HOLES = [1, 2, 3, 2, 1, 0];
var TABLE_HOLE_WIDTH = 334;
var TABLE_HOLE_GAP = 778;
var TABLE_BUTTON_INDEX = 4;
// Other settings
var COUNTDOWN_GAME = 60 * GAME_TICKS;
var HAMMER_RADIUS = 50;
// Messages
var MESSAGE_REFRESH = 5 * GAME_TICKS;
var MESSAGE_INTRO = 'Blue Lizard Entertainment proudly presents: #####Whac-a-Mo...##########\n... Whac-a-##########Politician? Are we T###R###Y###I###N###G### to get sued.########## Again?';
var MESSAGE_START = 'And off you go... Good luck. You\'ll probably need it for this beta-mess.';
var MESSAGE_WRONG = ['Apparently you shouldn\'t bonk the Kiwi.', 'This isn\'t Kiwi Clicker.'];
var MESSAGE_OUTRO = 'Well, that\'s all there is... Good job! Thanks for playing.';
var MESSAGE_EXTRA = 'That\'s a Sneaky one that... Good job! Thanks for playing.';
var MESSAGE_RANDO = [];
MESSAGE_RANDO.push('Was this a "Bobby-proposal"?');
MESSAGE_RANDO.push('Oh, we are S###O###O###O### getting sued for this.');
MESSAGE_RANDO.push('These people are the pinnacle leaders of humanity, surely not?');
MESSAGE_RANDO.push('The Europeans leaders seem...########## Okay?########## For once.');
MESSAGE_RANDO.push('This game must be divine punishment for milking a bad M###M###O### for decades.');
MESSAGE_RANDO.push('I\'m just here as a distraction to keep you from beating the company highscores.');
MESSAGE_RANDO.push('Let\'s play spin the bottle on which game company is halving their workforce, again.');
;
//==============================================================================
// Global variables
//==============================================================================
;
var started = false;
var score = 0;
var countdown = COUNTDOWN_GAME;
var spawnTime = LEADER_SPAWN_MIN;
var spawnTimer = spawnTime;
var messageTimer = MESSAGE_REFRESH;
var leaders = [LeaderGreat1, LeaderTroll1, LeaderTroll2, LeaderTroll3, LeaderTroll4, LeaderTroll5, LeaderTroll6];
var leaderList = [];
var particleList = [];
;
var background = game.addChild(new Container());
var midground = game.addChild(new Container());
var foreground = game.addChild(new Container());
var table = background.addChild(new Table({
x: GAME_WIDTH / 2,
y: GAME_HEIGHT / 2 - 600,
width: TABLE_WIDTH
}));
var startButton = midground.addChild(new StartButton({
x: GAME_WIDTH / 2,
y: TABLE_CENTER_Y
}));
;
var textbox = game.addChild(new Textbox(MESSAGE_INTRO, {
x: 100,
y: GAME_HEIGHT - 100,
width: GAME_WIDTH - 200,
height: 200
}));
var countdownText = LK.gui.top.addChild(new BorderedText(Math.ceil(countdown / GAME_TICKS), {
anchorX: 0.5,
anchorY: 0,
size: 200
}));
var scoreText = LK.gui.topRight.addChild(new BorderedText(score, {
x: -20,
anchorX: 1,
anchorY: 0,
size: 100
}));
;
//==============================================================================
// Game events
//==============================================================================
;
game.on('down', function (obj) {
var event = obj.event;
var pos = event.getLocalPosition(game);
var dx = Math.abs(GAME_WIDTH / 2 - pos.x) / TABLE_WIDTH;
var dy = Math.abs(TABLE_CENTER_Y - pos.y) / TABLE_DEPTH;
if (dx + dy <= 0.5) {
particleList.push(foreground.addChild(new HammerParticle({
xFlip: pos.x < GAME_WIDTH / 2 ? -1 : 1,
x: pos.x,
y: pos.y
})));
}
});
;
LK.on('tick', function () {
if (started) {
handleSpawnTimer();
handleMessageRefresh();
if (--countdown <= 0) {
LK.showGameOver();
}
countdownText.setText(Math.ceil(countdown / GAME_TICKS));
for (var i = leaderList.length - 1; i >= 0; i--) {
var leader = leaderList[i];
if (leader.update()) {
table.despawn(leader.slotIndex, leader.className);
leader.destroy();
leaderList.splice(i, 1);
}
}
}
for (var i = particleList.length - 1; i >= 0; i--) {
if (particleList[i].update()) {
particleList[i].destroy();
particleList.splice(i, 1);
}
}
});
;
//==============================================================================
// Global functions
//==============================================================================
;
// Handlers
;
function handleSpawnTimer() {
if (--spawnTimer <= 0) {
spawnTimer += spawnTime;
spawnTime = spawnTime * LEADER_SPAWN_FACTOR;
LK.setTimeout(table.spawn, Math.random() * LEADER_SPAWN_VAR);
}
}
function handleMessageRefresh() {
if (--messageTimer <= 0 && MESSAGE_RANDO.length) {
textbox.setText(MESSAGE_RANDO.splice(Math.floor(Math.random() * MESSAGE_RANDO.length), 1)[0]);
messageTimer = MESSAGE_REFRESH;
}
}
function handleImpactPoint(x, y) {
if (!started) {
var dx = GAME_WIDTH / 2 - x;
var dy = TABLE_CENTER_Y - y;
if (pointWithinOval(dx, dy, startButton.width * 0.5, startButton.height * 0.5)) {
started = true;
startButton.destroy();
startButton = undefined;
}
} else {
// TODO: Check bonk collisions
}
}
;
// Library
;
function hexToHex(input) {
if (typeof input === 'string') {
return parseInt(input.replace(/^#/, ''), 16);
} else if (typeof input === 'number') {
return '#' + input.toString(16).padStart(6, '0');
}
return input;
}
function pointWithinOval(dx, dy, rx, ry) {
return dx * dx / (rx * rx) + dy * dy / (ry * ry) <= 1;
}
logo for a company called "blue lizard entertainment" using a damaged font and frozen elements.
Pixel art of the bam symbol. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
pixel art of bam comic symbol.
pixel art of pow comic symbol.
pixel art of plastic squeaky hammer.
pixel art of a large, round, red start button.