如何解决与 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]
解决方法
解决抖动需要做三件事:
- 在碰撞测试之前移动播放器并更新对象 (
sprites.update()
)。 - 在检测到碰撞并且
rect
属性发生变化时更新pos
属性: - 当玩家站在地面或平台上时,将
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 举报,一经查实,本站将立刻删除。