Advertisement
dsgregfdhgfhjufdgh

Untitled

Mar 25th, 2025
962
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 24.68 KB | None | 0 0
  1. # Single-file Python Super Mario Clone (No External Assets)
  2. # Version: Added Title Screen
  3.  
  4. import pygame
  5. import sys
  6. import random
  7.  
  8. # --- Constants ---
  9. SCREEN_WIDTH = 800
  10. SCREEN_HEIGHT = 600
  11. FPS = 60
  12.  
  13. # Colors (RGB)
  14. WHITE = (255, 255, 255)
  15. BLACK = (0, 0, 0)
  16. RED = (200, 0, 0)
  17. BRIGHT_RED = (255, 0, 0)
  18. BLUE = (100, 149, 237)
  19. BROWN = (139, 69, 19)
  20. DARK_BROWN = (101, 67, 33)
  21. YELLOW = (255, 223, 0)
  22. GREEN = (0, 150, 0)
  23. DARK_GREEN = (0, 100, 0)
  24. GREY = (128, 128, 128)
  25. DARK_GREY = (105, 105, 105)
  26. POLE_COLOR = (192, 192, 192)
  27. CLOUD_WHITE = (245, 245, 245)
  28.  
  29. # Physics constants
  30. PLAYER_ACC = 0.5
  31. PLAYER_FRICTION = -0.12
  32. PLAYER_GRAVITY = 0.7
  33. PLAYER_JUMP_STRENGTH = -15
  34. PLAYER_MAX_FALL_SPEED = 10
  35. ENEMY_SPEED = 1.5
  36.  
  37. # --- Helper Functions ---
  38. def draw_text(surface, text, size, x, y, color=WHITE):
  39. try:
  40. font = pygame.font.Font(None, size)
  41. text_surface = font.render(text, True, color)
  42. text_rect = text_surface.get_rect(midtop=(x, y))
  43. surface.blit(text_surface, text_rect)
  44. except Exception as e:
  45. print(f"Error rendering font: {e}")
  46.  
  47. # --- Classes ---
  48. # (Player, Platform, Enemy, Coin, Flag, Bush, Cloud, Camera classes remain unchanged)
  49. # --- [Insert ALL class definitions from the previous version here] ---
  50. class Player(pygame.sprite.Sprite):
  51. # (Player class remains largely the same as the previous version)
  52. def __init__(self):
  53. super().__init__()
  54. self.base_image = pygame.Surface((30, 40)); self.base_image.fill(RED)
  55. hat = pygame.Surface((20, 8)); hat.fill(BRIGHT_RED)
  56. self.base_image.blit(hat, (5, 2))
  57. self.image = self.base_image.copy()
  58. self.rect = self.image.get_rect(center=(SCREEN_WIDTH // 4, SCREEN_HEIGHT - 100))
  59. self.pos = pygame.math.Vector2(self.rect.centerx, self.rect.bottom)
  60. self.vel = pygame.math.Vector2(0, 0)
  61. self.acc = pygame.math.Vector2(0, 0)
  62. self.on_ground = False
  63. self.score = 0
  64. self.won = False
  65.  
  66. def jump(self):
  67. if self.on_ground: self.vel.y = PLAYER_JUMP_STRENGTH; self.on_ground = False
  68.  
  69. def move(self, direction):
  70. if direction == "LEFT": self.acc.x = -PLAYER_ACC
  71. elif direction == "RIGHT": self.acc.x = PLAYER_ACC
  72.  
  73. def update(self, platforms):
  74. if self.won: self.vel.x = 0; return
  75.  
  76. # Horizontal
  77. self.acc = pygame.math.Vector2(0, PLAYER_GRAVITY)
  78. keys = pygame.key.get_pressed()
  79. if keys[pygame.K_LEFT] or keys[pygame.K_a]: self.move("LEFT")
  80. if keys[pygame.K_RIGHT] or keys[pygame.K_d]: self.move("RIGHT")
  81. if not (keys[pygame.K_LEFT] or keys[pygame.K_a] or keys[pygame.K_RIGHT] or keys[pygame.K_d]):
  82. self.acc.x += self.vel.x * PLAYER_FRICTION
  83. self.vel.x += self.acc.x
  84. MAX_SPEED_X = 5
  85. if abs(self.vel.x) > MAX_SPEED_X: self.vel.x = MAX_SPEED_X * (1 if self.vel.x > 0 else -1)
  86. self.pos.x += self.vel.x + 0.5 * self.acc.x
  87. self.rect.centerx = round(self.pos.x)
  88. self.check_platform_collisions(platforms, 'horizontal')
  89.  
  90. # Vertical
  91. self.vel.y += self.acc.y
  92. if self.vel.y > PLAYER_MAX_FALL_SPEED: self.vel.y = PLAYER_MAX_FALL_SPEED
  93. self.pos.y += self.vel.y + 0.5 * self.acc.y
  94. self.rect.bottom = round(self.pos.y)
  95. self.on_ground = False
  96. self.check_platform_collisions(platforms, 'vertical')
  97.  
  98. # Sync
  99. self.pos.x = self.rect.centerx
  100. self.pos.y = self.rect.bottom
  101.  
  102. def check_platform_collisions(self, platforms, direction):
  103. if direction == 'horizontal':
  104. hits = pygame.sprite.spritecollide(self, platforms, False)
  105. for platform in hits:
  106. if not getattr(platform, 'is_solid', True): continue
  107. if self.vel.x > 0: self.rect.right = platform.rect.left
  108. elif self.vel.x < 0: self.rect.left = platform.rect.right
  109. self.pos.x = self.rect.centerx; self.vel.x = 0
  110.  
  111. if direction == 'vertical':
  112. hits = pygame.sprite.spritecollide(self, platforms, False)
  113. solid_hits = [p for p in hits if getattr(p, 'is_solid', True)]
  114. if not solid_hits: return
  115.  
  116. if self.vel.y > 0: # Landing
  117. solid_hits.sort(key=lambda p: p.rect.top)
  118. landed_on = next((p for p in solid_hits if self.rect.bottom >= p.rect.top and self.rect.centery < p.rect.top + 15), None)
  119. if landed_on: self.rect.bottom = landed_on.rect.top; self.pos.y = self.rect.bottom; self.vel.y = 0; self.on_ground = True
  120. elif self.vel.y < 0: # Ceiling
  121. solid_hits.sort(key=lambda p: p.rect.bottom, reverse=True)
  122. bumped = next((p for p in solid_hits if self.rect.top <= p.rect.bottom and self.rect.centery > p.rect.bottom - 15), None)
  123. if bumped: self.rect.top = bumped.rect.bottom; self.pos.y = self.rect.bottom; self.vel.y = 0
  124.  
  125. def check_enemy_collisions(self, enemies):
  126. if self.won: return False
  127. hits = pygame.sprite.spritecollide(self, enemies, False)
  128. for enemy in hits:
  129. prox = abs(self.rect.bottom - enemy.rect.top) < 15
  130. overlap = (self.rect.right > enemy.rect.left + 5 and self.rect.left < enemy.rect.right - 5)
  131. is_stomp = self.vel.y > 1 and prox and overlap
  132. if is_stomp:
  133. enemy.kill(); self.vel.y = PLAYER_JUMP_STRENGTH * 0.6; self.pos.y = self.rect.bottom
  134. self.on_ground = False; self.score += 100; print(f"Stomped! Score: {self.score}")
  135. else:
  136. if not (self.vel.y < -1 and prox): # Avoid game over right after bounce
  137. print(f"Hit by enemy! V:{self.vel}, P_bot:{self.rect.bottom}, E_top:{enemy.rect.top}")
  138. return True # Game Over
  139. return False
  140.  
  141. def check_coin_collisions(self, coins):
  142. if self.won: return
  143. hits = pygame.sprite.spritecollide(self, coins, True)
  144. self.score += len(hits) * 50
  145. if hits: print(f"Coin! Score: {self.score}")
  146.  
  147. def check_goal_collision(self, goal_flag):
  148. if self.won: return False
  149. if pygame.sprite.collide_rect(self, goal_flag):
  150. print("Reached the flag! Level Complete!")
  151. self.won = True; self.score += 1000; return True
  152. return False
  153.  
  154. def draw(self, surface, camera_offset_x):
  155. draw_rect = self.rect.move(camera_offset_x, 0)
  156. surface.blit(self.image, draw_rect)
  157.  
  158. class Platform(pygame.sprite.Sprite):
  159. def __init__(self, x, y, width, height, color=BROWN, is_solid=True):
  160. super().__init__()
  161. self.image = pygame.Surface((width, height)); self.image.fill(color)
  162. self.rect = self.image.get_rect(topleft=(x, y))
  163. self.is_solid = is_solid
  164.  
  165. def draw(self, surface, camera_offset_x):
  166. draw_rect = self.rect.move(camera_offset_x, 0)
  167. if draw_rect.right > 0 and draw_rect.left < SCREEN_WIDTH:
  168. surface.blit(self.image, draw_rect)
  169.  
  170. class Enemy(pygame.sprite.Sprite):
  171. # (Enemy class remains largely the same)
  172. def __init__(self, x, y, patrol_range=100):
  173. super().__init__()
  174. self.image = pygame.Surface((25, 25)); self.image.fill(DARK_BROWN)
  175. pygame.draw.circle(self.image, WHITE, (7, 10), 3)
  176. pygame.draw.circle(self.image, WHITE, (18, 10), 3)
  177. self.rect = self.image.get_rect(bottomleft=(x, y))
  178. self.start_x = self.rect.left; self.patrol_range = patrol_range
  179. self.vel_x = ENEMY_SPEED; self.pos_x = float(self.rect.x)
  180. self.vel_y = 0; self.on_ground = False
  181.  
  182. def update(self, platforms):
  183. # Horizontal
  184. self.pos_x += self.vel_x; self.rect.x = round(self.pos_x)
  185. left = self.start_x; right = self.start_x + self.patrol_range
  186. if (self.vel_x < 0 and self.rect.left <= left) or (self.vel_x > 0 and self.rect.right >= right):
  187. self.vel_x *= -1
  188. if self.vel_x > 0: self.rect.left = left + 1
  189. else: self.rect.right = right - 1
  190. self.pos_x = float(self.rect.x)
  191. # Vertical
  192. solids = [p for p in platforms if getattr(p, 'is_solid', True)]
  193. if not self.on_ground:
  194. self.vel_y += PLAYER_GRAVITY * 0.5
  195. if self.vel_y > PLAYER_MAX_FALL_SPEED * 0.5: self.vel_y = PLAYER_MAX_FALL_SPEED * 0.5
  196. self.rect.y += int(self.vel_y)
  197. # Collision
  198. self.on_ground = False; self.rect.y += 1
  199. hits = pygame.sprite.spritecollide(self, solids, False)
  200. self.rect.y -= 1
  201. if hits:
  202. hits.sort(key=lambda p: p.rect.top)
  203. landed = next((p for p in hits if self.rect.bottom >= p.rect.top and self.rect.centery < p.rect.top + 5), None)
  204. if landed: self.rect.bottom = landed.rect.top; self.vel_y = 0; self.on_ground = True
  205.  
  206. def draw(self, surface, camera_offset_x):
  207. draw_rect = self.rect.move(camera_offset_x, 0)
  208. if draw_rect.right > 0 and draw_rect.left < SCREEN_WIDTH: surface.blit(self.image, draw_rect)
  209.  
  210. class Coin(pygame.sprite.Sprite):
  211. # (Coin class remains the same)
  212. def __init__(self, x, y):
  213. super().__init__()
  214. self.size = 15; self.image = pygame.Surface((self.size, self.size), pygame.SRCALPHA)
  215. center = self.size // 2
  216. pygame.draw.circle(self.image, YELLOW, (center, center), center)
  217. pygame.draw.circle(self.image, BLACK, (center, center), center, 1)
  218. self.rect = self.image.get_rect(center=(x, y))
  219.  
  220. def draw(self, surface, camera_offset_x):
  221. draw_rect = self.rect.move(camera_offset_x, 0)
  222. if draw_rect.right > 0 and draw_rect.left < SCREEN_WIDTH: surface.blit(self.image, draw_rect)
  223.  
  224. class Flag(pygame.sprite.Sprite):
  225. # (Flag class remains the same)
  226. def __init__(self, x, y):
  227. super().__init__()
  228. self.pole_height = 180; self.flag_width = 40; self.flag_height = 30; pole_width = 8
  229. self.image = pygame.Surface((self.flag_width + pole_width, self.pole_height), pygame.SRCALPHA)
  230. # Pole
  231. pole_rect = pygame.Rect(0, 0, pole_width, self.pole_height)
  232. pygame.draw.rect(self.image, POLE_COLOR, pole_rect)
  233. pygame.draw.circle(self.image, POLE_COLOR, (pole_width // 2, pole_width // 2), pole_width // 2)
  234. # Flag Head
  235. flag_points = [(pole_width, 10), (pole_width + self.flag_width, self.flag_height // 2 + 10), (pole_width, self.flag_height + 10)]
  236. pygame.draw.polygon(self.image, GREEN, flag_points)
  237. pygame.draw.polygon(self.image, BLACK, flag_points, 1)
  238. # Position
  239. self.rect = self.image.get_rect(bottomleft=(x, y))
  240.  
  241. def draw(self, surface, camera_offset_x):
  242. draw_rect = self.rect.move(camera_offset_x, 0)
  243. if draw_rect.right > 0 and draw_rect.left < SCREEN_WIDTH: surface.blit(self.image, draw_rect)
  244.  
  245. class Bush(pygame.sprite.Sprite):
  246. """A simple decorative bush."""
  247. def __init__(self, x, y):
  248. super().__init__()
  249. width = random.randint(40, 70); height = random.randint(20, 35)
  250. self.image = pygame.Surface((width, height), pygame.SRCALPHA)
  251. pygame.draw.ellipse(self.image, DARK_GREEN, (0, height*0.2, width*0.6, height*0.8))
  252. pygame.draw.ellipse(self.image, GREEN, (width*0.3, 0, width*0.7, height*0.9))
  253. self.rect = self.image.get_rect(bottomleft=(x, y))
  254.  
  255. def draw(self, surface, camera_offset_x):
  256. draw_rect = self.rect.move(camera_offset_x, 0)
  257. if draw_rect.right > 0 and draw_rect.left < SCREEN_WIDTH: surface.blit(self.image, draw_rect)
  258.  
  259. class Cloud(pygame.sprite.Sprite):
  260. """A simple decorative cloud."""
  261. def __init__(self, x, y):
  262. super().__init__()
  263. width = random.randint(60, 150); height = random.randint(30, 60)
  264. self.image = pygame.Surface((width, height), pygame.SRCALPHA)
  265. num_blobs = random.randint(3, 5)
  266. for _ in range(num_blobs):
  267. blob_w = random.uniform(0.3, 0.7) * width; blob_h = random.uniform(0.4, 0.8) * height
  268. blob_x = random.uniform(0, 1 - blob_w/width) * width; blob_y = random.uniform(0, 1 - blob_h/height) * height
  269. pygame.draw.ellipse(self.image, CLOUD_WHITE, (blob_x, blob_y, blob_w, blob_h))
  270. self.rect = self.image.get_rect(center=(x, y))
  271. self.drift_speed = random.uniform(-0.1, 0.1); self.true_x = float(x)
  272.  
  273. def update(self): # Cloud drifting
  274. self.true_x += self.drift_speed; self.rect.centerx = round(self.true_x)
  275.  
  276. def draw(self, surface, camera_offset_x):
  277. draw_rect = self.rect.move(camera_offset_x, 0)
  278. if draw_rect.right > 0 and draw_rect.left < SCREEN_WIDTH: surface.blit(self.image, draw_rect)
  279.  
  280. class Camera:
  281. # (Camera class remains the same)
  282. def __init__(self, level_width):
  283. self.level_width = level_width; self.camera_rect = pygame.Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT)
  284. def update(self, target):
  285. if target.won: return
  286. x = -target.rect.centerx + int(SCREEN_WIDTH / 2)
  287. x = min(0, x); x = max(-(self.level_width - SCREEN_WIDTH), x)
  288. self.camera_rect.x = x
  289. def get_offset_x(self): return self.camera_rect.x
  290.  
  291.  
  292. # --- Game Setup ---
  293. # (setup_level function remains the same as the previous version)
  294. def setup_level():
  295. platforms = pygame.sprite.Group()
  296. enemies = pygame.sprite.Group()
  297. coins = pygame.sprite.Group()
  298. goal_flag_group = pygame.sprite.GroupSingle()
  299. background_decorations = pygame.sprite.Group() # NEW group for decor
  300.  
  301. # --- Ground & Level Dimensions ---
  302. ground_y = SCREEN_HEIGHT - 40
  303. level_length = 12000
  304. hole_width = 150
  305. ground_segments = []
  306. current_x = 0
  307. segment_lengths = [1500, 2500, 1800, 3000] # Lengths before holes
  308. for length in segment_lengths:
  309. if current_x + length <= level_length:
  310. ground_segments.append(Platform(current_x, ground_y, length, 40))
  311. current_x += length + hole_width # Add hole width for next segment
  312. else: # Prevent overshoot
  313. ground_segments.append(Platform(current_x, ground_y, level_length - current_x, 40))
  314. current_x = level_length; break
  315. # Add final segment if needed
  316. if current_x < level_length:
  317. ground_segments.append(Platform(current_x, ground_y, level_length - current_x, 40))
  318. platforms.add(ground_segments)
  319.  
  320. # --- Floating Platforms --- (Positions relative to new ground/holes)
  321. floating_platforms = [
  322. Platform(400, ground_y - 100, 150, 20), Platform(750, ground_y - 180, 100, 20), Platform(1100, ground_y - 120, 120, 20),
  323. Platform(1800, ground_y - 150, 80, 20), Platform(2200, ground_y - 220, 100, 20), Platform(2600, ground_y - 100, 150, 20),
  324. Platform(4500, ground_y - 160, 100, 20), Platform(4900, ground_y - 250, 120, 20), Platform(5300, ground_y - 100, 80, 20),
  325. Platform(8000, ground_y - 120, 150, 20), Platform(8500, ground_y - 200, 100, 60), Platform(9000, ground_y - 280, 120, 20),
  326. Platform(10000, ground_y - 100, 200, 20), Platform(10500, ground_y - 180, 150, 20), Platform(11000, ground_y - 250, 100, 20),
  327. ]
  328. platforms.add(floating_platforms)
  329.  
  330. # --- Hills --- (Positions adjusted)
  331. # Hill 1
  332. hill1_x = 2000; platforms.add(Platform(hill1_x, ground_y-20, 250, 20), Platform(hill1_x+25, ground_y-40, 200, 20), Platform(hill1_x+50, ground_y-60, 150, 20), Platform(hill1_x+75, ground_y-80, 100, 20))
  333. # Hill 2
  334. hill2_x = 6000; platforms.add(Platform(hill2_x, ground_y-20, 150, 20), Platform(hill2_x+150, ground_y-40, 100, 40), Platform(hill2_x+250, ground_y-60, 100, 60), Platform(hill2_x+350, ground_y-40, 100, 40), Platform(hill2_x+450, ground_y-20, 150, 20))
  335.  
  336. # --- Background Decorations ---
  337. # Bushes
  338. num_bushes = level_length // 300
  339. for i in range(num_bushes):
  340. bush_x = random.randint(i*300, (i+1)*300 - 50)
  341. is_over_hole = False; temp_x = 0
  342. for length in segment_lengths:
  343. hole_start = temp_x + length; hole_end = hole_start + hole_width
  344. if bush_x > hole_start and bush_x < hole_end: is_over_hole = True; break
  345. temp_x = hole_end
  346. if not is_over_hole and bush_x < level_length - 100: background_decorations.add(Bush(bush_x, ground_y))
  347. # Clouds
  348. num_clouds = level_length // 500
  349. for i in range(num_clouds):
  350. cloud_x = random.randint(i*500, (i+1)*500 - 100); cloud_y = random.randint(50, SCREEN_HEIGHT // 3)
  351. background_decorations.add(Cloud(cloud_x, cloud_y))
  352.  
  353. # --- Enemies --- (Positions adjusted)
  354. level_enemies = [
  355. Enemy(600, ground_y, 100), Enemy(1000, ground_y, 150),
  356. Enemy(floating_platforms[4].rect.centerx-50, floating_platforms[4].rect.top, 50),
  357. Enemy(3000, ground_y, 200), Enemy(3500, ground_y, 100),
  358. Enemy(floating_platforms[7].rect.centerx-60, floating_platforms[7].rect.top, 60),
  359. Enemy(hill2_x + 300, ground_y - 80, 50), # On hill 2
  360. Enemy(8200, ground_y, 100), Enemy(8700, ground_y, 150),
  361. Enemy(floating_platforms[-2].rect.centerx-75, floating_platforms[-2].rect.top, 100),
  362. Enemy(11200, ground_y, 100),
  363. ]
  364. enemies.add(level_enemies)
  365.  
  366. # --- Coins --- (Positions adjusted)
  367. level_coins = []
  368. for i in range(4): level_coins.append(Coin(450+i*30, ground_y-150))
  369. for i in range(5): level_coins.append(Coin(2300+i*30, ground_y-50))
  370. level_coins.append(Coin(floating_platforms[4].rect.centerx, floating_platforms[4].rect.top-30))
  371. level_coins.append(Coin(hill1_x + 125, ground_y-120))
  372. level_coins.append(Coin(hill2_x + 300, ground_y-100))
  373. for i in range(3): level_coins.append(Coin(floating_platforms[-3].rect.centerx-30+i*30, floating_platforms[-3].rect.top-30))
  374. for i in range(6): level_coins.append(Coin(9200+i*30, ground_y-50))
  375. coins.add(level_coins)
  376.  
  377. # --- Castle and Flag ---
  378. castle_base_x = level_length - 500
  379. castle_width = 200; castle_height = 250
  380. platforms.add(Platform(castle_base_x, ground_y - castle_height, castle_width, castle_height, GREY, True))
  381. battlement_w=30; battlement_h=40
  382. for i in range(4): platforms.add(Platform(castle_base_x + i * (castle_width//4) + 5, ground_y - castle_height - battlement_h + 10, battlement_w, battlement_h, DARK_GREY, False))
  383. platforms.add(Platform(castle_base_x + castle_width//2 - 25, ground_y - 60, 50, 60, BLACK, False)) # Door
  384. flag_x = castle_base_x - 80 # Flag Left of castle
  385. the_flag = Flag(flag_x, ground_y)
  386. goal_flag_group.add(the_flag)
  387.  
  388. level_width_actual = castle_base_x + castle_width + 100
  389. return platforms, enemies, coins, goal_flag_group, background_decorations, level_width_actual
  390.  
  391.  
  392. # --- NEW: Title Screen Function ---
  393. def show_title_screen(screen, clock):
  394. """Displays the title screen and waits for player action."""
  395. title_font_size = 80
  396. instr_font_size = 30
  397. title_y = SCREEN_HEIGHT // 4
  398. instr_y = SCREEN_HEIGHT // 2 + 50
  399. start_key = pygame.K_SPACE # Or pygame.K_RETURN
  400.  
  401. waiting = True
  402. while waiting:
  403. screen.fill(BLUE) # Background color
  404.  
  405. # Draw Title
  406. draw_text(screen, "Python Pseudo-Mario", title_font_size, SCREEN_WIDTH / 2, title_y, YELLOW)
  407.  
  408. # Draw Instructions (could blink later)
  409. draw_text(screen, f"Press SPACE to Start", instr_font_size, SCREEN_WIDTH / 2, instr_y, WHITE)
  410. draw_text(screen, "Press ESC to Quit", instr_font_size, SCREEN_WIDTH / 2, instr_y + 40, WHITE)
  411.  
  412. # Draw a simple ground line
  413. pygame.draw.line(screen, BROWN, (0, SCREEN_HEIGHT - 40), (SCREEN_WIDTH, SCREEN_HEIGHT - 40), 40)
  414. # Maybe draw a stationary player icon?
  415. temp_player_img = pygame.Surface((30, 40)); temp_player_img.fill(RED)
  416. temp_hat = pygame.Surface((20, 8)); temp_hat.fill(BRIGHT_RED)
  417. temp_player_img.blit(temp_hat, (5, 2))
  418. screen.blit(temp_player_img, (SCREEN_WIDTH // 2 - 15, SCREEN_HEIGHT - 40 - 40)) # Place on ground
  419.  
  420.  
  421. pygame.display.flip()
  422. clock.tick(FPS) # Keep ticking the clock
  423.  
  424. # Event handling for title screen
  425. for event in pygame.event.get():
  426. if event.type == pygame.QUIT:
  427. pygame.quit() # Ensure pygame quits properly
  428. sys.exit() # Exit the program entirely
  429. if event.type == pygame.KEYDOWN:
  430. if event.key == start_key:
  431. waiting = False # Stop waiting, start the game
  432. return True # Signal to start game
  433. if event.key == pygame.K_ESCAPE:
  434. waiting = False # Stop waiting
  435. return False # Signal to quit game
  436. return False # Should technically not be reached, but safety default
  437.  
  438.  
  439. # --- Main Game Function ---
  440. def game_loop():
  441. pygame.init()
  442. try: pygame.font.init()
  443. except Exception as e: print(f"Font Error: {e}")
  444. screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
  445. pygame.display.set_caption("Python Pseudo-Mario") # Reset caption
  446. clock = pygame.time.Clock()
  447.  
  448. # --- Show Title Screen ---
  449. start_game = show_title_screen(screen, clock)
  450. if not start_game:
  451. pygame.quit()
  452. sys.exit()
  453. # --- End Title Screen Logic ---
  454.  
  455.  
  456. # --- Create Game Objects (Only if starting game) ---
  457. player = Player()
  458. platforms, enemies, coins, goal_flag_group, background_decorations, level_width = setup_level()
  459. player_group = pygame.sprite.GroupSingle(player)
  460. camera = Camera(level_width)
  461.  
  462. running = True; game_over = False; level_complete = False
  463.  
  464. # --- Main Game Loop ---
  465. while running:
  466. # --- Event Handling ---
  467. for event in pygame.event.get():
  468. if event.type == pygame.QUIT: running = False
  469. if event.type == pygame.KEYDOWN:
  470. if event.key == pygame.K_ESCAPE: running = False
  471. if not game_over and not level_complete:
  472. if event.key == pygame.K_UP or event.key == pygame.K_SPACE or event.key == pygame.K_w: player.jump()
  473. if event.key == pygame.K_r and (game_over or level_complete):
  474. # Clean Restart
  475. player = Player()
  476. platforms, enemies, coins, goal_flag_group, background_decorations, level_width = setup_level()
  477. player_group.add(player)
  478. camera = Camera(level_width)
  479. game_over = False; level_complete = False
  480.  
  481. # --- Updates ---
  482. if not game_over and not level_complete:
  483. player_group.update(platforms)
  484. enemies.update(platforms)
  485. background_decorations.update()
  486. camera.update(player)
  487. # Interactions
  488. player.check_coin_collisions(coins)
  489. if player.check_enemy_collisions(enemies): game_over = True
  490. if goal_flag_group.sprite and player.check_goal_collision(goal_flag_group.sprite): level_complete = True
  491. # Fall Death
  492. if player.rect.top > SCREEN_HEIGHT + 200: game_over = True; print("Fell!")
  493.  
  494. # --- Drawing ---
  495. screen.fill(BLUE)
  496. camera_offset_x = camera.get_offset_x()
  497. # Layers
  498. for sprite in background_decorations: sprite.draw(screen, camera_offset_x)
  499. for sprite in platforms: sprite.draw(screen, camera_offset_x)
  500. for sprite in coins: sprite.draw(screen, camera_offset_x)
  501. for sprite in enemies: sprite.draw(screen, camera_offset_x)
  502. if goal_flag_group.sprite: goal_flag_group.sprite.draw(screen, camera_offset_x)
  503. player.draw(screen, camera_offset_x)
  504.  
  505. # --- UI / Messages ---
  506. draw_text(screen, f"Score: {player.score}", 30, SCREEN_WIDTH / 2, 10, BLACK)
  507. if level_complete:
  508. overlay = pygame.Surface((SCREEN_WIDTH, SCREEN_HEIGHT), pygame.SRCALPHA); overlay.fill((50, 50, 50, 180)); screen.blit(overlay, (0,0))
  509. draw_text(screen, "LEVEL COMPLETE!", 72, SCREEN_WIDTH / 2, SCREEN_HEIGHT/3, YELLOW)
  510. draw_text(screen, f"Final Score: {player.score}", 40, SCREEN_WIDTH / 2, SCREEN_HEIGHT/2, WHITE)
  511. draw_text(screen, "Press 'R' to Restart or ESC", 30, SCREEN_WIDTH / 2, SCREEN_HEIGHT*2/3, WHITE)
  512. elif game_over:
  513. overlay = pygame.Surface((SCREEN_WIDTH, SCREEN_HEIGHT), pygame.SRCALPHA); overlay.fill((50, 50, 50, 180)); screen.blit(overlay, (0,0))
  514. draw_text(screen, "GAME OVER", 72, SCREEN_WIDTH/2, SCREEN_HEIGHT/3, BRIGHT_RED)
  515. draw_text(screen, f"Final Score: {player.score}", 40, SCREEN_WIDTH/2, SCREEN_HEIGHT/2, WHITE)
  516. draw_text(screen, "Press 'R' to Restart or ESC", 30, SCREEN_WIDTH/2, SCREEN_HEIGHT*2/3, WHITE)
  517.  
  518. # --- Display Update ---
  519. pygame.display.flip()
  520. clock.tick(FPS)
  521.  
  522. pygame.quit()
  523. sys.exit()
  524.  
  525. # --- Start ---
  526. if __name__ == '__main__':
  527. game_loop()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement