python - 在处理网格内的光标移动时如何提高性能? (皮游戏)

标签 python performance grid cursor pygame

好吧,用鼠标移动某个矩形非常简单。然而,当您想在“网格”内移动它时,事情就不那么简单了。

我的游戏默认分辨率是1024|768,整个屏幕都是(1024/16)|(768/16)的图 block 。这意味着 64|48。每个图 block 可以是一堵墙、一个玩家、一个敌人、一个元素或任何东西。

因此,光标是一个“选择光标”,提供有关图 block 的信息(它按图 block 移动,而不是按像素移动)。

我知道怎么做,但有一个问题:

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()

这意味着它在每个帧都会执行一个二维循环,以便在图 block 上移动鼠标选择光标。结果?当然,滞后。 当鼠标位于图 block 内时,光标会发生变化。为了检查它,有必要循环遍历当前正在绘制的所有图 block 。您知道如何在不使用二维循环的情况下做到这一点以节省一些处理能力吗?

最佳答案

您可以通过为 block /图 block 提供一个世界坐标(仅表示网格内 block 的列和行)来简化您的解决方案,而不是每次都手动计算。

然后,您可以在将鼠标位置转换为世界坐标后简单地进行检查。

此外,您可以创建一个字典,将每个列/行映射到 block /图 block 对象(您没有显示其余的代码,所以我不知道您实际上如何存储图 block ;也许是列表的列表?如果是,那么您只需使用索引检索正确的图 block 即可。

这会让你摆脱循环。

<小时/>

此外,我认为使用 pygame.event.poll() 而不是 pygame.event.get() 也可能是一个问题。

使用poll时,您只能从事件队列中获取一个事件。这意味着每一帧只能处理一个事件。也许这会导致你的滞后?

您还应该检查在主循环中运行的其他函数。我会运行一个分析器来查看游戏的瓶颈在哪里(有时结果令人惊讶)。

<小时/>

这是一个使用dict查找鼠标光标下的图 block 的简单示例。更多解释见评论。

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

关于python - 在处理网格内的光标移动时如何提高性能? (皮游戏),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23774440/

相关文章:

python - 如何允许在 PyQt4 中调整 QMessageBox 的大小

python - 使用字典和数组将点符号字符串转换为嵌套的 Python 对象

python - 如何在 Python 2.7 中检查字符串是(int 还是 float)

javascript - 什么更快 : anchoring or hide/show with JS?

wpf - 如何绑定(bind)到 RowDefinition 的高度?

selenium - 无法使用 Selenium Grid 访问虚拟机上的节点

python - 使用相同库的多个 AWS Lambda 函数

css - 使用转换 :all when only transitioning one property

mysql - MySQL 中的多字段索引是一个不错的选择吗?

jquery - Portfolio Grid随机间距@media查询