Files

130 lines
5.0 KiB
Python

import pygame
from ..constants import tileSize
from ..sim.tiles import AIR
from .theme import (
bufferWidth,
bufferHeight,
renderScale,
skyTop,
skyBottom,
hillFar,
hillNear,
cloudColor,
)
from .art import buildSprites
from .hud import Hud
class Renderer:
def __init__(self, sprites=None):
self.sprites = sprites if sprites is not None else buildSprites()
self.hud = Hud()
self.buffer = pygame.Surface((bufferWidth, bufferHeight))
self.sky = self.buildSky()
def buildSky(self):
surf = pygame.Surface((bufferWidth, bufferHeight))
for y in range(bufferHeight):
blend = y / bufferHeight
color = (
int(skyTop[0] + (skyBottom[0] - skyTop[0]) * blend),
int(skyTop[1] + (skyBottom[1] - skyTop[1]) * blend),
int(skyTop[2] + (skyBottom[2] - skyTop[2]) * blend),
)
pygame.draw.line(surf, color, (0, y), (bufferWidth, y))
return surf
def drawParallax(self, offsetX):
self.buffer.blit(self.sky, (0, 0))
for hillX in (40, 220, 430, 620, 820):
screenX = hillX - offsetX // 2 % 900
pygame.draw.ellipse(self.buffer, hillFar, (screenX, bufferHeight - 52, 140, 80))
pygame.draw.ellipse(self.buffer, hillNear, (screenX + 22, bufferHeight - 44, 96, 64))
for cloudX in (90, 260, 470, 640, 820):
screenX = cloudX - offsetX // 3 % 900
pygame.draw.ellipse(self.buffer, cloudColor, (screenX, 26, 46, 20))
pygame.draw.ellipse(self.buffer, cloudColor, (screenX + 18, 18, 40, 24))
def drawTiles(self, world, offsetX, offsetY):
level = world.level
firstCol = max(0, offsetX // tileSize)
lastCol = min(level.cols, (offsetX + bufferWidth) // tileSize + 1)
firstRow = max(0, offsetY // tileSize)
lastRow = min(level.rows, (offsetY + bufferHeight) // tileSize + 1)
for row in range(firstRow, lastRow):
for col in range(firstCol, lastCol):
name = level.collision[row][col]
if name == AIR:
continue
sprite = self.sprites.get(name)
if sprite is None:
continue
self.buffer.blit(sprite, (col * tileSize - offsetX, row * tileSize - offsetY))
def drawItems(self, world, offsetX, offsetY):
for item in world.items:
if item.collected:
continue
sprite = self.sprites.get(item.kind)
if sprite is None:
continue
bob = -2 if (item.bob and int(item.bobPhase * 2) % 2 == 0) else 0
self.buffer.blit(sprite, (int(item.x) - offsetX, int(item.y) - offsetY + bob))
def drawEnemies(self, world, offsetX, offsetY):
for enemy in world.enemies:
if not enemy.alive:
continue
sprite = self.sprites.get(enemy.kind, self.sprites["goomba"])
if enemy.facing > 0:
sprite = pygame.transform.flip(sprite, True, False)
self.buffer.blit(sprite, (int(enemy.x) - offsetX, int(enemy.y) - offsetY))
def drawProjectiles(self, world, offsetX, offsetY):
for projectile in world.projectiles:
if not projectile.alive:
continue
x = int(projectile.centerX) - offsetX
y = int(projectile.centerY) - offsetY
pygame.draw.circle(self.buffer, (255, 160, 60), (x, y), 3)
pygame.draw.circle(self.buffer, (255, 240, 180), (x, y), 1)
def drawParticles(self, world, offsetX, offsetY):
for particle in world.particles.particles:
x = int(particle.x) - offsetX
y = int(particle.y) - offsetY
self.buffer.fill(particle.color, (x, y, particle.size, particle.size))
def drawPlayer(self, world, offsetX, offsetY):
player = world.player
if not player.alive:
return
if player.iframes > 0 and player.iframes % 6 < 3:
return
sprite = self.sprites["player"]
if player.facing < 0:
sprite = pygame.transform.flip(sprite, True, False)
self.buffer.blit(sprite, (int(player.x) - 2 - offsetX, int(player.y) - offsetY))
def renderWorld(self, world):
offsetX, offsetY = world.camera.offset()
self.drawParallax(offsetX)
self.drawTiles(world, offsetX, offsetY)
self.drawItems(world, offsetX, offsetY)
self.drawProjectiles(world, offsetX, offsetY)
self.drawEnemies(world, offsetX, offsetY)
self.drawParticles(world, offsetX, offsetY)
self.drawPlayer(world, offsetX, offsetY)
return self.buffer
def present(self, world, mode=None):
self.renderWorld(world)
scaled = pygame.transform.scale(
self.buffer, (bufferWidth * renderScale, bufferHeight * renderScale)
)
self.hud.draw(scaled, world)
if mode in ("menu", "paused", "gameover", "complete", "victory"):
self.hud.drawOverlay(scaled, mode)
return scaled