import pygame
import sys
import random
# 初始化Pygame
pygame.init()
# 游戏窗口设置
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption("超级马里奥克隆")
# 确保中文正常显示
pygame.font.init()
font = pygame.font.SysFont(['SimHei', 'WenQuanYi Micro Hei', 'Heiti TC'], 36)
# 颜色定义
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
SKY_BLUE = (135, 206, 235)
BROWN = (139, 69, 19)
YELLOW = (255, 255, 0)
# 游戏参数
FPS = 60
GRAVITY = 0.75
SCROLL_THRESH = 200 # 玩家到达这个位置时开始滚动屏幕
# 玩家类
class Player(pygame.sprite.Sprite):
def __init__(self, x, y):
super().__init__()
self.width = 40
self.height = 60
self.image = pygame.Surface((self.width, self.height))
self.image.fill(RED)
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.vel_y = 0
self.speed = 5
self.jump_strength = -16
self.on_ground = False
self.facing_right = True
self.score = 0
self.lives = 3
self.invincible = False
self.invincible_time = 0
def update(self, world):
# 重置变量
self.on_ground = False
dx = 0
dy = 0
# 处理输入
key = pygame.key.get_pressed()
if key[pygame.K_LEFT]:
dx -= self.speed
self.facing_right = False
if key[pygame.K_RIGHT]:
dx += self.speed
self.facing_right = True
if key[pygame.K_SPACE] and self.on_ground:
self.vel_y = self.jump_strength
# 应用重力
self.vel_y += GRAVITY
dy += self.vel_y
# 检查无敌状态
if self.invincible:
self.invincible_time += 1
if self.invincible_time >= 120: # 2秒无敌时间
self.invincible = False
self.invincible_time = 0
# 碰撞检测 - 方块
for tile in world.tile_list:
# 水平碰撞
if tile[1].colliderect(self.rect.x + dx, self.rect.y, self.width, self.height):
dx = 0
# 垂直碰撞
if tile[1].colliderect(self.rect.x, self.rect.y + dy, self.width, self.height):
# 跳跃碰到方块底部
if self.vel_y < 0:
dy = tile[1].bottom - self.rect.top
self.vel_y = 0
# 下落碰到方块顶部
elif self.vel_y >= 0:
dy = tile[1].top - self.rect.bottom
self.vel_y = 0
self.on_ground = True
# 碰撞检测 - 敌人
if not self.invincible:
for enemy in world.enemy_group:
if pygame.sprite.collide_rect(self, enemy):
if self.vel_y > 0: # 从上方踩敌人
self.vel_y = -10 # 给玩家一个小弹跳
enemy.kill()
self.score += 100
else: # 被敌人碰到
self.lives -= 1
self.invincible = True
self.invincible_time = 0
# 碰撞检测 - 金币
for coin in world.coin_group:
if pygame.sprite.collide_rect(self, coin):
coin.kill()
self.score += 50
# 碰撞检测 - 蘑菇
for mushroom in world.mushroom_group:
if pygame.sprite.collide_rect(self, mushroom):
mushroom.kill()
self.score += 200
self.lives += 1 # 增加一条命
# 更新玩家位置
self.rect.x += dx
self.rect.y += dy
# 屏幕滚动
if self.rect.right > SCREEN_WIDTH - SCROLL_THRESH:
scroll = SCREEN_WIDTH - SCROLL_THRESH - self.rect.right
world.move_sprites(scroll)
self.rect.right = SCREEN_WIDTH - SCROLL_THRESH
if self.rect.left < SCROLL_THRESH:
scroll = SCROLL_THRESH - self.rect.left
world.move_sprites(scroll)
self.rect.left = SCROLL_THRESH
# 确保玩家不会掉出屏幕底部
if self.rect.bottom > SCREEN_HEIGHT:
self.lives -= 1
self.rect.y = 0
self.vel_y = 0
def draw(self, screen):
# 无敌状态闪烁效果
if not self.invincible or pygame.time.get_ticks() % 200 < 100:
screen.blit(self.image, self.rect)
# 敌人类
class Enemy(pygame.sprite.Sprite):
def __init__(self, x, y):
super().__init__()
self.width = 40
self.height = 40
self.image = pygame.Surface((self.width, self.height))
self.image.fill(GREEN)
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.speed = 2
def update(self, scroll):
# 移动敌人
self.rect.x += self.speed
# 翻转方向如果碰到障碍物
for tile in world.tile_list:
if tile[1].colliderect(self.rect.x + self.speed, self.rect.y, self.width, self.height):
self.speed *= -1
# 屏幕滚动
self.rect.y += scroll
# 如果敌人离开屏幕,删除它
if self.rect.top > SCREEN_HEIGHT:
self.kill()
# 金币类
class Coin(pygame.sprite.Sprite):
def __init__(self, x, y):
super().__init__()
self.width = 20
self.height = 20
self.image = pygame.Surface((self.width, self.height))
self.image.fill(YELLOW)
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
def update(self, scroll):
# 屏幕滚动
self.rect.y += scroll
# 如果金币离开屏幕,删除它
if self.rect.top > SCREEN_HEIGHT:
self.kill()
# 蘑菇类 (生命道具)
class Mushroom(pygame.sprite.Sprite):
def __init__(self, x, y):
super().__init__()
self.width = 30
self.height = 30
self.image = pygame.Surface((self.width, self.height))
self.image.fill(RED)
pygame.draw.rect(self.image, WHITE, (5, 5, 20, 20), 2) # 白色边框
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.speed = 1
def update(self, scroll):
# 移动蘑菇
self.rect.x += self.speed
# 翻转方向如果碰到障碍物
for tile in world.tile_list:
if tile[1].colliderect(self.rect.x + self.speed, self.rect.y, self.width, self.height):
self.speed *= -1
# 屏幕滚动
self.rect.y += scroll
# 如果蘑菇离开屏幕,删除它
if self.rect.top > SCREEN_HEIGHT:
self.kill()
# 世界类
class World:
def __init__(self, data):
self.tile_list = []
self.enemy_group = pygame.sprite.Group()
self.coin_group = pygame.sprite.Group()
self.mushroom_group = pygame.sprite.Group()
self.scroll_amount = 0
# 加载图块
self.grass_img = pygame.Surface((50, 50))
self.grass_img.fill(GREEN)
self.dirt_img = pygame.Surface((50, 50))
self.dirt_img.fill(BROWN)
# 生成世界
self.process_data(data)
def process_data(self, data):
for y, row in enumerate(data):
for x, tile in enumerate(row):
if tile == 1: # 草块
img = self.grass_img
rect = img.get_rect()
rect.x = x * 50
rect.y = y * 50
self.tile_list.append((img, rect))
if tile == 2: # 土块
img = self.dirt_img
rect = img.get_rect()
rect.x = x * 50
rect.y = y * 50
self.tile_list.append((img, rect))
if tile == 3: # 敌人
enemy = Enemy(x * 50, y * 50)
self.enemy_group.add(enemy)
if tile == 4: # 金币
coin = Coin(x * 50 + 15, y * 50 + 15)
self.coin_group.add(coin)
if tile == 5: # 蘑菇
mushroom = Mushroom(x * 50, y * 50)
self.mushroom_group.add(mushroom)
def move_sprites(self, scroll):
self.scroll_amount += scroll
# 更新所有图块的位置
for tile in self.tile_list:
tile[1].y += scroll
def draw(self, screen):
for tile in self.tile_list:
screen.blit(tile[0], tile[1])
self.enemy_group.draw(screen)
self.coin_group.draw(screen)
self.mushroom_group.draw(screen)
def update(self):
self.enemy_group.update(self.scroll_amount)
self.coin_group.update(self.scroll_amount)
self.mushroom_group.update(self.scroll_amount)
self.scroll_amount = 0 # 重置滚动量,避免累积
# 游戏地图数据
# 1 = 草块, 2 = 土块, 3 = 敌人, 4 = 金币, 5 = 蘑菇
world_data = [
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 1],
[1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 2, 2, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 5, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 7, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 7, 0, 0, 0, 0, 1],
[1, 0, 4, 0, 0, 7, 0, 7, 0, 0, 0, 2, 0, 0, 2, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]
]
# 创建游戏世界
world = World(world_data)
# 创建玩家
player = Player(100, SCREEN_HEIGHT - 100)
# 创建时钟控制帧率
clock = pygame.time.Clock()
# 游戏主循环
running = True
game_over = False
while running:
clock.tick(FPS)
# 填充背景色
screen.fill(SKY_BLUE)
# 事件处理
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if not game_over:
# 更新玩家
player.update(world)
# 更新世界
world.update()
# 绘制世界
world.draw(screen)
# 绘制玩家
player.draw(screen)
# 显示分数和生命值
score_text = font.render(f"分数: {player.score}", True, WHITE)
screen.blit(score_text, (10, 10))
lives_text = font.render(f"生命: {player.lives}", True, WHITE)
screen.blit(lives_text, (10, 50))
# 检查游戏是否结束
if player.lives <= 0:
game_over = True
else:
# 显示游戏结束画面
game_over_text = font.render("游戏结束!按 R 键重新开始", True, WHITE)
screen.blit(game_over_text, (SCREEN_WIDTH // 2 - game_over_text.get_width() // 2, SCREEN_HEIGHT // 2 - 50))
# 重新开始游戏
key = pygame.key.get_pressed()
if key[pygame.K_r]:
# 重置游戏状态
player = Player(100, SCREEN_HEIGHT - 100)
world = World(world_data)
game_over = False
# 更新显示
pygame.display.flip()
# 退出游戏
pygame.quit()
sys.exit()