272 lines
7 KiB
Python
272 lines
7 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()
|
|
|