Pygame mouse event.rel не работает за пределами окна - PullRequest
1 голос
/ 08 февраля 2020

Я пытаюсь реализовать функцию в Pygame, где, если пользователь перемещает мышь за пределы окна, относительная позиция (event.rel) может быть возвращена. Я пытаюсь сделать это, потому что я хочу сделать игру, в которой вы можете продолжать поворачивать влево или вправо от ввода мышью.

Я знаю, что это возможно из документов:

Если курсор мыши скрыт и ввод захватывается текущим дисплеем, мышь переходит в режим виртуального ввода, при котором относительные движения мыши никогда не будут останавливаться на границах экрана. См. Функции pygame.mouse.set_visible () и pygame.event.set_grab (), чтобы настроить это.

По этой причине я реализовал эти строки в своем коде

pygame.mouse.set_visible(False)
pygame.event.set_grab(True)

Однако это не помогает. Фактическое поведение:

  • , когда мышь перемещается в окне, event.rel печатает на консоль (ожидается)
  • , когда мышь перемещается за пределы окна, событие. rel не печатает на консоль (не ожидается)

Другое странное поведение:

  • Первоначально для event.rel установлено значение (300, 300), которое является центром моего экрана 600x600. В идеале начальный event.rel должен быть (0,0)

Возможная причина:

  • Я запускаю приведенный ниже код в trinket.io или repl.it . Поскольку это браузер, демонстрационное окно может вызвать проблемы. Может быть, это решается загрузкой python локально, но я не хочу этого делать, так как это занимает слишком много места (мой ноутбук отстой), а также было бы хорошо иметь онлайн-демонстрацию, чтобы легко показывать слишком ленивым работодателям вставить код в их IDE.

Аналогичная проблема: у этого парня на reddit была очень похожая проблема, но я думаю, что его решение не связано с моей ситуацией

Этот блок кода был тем, что я спрашивал изначально, но он не демонстрирует вопрос так же, как последний блок. Пожалуйста, прокрутите вниз, чтобы увидеть последний блок кода:)

import pygame
pygame.init()

# screen
X = 600  # width
Y = 600  # height
halfX = X/2
halfY = Y/2
screen = pygame.display.set_mode((X, Y), pygame.FULLSCREEN)
clock = pygame.time.Clock()

# Colors
WHITE = (255, 255, 255)
RED = (255, 0, 0)

# From the docs:
# "If the mouse cursor is hidden, and input is grabbed to the 
# current display the mouse will enter a virtual input mode, where 
# the relative movements of the mouse will never be stopped by the 
# borders of the screen."
pygame.mouse.set_visible(False)
pygame.event.set_grab(True)

def drawCross(point, size, color):
  pygame.draw.line(screen, color, (point[0]-size,point[1]-size), (point[0]+size,point[1]+size), 2)
  pygame.draw.line(screen, color, (point[0]+size,point[1]-size), (point[0]-size,point[1]+size), 2)

canvas_rel = (halfX,halfY)

running = True
while running:

  for event in pygame.event.get():
    if event.type == pygame.MOUSEMOTION:
      print('event.rel = ' + str(event.rel))
      canvas_rel = [10 * event.rel[0] + halfX, 10 * event.rel[1] + halfY]
      print(' canvas_rel = ' + str(canvas_rel))

    if event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
      print('escape')
      running = False
      break

  screen.fill(WHITE)

  # Red sight to represent pygame mouse event.rel
  drawCross(canvas_rel, 10, RED)

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

pygame.quit()

РЕДАКТИРОВАТЬ:

Приведенный выше код не полностью демонстрирует мою проблему. Я добавил лучший пример ниже, чтобы облегчить понимание вопроса. Этот образец нарисует треугольник в центре экрана. Треугольник будет вращаться с относительным горизонтальным движением мыши. Обратите внимание на попытку использовать pygame.mouse.set_pos

import pygame
from math import pi, cos, sin

pygame.init()

# screen
X = 600  # width
Y = 600  # height
halfX = X/2
halfY = Y/2
screen = pygame.display.set_mode((X, Y), pygame.FULLSCREEN)
clock = pygame.time.Clock()

# for getting relative mouse position when outside the screen
pygame.mouse.set_visible(False)
pygame.event.set_grab(True)

# Colors
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)

# sensitivity
senseTheta = 0.01

# player
stand = [halfX, halfY]
t = 0 # angle in radians from positive X axis to positive x axis anticlockwise about positive Z

# draws a white cross in the screen center for when shooting is implemented :)
def drawPlayer(): 
  p = stand
  d = 50

  a1 = 0.25*pi-t
  a2 = 0.75*pi-t

  P = (p[0],p[1])
  A1 = (p[0] + d*cos(a1), p[1] + d*sin(a1)) # P + (d*cos(a1), d*sin(a1))
  A2 = (p[0] + d*cos(a2), p[1] + d*sin(a2)) # P + (d*cos(a2), d*sin(a2))

  pygame.draw.line(screen, BLACK, P, A1, 2)
  pygame.draw.line(screen, BLACK, A1, A2, 2)
  pygame.draw.line(screen, BLACK, A2, P, 2)

running = True
while running:

  for event in pygame.event.get():

    if event.type == pygame.MOUSEMOTION:
      mouseMove = event.rel
      print('mouseMove = ' + str(mouseMove))

      t -= mouseMove[0] * senseTheta

      # "Fix" the mouse pointer at the center
      # pygame.mouse.set_pos((screen.get_width()//2, screen.get_height()//2))
      # But I think set_pos triggers another MOUSEMOTION event as moving in positive x
      # seems to move backward the same amount in x (i.e. the triangle doesn't
      # rotate). See the console log.
      # If you uncomment this line it works ok (the triangle rotates) but still 
      # glitches when the mouse leaves the window.
      # uncommented or not I still cant get the mouse to work outside the window

    if event.type == pygame.KEYDOWN:
      if event.key == pygame.K_ESCAPE:
        running = False
        break

  screen.fill(WHITE)

  drawPlayer()

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

pygame.quit()
...