在pygame中,当我与某个对象碰撞时,如何使其停留?

2024-09-29 19:18:50 发布

您现在位置:Python中文网/ 问答频道 /正文

因此,我使用了第一个答案here中稍微修改过的python脚本版本,并在这里添加了一个名为“SpeechBlock”的类:

    level = [
        "PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP",
        "P                                                             P",
        "P                                                             P",
        "P                                                             P",
        "P                                                             P",
        "P                                                             P",
        "P                                                             P",
        "P                                                             P",
        "PPPPPPPPSPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP",]
    # build the level
    for row in level:
        for col in row:
            if col == "P":
                p = Platform(x, y)
                platforms.append(p)
                entities.add(p)
            if col == "E":
                e = ExitBlock(x, y)
                platforms.append(e)
                entities.add(e)
            if col == "S":
                s = SpeechBlock(x, y)
                platforms.append(s)
                entities.add(s

让它成为一门课:

class SpeechBlock(Platform):
    def __init__(self, x, y):
        Platform.__init__(self, x, y)
        self.image.fill(Color("#0033FF"))
        self.x=x
        self.y=y

    def speak(self):
        self.events = [
            "test",
            ]
        for row in self.events:
            image=pygame.image.load(row+".png")
            screen.blit(image, (self.x,self.y))

脚本已经有了一个用于冲突的方法,我在这里添加了最后3行:

ef collide(self, xvel, yvel, platforms):
        for p in platforms:
            if pygame.sprite.collide_rect(self, p):
                if isinstance(p, ExitBlock):
                    pygame.event.post(pygame.event.Event(QUIT))
                if xvel > 0:
                    self.rect.right = p.rect.left
                    print("collide right")
                if xvel < 0:
                    self.rect.left = p.rect.right
                    print ("collide left")
                if yvel > 0:
                    self.rect.bottom = p.rect.top
                    self.onGround = True
                    self.yvel = 0
                if yvel < 0:
                    self.rect.top = p.rect.bottom
                if isinstance(p, SpeechBlock):
                    SpeechBlock.speak(self)
                    pygame.display.update()

我想要并且仍然想要实现的是,当玩家站在演讲块上时,一个演讲泡泡的图像会闪现在屏幕上。取而代之的是,当玩家站在演讲块的边缘时,图像会出现一小会儿,然后消失,然后再出现一小会儿,以此类推。。。 我做错了什么?我是pygame的新手,所以我不太了解blitting和显示更新/翻转的工作原理。任何帮助都将不胜感激。你知道吗


Tags: inrectimageselfforifcollevel
1条回答
网友
1楼 · 发布于 2024-09-29 19:18:50

你必须知道你的游戏是循环的。这个循环的每次迭代称为一个帧。在每一帧中,你清理屏幕上的所有内容,处理所有事件,更新游戏世界,再次绘制所有内容。你知道吗

因此,当您调用SpeechBlock.speak(self)pygame.display.update()时,您将图像(从speak方法)绘制到屏幕上,但它们将在下一帧中被删除。你知道吗

每个帧不应调用pygame.display.update()多次。你应该做的是引入一些新的状态来改变你触摸它时SpeechBlock的行为。你知道吗

太长了,读不下去了,下面是DR例子:

import pygame
from pygame import *
import sys

SCREEN_SIZE = pygame.Rect((0, 0, 800, 640))
TILE_SIZE = 32 
GRAVITY = pygame.Vector2((0, 0.3))

class CameraAwareLayeredUpdates(pygame.sprite.LayeredUpdates):
    def __init__(self, target, world_size):
        super().__init__()
        self.target = target
        self.cam = pygame.Vector2(0, 0)
        self.world_size = world_size
        if self.target:
            self.add(target)

    def update(self, *args):
        super().update(*args)
        if self.target:
            x = -self.target.rect.center[0] + SCREEN_SIZE.width/2
            y = -self.target.rect.center[1] + SCREEN_SIZE.height/2
            self.cam += (pygame.Vector2((x, y)) - self.cam) * 0.05
            self.cam.x = max(-(self.world_size.width-SCREEN_SIZE.width), min(0, self.cam.x))
            self.cam.y = max(-(self.world_size.height-SCREEN_SIZE.height), min(0, self.cam.y))

    def draw(self, surface):
        spritedict = self.spritedict
        surface_blit = surface.blit
        dirty = self.lostsprites
        self.lostsprites = []
        dirty_append = dirty.append
        init_rect = self._init_rect
        for spr in self.sprites():
            rec = spritedict[spr]
            newrect = surface_blit(spr.image, spr.rect.move(self.cam))
            if rec is init_rect:
                dirty_append(newrect)
            else:
                if newrect.colliderect(rec):
                    dirty_append(newrect.union(rec))
                else:
                    dirty_append(newrect)
                    dirty_append(rec)
            spritedict[spr] = newrect
        return dirty            

def main():
    pygame.init()
    screen = pygame.display.set_mode(SCREEN_SIZE.size)
    pygame.display.set_caption("Use arrows to move!")
    timer = pygame.time.Clock()

    level = [
        "PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP",
        "P                                          P",
        "P                                          P",
        "P                                          P",
        "P                    PPPPPPPPPPP           P",
        "P                                          P",
        "P                                          P",
        "P                                          P",
        "P    PPPPPPPP                              P",
        "P                                          P",
        "P                          PPPPPPP         P",
        "P                 PPPPPP                   P",
        "P                                          P",
        "P         PPPPPPP                          P",
        "P                                          P",
        "P                     PPPPPP               P",
        "P                                          P",
        "P   PPPPPPPPPPP                            P",
        "P                                          P",
        "P                 PPPPPPPPPPP              P",
        "P                                          P",
        "P                                          P",
        "P                                          P",
        "P                                          P",
        "PPPPPPPPPSPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP",]


    platforms = pygame.sprite.Group()
    player = Player(platforms, (TILE_SIZE, TILE_SIZE))
    level_width  = len(level[0])*TILE_SIZE
    level_height = len(level)*TILE_SIZE
    entities = CameraAwareLayeredUpdates(player, pygame.Rect(0, 0, level_width, level_height))

    # build the level
    x = y = 0
    for row in level:
        for col in row:
            if col == "P":
                Platform((x, y), entities, platforms)
            if col == "S":
                SpeechBlock((x, y), entities, platforms)
            x += TILE_SIZE
        y += TILE_SIZE
        x = 0

    dt = 0

    while 1:
        events = pygame.event.get()
        for e in events:
            if e.type == QUIT: 
                return
            if e.type == KEYDOWN and e.key == K_ESCAPE:
                return

        entities.update(dt, events)
        screen.fill((0, 0, 0))
        entities.draw(screen)
        pygame.display.update()
        dt = timer.tick(60)

class Entity(pygame.sprite.Sprite):
    def __init__(self, color, pos, *groups):
        super().__init__(*groups)
        self.image = Surface((TILE_SIZE, TILE_SIZE))
        self.image.fill(color)
        self.rect = self.image.get_rect(topleft=pos)

    def update(self, dt, events):
        pass

class Player(Entity):
    def __init__(self, platforms, pos, *groups):
        super().__init__(Color("#0000FF"), pos)
        self.vel = pygame.Vector2((0, 0))
        self.onGround = False
        self.platforms = platforms
        self.speed = 8
        self.jump_strength = 10

    def update(self, dt, events):
        pressed = pygame.key.get_pressed()
        up = pressed[K_UP]
        left = pressed[K_LEFT]
        right = pressed[K_RIGHT]
        running = pressed[K_SPACE]

        if up:
            # only jump if on the ground
            if self.onGround: self.vel.y = -self.jump_strength
        if left:
            self.vel.x = -self.speed
        if right:
            self.vel.x = self.speed
        if running:
            self.vel.x *= 1.5
        if not self.onGround:
            # only accelerate with gravity if in the air
            self.vel += GRAVITY
            # max falling speed
            if self.vel.y > 100: self.vel.y = 100

        if not(left or right):
            self.vel.x = 0
        # increment in x direction
        self.rect.left += self.vel.x * dt/10.
        # do x-axis collisions
        self.collide(self.vel.x, 0, self.platforms)
        # increment in y direction
        self.rect.top += self.vel.y * dt/10.
        # assuming we're in the air
        self.onGround = False;
        # do y-axis collisions
        self.collide(0, self.vel.y, self.platforms)

    def collide(self, xvel, yvel, platforms):
        for p in platforms:
            if pygame.sprite.collide_rect(self, p):
                if isinstance(p, SpeechBlock):
                    p.trigger()
                if xvel > 0:
                    self.rect.right = p.rect.left
                if xvel < 0:
                    self.rect.left = p.rect.right
                if yvel > 0:
                    self.rect.bottom = p.rect.top
                    self.onGround = True
                    self.yvel = 0
                if yvel < 0:
                    self.rect.top = p.rect.bottom

class Platform(Entity):
    def __init__(self, pos, *groups):
        super().__init__(Color("#DDDDDD"), pos, *groups)

class TextBlock(pygame.sprite.Sprite):
    def __init__(self, pos, text, *groups):
        super().__init__(*groups)
        self.image = Surface((200, 100))
        self.rect = self.image.get_rect(center=pos)
        self.image.fill(Color("white"))
        # todo: don't load font everytime
        self.image.blit(pygame.font.SysFont(None, 32).render(text, True, Color("Black")), (10, 10))

class SpeechBlock(Entity):
    def __init__(self, pos, *groups):
        super().__init__(Color("orange"), pos, *groups)
        self.cooldown = 0
        self.text = None

    def trigger(self):
        # do nothing if already triggered
        if self.cooldown: return

        self.cooldown = 2000
        # first group is the entity group
        self.text = TextBlock(self.rect.move(0, -150).center, 'Ouch!', self.groups()[0])

    def update(self, dt, events):

        if self.cooldown:
            self.cooldown -= dt
            if self.cooldown <= 0:
                self.text.kill()
                self.text = None
                self.cooldown = 0

if __name__ == "__main__":
    main()

在这里您可以看到,我们创建了一个新的Entity,当播放器进入SpeechBlock时显示文本。两秒钟后,SpeechBlock调用kill将其从游戏中删除。你知道吗

我还更新了一点代码,使用delta时间,这样我们就可以很容易地检查是否已经过了2秒。你知道吗

enter image description here

相关问题 更多 >

    热门问题