python用pygame制作横屏过关的射击小游戏

前言

一 、 代码: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()


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值