【发布时间】:2022-01-05 17:59:41
【问题描述】:
我已经看到this answer,并且仍在尝试添加此答案。这不是重复的。
我有一个 20x20 的网格,屏幕尺寸是 800x640。屏幕看不到完整的网格,我希望它能够通过滚动摄像头看到。
但是,我什至不确定如何实现这一点。
我的代码的工作方式是,在主循环中,调用player.update() 来更新玩家的位置和碰撞,然后调用update() 函数,它重绘网格中的所有精灵(以显示任何变化)。
代码:
import pygame
from pygame.locals import *
import os
import random
import time
pygame.init()
W, Height = 800, 640
screen = pygame.display.set_mode((W,Height))
SCREEN_SIZE = pygame.Rect((0,0,W,Height))
TILE_SIZE = 48
t0 = time.time()
font = pygame.font.SysFont(None, 24)
print("Time needed to create fonts: " + str(time.time() - t0))
vec = pygame.math.Vector2
# USER CAN MODIFY
ACC = 0.5
FRIC = -0.12
FPS = 60
clock = pygame.time.Clock()
class BlueBlock(pygame.sprite.Sprite):
def __init__(self, x, y):
super(BlueBlock, self).__init__()
self.surf = pygame.Surface((48,48))
self.surf.fill((0,191,255))
self.rect = self.surf.get_rect()
self.original_surface = self.surf
self.hover_surface = self.original_surface.copy()
pygame.draw.rect(self.hover_surface, (255, 255, 0), self.hover_surface.get_rect(), 6)
self.surf = self.original_surface
self.rect = self.surf.get_rect(center = (x, y))
self.hover = False
self.mouse_pos = None
self.count = 0
def update(self):
if player.mode == "build":
mouse_pos = pygame.mouse.get_pos()
self.hover = self.rect.collidepoint(mouse_pos)
self.surf = self.hover_surface if self.hover else self.original_surface
if self.hover and mouse_pos == self.mouse_pos:
self.count += 1
if self.count > 10:
self.image = pygame.Surface((48,48))
self.image.fill((255,255,255))
class textureblock(pygame.sprite.Sprite):
def __init__(self, imagefile, x, y, type):
super(textureblock, self).__init__()
self.imagefile = imagefile
self.original_image = pygame.image.load(imagefile).convert_alpha()
self.original_image = pygame.transform.scale(self.original_image, (48,48))
self.hover_image = self.original_image.copy()
pygame.draw.rect(self.hover_image, (255, 255, 0), self.hover_image.get_rect(), 6)
self.image = self.original_image
self.rect = self.image.get_rect(center = (x, y))
self.hover = False
self.mouse_pos = None
self.count = 0
self.type = type
def update(self):
if player.mode == "build":
pygame.draw.rect(self.hover_image, (255,0,0), self.hover_image.get_rect(), 6)
elif player.mode == "destroy":
pygame.draw.rect(self.hover_image, (255, 255,0), self.hover_image.get_rect(), 6)
mouse_pos = pygame.mouse.get_pos()
self.hover = self.rect.collidepoint(mouse_pos)
self.image = self.hover_image if self.hover else self.original_image
if self.hover and mouse_pos == self.mouse_pos and player.mode == "destroy":
self.count += 1
if self.count > 10:
self.image = pygame.Surface((48,48))
self.image.fill((0,191,255))
item = Item(self.imagefile, self.rect.x, self.rect.y, self.type)
items.add(item)
self.remove(blocks)
else:
self.count = 0
self.mouse_pos = mouse_pos
class Player(pygame.sprite.Sprite):
def __init__(self):
super(Player, self).__init__()
self.surf = pygame.Surface((40,40))
self.surf.fill((255,0,0))
self.rect = self.surf.get_rect()
self.pos = vec(0,144) # Position
self.vel = vec(0,0) # Velocity
self.acc = vec(0,0) # Acceleration
self.inventory = {} # Items can be added
self.mode = "destroy" # Mode. Probably will be changed later
self.selected_item = None # Selected item
def move(self, pressed_keys):
self.acc = vec(0,0.5)
if pressed_keys[K_LEFT]:
self.acc.x = -ACC
if pressed_keys[K_RIGHT]:
self.acc.x = ACC
self.acc.x += self.vel.x * FRIC
self.vel += self.acc
self.pos.x += self.vel.x + 0.5 * self.acc.x
self.rect.midbottom = self.pos
hit_side = False
for entity in blocks:
if self.rect.colliderect(entity.rect):
# move left and hit the block on the right
if self.vel.x < 0 and self.rect.right > entity.rect.right:
self.rect.left = entity.rect.right
self.pos.x = self.rect.centerx
hit_side = True
# move right and hit the block on the left
if self.vel.x > 0 and self.rect.left < entity.rect.left:
self.rect.right = entity.rect.left
self.pos.x = self.rect.centerx
hit_side = True
if hit_side:
self.vel.x = 0
self.acc.x = 0
def update(self):
self.acc = vec(0,0.5)
if pressed_keys[K_LEFT]:
self.acc.x = -ACC
if pressed_keys[K_RIGHT]:
self.acc.x = ACC
self.acc.x += self.vel.x * FRIC
self.vel += self.acc
self.pos.x += self.vel.x + 0.5 * self.acc.x
self.rect.midbottom = self.pos
hit_side = False
for entity in blocks:
if self.rect.colliderect(entity.rect):
# move left and hit the block on the right
if self.vel.x < 0 and self.rect.right > entity.rect.right:
self.rect.left = entity.rect.right
self.pos.x = self.rect.centerx
hit_side = True
# move right and hit the block on the left
if self.vel.x > 0 and self.rect.left < entity.rect.left:
self.rect.right = entity.rect.left
self.pos.x = self.rect.centerx
hit_side = True
if hit_side:
self.vel.x = 0
self.acc.x = 0
hits = pygame.sprite.spritecollide(self, blocks, False)
self.pos.y += self.vel.y + 0.5 * self.acc.y
self.rect.midbottom = self.pos
for entity in blocks:
if self.rect.colliderect(entity.rect):
if self.vel.y > 0:
self.rect.bottom = entity.rect.top
self.pos.y = self.rect.bottom
self.vel.y = 0
if self.vel.y > 0:
if hits:
self.pos.y = hits[0].rect.top + 1
self.vel.y = 0
def jump(self):
self.vel.y = -15
# Item class - Spawned when a player breaks a block.
class Item(pygame.sprite.Sprite):
def __init__(self, image, x, y, type):
super(Item, self).__init__()
self.image = pygame.image.load(image).convert_alpha()
self.image = pygame.transform.scale(self.image, (24,24))
self.rect = self.image.get_rect()
self.pos = vec(x, y)
self.vel = vec(0,0)
self.acc = vec(0,0)
self.type = type
def move(self):
self.acc = vec(0,0.5)
self.acc.x += self.vel.x * FRIC
self.vel += self.acc
self.pos.x += self.vel.x + 0.5 * self.acc.x
self.rect.midbottom = self.pos
hit_side = False
for entity in blocks:
if self.rect.colliderect(entity.rect):
# move left and hit the block on the right
if self.vel.x < 0 and self.rect.right > entity.rect.right:
self.rect.left = entity.rect.right
self.pos.x = self.rect.centerx
hit_side = True
# move right and hit the block on the left
if self.vel.x > 0 and self.rect.left < entity.rect.left:
self.rect.right = entity.rect.left
self.pos.x = self.rect.centerx
hit_side = True
if hit_side:
self.vel.x = 0
self.acc.x = 0
def update(self):
hits = pygame.sprite.spritecollide(self, blocks, False)
self.pos.y += self.vel.y + 0.5 * self.acc.y
self.rect.midbottom = self.pos
for entity in blocks:
if self.rect.colliderect(entity.rect):
if self.vel.y > 0:
self.rect.bottom = entity.rect.top
self.pos.y = self.rect.bottom
self.vel.y = 0
if self.vel.y > 0:
if hits:
self.pos.y = hits[0].rect.top + 1
self.vel.y = 0
# Now we check if we hit the Player
if self.rect.colliderect(player.rect):
# Attempt to check the player inventory
if self.type not in player.inventory.keys():
player.inventory[self.type] = 1
self.kill()
else:
player.inventory.update({self.type: player.inventory.get(self.type) + 1})
self.kill()
player = Player()
blueblock = BlueBlock(0,0)
running = True
all_sprites = pygame.sprite.Group()
blocks = pygame.sprite.Group()
items = pygame.sprite.Group()
miscBlocks = pygame.sprite.Group()
def drawGraph(graph, start):
y = start
x = 0
for item in graph:
if item == "O":
spr = BlueBlock(x, y)
spr.rect.x = x
spr.rect.y = y
all_sprites.add(spr)
miscBlocks.add(spr)
screen.blit(spr.surf, spr.rect)
x += 48
elif item == "G":
spr = textureblock("media/Grass.jpeg", x, y, "Grass")
spr.rect.x = x
spr.rect.y = y
all_sprites.add(spr)
blocks.add(spr)
screen.blit(spr.image, spr.rect)
x += 48
elif item == "S":
spr = textureblock("media/Stone.png",x,y, "Stone")
spr.rect.x = x
spr.rect.y = y
all_sprites.add(spr)
blocks.add(spr)
screen.blit(spr.image, spr.rect)
x += 48
elif item == "C":
spr = textureblock("media/Coal.jpeg",x,y, "Coal")
spr.rect.x = x
spr.rect.y = y
all_sprites.add(spr)
blocks.add(spr)
screen.blit(spr.image, spr.rect)
x += 48
elif item == "NL":
y += 48
x = 0
else:
print("Item not found: " + item)
print("[Debug] Generation finished. Amount of blocks: " + str(len(blocks.sprites())))
def randomGen(graph):
print("[Debug] Begin randomGen...")
# We assume the user has not done anything with the graph, so we add the sky and grass
for i in range(20):
newgraph.append('O')
newgraph.append('NL')
for i in range(20):
newgraph.append('O')
newgraph.append('NL')
for i in range(20):
newgraph.append('O')
newgraph.append('NL')
for i in range(20):
newgraph.append('O')
newgraph.append('NL')
for i in range(20):
newgraph.append('O')
newgraph.append('NL')
for i in range(20):
newgraph.append('G')
newgraph.append('NL')
# Next begins the random ore gen
for i in range(20):
x = 0
for i in range(20):
# Chance of coal - 1 in 15
iscoal = random.randint(1,15)
if iscoal == 6:
graph.append("C")
else:
graph.append("S")
x += 48
graph.append('NL')
print("[Debug] randomGen finished. Block Stats: %s air blocks, %s grass blocks, %s stone blocks, %s coal blocks, and %s newlines." % (str(graph.count('O')), str(graph.count('G')), str(graph.count('S')), str(graph.count('C')), str(graph.count('NL'))))
newgraph = []
randomGen(newgraph)
all_sprites.add(player)
def update():
for entity in all_sprites:
try:
screen.blit(entity.surf, entity.rect)
except:
screen.blit(entity.image, entity.rect)
screen.blit(player.surf, player.rect)
for entity in blocks:
screen.blit(entity.image, entity.rect)
for entity in items:
screen.blit(entity.image, entity.rect)
pygame.display.update()
drawGraph(newgraph, 0)
# Calculate the size of the level
level_width = 0
for i in newgraph:
if i != "NL":
level_width += 1
elif i == "NL":
break
level_width = level_width * TILE_SIZE
level_height = (newgraph.count("NL")-1)*TILE_SIZE
print("[Debug] Calculated level width and height: %s and %s" % (str(level_width), str(level_height)))
while running:
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
player.jump()
if event.key == pygame.K_ESCAPE:
running = False
pygame.quit()
if event.key == pygame.K_e:
if len(player.inventory) == 0:
print("Player Inventory: Empty")
else:
print("Player Inventory: " + str(player.inventory).replace("{", "").replace("}","").replace(":", " x").replace("'",""))
if event.key == pygame.K_b:
if player.mode == "build":
player.mode = "destroy"
elif player.mode == "destroy":
player.mode = "build"
print("Changed player mode to " + player.mode)
if event.key == pygame.K_1:
player.selected_item = list(player.inventory)[0]
print("Item: " + list(player.inventory)[0])
if event.type == pygame.MOUSEBUTTONDOWN:
x,y = event.pos
if event.type == pygame.QUIT:
running = False
pygame.quit()
miscBlocks.update()
blocks.update()
blocks.draw(screen)
pressed_keys = pygame.key.get_pressed()
for entity in items:
entity.move()
# Commented out because it lagged everything.
items.update()
player.update()
update()
img1 = font.render("FPS: " + str(clock.get_fps()), True, (255,255,0))
img2 = font.render("Mode: " + player.mode, True, (255,0,0))
try:
img3 = font.render("Selected Item: " + player.selected_item, True, (0,255,0))
except Exception:
img3 = font.render("Selected Item: None", True, (0,255,0))
screen.blit(img1, (0,0))
screen.blit(img2, (0,24))
screen.blit(img3, (0,48))
pygame.display.update()
clock.tick(60)
【问题讨论】:
-
好的。我将添加一些代码。
-
请阅读Minimal, Reproducible Example?是否真的需要所有代码来解释问题?代码太长了,不是最小的。您的代码依赖于外部资源,例如图像。没有图像,任何人都无法运行代码,因此无法重现。
-
您所要做的就是在您的
update方法中为entity.rect2添加一个偏移量,这在Add scrolling to a platformer in pygame 问题的答案中得到了很好的解释。 -
@Rabbid76 是的,我知道。 我试图在我的代码中实现这个问题,但它不起作用。如果有人尝试帮助我添加此代码,我将不胜感激。我对 pygame 很陌生,但这个答案与我的代码非常不同。我只是需要一些帮助。
-
我不太明白 Rytis B 在说什么(所以也许我也是这么说的)。但是您可以将所有精灵向您相机的相反方向移动。例如,我希望我的玩家向前 -> 移动相机 (0, -x),其中 x 是向前的量。然后将每个精灵移动 (0, x)。