/* Arkanoid level is 10x10 */ var score = 0; var highscore = 0; var lives = 3; var brick = World.spawn(gameobjects['brick']); var brickbb = brick.char.boundingbox; var bwidth = brickbb.r - brickbb.l; var bheight = brickbb.t-brickbb.b; brick.kill(); var rows = 15; var cols = 13; var lvlwidth = bwidth*cols; var lvlheight = 600; //var frameworld = World var f = World.spawn(gameobjects['edge2d']); f.edge2d.thickness = 10; f.edge2d.cpoints = Geometry.box(lvlwidth+f.edge2d.thickness*2,lvlheight); f.draw = function() { Debug.line(f.edge2d.points, Color.green, 0, f.edge2d.thickness*2); }; register_draw(f.draw,f); var fitbricks = Math.floor(lvlwidth/bwidth); var wingame = function() { allballs.forEach(x=>x.kill()); Log.warn("WINNER"); Player.players[0].uncontrol(paddle); register_gui(function() { GUI.text("WINNER", Window.dimensions.scale(0.5)); }); } /* Spawn bricks */ if (!IO.exists('lvl1.json')) { var lvl1 = {}; lvl1.bricks = []; for (var i = 0; i < rows; i++) { lvl1.bricks.push([]); for (var j = 0; j < cols; j++) { lvl1.bricks[i].push(1); } } IO.slurpwrite(JSON.stringify(lvl1), 'lvl1.json'); } Color.Arkanoid = { white: [0,0,0,255], orange: [255,143,0,255], teal: [0,255,255,255], green: [0,255,0,255], red: [255,0,0,255], blue: [0,112,255,255], purple: [255,0,255,255], yellow: [255,255,0], silver: [157,157,157], gold: [188,174,0], }; Color.Arkanoid.Powerups = { red: [174,0,0], /* laser */ blue: [0,0,174], /* enlarge */ green: [0,174,0], /* catch */ orange: [224,143,0], /* slow */ purple: [210,0,210], /* break */ cyan: [0,174,255], /* disruption */ gray: [143,143,143] /* 1up */ }; var lvl = JSON.parse(IO.slurp("lvl1.json")); for (var row = 0; row < rows; row++) { for (var col = 0; col < cols; col++) { if (lvl.bricks[row][col] === 0) continue; var brick = World.spawn(gameobjects['brick']); brick.powerup = function() { if (Math.random() < 0.1) spawn_random_powerup(this.pos); if (this.instances === 1) wingame(); }; // brick.char.color = bcolor; var startrow = lvlheight/2-bheight*2; // one brick gap between top and brick start var x = -(cols/2) * bwidth; var pos = [x+bwidth*col+bwidth/2, startrow-bheight*row]; brick.pos = pos; } } var flashtimer = timer.make(function() { if (gameobjects['brick'].instances.length === 0) { flashtimer.kill(); return; } var idx = Math.randomint(gameobjects['brick'].instances.length); gameobjects['brick'].instances[idx].flash(); flashtimer.time = Math.random_range(1,3); }, Math.random_range(1,3)); var paddle = World.spawn(gameobjects['paddle']); paddle.extents = lvlwidth/2 - f.edge2d.thickness; paddle.pos = [0,-lvlheight/2+paddle.height*4]; paddle.setgrow(3); paddle.lasership(); Gamestate.spawnball = function() { var bb = World.spawn(gameobjects['ball']); bb.pos = bb.pos.add([0,-200]); bb.velocity = [30,200]; bb.draw_layer = 3; bb.tag = 'ball'; } var powerups = {}; function mk_pup(color, fn, weight) { weight ??= 1; var o = {}; o.color = color; o.fn = fn; o.weight = weight; return o; }; powerups.laser = mk_pup(Color.Arkanoid.Powerups.red, function() { paddle.lasership(); }); powerups.enlarge = mk_pup(Color.Arkanoid.Powerups.blue, function() { paddle.grow(); }); powerups.catch = mk_pup(Color.Arkanoid.Powerups.green, function() { paddle.sticky = true; }); powerups.slow = mk_pup(Color.Arkanoid.Powerups.orange, function() { /* Slow all balls */ gameobjects['ball'].instances.forEach(function(x) { x.velocity = x.velocity.scale(0.5); }); }); powerups.break = mk_pup(Color.Arkanoid.Powerups.purple, function() { clear_level(); }, 0.5); powerups.disruption = mk_pup(Color.Arkanoid.Powerups.cyan, function() { var ball = gameobjects['ball'].instances[0]; if (!ball) return; ball.instandup(); ball.instandup(); }); powerups.player = mk_pup(Color.Arkanoid.Powerups.gray, function() { lives += 1; }, 0.5); function select_weighted(objs) { var total = 0; var total = objs.reduce(function(acc, item) { acc += item.weight; return acc; }, 0); var selection = Math.random() * total; var i; for (i = 0; i < objs.length-1; i++) { selection -= objs[i].weight; if (selection <= 0) return objs[i]; }; return objs.last; } function select_weighted_binary(objs) { var mobjs = objs.slice(); mobjs[0].total = 0; for (var i = 1; i < mobjs.length; i++) mobjs[i].total = mobjs[i-1].total + mobjs[i].weight; var select = Math.random() * mobjs.last.total var obj = Math.floor((mobjs.length-1)/2); while (mobjs.length > 0) { if (select < mobjs[obj].total) { mobjs.splice(obj,obj-1); obj = Math.floor((mobjs.length-1)/2); } else if (select > mobjs[obj+1].total) { mobjs.splice(0,obj-1); obj = Math.floor((mobjs.length-1)/2); } else return mobjs[obj]; } return mobjs[obj]; } var last_powerup = {}; function spawn_random_powerup(pos) { if (gameobjects['upgrade_drop'].instances.length !== 0) return; var p = World.spawn(gameobjects['upgrade_drop']); p.pos = pos; var power = select_weighted(powerups.array()); if (last_powerup === power) power = powerups.disruption; last_powerup = power; p.color = power.color; p.upgrade = power.fn; } function spawn_powerup(pos, fn) { var p = World.spawn(gameobjects['upgrade_drop']); p.pos = pos; p.upgrade = fn; return p; } function multiball(n) { for (var i = 0; i < n; i++) Gamestate.spawnball(); } function lostball() { if (gameobjects['ball'].instances.length === 0) lostlife(); }; function lostgame() { Log.warn("LOSER"); backtomain(); } function lostlife() { lives--; if (lives === 0) lostgame(); else Gamestate.spawnball(); }; Gamestate.spawnball(); var killbox = World.spawn(gameobjects['polygon2d']); killbox.polygon2d.points = Geometry.box(lvlwidth,30); killbox.pos = [0,-lvlheight/2]; killbox.polygon2d.sensor = true; killbox.register_hit(hit => { if (hit.obj.tag === 'ball') { hit.obj.kill(); lostball(); } }, killbox); //Sound.play("start.wav"); var pause = { gui() { var pausecolor = [0,0,0,100]; Debug.box(Window.dimensions.scale(0.5), Window.dimensions, pausecolor); GUI.text_fn("PAUSE", {font_size: 3, anchor: [0.5,0.5]}).draw(Window.dimensions.scale([0.5,0.5])); }, unpause() { unregister_gui(pause.gui); sim_start(); }, input_escape_pressed() { pause.unpause(); Player.players[0].control(gamepawn); }, }; var gamepawn = { pause() { register_gui(pause.gui); sim_pause(); }, input_escape_pressed() { backtomain(); return; this.pause(); Player.players[0].uncontrol(gamepawn); Player.players[0].control(pause); }, input_o_pressed() { clear_level(); }, } function clear_level() { var bricks = gameobjects['brick'].instances.slice(); bricks.forEach(function(x) { x.kill(); }); }; function gamegui() { GUI.column({ items: [ GUI.text_fn("SCORE", {color: Color.red}), GUI.text_fn(`${score}`), GUI.text_fn("HIGH SCORE", {color: Color.red}), GUI.text_fn(`${highscore}`), GUI.text_fn(`BRICKS: ${gameobjects['brick'].instances.length}`), GUI.text_fn(`BALLS IN PLAY: ${gameobjects['ball'].instances.length}`), GUI.text_fn(`LIVES: ${lives}`), GUI.text_fn("YARKANOID", {color: [5,120,240,255]}), GUI.text_fn("ODPLOT GAMES"), GUI.text_fn("[C] 2023"), ] }).draw(Window.dimensions.scale([0.8,0.8])); } register_gui(gamegui); Player.players[0].control(gamepawn); let backtomain = function() { World.clear(); run("startmenu.js"); unregister_gui(gamegui); Player.players[0].uncontrol(gamepawn); }