From: <hol...@us...> - 2008-07-07 05:27:36
|
Revision: 100 http://fortress.svn.sourceforge.net/fortress/?rev=100&view=rev Author: holomorph Date: 2008-07-06 22:27:36 -0700 (Sun, 06 Jul 2008) Log Message: ----------- initial import of a python prototype for fortress (using pyglet) Added Paths: ----------- trunk/pyfort/ trunk/pyfort/fortress.py trunk/pyfort/media/ trunk/pyfort/media/grass.png trunk/pyfort/sprites.py trunk/pyfort/test_world.py trunk/pyfort/testbase.py trunk/pyfort/world.py Added: trunk/pyfort/fortress.py =================================================================== --- trunk/pyfort/fortress.py (rev 0) +++ trunk/pyfort/fortress.py 2008-07-07 05:27:36 UTC (rev 100) @@ -0,0 +1,78 @@ +from pyglet.gl import * +from pyglet.window import key +from world import * +from sprites import * +import random + +def scratch(): + ''' For test code + ''' + camera = Camera(100,100) + pyglet.resource.path = ['../client/src/net/sourceforge/fortress/iso96', + '../client/src/fortress/image/unit/archer', + 'media'] + pyglet.resource.reindex() + terrain = Terrain() + base = pyglet.resource.image('squaretower/base.png') + base.anchor_x = 48 + stem = pyglet.resource.image('squaretower/stem.png') + stem.anchor_x = 48 + top = pyglet.resource.image('squaretower/top.png') + top.anchor_x = 48 + towers = [] + #tower = Tower(base,stem,top,x=tile_size,y=tile_size,level=2) + #tower2 = Tower(base,stem,top, x=tile_size*4,y=tile_size*2, level = 0) + #tower3 = Tower(base,stem,top, x=0,y=tile_size*3, level = 1) + + window = pyglet.window.Window() + @window.event + def on_draw(): + glClear(GL_COLOR_BUFFER_BIT| GL_DEPTH_BUFFER_BIT) + #grid.blit(200,100) + camera.apply() + terrain.draw() + for tower in towers: + tower.draw() + #tower2.draw() + #tower3.draw() + #tower.draw() + + @window.event + def on_resize(width, height): + glViewport(0, 0, width, height) + camera.isometric(width,height) + #perspective(width,height) + return True + + @window.event + def on_key_press(symbol, modifiers): + global tile_size + if symbol == key.SPACE: + print 'clear' + while len(towers)>0: + tower = towers.pop() + terrain.getTile(tower.x,tower.y).occupied = False + @window.event + def on_mouse_press(x, y, button, modifiers): + x_world, y_world = camera.to_world_ground_coords(x,y) + tile = terrain.getTile(x_world, y_world) + if tile is not None and not tile.occupied: + tile.occupied = True + towers.append(Tower(base,stem,top,x=tile.x,y=tile.y,level=random.randint(0,3))) + towers.sort(key = lambda a: -(a.x**2 + a.y**2)) + def perspective(width,height): + glMatrixMode(GL_PROJECTION) + glLoadIdentity() + gluPerspective(Camera.fov, float(width)/height, 0.1, Camera.FAR) + glMatrixMode(GL_MODELVIEW) + + def square(): + glBegin(GL_POLYGON) + glVertex2f(0, 0) + glVertex2f(0, 1) + glVertex2f(1, 1) + glVertex2f(1, 0) + glEnd() +tile_size = 68 +scratch() +pyglet.app.run() Added: trunk/pyfort/media/grass.png =================================================================== (Binary files differ) Property changes on: trunk/pyfort/media/grass.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: trunk/pyfort/sprites.py =================================================================== --- trunk/pyfort/sprites.py (rev 0) +++ trunk/pyfort/sprites.py 2008-07-07 05:27:36 UTC (rev 100) @@ -0,0 +1,85 @@ +from pyglet.gl import * +from world import Camera + +class IsoSprite(pyglet.sprite.Sprite): + '''Instance of an on-screen image. + This sprite will always orient toward the plane perpendicular to the + x-y component that the camera is facing. + ''' + def __init__(self, + img, + x=0, y=0, + blend_src=GL_SRC_ALPHA, + blend_dest=GL_ONE_MINUS_SRC_ALPHA, + batch=None, + group=None, + usage='dynamic'): + '''Create an IsoSprite. + See pyglet sprite documentation + ''' + super(IsoSprite, self).__init__(img,x,y,blend_src,blend_dest,batch,group,usage) + + def _create_vertex_list(self): + if self._batch is None: + self._vertex_list = pyglet.graphics.vertex_list(4, + 'v3i/%s' % self._usage, + 'c4B', ('t3f', self._texture.tex_coords)) + else: + self._vertex_list = self._batch.add(4, GL_QUADS, self._group, + 'v3i/%s' % self._usage, + 'c4B', ('t3f', self._texture.tex_coords)) + self._update_position() + self._update_color() + + def _update_position(self): + img = self._texture + z1 = 0 + z2 = 0 + if not self._visible: + self._vertex_list.vertices[:] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + elif self._scale != 1.0: + x1 = int( - img.anchor_x * self._scale) + y1 = int( - img.anchor_y * self._scale) + x2 = int((img.width - img.anchor_x) * self._scale) + y2 = int((img.height - img.anchor_y) * self._scale) + self._vertex_list.vertices[:] = [x1, y1, z1, x2, y1, z1 , x2, y2, z2, x1, y2, z2] + else: + x1 = - img.anchor_x + y1 = - img.anchor_y + x2 = img.width - img.anchor_x + y2 = img.height - img.anchor_y + self._vertex_list.vertices[:] = [x1, y1, z1, x2, y1, z1 , x2, y2, z2, x1, y2, z2] + + def draw(self): + '''Draw the sprite at its current position. + ''' + glPushMatrix() + #self._vertex_list.draw(GL_QUADS) + self._group.set_state_recursive() + glTranslatef(self._x,self._y,0) + #align with the view direction + glRotatef(-Camera.VIEW_Z_ROTATION,0,0,1) + #and stand the sprite up + glRotatef(90,1,0,0) + self._vertex_list.draw(GL_QUADS) + self._group.unset_state_recursive() + #self._vertex_list.draw(GL_LINES) + glPopMatrix() + +class Tower(object): + def __init__(self,base,stem,top,x,y,level=0): + self.x = x + self.y = y + self.level = level + self._pieces = [IsoSprite(base,x,y)] + for i in range(level): + stem.anchor_y = -base.height - i*stem.height + self._pieces.append(IsoSprite(stem,x,y)) + top.anchor_y = -base.height - stem.height*level + self._pieces.append(IsoSprite(top,x,y)) + self._pieces.reverse() # so they are drawn top to bottom + + def draw(self): + for piece in self._pieces: + piece.draw() + Added: trunk/pyfort/test_world.py =================================================================== --- trunk/pyfort/test_world.py (rev 0) +++ trunk/pyfort/test_world.py 2008-07-07 05:27:36 UTC (rev 100) @@ -0,0 +1,66 @@ +from testbase import * +import unittest + +from world import * + +class TerrainTests(BasicTestSet): + def setUp(self): + self.terrain = Terrain(width = 40, height = 40) + def tearDown(self): + pass + @testmethod + def testSize(self): + self.failUnless(self.terrain.width == 40, 'terrain width incorrect') + self.failUnless(self.terrain.height == 40, 'terrain height incorrect') + @testmethod + def testTileArrayBoundaries(self): + self.failUnlessRaises(IndexError,self.terrain.tiles.__getitem__,40) + t = Terrain(width=1, height=2) + #this should be ok + t.tiles[0][1] + # t.tiles[1][0] should raise an exception + self.failUnlessRaises(IndexError,t.tiles.__getitem__,1) + @testmethod + def testGetTileReturnsTileWithCorrectCoords(self): + tile = self.terrain.getTile(22, TILE_SIZE*2+33) + self.failUnlessEqual(tile.center_x , (22 / TILE_SIZE)*TILE_SIZE + TILE_SIZE/2) + self.failUnlessEqual(tile.center_y , ((TILE_SIZE*2+33) / TILE_SIZE)*TILE_SIZE + TILE_SIZE/2) + self.failUnlessEqual(tile.x , (22 / TILE_SIZE)*TILE_SIZE) + self.failUnlessEqual(tile.y , ((TILE_SIZE*2+33) / TILE_SIZE)*TILE_SIZE) + @testmethod + def testGetTileSameCoordsReturnSameTile(self): + tile1 = self.terrain.getTile(100,200) + tile2 = self.terrain.getTile(100,200) + self.failUnlessEqual(tile1,tile2) + @testmethod + def testGetTileAtSufficiontlyDifferentCoordsReturnsDifferentTiles(self): + tile1 = self.terrain.getTile(100,200) + tile2 = self.terrain.getTile(100+2*TILE_SIZE,200) + self.failIfEqual(tile1,tile2) + @testmethod + def testGetTileOutOfBoundsReturnsNoTile(self): + tile = self.terrain.getTile(self.terrain.width*TILE_SIZE+1, 10) + self.failUnless(tile is None) + tile = self.terrain.getTile(-1,10) + self.failUnless(tile is None) + +class TileTests(BasicTestSet): + def setUp(self): + self.tile = Tile(x=0,y=0) + @testmethod + def testCreate(self): + self.failUnlessEqual(0,self.tile.x) + self.failUnlessEqual(0,self.tile.y) + self.failUnlessEqual(TILE_SIZE/2, self.tile.center_x) + self.failUnlessEqual(TILE_SIZE/2, self.tile.center_y) + @testmethod + def testCenter(self): + tile = Tile(x=100,y=200) + self.failUnlessEqual(100+TILE_SIZE/2,tile.center_x) + self.failUnlessEqual(200+TILE_SIZE/2,tile.center_y) + @testmethod + def testNewTileNotOccupied(self): + self.failIf(self.tile.occupied) + + +unittest.TextTestRunner().run(suite(TileTests, TerrainTests)) Added: trunk/pyfort/testbase.py =================================================================== --- trunk/pyfort/testbase.py (rev 0) +++ trunk/pyfort/testbase.py 2008-07-07 05:27:36 UTC (rev 100) @@ -0,0 +1,20 @@ +import unittest + +def testmethod(testMethod): + testMethod._isTest = True + return testMethod +class BasicTestSet(unittest.TestCase): + @classmethod + def suite(cls): + def isTestMethod(attrname): + attr = getattr(cls, attrname) + return hasattr(attr, "_isTest") + testNames = filter(isTestMethod, dir(cls)) + return unittest.TestSuite(map(cls,testNames)) + + +def suite(*args): + fullSuite = unittest.TestSuite() + for testSet in args: + fullSuite.addTest(testSet.suite()) + return fullSuite Added: trunk/pyfort/world.py =================================================================== --- trunk/pyfort/world.py (rev 0) +++ trunk/pyfort/world.py 2008-07-07 05:27:36 UTC (rev 100) @@ -0,0 +1,87 @@ +from pyglet.gl import * +pyglet.resource.path = ['media'] +pyglet.resource.reindex() + +class Camera(object): + VIEW_Z_ROTATION = 45 + VIEW_X_ROTATION = -60 + VIEW_HEIGHT = 128 + FAR=2048 + fov=45 + def __init__(self,x=0,y=0): + self._x = x + self._y = y + def isometric(self,width,height): + glMatrixMode(GL_PROJECTION) + glLoadIdentity() + glOrtho(-width/2.,width/2.,-height/2.,height/2.,0,Camera.FAR) + glMatrixMode(GL_MODELVIEW) + def apply(self): + glLoadIdentity() + glRotatef(Camera.VIEW_X_ROTATION,1,0,0) + glRotatef(Camera.VIEW_Z_ROTATION,0,0,1) + glTranslatef(-self._x,-self._y,-Camera.VIEW_HEIGHT) + def to_world_ground_coords(self,x,y): + ''' + take the screen coordinates, x,y and return the coresponding + x,y coordinates of the ground + ''' + modelview,proj,view = (GLdouble*16)(),(GLdouble*16)(),(GLint*4)() + #get the current modelview and projection matrices + glGetDoublev(GL_MODELVIEW_MATRIX , modelview) + glGetDoublev(GL_PROJECTION_MATRIX, proj) + #and the viewport + glGetIntegerv(GL_VIEWPORT, view) + pX,pY,pZ = GLdouble(),GLdouble(),GLdouble() + #get the screen coordinates of two sample points + gluProject(0,0,0,modelview,proj,view,pX,pY,pZ) + y_origin, z_origin = pY.value, pZ.value + gluProject(100,100,0,modelview,proj,view,pX,pY,pZ) + # find the change in Z per pixel in Y + dz_dy = (pZ.value-z_origin)/(pY.value-y_origin) + # so the z coordinate of the point of interest is: + z = z_origin + dz_dy*(y-y_origin) + #finally, get the (x,y,0) coordinate for the point clicked + gluUnProject(x,y,z, modelview, proj, view, byref(pX),byref(pY),byref(pZ)) + print 'world :', int(pX.value),int(pY.value),int(pZ.value) + return int(pX.value),int(pY.value) + +TILE_SIZE = 68 + +class Terrain(object): + def __init__(self, width = 10, height = 10): + self.width = width + self.height = height + self.batch = pyglet.graphics.Batch() + self.tiles = [[Tile(x=w*TILE_SIZE, y=h*TILE_SIZE, batch=self.batch) for h in range(height)] for w in range(width)] + + def getTile(self,x,y): + '''Return the tile which contains the specified point + ''' + if x<0 or y<0 or x>self.width*TILE_SIZE or y> self.width*TILE_SIZE: + return None + return self.tiles[x/TILE_SIZE][y/TILE_SIZE] + def draw(self): + self.batch.draw() + +class Tile(pyglet.sprite.Sprite): + ''' + A tile in the world. Can be drawn and keeps track of whether it is + occupied, meaning built on or not. + ''' + grass_image = pyglet.resource.image('grass.png') + def __init__(self, + img=grass_image, + x=0, y=0, + blend_src=GL_SRC_ALPHA, + blend_dest=GL_ONE_MINUS_SRC_ALPHA, + batch=None, + group=None, + usage='dynamic'): + '''Create an IsoSprite. + See pyglet sprite documentation + ''' + super(Tile, self).__init__(img,x,y,blend_src,blend_dest,batch,group,usage) + self.center_x = x+TILE_SIZE/2 + self.center_y = y+TILE_SIZE/2 + self.occupied = False This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |