treasurehunting2/PySDL2-0.9.5/examples/pong.py
2017-05-13 11:00:53 +02:00

235 lines
7.6 KiB
Python

"""The Pong Game."""
import sys
import sdl2
import sdl2.ext
BLACK = sdl2.ext.Color(0, 0, 0)
WHITE = sdl2.ext.Color(255, 255, 255)
PADDLE_SPEED = 3
BALL_SPEED = 3
class CollisionSystem(sdl2.ext.Applicator):
def __init__(self, minx, miny, maxx, maxy):
super(CollisionSystem, self).__init__()
self.componenttypes = Velocity, sdl2.ext.Sprite
self.ball = None
self.minx = minx
self.miny = miny
self.maxx = maxx
self.maxy = maxy
def _overlap(self, item):
sprite = item[1]
if sprite == self.ball.sprite:
return False
left, top, right, bottom = sprite.area
bleft, btop, bright, bbottom = self.ball.sprite.area
return (bleft < right and bright > left and
btop < bottom and bbottom > top)
def process(self, world, componentsets):
collitems = [comp for comp in componentsets if self._overlap(comp)]
if len(collitems) != 0:
self.ball.velocity.vx = -self.ball.velocity.vx
sprite = collitems[0][1]
ballcentery = self.ball.sprite.y + self.ball.sprite.size[1] // 2
halfheight = sprite.size[1] // 2
stepsize = halfheight // 10
degrees = 0.7
paddlecentery = sprite.y + halfheight
if ballcentery < paddlecentery:
factor = (paddlecentery - ballcentery) // stepsize
self.ball.velocity.vy = -int(round(factor * degrees))
elif ballcentery > paddlecentery:
factor = (ballcentery - paddlecentery) // stepsize
self.ball.velocity.vy = int(round(factor * degrees))
else:
self.ball.velocity.vy = -self.ball.velocity.vy
if (self.ball.sprite.y <= self.miny or
self.ball.sprite.y + self.ball.sprite.size[1] >= self.maxy):
self.ball.velocity.vy = -self.ball.velocity.vy
if (self.ball.sprite.x <= self.minx or
self.ball.sprite.x + self.ball.sprite.size[0] >= self.maxx):
self.ball.velocity.vx = -self.ball.velocity.vx
class MovementSystem(sdl2.ext.Applicator):
def __init__(self, minx, miny, maxx, maxy):
super(MovementSystem, self).__init__()
self.componenttypes = Velocity, sdl2.ext.Sprite
self.minx = minx
self.miny = miny
self.maxx = maxx
self.maxy = maxy
def process(self, world, componentsets):
for velocity, sprite in componentsets:
swidth, sheight = sprite.size
sprite.x += velocity.vx
sprite.y += velocity.vy
sprite.x = max(self.minx, sprite.x)
sprite.y = max(self.miny, sprite.y)
pmaxx = sprite.x + swidth
pmaxy = sprite.y + sheight
if pmaxx > self.maxx:
sprite.x = self.maxx - swidth
if pmaxy > self.maxy:
sprite.y = self.maxy - sheight
class TrackingAIController(sdl2.ext.Applicator):
def __init__(self, miny, maxy):
super(TrackingAIController, self).__init__()
self.componenttypes = PlayerData, Velocity, sdl2.ext.Sprite
self.miny = miny
self.maxy = maxy
self.ball = None
def process(self, world, componentsets):
for pdata, vel, sprite in componentsets:
if not pdata.ai:
continue
sheight = sprite.size[1]
centery = sprite.y + sheight // 2
if self.ball.velocity.vx < 0:
# ball is moving away from the AI
if centery < self.maxy // 2 - PADDLE_SPEED:
vel.vy = PADDLE_SPEED
elif centery > self.maxy // 2 + PADDLE_SPEED:
vel.vy = -PADDLE_SPEED
else:
vel.vy = 0
else:
bcentery = self.ball.sprite.y + self.ball.sprite.size[1] // 2
if bcentery < centery:
vel.vy = -PADDLE_SPEED
elif bcentery > centery:
vel.vy = PADDLE_SPEED
else:
vel.vy = 0
class SoftwareRenderSystem(sdl2.ext.SoftwareSpriteRenderSystem):
def __init__(self, window):
super(SoftwareRenderSystem, self).__init__(window)
def render(self, components):
sdl2.ext.fill(self.surface, BLACK)
super(SoftwareRenderSystem, self).render(components)
class TextureRenderSystem(sdl2.ext.TextureSpriteRenderSystem):
def __init__(self, renderer):
super(TextureRenderSystem, self).__init__(renderer)
self.renderer = renderer
def render(self, components):
tmp = self.renderer.color
self.renderer.color = BLACK
self.renderer.clear()
self.renderer.color = tmp
super(TextureRenderSystem, self).render(components)
class Velocity(object):
def __init__(self):
super(Velocity, self).__init__()
self.vx = 0
self.vy = 0
class PlayerData(object):
def __init__(self):
super(PlayerData, self).__init__()
self.ai = False
self.points = 0
class Player(sdl2.ext.Entity):
def __init__(self, world, sprite, posx=0, posy=0, ai=False):
self.sprite = sprite
self.sprite.position = posx, posy
self.velocity = Velocity()
self.playerdata = PlayerData()
self.playerdata.ai = ai
class Ball(sdl2.ext.Entity):
def __init__(self, world, sprite, posx=0, posy=0):
self.sprite = sprite
self.sprite.position = posx, posy
self.velocity = Velocity()
def run():
sdl2.ext.init()
window = sdl2.ext.Window("The Pong Game", size=(800, 600))
window.show()
if "-hardware" in sys.argv:
print("Using hardware acceleration")
renderer = sdl2.ext.Renderer(window)
factory = sdl2.ext.SpriteFactory(sdl2.ext.TEXTURE, renderer=renderer)
else:
print("Using software rendering")
factory = sdl2.ext.SpriteFactory(sdl2.ext.SOFTWARE)
# Create the paddles - we want white ones. To keep it easy enough for us,
# we create a set of surfaces that can be used for Texture- and
# Software-based sprites.
sp_paddle1 = factory.from_color(WHITE, size=(20, 100))
sp_paddle2 = factory.from_color(WHITE, size=(20, 100))
sp_ball = factory.from_color(WHITE, size=(20, 20))
world = sdl2.ext.World()
movement = MovementSystem(0, 0, 800, 600)
collision = CollisionSystem(0, 0, 800, 600)
aicontroller = TrackingAIController(0, 600)
if factory.sprite_type == sdl2.ext.SOFTWARE:
spriterenderer = SoftwareRenderSystem(window)
else:
spriterenderer = TextureRenderSystem(renderer)
world.add_system(aicontroller)
world.add_system(movement)
world.add_system(collision)
world.add_system(spriterenderer)
player1 = Player(world, sp_paddle1, 0, 250)
player2 = Player(world, sp_paddle2, 780, 250, True)
ball = Ball(world, sp_ball, 390, 290)
ball.velocity.vx = -BALL_SPEED
collision.ball = ball
aicontroller.ball = ball
running = True
while running:
for event in sdl2.ext.get_events():
if event.type == sdl2.SDL_QUIT:
running = False
break
if event.type == sdl2.SDL_KEYDOWN:
if event.key.keysym.sym == sdl2.SDLK_UP:
player1.velocity.vy = -PADDLE_SPEED
elif event.key.keysym.sym == sdl2.SDLK_DOWN:
player1.velocity.vy = PADDLE_SPEED
elif event.type == sdl2.SDL_KEYUP:
if event.key.keysym.sym in (sdl2.SDLK_UP, sdl2.SDLK_DOWN):
player1.velocity.vy = 0
sdl2.SDL_Delay(10)
world.process()
if __name__ == "__main__":
sys.exit(run())