python - 用pygame蹲在python平台游戏中
问题描述
我正在为我的 python/pygame 类中的最终项目制作游戏。我遇到了“蹲伏”能力的问题。我希望能够改变播放器的大小,但目前唯一改变的是顶部的精灵。
我的班级正在使用此站点中的这个特定示例:
我如何缩放或更改播放器的大小以适应精灵,并能够在我“松开”时将其更改回来?
不确定哪些部分是相关的,但这是我的代码(我为它如此 frankenstein-y 道歉):
class Bink(pygame.sprite.Sprite):
""" This class represents the bar at the bottom that the player
controls. """
# -- Methods
def __init__(self):
""" Constructor function """
# Call the parent's constructor
super().__init__()
# -- Attributes
# Set speed vector of player
self.change_x = 0
self.change_y = 0
# Set fall rate
self.y_speedup = .45
# Double jump functions
self.jump_no = 0
# Set the players height and length
self.length = 40
self.height = 60
# Set crouching to false
self.crouching = False
# This holds all the images for the animated walk left/right
# of our player
self.walking_frames_l = []
self.walking_frames_r = []
self.standing_frames_l = []
self.standing_frames_r = []
self.jumping_frames_l = []
self.jumping_frames_r = []
self.falling_frames_l = []
self.falling_frames_r = []
self.crouching_frames_l = []
self.crouching_frames_r = []
# What direction is the player facing?
self.direction = "Right"
# What 'state' is the player in
self.state = "Stand"
# List of sprites we can bump against
self.level = None
sprite_sheet = SpriteSheet("player_sprite_sheet.png")
# Load all the right walking images into a list
image = sprite_sheet.get_image(419, 65, 40, 60)
self.walking_frames_r.append(image)
image = sprite_sheet.get_image(460, 65, 40, 60)
self.walking_frames_r.append(image)
image = sprite_sheet.get_image(501, 65, 40, 60)
self.walking_frames_r.append(image)
image = sprite_sheet.get_image(542, 65, 40, 60)
self.walking_frames_r.append(image)
image = sprite_sheet.get_image(583, 65, 40, 60)
self.walking_frames_r.append(image)
image = sprite_sheet.get_image(624, 65, 40, 60)
self.walking_frames_r.append(image)
image = sprite_sheet.get_image(665, 65, 40, 60)
self.walking_frames_r.append(image)
image = sprite_sheet.get_image(706, 65, 40, 60)
self.walking_frames_r.append(image)
image = sprite_sheet.get_image(747, 65, 40, 60)
self.walking_frames_r.append(image)
image = sprite_sheet.get_image(788, 65, 40, 60)
self.walking_frames_r.append(image)
# Load all the left walking images
image = sprite_sheet.get_image(419, 0, 40, 60)
self.walking_frames_l.append(image)
image = sprite_sheet.get_image(460, 0, 40, 60)
self.walking_frames_l.append(image)
image = sprite_sheet.get_image(501, 0, 40, 60)
self.walking_frames_l.append(image)
image = sprite_sheet.get_image(542, 0, 40, 60)
self.walking_frames_l.append(image)
image = sprite_sheet.get_image(583, 0, 40, 60)
self.walking_frames_l.append(image)
image = sprite_sheet.get_image(624, 0, 40, 60)
self.walking_frames_l.append(image)
image = sprite_sheet.get_image(665, 0, 40, 60)
self.walking_frames_l.append(image)
image = sprite_sheet.get_image(706, 0, 40, 60)
self.walking_frames_l.append(image)
image = sprite_sheet.get_image(747, 0, 40, 60)
self.walking_frames_l.append(image)
image = sprite_sheet.get_image(788, 0, 40, 60)
self.walking_frames_l.append(image)
# Load all the left standing sprites
image = sprite_sheet.get_image(0, 0, 40, 60)
self.standing_frames_l.append(image)
# Load all the right standing sprites
image = sprite_sheet.get_image(419, 195, 40, 60)
self.standing_frames_r.append(image)
# Load all the left jumping sprites
image = sprite_sheet.get_image(0, 65, 40, 60)
self.jumping_frames_l.append(image)
image = sprite_sheet.get_image(41, 65, 40, 60)
self.jumping_frames_l.append(image)
image = sprite_sheet.get_image(82, 65, 40, 60)
self.jumping_frames_l.append(image)
image = sprite_sheet.get_image(123, 65, 40, 60)
self.jumping_frames_l.append(image)
image = sprite_sheet.get_image(164, 65, 40, 60)
self.jumping_frames_l.append(image)
image = sprite_sheet.get_image(205, 65, 40, 60)
self.jumping_frames_l.append(image)
image = sprite_sheet.get_image(246, 65, 40, 60)
self.jumping_frames_l.append(image)
image = sprite_sheet.get_image(287, 65, 40, 60)
self.jumping_frames_l.append(image)
image = sprite_sheet.get_image(328, 65, 40, 60)
self.jumping_frames_l.append(image)
image = sprite_sheet.get_image(369, 65, 40, 60)
self.jumping_frames_l.append(image)
# Load all the right jumping sprites
image = sprite_sheet.get_image(419, 130, 40, 60)
self.jumping_frames_r.append(image)
image = sprite_sheet.get_image(460, 130, 40, 60)
self.jumping_frames_r.append(image)
image = sprite_sheet.get_image(501, 130, 40, 60)
self.jumping_frames_r.append(image)
image = sprite_sheet.get_image(542, 130, 40, 60)
self.jumping_frames_r.append(image)
image = sprite_sheet.get_image(583, 130, 40, 60)
self.jumping_frames_r.append(image)
image = sprite_sheet.get_image(624, 130, 40, 60)
self.jumping_frames_r.append(image)
image = sprite_sheet.get_image(665, 130, 40, 60)
self.jumping_frames_r.append(image)
image = sprite_sheet.get_image(706, 130, 40, 60)
self.jumping_frames_r.append(image)
image = sprite_sheet.get_image(747, 130, 40, 60)
self.jumping_frames_r.append(image)
image = sprite_sheet.get_image(788, 130, 40, 60)
self.jumping_frames_r.append(image)
# Load all left falling sprites
image = sprite_sheet.get_image(0, 130, 40, 60)
self.falling_frames_l.append(image)
image = sprite_sheet.get_image(41, 130, 40, 60)
self.falling_frames_l.append(image)
image = sprite_sheet.get_image(82, 130, 40, 60)
self.falling_frames_l.append(image)
image = sprite_sheet.get_image(123, 130, 40, 60)
self.falling_frames_l.append(image)
image = sprite_sheet.get_image(164, 130, 40, 60)
self.falling_frames_l.append(image)
# Load all right falling sprites
image = sprite_sheet.get_image(205, 130, 40, 60)
self.falling_frames_r.append(image)
image = sprite_sheet.get_image(246, 130, 40, 60)
self.falling_frames_r.append(image)
image = sprite_sheet.get_image(287, 130, 40, 60)
self.falling_frames_r.append(image)
image = sprite_sheet.get_image(328, 130, 40, 60)
self.falling_frames_r.append(image)
image = sprite_sheet.get_image(369, 130, 40, 60)
self.falling_frames_r.append(image)
# Load all the left crouching sprites
image = sprite_sheet.get_image(0, 195, 45, 40)
self.crouching_frames_l.append(image)
image = sprite_sheet.get_image(46, 195, 45, 40)
self.crouching_frames_l.append(image)
image = sprite_sheet.get_image(92, 195, 45, 40)
self.crouching_frames_l.append(image)
image = sprite_sheet.get_image(138, 195, 45, 40)
self.crouching_frames_l.append(image)
image = sprite_sheet.get_image(184, 195, 45, 40)
self.crouching_frames_l.append(image)
# Load all right crouching sprites
image = sprite_sheet.get_image(0, 240, 45, 40)
self.crouching_frames_r.append(image)
image = sprite_sheet.get_image(46, 240, 45, 40)
self.crouching_frames_r.append(image)
image = sprite_sheet.get_image(92, 240, 45, 40)
self.crouching_frames_r.append(image)
image = sprite_sheet.get_image(138, 240, 45, 40)
self.crouching_frames_r.append(image)
image = sprite_sheet.get_image(184, 240, 45, 40)
self.crouching_frames_r.append(image)
# Set the image the player starts with
self.image = self.standing_frames_r[0]
# Set a reference to the image rect.
self.rect = self.image.get_rect()
# Build a hitbox that objects collide with
self.hitbox = self.rect.inflate(0, 0)
# Add or subtract to see if the player is crouching
self.is_crouching = 0
def update(self):
""" Move the player. """
# Gravity
self.calc_grav()
# Set the hitbox on top of the player
self.hitbox.center = self.rect.center
# Check for the direction
if self.change_x < 0:
self.direction = "Left"
elif self.change_x > 0:
self.direction = "Right"
# Check for the state
# See if we hit anything
self.rect.y += 2
platform_hit_list = pygame.sprite.spritecollide(self, self.level.platform_list, False)
self.rect.y -= 2
# If it is ok to jump, set our speed upwards
if len(platform_hit_list) > 0 or self.hitbox.bottom >= SCREEN_HEIGHT and self.change_x == 0:
self.state = "Stand"
elif len(platform_hit_list) > 0 or self.hitbox.bottom >= SCREEN_HEIGHT and self.change_x != 0:
self.state = "Walk"
elif self.change_y < 0 or self.change_y < 0 and self.change_x != 0:
self.state = "Jump"
elif self.change_y > 0 or self.change_y > 0 and self.change_x != 0:
self.state = "Fall"
if self.is_crouching == 1:
self.state = "Crouch"
# Move left/right
self.rect.x += self.change_x
x_pos = self.rect.x + self.level.world_shift
y_pos = self.rect.y + self.level.world_shift
# "If" in 'this' state and 'this' direction use 'that' sprite list for reference
if self.direction == "Right" and self.state == "Stand":
frame = (x_pos // 30) % len(self.standing_frames_r)
self.image = self.standing_frames_r[frame]
elif self.direction == "Left" and self.state == "Stand":
frame = (x_pos // 30) % len(self.standing_frames_l)
self.image = self.standing_frames_l[frame]
elif self.direction == "Right" and self.state == "Walk":
frame = (x_pos // 30) % len(self.walking_frames_r)
self.image = self.walking_frames_r[frame]
elif self.direction == "Left" and self.state == "Walk":
frame = (x_pos // 30) % len(self.walking_frames_l)
self.image = self.walking_frames_l[frame]
elif self.direction == "Right" and self.state == "Jump":
frame = (y_pos // 30) % len(self.jumping_frames_r)
self.image = self.jumping_frames_r[frame]
elif self.direction == "Left" and self.state == "Jump":
frame = (y_pos // 30) % len(self.jumping_frames_l)
self.image = self.jumping_frames_l[frame]
elif self.direction == "Right" and self.state == "Fall":
frame = (y_pos // 30) % len(self.falling_frames_r)
self.image = self.falling_frames_r[frame]
elif self.direction == "Left" and self.state == "Fall":
frame = (y_pos // 30) % len(self.falling_frames_l)
self.image = self.falling_frames_l[frame]
elif self.direction == "Right" and self.state == "Crouch":
frame = (x_pos // 30) % len(self.crouching_frames_r)
self.rect.inflate(5, -20)
# if self.length != 40:
# self.rect.inflate(0, 0)
self.image = self.crouching_frames_r[frame]
elif self.direction == "Left" and self.state == "Crouch":
frame = (x_pos // 30) % len(self.crouching_frames_l)
self.image = self.crouching_frames_l[frame]
# See if we hit anything
block_hit_list = pygame.sprite.spritecollide(self, self.level.platform_list, False)
for block in block_hit_list:
# If we are moving right,
# set our right side to the left side of the item we hit
if self.change_x > 0:
self.rect.right = block.rect.left
elif self.change_x < 0:
# Otherwise if we are moving left, do the opposite.
self.rect.left = block.rect.right
# Move up/down
self.rect.y += self.change_y
# Check and see if we hit anything
block_hit_list = pygame.sprite.spritecollide(self, self.level.platform_list, False)
for block in block_hit_list:
# Reset our position based on the top/bottom of the object.
if self.change_y > 0:
self.rect.bottom = block.rect.top
elif self.change_y < 0:
self.rect.top = block.rect.bottom
# Stop our vertical movement
self.change_y = 0
if isinstance(block, MovingPlatform):
self.rect.x += block.change_x
self.length = self.rect.right - self.rect.left
print(self.length)
def calc_grav(self):
""" Calculate effect of gravity. """
# Import the wallslide method
self.wall_slide()
if self.change_y == 0:
self.change_y = 1.75
else:
self.change_y += .45
# See if we are on the ground.
if self.rect.y >= SCREEN_HEIGHT - self.rect.height and self.change_y >= 0:
self.change_y = 0
self.rect.y = SCREEN_HEIGHT - self.rect.height
我真的很感激任何和所有的反馈!我对此很陌生,所以我完全愿意完全和完全错误。
解决方案
我决定将我的评论扩展到答案。
所以程序正在从一个精灵表中加载一堆精灵。请注意,“标准”字符图像似乎是40 x 60
像素,而“蹲伏”图像是45 x 40
. 相差 20 像素(蹲下的图像也宽了 5 像素。)
当精灵进入“蹲伏”模式时self.state == "Crouch"
,代码只是改变精灵图像。它不考虑位置的变化。如果角色通过向上拉它的腿/轮子/触手来“蹲下”,并保持相同的高度,那很好。但如果它是传统意义上的蹲伏,则Y
需要通过精灵图像高度的差异来增加位置。这是因为 PyGame 从左上角绘制精灵。
问题中不包含代码,但是无论什么操作导致self.state
变为"Crouch"
,这也需要在进入蹲伏模式和返回直立状态时调整角色的Y
位置。这种差异可能最好在加载的图像上计算,而不是作为一个常数。精灵也需要重新设置,因为精灵图像的大小现在不同了,并且需要调整碰撞框。20 pixels
-20 pixels
rect
我写了一些快速演示代码,说明这如何在精灵上工作。它只是一个螺旋弹簧 - 结果是生成了一个像素化程度很差的位图,但它说明了压缩/未压缩状态。代码的重要部分是SpringSprite.crouch()
函数,它Y
通过图像高度的差异来实现位置的变化。由于此代码位于精灵居中的矩形上,显然高度变化减半。
向上/向下按压缩和解压缩弹簧。
import pygame
# Window size
WINDOW_WIDTH = 400
WINDOW_HEIGHT = 400
GREY = ( 226, 232, 233 )
###
### Spring sprite that is either upright or compressed
###
class SpringSprite( pygame.sprite.Sprite ):
def __init__( self ):
pygame.sprite.Sprite.__init__( self )
self.upright = pygame.image.load("spring.png").convert_alpha() # 64 x 100
self.compressed = pygame.image.load("spring_compressed.png").convert_alpha() # 64 x 70
self.image = self.upright
self.rect = self.image.get_rect()
self.rect.center = ( WINDOW_WIDTH//2, WINDOW_HEIGHT//2 )
self.crouched = False
self.height_delta= ( self.upright.get_height() - self.compressed.get_height() ) // 2 # 15 pixels (centred)
def crouch( self, crouch=True ):
if ( self.crouched != crouch ):
x,y = self.rect.center
if ( crouch ):
# We've changed from upright to crouched
self.image = self.compressed
y += self.height_delta # difference is centred sprite height
else:
# Changed from crouched back to upright
self.image = self.upright
y -= self.height_delta # difference is centred-sprite height
self.crouched = crouch;
self.rect = self.image.get_rect()
self.rect.center = ( x, y )
def update( self ):
pass
### MAIN
# Open the window
pygame.init()
WINDOW = pygame.display.set_mode( ( WINDOW_WIDTH, WINDOW_HEIGHT ), pygame.HWSURFACE|pygame.DOUBLEBUF|pygame.RESIZABLE )
SPRITES = pygame.sprite.Group()
pygame.display.set_caption("Coiled Spring")
# Add a sprite
spring = SpringSprite()
SPRITES.add( spring )
clock = pygame.time.Clock()
done = False
# Main loop
while not done:
for event in pygame.event.get():
if ( event.type == pygame.QUIT ):
done = True
elif ( event.type == pygame.VIDEORESIZE ):
WINDOW_WIDTH = event.w
WINDOW_HEIGHT = event.h
WINDOW = pygame.display.set_mode( ( WINDOW_WIDTH, WINDOW_HEIGHT ), pygame.HWSURFACE|pygame.DOUBLEBUF|pygame.RESIZABLE )
# Movement keys
keys = pygame.key.get_pressed()
if ( keys[pygame.K_UP] ):
spring.crouch( False ) # Upright
elif ( keys[pygame.K_DOWN] ):
spring.crouch( True ) # Compressed
WINDOW.fill( GREY )
SPRITES.draw( WINDOW )
pygame.display.update()
pygame.display.flip()
clock.tick_busy_loop(60)
pygame.quit()
推荐阅读
- ansible - 如何使用 Ansible F5 模块集合在 F5 设备上检索 SSL 证书序列号?
- python - 无法分配“...”:“...”必须是“用户”实例
- python - Pandas to_csv 不接受 Windows 上的路径
- influxdb - 使用 Kapacitor 组合数据并存储在表中
- javascript - React PropTypes - OneOf 对象列表
- html - CSS Grid:改变一行的方向?子元素是否可以缩进 1/-1 列?
- php - 在 php 表中显示不同的级别
- logging - 你可以在godot中制作一个日志文件吗?
- java - 如何在 Shiro SessionListener 中触发会话到期重定向?
- unit-testing - Azure Devops 是否有与 tcm / import 类似的工具?