我正在尝试用Python制作一个微环境模拟器,到目前为止我有一个分形图生成器和一个简单的碰撞检测类移动'实体'。当画布稀疏时,实体工作正常,但现在它必须在每次更新时重绘地图,它运行缓慢。我正在使用create_rectangle来显示地图矩阵顶部的实体矩阵(它被称为'tiles')。
我已经尝试过使用pygame和其他一些模块,但我不能让它们与任何版本的python(甚至是旧的和32位版本)一起工作,我想这是因为我运行的是Windows 7 64-他们似乎不兼容。
无论如何,有没有办法更快地可视化这两个矩阵,以便我可以获得更高的FPS?
非常感谢,这是我的代码(你可以用箭头键移动白色实体!!!):
from Tkinter import *
from random import *
from time import *
root = Tk()
w = Canvas(root, width = 640, height=640)
w.pack()
entities = []
running = True
## Size of squares, in pixels
size = 5
## Make tiles a 128x128 array
tiles = []
for i in range(128):
tiles.append(128*[0])
## IMPORTANT: all entities must have .x and .y attributes!
class Entity:
def __init__(self):
self.setup()
entities.append(self)
def setup(self, x=0,y=0, name='Undefined', color='pink'):
self.x = x
self.y = y
self.name = name
self.color = color
def checkCollsn(self, try_x , try_y):
for i in entities:
if i is not self and try_x == i.x and try_y == i.y:
print i.name, 'is in the way of', self.name, '!'
return False
else:
## print 'All clear!'
return True
def maintain(self):
for i in entities:
if i is not self:
## Detect anything in immediate proximity:
dx = abs(i.x - self.x)
dy = abs(i.y - self.y)
if (dx == 1 or dx == 0) and (dy == 1 or dy== 0):
print self.name, 'has detected', i.name
## TODO: Then what?
## TODO: Add other 'maintainance checks' here.
class Mobile(Entity): ## Mobile is a subclass of Entity, which can move!
def up(self):
if self.y < 1:
print 'Upper bound!'
else:
if self.checkCollsn(self.x, self.y-1):
self.y -= 1
def down(self):
if self.y > 127:
print 'Lower bound!'
else:
if self.checkCollsn(self.x, self.y+1):
self.y += 1
def left(self):
if self.x < 1:
print 'Leftmost bound!'
else:
if self.checkCollsn(self.x-1, self.y):
self.x -= 1
def right(self):
if self.x > 127:
print 'Rightmost bound!'
else:
if self.checkCollsn(self.x+1, self.y):
self.x += 1
def fractalGen(iterations=5, chanceWater=0.5):
for i in range(iterations):
if i == 0:
## Generate random 16x16 blocks
blockNo = 8
blockLen = 16
randomize = True
fractalize = False
else:
randomize = False
fractalize = True
if i == 1:
blockNo = 16
blockLen = 8
if i == 2:
blockNo = 32
blockLen = 4
if i == 3:
blockNo = 64
blockLen = 2
if i == 4:
blockNo = 128
blockLen = 1
if i > 4:
print 'Excessive i value! Was', i
for yBlock in range(blockNo):
## If it stays red, something's screwy!
blockVal = 0
for xBlock in range(blockNo):
if randomize:
## print 'i:',i,'Randomizing.'
r = random()
if r <= chanceWater:
blockVal = 4
else: blockVal = 3
if fractalize:
land = 0
water = 0
## First, assess surrounding % water of all valid surrounding blocks.
## Remember, blocks are now higher res than previous iteration!
xRange = [0] ## This paragraph makes sure we're staying within
yRange = [0] ## the range of the matrix.
if xBlock != 0:
xRange.append(-1)
if xBlock != blockNo-1:
xRange.append(1)
if yBlock != 0:
yRange.append(-1)
if yBlock != blockNo-1:
yRange.append(1)
for ySign in yRange:
yCheck = (yBlock+ySign)*blockLen
for xSign in xRange:
xCheck = (xBlock+xSign)*blockLen
if xSign ==0 and ySign == 0:
selfVal = tiles[yCheck][xCheck]
## print 'Self is', selfVal
else:
if tiles[yCheck][xCheck] == 4:
## print 'Water at', xCheck, yCheck
water += 1
if tiles[yCheck][xCheck] == 3:
land += 1
## print 'Land at', xCheck, yCheck
percentWater = water/float(land+water)
##print percentWater
if selfVal == 4: #If self is water, oppSurr is % land
oppSurr = 1 - percentWater
if selfVal == 3: #If self is land, oppSurr is % water
oppSurr = percentWater
r = randint(0,25)/100.0
##print oppSurr, r, oppSurr + r
if oppSurr + r >= 0.625:
## If surroundings + random > 50%, switch self type!
if selfVal == 4:
blockVal = 3
## print 'To land'
elif selfVal == 3:
blockVal = 4
## print 'To water'
## else: print 'Not switched, remains', selfVal
else: blockVal = selfVal
## NB: Must assign blockVal in all cases, otherwise
## you get the last value of blockVal carried over!
for y in range(yBlock*blockLen,(yBlock+1)*blockLen):
for x in range(xBlock*blockLen,(xBlock+1)*blockLen):
tiles[y][x] = blockVal
def drawWorld():
w.delete(ALL)
x=0
y=0
for i in tiles:
for j in i:
color = 'gray'
if j == 0: tColor = 'red'
if j == 1: tColor = 'orange'
if j == 2: tColor = 'yellow'
if j == 3: tColor = 'green'
if j == 4: tColor = 'blue'
if j == 5: tColor = 'purple'
w.create_rectangle(x,y,x+size,y+size,fill=tColor)
x += size
x = 0
y += size
for i in entities:
w.create_rectangle(i.x*size, i.y*size, i.x*size+size, i.y*size+size, fill=i.color)
w.update()
fractalGen(5,.4)
drawWorld()
def keyPress(event):
if event.keysym == 'Up':
p.up()
if event.keysym == 'Down':
p.down()
if event.keysym == 'Left':
p.left()
if event.keysym == 'Right':
p.right()
def moveRand(ent):
cmd = randint(0,3)
if cmd == 0: ent.up()
if cmd == 1: ent.down()
if cmd == 2: ent.left()
if cmd == 3: ent.right()
## Player:
p = Mobile()
p.setup(0,5,'Man', 'white')
## Boulder:
b = Entity()
b.setup(10,15,'Boulder','black')
## Flower:
f = Entity()
f.setup(5,5,'Flower', 'red')
## Elf:
elf = Mobile()
elf.setup(10,10,'Elf','green')
interval = 0.2
while running:
moveRand(elf)
root.bind_all('<Key>', keyPress)
for i in entities:
i.maintain()
drawWorld()
答案 0 :(得分:1)
可能需要做一些事情来改善代码的FPS:
答案 1 :(得分:0)
你可能已经达到了Tk的极限 - 它不是为动画和其他花哨的步法而设计的。
最好的选择是优化的库,例如PyGame。应该没有理由不能在Win 7 64bit上运行 - 只要确保你有一个与PyGame匹配的Python(可能是32位Python)。
答案 2 :(得分:-1)
一些微小的变化:
from Tkinter import *
from random import *
from time import *
root = Tk()
w = Canvas(root, width = 640, height=640, bd=0, highlightthickness=0)
w.pack()
entities = []
running = True
## Size of squares, in pixels
size = 5
## Make tiles a 128x128 array
tiles = []
for i in range(128):
tiles.append(128*[0])
## IMPORTANT: all entities must have .x and .y attributes!
class Entity:
def __init__(self):
self.setup()
entities.append(self)
def setup(self, x=0,y=0, name='Undefined', color='pink'):
self.x = x
self.y = y
self.name = name
self.color = color
def checkCollsn(self, try_x , try_y):
for i in entities:
if i is not self and try_x == i.x and try_y == i.y:
#print i.name, 'is in the way of', self.name, '!'
return False
else:
## print 'All clear!'
return True
def maintain(self):
for i in entities:
if i is not self:
## Detect anything in immediate proximity:
dx = abs(i.x - self.x)
dy = abs(i.y - self.y)
if (dx == 1 or dx == 0) and (dy == 1 or dy== 0):
pass
#print self.name, 'has detected', i.name
## TODO: Then what?
## TODO: Add other 'maintainance checks' here.
class Mobile(Entity): ## Mobile is a subclass of Entity, which can move!
def up(self):
if self.y < 1:
self.y = 0
else:
if self.checkCollsn(self.x, self.y-1):
self.y -= 1
def down(self):
if self.y > 127:
self.y = 127
else:
if self.checkCollsn(self.x, self.y+1):
self.y += 1
def left(self):
if self.x < 1:
self.x = 0
else:
if self.checkCollsn(self.x-1, self.y):
self.x -= 1
def right(self):
if self.x > 127:
self.x = 127
else:
if self.checkCollsn(self.x+1, self.y):
self.x += 1
def fractalGen(iterations=5, chanceWater=0.5):
for i in range(iterations):
if i == 0:
## Generate random 16x16 blocks
blockNo = 8
blockLen = 16
randomize = True
fractalize = False
else:
randomize = False
fractalize = True
if i == 1:
blockNo = 16
blockLen = 8
if i == 2:
blockNo = 32
blockLen = 4
if i == 3:
blockNo = 64
blockLen = 2
if i == 4:
blockNo = 128
blockLen = 1
if i > 4:
print 'Excessive i value! Was', i
for yBlock in range(blockNo):
## If it stays red, something's screwy!
blockVal = 0
for xBlock in range(blockNo):
if randomize:
## print 'i:',i,'Randomizing.'
r = random()
if r <= chanceWater:
blockVal = 4
else: blockVal = 3
if fractalize:
land = 0
water = 0
## First, assess surrounding % water of all valid surrounding blocks.
## Remember, blocks are now higher res than previous iteration!
xRange = [0] ## This paragraph makes sure we're staying within
yRange = [0] ## the range of the matrix.
if xBlock != 0:
xRange.append(-1)
if xBlock != blockNo-1:
xRange.append(1)
if yBlock != 0:
yRange.append(-1)
if yBlock != blockNo-1:
yRange.append(1)
for ySign in yRange:
yCheck = (yBlock+ySign)*blockLen
for xSign in xRange:
xCheck = (xBlock+xSign)*blockLen
if xSign ==0 and ySign == 0:
selfVal = tiles[yCheck][xCheck]
## print 'Self is', selfVal
else:
if tiles[yCheck][xCheck] == 4:
## print 'Water at', xCheck, yCheck
water += 1
if tiles[yCheck][xCheck] == 3:
land += 1
## print 'Land at', xCheck, yCheck
percentWater = water/float(land+water)
##print percentWater
if selfVal == 4: #If self is water, oppSurr is % land
oppSurr = 1 - percentWater
if selfVal == 3: #If self is land, oppSurr is % water
oppSurr = percentWater
r = randint(0,25)/100.0
##print oppSurr, r, oppSurr + r
if oppSurr + r >= 0.625:
## If surroundings + random > 50%, switch self type!
if selfVal == 4:
blockVal = 3
## print 'To land'
elif selfVal == 3:
blockVal = 4
## print 'To water'
## else: print 'Not switched, remains', selfVal
else: blockVal = selfVal
## NB: Must assign blockVal in all cases, otherwise
## you get the last value of blockVal carried over!
for y in range(yBlock*blockLen,(yBlock+1)*blockLen):
for x in range(xBlock*blockLen,(xBlock+1)*blockLen):
tiles[y][x] = blockVal
def drawWorld():
x=0
y=0
for i in tiles:
for j in i:
color = 'gray'
if j == 0: tColor = 'red'
if j == 1: tColor = 'orange'
if j == 2: tColor = 'yellow'
if j == 3: tColor = 'green'
if j == 4: tColor = 'blue'
if j == 5: tColor = 'purple'
w.create_rectangle(x,y,x+size,y+size,fill=tColor)
x += size
x = 0
y += size
w.update()
def draw_entities():
w.delete('ent')
for i in entities:
w.create_rectangle(i.x*size, i.y*size, i.x*size+size, i.y*size+size, fill=i.color, tags='ent')
def moveRand(ent):
cmd = randint(0,3)
if cmd == 0: ent.up()
if cmd == 1: ent.down()
if cmd == 2: ent.left()
if cmd == 3: ent.right()
def keyPress(event):
if event.keysym == 'Up':
p.up()
if event.keysym == 'Down':
p.down()
if event.keysym == 'Left':
p.left()
if event.keysym == 'Right':
p.right()
fractalGen(5,.4)
drawWorld()
## Player:
p = Mobile()
p.setup(0,5,'Man', 'white')
## Boulder:
b = Entity()
b.setup(10,15,'Boulder','black')
## Flower:
f = Entity()
f.setup(5,5,'Flower', 'red')
## Elf:
elf = Mobile()
elf.setup(10,10,'Elf','pink')
##interval = 0.2 #?
draw_entities()
root.bind_all('<Key>', keyPress)
try:
while running:
moveRand(elf)
for i in entities:
i.maintain()
draw_entities()
w.update()
except TclError:
pass