微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

与 pygame 冲突作斗争

如何解决与 pygame 冲突作斗争

我正在为 pygame sonic clone 编写一些代码,但我正在努力解决瓷砖碰撞问题。各种bug不断出现。例如,一个错误是当玩家与瓷砖的矩形发生碰撞时,它看起来像是在振动。我的运动涉及使用向量,我的一些值是浮点数。我认为这是问题所在,因为浮动会导致各种奇怪的错误。不管怎样,你怎么看?是否有可能发生适当的碰撞?

Main.py

from settings import *
from sprites import *
import pygame

pygame.init()
pygame.mixer.init()

clock = pygame.time.Clock()
running = True


window = pygame.display.set_mode((WIDTH,HEIGHT))

# initialise camera
camera = Camera(WIDTH,HEIGHT)


# player sprites
s = Sonic()
player = pygame.sprite.Group()

# floor sprites
ground = Ground(0,HEIGHT - 50,GROUND)
floor = pygame.sprite.Group()
floor.add(ground)

# platform sprites

platforms = [Platform(WIDTH + 200,HEIGHT - 100,SMALL)]

plats = pygame.sprite.Group()

platx = 100 

platy = 50


for i in platforms:
    plats.add(i)
    

# all sprites
sprites = pygame.sprite.Group()
sprites.add(s)
sprites.add(plats)
sprites.add(ground)

# Todo: figure out a way to blit the camera (done)

while running:
    clock.tick(FPS)

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

    # update
    if s.vel.y > 0:
        collisions = pygame.sprite.spritecollide(s,floor,False)

        if collisions:
            for collision in collisions:
                # Todo: create different classes of platforms each with their own collision properties (done)
                if s.pos.y > collision.rect.top: 
                    s.vel.y = (s.vel.y - 0.6)
                    s.pos.y = collision.rect.top
                    
                
    
    # Todo: figure out how to reset x vel when jumping
    
    if s.vel.x > 0:
        hits = pygame.sprite.spritecollide(s,plats,False)
        
        if hits:
            for hit in hits:
                if s.pos.x > hit.rect.left and s.pos.x < hit.rect.right:
                    s.vel.x = 0
                    s.pos.x = (hit.rect.left - 30)
                    
    if s.vel.x < 0:
        hits = pygame.sprite.spritecollide(s,False)

        if hits:
            for hit in hits:
                if s.pos.x < hit.rect.right and s.pos.x > hit.rect.left:
                    s.vel.x = 0
                    s.pos.x = (hit.rect.right + 30)
    
    if s.vel.y > 0:
        s.vel.x = 0
        s.vel.y = 0
        hits = pygame.sprite.spritecollide(s,False)

        if hits:
            for hit in hits:
                if s.pos.y > hit.rect.top:
                    s.vel.y = 0
                    s.pos.y = hit.rect.top
    
    if s.vel.y < 0:
        if s.vel.x > 0 and s.vel.x < 0:
            s.vel.x = 0
        hits = pygame.sprite.spritecollide(s,False)

        if hits:
            for hit in hits:
                if s.pos.y < hit.rect.bottom:
                    s.vel.x = 0
                    s.vel.y = 0
                    s.pos.y = hit.rect.bottom
    


                
                # if s.vel.x < 0:
                #     s.rect.left = hits[0].rect.right
                #     s.vel.x = 0
                # if s.vel.y < 0:
                #     s.rect.top = hits[0].rect.bottom
                #     s.vel.y = 0
                # if s.vel.y > 0:
                #     s.rect.bottom = hits[0].rect.top
                #     s.vel.y = 0
            

    
        
    # if s.pos.x > WIDTH:
    #     for plat in plats.sprites():
    #         plat.rect.x -= max(abs(s.vel.x),2)
    #         # set locations for each platform
    #         # set the camera to follow sonic so that he doesn't disappear off the screen
    #         print("poop")

    print(s.vel)
    
    sprites.update()
    camera.update(s)

    # draw
    window.fill(BLACK)
    
    for sprite in sprites:
        window.blit(sprite.image,camera.apply(sprite))
    
    

#Todo: Create a way to dynamically generate platforms

    # double buffering 
    pygame.display.flip()

sprites.py

import pygame
from settings import *

vec = pygame.math.Vector2

class Sonic(pygame.sprite.Sprite):
    
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.Surface((50,50))
        self.image.fill(BLUE)
        self.rect = self.image.get_rect()
        self.rect.center = (WIDTH / 2,HEIGHT - 51)
        self.pos = vec(WIDTH / 2,HEIGHT - 51)
        self.vel = vec(0,0)
        self.acc = vec(0,0)
        self.last_update = 0
        self.time_passed = 0
        

    def update(self):
        self.acc = vec(0,GraviTY)
        keys = pygame.key.get_pressed()
        if keys[pygame.K_LEFT]:
            self.acc.x = -ACCEL - 2
            self.faster()
        if keys[pygame.K_RIGHT]:
            self.acc.x = ACCEL
            self.faster()
        if keys[pygame.K_UP]:
            self.acc.y = -ACCEL
                    
       
       # friction check
        self.acc.x += self.vel.x * FRICTION
        if self.vel.x < -2:
            self.vel.x = -2

       # equations of motion
        self.vel += self.acc
        self.pos += self.vel + 0.5 * self.acc

        # if self.pos.x > WIDTH:
        #     self.pos.x = 0
        # if self.pos.x < 0:
        #     self.pos.x = WIDTH

        self.rect.midbottom = self.pos

    # sonic speed feature - get faster after running for x amount of time
    def faster(self):
        Now = pygame.time.get_ticks()
        if Now - self.last_update > FASTER_TIME:
            self.time_passed += (Now - self.last_update)
            self.acc.x /= 0.5 # player becomes 50% faster
            if self.time_passed >= 3000:
                self.acc.x /= 0.75
            
class Ground(pygame.sprite.Sprite):

    def __init__(self,x,y,plat):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.Surface((GROUND))
        self.image.fill(GREEN)
        self.rect = self.image.get_rect()
        self.rect.x = x
        self.rect.y = y
        


class Platform(pygame.sprite.Sprite):

    def __init__(self,plat):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.Surface((plat))
        self.image.fill(GREEN)
        self.rect = self.image.get_rect()
        self.rect.x = x 
        self.rect.y = y

# creates a camera that follows the player
class Camera():
    def __init__(self,width,height):
        self.camera = pygame.Rect(0,height)
        self.width = width
        self.height = height
    
    # set the camera's focus - offset then applied to above Rect
    def apply(self,entity):
        return entity.rect.move(self.camera.topleft) # move by current camera's (0,0) and returns a new rect
    
    # update the camera's position
    def update(self,target):
        x = -target.rect.x + int(WIDTH / 2) # keeps player centered
        y = -target.rect.y + int(HEIGHT - 50) # keeps player centered
 
        x = min(0,x) # ensure camera doesn't go off the screen
        y = min(0,y)

        self.camera = pygame.Rect(x,self.width,self.height)

settings.py

# game properties
WIDTH = 800
HEIGHT = 600
FPS = 60

# colors
BLACK = (0,0)
WHITE = (255,255,255)
BLUE = (0,255)
GREEN = (0,0)
RED = (255,0)

# physics
GraviTY = 0.2
ACCEL = 1
FRICTION = -0.12
FASTER_TIME = 2000

# Platform properties
SMALL = (100,50)
MEDIUM = (20000,200)
GROUND = (100000,100)

# Player properties
HALF_P_WIDTH = 25
PREVIoUS_POS = [0,0]

解决方法

解决抖动需要做三件事:

  1. 在碰撞测试之前移动播放器并更新对象 (sprites.update())。
  2. 在检测到碰撞并且 rect 属性发生变化时更新 pos 属性:
  3. 当玩家站在地面或平台上时,将 vel.y 设置为 0

例如:

while running:
    clock.tick(FPS)

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

    sprites.update()                              # 1. update

    if s.vel.y > 0:
        collisions = pygame.sprite.spritecollide(s,floor,False)
        for collision in collisions:
            if s.pos.y > collision.rect.top: 
                s.pos.y = collision.rect.top
                s.rect.bottom = s.pos.y           # 2. set rect.bottom = s.pos.y
                s.vel.y = 0                       # 3. set vel.y = 0

    
    # [...]

    camera.update(s)

    # draw
    window.fill(BLACK)
    
    for sprite in sprites:
        window.blit(sprite.image,camera.apply(sprite))

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。