【问题标题】:Can't click on image again, what's wrong with my pygame code?无法再次单击图像,我的 pygame 代码有什么问题?
【发布时间】:2017-02-20 01:14:37
【问题描述】:

好的,我正在尝试使用 pygame 库创建汤姆和杰瑞游戏。

游戏的重点是在老鼠出现在洞中时点击它们来捕捉老鼠。问题 是有时会出现一只猫而不是鼠标,如果玩家错误地点击了 cat (s)he 失去了所有获得的积分,但游戏继续进行。 老鼠是老鼠的形象,猫是猫的形象。 如果你点击鼠标,你会得到鼠标,否则猫会得到分数。 代码一团糟,那是因为我不知道自己在做什么,只是设置了另一个事件循环,因为它可以工作,因为它在我创建鼠标后运行。它可以单击鼠标,但然后您单击其他位置,然后就像您没有单击鼠标一样。

鼠标是在循环中创建的,应该等待 5 秒,如果您在这些秒内单击鼠标,则会在控制台中打印出相应的消息,Jerry clicked!" else "1 click"。如果你在 5 秒内没有点击鼠标,图像覆盖了鼠标,所以她消失了。

现在,我现在要做的是在玩家没有点击任何内容时打印消息 1 click ,而是在玩家点击鼠标时打印 1 click jerry clicked 。我有一个鼠标孔的图像,然后我将鼠标放在鼠标孔上,即另一个图像上。

此代码至少适用于一张图片:

pygame.init()
width=350;
height=400
screen = pygame.display.set_mode( (width, height ) )
pygame.display.set_caption('clicked on image')
redSquare = pygame.image.load("images/red-square.png").convert()

x = 20; # x coordnate of image
y = 30; # y coordinate of image
screen.blit(redSquare ,  ( x,y)) # paint to screen
pygame.display.flip() # paint screen one time

running = True
while (running):
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        if event.type == pygame.MOUSEBUTTONDOWN:
            # Set the x, y postions of the mouse click
            x, y = event.pos
            if redSquare.get_rect().collidepoint(x, y):
                print('clicked on image')
#loop over, quite pygame
pygame.quit()

我的问题是,当我点击鼠标然后我不点击鼠标时,我无法在另一个位置再次点击鼠标。

那怎么了?我在这里做错了什么?

这是我的代码:

import pygame
from pygame import *
from random import *

init()

run = True
screen = (800,800)
screen = display.set_mode(screen)
xpos = 0
ypos = 0
mouseorcatxpos = 5
mouseorcatypos = 0

mousehole = image.load("mousehole.png").convert()

cat = image.load("tom.png")
jerry = image.load("jerry.png")

def makeholes():
    global ypos
    global xpos

    for holey in range(1,9):

        for holex in range(1,9):
            screen.blit(mousehole,(xpos,ypos))
            display.flip()

            xpos += 100

        ypos += 100
        xpos = 0

def mouseorcat():
    global xpos
    mouseorcatxpos = 5
    ypos = 0

    for mousecaty in range(1,9):

            pygame.event.pump()

            for mousecatx in range(1,9):

                randommouse = randint(1, 3)
                randomcat = randint(1, 10)

                if(randommouse == 2):

                    screen.blit(jerry, (mouseorcatxpos, ypos))
                    display.flip()

                    for event in pygame.event.get():

                        if (event.type == MOUSEBUTTONDOWN):

                            if jerry.get_rect().collidepoint(xpos, ypos) == False:

                               print("l clicked!")

                            x, y = event.pos

                            if jerry.get_rect().collidepoint(xpos, y):
                                print("JERRY CLICKED!!")
                                x, y = event.pos
                                print(x, y)


                    time.wait(5000)
                    #screen.blit(mousehole, (mouseorcatxpos - 5, ypos))
                    display.flip()

                elif(randomcat == 2):
                    screen.blit(cat, (mouseorcatxpos, ypos))
                    display.flip()
                    time.wait(1500)
                    screen.blit(mousehole, (mouseorcatxpos-5, ypos))
                    display.flip()

                mouseorcatxpos += 100
            mouseorcatxpos = 0
            ypos += 100


makeholes()


while run == True:


    for event in pygame.event.get():
        mouseorcat()

        if event.type == QUIT:
            run = False

【问题讨论】:

  • 请详细说明游戏的规则和机制。我不确定它应该如何工作。看起来代码需要大幅重组。例如,应该只有一个事件循环和一个 display.flip() 调用。
  • 对于投反对票的人,不要粗鲁,不加解释就投反对票,而是帮助改善问题。
  • 我提交了一个带有全新示例的答案,但明天我会再看看你的程序,看看它是否可以“拯救”。 ;) 但是,它看起来确实不太好。不用太担心,大家一开始都是这样写代码的。另外,也许下次在reddit.com/r/pygame之类的论坛上寻求帮助会更好。
  • 我在回答中添加了一些注释。顺便说一句,我提到 reddit 是因为您的问题需要大量解释和调试,所以 SO 似乎不是正确的地方。
  • 看看Program Arcade Games。有一些有趣的示例可能会帮助您更好地学习构建代码。

标签: python debugging pygame


【解决方案1】:

我重写了你的游戏,向你展示我会怎么做。

为了跟踪时间并限制帧速率,我使用了 pygame.time.Clock 和计时器变量。时钟返回自上次调用clock.tick 以来的毫秒数,用于增加定时器变量。猫只是在两秒钟后更换鼠标,并将鼠标设置到新位置。我使用pygame.Rects 来存储位置,但您也可以使用列表或元组。

import sys
import random
import pygame


pygame.init()

size = (800, 800)
screen = pygame.display.set_mode(size)

# Images replaced by pygame.Surface. Do that too
# in the future before you post your code.
mousehole = pygame.Surface((40, 40)).convert()
mousehole.fill(pygame.Color(30, 30, 30))
cat = pygame.Surface((40, 40)).convert()
cat.fill(pygame.Color(110, 110, 130))
jerry = pygame.Surface((40, 40)).convert()
jerry.fill(pygame.Color(190, 130, 0))
# Create the background image and blit the holes.
background = pygame.Surface(size).convert()
for holey in range(8):
    for holex in range(8):
        background.blit(mousehole, (holex*100, holey*100))


def new_position():
    """Return a random position between 0-700 in steps of 100."""
    return (random.randrange(0, 701, 100), random.randrange(0, 701, 100))


def main():
    fps = 30
    clock = pygame.time.Clock()

    jerry_rect = jerry.get_rect()  # Stores jerry's position and size.
    jerry_rect.topleft = new_position() # New random position.
    # The cat is outside of the screen first.
    cat_rect = cat.get_rect(topleft=(-100, -100))
    points = 0
    timer = 0

    running = True
    while running:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
            if event.type == pygame.MOUSEBUTTONDOWN:
                if jerry_rect.collidepoint(event.pos):
                    points += 1
                    print('Jerry caught! Points:', points)
                    timer = 0
                    jerry_rect.topleft = new_position()
                else:
                    print('Missed. Points:', points)

        # Run logic.
        timer += clock.tick(fps) / 1000  # timer + seconds since last tick.
        if timer > 2:  # Cat catches mouse after 2 seconds.
            cat_rect.topleft = jerry_rect.topleft
            jerry_rect.topleft = new_position()
            timer = 0
            points = 0
            print('Tom caught Jerry.')
        # Draw.
        # Clear the screen by blitting the bg.
        screen.blit(background, (0, 0))  
        screen.blit(jerry, jerry_rect)
        screen.blit(cat, cat_rect)
        pygame.display.flip()

if __name__ == '__main__':
    main()
    pygame.quit()
    sys.exit()

旁注:

不要使用星号导入 (from module import *),因为这会使代码更难阅读。如果你愿意,你可以使用from pygame.locals import *,如果它是唯一的星号导入。

不要使用全局变量,因为它们会使代码更难阅读、理解和维护。将变量作为参数传递给函数,然后返回结果。


更新:关于您的程序的一些说明:

第一个大问题是您的游戏有两个事件循环,而重要的一个深深嵌套在另外两个 for 循环和一个 if 中。事件循环应该直接在主while循环之下(一个缩进级别(当您有更多经验时,您可以将其放入函数或类方法中))。


这两个for循环的目的似乎是让代码运行到randommouse或randomcat为2。运行代码直到满足条件是while循环的目的。但在这种情况下,您最好选择一个随机数并编写 if/elif 条件,以便它们始终适用。例如,您希望鼠标有 2/3 的机会,猫有 1/3 的机会,

random_number = random.randint(1, 3)
if random_number < 3:
    print("2/3 probability. It's a mouse")
else:
    print("1/3 probability. It's a cat")

或将random.choice 与列表一起使用:

>>> random.choice(['mouse', 'mouse', 'cat'])
'mouse'

time.wait(5000) 不应该被使用,因为此时游戏只是挂起。你甚至不能关上窗户。使用pygame.time.Clock 限制帧速率并获取自上次滴答以来的时间。


pygame.event.pump() 不需要。


如果你在没有参数的情况下调用 get_rect(),矩形定位在 (0, 0)。

if jerry.get_rect().collidepoint(xpos, y):

这就是为什么单击 jerry 只能在顶行起作用的原因,并且因为您在这里使用全局 xpos。由于 xpos 为 0,因此整个顶行都算作 Jerry。

您可以像这样将坐标传递给get_rect(您也可以使用center 或其他args 代替topleft):

jerry_rect = jerry.get_rect(topleft=(50, 100))

很抱歉,我认为我不能简单地修复您的代码。我试过好几次了,但我总是完全重写它。

我首先从两个嵌套的 for 循环中提取事件循环,然后删除这些循环,为鼠标和猫创建矩形,修复碰撞检测,添加计时器等等。仔细看看我的例子,尝试用类似的方式重写你的游戏,如果你有不明白的地方继续提问。

【讨论】:

  • 我从我的编程老师那里得到了一些代码,这些代码只需稍加改动即可完成任务。感谢您的帮助,我接受此作为答案,因为此代码也可以工作,并且可以在这样的项目中使用它。我没有在这里展示我的代码的原因是我没有自己编写大部分代码并且为了尊重作者,我不会在未经许可的情况下发布他的代码。是的,问题中的代码不可用,太糟糕了:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-01-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多