summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--css/index.css111
-rw-r--r--css/neo-brutalist.css308
-rw-r--r--index.html4
-rw-r--r--js/index.js35
-rw-r--r--js/joystick.js108
5 files changed, 549 insertions, 17 deletions
diff --git a/css/index.css b/css/index.css
index 766d45f..ab194ab 100644
--- a/css/index.css
+++ b/css/index.css
@@ -105,3 +105,114 @@ canvas {
max-width: none;
}
}
+
+
+/* D-pad styles */
+/* Update these styles in your index.css file */
+
+.instructions {
+ min-height: 200px; /* Ensure consistent height before and after d-pad appears */
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ padding: 20px;
+}
+
+.start-button {
+ display: block;
+ margin: 20px auto;
+ padding: 12px 24px;
+ font-size: 18px;
+ background-color: #4CAF50;
+ color: white;
+ border: none;
+ border-radius: 5px;
+ cursor: pointer;
+ transition: background-color 0.3s;
+}
+
+.start-button:hover {
+ background-color: #45a049;
+}
+
+.start-button:active {
+ background-color: #3d8b40;
+ transform: scale(0.98);
+}
+
+.d-pad {
+ position: relative;
+ width: 150px;
+ height: 150px;
+ margin: 20px auto;
+}
+
+.d-pad-btn {
+ position: absolute;
+ width: 40px;
+ height: 40px;
+ border: 2px solid #333;
+ background: #fff;
+ border-radius: 8px;
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 20px;
+ transition: all 0.2s;
+}
+
+.d-pad-btn:hover {
+ background: #eee;
+}
+
+.d-pad-btn.active {
+ background: #ddd;
+ transform: scale(0.95);
+}
+
+.d-pad-btn.up {
+ top: 0;
+ left: 50%;
+ transform: translateX(-50%);
+}
+
+.d-pad-btn.right {
+ top: 50%;
+ right: 0;
+ transform: translateY(-50%);
+}
+
+.d-pad-btn.down {
+ bottom: 0;
+ left: 50%;
+ transform: translateX(-50%);
+}
+
+.d-pad-btn.left {
+ top: 50%;
+ left: 0;
+ transform: translateY(-50%);
+}
+
+.d-pad-btn.center {
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ background: #f0f0f0;
+}
+
+/* Mobile-friendly adjustments */
+@media (max-width: 768px) {
+ .d-pad {
+ width: 120px;
+ height: 120px;
+ }
+
+ .d-pad-btn {
+ width: 35px;
+ height: 35px;
+ font-size: 16px;
+ }
+} \ No newline at end of file
diff --git a/css/neo-brutalist.css b/css/neo-brutalist.css
new file mode 100644
index 0000000..c837a16
--- /dev/null
+++ b/css/neo-brutalist.css
@@ -0,0 +1,308 @@
+/* Neo-brutalist UI styles */
+:root {
+ --primary-black: #000000;
+ --primary-white: #ffffff;
+ --accent-yellow: #FFE600;
+ --accent-red: #FF2D2D;
+ --accent-blue: #0066FF;
+ --box-shadow: 4px 4px 0 var(--primary-black);
+ }
+
+ /* Container styles */
+ .container {
+ max-width: 1200px;
+ margin: 0 auto;
+ padding: 10px;
+ background-color: var(--primary-white);
+ border: 3px solid var(--primary-black);
+ }
+
+ /* Header styles */
+ header {
+ background-color: var(--accent-yellow);
+ border: 3px solid var(--primary-black);
+ padding: 10px;
+ margin-bottom: 15px;
+ box-shadow: var(--box-shadow);
+ }
+
+ h1 {
+ font-family: 'Arial Black', sans-serif;
+ font-size: 2.5rem;
+ margin: 0;
+ text-transform: uppercase;
+ letter-spacing: -1px;
+ }
+
+ /* Game container */
+ .game-container {
+ display: grid;
+ grid-template-columns: 3fr 2fr; /* Adjusted ratio */
+ gap: 10px; /* Reduced gap */
+ }
+
+ /* Game board section */
+ .game-board {
+ border: 3px solid var(--primary-black);
+ padding: 10px;
+ background-color: var(--primary-white);
+ box-shadow: var(--box-shadow);
+ }
+
+ #gameCanvas {
+ border: 3px solid var(--primary-black);
+ background-color: #f0f0f0;
+ display: block; /* Prevents unwanted margins */
+ }
+
+ /* Game info section */
+ .game-info {
+ border: 3px solid var(--primary-black);
+ padding: 10px;
+ background-color: var(--primary-white);
+ box-shadow: var(--box-shadow);
+ }
+
+ /* Difficulty control */
+ .difficulty-control {
+ margin-bottom: 15px;
+ padding: 10px;
+ border: 3px solid var(--primary-black);
+ background-color: var(--accent-yellow);
+ }
+
+ .difficulty-control label {
+ font-family: 'Arial Black', sans-serif;
+ display: block;
+ margin-bottom: 5px;
+ font-size: 1.1rem;
+ }
+
+ input[type="range"] {
+ width: 100%;
+ height: 20px;
+ -webkit-appearance: none;
+ appearance: none;
+ background-color: var(--primary-white);
+ border: 2px solid var(--primary-black);
+ }
+
+ input[type="range"]::-webkit-slider-thumb {
+ -webkit-appearance: none;
+ width: 25px;
+ height: 25px;
+ background: var(--primary-black);
+ cursor: pointer;
+ border: 2px solid var(--primary-white);
+ }
+
+ /* Game stats */
+ .game-stats {
+ margin-bottom: 15px;
+ padding: 10px;
+ border: 3px solid var(--primary-black);
+ background-color: var(--accent-blue);
+ color: var(--primary-white);
+ }
+
+ .game-stats p {
+ margin: 5px 0;
+ font-family: 'Courier New', monospace;
+ font-size: 1rem;
+ font-weight: bold;
+ }
+
+ /* Instructions */
+ .instructions {
+ padding: 10px;
+ border: 3px solid var(--primary-black);
+ background-color: var(--primary-white);
+ min-height: 180px; /* Ensure space for d-pad */
+ }
+
+ .instructions h2 {
+ font-family: 'Arial Black', sans-serif;
+ font-size: 1.3rem;
+ margin-top: 0;
+ margin-bottom: 10px;
+ text-transform: uppercase;
+ }
+
+ .instructions p {
+ font-family: 'Courier New', monospace;
+ font-size: 0.9rem;
+ line-height: 1.3;
+ margin-bottom: 10px;
+ }
+
+ /* Start button */
+ .start-button {
+ display: block;
+ width: 100%;
+ padding: 12px 20px;
+ font-family: 'Arial Black', sans-serif;
+ font-size: 1.1rem;
+ text-transform: uppercase;
+ background-color: var(--accent-red);
+ color: var(--primary-white);
+ border: 3px solid var(--primary-black);
+ cursor: pointer;
+ box-shadow: var(--box-shadow);
+ transition: transform 0.1s, box-shadow 0.1s;
+ }
+
+ .start-button:hover {
+ transform: translate(2px, 2px);
+ box-shadow: 2px 2px 0 var(--primary-black);
+ }
+
+ .start-button:active {
+ transform: translate(4px, 4px);
+ box-shadow: none;
+ }
+
+ /* D-pad styles */
+ .d-pad {
+ position: relative;
+ width: 160px;
+ height: 160px;
+ margin: 10px auto;
+ }
+
+ .d-pad-btn {
+ position: absolute;
+ width: 45px;
+ height: 45px;
+ background: var(--primary-white);
+ border: 3px solid var(--primary-black);
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 20px;
+ font-weight: bold;
+ box-shadow: var(--box-shadow);
+ transition: transform 0.1s, box-shadow 0.1s;
+ }
+
+ .d-pad-btn:hover {
+ transform: translate(2px, 2px);
+ box-shadow: 2px 2px 0 var(--primary-black);
+ }
+
+ .d-pad-btn.active {
+ transform: translate(4px, 4px);
+ box-shadow: none;
+ background-color: var(--accent-yellow);
+ }
+
+ .d-pad-btn.up {
+ top: 0;
+ left: 50%;
+ transform: translateX(-50%);
+ }
+
+ .d-pad-btn.right {
+ top: 50%;
+ right: 0;
+ transform: translateY(-50%);
+ }
+
+ .d-pad-btn.down {
+ bottom: 0;
+ left: 50%;
+ transform: translateX(-50%);
+ }
+
+ .d-pad-btn.left {
+ top: 50%;
+ left: 0;
+ transform: translateY(-50%);
+ }
+
+ .d-pad-btn.center {
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ background-color: var(--accent-blue);
+ color: var(--primary-white);
+ }
+
+/* Previous styles remain the same until the media query... */
+
+/* Responsive adjustments */
+@media (max-width: 768px) {
+ .container {
+ padding: 5px;
+ }
+
+ .game-container {
+ grid-template-columns: 1fr;
+ gap: 5px;
+ }
+
+ h1 {
+ font-size: 2rem;
+ }
+
+ .game-board {
+ position: relative;
+ padding-bottom: 180px; /* Make space for the D-pad */
+ }
+
+ /* D-pad mobile positioning */
+ .instructions .d-pad {
+ position: fixed;
+ bottom: 20px;
+ left: 50%;
+ transform: translateX(-50%);
+ width: 180px;
+ height: 180px;
+ margin: 0;
+ z-index: 1000;
+ background: rgba(255, 255, 255, 0.9);
+ padding: 10px;
+ border: 3px solid var(--primary-black);
+ border-radius: 10px;
+ box-shadow: var(--box-shadow);
+ }
+
+ .d-pad-btn {
+ width: 45px;
+ height: 45px;
+ font-size: 20px;
+ }
+
+ /* Hide instructions when game starts on mobile */
+ .instructions {
+ min-height: auto;
+ }
+
+ .instructions h2,
+ .instructions p {
+ display: none;
+ }
+
+ .instructions .start-button {
+ margin: 10px auto;
+ max-width: 200px;
+ }
+ }
+
+ /* Add styles for landscape orientation */
+ @media (max-width: 768px) and (orientation: landscape) {
+ .instructions .d-pad {
+ right: 20px;
+ left: auto;
+ transform: none;
+ bottom: 20px;
+ width: 150px;
+ height: 150px;
+ }
+
+ .d-pad-btn {
+ width: 40px;
+ height: 40px;
+ font-size: 18px;
+ }
+ } \ No newline at end of file
diff --git a/index.html b/index.html
index c3330f6..398dd5d 100644
--- a/index.html
+++ b/index.html
@@ -5,12 +5,14 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CatchUp</title>
<link rel="stylesheet" href="css/index.css">
+ <link rel="stylesheet" href="css/neo-brutalist.css">
<script src="js/enemy.js" defer></script>
<script src="js/maze.js" defer></script>
<script src="js/logic.js" defer></script>
<script src="js/render.js" defer></script>
- <script src="js/index.js" defer></script>
+ <script src="js/joystick.js" type="module"></script>
+ <script src="js/index.js" type="module"></script>
</head>
<body>
<div class="container">
diff --git a/js/index.js b/js/index.js
index cec210b..492dada 100644
--- a/js/index.js
+++ b/js/index.js
@@ -1,35 +1,38 @@
+import DPadController from './joystick.js';
+
const moves = document.getElementById("moves");
const movesLeft = document.getElementById("movesLeft");
const state = document.getElementById("state");
const hardness = document.getElementById("hardness");
-
-let game, renderer;
+let game, renderer, dpadController;
function setUpGame(){
- const hardnessValue = parseFloat(hardness.value);
- const grid = hardnessValue < 0.5 ? 10 : hardnessValue > 0.8 ? 20 : 15;
- game = new MazeGame(grid, grid, hardnessValue);
- renderer = new MazeRenderer(game, 'gameCanvas');
- game.initializeGame();
- renderer.drawMaze();
+ const hardnessValue = parseFloat(hardness.value);
+ const grid = hardnessValue < 0.5 ? 10 : hardnessValue > 0.8 ? 20 : 15;
+ game = new MazeGame(grid, grid, hardnessValue);
+ renderer = new MazeRenderer(game, 'gameCanvas');
+ game.initializeGame();
+ renderer.drawMaze();
}
function showGameState(){
- const { moves: movesMade, moveLimit, gameWon, gameOver } = game.getGameState();
- moves.innerText = movesMade;
- movesLeft.innerText = String(moveLimit - movesMade);
- state.innerText = gameWon ? 'Game Won' : gameOver ? 'Game Over' : 'On Going';
+ const { moves: movesMade, moveLimit, gameWon, gameOver } = game.getGameState();
+ moves.innerText = movesMade;
+ movesLeft.innerText = String(moveLimit - movesMade);
+ state.innerText = gameWon ? 'Game Won' : gameOver ? 'Game Over' : 'On Going';
}
document.addEventListener('keydown', (event) => {
- renderer.handleKeyPress(event);
- showGameState();
+ renderer.handleKeyPress(event);
+ showGameState();
});
hardness.addEventListener('change', () => {
- setUpGame();
- showGameState();
+ setUpGame();
+ showGameState();
});
+// Initialize the game and D-pad controller
setUpGame();
showGameState();
+dpadController = new DPadController(); \ No newline at end of file
diff --git a/js/joystick.js b/js/joystick.js
new file mode 100644
index 0000000..de9ba01
--- /dev/null
+++ b/js/joystick.js
@@ -0,0 +1,108 @@
+class DPadController {
+ constructor() {
+ this.createStartButton();
+ this.currentDirection = null;
+ this.isMobile = window.innerWidth <= 768;
+ this.handleResize = this.handleResize.bind(this);
+ window.addEventListener('resize', this.handleResize);
+ }
+
+ handleResize() {
+ this.isMobile = window.innerWidth <= 768;
+ const dpad = document.querySelector('.d-pad');
+ if (dpad) {
+ if (this.isMobile) {
+ document.body.appendChild(dpad);
+ } else {
+ const instructions = document.querySelector('.instructions');
+ instructions.appendChild(dpad);
+ }
+ }
+ }
+
+ createStartButton() {
+ const startButton = document.createElement('button');
+ startButton.className = 'start-button';
+ startButton.textContent = 'Start Game';
+ startButton.addEventListener('click', () => this.startGame());
+
+ const instructions = document.querySelector('.instructions');
+ instructions.appendChild(startButton);
+ }
+
+ startGame() {
+ const instructions = document.querySelector('.instructions');
+
+ if (this.isMobile) {
+ // On mobile, just hide the instructions content
+ Array.from(instructions.children).forEach(child => {
+ if (!child.classList.contains('d-pad')) {
+ child.style.display = 'none';
+ }
+ });
+ } else {
+ // On desktop, clear and add d-pad
+ instructions.innerHTML = '';
+ }
+
+ this.createDPad(this.isMobile ? document.body : instructions);
+ this.setupEventListeners();
+ }
+
+ createDPad(container) {
+ const dpad = document.createElement('div');
+ dpad.className = 'd-pad';
+ dpad.innerHTML = `
+ <button class="d-pad-btn up" data-direction="ArrowUp">↑</button>
+ <button class="d-pad-btn right" data-direction="ArrowRight">→</button>
+ <button class="d-pad-btn down" data-direction="ArrowDown">↓</button>
+ <button class="d-pad-btn left" data-direction="ArrowLeft">←</button>
+ <button class="d-pad-btn center" data-direction=" ">⚡</button>
+ `;
+ container.appendChild(dpad);
+ }
+
+ setupEventListeners() {
+ const dpad = document.querySelector('.d-pad');
+
+ // Mouse events
+ dpad.addEventListener('mousedown', (e) => this.handleInput(e));
+ document.addEventListener('mouseup', () => this.clearInput());
+
+ // Touch events
+ dpad.addEventListener('touchstart', (e) => {
+ e.preventDefault();
+ this.handleInput(e);
+ });
+ document.addEventListener('touchend', (e) => {
+ e.preventDefault();
+ this.clearInput();
+ });
+ }
+
+ handleInput(event) {
+ const target = event.target;
+ if (target.classList.contains('d-pad-btn')) {
+ const direction = target.dataset.direction;
+ this.currentDirection = direction;
+
+ const keyEvent = new KeyboardEvent('keydown', {
+ key: direction,
+ code: direction,
+ bubbles: true
+ });
+ document.dispatchEvent(keyEvent);
+
+ target.classList.add('active');
+ }
+ }
+
+ clearInput() {
+ document.querySelectorAll('.d-pad-btn').forEach(btn => {
+ btn.classList.remove('active');
+ });
+ this.currentDirection = null;
+ }
+}
+
+export default DPadController; \ No newline at end of file