1

我正在开发一个平台游戏,其中玩家有一把剑。我希望玩家只有在他脚下有地面时才能攻击(所以他不能在空中攻击)。所以我实现了这段代码:

for b in instancelist:
    for p in players:
        if b.rect.collidepoint(p.rect.centerx,p.rect.bottom+4):
            grounded=1
        else:
            grounded=0
print grounded

但..

print grounded

每次都返回零..虽然如果我添加exit(1)到它测试玩家是否在地面上的部分,它仍然会退出!(虽然接地仍为零)

这是完整的代码:

import pygame,random
from collections import namedtuple
from pygame.locals import *
pygame.init()
pygame.display.set_caption('Legend of Zelda | By Sam Tubb')
screen=pygame.display.set_mode((640,480))
instancelist=[]
players=[]
enemys=[]
clock=pygame.time.Clock()
Move = namedtuple('Move', ['up', 'left', 'right'])

#load sprites
block1=pygame.image.load('block1.png').convert()

#load/init player stuffs
playersprites=[pygame.image.load('link1.png').convert(),pygame.image.load('link2.png').convert(),
pygame.image.load('link3.png').convert(),pygame.image.load('linkatk.png').convert(),pygame.image.load('linkup.png').convert()]
for s in playersprites:
    s.set_colorkey((255,0,0))
frame=0
frameplus=1
frametime=0
psprite=playersprites[frame]
max_gravity = 75
left=0
atk=0
atktime=0
grounded=0

class Enemy(object):
    def __init__(self,x,y):
        self.x=x
        self.y=y
        self.sprite=playersprites[0]
        self.rect=self.sprite.get_rect(left=x,top=y)
class Player(object):
    sprite=psprite
    def __init__(self, x, y):
        self.rect = self.sprite.get_rect(centery=y, centerx=x)
        # indicates that we are standing on the ground
        # and thus are "allowed" to jump
        self.on_ground = True
        self.xvel = 0
        self.yvel = 0
        self.jump_speed = 7
        self.move_speed = 3

    def update(self, move, blocks):

        # check if we can jump 
        if move.up and self.on_ground:
            self.yvel -= self.jump_speed

        # simple left/right movement
        if move.left:
                self.xvel = -self.move_speed
        if move.right:
                self.xvel = self.move_speed

        # if in the air, fall down
        if not self.on_ground:
            self.yvel += 0.3
            # but not too fast
            if self.yvel > max_gravity: self.yvel = max_gravity

        # if no left/right movement, x speed is 0, of course
        if not (move.left or move.right):
            self.xvel = 0

        # move horizontal, and check for horizontal collisions
        self.rect.left += self.xvel
        self.collide(self.xvel, 0, blocks)

        # move vertically, and check for vertical collisions
        self.rect.top += self.yvel
        self.on_ground = False;
        self.collide(0, self.yvel, blocks)

    def collide(self, xvel, yvel, blocks):
        # all blocks that we collide with
        for block in [blocks[i] for i in self.rect.collidelistall(blocks)]:

            # if xvel is > 0, we know our right side bumped 
            # into the left side of a block etc.
            if xvel > 0:
                    self.rect.right = block.rect.left
            if xvel < 0:
                    self.rect.left = block.rect.right

            # if yvel > 0, we are falling, so if a collision happpens 
            # we know we hit the ground (remember, we seperated checking for
            # horizontal and vertical collision, so if yvel != 0, xvel is 0)
            if yvel > 0:
                self.rect.bottom = block.rect.top+0.4
                self.on_ground = True
                self.yvel = 0
            # if yvel < 0 and a collision occurs, we bumped our head
            # on a block above us
            if yvel < 0: self.rect.top = block.rect.bottom

class Block(object):
    def __init__(self,x,y,sprite):
        self.x=x
        self.y=y
        self.sprite=sprite
        self.rect=self.sprite.get_rect(x=self.x,y=self.y)

x = y = 0
level = [
"BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB",
"B                                       B",
"B                                       B",
"B               L                       B",
"B                                       B",
"B                                       B",
"B                                       B",
"B                       E               B",
"B                                       B",
"B         BBBBBBBBBBBBBBB               B",
"B        B                              B",
"B     E B                               B",
"B      B                                B",
"B     B                                 B",
"B    B                                  B",
"B   B                                   B",
"B                   E                   B",
"B                                       B",
"BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB",
]
# build the level
for row in level:
    for col in row:
        if col == "B":
            p = Block(x,y,block1)
            instancelist.append(p)
        if col=="L":
             players.append(Player(x, y))
        if col=="E":
            enemys.append(Enemy(x,y))
        x += 16
    y += 16
    x = 0

#mainloop
while True:
    for b in instancelist:
        for p in players:
            if b.rect.collidepoint(p.rect.centerx,p.rect.bottom+4):
                grounded=1
            else:
                grounded=0
    print grounded
    #total_level_width  = len(level[0])*16
    #total_level_height = len(level)*16
    screen.fill((0,0,0))
    mse=pygame.mouse.get_pos()
    key=pygame.key.get_pressed()
    if atk==0:
        if not key[K_w]:
            if key[K_a]:
                left=1
                if frameplus==1:
                    if frame<2:
                        frameplus=0
                        frametime=5
                        frame+=1
                    else:
                        frame=0
                psprite=pygame.transform.flip(playersprites[frame],1,0)
            if key[K_d]:
                left=0
                if frameplus==1:
                    if frame<2:
                        frameplus=0
                        frametime=5
                        frame+=1
                    else:
                        frame=0
                psprite=playersprites[frame]
            if not key[K_a]:
                if not key[K_d]:
                    if left==0:
                        psprite=playersprites[0]
                    else:
                        psprite=pygame.transform.flip(playersprites[0],1,0)
        else:
            if left==0:
                psprite=playersprites[4]
            else:
                psprite=pygame.transform.flip(playersprites[4],1,0)
    if key[K_SPACE]:
        if atk==0:
            atk=1
            atktime=15
            if left==0:
                psprite=playersprites[3]
                p.rect.right+=4
            else:
                psprite=pygame.transform.flip(playersprites[3],1,0)
                p.rect.right-=16
    for e in pygame.event.get():
        if e.type==QUIT:
            exit(1)
    for inst in instancelist:
        screen.blit(inst.sprite,inst.rect)
    for p in players:
        if atk==0:
            p.rect=psprite.get_rect(x=p.rect.left,y=p.rect.top)
            move = Move(key[K_w], key[K_a], key[K_d])
            p.update(move, instancelist)
        #scrolling
        if p.rect.right>=500:
            for inst in instancelist:
                inst.rect.left-=4
            for e in enemys:
                e.rect.left-=4
            p.rect.left-=4
        if p.rect.left<=140:
            for inst in instancelist:
                inst.rect.left+=4
            for e in enemys:
                e.rect.left+=4
            p.rect.left+=4
        if p.rect.top<=80:
            for inst in instancelist:
                inst.rect.top+=4
            for e in enemys:
                e.rect.top+=4
            p.rect.top+=4
        if p.rect.bottom>300:
            for inst in instancelist:
                inst.rect.bottom-=4
            for e in enemys:
                e.rect.bottom-=4
            p.rect.bottom-=4


        for b in instancelist:
            if p.rect.colliderect(b.rect):
                p.ground=1
        screen.blit(psprite,p.rect)

        for e in enemys:
            if atk==1:
                if left==0:
                    if p.rect.left<e.rect.left:
                        if p.rect.colliderect(e.rect):
                            enemys.remove(e)
                else:
                    if p.rect.right>e.rect.right:
                        if p.rect.colliderect(e.rect):
                            enemys.remove(e)
            screen.blit(e.sprite,e.rect)

    #timers
    if frametime>0:
        frametime-=1
    else:
        frameplus=1

    if atktime>0:
        atktime-=1
    else:
        if atk==1:
            if left==1:
                p.rect.right+=16
            else:
                p.rect.right-=4
        atktime=0
        atk=0

    p.rect=psprite.get_rect(x=p.rect.left,y=p.rect.top)
    pygame.draw.rect(screen, ((255,0,0)), p.rect, 1)
    clock.tick(60)
    pygame.display.flip()

有人可以帮忙吗?:)

4

2 回答 2

1

根据我对您代码的阅读,您有一个Playerinplayers和多个Blocksin instancelist. 每一对都调用你的内部Block循环Player。除非你很幸运(或者很不幸,因为这会隐藏一个错误),否则碰撞的Block那个Player不会是你检查的最后一个。因此,在您的循环的后续迭代中,Block您检查的 不会与 冲突,Player并且grounded0else子句中设置回。

一种解决方案可能是摆脱您的else陈述。因此,如果有任何Block与 的碰撞Player,接地将设置为1,如果没有BlocksPlayergrounded将简单地保持在0。如果 a 发生Block碰撞,之后Blocks不改变 的值grounded

while True:
    grounded = 0
    for b in instancelist:
        for p in players:
            if b.rect.collidepoint(p.rect.centerx,p.rect.bottom+4):
                grounded=1
    print grounded

更好的解决方案可能会使用break语句来避免不必要的工作。

while True:
    grounded = 0
    for p in players:
        for b in instancelist:
            if b.rect.collidepoint(p.rect.centerx,p.rect.bottom+4):
                grounded=1
                break
    print grounded
于 2013-10-15T16:23:55.973 回答
1

最重要的是,正如马蒂诺所说,接地回路将重置任何接地的发现。

实例列表似乎受益于位置字典或数组,您可以根据玩家的位置更有效地测试它,而不是每次都将玩家的位置与每个块进行比较。


*编辑 - 忽略下面。@monkey 好心地指出我是如何反转 pygame 坐标系的。

此外,我对文档的阅读表明您的代码正在检查给定点是否位于 b.rect 中。给定点是玩家的水平中心和玩家底部上方的 4。如果玩家停留在块的底部,那很好,因为它看起来是 16 号的。但是你的 fall 代码看起来会在玩家与块碰撞之前将其发送到 -4?无论如何,您可能希望将其反转-4并查看其行为是否更像您想要的。

于 2013-10-15T17:07:59.433 回答