2010-12-29 13 views
0

私はPythonで微環境シミュレータを作ろうとしていますが、これまでフラクタルマップジェネレータと簡単な衝突検出クラスのエンティティがありました。キャンバスが疎であったときにエンティティが正常に機能しましたが、各更新でマップを再描画する必要があるので、ゆっくりと実行されます。私はマップマトリックス(それは 'タイル'と呼ばれる)の上にエンティティの行列を視覚化するcreate_rectangleのを使用しています。Tkinterのウィンドウをすばやく再描画 - より速い方法とは?

私はpygameといくつかの他のモジュールを使用しようとしましたが、Pythonのどのバージョン(これも古いバージョンと32ビットバージョン)で動作させることはできません。これはWindows 7 64彼らは互換性がないようです。

とにかく、これらの2つのマトリックスをより迅速に視覚化して、より高い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

をあなたはおそらくのTkの限界に達してきた - そのは、アニメーションのために設計されていませんファンシーなフットワーク。

最適なオプションは、PyGameなどの最適化されたライブラリです。 Win 7 64bitで動かない理由はないはずです。PyGame(おそらく32bit Python)に合ったPythonがあることを確認してください。

+0

はpygameのダウンロードが実行されない理由があってはならないが、それは失敗しますそれにもかかわらず実行する!私は32ビットPython 2.6.6を試しましたが、pygameはインストールされますが、例のどれも動作しません!たとえば、次のようになります。 トレースバック(最新の最終コール): ファイル "C:\ Python26 \ Lib \ site-packages \ pygame \ examples \ chimp.py"、行18、 main_dir = os.path。 split(os.path.abspath(__ file __))[0] NameError:名前 '__file__'が定義されていません どうしてですか? ありがとうございます。 –

+0

実際、pygameは私がオンラインになったいくつかの例では動作しますが、インストールに付属の例(ex、chimp.py)では動作しません!何が起こっているのでしょうか? –

+0

Tkの制限ではなく、TkはTcl'ers wikiのデモやゲームを見て、ちょっとしたアニメをやってもいいです。たとえば、http://wiki.tcl.tk/898のリンク – schlenk

0

いくつかのことは、おそらくあなたのコードのFPSを改善するために行うことができます。

  1. (w.updateを取り除く)と(メインループを経由して、通常のイベントループを使用)
  2. を取り除きます
  3. チェックの代わりに衝突検出を行うには、キャンバスのfind()メソッドの助けを借りて、Pythonコード
  4. でのみ実行してください。
  5. Tclで書き直して、不自由なCPythoの代わりにTclのスレッドを使うことができますn個のスレッド(あなたは1 CPU /コア以上のものを持っている場合にのみ有効);-)
-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 
関連する問題