Python 将滚动添加到 pygame 中的平台游戏
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14354171/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Add scrolling to a platformer in pygame
提问by user1758231
Ok so I included the code for my project below, I'm just doing some experimenting with pygame on making a platformer. I'm trying to figure out how to do some very simple scrolling that follows the player, so the player is the center of the camera and it bounces/follows him. Can anyone help me?
好的,所以我在下面包含了我的项目的代码,我只是在尝试使用 pygame 制作平台游戏。我试图弄清楚如何做一些跟随玩家的非常简单的滚动,所以玩家是相机的中心,它会反弹/跟随他。谁能帮我?
import pygame
from pygame import *
WIN_WIDTH = 800
WIN_HEIGHT = 640
HALF_WIDTH = int(WIN_WIDTH / 2)
HALF_HEIGHT = int(WIN_HEIGHT / 2)
DISPLAY = (WIN_WIDTH, WIN_HEIGHT)
DEPTH = 32
FLAGS = 0
CAMERA_SLACK = 30
def main():
global cameraX, cameraY
pygame.init()
screen = pygame.display.set_mode(DISPLAY, FLAGS, DEPTH)
pygame.display.set_caption("Use arrows to move!")
timer = pygame.time.Clock()
up = down = left = right = running = False
bg = Surface((32,32))
bg.convert()
bg.fill(Color("#000000"))
entities = pygame.sprite.Group()
player = Player(32, 32)
platforms = []
x = y = 0
level = [
"PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP",
"P P",
"P P",
"P P",
"P P",
"P P",
"P P",
"P P",
"P PPPPPPPPPPP P",
"P P",
"P P",
"P P",
"P P",
"PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP",]
# build the level
for row in level:
for col in row:
if col == "P":
p = Platform(x, y)
platforms.append(p)
entities.add(p)
if col == "E":
e = ExitBlock(x, y)
platforms.append(e)
entities.add(e)
x += 32
y += 32
x = 0
entities.add(player)
while 1:
timer.tick(60)
for e in pygame.event.get():
if e.type == QUIT: raise SystemExit, "QUIT"
if e.type == KEYDOWN and e.key == K_ESCAPE:
raise SystemExit, "ESCAPE"
if e.type == KEYDOWN and e.key == K_UP:
up = True
if e.type == KEYDOWN and e.key == K_DOWN:
down = True
if e.type == KEYDOWN and e.key == K_LEFT:
left = True
if e.type == KEYDOWN and e.key == K_RIGHT:
right = True
if e.type == KEYDOWN and e.key == K_SPACE:
running = True
if e.type == KEYUP and e.key == K_UP:
up = False
if e.type == KEYUP and e.key == K_DOWN:
down = False
if e.type == KEYUP and e.key == K_RIGHT:
right = False
if e.type == KEYUP and e.key == K_LEFT:
left = False
if e.type == KEYUP and e.key == K_RIGHT:
right = False
# draw background
for y in range(32):
for x in range(32):
screen.blit(bg, (x * 32, y * 32))
# update player, draw everything else
player.update(up, down, left, right, running, platforms)
entities.draw(screen)
pygame.display.update()
class Entity(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
class Player(Entity):
def __init__(self, x, y):
Entity.__init__(self)
self.xvel = 0
self.yvel = 0
self.onGround = False
self.image = Surface((32,32))
self.image.fill(Color("#0000FF"))
self.image.convert()
self.rect = Rect(x, y, 32, 32)
def update(self, up, down, left, right, running, platforms):
if up:
# only jump if on the ground
if self.onGround: self.yvel -= 10
if down:
pass
if running:
self.xvel = 12
if left:
self.xvel = -8
if right:
self.xvel = 8
if not self.onGround:
# only accelerate with gravity if in the air
self.yvel += 0.3
# max falling speed
if self.yvel > 100: self.yvel = 100
if not(left or right):
self.xvel = 0
# increment in x direction
self.rect.left += self.xvel
# do x-axis collisions
self.collide(self.xvel, 0, platforms)
# increment in y direction
self.rect.top += self.yvel
# assuming we're in the air
self.onGround = False;
# do y-axis collisions
self.collide(0, self.yvel, platforms)
def collide(self, xvel, yvel, platforms):
for p in platforms:
if pygame.sprite.collide_rect(self, p):
if isinstance(p, ExitBlock):
pygame.event.post(pygame.event.Event(QUIT))
if xvel > 0:
self.rect.right = p.rect.left
print "collide right"
if xvel < 0:
self.rect.left = p.rect.right
print "collide left"
if yvel > 0:
self.rect.bottom = p.rect.top
self.onGround = True
self.yvel = 0
if yvel < 0:
self.rect.top = p.rect.bottom
class Platform(Entity):
def __init__(self, x, y):
Entity.__init__(self)
self.image = Surface((32, 32))
self.image.convert()
self.image.fill(Color("#DDDDDD"))
self.rect = Rect(x, y, 32, 32)
def update(self):
pass
class ExitBlock(Platform):
def __init__(self, x, y):
Platform.__init__(self, x, y)
self.image.fill(Color("#0033FF"))
if __name__ == "__main__":
main()
采纳答案by sloth
You need to apply an offsetto the position of your entities when drawing them. Let's call that offseta camera, since this is the effect we want to achieve with this.
在绘制实体时,您需要对实体的位置应用偏移量。让我们称其为偏移a camera,因为这是我们想要通过 this 实现的效果。
First of all, we can't use the drawfunction of the sprite group, since the sprites don't need to know that their position (rect) is not the position they are going to be drawn on the screen (At the end, we'll subclass the Groupclass and reimplement the it's drawto be aware of the camera, but let's start slow).
首先,我们不能使用draw精灵组的功能,因为精灵不需要知道它们的位置(rect)不是它们将要在屏幕上绘制的位置(最后,我们'将子类化Group该类并重新实现它draw以了解相机,但让我们慢慢开始)。
Let's start by creating a Cameraclass to hold the state of the offset we want to apply to the position of our entities:
让我们首先创建一个Camera类来保存我们要应用于实体位置的偏移量的状态:
class Camera(object):
def __init__(self, camera_func, width, height):
self.camera_func = camera_func
self.state = Rect(0, 0, width, height)
def apply(self, target):
return target.rect.move(self.state.topleft)
def update(self, target):
self.state = self.camera_func(self.state, target.rect)
some things to note here:
这里需要注意的一些事情:
We need to store the position of the camera, and the width and height of the level in pixels (since we want to stop scrolling at the edges of the level). I used a Rectto store all these informations, but you could easily just use some fields.
我们需要存储相机的位置,以及以像素为单位的关卡宽度和高度(因为我们想在关卡边缘停止滚动)。我使用 aRect来存储所有这些信息,但您可以轻松地使用一些字段。
Using Rectcomes in handy in the applyfunction. This is where we re-calculate the position of an entity on the screen to applythe scrolling.
Rect在apply函数中使用就派上用场了。这是我们重新计算实体在屏幕上的位置以应用滚动的地方。
Once per iteration of the main loop, we need to update the position of the camera, hence there's the updatefunction. It just alters the state by calling the camera_funcfunction, which will do all the hard workfor us. We implement it later.
在主循环的每次迭代中,我们需要更新相机的位置,因此就有了这个update函数。它只是通过调用camera_func函数来改变状态,这将为我们完成所有艰苦的工作。我们稍后实施。
Let's create an instace of the camera:
让我们创建一个相机实例:
for row in level:
...
total_level_width = len(level[0])*32 # calculate size of level in pixels
total_level_height = len(level)*32 # maybe make 32 an constant
camera = Camera(*to_be_implemented*, total_level_width, total_level_height)
entities.add(player)
...
and alter our main loop:
并改变我们的主循环:
# draw background
for y in range(32):
...
camera.update(player) # camera follows player. Note that we could also follow any other sprite
# update player, draw everything else
player.update(up, down, left, right, running, platforms)
for e in entities:
# apply the offset to each entity.
# call this for everything that should scroll,
# which is basically everything other than GUI/HUD/UI
screen.blit(e.image, camera.apply(e))
pygame.display.update()
Our camera class is already very flexible and yet dead simple. It can use different kinds of scrolling (by providing different camera_funcfunctions), and it can follow any arbitary sprite, not just the player. You even can change this at runtime.
我们的相机类已经非常灵活而且非常简单。它可以使用不同类型的滚动(通过提供不同的camera_func功能),并且可以跟随任何任意精灵,而不仅仅是玩家。您甚至可以在运行时更改此设置。
Now for the implementation of camera_func. A simple approach is to just center the player (or whichever entity we want to follow) at the screen, and the implementation is straight forward:
现在为了实现camera_func. 一个简单的方法是将玩家(或我们想要跟随的任何实体)在屏幕上居中,并且实现很简单:
def simple_camera(camera, target_rect):
l, t, _, _ = target_rect # l = left, t = top
_, _, w, h = camera # w = width, h = height
return Rect(-l+HALF_WIDTH, -t+HALF_HEIGHT, w, h)
We just take the position of our target, and add the half total screen size. You can try it by creating your camera like this:
我们只是取我们的位置target,并添加一半的屏幕尺寸。您可以通过像这样创建相机来尝试它:
camera = Camera(simple_camera, total_level_width, total_level_height)
So far, so good. But maybe we don't want to see the black background outsidethe level? How about:
到现在为止还挺好。但也许我们不想看到关卡外的黑色背景?怎么样:
def complex_camera(camera, target_rect):
# we want to center target_rect
x = -target_rect.center[0] + WIN_WIDTH/2
y = -target_rect.center[1] + WIN_HEIGHT/2
# move the camera. Let's use some vectors so we can easily substract/multiply
camera.topleft += (pygame.Vector2((x, y)) - pygame.Vector2(camera.topleft)) * 0.06 # add some smoothness coolnes
# set max/min x/y so we don't see stuff outside the world
camera.x = max(-(camera.width-WIN_WIDTH), min(0, camera.x))
camera.y = max(-(camera.height-WIN_HEIGHT), min(0, camera.y))
return camera
Here we simply use the min/maxfunctions to ensure we don't scroll outsideout level.
在这里,我们只是使用min/max函数来确保我们不会向外滚动。
Try it by creating your camera like this:
通过像这样创建您的相机来尝试它:
camera = Camera(complex_camera, total_level_width, total_level_height)
There's a little animation of our final scrolling in action:
有一个我们最后滚动的小动画:
Here's the complete code again. Note I changed some things:
这是完整的代码。注意我改变了一些东西:
- the level is bigger and to have some more platforms
- use python 3
- use a sprite group to handle the camera
- refactored some duplicate code
- since Vector2/3 is now stable, use them for easier math
- get rid of that ugly event handling code and use
pygame.key.get_pressedinstead
- 关卡更大,平台更多
- 使用蟒蛇 3
- 使用精灵组来处理相机
- 重构了一些重复的代码
- 由于 Vector2/3 现在很稳定,使用它们来简化数学运算
- 摆脱那些丑陋的事件处理代码并
pygame.key.get_pressed改用
#! /usr/bin/python
import pygame
from pygame import *
SCREEN_SIZE = pygame.Rect((0, 0, 800, 640))
TILE_SIZE = 32
GRAVITY = pygame.Vector2((0, 0.3))
class CameraAwareLayeredUpdates(pygame.sprite.LayeredUpdates):
def __init__(self, target, world_size):
super().__init__()
self.target = target
self.cam = pygame.Vector2(0, 0)
self.world_size = world_size
if self.target:
self.add(target)
def update(self, *args):
super().update(*args)
if self.target:
x = -self.target.rect.center[0] + SCREEN_SIZE.width/2
y = -self.target.rect.center[1] + SCREEN_SIZE.height/2
self.cam += (pygame.Vector2((x, y)) - self.cam) * 0.05
self.cam.x = max(-(self.world_size.width-SCREEN_SIZE.width), min(0, self.cam.x))
self.cam.y = max(-(self.world_size.height-SCREEN_SIZE.height), min(0, self.cam.y))
def draw(self, surface):
spritedict = self.spritedict
surface_blit = surface.blit
dirty = self.lostsprites
self.lostsprites = []
dirty_append = dirty.append
init_rect = self._init_rect
for spr in self.sprites():
rec = spritedict[spr]
newrect = surface_blit(spr.image, spr.rect.move(self.cam))
if rec is init_rect:
dirty_append(newrect)
else:
if newrect.colliderect(rec):
dirty_append(newrect.union(rec))
else:
dirty_append(newrect)
dirty_append(rec)
spritedict[spr] = newrect
return dirty
def main():
pygame.init()
screen = pygame.display.set_mode(SCREEN_SIZE.size)
pygame.display.set_caption("Use arrows to move!")
timer = pygame.time.Clock()
level = [
"PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP",
"P P",
"P P",
"P P",
"P PPPPPPPPPPP P",
"P P",
"P P",
"P P",
"P PPPPPPPP P",
"P P",
"P PPPPPPP P",
"P PPPPPP P",
"P P",
"P PPPPPPP P",
"P P",
"P PPPPPP P",
"P P",
"P PPPPPPPPPPP P",
"P P",
"P PPPPPPPPPPP P",
"P P",
"P P",
"P P",
"P P",
"PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP",]
platforms = pygame.sprite.Group()
player = Player(platforms, (TILE_SIZE, TILE_SIZE))
level_width = len(level[0])*TILE_SIZE
level_height = len(level)*TILE_SIZE
entities = CameraAwareLayeredUpdates(player, pygame.Rect(0, 0, level_width, level_height))
# build the level
x = y = 0
for row in level:
for col in row:
if col == "P":
Platform((x, y), platforms, entities)
if col == "E":
ExitBlock((x, y), platforms, entities)
x += TILE_SIZE
y += TILE_SIZE
x = 0
while 1:
for e in pygame.event.get():
if e.type == QUIT:
return
if e.type == KEYDOWN and e.key == K_ESCAPE:
return
entities.update()
screen.fill((0, 0, 0))
entities.draw(screen)
pygame.display.update()
timer.tick(60)
class Entity(pygame.sprite.Sprite):
def __init__(self, color, pos, *groups):
super().__init__(*groups)
self.image = Surface((TILE_SIZE, TILE_SIZE))
self.image.fill(color)
self.rect = self.image.get_rect(topleft=pos)
class Player(Entity):
def __init__(self, platforms, pos, *groups):
super().__init__(Color("#0000FF"), pos)
self.vel = pygame.Vector2((0, 0))
self.onGround = False
self.platforms = platforms
self.speed = 8
self.jump_strength = 10
def update(self):
pressed = pygame.key.get_pressed()
up = pressed[K_UP]
left = pressed[K_LEFT]
right = pressed[K_RIGHT]
running = pressed[K_SPACE]
if up:
# only jump if on the ground
if self.onGround: self.vel.y = -self.jump_strength
if left:
self.vel.x = -self.speed
if right:
self.vel.x = self.speed
if running:
self.vel.x *= 1.5
if not self.onGround:
# only accelerate with gravity if in the air
self.vel += GRAVITY
# max falling speed
if self.vel.y > 100: self.vel.y = 100
print(self.vel.y)
if not(left or right):
self.vel.x = 0
# increment in x direction
self.rect.left += self.vel.x
# do x-axis collisions
self.collide(self.vel.x, 0, self.platforms)
# increment in y direction
self.rect.top += self.vel.y
# assuming we're in the air
self.onGround = False;
# do y-axis collisions
self.collide(0, self.vel.y, self.platforms)
def collide(self, xvel, yvel, platforms):
for p in platforms:
if pygame.sprite.collide_rect(self, p):
if isinstance(p, ExitBlock):
pygame.event.post(pygame.event.Event(QUIT))
if xvel > 0:
self.rect.right = p.rect.left
if xvel < 0:
self.rect.left = p.rect.right
if yvel > 0:
self.rect.bottom = p.rect.top
self.onGround = True
self.yvel = 0
if yvel < 0:
self.rect.top = p.rect.bottom
class Platform(Entity):
def __init__(self, pos, *groups):
super().__init__(Color("#DDDDDD"), pos, *groups)
class ExitBlock(Platform):
def __init__(self, pos, *groups):
super().__init__(Color("#0033FF"), pos, *groups)
if __name__ == "__main__":
main()
回答by Bartlomiej Lewandowski
Since right know, you have a static background, and the player that you control, is blitted in the position he is in, you have 2 options to always show the character in the middle.
既然你知道,你有一个静态的背景,你控制的玩家在他所处的位置被 blit,你有 2 个选项来始终在中间显示角色。
If you map is small enought, you can have a big img A, and derive a rectangle, based on the position of the player that will be the size of the screen. That way, the player will always be in the middle. A Rect.clamp(Rect) or Rect.clamp_ip(Rect) will aid you in that.
Another approach is to have a different tuple for position on screen. The player will have a constant value in the center of the screen, while the backgrounds position will be the negative of the player position.
如果你的地图足够小,你可以有一个大的 img A,并根据将是屏幕大小的玩家位置推导出一个矩形。这样,玩家将始终处于中间位置。一个 Rect.clamp(Rect) 或 Rect.clamp_ip(Rect) 将帮助你。
另一种方法是为屏幕上的位置使用不同的元组。玩家将在屏幕中央有一个恒定值,而背景位置将是玩家位置的负值。
回答by jsbueno
The only way to do that is to separate logical positions in the map, from physical positions on the screen .
唯一的方法是将地图中的逻辑位置与屏幕上的物理位置分开。
Any code related to actually drawing your map on the screen - in your case all the .rectattributes of your sprites - have to do so based on an offset of what part of yor map the screen is actually using.
任何与在屏幕上实际绘制地图相关的代码(在您的情况下.rect是精灵的所有属性)都必须根据屏幕实际使用的地图部分的偏移量来执行。
For example, your screen might be showing your map starting with position (10,10) on the top left - all display related code them (which in the case above are the .rectattributes) should subtract the screen offset from the current logical position - (say the character is at map coords(12,15) - so, it should be drawn at (12,15) - (10, 10) -> (2, 5) * BLOCK_SIZE)
In your example above BLOCK_SIZE is hardcoded to 32,32, so you want to draw it at physical pixel position (2 * 32, 5 * 32) on the display)
例如,您的屏幕可能会显示从左上角位置 (10,10) 开始的地图 - 所有与显示相关的代码(在上面的情况下是.rect属性)应该从当前逻辑位置减去屏幕偏移量 - (说角色在地图坐标(12,15) - 所以,它应该在(12,15) - (10, 10) - >(2, 5)* BLOCK_SIZE)在你上面的例子中BLOCK_SIZE被硬编码为32 ,32,所以你想在显示器上的物理像素位置(2 * 32, 5 * 32)绘制它)
(hint: avoid hardcoding things this way, make it a constant declaration at the beginning of your code)
(提示:避免以这种方式进行硬编码,在代码的开头将其作为常量声明)
回答by Giovanni G. PY
I put a safer way to exit the window
我提出了一个更安全的退出窗口的方法
#! /usr/bin/python
import pygame
from pygame import *
import sys
SCREEN_SIZE = pygame.Rect((0, 0, 800, 640))
TILE_SIZE = 32
GRAVITY = pygame.Vector2((0, 0.3))
class CameraAwareLayeredUpdates(pygame.sprite.LayeredUpdates):
def __init__(self, target, world_size):
super().__init__()
self.target = target
self.cam = pygame.Vector2(0, 0)
self.world_size = world_size
if self.target:
self.add(target)
def update(self, *args):
super().update(*args)
if self.target:
x = -self.target.rect.center[0] + SCREEN_SIZE.width/2
y = -self.target.rect.center[1] + SCREEN_SIZE.height/2
self.cam += (pygame.Vector2((x, y)) - self.cam) * 0.05
self.cam.x = max(-(self.world_size.width-SCREEN_SIZE.width), min(0, self.cam.x))
self.cam.y = max(-(self.world_size.height-SCREEN_SIZE.height), min(0, self.cam.y))
def draw(self, surface):
spritedict = self.spritedict
surface_blit = surface.blit
dirty = self.lostsprites
self.lostsprites = []
dirty_append = dirty.append
init_rect = self._init_rect
for spr in self.sprites():
rec = spritedict[spr]
newrect = surface_blit(spr.image, spr.rect.move(self.cam))
if rec is init_rect:
dirty_append(newrect)
else:
if newrect.colliderect(rec):
dirty_append(newrect.union(rec))
else:
dirty_append(newrect)
dirty_append(rec)
spritedict[spr] = newrect
return dirty
def exit():
pygame.quit()
sys.exit()
def main():
pygame.init()
screen = pygame.display.set_mode(SCREEN_SIZE.size)
pygame.display.set_caption("Use arrows to move!")
timer = pygame.time.Clock()
level = [
"PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP",
"P P",
"P P",
"P P",
"P PPPPPPPPPPP P",
"P P",
"P P",
"P P",
"P PPPPPPPP P",
"P P",
"P PPPPPPP P",
"P PPPPPP P",
"P P",
"P PPPPPPP P",
"P P",
"P PPPPPP P",
"P P",
"P PPPPPPPPPPP P",
"P P",
"P PPPPPPPPPPP P",
"P P",
"P P",
"P P",
"P P",
"PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP",]
platforms = pygame.sprite.Group()
player = Player(platforms, (TILE_SIZE, TILE_SIZE))
level_width = len(level[0])*TILE_SIZE
level_height = len(level)*TILE_SIZE
entities = CameraAwareLayeredUpdates(player, pygame.Rect(0, 0, level_width, level_height))
# build the level
x = y = 0
for row in level:
for col in row:
if col == "P":
Platform((x, y), platforms, entities)
if col == "E":
ExitBlock((x, y), platforms, entities)
x += TILE_SIZE
y += TILE_SIZE
x = 0
while 1:
for e in pygame.event.get():
if e.type == QUIT:
exit()
if e.type == KEYDOWN and e.key == K_ESCAPE:
exit()
entities.update()
screen.fill((0, 0, 0))
entities.draw(screen)
pygame.display.update()
timer.tick(60)
class Entity(pygame.sprite.Sprite):
def __init__(self, color, pos, *groups):
super().__init__(*groups)
self.image = Surface((TILE_SIZE, TILE_SIZE))
self.image.fill(color)
self.rect = self.image.get_rect(topleft=pos)
class Player(Entity):
def __init__(self, platforms, pos, *groups):
super().__init__(Color("#0000FF"), pos)
self.vel = pygame.Vector2((0, 0))
self.onGround = False
self.platforms = platforms
self.speed = 8
self.jump_strength = 10
def update(self):
pressed = pygame.key.get_pressed()
up = pressed[K_UP]
left = pressed[K_LEFT]
right = pressed[K_RIGHT]
running = pressed[K_SPACE]
if up:
# only jump if on the ground
if self.onGround: self.vel.y = -self.jump_strength
if left:
self.vel.x = -self.speed
if right:
self.vel.x = self.speed
if running:
self.vel.x *= 1.5
if not self.onGround:
# only accelerate with gravity if in the air
self.vel += GRAVITY
# max falling speed
if self.vel.y > 100: self.vel.y = 100
print(self.vel.y)
if not(left or right):
self.vel.x = 0
# increment in x direction
self.rect.left += self.vel.x
# do x-axis collisions
self.collide(self.vel.x, 0, self.platforms)
# increment in y direction
self.rect.top += self.vel.y
# assuming we're in the air
self.onGround = False;
# do y-axis collisions
self.collide(0, self.vel.y, self.platforms)
def collide(self, xvel, yvel, platforms):
for p in platforms:
if pygame.sprite.collide_rect(self, p):
if isinstance(p, ExitBlock):
pygame.event.post(pygame.event.Event(QUIT))
if xvel > 0:
self.rect.right = p.rect.left
if xvel < 0:
self.rect.left = p.rect.right
if yvel > 0:
self.rect.bottom = p.rect.top
self.onGround = True
self.yvel = 0
if yvel < 0:
self.rect.top = p.rect.bottom
class Platform(Entity):
def __init__(self, pos, *groups):
super().__init__(Color("#DDDDDD"), pos, *groups)
class ExitBlock(Platform):
def __init__(self, pos, *groups):
super().__init__(Color("#0033FF"), pos, *groups)
if __name__ == "__main__":
main()


