You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

273 lines
7.0 KiB
Python

from __future__ import division
from random import randint, choice
from itertools import chain, repeat
from logging import getLogger
from pyglet import gl
from pyglet import clock
from pyglet.event import EventDispatcher
from pyglet.resource import Loader
from pyglet.image import ImageGrid, TextureGrid, Animation
from pyglet.sprite import Sprite
from pyglet.graphics import Batch, TextureGroup
LOGGER = getLogger("defence.tilemap")
TILE_LOADER = Loader(["graphics/tiles"])
class TileLayerGroup(TextureGroup):
def __init__(self, texture, translation=(0, 0), rotation=0):
super(TileLayerGroup, self).__init__(texture)
self.translation = translation
self.rotation = rotation
def set_state(self):
super(TileLayerGroup, self).set_state()
gl.glPushAttrib(gl.GL_COLOR_BUFFER_BIT)
gl.glEnable(gl.GL_BLEND)
gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA)
x, y = self.translation
gl.glPushMatrix()
gl.glTranslatef(x, y, 0)
gl.glRotatef(self.rotation, 0, 0, 1)
#gl.glTexParameterf(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MAG_FILTER, gl.GL_NEAREST)
#gl.glTexParameterf(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MIN_FILTER, gl.GL_NEAREST)
#gl.glTexParameterf(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_WRAP_S, gl.GL_CLAMP)
#gl.glTexParameterf(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_WRAP_T, gl.GL_CLAMP)
#gl.glTexParameterfv(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_BORDER_COLOR, (1, 1, 1, 1))
def unset_state(self):
super(TileLayerGroup, self).unset_state()
gl.glPopMatrix()
gl.glPopAttrib()
def __eq__(self, other):
return (super(TileLayerGroup, self).__eq__(other)
and self.translation == other.translation
and self.rotation == other.rotation)
def __repr__(self):
return '%s(id=%d, transformation=%s, rotation=%d)' % (
self.__class__.__name__,
self.texture.id,
self.translation,
self.rotation)
class Animator(object):
def __init__(self, delay):
self.delay = delay
self.paused = False
self.tiles = set()
def animate(self, dt):
for tile in self.tiles:
pass
class Tileset(object):
def __init__(self, graphic, tilesize=16, framedelay=1):
rows, columns = graphic.height // tilesize, graphic.width // tilesize
grid = TextureGrid(ImageGrid(graphic, rows, columns))
self.texture = grid.texture
self.frames = rows
self.animated = self.frames > 1
self.framedelay = framedelay
self.subtiles = [grid[(0, x):(grid.rows, x+1)] for x in xrange(grid.columns)]
self.texcoords = [[frame.tex_coords for frame in subtile] for subtile in self.subtiles]
def __getitem__(self, index):
return self.subtiles[index]
class Tile(object):
def __init__(self, tileset, frame=0):
self.tileset = tileset
self.frame = frame
#self.subtiles = (2, 3, 0, 1)
self.subtiles = [randint(0, 3) for x in xrange(4)]
self.subtiles = [randint(12, 15) for x in xrange(4)]
def vertices(self, offset=(0, 0)):
"""x, y = offset
vertices = (
x, y, x+1, y, x+1, y+1, x, y+1,
x+1, y, x+2, y, x+2, y+1, x+1, y+1,
x, y+1, x+1, y+1, x+1, y+2, x, y+2,
x+1, y+1, x+2, y+1, x+2, y+2, x+1, y+2)"""
vertices = (
0, 0, 1, 0, 1, 1, 0, 1,
1, 0, 2, 0, 2, 1, 1, 1,
0, 1, 1, 1, 1, 2, 0, 2,
1, 1, 2, 1, 2, 2, 1, 2)
"""vertices = (
0, 0, 0, 1, 0, 3, 1, 1, 5, 0, 1, 0,
1, 0, 1, 2, 0, 5, 2, 1, 2, 1, 1, 4,
0, 1, 9, 1, 1, 0, 1, 2, 1, 0, 2, 5,
1, 1, 4, 2, 1, 3, 2, 2, 0, 1, 2, 1)
offset = list(offset)
offset.append(0)"""
return ((coord * 16) + offset[i%2] for i, coord in enumerate(vertices))
@property
def texcoords(self):
for subtile in self.subtiles:
for coord in self.tileset.texcoords[subtile][self.frame]:
yield coord
@property
def colours(self):
return repeat(255, 4*4*4)
tilesets = {
"#": Tileset(TILE_LOADER.image("grass.png")),
"~": Tileset(TILE_LOADER.image("water.png"))}
class TileLayer(EventDispatcher):
def __init__(self, tileset, tiles):
self.tileset = tileset
self._tiles = tiles
def __getitem__(self, coords):
x, y = coords
return self._tiles[y][x]
def __len__(self):
return len(list(self.tiles))
def animate(self, dt):
for tile in self.tiles:
tile.frame += 1# random.randint(0, 2)
if tile.frame >= tile.tileset.frames:
tile.frame = 0
self.dispatch_event("on_animate")
"""return
start = index*(3*4*4)
end = (index+1)*(3*4*4)
self.tempcoords[start:end]=tile.texcoords
#self.vlists[0].tex_coords[start:end]=tile.texcoords
self.vlists[0].tex_coords=self.tempcoords"""
@property
def tiles(self):
for row in self._tiles:
for tile in row:
if tile is not None:
yield tile
def coordtiles(self):
for y, row in enumerate(self.tilelayer):
for x, tile in enumerate(row):
yield (x, y), tile
TileLayer.register_event_type('on_animate')
class LayerView(object):
def __init__(self, mapview, tilelayer):
self.tilelayer = tilelayer
self.group = TileLayerGroup(self.tilelayer.tileset.texture)
self.mapview = mapview
self.vlist = None
def rotate(dt):
self.group.rotation += 0.5
self.tilelayer.push_handlers(self)
#clock.schedule_interval(rotate, 0.01)
def refresh(self):
if self.vlist is not None:
self.vlist.delete()
vertices = []
for y, row in enumerate(self.tilelayer._tiles):
for x, tile in enumerate(row):
if tile is not None:
vertices.extend(tile.vertices((x*32, y*32)))
texcoords = list(chain(*(tile.texcoords for tile in self.tilelayer.tiles)))
colours = list(chain(*(tile.colours for tile in self.tilelayer.tiles)))
self.vlist = self.mapview.batch.add(
len(self.tilelayer)*16, gl.GL_QUADS, self.group,
('v2i', vertices),
('t3f', texcoords),
('c4B', colours))
def on_animate(self):
def tex():
for tile in self.tilelayer.tiles:
for texcoord in tile.texcoords:
yield texcoord
self.vlist.tex_coords = list(tex())
class TileMap(object):
def __init__(self, layers):
self.layers = [
TileLayer(tilesets["#"], [[Tile(tilesets["#"]) for x in xrange(20)] for y in xrange(15)]),
TileLayer(tilesets["~"], [[choice((Tile(tilesets["~"]), None)) for x in xrange(20)] for y in xrange(15)])]
def animate(self, dt):
for layer in self.layers:
if layer.tileset.animated:
layer.animate(dt)
class MapView(object):
def __init__(self, tilemap):
self.tilemap = tilemap
self.batch = Batch()
self.layerviews = [LayerView(self, layer) for layer in tilemap.layers]
self.refresh()
def refresh(self):
for layerview in self.layerviews:
layerview.refresh()
def draw(self):
self.batch.draw()
def move(self, movement):
dx, dy = movement
for layerview in self.layerviews:
x, y = layerview.group.translation
layerview.group.translation = (x+dx, y+dy)
if __name__ == "__main__":
import pyglet
window = pyglet.window.Window(640, 480, "Defence", vsync=False)
tmap = TileMap(None)
view = MapView(tmap)
fps = pyglet.clock.ClockDisplay()
@window.event
def on_draw():
window.clear()
view.draw()
fps.draw()
@window.event
def on_mouse_drag(x, y, dx, dy, buttons, modifiers):
view.move((dx, dy))
pyglet.clock.schedule_interval(tmap.animate, 1/10.0)
pyglet.clock.schedule(lambda dt: None)
pyglet.app.run()