简体   繁体   English

如何在pygame中创建交互式对象?

[英]How can I create an interactive object in pygame?

In a pygame program I am creating, I have need for an interactive object on the screen that will call a function when the player character moves onto it and presses the enter key. 在我创建的pygame程序中,我需要屏幕上的一个交互式对象,当玩家角色移到该对象并按Enter键时,该对象将调用该函数。 Here is the code I have so far: 这是我到目前为止的代码:

import pygame

pygame.init()
screen = pygame.display.set_mode((800, 600))
done = False
x = 30
y = 30

clock = pygame.time.Clock()

while not done:
        for event in pygame.event.get():
                if event.type == pygame.QUIT:
                        done = True

    pressed = pygame.key.get_pressed()
    if pressed[pygame.K_UP] and y > 0: y -= 5
    if pressed[pygame.K_DOWN] and y < 600 - 60: y += 5
    if pressed[pygame.K_LEFT] and x > 0: x -= 5
    if pressed[pygame.K_RIGHT] and x < 800 - 60: x += 5

    screen.fill((0, 0, 0))
    color = (0, 128, 255)
    pygame.draw.rect(screen, color, pygame.Rect(x, y, 60, 60))

    myfont = pygame.font.SysFont("monospace", 15)

    label = myfont.render("Start the experiment simulator", 1, (255,255,255))
    screen.blit(label, (100, 100))

    label2 = myfont.render("Start the quiz", 1, (255,255,255))
    screen.blit(label2, (550, 100))

    label3 = myfont.render("Quit game", 1, (255,255,255))
    screen.blit(label3, (350, 400))

    pygame.draw.rect(screen, red, pygame.Rect(600, 125, 30, 30))
    pygame.draw.rect(screen, red, pygame.Rect(225, 125, 30, 30))
    pygame.draw.rect(screen, red, pygame.Rect(375, 425, 30, 30))

    pygame.display.flip()
    clock.tick(60)

At the moment, the object is just a test so would be best to be a small red rectangle, about half the size of the player, that I can replace with an icon later on. 目前,该对象只是一个测试,因此最好是一个小的红色矩形,大约是播放器大小的一半,稍后可以用图标替换。 This rectangle should be placed below the 'quit game' label on the pygame window and quit the game when interacted with. 将该矩形放置在pygame窗口上“退出游戏”标签下方,并在与之互动时退出游戏。 This is one method that I have tried so far: 到目前为止,这是我尝试过的一种方法:

if pressed[pygame.K_RETURN] and x >= 375 or x <= 405 and y >=425 or y <= 455:
            pygame.display.quit()
            pygame.quit()
            sys.exit()

Where theoretically the system checks if the user is in a specific area and has pressed the enter key before performing the command. 从理论上讲,系统会在执行命令之前检查用户是否在特定区域中并按下Enter键。

Answer to my own question, I managed to make my first attempt work by adding brackets around the x and y checks in this section: 回答我自己的问题,我设法通过在此部分的x和y支票周围添加方括号来使我的第一次尝试成功:

and x >= 375 or x <= 405 and y >=425 or y <= 455:

So that it now reads: 现在,它显示为:

and (x >= 375 and x <= 405) and (y >= 425 and y <= 455):

You can check for collision, using pygame's colliderect 您可以使用pygame的colliderect检查碰撞

First, create three rects that will represent your three option rects : 首先,创建三个rect,它们将代表您的三个选项rect:

simulator_rect = pygame.Rect(600, 125, 30, 30)
quiz_rect = pygame.Rect(225, 125, 30, 30)
quit_rect = pygame.Rect(375, 425, 30, 30)

Next, we'll create a rect that will represent the blue selector rect : 接下来,我们将创建一个表示蓝色选择器rect的rect:

selector_rect = pygame.Rect(50, 50, 60, 60)

So now you've got rects that are created only once, instead of unnamed rects that are created every time 因此,现在您只能创建一次rect,而不是每次都创建未命名的rect。

Now, for the actual collision detection : 现在,对于实际的碰撞检测:

# Check to see if the user presses the enter key
    if pressed[pygame.K_RETURN]:
        # Check to see if the selection rect 
        # collides with any other rect
        for rect in option_rects:
            if selector_rect.colliderect(rect):
                if rect == simulator_rect:
                    # Do simulations stuff!
                    print('Simulating!')
                elif rect == quiz_rect:
                    # Do quizzing stuff!
                    print('Quizzing!')
                elif rect == quit_rect:
                    # Quit!
                    done = True

Final code : 最终代码:

import pygame

pygame.init()
screen = pygame.display.set_mode((800, 600))
done = False
x = 30
y = 30

clock = pygame.time.Clock()

# RGB values for red
red = (255, 0 ,0)

# Your three button rects :
simulator_rect = pygame.Rect(225, 125, 30, 30)
quiz_rect = pygame.Rect(600, 125, 30, 30)
quit_rect = pygame.Rect(375, 425, 30, 30)
# These represent your three option rects
option_rects = [simulator_rect, quiz_rect, quit_rect]

# Your blue selector rect
selector_rect = pygame.Rect(50, 50, 60, 60)
# The 50, 50 xy coords are temporary

while not done:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            done = True

    pressed = pygame.key.get_pressed()
    if pressed[pygame.K_UP] and y > 0: y -= 5
    if pressed[pygame.K_DOWN] and y < 600 - 60: y += 5
    if pressed[pygame.K_LEFT] and x > 0: x -= 5
    if pressed[pygame.K_RIGHT] and x < 800 - 60: x += 5

    # Set the slector rect's coords to x/y
    selector_rect.x, selector_rect.y = x, y

    screen.fill((0, 0, 0))

    color = (0, 128, 255)
    pygame.draw.rect(screen, color, selector_rect)

    myfont = pygame.font.SysFont("monospace", 15)

    label = myfont.render("Start the experiment simulator", 1, (255,255,255))
    screen.blit(label, (100, 100))

    label2 = myfont.render("Start the quiz", 1, (255,255,255))
    screen.blit(label2, (550, 100))

    label3 = myfont.render("Quit game", 1, (255,255,255))
    screen.blit(label3, (350, 400))

    # Use our created rects
    pygame.draw.rect(screen, red, simulator_rect)
    pygame.draw.rect(screen, red, quiz_rect)
    pygame.draw.rect(screen, red, quit_rect)

    # Check to see if the user presses the enter key
    if pressed[pygame.K_RETURN]:
        # Check to see if the selection rect 
        # collides with any other rect
        for rect in option_rects:
        # Add rects as needed
            if selector_rect.colliderect(rect):
                if rect == simulator_rect:
                    # Do simulations stuff!
                    print('Simulating!')
                elif rect == quiz_rect:
                    # Do quizzing stuff!
                    print('Quizzing!')
                elif rect == quit_rect:
                    # Quit!
                    done = True




    pygame.display.flip()
    clock.tick(60)

This does add some complication to your program, but at least it's a rock solid method that you can add features too, and that will remain robust. 这确实给程序增加了一些复杂性,但是至少它是坚如磐石的方法,您也可以添加功能,并且这种方法仍然很健壮。

I just create a system for interactable object and it easy to scale. 我只是为可交互对象创建了一个系统,它易于扩展。

listBox = [] # this list used to store all object inside

listBox.append(("text", pos, size, bgColor, textColor, InteractAction)) 
# add dumy object to the list, "text" can be empty if you dont want.

def InteractAction(mousePos):  # sample action used to tie to object
    print("do somehthing")    

def newDrawBox(IableO):
      pygame.draw.rect(gameDisplay, IableO[3],(IableO[1][0], IableO[1][1], IableO[2][0], IableO[2][1]))
      text = basicfont.render(str(IableO[0]), True,IableO[4], None)
      textrect = text.get_rect()
      textrect.centerx = IableO[1][0] + IableO[2][0] / 2
      textrect.centery = IableO[1][1] + IableO[2][1] / 2
      gameDisplay.blit(text, textrect)

while not gameExit:
  for event in pygame.event.get():
        if event.type == pygame.QUIT:
            gameExit = True
        elif event.type == pygame.MOUSEBUTTONDOWN:
            Mouse[event.button] = 1
            Mouse[0] = (event.pos[0], event.pos[1])
        elif event.type == pygame.MOUSEBUTTONUP:
            Mouse[event.button] = 0
            Mouse[0] = (event.pos[0], event.pos[1])
#-------- check if mouse is click on any object in the list of Interatable object
  if Mouse[1] == 1:
        for x in listBox:
            if x[1][0] < Mouse[0][0] < x[1][0] + x[2][0] and x[1][1] < Mouse[0][1] < x[1][1] + x[2][1]:
                x[5](Mouse[0])
#---- draw all object -----
  for x in listBox:
        newDrawBox(x)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM