Mon Sep 10 14:38:56 PDT 2001
Someone has adopted the PyRPG!
I didn't write the Python RPG, it is primarily the work of Brian Blackwell and John Michaelsome
However, I did pull the code down one evening, and cleaned it up a bit. The code I came up with is at the end of this web page.
I was proudest of these 3 lines:
images = {}
for filename in filter( lambda x: x[-4:] == ".gif", os.listdir( os.curdir ) ):
images[ filename[:-4] ] = Tkinter.PhotoImage( file = filename )
I wish that every game library that was striving towards user-friendly-ness would automatically load all the gif's (or whatevers) in the current directory. The code above shows how to do it.
Extra points if it's then just a matter of saying
images[ "robot1" ].draw( 50, 60 )
to draw the image robot1.gif to 50, 60.
Unfortunately, I didn't make it do that. =^_^=
Python is so cool, that if you don't want to have to use the images dictionary, you can just change...
images[ filename[:-4] ] = Tkinter.PhotoImage( file = filename )
...to...
globals()[ filename[:-4] ] = Tkinter.PhotoImage( file = filename )
...and all of the image files are automatically loaded, and assigned to global variables!
So if you have a file "robot.gif" in your directory, you would now be able to type:
robot.draw( 40, 34 )
and the robot would draw to 40, 34!
Tres cool!
# pyrpg - The Python Role-Playing Game Engine
# (C) 1999 Brian Blackwell and John Michelsen, distributed under the terms of the
# GNU General Public License.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# drawmap.py - simple 3D maze drawing module for pyrpg
ver = '0.0.4 lion'
import Tkinter
import os
import time
# GPL #
print "pyrpg", ver, "- (C) 1999 Brian Blackwell."
print "Distributed under the terms of the GNU General Public License."
print "See file COPYING for details."
# build map #
map = [[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
[1,0,0,1,0,0,0,0,0,0,0,0,1,0,1,0,1,1,1],
[1,0,1,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,1],
[1,0,0,1,0,1,0,1,1,0,1,0,1,0,1,0,1,0,1],
[1,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,1,0,1],
[1,1,1,1,0,0,0,1,0,0,1,1,5,1,1,0,0,1,1],
[1,0,7,0,0,0,0,0,1,0,1,0,1,0,0,1,0,1,1],
[1,0,1,0,0,1,1,0,0,0,0,0,0,0,1,0,1,0,1],
[1,0,1,1,0,1,0,1,2,0,1,1,1,1,0,0,1,0,1],
[1,0,0,0,0,0,0,1,0,0,0,0,1,0,1,1,1,1,1],
[1,0,1,0,0,1,0,1,0,1,0,0,1,0,1,0,1,0,1],
[1,0,0,0,0,1,0,0,0,0,1,0,0,1,1,0,0,1,1],
[1,0,1,1,0,0,1,0,1,1,0,0,1,0,0,0,1,0,1],
[1,1,0,0,0,1,0,0,0,1,0,0,0,0,1,1,1,0,1],
[1,0,0,1,0,0,1,1,0,1,0,1,0,0,0,1,0,1,1],
[1,4,0,1,0,1,0,0,0,1,1,0,1,0,1,0,1,1,1],
[1,4,1,0,0,1,0,1,1,1,0,0,1,0,1,0,1,0,1],
[1,0,1,0,1,1,0,1,0,0,6,1,0,0,1,8,1,3,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]]
map_height = len( map )
map_width = len( map[ 0 ] )
# turn map template into collection of cells #
def new_cell( state ):
return { "state": state,
"visited": 0,
"contents": [] }
templateDict = { 0: 'empty',
1: 'wall',
2: 'enemy',
3: 'treasure',
4: 'fake_wall',
5: 'teleport',
6: 'stairs_up',
7: 'stairs_down',
8: 'stairs_both' }
for y in range( len( map ) ):
for x in range( len( map[ y ] ) ):
map[ y ][ x ] = new_cell( templateDict[ map[ y ][ x ] ] )
# initial settings #
pos = [1, 1] # player pos: x, y
facing = 'S' # N,E,S,W?
# UI response functions #
def firstperson_click( event = None ):
(w,h) = ( canv.winfo_width(), canv.winfo_height() )
if event.x < w/3: move_left()
elif event.x > 2*w/3: move_right()
else:
if event.y < h/3: print "climb the stairs"
elif event.y > 2*h/3: print "decend the stairs"
else: move_forward()
def overhead_click(self, event):
pos = [int(event.x/canv2scale),int(event.y/canv2scale)]
drawmap()
# player motion functions #
def move_forward( event = None ):
global pos, map
(x,y) = (pos[0], pos[1])
dx = { "N": 0, "E": 1, "S": 0, "W": -1 }[ facing ]
dy = { "N": -1, "E": 0, "S": 1, "W": 0 }[ facing ]
if map[ y+dy ][ x+dx ][ "state" ] != 'wall':
pos = [ x+dx, y+dy ]
map[ y ][ x ][ "visited" ] = 1
drawmap()
def move_back( event = None ):
global pos, map
(x,y) = (pos[0], pos[1])
dx = { "N": 0, "E": -1, "S": 0, "W": 1 }[ facing ]
dy = { "N": 1, "E": 0, "S": -1, "W": 0 }[ facing ]
if map[ y+dy ][ x+dx ][ "state" ] != 'wall':
pos = [ x+dx, y+dy ]
map[ y ][ x ][ "visited" ] = 1
drawmap()
def turn_right( event = None ):
global facing
facing = { "N": "E", "E": "S", "S": "W", "W": "N" }[ facing ]
drawmap()
def turn_left( event = None ):
global facing
facing = { "N": "W", "E": "N", "S": "E", "W": "S" }[ facing ]
drawmap()
def turn_around( event = None ):
global facing
facing = { "N": "S", "E": "W", "S": "N", "W": "E" }[ facing ]
drawmap()
# UI #
root = Tkinter.Tk()
root.title( "PyRPG" )
images = {}
for filename in filter( lambda x: x[-4:] == ".gif", os.listdir( os.curdir ) ):
images[ filename[:-4] ] = Tkinter.PhotoImage( file = filename )
firstperson = Tkinter.Frame( root )
firstperson.pack( side='left', anchor=Tkinter.NW )
overhead = Tkinter.Frame( root )
overhead.pack( side='left', anchor=Tkinter.NW )
canv = Tkinter.Canvas( firstperson, width=253, height=253, relief='sunken', bd=1 )
canv.pack()
canv.bind( "", firstperson_click )
canv.bind( "", turn_around )
canv.bind( "", move_back )
canv2 = Tkinter.Canvas( overhead, width=253, height=253, relief='sunken', bd=1 )
canv2.pack()
canv2.bind( "", overhead_click )
side = Tkinter.Frame( firstperson )
side.pack( side='left' )
arrows = Tkinter.Frame( firstperson )
arrows.pack( side='left' )
title = Tkinter.Label( side, image=images[ "pyrpg" ] )
title.pack( padx=20 )
def build_button( imagename, commandval, rowval, colval, bindstr ):
b = Tkinter.Button( arrows, image=images[ imagename ], command=commandval,
width=21, height=21 )
b.grid( row=rowval, column=colval )
root.bind_all( bindstr, commandval )
return b
button_forward = build_button( "up", move_forward, 0, 1, "" )
button_back = build_button( "down", move_back, 2, 1, "" )
button_right = build_button( "right", turn_right, 1, 2, "" )
button_left = build_button( "left", turn_left, 1, 0, "" )
button_turn = build_button( "rotate", turn_around, 1, 1, "" )
label = Tkinter.Label( overhead, text="could put some zooming mode buttons here" )
label.pack( pady=30 )
# map windows & calculate drawing scaling factor #
root.update()
canv2scale = canv2.winfo_width()/(map_width+1)
# screen drawing functions #
def valid_cell( x, y ):
if (0 <= y < map_height) and (0 <= x < map_width):
return 1
return 0
def getview():
"""
Return player's point of view
consisting of three lists,
closest to farthest.
"""
view = []
(xpos,ypos) = (pos[0],pos[1])
# use facing to determine rasterization #
across_dx, across_dy = { "N": (+1,0),
"E": (0,+1),
"S": (-1,0),
"W": (0,-1) }[ facing ]
deep_dx, deep_dy = { "N": (-2,-1),
"E": (+1,-2),
"S": (+2,+1),
"W": (-1,+2) }[ facing ]
# cue up to start position #
xpos = xpos + across_dx + deep_dx
ypos = ypos + across_dy + deep_dy
for godeep in range( 3 ):
# clear this level #
vlevel = []
# scan this level #
for goacross in range( 3 ):
if valid_cell( xpos, ypos ):
vlevel.append( map[ ypos ][ xpos ] )
else:
vlevel.append( new_cell( "wall" ) )
xpos = xpos + across_dx
ypos = ypos + across_dy
# go back to last spot #
# (Yes, we could get rid of this by changing the deep_dx/dy.)
xpos = xpos - across_dx
ypos = ypos - across_dy
# cue up to start of next across #
xpos = xpos + deep_dx
ypos = ypos + deep_dy
view.append( vlevel )
return view
def image( x, y, imagename ):
canv.create_image( x, y, anchor=Tkinter.NW, image=images[ imagename ] )
def drawmap():
local = getview()
canv.delete( Tkinter.ALL )
canv2.delete( Tkinter.ALL )
image( 0, 0, "back" )
if len( local ) > 1:
if local[1][0][ "state" ] == 'wall': image(0, 92, "vlevel-2-left" )
if local[1][1][ "state" ] == 'wall': image(80, 92, "vlevel-2-mid" )
if local[1][2][ "state" ] == 'wall': image(153, 92, "vlevel-2-right" )
if local[0][0][ "state" ] == 'wall': image( 0, 30, "vlevel-1-left" )
if local[0][2][ "state" ] == 'wall': image( 178, 30, "vlevel-1-right" )
if local[0][1][ "state" ] == 'wall': image( 0, 30, "vlevel-1-mid" )
drawoverhead()
def drawoverhead():
# draw map #
y = 0
for row in map:
y = y + 1
x = 0
for cell in row:
x = x + 1
# call function depending on cell state #
{ "wall": draw_wall,
"enemy": draw_enemy,
"treasure": draw_treasure,
"fake_wall": draw_wall,
"teleport": draw_teleport,
"stairs_up": draw_stairs_up,
"stairs_down": draw_stairs_down,
"stairs_both": draw_stairs_both,
"empty": draw_nothing }[ cell[ "state" ] ]( x, y )
# draw player #
draw_rect( pos[0]+1, pos[1]+1, "black", 0.7, 1 )
(_x,_y) = ( (pos[0]+1)*canv2scale, (pos[1]+1)*canv2scale )
d = (canv2scale / 2) * .9
(_x1, _y1, _x2, _y2) = { "N": (_x, _y+d, _x, _y-d ),
"E": (_x-d, _y, _x+d, _y ),
"S": (_x, _y-d, _x, _y+d ),
"W": (_x+d, _y, _x-d, _y ) }[ facing ]
canv2.create_line( _x1, _y1, _x2, _y2, arrow='last', fill='white' )
def draw_rect( x, y, color, scale, fill ):
(_x,_y) = ( x * canv2scale, y * canv2scale )
d = (canv2scale / 2) * scale
if fill == 0:
canv2.create_rectangle( _x-d, _y-d, _x+d, _y+d, outline=color )
else:
canv2.create_rectangle( _x-d, _y-d, _x+d, _y+d, fill=color, outline=color )
def draw_wall( x, y ): draw_rect( x, y, "#808080", 1.0, 1 )
def draw_enemy( x, y ): draw_rect( x, y, "red", 0.7, 1 )
def draw_treasure( x, y ): draw_rect( x, y, "gold", 0.7, 1 )
def draw_teleport( x, y ): draw_rect( x, y, "darkgreen", 0.7, 1 )
def draw_stairs_up( x, y ): draw_rect( x, y, "darkgreen", 0.7, 0 )
def draw_stairs_down( x, y ): draw_rect( x, y, "darkgreen", 0.7, 0 )
def draw_stairs_both( x, y ): draw_rect( x, y, "darkgreen", 0.7, 0 )
def draw_nothing( x, y ): pass
root.update()
drawmap()
root.mainloop()