2014-05-21 19 views
1

好吧,用鼠標移動一些矩形很容易。儘管如此,當你想在「網格」中移動它時,事情並不那麼簡單。如何在處理網格中的光標移動時提高性能? (Pygame)

默認情況下,我的遊戲分辨率爲1024 | 768,整個屏幕都填滿了(1024/16)|(768/16)的貼圖。這意味着64 | 48。每個瓷磚可以是牆壁或玩家或敵人或物品或任何東西。

所以光標是一個「選擇光標」,它提供關於瓦片的信息(它通過瓦片而不是像素移動)。

我知道該怎麼做,但有一個問題:

def move(self,pos): 

    mouseX = pos[0] 
    mouseY = pos[1] 

    for i in range(0,16*Wall.BRICK_HEIGHT,Wall.BRICK_HEIGHT): // Brick Height = 48 
     for j in range(0,16*Wall.BRICK_WIDTH,Wall.BRICK_WIDTH): // Brick Width = 64 
      if (((mouseX > j) and (mouseX < (j + Wall.BRICK_WIDTH)) and (mouseY > i) and (mouseY < (i + Wall.BRICK_HEIGHT)))): 
       self.x = j 
       self.y = i 

我運行遊戲主循環內此過程:

while not e.Global.DONE: 

game.runLanguageMenu() 
game.runIntroduction() 
game.runMainMenu() 
game.runDungeonMenu() 
game.loadStuff() 
game.runPauseMenu() 

event = pygame.event.poll() 
if event.type == pygame.QUIT: 
    e.Global.DONE = True 
elif event.type == pygame.MOUSEMOTION: 
    if e.Global.gameScreen == "GAME": 
     game.cursor.move(event.pos) // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 

if e.Global.gameScreen == "GAME": 
    game.player.move(pygame.key.get_pressed()) 
    game.runGame() 

pygame.display.flip() 

這意味着在每一幀它一個二維循環爲了移動鼠標選擇光標通過瓦片。結果?延遲,當然。 當鼠標位於其中時,光標會發生變化。爲了檢查它,有必要遍歷當前正在繪製的所有圖塊。你知道怎麼做,而不使用二維循環來節省一些處理能力嗎?

回答

1

您可以通過給塊/瓦片世界座標(即表示網格內塊的列和行)而不是每次手動計算它來簡化您的解決方案。

然後,你可以簡單地檢查後,將鼠標位置翻譯爲世界座標。另外,您可以創建一個字典,將每個列/行映射到塊/瓷磚對象(您沒有顯示剩餘的代碼,因此我不知道您是如何實際存儲瓷磚的;也許列表列表?如果是,那麼您只需檢索具有索引的正確圖塊)。

這會讓你擺脫循環。


另外,我覺得使用pygame.event.poll()代替pygame.event.get()可能是一個問題了。

使用poll時,您只能從事件隊列中獲取一個事件。這意味着您每幀只能處理一個事件。也許這會導致你的滯後?

您應該檢查您在主循環中運行的其他函數。我會運行一個分析器來查看遊戲瓶頸的位置(有時結果令人驚訝)。


下面是使用dict來查找鼠標光標下的圖塊的簡單示例。評論中有更多解釋。

import pygame 
import random 

pygame.init() 

BRICK_HEIGHT = 48 
BRICK_WIDTH = 64 

class Block(object): 
    def __init__(self, x=0, y=0, num=0, width=0, color=(122, 122, 122)): 
     # w_x and w_y represents the world coordinates 
     # that means the 'column' and 'row' in the 'grid' 
     self.w_x, self.w_y = x, y 
     # to calculate the absolute (screen) position, 
     # simply multiply x, y with BRICK_WIDTH, BRICK_HEIGHT 
     self.rect = pygame.rect.Rect(x*BRICK_WIDTH, y*BRICK_HEIGHT, BRICK_WIDTH, BRICK_HEIGHT) 
     self.width = width 
     self.color = color 

    def draw(self, surface): 
     pygame.draw.rect(surface, self.color, self.rect, self.width) 

    def move(self, global_pos): 
     # to translate the absolute (screen) position 
     # back to the world coordinates, simply divide 
     # with BRICK_WIDTH, BRICK_HEIGHT 
     x, y = global_pos 
     self.w_x = (x/BRICK_WIDTH) 
     self.w_y = (y/BRICK_HEIGHT) 
     # recalculate the absolute (screen) position, 
     # so the cursor "snaps" to the grid 
     self.rect.x = self.w_x * BRICK_WIDTH 
     self.rect.y = self.w_y * BRICK_HEIGHT 

screen = pygame.display.set_mode((10*BRICK_WIDTH, 10*BRICK_HEIGHT)) 
clock = pygame.time.Clock() 

c = Block(width=4, color=(200, 255, 200)) 

def r_color(): 
    return (random.randint(30, 255), 
      random.randint(30, 255), 
      random.randint(30, 255)) 

# blocks maps (column, row) to a block 
# note that this keeps the information of the 
# position of a block at *two* places, which needs 
# to be in sync. That's a drawback, but the 
# lookup is fast! 
blocks = {} 
for x in xrange(10): 
    for y in xrange(10): 
     if random.randint(0, 100) < 33: 
      blocks[(x, y)] = Block(x, y, color=r_color()) 

while True: 
    pos = pygame.mouse.get_pos() 
    c.move(pos) 

    for e in pygame.event.get(): 
     if e.type == pygame.QUIT: 
      raise Exception() 
     if e.type == pygame.MOUSEBUTTONDOWN: 
      # finding the tile under the mouse is as easy as: 
      block = blocks.get((c.w_x, c.w_y)) 
      # and since it's a dict, the lookup is very fast. 
      print 'Selected block color: {}'.format(block.color) if block else 'No block selected' 

    screen.fill((0, 30, 30)) 
    for b in blocks.values(): 
     # The blocks calculated their absolute position by themself. 
     # That may or may not what you want. Another way is to calculate 
     # their absolute position here, so the blocks only needs to 
     # know about their world coordinates 
     b.draw(screen) 
    c.draw(screen) 

    # run at 60 FPS 
    clock.tick(60) 
    pygame.display.flip() 

enter image description here

+0

輝煌!非常感謝你。在發佈這個問題之後不久,我發現引起巨大延遲的原因實際上是poll()而不是get()。儘管如此,你的解決方案要聰明得多(考慮到我使用「碰撞方法」來「選擇」),我的解決方案可能會更復雜一些。不,我不使用字典。世界實際上是由程序產生的。我生成了N個迷宮的隨機迷宮(每個屏幕都是不同的迷宮),並且它們存儲在一個列表中。每個迷宮都是一個列表,地牢本身就是迷宮對象列表。非常感謝你!! –