dannyboy84 commited on
Commit
b7bb800
·
verified ·
1 Parent(s): e92b0de

Make a game that a ball gets out of the 260 rings outside a ring

Browse files
Files changed (4) hide show
  1. components/ring-game.js +197 -0
  2. index.html +2 -7
  3. script.js +1 -171
  4. style.css +1 -0
components/ring-game.js ADDED
@@ -0,0 +1,197 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ class RingGame extends HTMLElement {
2
+ connectedCallback() {
3
+ this.attachShadow({ mode: 'open' });
4
+ this.shadowRoot.innerHTML = `
5
+ <style>
6
+ :host {
7
+ display: block;
8
+ width: 100%;
9
+ height: 100%;
10
+ }
11
+ canvas {
12
+ display: block;
13
+ background: #1a1a2e;
14
+ }
15
+ </style>
16
+ <canvas></canvas>
17
+ `;
18
+
19
+ this.canvas = this.shadowRoot.querySelector('canvas');
20
+ this.ctx = this.canvas.getContext('2d');
21
+ this.resizeCanvas();
22
+ window.addEventListener('resize', () => this.resizeCanvas());
23
+
24
+ this.setupGame();
25
+ this.gameLoop();
26
+ }
27
+
28
+ resizeCanvas() {
29
+ this.canvas.width = this.clientWidth;
30
+ this.canvas.height = this.clientHeight;
31
+ this.center = {
32
+ x: this.canvas.width / 2,
33
+ y: this.canvas.height / 2
34
+ };
35
+ this.maxRadius = Math.min(this.canvas.width, this.canvas.height) * 0.45;
36
+ }
37
+
38
+ setupGame() {
39
+ this.rings = [];
40
+ this.ball = {
41
+ x: 0,
42
+ y: 0,
43
+ radius: 10,
44
+ speed: 2,
45
+ angle: Math.random() * Math.PI * 2,
46
+ color: '#ff6b6b'
47
+ };
48
+
49
+ // Create 260 concentric rings
50
+ for (let i = 0; i < 260; i++) {
51
+ const radius = this.maxRadius * (1 - i/260);
52
+ this.rings.push({
53
+ radius: radius,
54
+ color: i % 2 === 0 ? '#3a3a5e' : '#2a2a4e',
55
+ thickness: 2
56
+ });
57
+ }
58
+
59
+ // Start ball at center
60
+ this.ball.x = this.center.x;
61
+ this.ball.y = this.center.y;
62
+ this.currentRing = this.rings.length - 1;
63
+ this.gameOver = false;
64
+ this.score = 0;
65
+ }
66
+
67
+ gameLoop() {
68
+ if (this.gameOver) return;
69
+
70
+ this.update();
71
+ this.draw();
72
+
73
+ requestAnimationFrame(() => this.gameLoop());
74
+ }
75
+
76
+ update() {
77
+ // Move ball
78
+ this.ball.x += Math.cos(this.ball.angle) * this.ball.speed;
79
+ this.ball.y += Math.sin(this.ball.angle) * this.ball.speed;
80
+
81
+ // Check collision with current ring
82
+ const ring = this.rings[this.currentRing];
83
+ const distance = Math.sqrt(
84
+ Math.pow(this.ball.x - this.center.x, 2) +
85
+ Math.pow(this.ball.y - this.center.y, 2)
86
+ );
87
+
88
+ if (distance + this.ball.radius > ring.radius) {
89
+ // Bounce off ring
90
+ this.ball.angle = Math.atan2(
91
+ this.ball.y - this.center.y,
92
+ this.ball.x - this.center.x
93
+ );
94
+ this.score++;
95
+
96
+ // Move to next outer ring
97
+ if (this.currentRing > 0) {
98
+ this.currentRing--;
99
+ } else {
100
+ // Escaped all rings!
101
+ this.gameOver = true;
102
+ this.showGameOver(true);
103
+ }
104
+ }
105
+
106
+ // Check if ball escaped the game area
107
+ if (
108
+ this.ball.x < -this.ball.radius ||
109
+ this.ball.x > this.canvas.width + this.ball.radius ||
110
+ this.ball.y < -this.ball.radius ||
111
+ this.ball.y > this.canvas.height + this.ball.radius
112
+ ) {
113
+ this.gameOver = true;
114
+ this.showGameOver(false);
115
+ }
116
+ }
117
+
118
+ draw() {
119
+ // Clear canvas
120
+ this.ctx.fillStyle = '#1a1a2e';
121
+ this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
122
+
123
+ // Draw rings
124
+ this.rings.forEach((ring, i) => {
125
+ if (i <= this.currentRing) {
126
+ this.ctx.beginPath();
127
+ this.ctx.arc(
128
+ this.center.x,
129
+ this.center.y,
130
+ ring.radius,
131
+ 0,
132
+ Math.PI * 2
133
+ );
134
+ this.ctx.strokeStyle = ring.color;
135
+ this.ctx.lineWidth = ring.thickness;
136
+ this.ctx.stroke();
137
+ }
138
+ });
139
+
140
+ // Draw ball
141
+ this.ctx.fillStyle = this.ball.color;
142
+ this.ctx.beginPath();
143
+ this.ctx.arc(
144
+ this.ball.x,
145
+ this.ball.y,
146
+ this.ball.radius,
147
+ 0,
148
+ Math.PI * 2
149
+ );
150
+ this.ctx.fill();
151
+
152
+ // Draw score
153
+ this.ctx.fillStyle = '#ffffff';
154
+ this.ctx.font = '16px "Press Start 2P", cursive';
155
+ this.ctx.textAlign = 'left';
156
+ this.ctx.fillText(`Rings left: ${this.currentRing + 1}`, 20, 30);
157
+ }
158
+
159
+ showGameOver(success) {
160
+ const gameOverDiv = document.createElement('div');
161
+ gameOverDiv.style.position = 'absolute';
162
+ gameOverDiv.style.top = '50%';
163
+ gameOverDiv.style.left = '50%';
164
+ gameOverDiv.style.transform = 'translate(-50%, -50%)';
165
+ gameOverDiv.style.backgroundColor = 'rgba(26, 26, 46, 0.9)';
166
+ gameOverDiv.style.padding = '2rem';
167
+ gameOverDiv.style.borderRadius = '8px';
168
+ gameOverDiv.style.textAlign = 'center';
169
+ gameOverDiv.style.color = 'white';
170
+ gameOverDiv.style.fontFamily = '"Press Start 2P", cursive';
171
+ gameOverDiv.style.zIndex = '100';
172
+
173
+ gameOverDiv.innerHTML = `
174
+ <h2>${success ? 'ESCAPED!' : 'GAME OVER'}</h2>
175
+ <p>You passed ${this.score} rings</p>
176
+ <button id="restart-btn" style="
177
+ background: #ff6b6b;
178
+ color: white;
179
+ border: none;
180
+ padding: 0.5rem 1rem;
181
+ margin-top: 1rem;
182
+ font-family: inherit;
183
+ cursor: pointer;
184
+ ">Play Again</button>
185
+ `;
186
+
187
+ this.shadowRoot.appendChild(gameOverDiv);
188
+
189
+ gameOverDiv.querySelector('#restart-btn').addEventListener('click', () => {
190
+ this.shadowRoot.removeChild(gameOverDiv);
191
+ this.setupGame();
192
+ this.gameLoop();
193
+ });
194
+ }
195
+ }
196
+
197
+ customElements.define('ring-game', RingGame);
index.html CHANGED
@@ -16,14 +16,9 @@
16
  <body>
17
  <wormate-nav></wormate-nav>
18
  <div id="game-container">
19
- <canvas id="gameCanvas"></canvas>
20
- <div id="game-ui">
21
- <div id="score-display">Score: 0</div>
22
- <div id="leaderboard"></div>
23
- <button id="play-btn" class="wormate-btn">PLAY</button>
24
- </div>
25
  </div>
26
- <section id="about-preview" class="info-section">
27
  <h2>About the Game</h2>
28
  <p>Grow your worm, compete with others, and dominate the leaderboard!</p>
29
  <a href="about.html" class="info-link">Learn More →</a>
 
16
  <body>
17
  <wormate-nav></wormate-nav>
18
  <div id="game-container">
19
+ <ring-game></ring-game>
 
 
 
 
 
20
  </div>
21
+ <section id="about-preview" class="info-section">
22
  <h2>About the Game</h2>
23
  <p>Grow your worm, compete with others, and dominate the leaderboard!</p>
24
  <a href="about.html" class="info-link">Learn More →</a>
script.js CHANGED
@@ -2,174 +2,4 @@
2
  document.addEventListener('DOMContentLoaded', () => {
3
  // Initialize Feather Icons
4
  feather.replace();
5
-
6
- const canvas = document.getElementById('gameCanvas');
7
- const ctx = canvas.getContext('2d');
8
-
9
- // Set canvas size
10
- function resizeCanvas() {
11
- canvas.width = window.innerWidth;
12
- canvas.height = window.innerHeight;
13
- }
14
- window.addEventListener('resize', resizeCanvas);
15
- resizeCanvas();
16
-
17
- // Game variables
18
- const gridSize = 20;
19
- const tileCount = Math.floor(canvas.width / gridSize);
20
- let speed = 7;
21
- let score = 0;
22
- let gameRunning = false;
23
- // Worm
24
- let worm = [];
25
- worm[0] = {
26
- x: Math.floor(tileCount/2) * gridSize,
27
- y: Math.floor(tileCount/2) * gridSize
28
- };
29
-
30
- // Food
31
- let food = {
32
- x: Math.floor(Math.random() * tileCount) * gridSize,
33
- y: Math.floor(Math.random() * tileCount) * gridSize,
34
- color: getRandomColor()
35
- };
36
-
37
- // Direction
38
- let xVelocity = 0;
39
- let yVelocity = 0;
40
-
41
- // Game loop
42
- function gameLoop() {
43
- // Clear canvas
44
- ctx.fillStyle = '#f0fdf4';
45
- ctx.fillRect(0, 0, canvas.width, canvas.height);
46
-
47
- // Move worm
48
- let head = {x: worm[0].x + xVelocity, y: worm[0].y + yVelocity};
49
- worm.unshift(head);
50
-
51
- // Check if worm eats food
52
- if(head.x === food.x && head.y === food.y) {
53
- score++;
54
- food = {
55
- x: Math.floor(Math.random() * tileCount) * gridSize,
56
- y: Math.floor(Math.random() * tileCount) * gridSize,
57
- color: getRandomColor()
58
- };
59
- } else {
60
- worm.pop();
61
- }
62
-
63
- // Draw worm
64
- for(let i = 0; i < worm.length; i++) {
65
- ctx.fillStyle = i === 0 ? '#22c55e' : '#4ade80';
66
- ctx.beginPath();
67
- ctx.arc(worm[i].x + gridSize/2, worm[i].y + gridSize/2, gridSize/2, 0, Math.PI*2);
68
- ctx.fill();
69
-
70
- // Add eyes to head
71
- if(i === 0) {
72
- ctx.fillStyle = 'white';
73
- ctx.beginPath();
74
- ctx.arc(worm[i].x + gridSize/3, worm[i].y + gridSize/3, gridSize/8, 0, Math.PI*2);
75
- ctx.arc(worm[i].x + 2*gridSize/3, worm[i].y + gridSize/3, gridSize/8, 0, Math.PI*2);
76
- ctx.fill();
77
-
78
- ctx.fillStyle = 'black';
79
- ctx.beginPath();
80
- ctx.arc(worm[i].x + gridSize/3, worm[i].y + gridSize/3, gridSize/12, 0, Math.PI*2);
81
- ctx.arc(worm[i].x + 2*gridSize/3, worm[i].y + gridSize/3, gridSize/12, 0, Math.PI*2);
82
- ctx.fill();
83
- }
84
- }
85
-
86
- // Draw food
87
- ctx.fillStyle = food.color;
88
- ctx.beginPath();
89
- ctx.arc(food.x + gridSize/2, food.y + gridSize/2, gridSize/2, 0, Math.PI*2);
90
- ctx.fill();
91
-
92
- // Check collision with walls
93
- if(head.x < 0 || head.x >= canvas.width || head.y < 0 || head.y >= canvas.height) {
94
- gameOver();
95
- }
96
-
97
- // Check collision with self
98
- for(let i = 1; i < worm.length; i++) {
99
- if(head.x === worm[i].x && head.y === worm[i].y) {
100
- gameOver();
101
- }
102
- }
103
- }
104
-
105
- // Game controls
106
- document.addEventListener('keydown', (e) => {
107
- // Prevent reverse direction
108
- switch(e.key) {
109
- case 'ArrowUp':
110
- if(yVelocity === 0) {
111
- xVelocity = 0;
112
- yVelocity = -gridSize;
113
- }
114
- break;
115
- case 'ArrowDown':
116
- if(yVelocity === 0) {
117
- xVelocity = 0;
118
- yVelocity = gridSize;
119
- }
120
- break;
121
- case 'ArrowLeft':
122
- if(xVelocity === 0) {
123
- xVelocity = -gridSize;
124
- yVelocity = 0;
125
- }
126
- break;
127
- case 'ArrowRight':
128
- if(xVelocity === 0) {
129
- xVelocity = gridSize;
130
- yVelocity = 0;
131
- }
132
- break;
133
- }
134
- });
135
-
136
- // Game over function
137
- function gameOver() {
138
- clearInterval(gameInterval);
139
-
140
- // Show game over screen
141
- const gameOverDiv = document.createElement('div');
142
- gameOverDiv.className = 'game-over';
143
- gameOverDiv.innerHTML = `
144
- <h2 class="text-4xl font-bold text-white mb-4">Game Over!</h2>
145
- <p class="text-2xl text-white mb-6">Your score: ${score}</p>
146
- <button onclick="location.reload()" class="game-button text-xl">
147
- Play Again <i data-feather="refresh-cw" class="ml-2"></i>
148
- </button>
149
- `;
150
- canvas.parentElement.appendChild(gameOverDiv);
151
- feather.replace();
152
- }
153
-
154
- // Random color generator for food
155
- function getRandomColor() {
156
- const colors = [
157
- '#ef4444', '#f97316', '#f59e0b', '#10b981',
158
- '#3b82f6', '#6366f1', '#8b5cf6', '#ec4899'
159
- ];
160
- return colors[Math.floor(Math.random() * colors.length)];
161
- }
162
- // Start game when play button clicked
163
- document.getElementById('play-btn').addEventListener('click', () => {
164
- if (!gameRunning) {
165
- gameRunning = true;
166
- document.getElementById('play-btn').style.display = 'none';
167
- setInterval(gameLoop, 1000/speed);
168
- }
169
- });
170
- // Responsive canvas
171
- window.addEventListener('resize', () => {
172
- canvas.width = canvas.parentElement.clientWidth;
173
- canvas.height = canvas.parentElement.clientHeight;
174
- });
175
- });
 
2
  document.addEventListener('DOMContentLoaded', () => {
3
  // Initialize Feather Icons
4
  feather.replace();
5
+ });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
style.css CHANGED
@@ -67,6 +67,7 @@ body {
67
  flex: 1;
68
  position: relative;
69
  width: 100%;
 
70
  overflow: hidden;
71
  }
72
  =======
 
67
  flex: 1;
68
  position: relative;
69
  width: 100%;
70
+ height: 100vh;
71
  overflow: hidden;
72
  }
73
  =======