Python 如何通过碰撞检测阻止玩家精灵通过方块?

Python 如何通过碰撞检测阻止玩家精灵通过方块?,python,pygame,collision,Python,Pygame,Collision,我试图阻止球员通过拦网。我希望他们能够降落在障碍物上,但如果障碍物的另一边发生碰撞,他们会反弹离开 我以前尝试过改变球员在击中拦网时重置的距离 运行每一帧以检查是否存在碰撞: hits = pygame.sprite.spritecollide(player, walls, False) if hits: player.checkCollisionWall(hits) 球员级别 import pygame, time, Settings from pygame.locals impor

我试图阻止球员通过拦网。我希望他们能够降落在障碍物上,但如果障碍物的另一边发生碰撞,他们会反弹离开

我以前尝试过改变球员在击中拦网时重置的距离

运行每一帧以检查是否存在碰撞:

hits = pygame.sprite.spritecollide(player, walls, False)
if hits:
    player.checkCollisionWall(hits)
球员级别

import pygame, time, Settings
from pygame.locals import *
vec = pygame.math.Vector2

pygame.init()

class player(pygame.sprite.Sprite):
    ACCEL = 0.5 # Acceleration
    GFRICTION = vec(-0.2, 0) # Ground Friction
    AFRICTION = vec(-0.2, 0) # Air Friction
    GRAVITY = 0.8 # must be greater than 0.6
    JUMP_HEIGHT = 10
    START_X = 25 
    START_Y = 600
    WIDTH = 10
    HEIGHT = 10
    START_POS = vec(START_X + WIDTH/2, START_Y + HEIGHT) # point at bottom middle
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.Pos = self.START_POS
        self.image = pygame.surface.Surface((self.WIDTH, self.HEIGHT))
        self.image.fill((0, 255, 0))
        self.rect = self.image.get_rect()
        self.rect.center = (self.Pos.x, self.Pos.y)
        self.vel = vec(0,0) # set velocity as a vector
        self.acc = vec(0,0) # set acceleration as a vector
        self.inJump = False
        self.tryingToJump = False
    def update(self):
        self.tryingToJump = False
        self.acc = vec(0, self.GRAVITY)
        self.move()
    def draw(self):
        # draw the rectangle
        self.Pos += self.vel + 0.5 *self.acc
        self.rect.center = self.Pos
    def move(self):
        # identify which keys are pressed
        pressed_keys = pygame.key.get_pressed()
        if pressed_keys[K_LEFT]:
            self.changeX("left")
        elif pressed_keys[K_RIGHT]:
            self.changeX("right")
        if pressed_keys[K_UP]:
            self.jump()
        # check player is on screen and place player where it should be if neccessary
        if self.Pos.y > Settings.WINDOW_HEIGHT:
            self.Pos.x = self.START_POS.x
            self.Pos.y = self.START_POS.y
        if self.Pos.x < 0:
            self.vel.x = 2
        if self.Pos.x > Settings.WINDOW_WIDTH:
            self.vel.x = -2
        # apply friction 
        if self.inJump: #in the air
            self.acc.x += self.vel.x * self.AFRICTION.x
        else: #touching the ground
            self.acc.x += self.vel.x * self.GFRICTION.x
        # move the player
        self.vel += self.acc
    def changeX(self, direction):
        # move left or right
        if direction == "right":
            self.acc.x = self.ACCEL
        elif direction == "left":
            self.acc.x = -self.ACCEL
    def jump(self):
        # jump only if standing on a platform
        if self.inJump == False:
            self.tryingToJump = True
            self.inJump = True
            self.vel.y -= self.JUMP_HEIGHT
    def checkCollisionWall(self, hits):
        self.lowestWall = self.highestWall = hits[0]
        for i in hits:
            if i.rect.bottom > self.lowestWall.rect.bottom:
                self.lowestWall = i # find the lowest wall that the player is touching
            if i.rect.top < self.highestWall.rect.top:
                self.highestWall = i # find the highest wall that the player is touching
        if self.vel.y > 0: # check if a block is below
            print("below")
            self.rect.bottom = self.lowestWall.rect.top
            self.acc.y = self.vel.y = 0 # set acceleration and velocity to 0 on the y axis
            self.inJump = False
        if self.vel.y < 0: # check if a block is above
            if not self.tryingToJump: # if the block isn't trying to jump (I have this in otherwise player doesn't jump)
                print("above")
                self.rect.top = self.highestWall.rect.bottom
                self.acc.y = self.vel.y = 0 # set acceleration and velocity to 0 on the y axis
        if self.highestWall.rect.top < self.lowestWall.rect.top and self.rect.bottom == self.lowestWall.rect.top: # I have this line in too make sure that the player does not snap to the side of the block it is in when it moves side to side
            if self.vel.x > 0:
                print("right")
                self.rect.right = self.highestWall.rect.left
                self.acc.x = self.vel.x = -self.ACCEL # set acceleration and velocity to -0.5 on the x axis
            if self.vel.x < 0:
                print("left")
                self.rect.left = self.highestWall.rect.right
                self.acc.x = self.vel.x = self.ACCEL # set acceleration and velocity to 0.5 on the x axis


导入pygame、时间、设置
从pygame.locals导入*
vec=pygame.math.Vector2
pygame.init()
职业玩家(pygame.sprite.sprite):
加速度=0.5#加速度
GFRICTION=vec(-0.2,0)#地面摩擦力
F摩擦=矢量(-0.2,0)#空气摩擦
重力=0.8#必须大于0.6
跳跃高度=10
起点X=25
启动Y=600
宽度=10
高度=10
开始位置=向量(开始X+宽度/2,开始Y+高度)#点在底部中间
定义初始化(自):
pygame.sprite.sprite.\uuuuu init\uuuuuuu(自我)
self.Pos=self.START\u Pos
self.image=pygame.surface.surface((self.WIDTH,self.HEIGHT))
self.image.fill((0,255,0))
self.rect=self.image.get_rect()
self.rect.center=(self.Pos.x,self.Pos.y)
self.vel=vec(0,0)#将速度设置为向量
self.acc=vec(0,0)#将加速度设置为矢量
self.inJump=False
self.tryingToJump=False
def更新(自我):
self.tryingToJump=False
self.acc=vec(0,self.GRAVITY)
self.move()
def牵引(自):
#画矩形
自我位置+=自我水平+0.5*self.acc
self.rect.center=self.Pos
def移动(自我):
#确定按下了哪些键
按下按键=pygame.key.get_pressed()
如果按[左]键[左]:
self.changeX(“左”)
埃利夫按下[右]键:
self.changeX(“右”)
如果按下[K\U UP]键:
self.jump()
#检查播放机是否在屏幕上,如有必要,将播放机放置在应该的位置
如果self.Pos.y>Settings.WINDOW\u高度:
self.Pos.x=self.START\u Pos.x
self.Pos.y=self.START_Pos.y
如果自身位置x<0:
自我水平x=2
如果self.Pos.x>Settings.WINDOW\u宽度:
self.vel.x=-2
#施加摩擦力
如果自吸:#在空中
自加速x+=自加速x*自加速x
否则:#触地
self.acc.x+=self.vel.x*self.GFRICTION.x
#移动玩家
self.vel+=self.acc
def changeX(自身、方向):
#向左或向右移动
如果方向==“右”:
自加速x=自加速
elif方向==“左”:
self.acc.x=-self.ACCEL
def跳转(自):
#只有站在平台上才能跳
如果self.inJump==False:
self.tryingToJump=True
self.inJump=True
自升高度y-=自升高度
def checkCollisionWall(自身,点击):
self.lowestWall=self.highestWall=hits[0]
对于我在点击:
如果i.rect.bottom>self.lowerstwall.rect.bottom:
self.lowestWall=i#找到玩家触摸的最下面的墙
如果i.rect.top0:#检查下面是否有块
打印(“以下”)
self.rect.bottom=self.lowerstwall.rect.top
self.acc.y=self.vel.y=0#将y轴上的加速度和速度设置为0
self.inJump=False
如果self.vel.y<0:#检查块是否在上方
如果不是self.tryingToJump:#如果区块没有尝试跳跃(我有这个,否则玩家不会跳跃)
打印(“以上”)
self.rect.top=self.highestWall.rect.bottom
self.acc.y=self.vel.y=0#将y轴上的加速度和速度设置为0
如果self.highestWall.rect.top0:
打印(“右”)
self.rect.right=self.highestWall.rect.left
self.acc.x=self.vel.x=-self.ACCEL#在x轴上将加速度和速度设置为-0.5
如果自身水平x<0:
打印(“左”)
self.rect.left=self.highestWall.rect.right
self.acc.x=self.vel.x=self.ACCEL#将x轴上的加速度和速度设置为0.5
当我试着这样做的时候,玩家会很好地落在方块上,但是当他们触到方块底部时,玩家会跳到方块的顶部,而不是反弹。当玩家在进入区块时跳跃时,玩家会捕捉到较高区块的顶部。

根据我的经验(不太广泛),如果没有对每个维度分别测试玩家的移动,可能会出现此类问题

我建议你:

  • 分开x和y的移动和碰撞测试,这样你就可以沿着x移动你的玩家,测试碰撞并确定x的位置(如果需要),然后对y重复这个过程

  • 编辑
    checkCollisionWall
    方法,使其采用单个块,而不是块列表。若你们分开x和y的移动,玩家最多会碰撞一个方块。所以不需要搜索最低的墙和最高的墙。您的代码将更简单

  • 在这里,我建议您进行一些编辑<代码>移动已分为
    移动x
    移动y
    checkCollisionWall
    进入
    checkCollision\u x
    checkCollision\u y

    我还编辑了
    update
    方法:现在它完成了第1点中描述的整个过程,因此调用
    update
    也将检查冲突。

    def update(self): self.tryingToJump = False self.acc = vec(0, self.GRAVITY) self.move_x() hits = pygame.sprite.spritecollide(player, walls, False) for bhit in hits: player.checkCollision_x(bhit) self.move_y() hits = pygame.sprite.spritecollide(player, walls, False) for bhit in hits: player.checkCollision_y(bhit) def move_x(self): # identify which keys are pressed pressed_keys = pygame.key.get_pressed() if pressed_keys[K_LEFT]: self.changeX("left") elif pressed_keys[K_RIGHT]: self.changeX("right") # check player is on screen and place player where it should be if neccessary if self.Pos.x < 0: self.vel.x = 2 if self.Pos.x > Settings.WINDOW_WIDTH: self.vel.x = -2 # apply friction if self.inJump: #in the air self.acc.x += self.vel.x * self.AFRICTION.x else: #touching the ground self.acc.x += self.vel.x * self.GFRICTION.x # move the player self.vel.x += self.acc.x def move_y(self): # identify which keys are pressed pressed_keys = pygame.key.get_pressed() if pressed_keys[K_UP]: self.jump() # check player is on screen and place player where it should be if neccessary if self.Pos.y > Settings.WINDOW_HEIGHT: self.Pos.x = self.START_POS.x self.Pos.y = self.START_POS.y # move the player self.vel.y += self.acc.y def checkCollision_x(self, coll_block): if self.vel.x > 0: print("right") self.rect.right = coll_block.rect.left self.acc.x = self.vel.x = -self.ACCEL # set acceleration and velocity to -0.5 on the x axis elif self.vel.x < 0: print("left") self.rect.left = coll_block.rect.right self.acc.x = self.vel.x = self.ACCEL # set acceleration and velocity to 0.5 on the x axis def checkCollision_y(self, coll_block): if self.vel.y > 0: # check if a block is below print("below") self.rect.bottom = coll_block.rect.top self.acc.y = self.vel.y = 0 # set acceleration and velocity to 0 on the y axis self.inJump = False elif self.vel.y < 0: # check if a block is above if not self.tryingToJump: # if the block isn't trying to jump (I have this in otherwise player doesn't jump) print("above") self.rect.top = coll_block.rect.bottom self.acc.y = self.vel.y = 0 # set acceleration and velocity to 0 on the y axis