Я пытаюсь создать симулятор микросреды в Python, и до сих пор у меня есть генератор фрактальных карт и простой класс обнаружения столкновений с движущимися «сущностями». Сущности работали хорошо, когда холст был разреженным, но теперь, когда он должен перерисовывать карту с каждым обновлением, он работает медленно. Я использую create_rectangle для визуализации матрицы объектов поверх матрицы карты (она называется «плитки»).
Я пытался использовать 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()