如何让精灵在撞墙后停止加速?

2024-09-30 14:37:11 发布

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

制作一个平台游戏,期望精灵与墙壁碰撞,并与墙壁顶部对齐,不会加速穿过墙壁,但当它与墙壁碰撞时,它会慢慢穿过墙壁,测试后,它显示在下沉部分,它实际上不会与墙壁碰撞。现在我只关注重力和y轴

import os
import pygame
import time
import random
vec = pygame.math.Vector2

class player(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()
        self.image=pygame.image.load("rectmo.png").convert_alpha()
        self.image=pygame.transform.scale(self.image, (25,100))
        self.rect = self.image.get_rect()
        self.rect.center = (width/2,height/2)
        self.pos = vec(width/2,height/2)
        self.vel = vec(0,0)
        self.acc = vec(0,0)

    def update(self):

        user_input=pygame.key.get_pressed()

        if user_input[pygame.K_d]:
            self.acc.x=player_acc
        if user_input[pygame.K_a]:
            self.acc.x=-player_acc

        for wall in walls:
            if self.rect.colliderect(wall.rect)==True:
                if self.acc.x > 0:
                    self.rect.right=wall.rect.left
                    self.vel.x=0
                if self.acc.x < 0:
                    self.rect.left=wall.rect.right                    
                    self.vel.x=0
                if self.acc.y > 0:
                    self.rect.bottom=wall.rect.top
                    self.acc.y=0
                    self.vel.y=0
                if self.pos.y < 0:
                    self.rect.top=wall.rect.bottom
                    self.acc.y=0
            if self.rect.colliderect(wall.rect)==False:
                #gravity
                self.acc = vec(0,0.5)


        #adds Friction    
        self.acc.x += self.vel.x * player_friction
        #applying accelerating equation
        self.vel += self.acc
        self.pos += self.vel + 0.5 * self.acc
        self.rect.center = self.pos

我不知道我造墙的方式是否有问题,所以我就把它留在这里

class Wall(object):
    def __init__(self,wx,wy):
        walls.append(self)
        self.rect= pygame.Rect(wx,wy,30,30)
    def reset_wall(self):
        self.active = False

walls=[]

levels= [['WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW',
   'W  E                                         W',
   'W                                            W',
   'W                                            W',
   'W                                            W',
   'W                                            W',
   'W                                            W',
   'W                                            W',
   'W                                            W',
   'W                                            W',
   'W             W                              W',
   'W             W                              W',
   'W             W                              W',
   'W             W                 W            W',
   'W             W                 W            W',
   'W             W                 W            W',
   'W             W                 W            W',
   'W             WWWWWWWWWWWWWWWWWWW            W',
   'W                                            W',
   'W                                            W',
   'W                                            W',
   'W                                            W',
   'W                                            W',
   'W                                            W',
   'W                                            W',
   'WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW',
 ]]

x=y=0
level=random.choice(levels)
for row in level:
    for col in row:
        if col=='W':
            Wall(x,y)
        if col=='E':
            end_rect=pygame.Rect(x,y,30,30)
        x += 30
    y+=30
    x=0

以下是测试的全部代码:

import os
import pygame
import time
import random
vec = pygame.math.Vector2

class player(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()
        self.image=pygame.image.load("rectmo.png").convert_alpha()
        self.image=pygame.transform.scale(self.image, (25,100))
        self.rect = self.image.get_rect()
        self.rect.center = (width/2,height/2)
        self.pos = vec(width/2,height/2)
        self.vel = vec(0,0)
        self.acc = vec(0,0)

    def update(self):

        user_input=pygame.key.get_pressed()

        if user_input[pygame.K_d]:
            self.acc.x=player_acc
        if user_input[pygame.K_a]:
            self.acc.x=-player_acc

        for wall in walls:
            if self.rect.colliderect(wall.rect)==True:
                if self.acc.x > 0:
                    self.rect.right=wall.rect.left
                    self.vel.x=0
                if self.acc.x < 0:
                    self.rect.left=wall.rect.right
                    self.vel.x=0
                if self.acc.y > 0:
                    self.rect.bottom=wall.rect.top
                    self.vel.y=0
                if self.pos.y < 0:
                    self.rect.top=wall.rect.bottom
                    self.vel.y=0
            if self.rect.colliderect(wall.rect)==False:
                self.acc = vec(0,0.5)


        #adds Friction    
        self.acc.x += self.vel.x * player_friction
        #applying accelerating equation
        self.vel += self.acc
        self.pos += self.vel + 0.5 * self.acc
        self.rect.center = self.pos




class Wall(object):
    def __init__(self,wx,wy):
        walls.append(self)
        self.rect= pygame.Rect(wx,wy,30,30)
    def reset_wall(self):
        self.active = False


os.environ['SDL_VIDEO_CENTERED'] = '1'
pygame.init()

pygame.display.set_caption('A Game')
width = 1366
height= 768
screen=pygame.display.set_mode((width,height))

clock = pygame.time.Clock()
walls=[]
player_acc=0.5
player_friction=-0.05
rectmo=player()

rectmo.rect.x=500
rectmo.rect.y=400
main_colour=(0,0,0)
colour=main_colour
wall_colour=(255,255,255)
current_score=0

levels= [['WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW',
   'W  E                                         W',
   'W                                            W',
   'W                                            W',
   'W                                            W',
   'W                                            W',
   'W                                            W',
   'W                                            W',
   'W                                            W',
   'W                                            W',
   'W             W                              W',
   'W             W                              W',
   'W             W                              W',
   'W             W                 W            W',
   'W             W                 W            W',
   'W             W                 W            W',
   'W             W                 W            W',
   'W             WWWWWWWWWWWWWWWWWWW            W',
   'W                                            W',
   'W                                            W',
   'W                                            W',
   'W                                            W',
   'W                                            W',
   'W                                            W',
   'W                                            W',
   'WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW',
 ]]

x=y=0
level=random.choice(levels)
for row in level:
    for col in row:
        if col=='W':
            Wall(x,y)
        if col=='E':
            end_rect=pygame.Rect(x,y,30,30)
        x += 30
    y+=30
    x=0

running=True

while running==True:
    clock.tick(60)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
    rectmo.update()










    if running==True:
        screen.fill(main_colour)
        for wall in walls:
            pygame.draw.rect(screen, wall_colour,wall.rect)
        pygame.draw.rect(screen,(255,0,0),end_rect)
        pygame.draw.rect(screen,colour,rectmo.rect)

        all_sprites_list = pygame.sprite.Group()
        all_sprites_list.add(rectmo)
        all_sprites_list.draw(screen)
        pygame.display.flip()


Tags: posrectimageimportselfforifdef
2条回答

在评估碰撞之前,更改玩家的位置。 如果播放器发生冲突,则必须更新self.rect,并且必须将self.pos同步到self.rect.center。对于Instance:

if self.val.x > 0:
    self.rect.right=wall.rect.left
    self.vel.x=0
    self.pos = vec(self.rect.center)

通过测试玩家是否会与墙相交(如果他位于下方1个像素处),评估玩家是否停留在地面上:

test_rect = pygame.Rect(self.rect.x, self.rect.y+1, self.rect.width, self.rect.height) 
if test_rect.colliderect(wall.rect):
   on_ground = True

根据状态设置y方向上的加速度on_ground

if on_ground:
    self.acc.y = 0
elif self.acc.y == 0:
    self.acc.y = 0.5

方法update

class player(pygame.sprite.Sprite):
    # [...]

    def update(self):

        user_input=pygame.key.get_pressed()

        self.acc.x = 0
        if user_input[pygame.K_d]:
            self.acc.x=player_acc
        if user_input[pygame.K_a]:
            self.acc.x=-player_acc

        self.vel.x = self.vel.x * 0.95 + self.acc.x
        self.vel.y += self.acc.y
        self.pos += self.vel
        self.rect.center = self.pos

        on_ground = False
        for wall in walls:
            if self.rect.colliderect(wall.rect)==True:
                if self.vel.x > 0:
                    self.rect.right=wall.rect.left
                    self.vel.x=0
                    self.pos = vec(self.rect.center)
                if self.vel.x < 0:
                    self.rect.left=wall.rect.right
                    self.vel.x=0
                    self.pos = vec(self.rect.center)
                if self.vel.y > 0:
                    self.rect.bottom=wall.rect.top
                    self.vel.y=0
                    self.pos = vec(self.rect.center)
                if self.vel.y < 0:
                    self.rect.top=wall.rect.bottom
                    self.vel.y=0
                    self.pos = vec(self.rect.center)

            test_rect = pygame.Rect(self.rect.x, self.rect.y+1, self.rect.width, self.rect.height) 
            if test_rect.colliderect(wall.rect):
                on_ground = True

        if on_ground:
            self.acc.y = 0
        elif self.acc.y == 0:
            self.acc.y = 0.5

只要在精灵与墙碰撞时将self.vel和self.acc变量设置为vec(0,0)。应该可以了。。。希望这有帮助

为避免位置重叠:

main_loop():
    move_sprite()
    r = mySprite.rect
    if r.colliderect(myWall.rect):
        mySprite.vel, mySprite.acc = vec(0, 0), vec(0, 0)
        # Test which wall he is hitting:
        left = [r.topleft, r.midleft, r.bottomleft]
        for point in left:
            if myWall.rect.collideppoint(point):
                r.left = myWall.rect.right  # Sets the sprite outside of the wall
    pygame.display.flip()

这应该行得通。确保在测试墙碰撞之前移动精灵。否则,您可能会遇到一些小故障,精灵会进进出出墙。我只编写了测试左侧墙的代码,但您可以在pygame文档中找到所需的任何内容:

https://www.pygame.org/docs/ref/rect.html

相关问题 更多 >