前言
一 、 代码:5个py文件
1 config.py :存放常量
2.button.py::按钮
3 classimage.py:图片导入
4 classCollidCricle.py:检测圆形碰撞
5 game.py:游戏运行的主程序
二、所需要的素材如下
1 img文件夹: 图片
2 audio文件夹:音乐 音效
三、字体、地图
1 font.ttf:字体
2 地图:1.csv 2.csv 3.csv
四、地图编辑器
代码
1 config.py
# window
WINDOW_WIDTH = 800
WINDOW_HEIGHT = int(WINDOW_WIDTH * 0.8)
ROWS = 16
COLUMNS = 150
TILE_SIZE = WINDOW_HEIGHT // ROWS
world_data = []
for world_row in range(ROWS):
world_r = [-1] * COLUMNS
world_data.append(world_r)
screen_scroll = 0
bg_scroll = 0
move_left = False
move_right = False
shoot = False
grenade = False
grenade_throw = False
GRAVITY = 0.65
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
PINK = (235, 65, 54)
BG = (144, 201, 120)
2 button.py
import pygame
class Button(pygame.sprite.Sprite):
def __init__(self, image, x, y, scale, surface):
super().__init__()
self.surface = surface
self.image = image
width = self.image.get_width()
height = self.image.get_height()
self.image = pygame.transform.scale(self.image, (int(width * scale), int(height * scale)))
self.rect = self.image.get_rect()
self. rect.center = (x, y)
self.clicked = False
def draw(self):
action = False
pos = pygame.mouse.get_pos()
if self.rect.collidepoint(pos):
if pygame.mouse.get_pressed()[0] == 1 and not self.clicked:
action = True
self.clicked = True
if pygame.mouse.get_pressed()[0] == 0:
self.clicked = False
self.surface.blit(self.image, self.rect)
return action
3 classimage.py
import pygame
from config import *
class Image:
def __init__(self, path, name, scale):
self.image_lst = []
self.path = path
self.scale = scale
self.name = name
self.image = None
def picture(self):
self.image = pygame.image.load(f'{self.path}/{self.name}').convert_alpha()
width = self.image.get_width()
height = self.image.get_height()
self.image = pygame.transform.scale(self.image, (int(width * self.scale), int(height * self.scale)))
return self.image
def pictures(self):
for a in range(self.name):
self.image = pygame.image.load(f'{self.path}/{a}.png').convert_alpha()
self.image = pygame.transform.scale(self.image, (TILE_SIZE * self.scale, TILE_SIZE * self.scale))
self.image_lst.append(self.image)
return self.image_lst
4 classCollidCircle.py
import pygame
import math
class CollideCircle:
def __init__(self, center1, center2, radius1, radius2):
super().__init__()
self.center1 = center1
self.center2 = center2
self.radius1 = radius1
self.radius2 = radius2
def update(self):
action = False
if int(math.sqrt((self.center1[0] - self.center2[0]) ** 2 + (self.center1[1] - self.center2[1]) ** 2)) < self.radius1 + self.radius2:
action = True
return action
5 game.py
import random
import pygame
from button import Button
from config import *
from classimage import Image
import csv
from classCollidCircle import CollideCircle
pygame.mixer.init()
pygame.mixer.music.load('audio/music2.mp3')
pygame.mixer.music.set_volume(0.5)
pygame.mixer.music.play(-1, 1, 5000)
shot_sound = pygame.mixer.Sound('audio/shot.wav')
shot_sound.set_volume(0.8)
jump_sound = pygame.mixer.Sound('audio/jump.wav')
jump_sound.set_volume(0.8)
grenade_sound = pygame.mixer.Sound('audio/grenade.wav')
grenade_sound.set_volume(0.8)
pygame.init()
screen = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))
pygame.display.set_caption('Shot-Game')
clock = pygame.time.Clock()
FPS = 60
pygame.key.stop_text_input()
# 背景图片
sky = Image('img/background', 'sky_cloud.png', 1).picture()
mountain = Image('img/background', 'mountain.png', 1).picture()
pine1 = Image('img/background', 'pine1.png', 1).picture()
pine2 = Image('img/background', 'pine2.png', 1).picture()
# 砖块
tile_lst = Image('img/tile', 21, 1).pictures()
# 宝箱
item_box = {
'ammo': Image('img/icons', 'ammo_box.png', 1).picture(),
'health': Image('img/icons', 'health_box.png', 1).picture(),
'grenade': Image('img/icons', 'grenade_box.png', 1).picture()
}
level = 1
with open(f'{level}.csv', mode='r', encoding='utf-8') as csvfile:
csv_reader = csv.reader(csvfile)
for x_csv, row_csv in enumerate(csv_reader):
for y_csv, tile_csv in enumerate(row_csv):
world_data[x_csv][y_csv] = int(tile_csv)
# 子弹
bullet_image = Image('img/icons', 'bullet.png', 1).picture()
def draw_background():
width = sky.get_width()
for a in range(5):
screen.blit(sky, (a * width + bg_scroll * 0.5, 0))
screen.blit(mountain, (a * width + bg_scroll * 0.6, 100))
screen.blit(pine1, (a * width + bg_scroll * 0.7, 200))
screen.blit(pine2, (a * width + bg_scroll * 0.8, WINDOW_HEIGHT - pine2.get_height()))
class World:
def __init__(self):
self.obstacle_lst = []
self.level_length = 0
def process_data(self, data):
self.level_length = len(data[0])
for y_world, row_world in enumerate(world_data):
for x_world, tile_world in enumerate(row_world):
if tile_world >= 0:
img = tile_lst[tile_world]
img_rect = img.get_rect()
img_rect.x = x_world * TILE_SIZE
img_rect.y = y_world * TILE_SIZE
tile_data = (img, img_rect)
if 0 <= tile_world <= 8:
self.obstacle_lst.append(tile_data)
elif 9 <= tile_world <= 10:
water = Water(img, x_world * TILE_SIZE, y_world * TILE_SIZE)
water_group.add(water)
elif 11 <= tile_world <= 14:
decoration = Decoration(img, x_world * TILE_SIZE, y_world * TILE_SIZE)
decoration_group.add(decoration)
elif tile_world == 15:
player0 = Soldier('player', x_world * TILE_SIZE, y_world * TILE_SIZE, 1.5, 5, 20, 5)
health_bar = HealthBar(10, 10, player0.health, player0.health)
elif tile_world == 16:
enemy = Soldier('enemy', x_world * TILE_SIZE, y_world * TILE_SIZE, 1.5, 2, 20, 0)
enemy_group.add(enemy)
elif tile_world == 17:
ammo = ItemBox('ammo', x_world * TILE_SIZE, y_world * TILE_SIZE)
item_box_group.add(ammo)
elif tile_world == 18:
grenade = ItemBox('grenade', x_world * TILE_SIZE, y_world * TILE_SIZE)
item_box_group.add(grenade)
elif tile_world == 19:
health = ItemBox('health', x_world * TILE_SIZE, y_world * TILE_SIZE)
item_box_group.add(health)
elif tile_world == 20:
level_map = LevelMap(img, x_world * TILE_SIZE, y_world * TILE_SIZE)
level_group.add(level_map)
return player0, health_bar
def draw(self):
for tile in self.obstacle_lst:
tile[1][0] += screen_scroll
screen.blit(tile[0], tile[1])
class Soldier(pygame.sprite.Sprite):
def __init__(self, char_type, x, y, scale, speed, ammo, grenades):
super().__init__()
self.alive = True
self.char_type = char_type
self.speed = speed
self.scale = scale
self.ammo = ammo
self.start_ammo = ammo
self.grenades = grenades
self.start_grenades = grenades
self.health = 100
self.max_health = 100
self.direction = 1
self.action = 0
self.path = f'img/{self.char_type}'
self.frame_index = 0
self.animation_lst = [
Image(self.path + '/Idle', 5, self.scale).pictures(),
Image(self.path + '/Run', 6, self.scale).pictures(),
Image(self.path + '/Jump', 1, self.scale).pictures(),
Image(self.path + '/Death', 8, self.scale).pictures()
]
self.image = self.animation_lst[self.action][self.frame_index]
self.flip = False
self.rect = self.image.get_rect()
self.rect.center = (x, y)
self.width = self.rect.width
self.height = self.rect.height
self.update_time = pygame.time.get_ticks()
self.velocity_y = 0
self.jump = False
self.in_air = True
self.move_counter = 0
self.version = pygame.Rect(0, 0, 150, 20)
self.idling = False
self.idle_count = 0
self.shoot_cooldown = 0
self.radius = self.rect.width // 2
self.score = 0
def update(self):
self.update_animation()
self.check_alive()
if self.shoot_cooldown > 0:
self.shoot_cooldown -= 1
def move(self, move_left, move_right):
screen_scroll = 0
dx = 0
dy = 0
if move_left:
dx = -self.speed
self.flip = True
self.direction = -1
if move_right:
dx = self.speed
self.flip = False
self.direction = 1
if self.jump and not self.in_air:
self.velocity_y = -11
self.jump = False
self.in_air = True
self.velocity_y += GRAVITY
dy += self.velocity_y
water_hit = pygame.sprite.spritecollide(self, water_group, False)
if water_hit:
self_mask = pygame.mask.from_surface(self.image)
water_hit_mask = pygame.mask.from_surface(water_hit[0].image)
if self_mask.overlap(water_hit_mask, (water_hit[0].rect.x - self.rect.x, water_hit[0].rect.y -self.rect.y)):
self.health = 0
dy = 0
for tile in world.obstacle_lst:
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.velocity_y < 0:
self.velocity_y = 0
dy = tile[1].bottom - self.rect.top
else:
self.velocity_y = 0
dy = tile[1].top - self.rect.bottom
self.in_air = False
self.rect.x += dx
self.rect.y += dy
if self.char_type == 'player':
if self.rect.left < 0:
self.rect.left = 0
elif self.rect.right > WINDOW_WIDTH:
self.rect.right = WINDOW_WIDTH
if self.rect.bottom > WINDOW_HEIGHT:
self.health = 0
self.rect.bottom = WINDOW_HEIGHT
if self.char_type == 'player':
if (self.rect.right > WINDOW_WIDTH - 200 and bg_scroll > -world.level_length * TILE_SIZE + WINDOW_WIDTH) \
or (self.rect.left < 200 and bg_scroll < 0):
self.rect.x -= dx
screen_scroll = -dx
level_complete = False
if pygame.sprite.spritecollide(player, level_group, False):
level_complete = True
return screen_scroll, level_complete
def update_animation(self):
ANIMATION_COOLDOWN = 100
self.image = self.animation_lst[self.action][self.frame_index]
if pygame.time.get_ticks() - self.update_time > ANIMATION_COOLDOWN:
self.update_time = pygame.time.get_ticks()
self.frame_index += 1
if self.frame_index >= len(self.animation_lst[self.action]):
if self.action == 3:
self.frame_index = len(self.animation_lst[self.action]) - 1
else:
self.frame_index = 0
def update_action(self, new_action):
if new_action != self.action:
self.action = new_action
self.frame_index = 0
self.update_time = pygame.time.get_ticks()
def shot(self):
if self.ammo > 0:
if self.char_type == 'player':
if self.shoot_cooldown == 0:
self.shoot_cooldown = 20
bullet = Bullet(self.rect.centerx + self.direction * (self.rect.size[0] * 0.75), self.rect.centery - 5, self.direction)
player_bullet_group.add(bullet)
shot_sound.play()
self.ammo -= 1
elif self.char_type == 'enemy':
if self.shoot_cooldown == 0:
self.shoot_cooldown = 20
bullet = Bullet(self.rect.centerx + self.direction * (self.rect.size[0] * 0.75), self.rect.centery - 5, self.direction)
enemy_bullet_group.add(bullet)
shot_sound.play()
self.ammo -= 1
def check_alive(self):
if self.health <= 0:
self.health = 0
self.speed = 0
self.alive = False
self.update_action(3)
if self.char_type == 'enemy':
if self.frame_index == len(self.animation_lst[3]) - 1:
self.kill()
player.score += 10
def ai(self):
if self.alive and player.alive:
if not self.idling and random.randint(1, 200) == 1:
self.update_action(0)
self.idle_count = 50
self.idling = True
if self.version.colliderect(player.rect):
self.update_action(0)
if self.rect.x < player.rect.x:
self.flip = False
self.direction = 1
else:
self.flip = True
self.direction = -1
self.shot()
else:
if not self.idling:
if self.direction == 1:
ai_move_right = True
else:
ai_move_right = False
ai_move_left = not ai_move_right
self.move(ai_move_left, ai_move_right)
self.update_action(1)
self.move_counter += 1
if self.move_counter > TILE_SIZE:
self.direction *= -1
self.move_counter *= -1
else:
self.idle_count -= 1
if self.idle_count <= 0:
self.idling = False
if self.direction == 1:
self.version.x = self.rect.right
else:
self.version.x = self.rect.left - self.version.width
self.version.y = self.rect.centery
self.rect.x += screen_scroll
def draw(self):
img = self.image
image = pygame.transform.flip(img, self.flip, False)
screen.blit(image, self.rect)
# pygame.draw.circle(screen, RED, self.rect.center, self.radius, 2)
class Water(pygame.sprite.Sprite):
def __init__(self, image, x, y):
super().__init__()
self.image = image
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
def update(self):
self.rect.x += screen_scroll
class Decoration(pygame.sprite.Sprite):
def __init__(self, image, x, y):
super().__init__()
self.image = image
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
def update(self):
self.rect.x += screen_scroll
class ItemBox(pygame.sprite.Sprite):
def __init__(self, char_type, x, y):
super().__init__()
self.char_type = char_type
self.image = item_box[self.char_type]
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
def update(self):
self.rect.x += screen_scroll
# if pygame.sprite.collide_rect(self, player): # 两个精灵是否发生了碰撞 if self.rect.colliderect(player.rect):
if self.rect.colliderect(player.rect):
if self.char_type == 'health':
player.health += 25
if player.health >= 100:
player.health = 100
elif self.char_type == 'ammo':
player.ammo += 10
elif self.char_type == 'grenade':
player.grenades += 5
self.kill()
class Bullet(pygame.sprite.Sprite):
def __init__(self, x, y, direction):
super().__init__()
self.image = bullet_image
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.direction = direction
self.bullet_speed = 10
def update(self):
self.rect.x += self.direction * self.bullet_speed
if self.rect.left < 0:
self.kill()
elif self.rect.right > WINDOW_WIDTH:
self.kill()
for tile in world.obstacle_lst:
if self.rect.colliderect(tile[1]):
self.kill()
if pygame.sprite.spritecollide(player, enemy_bullet_group, False):
player.health -= 5
self.kill()
for enemy0 in enemy_group:
if pygame.sprite.spritecollide(enemy0, player_bullet_group, False):
enemy0.health -= 25
self.kill()
class HealthBar:
def __init__(self, x, y, player_health, max_health):
self.x = x
self.y = y
self.health = player_health
self.max_health = max_health
def draw(self, health_player):
self.health = health_player
ratio = self.health / self.max_health
pygame.draw.rect(screen, BLACK, (self.x - 2, self.y - 2, 154, 24))
pygame.draw.rect(screen, RED, (self.x, self.y, 150, 20))
pygame.draw.rect(screen, GREEN, (self.x, self.y, 150 * ratio, 20))
class LevelMap(pygame.sprite.Sprite):
def __init__(self, img, x, y):
super().__init__()
self.image = img
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
def update(self):
self.rect.x += screen_scroll
class ScreenFade:
def __init__(self, direction, color, speed):
self.direction = direction
self.color = color
self.speed = speed
self.fade_counter = 0
def fade(self):
fade_complete = False
self.fade_counter += self.speed
if self.direction == 1:
pygame.draw.rect(screen, self.color, (0 - self.fade_counter, 0, WINDOW_WIDTH // 2, WINDOW_HEIGHT))
pygame.draw.rect(screen, self.color, (WINDOW_WIDTH // 2 + self.fade_counter, 0, WINDOW_WIDTH // 2, WINDOW_HEIGHT))
pygame.draw.rect(screen, self.color,
(0, 0 - self.fade_counter, WINDOW_WIDTH, WINDOW_HEIGHT // 2))
pygame.draw.rect(screen, self.color,
(0, WINDOW_HEIGHT // 2 + self.fade_counter, WINDOW_WIDTH, WINDOW_HEIGHT // 2))
elif self.direction == 2:
pygame.draw.rect(screen, self.color, (0, 0, WINDOW_WIDTH, 0 + self.fade_counter))
elif self.direction == 3:
pygame.draw.rect(screen, self.color, (0, 0, WINDOW_WIDTH, 0 + self.fade_counter))
if self.fade_counter >= WINDOW_HEIGHT:
fade_complete = True
self.fade_counter = WINDOW_HEIGHT
return fade_complete
intro_fade = ScreenFade(1, BLACK, 4)
death_fade = ScreenFade(2, PINK, 4)
complete_fade = ScreenFade(3, BG, 4)
start_image = Image('img', 'start_btn.png', 1).picture()
start_button = Button(start_image, WINDOW_WIDTH // 2, WINDOW_HEIGHT // 4, 1, screen)
restart_image = Image('img', 'restart_btn.png', 3).picture()
restart_button = Button(restart_image, WINDOW_WIDTH // 2, WINDOW_HEIGHT // 4, 1, screen)
exit_image = Image('img', 'exit_btn.png', 1).picture()
exit_button = Button(exit_image, WINDOW_WIDTH // 2, WINDOW_HEIGHT * 3 // 4, 1, screen)
font = pygame.font.Font('font.ttf', 50)
yes_img = font.render('YES', 1, RED)
yes_button = Button(yes_img, WINDOW_WIDTH // 4, 500, 1, screen)
no_img = font.render('NO', 1, RED)
no_button = Button(no_img, WINDOW_WIDTH * 3 // 4, 500, 1, screen)
grenade_image = Image('img/icons', 'grenade.png', 1).picture()
class Grenade(pygame.sprite.Sprite):
def __init__(self, x_g, y_g, direction):
super().__init__()
self.timer = 100
self.velocity_y = -11
self.speed = 7
self.image = grenade_image
self.rect = self.image.get_rect()
self.rect.center = (x_g, y_g)
self.width = self.rect.width
self.height = self.rect.height
self.direction = direction
def update(self):
self.velocity_y += GRAVITY
dx = self.direction * self.speed
dy = self.velocity_y
for tile in world.obstacle_lst:
if tile[1].colliderect(self.rect.x + dx, self.rect.y, self.width, self.height):
self.direction *= -1
dx = self.direction * self.speed
if tile[1].colliderect(self.rect.x, self.rect.y + dy, self.width, self.height):
if self.velocity_y < 0:
self.velocity_y = 0
dy = tile[1].bottom - self.rect.top
elif self.velocity_y >= 0:
self.speed = 0
self.velocity_y = 0
dy = tile[1].top - self.rect.bottom
self.rect.x += dx + screen_scroll
self.rect.y += dy
self.timer -= 1
if self.timer <= 0:
self.kill()
grenade_sound.play()
explosion = Explosion(self.rect.centerx, self.rect.centery)
explosion_group.add(explosion)
explosion_lst = Image('img/explosion', 5, 1).pictures()
class Explosion(pygame.sprite.Sprite):
def __init__(self, x, y):
super().__init__()
self.frame_index = 0
self.image = explosion_lst[self.frame_index]
self.rect = self.image.get_rect()
self.rect.center = (x, y)
self.counter = 0
self.radius = player.radius * 3
def update(self):
self.rect.x += screen_scroll
# pygame.draw.circle(screen, RED, self.rect.center, self.radius, 2)
self.counter += 1
if self.counter >= 4:
self.counter = 0
self.frame_index += 1
if CollideCircle(player.rect.center, self.rect.center, player.radius, self.radius).update() and self.frame_index == 2:
player.health -= 50
for enemy0 in enemy_group:
if CollideCircle(enemy0.rect.center, self.rect.center, enemy0.radius,
self.radius).update() and self.frame_index == 2:
enemy0.health -= 50
if self.frame_index >= len(explosion_lst):
self.kill()
else:
self.image = explosion_lst[self.frame_index]
def draw_icon(img, x, y, n):
for i in range(n):
screen.blit(img, (x + i * 15, y))
def reset_level():
water_group.empty()
decoration_group.empty()
player_bullet_group.empty()
enemy_bullet_group.empty()
item_box_group.empty()
enemy_group.empty()
level_group.empty()
data = []
for row in range(ROWS):
row_lst = [-1] * COLUMNS
data.append(row_lst)
return data
def draw_text(x_t, y_t, text, size, color):
font = pygame.font.Font('font.ttf', size)
text_render = font.render(text, 1, color)
rect = text_render.get_rect()
rect.center = (x_t, y_t)
screen.blit(text_render, rect)
# 群组
water_group = pygame.sprite.Group()
decoration_group = pygame.sprite.Group()
player_bullet_group = pygame.sprite.Group()
enemy_bullet_group = pygame.sprite.Group()
enemy_group = pygame.sprite.Group()
item_box_group = pygame.sprite.Group()
level_group = pygame.sprite.Group()
grenade_group = pygame.sprite.Group()
explosion_group = pygame.sprite.Group()
# 实例化
world = World()
player, health = world.process_data(world_data)
start_game = False
start_intro = False
complete_game = False
run = True
old_score = 0
while run:
clock.tick(FPS)
if not start_game and not complete_game:
screen.fill(BG)
if start_button.draw():
start_game = True
start_intro = True
if exit_button.draw():
run = False
elif start_game and not complete_game:
draw_background()
world.draw()
draw_text(WINDOW_WIDTH // 2, 20, f'SCORE = {old_score + player.score}', 30, RED)
player.update()
player.draw()
health.draw(player.health)
draw_icon(bullet_image, 10, 35, player.ammo)
draw_icon(grenade_image, 10, 60, player.grenades)
water_group.update()
decoration_group.update()
player_bullet_group.update()
enemy_bullet_group.update()
item_box_group.update()
level_group.update()
grenade_group.update()
explosion_group.update()
water_group.draw(screen)
decoration_group.draw(screen)
player_bullet_group.draw(screen)
enemy_bullet_group.draw(screen)
item_box_group.draw(screen)
level_group.draw(screen)
grenade_group.draw(screen)
explosion_group.draw(screen)
for enemy in enemy_group:
enemy.ai()
enemy.update()
enemy.draw()
if enemy.health > 0:
ratio = enemy.health / enemy.max_health
pygame.draw.rect(screen, BLACK, (enemy.rect.x, enemy.rect.y - 10, enemy.rect.width, 10))
pygame.draw.rect(screen, RED, (enemy.rect.x + 2, enemy.rect.y - 8, enemy.rect.width - 4, 6))
pygame.draw.rect(screen, GREEN, (enemy.rect.x + 2, enemy.rect.y - 8, (enemy.rect.width - 4) * ratio, 6))
if start_intro:
if intro_fade.fade():
start_intro = False
intro_fade.fade_counter = 0
if player.alive:
if shoot:
player.shot()
elif grenade and not grenade_throw and player.grenades > 0:
grenade = Grenade(player.rect.centerx + player.direction * player.width * 0.75, player.rect.top + 10, player.direction)
grenade_group.add(grenade)
grenade_throw = True
player.grenades -= 1
if player.in_air:
player.update_action(2)
elif move_left or move_right:
player.update_action(1)
else:
player.update_action(0)
screen_scroll, level_complete = player.move(move_left, move_right)
bg_scroll += screen_scroll
if level_complete:
start_intro = True
level += 1
bg_scroll = 0
world_data = reset_level()
old_score += player.score
if level <= 3:
with open(f'{level}.csv', mode='r', encoding='utf-8') as csv_file:
csv_reader = csv.reader(csv_file)
for x, row in enumerate(csv_reader):
for y, tile in enumerate(row):
world_data[x][y] = int(tile)
world = World()
player, health = world.process_data(world_data)
else:
complete_game = True
start_game = False
else:
screen_scroll = 0
if death_fade.fade():
death_fade.fade_counter = WINDOW_HEIGHT
if restart_button.draw():
death_fade.fade_counter = 0
start_intro = True
bg_scroll = 0
world_data = reset_level()
with open(f'{level}.csv', mode='r', encoding='utf-8') as csv_file:
csv_reader = csv.reader(csv_file)
for x, row in enumerate(csv_reader):
for y, tile in enumerate(row):
world_data[x][y] = int(tile)
world = World()
player, health = world.process_data(world_data)
elif exit_button.draw():
run = False
else:
if complete_fade.fade():
complete_fade.fade_counter = WINDOW_HEIGHT
draw_text(WINDOW_WIDTH // 2, 100, f'SCORE = {old_score + player.score}', 50, RED)
draw_text(WINDOW_WIDTH // 2, 200, 'CONGRATULATION', 50, RED)
draw_text(WINDOW_WIDTH // 2, 300, 'YOU WIN', 50, RED)
draw_text(WINDOW_WIDTH // 2, 400, 'DO YOU WANT TO PLAY GAME AGAIN ?', 30, RED)
if yes_button.draw():
player.score = 0
start_game = False
complete_game = False
world_data = reset_level()
level = 1
bg_scroll = 0
with open(f'{level}.csv', mode='r', encoding='utf-8') as csv_file:
csv_reader = csv.reader(csv_file)
for x, row in enumerate(csv_reader):
for y, tile in enumerate(row):
world_data[x][y] = int(tile)
world = World()
player, health = world.process_data(world_data)
elif no_button.draw():
run = False
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
move_left = True
if event.key == pygame.K_RIGHT:
move_right = True
if event.key == pygame.K_UP:
player.jump = True
jump_sound.play()
if event.key == pygame.K_SPACE:
shoot = True
if event.key == pygame.K_g:
grenade = True
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
move_left = False
if event.key == pygame.K_RIGHT:
move_right = False
if event.key == pygame.K_SPACE:
shoot = False
if event.key == pygame.K_g:
grenade = False
grenade_throw = False
pygame.display.flip()
pygame.quit()
素材
1 img文件夹
1 3个图片文件 5个文件夹
2 audio文件夹
字体 地图
地图编辑器
1 需要button.py
2 需要img文件夹下的tile文件夹
import os
import pygame
import csv
from button import Button
# screen_size
WINDOW_WIDTH = 800
WINDOW_HEIGHT = int(WINDOW_WIDTH * 0.8)
WINDOW_RIGHT = 300
WINDOW_BOTTOM = 100
# colors
GRAY = (194, 194, 194)
GREEN = (144, 201, 120)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
BLACK = (0, 0, 0)
pygame.init()
screen = pygame.display.set_mode((WINDOW_WIDTH + WINDOW_RIGHT, WINDOW_HEIGHT + WINDOW_BOTTOM))
pygame.display.set_caption('Map')
clock = pygame.time.Clock()
FPS = 60
# BACKGROUND
mountain = pygame.image.load('img/background/mountain.png').convert_alpha()
pine1 = pygame.image.load('img/background/pine1.png').convert_alpha()
pine2 = pygame.image.load('img/background/pine2.png').convert_alpha()
sky = pygame.image.load('img/background/sky_cloud.png').convert_alpha()
# grids
ROWS = 16
SIZE = WINDOW_HEIGHT // ROWS
COLUMNS = sky.get_width() * 3 // SIZE
# tile's image
tiles = []
# tile_lst = os.listdir('img/tile')
for tile in range(21):
image = pygame.image.load(f'img/tile/{tile}.png')
image = pygame.transform.scale(image, (SIZE, SIZE))
tiles.append(image)
# buttons
button_tiles = []
r = 0
c = 0
for img in tiles:
button = Button((WINDOW_WIDTH + 75 + 60 * c, 75 + 60 * r), screen, img, 1)
button_tiles.append(button)
c += 1
if c >= 3:
c = 0
r += 1
# draw_world
tile_number = 0
world_data = []
for row in range(ROWS):
lst = [-1] * COLUMNS
world_data.append(lst)
def draw_button():
global tile_number
for num, btn in enumerate(button_tiles):
if btn.draw():
tile_number = num
pygame.draw.rect(screen, RED, button_tiles[tile_number].rect, 3)
def draw_world():
for w_y, world_row in enumerate(world_data):
for w_x, w_tile in enumerate(world_row):
if world_data[w_y][w_x] >= 0:
screen.blit(tiles[w_tile], (w_x * SIZE + roll, w_y * SIZE))
pos = pygame.mouse.get_pos()
x = (pos[0] - roll) // SIZE
y = pos[1] // SIZE
if 0 <= pos[0] < WINDOW_WIDTH and 0 <= pos[1] < WINDOW_HEIGHT:
if pygame.mouse.get_pressed()[0] == 1:
if world_data[y][x] != tile_number:
world_data[y][x] = tile_number
elif pygame.mouse.get_pressed()[2] == 1:
if world_data[y][x] != -1:
world_data[y][x] = -1
roll = 0
roll_right = False
roll_left = False
roll_speed = 5
def draw_background():
screen.fill(GREEN)
for num in range(3):
screen.blit(sky, (num * sky.get_width() + roll, 0))
screen.blit(mountain, (-50 + mountain.get_width() * num + roll, int(WINDOW_HEIGHT * 0.15)))
screen.blit(pine1, (-150 + pine1.get_width() * num + roll, int(WINDOW_HEIGHT * 0.25)))
screen.blit(pine2, (-200 + pine2.get_width() * num + roll, WINDOW_HEIGHT - pine2.get_height()))
pygame.draw.rect(screen, GREEN, (0, WINDOW_HEIGHT, WINDOW_WIDTH, WINDOW_BOTTOM))
pygame.draw.rect(screen, GREEN, (WINDOW_WIDTH, 0, WINDOW_RIGHT, WINDOW_BOTTOM + WINDOW_HEIGHT))
# edit
rect1 = pygame.Rect(100, WINDOW_HEIGHT + 30, 100, 30)
rect2 = pygame.Rect(300, WINDOW_HEIGHT + 30, 100, 30)
rect3 = pygame.Rect(500, WINDOW_HEIGHT + 30, 100, 30)
rect4 = pygame.Rect(700, WINDOW_HEIGHT + 30, 100, 30)
font = pygame.font.SysFont('times', 25)
def draw_edit():
global level
pygame.draw.rect(screen, BLACK, rect1)
draw_text(font, 'Load', WHITE, rect1)
pygame.draw.rect(screen, WHITE, rect1, 3)
pygame.draw.rect(screen, BLACK, rect2)
draw_text(font, 'Save', WHITE, rect2)
pygame.draw.rect(screen, WHITE, rect2, 3)
pygame.draw.rect(screen, BLACK, rect3)
draw_text(font, 'Reset', WHITE, rect3)
pygame.draw.rect(screen, WHITE, rect3, 3)
pygame.draw.rect(screen, BLACK, rect4)
draw_text(font, f'level={level}', WHITE, rect4)
pygame.draw.rect(screen, WHITE, rect4, 3)
def draw_text(fonts, text, color1, rect):
load_text = fonts.render(text, 1, color1)
screen.blit(load_text, (rect.x + 50 - load_text.get_width() // 2, WINDOW_HEIGHT + 30))
def draw_map():
pos = pygame.mouse.get_pos()
if rect1.collidepoint(pos):
if pygame.mouse.get_pressed()[0] == 1:
if os.path.isfile(f'map/{level}.csv'):
pygame.draw.rect(screen, RED, rect1, 3)
with open(f'map/{level}.csv', mode='r', encoding='utf-8') as f:
csv_reader = csv.reader(f)
for x, row in enumerate(csv_reader):
for y, tile in enumerate(row):
world_data[x][y] = int(tile)
if rect2.collidepoint(pos):
if pygame.mouse.get_pressed()[0] == 1:
pygame.draw.rect(screen, RED, rect2, 3)
with open(f'map/{level}.csv', mode='w', encoding='utf-8', newline='') as f:
csv_writer = csv.writer(f)
csv_writer.writerows(world_data)
if rect3.collidepoint(pos):
if pygame.mouse.get_pressed()[0] == 1:
pygame.draw.rect(screen, RED, rect3, 3)
with open(f'map/level.csv', mode='r', encoding='utf-8') as f:
for x in range(ROWS):
for y in range(COLUMNS):
world_data[x][y] = -1
running = True
level = 0
while running:
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
roll_right = True
if event.key == pygame.K_LEFT:
roll_left = True
if event.key == pygame.K_UP:
level += 1
if event.key == pygame.K_DOWN:
level -= 1
if event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT:
roll_right = False
if event.key == pygame.K_LEFT:
roll_left = False
if roll_right and roll > -sky.get_width() * 3 + WINDOW_WIDTH + 205:
roll -= roll_speed
if roll_left and roll < 0:
roll += roll_speed
draw_background()
draw_world()
draw_button()
draw_edit()
draw_map()
pygame.display.flip()
pygame.quit()