试图用kill()删除sprite,但是sprite并没有消失

时间:2018-05-23 20:45:59

标签: python pygame sprite

这是我第一次问这里,很抱歉,如果我不好问。

最近我一直试图制作一个Terraria型游戏,你可以在随机生成的景观中打破/放置块。在尝试实现破解机制(通过单击块触发)时,我遇到了一个问题。块不再变得坚固(这是一件好事),但块的图像仍然存在,我可以直接穿过它。

一个直观的例子: Before breaking block vs. After breaking block

这是代码

主文件(希望只有相关位):

# Imports
import pygame as pg
import json
import sys
import random
import os
from settings import *
from world_handler import *

# Initialize pygame
pg.mixer.pre_init()
pg.init()

# Fonts
# NOTE: put fonts in here

# Helper functions
def load_image(file_path):
    # Loads an image
    img = pg.image.load(file_path)
    return img

def play_sound(sound, loops=0, maxtime=0, fade_ms=0):
    # Plays some audio
    if sound_on:
        sound.play(loops, maxtime, fade_ms)

def play_music():
    # Plays background music
    if sound_on:
        pg.mixer.music.play(-1)

# File paths
current_path = os.path.dirname(__file__)
assets_path = os.path.join(current_path, "assets")
image_path = os.path.join(assets_path, "img")

# Images
player_standing = load_image((os.path.join(image_path, "player", "standing", "player-standing.png")))
player_walking1 = load_image((os.path.join(image_path, "player", "walking", "player-walking1.png")))
player_walking2 = load_image((os.path.join(image_path, "player", "walking", "player-walking2.png")))
player_walking3 = load_image((os.path.join(image_path, "player", "walking", "player-walking3.png")))
player_walking4 = load_image((os.path.join(image_path, "player", "walking", "player-walking4.png")))
player_jumping = load_image((os.path.join(image_path, "player", "jumping", "player-jumping.png")))
player_images = {"walking": [player_walking1, player_walking2, player_walking3, player_walking4],
                 "jumping": player_jumping,
                 "standing": player_standing}

block_images = {"Grass": load_image((os.path.join(image_path, "blocks", "grass.png"))),
                "Dirt": load_image((os.path.join(image_path, "blocks", "dirt.png"))),
                "Stone": load_image((os.path.join(image_path, "blocks", "stone.png")))}

cursor_tracker = load_image((os.path.join(image_path, "misc", "clear-single-pixel.png")))



class Entity(pg.sprite.Sprite):

    def __init__(self, x, y, image):
        # Initialize an entity
        super().__init__()

        self.image = image
        self.rect = self.image.get_rect()
        self.rect.x = x
        self.rect.y = y

        self.vx = 0
        self.vy = 0

    def apply_gravity(self, world):
        # Let the enemy be affected by gravity
        self.vy += world.gravity
        self.vy = min(self.vy, world.terminal_velocity)



class Block(Entity):

    def __init__(self, x, y, image):
        # Initialize the block
        super().__init__(x, y, image)



class Cursor(Entity):

    def __init__(self, x, y, image):
        # Initialize the invisible mouse cursor object
        # This will be used to track where the mouse goes and if the mouse is on a block
        super().__init__(x, y, image)

        self.on_block = False

    def follow_mouse(self):
        # Make object follow the mouse
        self.mouse_x, self.mouse_y = pg.mouse.get_pos()
        self.rect.x = self.mouse_x
        self.rect.y = self.mouse_y

    def detect_block_collision(self, world):
        # Detects collsion between cursor tracker and a block
        hit_list = pg.sprite.spritecollide(self, world.blocks, True)

        if len(hit_list) > 0:
            pass

    def update(self, world):
        # Update the cursor object
        self.follow_mouse()
        world.active_sprites.add(self)



class Player(Entity):

    def __init__(self, images):
        # Initialize the player
        super().__init__(0, 0, images["standing"])

        # Images in each direction
        self.image_standing_right = images["standing"]
        self.image_standing_left = pg.transform.flip(self.image_standing_right, 1, 0)
        self.images_walking_right = images["walking"]
        self.images_walking_left = [pg.transform.flip(img, 1, 0) for img in self.images_walking_right]
        self.image_jumping_right = images["jumping"]
        self.image_jumping_left = pg.transform.flip(self.image_jumping_right, 1, 0)

        # Player variables
        self.running_images = self.images_walking_right
        self.image_index = 0
        self.steps = 0
        self.speed = 3.5
        self.jump_power = 12

        self.vx = 0
        self.vy = 0
        self.direction = "right"
        self.on_ground = True

        self.score = 0
        self.health = 100
        self.max_health = 100
        self.invincibility = 0

    def move_left(self):
        # Move to the left
        self.vx = -self.speed + 0.9
        self.direction = "left"

    def move_right(self):
        # Move to the rightS
        self.vx = self.speed
        self.direction = "right"

    def stop(self):
        # Stop it right there
        self.vx = 0

    def jump(self, blocks):
        # Jump up, jump up, and get down
        self.rect.y += 1

        hit_list = pg.sprite.spritecollide(self, blocks, False)

        if len(hit_list) > 0:
            self.vy = -1 * self.jump_power

        self.rect.y -= 1

    def check_world_boundaries(self, world):
        # Make sure the player doesn"t walk off the world
        if self.rect.left < 0:
            self.rect.left = 0
        elif self.rect.right > world.width:
            self.rect.right = world.width

    def move_and_process_blocks(self, blocks):
        # Detect block collisions
        # Block side collisions
        self.rect.x += self.vx
        hit_list = pg.sprite.spritecollide(self, blocks, False)

        for block in hit_list:
            if self.vx > 0:
                self.rect.right = block.rect.left
                self.vx = 0
            elif self.vx < 0:
                self.rect.left = block.rect.right
                self.vx = 0

        self.on_ground = False

        # Block top and bottom collisions
        self.rect.y += self.vy + 1 # The +1 isn"t necessary, but it helps
        hit_list = pg.sprite.spritecollide(self, blocks, False)

        for block in hit_list:
            if self.vy > 0:
                self.rect.bottom = block.rect.top
                self.on_ground = True
                self.vy = 0
            elif self.vy < 0:
                self.rect.top = block.rect.bottom
                self.on_ground = True
                self.vy = 0

    def set_image(self):
        # Set images and animate
        if self.on_ground:
            if self.vx != 0:
                if self.direction == "right":
                    self.walking_images = self.images_walking_right
                elif self.direction == "left":
                    self.walking_images = self.images_walking_left

                self.steps = (self.steps + 1) % self.speed

                if self.steps == 0:
                    self.image_index = (self.image_index + 1) % len(self.walking_images)
                    self.image = self.walking_images[self.image_index]
            else:
                if self.direction == "right":
                    self.image = self.image_standing_right
                elif self.direction == "left":
                    self.image = self.image_standing_left
        else:
            if self.direction == "right":
                self.image = self.image_jumping_right
            elif self.direction == "left":
                self.image = self.image_jumping_left

    def die(self):
        # D E D
        pass

    def check_block_breaks(self, blocks):
        # Break a block
        # mouse_pos = pg.mouse.get_pos()
        # for block in blocks:
        #     if block.rect.collidepoint(mouse_pos):
        #         print("hi")
        pass

    def respawn(self, world):
        # Hey, you"re back!
        self.rect.x = world.start_x
        self.rect.y = world.start_y
        self.health = self.max_health
        self.invincibility = 0
        self.direction = "right"

    def update(self, world):
        # Constantly update the player
        self.apply_gravity(world)
        self.move_and_process_blocks(world.blocks)
        self.check_world_boundaries(world)
        self.set_image()
        self.check_block_breaks(world.blocks)

        if self.health > 0:
            if self.invincibility > 0:
                self.invincibility -= 1
        else:
            self.die()



class Game():

    def __init__(self):
        # Initialize the game itself
        self.window = pg.display.set_mode([WINDOWWIDTH, WINDOWHEIGHT])
        pg.display.set_caption(TITLE)
        self.clock = pg.time.Clock()
        self.done = False
        self.reset()

    def start(self):
        # Start the whole thing up
        self.world = World(worlds[self.current_world])
        self.cursor = Cursor(0, 0, cursor_tracker)
        self.world.reset()
        self.player.respawn(self.world)

    def reset(self):
        # Reset the game
        self.player = Player(player_images)
        self.current_world = 0
        self.start()

    def update(self):
        # Update things in the game
        self.player.update(self.world)
        self.cursor.update(self.world)

        if self.player.health <= 0:
            self.player.respawn(self.world)

    def calculate_offset(self):
        # Calculate x/y coordinates after screen scrolls
        x = -1 * self.player.rect.centerx + WINDOWWIDTH / 2

        if self.player.rect.centerx < WINDOWWIDTH / 2:
            x = 0
        elif self.player.rect.centerx > self.world.width - WINDOWWIDTH / 2:
            x = -1 * self.world.width + WINDOWWIDTH

        y = -1 * self.player.rect.centery + WINDOWHEIGHT / 2

        if self.player.rect.centery < WINDOWHEIGHT / 2:
            y = 0
        elif self.player.rect.centery > self.world.height - WINDOWHEIGHT / 2:
            y = -1 * self.world.height + WINDOWHEIGHT

        return x, y

    def draw(self):
        # Draw sprites to the screen
        self.offset_x, self.offset_y = self.calculate_offset()

        self.world.active_layer.fill(TRANSPARENT)
        self.world.active_sprites.draw(self.world.active_layer)

        if self.player.invincibility % 3 < 2:
            self.world.active_layer.blit(self.player.image, [self.player.rect.x, self.player.rect.y])

        self.window.blit(self.world.background_layer, [self.offset_x / 3, self.offset_y])
        self.window.blit(self.world.inactive_layer, [self.offset_x, self.offset_y])
        self.window.blit(self.world.active_layer, [self.offset_x, self.offset_y])

        self.offset_cursor_x = self.cursor.rect.x - self.offset_x
        self.offset_cursor_y = self.cursor.rect.y - self.offset_y

        self.cursor.rect.x = self.offset_cursor_x
        self.cursor.rect.y = self.offset_cursor_y

        pg.display.update(0, 0, WINDOWWIDTH, WINDOWHEIGHT)

    def process_events(self):
        # Handle events (key presses, mouse clicks, etc)
        for event in pg.event.get():
            if event.type == pg.QUIT:
                self.done = True

            elif event.type == pg.KEYDOWN:
                # Jump
                if event.key == JUMP:
                    self.player.jump(self.world.blocks)
                # Debug reset
                elif event.key == pg.K_r:
                    self.reset()
                # Debug close
                elif event.key == pg.K_q:
                    self.done = True

            # Break a block if you click on it
            if event.type == pg.MOUSEBUTTONDOWN:
                # for block in self.world.blocks:
                #     if block.rect.collidepoint(self.offset_cursor_x, self.offset_cursor_y):
                #         block.kill()
                self.cursor.detect_block_collision(self.world)

        pressed = pg.key.get_pressed()

        if pressed[LEFT]:
            self.player.move_left()
        elif pressed[RIGHT]:
            self.player.move_right()
        else:
            self.player.stop()

    def loop(self):
        # Loop through essential functions
        while not self.done:
            self.process_events()
            self.update()
            self.draw()
            self.clock.tick(FPS)



if __name__ == "__main__":
    # Begin the loop and pre-initialize the game
    game = Game()
    game.start()
    game.loop()
    pg.quit()
    sys.exit()

World Handler(生成块并将其添加到组): 有些部分已被注释掉,因为它们没有任何用途,但很快就会出现。

# Imports
import pygame as pg
import json
import random
import os
from settings import *
from main import *

# Initialize pygame
pg.init()



class World():

    def __init__(self, file_path):
        # Initialize the world
        # Starting entities
        self.starting_blocks = []

        # Entity groups
        self.blocks = pg.sprite.Group()

        # Sprite groups (active/inactive)
        self.active_sprites = pg.sprite.Group()
        self.inactive_sprites = pg.sprite.Group()

        # Read the world json file
        with open(file_path, "r") as f:
            data = f.read()

        map_data = json.loads(data)

        # World width and height
        self.width = map_data["width"] * GRID_SIZE
        self.height = map_data["height"] * GRID_SIZE

        # Player start position
        self.start_x = map_data["start"][0] * GRID_SIZE
        self.start_y = map_data["start"][1] * GRID_SIZE

        # Load blocks
        for item in map_data["blocks"]:
            x, y = item[0] * GRID_SIZE, item[1] * GRID_SIZE
            img = block_images[item[2]]
            self.starting_blocks.append(Block(x, y, img))

        # Layers
        self.background_layer = pg.Surface([self.width, self.height], pg.SRCALPHA, 32)
        self.inactive_layer = pg.Surface([self.width, self.height], pg.SRCALPHA, 32)
        self.active_layer = pg.Surface([self.width, self.height], pg.SRCALPHA, 32)

        # Load background color
        if map_data["bg-color"] != "":
            self.background_layer.fill(map_data["bg-color"])

        # Load background image
        # if map_data["bg-image"] != "":
        #     bg_image = pg.image.load(map_data["bg-image"]).convert_alpha()
        #
        #     if map_data["bg-fill-y"]:
        #         h = bg_image.get_height()
        #         w = int(bg_image.get_width() * WINDOWHEIGHT / h)
        #         bg_image = pg.transform.scale(bg_image, (w, WINDOWHEIGHT))
        #
        #     if "top" in map_data["bg-position"]:
        #         start_y = 0
        #     elif "bottom" in map_data["bg-postion"]:
        #         start_y = self.height = bg_image.get_height()
        #
        #     if map_data["bg-repeat-x"]:
        #         for x in range(0, self.width, bg_image.get_width()):
        #             self.background_layer.blit(bg_image, [x, start_y])
        #     else:
        #         self.background_layer.blit(bg_image, [0, start_y])

        # Load background music
        # pg.mixer.music.load(map_data["music"])

        # Set the world's gravity strength and terminal velocity
        self.gravity = map_data["gravity"]
        self.terminal_velocity = map_data["terminal-velocity"]

        # Grass generator
        if map_data["gen-type"] == "earth":
            gen_loop = map_data["width"]
            x = 0
            y = 56 * GRID_SIZE # The general y coordinate for block placing
            y_gen = 56 * GRID_SIZE # Stored to be referenced in order to make a smoother landscape

            for i in range (0, map_data["width"]):
                # Generate grass
                img = block_images["Grass"]
                self.starting_blocks.append(Block(x, y, img))
                y += GRID_SIZE
                # Generate dirt
                for i in range(0, 6):
                    img = block_images["Dirt"]
                    self.starting_blocks.append(Block(x, y, img))
                    y += GRID_SIZE
                # Generate stone
                for i in range(1, int((self.height / GRID_SIZE))):
                    img = block_images["Stone"]
                    self.starting_blocks.append(Block(x, y, img))
                    y += GRID_SIZE

                y = y_gen
                x += GRID_SIZE
                gen_loop -= 1

                # Randomly decide what the next grass' y will be in relation to the previous one
                random_grass = random.randint(0, 5)
                # The lowest point you'll find a block of grass
                lowest_grass_y = 53 * GRID_SIZE
                # How extreme the changes in block heights will be
                # 0 is flat, 1 will have pretty smooth terrain, while something like 10 would be super steep
                gen_extremity = 1

                # Keep the grass at the same y
                if random_grass == 0 or random_grass == 1 or random_grass == 2 or random_grass == 3:
                    gen_loop -= 1
                    if y <= lowest_grass_y:
                        y += GRID_SIZE

                # Increase y
                elif random_grass == 4:
                    y_gen += GRID_SIZE * gen_extremity
                    if y <= lowest_grass_y:
                        y += GRID_SIZE

                # Decrease y
                elif random_grass == 5:
                    y_gen -= GRID_SIZE * gen_extremity
                    if y <= lowest_grass_y:
                        y += GRID_SIZE
                else:
                    raise ValueError("How did we get here? Grass generator somehow generated an invalid number.")

        # Add starting entities to their groups
        self.blocks.add(self.starting_blocks)

        # Add sprites to inactive/active sprite groups
        self.inactive_sprites.add(self.blocks)

        # Does... something?
        for s in self.active_sprites:
            s.image.convert()

        for s in self.inactive_sprites:
            s.image.convert()

        # Draw inactive sprites to the inactive layer
        self.inactive_sprites.draw(self.inactive_layer)

        # Convert layers
        self.background_layer.convert()
        self.inactive_layer.convert()
        self.active_layer.convert()

设置文件(帮助您重新创建问题并找出正在进行的操作

# Imports
import pygame as pg
import os

# File paths
current_path = os.path.dirname(__file__)
assets_path = os.path.join(current_path, 'assets')
image_path = os.path.join(assets_path, 'img')

# Window settings
TITLE = "Mooncraft"
WINDOWWIDTH = 960
WINDOWHEIGHT = 640
FPS = 60
GRID_SIZE = 32

# Options
sound_on = True

# Controls
LEFT = pg.K_a
RIGHT = pg.K_d
JUMP = pg.K_SPACE

# Colors
TRANSPARENT = (0, 0, 0, 0)
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)

# World files
worlds = [(os.path.join(assets_path, 'worlds', 'earth.json'))]

如果有人可以解释我做错了什么,我们将不胜感激。

更新2:添加了播放器类和设置文件,以帮助任何愿意帮助我找到问题的人。

1 个答案:

答案 0 :(得分:0)

从一目了然,看起来你可能不会在更新循环中的任何一点清除屏幕,而是覆盖已经存在的内容。这将导致块仍然可见,但实际上并不存在。尝试在翻转显示之前添加screen.fill(#Color here)。另请尝试使用pygame.display.update()代替pygame.display.flip()