Made more changes to make the game more efficient
parent
d3aa3abeae
commit
d602bc16c5
|
|
@ -1,3 +1,4 @@
|
||||||
0.01: It works somehow, early version for testers and feedback :)
|
0.01: It works somehow, early version for testers and feedback :)
|
||||||
0.02: Changed almost all code with Frederic version of Pong and adjusted to be a BrickBreaker!, still Alpha
|
0.02: Changed almost all code with Frederic version of Pong and adjusted to be a BrickBreaker!, still Alpha
|
||||||
0.03: Rewrote the whole thing to have less code and better graphics, now it works.
|
0.03: Rewrote the whole thing to have less code and better graphics, now it works.
|
||||||
|
0.04: Rewrote part of the code to coupe with the flickering and added better logic to handle the graphics.
|
||||||
|
|
@ -21,6 +21,8 @@ https://developer.mozilla.org/en-US/docs/Games/Tutorials/2D_Breakout_game_pure_J
|
||||||
|
|
||||||
Started on 2020 but rewrote all in 2025 and this is the version I got without having issues with Memory Exhaustion.
|
Started on 2020 but rewrote all in 2025 and this is the version I got without having issues with Memory Exhaustion.
|
||||||
|
|
||||||
|
And yes, for Bangle 1, old school!
|
||||||
|
|
||||||
## Creator
|
## Creator
|
||||||
|
|
||||||
Israel Ochoa <isuraeru at gmail.com>
|
Israel Ochoa <isuraeru at gmail.com>
|
||||||
|
|
@ -1,31 +1,31 @@
|
||||||
|
|
||||||
(function () {
|
(function () {
|
||||||
const BALL_RADIUS = 3;
|
var BALL_RADIUS = 3;
|
||||||
const PADDLE_WIDTH = 26;
|
var PADDLE_WIDTH = 26;
|
||||||
const PADDLE_HEIGHT = 6;
|
var PADDLE_HEIGHT = 6;
|
||||||
const BRICK_ROWS = 2;
|
var BRICK_ROWS = 2;
|
||||||
const BRICK_HEIGHT = 8;
|
var BRICK_HEIGHT = 8;
|
||||||
const BRICK_PADDING = 4;
|
var BRICK_PADDING = 4;
|
||||||
const BRICK_OFFSET_TOP = 40;
|
var BRICK_OFFSET_TOP = 60;
|
||||||
const BRICK_OFFSET_LEFT = 2;
|
var BRICK_OFFSET_LEFT = 2;
|
||||||
const SPEED_MULTIPLIER = 1.1;
|
var SPEED_MULTIPLIER = 1.1;
|
||||||
const PADDLE_SPEED = 12;
|
var PADDLE_SPEED = 12;
|
||||||
|
|
||||||
let ball, paddle, interval;
|
var ball, paddle, interval;
|
||||||
let bricks = [];
|
var bricks = [];
|
||||||
let BRICK_WIDTH, BRICK_COLS;
|
var BRICK_WIDTH, BRICK_COLS;
|
||||||
let paddleIntervalLeft, paddleIntervalRight;
|
var score = 0;
|
||||||
let score = 0;
|
var level = 1;
|
||||||
let level = 1;
|
var highScore = 0;
|
||||||
let highScore = 0;
|
var paused = false;
|
||||||
let paused = false;
|
var gameOver = false;
|
||||||
let gameOver = false;
|
var lives = 3;
|
||||||
let lives = 3;
|
var paddleMove = 0;
|
||||||
|
|
||||||
const storage = require("Storage");
|
var storage = require("Storage");
|
||||||
//const BEEP = () => Bangle.buzz(100);
|
|
||||||
|
|
||||||
function loadHighScore() {
|
function loadHighScore() {
|
||||||
const saved = storage.readJSON("breakout_highscore.json", 1);
|
var saved = storage.readJSON("breakout_highscore.json", 1);
|
||||||
highScore = saved && saved.highScore ? saved.highScore : 0;
|
highScore = saved && saved.highScore ? saved.highScore : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -37,46 +37,32 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function initBricks() {
|
function initBricks() {
|
||||||
bricks = []; // Reset the array completely
|
bricks = [];
|
||||||
let brickCount = 0;
|
for (var i = 0; i < BRICK_ROWS * BRICK_COLS; i++) {
|
||||||
for (let r = 0; r < BRICK_ROWS; r++) {
|
bricks.push(1);
|
||||||
for (let c = 0; c < BRICK_COLS; c++) {
|
|
||||||
let brickX = BRICK_OFFSET_LEFT + c * (BRICK_WIDTH + BRICK_PADDING);
|
|
||||||
let brickY = BRICK_OFFSET_TOP + r * (BRICK_HEIGHT + BRICK_PADDING);
|
|
||||||
if (brickCount++ > 20) return;
|
|
||||||
bricks.push({ x: brickX, y: brickY, status: 1 });
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
function showGetReady(callback) {
|
|
||||||
g.clear();
|
|
||||||
g.setFont("6x8", 2);
|
|
||||||
g.setFontAlign(0, 0);
|
|
||||||
g.setColor(1, 1, 0);
|
|
||||||
g.drawString("GET READY!", g.getWidth() / 2, g.getHeight() / 2);
|
|
||||||
g.flip();
|
|
||||||
setTimeout(callback, 1500); // wait 1.5 seconds then start
|
|
||||||
}
|
|
||||||
|
|
||||||
function initGame() {
|
function initGame() {
|
||||||
const screenWidth = g.getWidth();
|
var screenWidth = g.getWidth();
|
||||||
BRICK_COLS = Math.min(5, Math.floor((screenWidth - BRICK_OFFSET_LEFT + BRICK_PADDING) / (15 + BRICK_PADDING)));
|
BRICK_COLS = Math.min(5, Math.floor((screenWidth - BRICK_OFFSET_LEFT + BRICK_PADDING) / (15 + BRICK_PADDING)));
|
||||||
BRICK_WIDTH = Math.floor((screenWidth - BRICK_OFFSET_LEFT - (BRICK_COLS - 1) * BRICK_PADDING) / BRICK_COLS);
|
BRICK_WIDTH = Math.floor((screenWidth - BRICK_OFFSET_LEFT - (BRICK_COLS - 1) * BRICK_PADDING) / BRICK_COLS);
|
||||||
|
|
||||||
ball = {
|
ball = {
|
||||||
x: screenWidth / 2,
|
x: screenWidth / 2,
|
||||||
y: g.getHeight() - 20,
|
y: g.getHeight() - 40,
|
||||||
dx: 3,
|
dx: (Math.random() > 0.5 ? 1 : -1) * 3,
|
||||||
dy: -3,
|
dy: -3,
|
||||||
radius: BALL_RADIUS
|
radius: BALL_RADIUS,
|
||||||
|
prevPos: null
|
||||||
};
|
};
|
||||||
|
|
||||||
paddle = {
|
paddle = {
|
||||||
x: screenWidth / 2 - PADDLE_WIDTH / 2,
|
x: screenWidth / 2 - PADDLE_WIDTH / 2,
|
||||||
y: g.getHeight() - 10,
|
y: g.getHeight() - 20,
|
||||||
width: PADDLE_WIDTH,
|
width: PADDLE_WIDTH,
|
||||||
height: PADDLE_HEIGHT
|
height: PADDLE_HEIGHT,
|
||||||
|
prevPos: null
|
||||||
};
|
};
|
||||||
lives = 3;
|
lives = 3;
|
||||||
score = 0;
|
score = 0;
|
||||||
|
|
@ -88,30 +74,26 @@ if (brickCount++ > 20) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
function drawLives() {
|
function drawLives() {
|
||||||
const heartSize = 6;
|
var heartSize = 6;
|
||||||
const spacing = 2;
|
var spacing = 2;
|
||||||
const startX = g.getWidth() - (lives * (heartSize + spacing)) - 2;
|
var startX = g.getWidth() - (lives * (heartSize + spacing)) - 2;
|
||||||
const y = 12;
|
var y = 32;
|
||||||
|
g.setColor(1, 0, 0);
|
||||||
g.setColor(1, 0, 0); // red
|
for (var i = 0; i < lives; i++) {
|
||||||
|
var x = startX + i * (heartSize + spacing);
|
||||||
for (let i = 0; i < lives; i++) {
|
g.fillPoly([x + 3, y, x + 6, y + 3, x + 3, y + 6, x, y + 3], true);
|
||||||
const x = startX + i * (heartSize + spacing);
|
|
||||||
g.fillPoly([
|
|
||||||
x + 3, y,
|
|
||||||
x + 6, y + 3,
|
|
||||||
x + 3, y + 6,
|
|
||||||
x, y + 3
|
|
||||||
], true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function drawBricks() {
|
function drawBricks() {
|
||||||
g.setColor(0, 1, 0);
|
g.setColor(0, 1, 0);
|
||||||
for (let i = 0; i < bricks.length; i++) {
|
for (var i = 0; i < bricks.length; i++) {
|
||||||
let b = bricks[i];
|
if (bricks[i]) {
|
||||||
if (b.status) {
|
var c = i % BRICK_COLS;
|
||||||
g.fillRect(b.x, b.y, b.x + BRICK_WIDTH, b.y + BRICK_HEIGHT);
|
var r = Math.floor(i / BRICK_COLS);
|
||||||
|
var brickX = BRICK_OFFSET_LEFT + c * (BRICK_WIDTH + BRICK_PADDING);
|
||||||
|
var brickY = BRICK_OFFSET_TOP + r * (BRICK_HEIGHT + BRICK_PADDING);
|
||||||
|
g.fillRect(brickX, brickY, brickX + BRICK_WIDTH - 1, brickY + BRICK_HEIGHT - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -125,18 +107,19 @@ if (brickCount++ > 20) return;
|
||||||
|
|
||||||
function drawPaddle() {
|
function drawPaddle() {
|
||||||
g.setColor(0, 1, 1);
|
g.setColor(0, 1, 1);
|
||||||
g.fillRect(paddle.x, paddle.y, paddle.x + paddle.width, paddle.y + paddle.height);
|
g.fillRect(paddle.x, paddle.y, paddle.x + paddle.width - 1, paddle.y + paddle.height - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
function drawHUD() {
|
function drawHUD() {
|
||||||
|
g.setColor(0, 0, 0).fillRect(0, 0, g.getWidth(), BRICK_OFFSET_TOP - 1);
|
||||||
g.setColor(1, 1, 1);
|
g.setColor(1, 1, 1);
|
||||||
g.setFont("6x8", 1);
|
g.setFont("6x8", 1);
|
||||||
g.setFontAlign(-1, -1);
|
g.setFontAlign(-1, -1);
|
||||||
g.drawString("Score: " + score, 2, 2);
|
g.drawString("Score: " + score, 2, 22);
|
||||||
g.setFontAlign(0, -1);
|
g.setFontAlign(0, -1);
|
||||||
g.drawString("High: " + highScore, g.getWidth() / 2, 2);
|
g.drawString("High: " + highScore, g.getWidth() / 2, 22);
|
||||||
g.setFontAlign(1, -1);
|
g.setFontAlign(1, -1);
|
||||||
g.drawString("Lvl: " + level, g.getWidth() - 2, 2);
|
g.drawString("Lvl: " + level, g.getWidth() - 2, 22);
|
||||||
drawLives();
|
drawLives();
|
||||||
if (paused) {
|
if (paused) {
|
||||||
g.setFontAlign(0, 0);
|
g.setFontAlign(0, 0);
|
||||||
|
|
@ -145,12 +128,18 @@ if (brickCount++ > 20) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
function draw() {
|
function draw() {
|
||||||
g.clear();
|
if (paddle.prevPos) {
|
||||||
drawBricks();
|
g.setColor(0, 0, 0).fillRect(paddle.prevPos.x - 1, paddle.prevPos.y - 1, paddle.prevPos.x + paddle.width + 1, paddle.prevPos.y + paddle.height + 1);
|
||||||
|
}
|
||||||
|
if (ball.prevPos) {
|
||||||
|
g.setColor(0, 0, 0).fillCircle(ball.prevPos.x, ball.prevPos.y, ball.radius + 1);
|
||||||
|
}
|
||||||
|
drawHUD();
|
||||||
drawBall();
|
drawBall();
|
||||||
drawPaddle();
|
drawPaddle();
|
||||||
drawHUD();
|
|
||||||
g.flip();
|
g.flip();
|
||||||
|
ball.prevPos = { x: ball.x, y: ball.y };
|
||||||
|
paddle.prevPos = { x: paddle.x, y: paddle.y, width: paddle.width, height: paddle.height };
|
||||||
}
|
}
|
||||||
|
|
||||||
function showGameOver() {
|
function showGameOver() {
|
||||||
|
|
@ -168,148 +157,137 @@ if (brickCount++ > 20) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
function collisionDetection() {
|
function collisionDetection() {
|
||||||
for (let i = 0; i < bricks.length; i++) {
|
for (var i = 0; i < bricks.length; i++) {
|
||||||
let b = bricks[i];
|
if (bricks[i]) {
|
||||||
if (b.status) {
|
var c = i % BRICK_COLS;
|
||||||
if (
|
var r = Math.floor(i / BRICK_COLS);
|
||||||
ball.x + ball.radius > b.x &&
|
var brickX = BRICK_OFFSET_LEFT + c * (BRICK_WIDTH + BRICK_PADDING);
|
||||||
ball.x - ball.radius < b.x + BRICK_WIDTH &&
|
var brickY = BRICK_OFFSET_TOP + r * (BRICK_HEIGHT + BRICK_PADDING);
|
||||||
ball.y + ball.radius > b.y &&
|
if (ball.x + ball.radius > brickX && ball.x - ball.radius < brickX + BRICK_WIDTH && ball.y + ball.radius > brickY && ball.y - ball.radius < brickY + BRICK_HEIGHT) {
|
||||||
ball.y - ball.radius < b.y + BRICK_HEIGHT
|
|
||||||
) {
|
|
||||||
ball.dy = -ball.dy;
|
ball.dy = -ball.dy;
|
||||||
b.status = 0;
|
bricks[i] = 0;
|
||||||
score += 10;
|
score += 10;
|
||||||
|
g.setColor(0, 0, 0).fillRect(brickX, brickY, brickX + BRICK_WIDTH - 1, brickY + BRICK_HEIGHT - 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function allBricksCleared() {
|
function allBricksCleared() {
|
||||||
for (let i = 0; i < bricks.length; i++) {
|
for (var i = 0; i < bricks.length; i++) {
|
||||||
if (bricks[i].status !== 0) return false;
|
if (bricks[i]) return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function resetAfterLifeLost() {
|
||||||
|
clearInterval(interval);
|
||||||
|
interval = undefined;
|
||||||
|
ball.x = g.getWidth() / 2;
|
||||||
|
ball.y = g.getHeight() - 40;
|
||||||
|
ball.dx = (Math.random() > 0.5 ? 1 : -1) * 3;
|
||||||
|
ball.dy = -3;
|
||||||
|
paddle.x = g.getWidth() / 2 - PADDLE_WIDTH / 2;
|
||||||
|
ball.prevPos = null;
|
||||||
|
paddle.prevPos = null;
|
||||||
|
g.clear();
|
||||||
|
drawBricks();
|
||||||
|
draw();
|
||||||
|
setTimeout(() => { interval = setInterval(update, 50); }, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
function update() {
|
function update() {
|
||||||
if (paused || gameOver) return;
|
if (paused || gameOver) return;
|
||||||
|
if (paddleMove) {
|
||||||
|
paddle.x += paddleMove * PADDLE_SPEED;
|
||||||
|
if (paddle.x < 0) paddle.x = 0;
|
||||||
|
if (paddle.x + paddle.width > g.getWidth()) {
|
||||||
|
paddle.x = g.getWidth() - paddle.width;
|
||||||
|
}
|
||||||
|
}
|
||||||
ball.x += ball.dx;
|
ball.x += ball.dx;
|
||||||
ball.y += ball.dy;
|
ball.y += ball.dy;
|
||||||
|
|
||||||
if (ball.x + ball.radius > g.getWidth() || ball.x - ball.radius < 0) {
|
if (ball.x + ball.radius > g.getWidth() || ball.x - ball.radius < 0) {
|
||||||
ball.dx = -ball.dx;
|
ball.dx = -ball.dx;
|
||||||
}
|
}
|
||||||
if (ball.y - ball.radius < 0) {
|
if (ball.y - ball.radius < 0) {
|
||||||
ball.dy = -ball.dy;
|
ball.dy = -ball.dy;
|
||||||
}
|
}
|
||||||
|
if (ball.y + ball.radius >= paddle.y && ball.x >= paddle.x && ball.x <= paddle.x + paddle.width) {
|
||||||
if (
|
|
||||||
ball.y + ball.radius >= paddle.y &&
|
|
||||||
ball.x >= paddle.x &&
|
|
||||||
ball.x <= paddle.x + paddle.width
|
|
||||||
) {
|
|
||||||
ball.dy = -ball.dy;
|
ball.dy = -ball.dy;
|
||||||
ball.y = paddle.y - ball.radius;
|
ball.y = paddle.y - ball.radius;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ball.y + ball.radius > g.getHeight()) {
|
if (ball.y + ball.radius > g.getHeight()) {
|
||||||
lives--;
|
lives--;
|
||||||
if (lives > 0) {
|
if (lives > 0) {
|
||||||
// Reset ball and paddle only
|
resetAfterLifeLost();
|
||||||
ball.x = g.getWidth() / 2;
|
|
||||||
ball.y = g.getHeight() - 30;
|
|
||||||
ball.dx = 3;
|
|
||||||
ball.dy = -3;
|
|
||||||
paddle.x = g.getWidth() / 2 - PADDLE_WIDTH / 2;
|
|
||||||
paddle.y = g.getHeight() - 20;
|
|
||||||
draw();
|
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
clearInterval(interval);
|
clearInterval(interval);
|
||||||
interval = undefined;
|
interval = undefined;
|
||||||
if (paddleIntervalLeft) {
|
|
||||||
clearInterval(paddleIntervalLeft);
|
|
||||||
paddleIntervalLeft = null;
|
|
||||||
}
|
|
||||||
if (paddleIntervalRight) {
|
|
||||||
clearInterval(paddleIntervalRight);
|
|
||||||
paddleIntervalRight = null;
|
|
||||||
}
|
|
||||||
saveHighScore();
|
saveHighScore();
|
||||||
gameOver = true;
|
gameOver = true;
|
||||||
draw();
|
|
||||||
setTimeout(showGameOver, 50);
|
setTimeout(showGameOver, 50);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
collisionDetection();
|
collisionDetection();
|
||||||
|
|
||||||
if (allBricksCleared()) {
|
if (allBricksCleared()) {
|
||||||
ball.dx *= SPEED_MULTIPLIER;
|
|
||||||
ball.dy *= SPEED_MULTIPLIER;
|
|
||||||
level++;
|
level++;
|
||||||
|
ball.dx = (Math.random() > 0.5 ? 1 : -1) * Math.abs(ball.dx) * SPEED_MULTIPLIER;
|
||||||
|
ball.dy *= SPEED_MULTIPLIER;
|
||||||
initBricks();
|
initBricks();
|
||||||
|
ball.prevPos = null;
|
||||||
|
paddle.prevPos = null;
|
||||||
|
g.clear();
|
||||||
|
drawBricks();
|
||||||
}
|
}
|
||||||
|
|
||||||
draw();
|
draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
function movePaddle(x) {
|
function showGetReady(callback) {
|
||||||
if (gameOver || paused) return; // prevent paddle movement when not needed
|
g.clear();
|
||||||
paddle.x += x;
|
g.setFont("6x8", 2);
|
||||||
if (paddle.x < 0) paddle.x = 0;
|
g.setFontAlign(0, 0);
|
||||||
if (paddle.x + paddle.width > g.getWidth()) {
|
g.setColor(1, 1, 0);
|
||||||
paddle.x = g.getWidth() - paddle.width;
|
g.drawString("GET READY!", g.getWidth() / 2, g.getHeight() / 2);
|
||||||
}
|
g.flip();
|
||||||
|
setTimeout(() => {
|
||||||
|
g.clear();
|
||||||
|
drawBricks();
|
||||||
|
draw();
|
||||||
|
callback();
|
||||||
|
}, 1500);
|
||||||
}
|
}
|
||||||
|
|
||||||
function startGame() {
|
function startGame() {
|
||||||
initGame();
|
initGame();
|
||||||
draw();
|
|
||||||
showGetReady(() => {
|
showGetReady(() => {
|
||||||
interval = setInterval(update, 80);
|
interval = setInterval(update, 50);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
setWatch(() => {
|
setWatch(() => {
|
||||||
if (gameOver) {
|
if (gameOver) {
|
||||||
startGame();
|
startGame();
|
||||||
} else {
|
return;
|
||||||
|
}
|
||||||
paused = !paused;
|
paused = !paused;
|
||||||
|
if (paused) {
|
||||||
|
drawHUD();
|
||||||
|
g.flip();
|
||||||
|
} else {
|
||||||
|
g.clear();
|
||||||
|
drawBricks();
|
||||||
draw();
|
draw();
|
||||||
}
|
}
|
||||||
}, BTN2, { repeat: true, edge: "rising" });
|
}, BTN2, { repeat: true, edge: "rising" });
|
||||||
|
|
||||||
setWatch(() => {
|
setWatch(() => { paddleMove = -1; }, BTN1, { repeat: true, edge: "rising" });
|
||||||
if (!paddleIntervalLeft) {
|
setWatch(() => { paddleMove = 0; }, BTN1, { repeat: true, edge: "falling" });
|
||||||
paddleIntervalLeft = setInterval(() => movePaddle(-PADDLE_SPEED), 50);
|
setWatch(() => { paddleMove = 1; }, BTN3, { repeat: true, edge: "rising" });
|
||||||
}
|
setWatch(() => { paddleMove = 0; }, BTN3, { repeat: true, edge: "falling" });
|
||||||
}, BTN1, { repeat: true, edge: "rising" });
|
|
||||||
|
|
||||||
setWatch(() => {
|
|
||||||
if (paddleIntervalLeft) {
|
|
||||||
clearInterval(paddleIntervalLeft);
|
|
||||||
paddleIntervalLeft = null;
|
|
||||||
}
|
|
||||||
}, BTN1, { repeat: true, edge: "falling" });
|
|
||||||
|
|
||||||
setWatch(() => {
|
|
||||||
if (!paddleIntervalRight) {
|
|
||||||
paddleIntervalRight = setInterval(() => movePaddle(PADDLE_SPEED), 50);
|
|
||||||
}
|
|
||||||
}, BTN3, { repeat: true, edge: "rising" });
|
|
||||||
|
|
||||||
setWatch(() => {
|
|
||||||
if (paddleIntervalRight) {
|
|
||||||
clearInterval(paddleIntervalRight);
|
|
||||||
paddleIntervalRight = null;
|
|
||||||
}
|
|
||||||
}, BTN3, { repeat: true, edge: "falling" });
|
|
||||||
|
|
||||||
startGame();
|
startGame();
|
||||||
})();
|
})();
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
"name": "BrickBreaker",
|
"name": "BrickBreaker",
|
||||||
"shortName":"BrickBreaker",
|
"shortName":"BrickBreaker",
|
||||||
"icon": "bbreaker.png",
|
"icon": "bbreaker.png",
|
||||||
"version":"0.03",
|
"version":"0.04",
|
||||||
"description": "A simple BreakOut clone for the Banglejs",
|
"description": "A simple BreakOut clone for the Banglejs",
|
||||||
"tags": "game",
|
"tags": "game",
|
||||||
"readme": "README.md",
|
"readme": "README.md",
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue