Skip to content

Commit 59b7b23

Browse files
Enhance Coin-Poison game: add levels, lives, shield, and dynamic score
- Introduced levels: game speed and difficulty increase after clearing coins - Added 3-life system before game over - Added shield power-up that protects from poison collision - Display updated score, coins left, lives, and level dynamically - Refactored spawn and reset logic for better code structure - Significant gameplay improvements to make game more engaging and robust
1 parent 00a6c93 commit 59b7b23

File tree

1 file changed

+106
-36
lines changed

1 file changed

+106
-36
lines changed

Coin-Poison/coin-poison.py

Lines changed: 106 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,51 @@
11
import pygame
22
import random
3+
34
pygame.init()
45

6+
# ================== CONFIG ==================
57
GRID_SIZE = 40
6-
GRID_WIDTH = 17
7-
GRID_HEIGHT = 17
8+
GRID_WIDTH = 17
9+
GRID_HEIGHT = 17
810
SCREEN_WIDTH = GRID_SIZE * GRID_WIDTH
911
SCREEN_HEIGHT = GRID_SIZE * GRID_HEIGHT
10-
BG_COLOR = (30, 30, 30)
12+
13+
BG_COLOR = (30, 30, 30)
1114
PLAYER_COLOR = (0, 255, 0)
1215
COIN_COLOR = (255, 215, 0)
1316
POISON_COLOR = (255, 0, 0)
17+
SHIELD_COLOR = (0, 191, 255)
18+
1419
FPS = 15
1520

1621
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
17-
pygame.display.set_caption("coin&poison")
22+
pygame.display.set_caption("Coin & Poison Adventure")
1823

1924
font = pygame.font.Font(None, 36)
2025

26+
# ================== CLASSES ==================
27+
2128
class Player(pygame.sprite.Sprite):
29+
"""Player controlled by arrow keys"""
2230
def __init__(self):
2331
super().__init__()
2432
self.image = pygame.Surface((GRID_SIZE, GRID_SIZE))
2533
self.image.fill(PLAYER_COLOR)
2634
self.rect = self.image.get_rect()
2735
self.rect.topleft = (0, 0)
2836
self.score = 0
37+
self.lives = 3
38+
self.shield = False
2939

3040
def move(self, dx, dy):
3141
new_rect = self.rect.move(dx * GRID_SIZE, dy * GRID_SIZE)
32-
if 0 <= new_rect.left < SCREEN_WIDTH and 0 <= new_rect.top < SCREEN_HEIGHT: # within limits
42+
if 0 <= new_rect.left < SCREEN_WIDTH and 0 <= new_rect.top < SCREEN_HEIGHT:
3343
self.rect = new_rect
3444
else:
35-
self.score -= 1 # hit the boundary
45+
self.score -= 1 # penalize hitting boundary
3646

3747
class Coin(pygame.sprite.Sprite):
48+
"""Collectible coin"""
3849
def __init__(self, x, y):
3950
super().__init__()
4051
self.image = pygame.Surface((GRID_SIZE, GRID_SIZE))
@@ -43,15 +54,27 @@ def __init__(self, x, y):
4354
self.rect.topleft = (x * GRID_SIZE, y * GRID_SIZE)
4455

4556
class Poison(pygame.sprite.Sprite):
57+
"""Poison block that reduces life"""
4658
def __init__(self, x, y):
4759
super().__init__()
4860
self.image = pygame.Surface((GRID_SIZE, GRID_SIZE))
4961
self.image.fill(POISON_COLOR)
5062
self.rect = self.image.get_rect()
5163
self.rect.topleft = (x * GRID_SIZE, y * GRID_SIZE)
5264

53-
# to spawn coin and poison blocks without overlapping with each other and player
65+
class Shield(pygame.sprite.Sprite):
66+
"""Power-up shield to protect from poison"""
67+
def __init__(self, x, y):
68+
super().__init__()
69+
self.image = pygame.Surface((GRID_SIZE, GRID_SIZE))
70+
self.image.fill(SHIELD_COLOR)
71+
self.rect = self.image.get_rect()
72+
self.rect.topleft = (x * GRID_SIZE, y * GRID_SIZE)
73+
74+
# ================== HELPER FUNCTIONS ==================
75+
5476
def spawn_objects(num_objects, avoid_positions):
77+
"""Spawn objects without overlapping"""
5578
objects = []
5679
while len(objects) < num_objects:
5780
x = random.randint(0, GRID_WIDTH - 1)
@@ -61,35 +84,67 @@ def spawn_objects(num_objects, avoid_positions):
6184
avoid_positions.add((x, y))
6285
return objects
6386

87+
def reset_level():
88+
"""Reset coins, poisons, and optionally add shield"""
89+
global coins, poisons, shield_powerups, all_sprites, avoid_positions, FPS, level
90+
level += 1
91+
FPS += 1 # increase speed for next level
92+
num_coins = 10 + level * 2
93+
num_poisons = 5 + level
94+
95+
# Clear old objects
96+
for sprite in coins.sprites() + poisons.sprites() + shield_powerups.sprites():
97+
all_sprites.remove(sprite)
98+
99+
# Reset positions
100+
avoid_positions = {(player.rect.x // GRID_SIZE, player.rect.y // GRID_SIZE)}
101+
102+
# Spawn coins
103+
coin_positions = spawn_objects(num_coins, avoid_positions)
104+
coins = pygame.sprite.Group()
105+
for pos in coin_positions:
106+
coin = Coin(*pos)
107+
coins.add(coin)
108+
all_sprites.add(coin)
109+
110+
# Spawn poisons
111+
poison_positions = spawn_objects(num_poisons, avoid_positions)
112+
poisons = pygame.sprite.Group()
113+
for pos in poison_positions:
114+
poison = Poison(*pos)
115+
poisons.add(poison)
116+
all_sprites.add(poison)
117+
118+
# Spawn shield occasionally
119+
shield_positions = spawn_objects(1, avoid_positions)
120+
shield_powerups = pygame.sprite.Group()
121+
for pos in shield_positions:
122+
shield = Shield(*pos)
123+
shield_powerups.add(shield)
124+
all_sprites.add(shield)
125+
126+
# ================== GAME INIT ==================
127+
64128
player = Player()
65129
all_sprites = pygame.sprite.Group()
66130
all_sprites.add(player)
67131

68-
# total no of coins and poison blocks
69-
num_coins = 20
70-
num_poisons = 10
71-
132+
coins = pygame.sprite.Group()
133+
poisons = pygame.sprite.Group()
134+
shield_powerups = pygame.sprite.Group()
72135
avoid_positions = {(player.rect.x // GRID_SIZE, player.rect.y // GRID_SIZE)}
73136

74-
poison_positions = spawn_objects(num_poisons, avoid_positions)
75-
poisons = pygame.sprite.Group()
76-
for pos in poison_positions:
77-
poison = Poison(*pos)
78-
poisons.add(poison)
79-
all_sprites.add(poison)
80-
81-
coin_positions = spawn_objects(num_coins, avoid_positions)
82-
coins = pygame.sprite.Group()
83-
for pos in coin_positions:
84-
coin = Coin(*pos)
85-
coins.add(coin)
86-
all_sprites.add(coin)
137+
level = 1
138+
reset_level()
87139

88140
clock = pygame.time.Clock()
89-
90141
running = True
142+
143+
# ================== GAME LOOP ==================
144+
91145
while running:
92-
clock.tick(FPS)
146+
clock.tick(FPS)
147+
93148
for event in pygame.event.get():
94149
if event.type == pygame.QUIT:
95150
running = False
@@ -104,24 +159,39 @@ def spawn_objects(num_objects, avoid_positions):
104159
if keys[pygame.K_DOWN]:
105160
player.move(0, 1)
106161

162+
# Collect coins
107163
collected_coins = pygame.sprite.spritecollide(player, coins, True)
108164
player.score += len(collected_coins)
109165

110-
if pygame.sprite.spritecollideany(player, poisons):
111-
print(f"collided with poison block! score: {player.score}")
112-
running = False
166+
# Collect shield
167+
if pygame.sprite.spritecollide(player, shield_powerups, True):
168+
player.shield = True
169+
print("Shield activated! Next poison hit will be ignored.")
113170

114-
# if all coins collected, won
171+
# Poison collision
172+
if pygame.sprite.spritecollideany(player, poisons):
173+
if player.shield:
174+
player.shield = False
175+
print("Shield protected you from poison!")
176+
else:
177+
player.lives -= 1
178+
if player.lives == 0:
179+
print(f"Game Over! Final Score: {player.score}")
180+
running = False
181+
else:
182+
print(f"Hit poison! Lives left: {player.lives}")
183+
184+
# Level completed
115185
if len(coins) == 0:
116-
print(f"collected all coins! score: {player.score}")
117-
running = False
186+
print(f"Level {level} cleared! Moving to next level...")
187+
reset_level()
118188

189+
# Draw everything
119190
screen.fill(BG_COLOR)
120191
all_sprites.draw(screen)
121-
122-
score_text = font.render(f"score: {player.score}", True, (255, 255, 255))
123-
screen.blit(score_text, (10, 10))
192+
score_text = font.render(f"Score: {player.score} | Coins left: {len(coins)} | Lives: {player.lives} | Level: {level}", True, (255, 255, 255))
193+
screen.blit(score_text, (10, 10))
124194

125195
pygame.display.flip()
126196

127-
pygame.quit()
197+
pygame.quit()

0 commit comments

Comments
 (0)