pygame坠落碰撞导致玩家振荡上下

我试图在pygame中创建一个下降的效果,但我被困在一个特定的问题。那就是当玩家跌倒并与平台相撞时,我的玩家阶层开始上下摆动。我确信这与我的更新循环有关,但我不确定它到底是什么。我已经尝试了几种方法,例如重新排列层次结构无济于事。我结束了在线搜索,但没有得到答案。所以,如果任何人都可以帮助我,我真的很感激它。pygame坠落碰撞导致玩家振荡上下

谢谢!

import pygame as pg 

import os

#vector

VEC = pg.math.Vector2

def paint(parent, color=None):

""" fills the background for surfaces.

color: for none sprite surfaces optional parameter if given

"""

#set background color based on surface type

if color:

#class based surfaces or sprites

background = pg.Color(color)

else:

#none sprite surfaces usuallly not class

background = pg.Color(parent.background)

#check for image attribure

#if found fill the image's backround

if hasattr(parent, "image"):

parent.image.fill(background)

#if "image" not found fill the surface itself

else:

parent.fill(background)

class Asset(pg.sprite.Sprite):

""" asset class functions as base class for various assets in this case

either a player asset or a block asset group """

#if the given family name(see bellow in constructor) is block,

#all instances of block will be added to this group else its ignored

GROUP = pg.sprite.Group()

def __init__(self, parent=None, family=None, pos=None):

"""

parent:surface asset is being rendered to

family:type of asset(type is not used due to it being a buil-in)

pos: position of asset

"""

super().__init__()

self.parent = parent

self.family = family

self.pos = VEC(pos)

self.size = [20, 20]

#background will be based on family

self.background = {"block":"#000000","player":"#ff0000"}[self.family]

self.image, self.rect = self.set_image()

#see class documention for explanation

if self.family == "block":

Asset.GROUP.add(self)

#if family is player add essential fields for physics

else:

#velocity

self.vel = VEC(3, 3)

#acceleration(x:friction, y:gravity)

self.ac = VEC(.3, .3)

#jump height

self.height = 5

def update(self):

if self.family == "player":

#fall code

self.vel.y += self.ac.y

self.pos.y += self.vel.y

#prevents player from falling of the edge and adds teleportation

if self.pos.x + self.size[0] <= 0:

self.pos.x = 399

elif self.pos.x >= 400:

self.pos.x = 1 - self.size[0]

#updates asset rect postion

self.rect.topleft = self.pos

def render(self):

""" renders image to parent surface """

self.parent.blit(self.image, self.rect)

def set_image(self):

"""creates initial image and rect for sprite"""

self.image = pg.Surface(self.size)

paint(self)

self.rect = self.image.get_rect()

self.rect.topleft = self.pos

return self.image, self.rect

def move(self, key):

"""handles player movmet"""

for i in range(2):

#checks for right or left movment

if key[[pg.K_LEFT, pg.K_RIGHT][i]]:

self.pos.x += self.vel.x*[-1, 1][i]

def jump(self):

""" handles jumping """

self.vel.y = -self.height

def block_collision(player, blocks):

"""collision detection between blocks and player"""

hit = pg.sprite.spritecollide(player, blocks, False)

if hit:

if player.rect.bottom >= hit[0].rect.top:

player.pos.y = hit[0].rect.top - hit[0].rect.height

player.vel.y = 0

def main():

POS = [0, 0]

SIZE = [400, 400]

TITLE = "Test"

BACKGROUND = "#ffffff"

CLOCK = pg.time.Clock()

FPS = 60

RUN = True

os.environ["SDL_VIDEO_CENTERED"] = "1"

win = pg.display.set_mode(SIZE)

pg.display.set_caption(TITLE)

# create blocks group

#NOTE:blocks do not need a variable instance because they are

#automatically added to the class group on construction

for x in range(20):

Asset(family="block", pos=[x*20, 380])

#set player filed

player = Asset(win, family="player", pos=[20, 20])

while RUN:

for event in pg.event.get():

if event.type == pg.QUIT:

RUN = False

elif event.type == pg.KEYDOWN:

if event.key == pg.K_UP:

#player jump

player.jump()

#player movement

player.move(pg.key.get_pressed())

#fill window background

paint(win, BACKGROUND)

#check for collision

block_collision(player, Asset.GROUP)

#update player

player.update()

#update block group

Asset.GROUP.update()

#render player

player.render()

#render block group

Asset.GROUP.draw(win)

pg.display.update()

CLOCK.tick(FPS)

if __name__ == '__main__':

main()

回答:

有两个失误一起给问题

第一:

player.pos.y = hit[0].rect.top - hit[0].rect.height 

这是没有意义的。 top - height给同bottom所以你必须

player.pos.y = hit[0].rect.bottom 

但你需要hit[0].rect.topplayer.rect.bottom

player.rect.bottom = hit[0].rect.top 

player.pos.y = player.rect.y

(这里我不知道为什么你使用player.pos,如果它总是具有相同的值player.rect ,并且rect有许多有用的字段,如rect.bottom,rect.center等,并且当您更改rect.bottom,rect.center等时,它会自动重新计算rect.x,rect.y

所以第一校正

if hit: 

if player.rect.bottom >= hit[0].rect.top:

#player.pos.y = hit[0].rect.top - hit[0].rect.height

player.rect.bottom = hit[0].rect.top

player.pos.y = player.rect.y

player.vel.y = 0

二:

你应该尽一切举动检查collisionts

# player movement 

player.move(pg.key.get_pressed())

# update player

player.update()

#update block group

Asset.GROUP.update()

# check for collision - after all moves

block_collision(player, Asset.GROUP)


的完整代码

import pygame as pg 

import os

#vector

VEC = pg.math.Vector2

def paint(parent, color=None):

""" fills the background for surfaces.

color: for none sprite surfaces optional parameter if given

"""

#set background color based on surface type

if color:

#class based surfaces or sprites

background = pg.Color(color)

else:

#none sprite surfaces usuallly not class

background = pg.Color(parent.background)

#check for image attribure

#if found fill the image's backround

if hasattr(parent, "image"):

parent.image.fill(background)

#if "image" not found fill the surface itself

else:

parent.fill(background)

class Asset(pg.sprite.Sprite):

""" asset class functions as base class for various assets in this case

either a player asset or a block asset group """

#if the given family name(see bellow in constructor) is block,

#all instances of block will be added to this group else its ignored

GROUP = pg.sprite.Group()

def __init__(self, parent=None, family=None, pos=None):

"""

parent:surface asset is being rendered to

family:type of asset(type is not used due to it being a buil-in)

pos: position of asset

"""

super().__init__()

self.parent = parent

self.family = family

self.pos = VEC(pos)

self.size = [20, 20]

#background will be based on family

self.background = {"block":"#000000","player":"#ff0000"}[self.family]

self.image, self.rect = self.set_image()

#see class documention for explanation

if self.family == "block":

Asset.GROUP.add(self)

#if family is player add essential fields for physics

else:

#velocity

self.vel = VEC(3, 3)

#acceleration(x:friction, y:gravity)

self.ac = VEC(.3, .3)

#jump height

self.height = 5

def update(self):

if self.family == "player":

#fall code

self.vel.y += self.ac.y

self.pos.y += self.vel.y

#prevents player from falling of the edge and adds teleportation

if self.pos.x + self.size[0] <= 0:

self.pos.x = 399

elif self.pos.x >= 400:

self.pos.x = 1 - self.size[0]

#updates asset rect postion

self.rect.topleft = self.pos

def render(self):

""" renders image to parent surface """

self.parent.blit(self.image, self.rect)

def set_image(self):

"""creates initial image and rect for sprite"""

self.image = pg.Surface(self.size)

paint(self)

self.rect = self.image.get_rect()

self.rect.topleft = self.pos

return self.image, self.rect

def move(self, key):

"""handles player movmet"""

for i in range(2):

#checks for right or left movment

if key[[pg.K_LEFT, pg.K_RIGHT][i]]:

self.pos.x += self.vel.x*[-1, 1][i]

def jump(self):

""" handles jumping """

self.vel.y = -self.height

def block_collision(player, blocks):

"""collision detection between blocks and player"""

hit = pg.sprite.spritecollide(player, blocks, False)

if hit:

if player.rect.bottom >= hit[0].rect.top:

#player.pos.y = hit[0].rect.top - hit[0].rect.height

player.rect.bottom = hit[0].rect.top

player.pos.y = player.rect.y

player.vel.y = 0

def main():

POS = [0, 0]

SIZE = [400, 400]

TITLE = "Test"

BACKGROUND = "#ffffff"

CLOCK = pg.time.Clock()

FPS = 60

RUN = True

os.environ["SDL_VIDEO_CENTERED"] = "1"

win = pg.display.set_mode(SIZE)

pg.display.set_caption(TITLE)

# create blocks group

#NOTE:blocks do not need a variable instance because they are

#automatically added to the class group on construction

for x in range(20):

Asset(family="block", pos=[x*20, 380])

#set player filed

player = Asset(win, family="player", pos=[20, 20])

while RUN:

# --- events ---

for event in pg.event.get():

if event.type == pg.QUIT:

RUN = False

elif event.type == pg.KEYDOWN:

if event.key == pg.K_UP:

#player jump

player.jump()

#player movement

player.move(pg.key.get_pressed())

# --- updates --

#update player

player.update()

#update block group

Asset.GROUP.update()

#check for collision

block_collision(player, Asset.GROUP)

# --- draws ---

#fill window background

paint(win, BACKGROUND)

#render player

player.render()

#render block group

Asset.GROUP.draw(win)

pg.display.update()

CLOCK.tick(FPS)

# ---- end ---

pg.quit()

if __name__ == '__main__':

main()

以上是 pygame坠落碰撞导致玩家振荡上下 的全部内容, 来源链接: utcz.com/qa/259059.html

回到顶部