Как заставить спрайт перестать ускоряться после столкновения со стеной? - PullRequest
1 голос
/ 27 мая 2020

Создание платформенной игры и ожидание, что спрайт столкнется со стеной и будет выровнен с верхом стены, и не будет ускоряться через стену, но в момент столкновения со стеной он медленно проникает сквозь стену, после тестирования он Показано, что во время опускания часть фактически не сталкивается со стеной. На данный момент я сосредоточился только на гравитации и оси 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()

Ответы [ 2 ]

1 голос
/ 28 мая 2020

Просто установите переменные self.vel и self.a cc на ve c (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

0 голосов
/ 28 мая 2020

Измените положение игрока перед оценкой столкновений. Если игрок сталкивается, вам нужно обновить self.rect и синхронизировать self.pos с self.rect.center. Для instnace:

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...