Skip to content

Commit cf921e4

Browse files
authored
Merge pull request #86 from sweatypenguin624/penguin-python
a simple space dodge game
2 parents 7938c22 + ec07340 commit cf921e4

1 file changed

Lines changed: 300 additions & 0 deletions

File tree

python/spaceDodge.py

Lines changed: 300 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,300 @@
1+
from flask import Flask, render_template_string
2+
3+
# PLEASE INSTALL FLASK BEFORE RUNNING THIS CODE
4+
# pip install flask
5+
6+
app = Flask(__name__)
7+
8+
9+
HTML_TEMPLATE = """
10+
<!DOCTYPE html>
11+
<html lang="en">
12+
<head>
13+
<meta charset="UTF-8">
14+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
15+
<title>Space Dodge Game</title>
16+
<style>
17+
body {
18+
margin: 0;
19+
padding: 0;
20+
display: flex;
21+
justify-content: center;
22+
align-items: center;
23+
min-height: 100vh;
24+
background: linear-gradient(to bottom, #0a0e27, #1a1a2e);
25+
font-family: 'Arial', sans-serif;
26+
color: white;
27+
}
28+
#gameContainer {
29+
text-align: center;
30+
}
31+
canvas {
32+
border: 3px solid #4a5568;
33+
box-shadow: 0 0 20px rgba(74, 85, 104, 0.5);
34+
background: #000;
35+
}
36+
h1 {
37+
margin-bottom: 10px;
38+
color: #fff;
39+
text-shadow: 0 0 10px #4299e1;
40+
}
41+
.info {
42+
margin-top: 10px;
43+
color: #a0aec0;
44+
}
45+
</style>
46+
</head>
47+
<body>
48+
<div id="gameContainer">
49+
<h1>🚀 Space Dodge 🚀</h1>
50+
<canvas id="gameCanvas" width="800" height="600"></canvas>
51+
<div class="info">
52+
Use Arrow Keys to move • Collect green power-ups for shields • Press SPACE to restart
53+
</div>
54+
</div>
55+
56+
<script>
57+
const canvas = document.getElementById('gameCanvas');
58+
const ctx = canvas.getContext('2d');
59+
const WIDTH = canvas.width;
60+
const HEIGHT = canvas.height;
61+
62+
class Player {
63+
constructor() {
64+
this.size = 30;
65+
this.x = WIDTH / 2;
66+
this.y = HEIGHT - 80;
67+
this.speed = 7;
68+
this.shield = false;
69+
this.shieldTime = 0;
70+
}
71+
72+
move(keys) {
73+
if (keys.ArrowLeft && this.x > this.size) this.x -= this.speed;
74+
if (keys.ArrowRight && this.x < WIDTH - this.size) this.x += this.speed;
75+
if (keys.ArrowUp && this.y > this.size) this.y -= this.speed;
76+
if (keys.ArrowDown && this.y < HEIGHT - this.size) this.y += this.speed;
77+
}
78+
79+
draw() {
80+
const color = this.shield ? '#ffff33' : '#3296ff';
81+
82+
// Draw spaceship
83+
ctx.fillStyle = color;
84+
ctx.beginPath();
85+
ctx.moveTo(this.x, this.y - this.size);
86+
ctx.lineTo(this.x - this.size, this.y + this.size);
87+
ctx.lineTo(this.x + this.size, this.y + this.size);
88+
ctx.closePath();
89+
ctx.fill();
90+
91+
// Draw shield
92+
if (this.shield) {
93+
ctx.strokeStyle = '#ffff33';
94+
ctx.lineWidth = 2;
95+
ctx.beginPath();
96+
ctx.arc(this.x, this.y, this.size + 10, 0, Math.PI * 2);
97+
ctx.stroke();
98+
}
99+
}
100+
101+
update() {
102+
if (this.shield) {
103+
this.shieldTime--;
104+
if (this.shieldTime <= 0) this.shield = false;
105+
}
106+
}
107+
}
108+
109+
class Asteroid {
110+
constructor() {
111+
this.size = Math.random() * 25 + 15;
112+
this.x = Math.random() * (WIDTH - this.size * 2) + this.size;
113+
this.y = -this.size;
114+
this.speed = Math.random() * 4 + 3;
115+
}
116+
117+
move() {
118+
this.y += this.speed;
119+
}
120+
121+
draw() {
122+
ctx.fillStyle = '#ff3232';
123+
ctx.beginPath();
124+
ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
125+
ctx.fill();
126+
}
127+
128+
offScreen() {
129+
return this.y > HEIGHT + this.size;
130+
}
131+
}
132+
133+
class PowerUp {
134+
constructor() {
135+
this.size = 20;
136+
this.x = Math.random() * (WIDTH - this.size * 2) + this.size;
137+
this.y = -this.size;
138+
this.speed = 3;
139+
}
140+
141+
move() {
142+
this.y += this.speed;
143+
}
144+
145+
draw() {
146+
ctx.fillStyle = '#32ff32';
147+
ctx.beginPath();
148+
ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
149+
ctx.fill();
150+
151+
ctx.fillStyle = '#ffffff';
152+
ctx.beginPath();
153+
ctx.arc(this.x, this.y, this.size / 2, 0, Math.PI * 2);
154+
ctx.fill();
155+
}
156+
157+
offScreen() {
158+
return this.y > HEIGHT + this.size;
159+
}
160+
}
161+
162+
function checkCollision(player, obj) {
163+
const dist = Math.sqrt((player.x - obj.x) ** 2 + (player.y - obj.y) ** 2);
164+
return dist < player.size + obj.size;
165+
}
166+
167+
function drawStars(time) {
168+
ctx.fillStyle = '#ffffff';
169+
for (let i = 0; i < 50; i++) {
170+
const x = (i * 123) % WIDTH;
171+
const y = (i * 456 + time / 20) % HEIGHT;
172+
ctx.beginPath();
173+
ctx.arc(x, y, 1, 0, Math.PI * 2);
174+
ctx.fill();
175+
}
176+
}
177+
178+
let player = new Player();
179+
let asteroids = [];
180+
let powerups = [];
181+
let score = 0;
182+
let gameOver = false;
183+
let spawnTimer = 0;
184+
let powerupTimer = 0;
185+
let keys = {};
186+
let startTime = Date.now();
187+
188+
document.addEventListener('keydown', (e) => {
189+
keys[e.key] = true;
190+
if (e.key === ' ' && gameOver) {
191+
// Restart game
192+
player = new Player();
193+
asteroids = [];
194+
powerups = [];
195+
score = 0;
196+
gameOver = false;
197+
spawnTimer = 0;
198+
powerupTimer = 0;
199+
startTime = Date.now();
200+
}
201+
e.preventDefault();
202+
});
203+
204+
document.addEventListener('keyup', (e) => {
205+
keys[e.key] = false;
206+
});
207+
208+
function gameLoop() {
209+
const currentTime = Date.now() - startTime;
210+
211+
// Clear canvas
212+
ctx.fillStyle = '#000000';
213+
ctx.fillRect(0, 0, WIDTH, HEIGHT);
214+
215+
// Draw stars
216+
drawStars(currentTime);
217+
218+
if (!gameOver) {
219+
player.move(keys);
220+
player.update();
221+
222+
// Spawn asteroids
223+
spawnTimer++;
224+
if (spawnTimer > Math.max(20, 60 - Math.floor(score / 10))) {
225+
asteroids.push(new Asteroid());
226+
spawnTimer = 0;
227+
}
228+
229+
// Spawn powerups
230+
powerupTimer++;
231+
if (powerupTimer > 300) {
232+
powerups.push(new PowerUp());
233+
powerupTimer = 0;
234+
}
235+
236+
// Update asteroids
237+
for (let i = asteroids.length - 1; i >= 0; i--) {
238+
asteroids[i].move();
239+
if (asteroids[i].offScreen()) {
240+
asteroids.splice(i, 1);
241+
score++;
242+
} else if (checkCollision(player, asteroids[i])) {
243+
if (!player.shield) {
244+
gameOver = true;
245+
} else {
246+
asteroids.splice(i, 1);
247+
}
248+
}
249+
}
250+
251+
// Update powerups
252+
for (let i = powerups.length - 1; i >= 0; i--) {
253+
powerups[i].move();
254+
if (powerups[i].offScreen()) {
255+
powerups.splice(i, 1);
256+
} else if (checkCollision(player, powerups[i])) {
257+
powerups.splice(i, 1);
258+
player.shield = true;
259+
player.shieldTime = 180;
260+
score += 5;
261+
}
262+
}
263+
}
264+
265+
// Draw everything
266+
player.draw();
267+
asteroids.forEach(a => a.draw());
268+
powerups.forEach(p => p.draw());
269+
270+
// Draw score
271+
ctx.fillStyle = '#ffffff';
272+
ctx.font = '32px Arial';
273+
ctx.fillText(`Score: ${score}`, 10, 40);
274+
275+
if (gameOver) {
276+
ctx.fillStyle = '#ff3232';
277+
ctx.font = '64px Arial';
278+
ctx.fillText('GAME OVER!', WIDTH / 2 - 200, HEIGHT / 2 - 50);
279+
280+
ctx.fillStyle = '#ffffff';
281+
ctx.font = '32px Arial';
282+
ctx.fillText(`Final Score: ${score}`, WIDTH / 2 - 110, HEIGHT / 2 + 20);
283+
ctx.fillText('Press SPACE to restart', WIDTH / 2 - 150, HEIGHT / 2 + 80);
284+
}
285+
286+
requestAnimationFrame(gameLoop);
287+
}
288+
289+
gameLoop();
290+
</script>
291+
</body>
292+
</html>
293+
"""
294+
295+
@app.route('/')
296+
def index():
297+
return render_template_string(HTML_TEMPLATE)
298+
299+
if __name__ == '__main__':
300+
app.run(debug=True, host='0.0.0.0', port=5001)

0 commit comments

Comments
 (0)