К основному содержанию
правило

pygame — правило для Cursor: структура игры и pygame-gui

Правило для Cursor задаёт каркас Pygame-проекта: один UIManager, фиксированный шаг времени, вёрстка на якорях и темы в JSON.

Установить в Cursor · Вручную: положить файлы Все способы и платформы ↓
.cursor/rules/pygame.mdc
Открыть на GitHub

Что делает pygame

Файл .cursor/rules/pygame.mdc подключается к Cursor и срабатывает на Python-файлы по маске **/*.py. Внутри — набор паттернов: класс игры с главным циклом, отдельные методы обработки событий, обновления и отрисовки, единственный экземпляр UIManager из pygame-gui, созданный на старте.

Для интерфейса правило требует relative_rect и якоря вместо жёстких пиксельных координат, поэтому кнопки переживают изменение размера окна. Стили выносятся в JSON-тему, а конкретные элементы получают object_id вроде #red_button. Кадры ограничиваются через pygame.time.Clock().tick(FPS), а time_delta уходит в manager.update — без этого анимации интерфейса плывут на разной частоте обновления экрана.

Каждый блок идёт парой: сначала пример «как не надо» с разбросанной логикой UI прямо в цикле, потом рабочий вариант. Если вы уже используете другой UI-слой, скажем pygame_menu, примеры придётся переписывать под него — правило про pygame-gui говорит прямо.

Какие задачи решает

  • собрать каркас игры с отдельными методами событий, обновления и отрисовки
  • вынести стили кнопок и шрифты в JSON-тему вместо правок кода
  • сделать интерфейс, который не разъезжается при изменении размера окна
  • привязать скорость игры к фиксированному FPS, а не к мощности железа
  • убрать создание элементов UI прямо из главного цикла

Примеры запросов агенту

  • Собери каркас Pygame-игры по правилу pygame: один UIManager, фиксированный timestep
  • Перепиши эту кнопку на relative_rect и якоря, как требует правило pygame
  • Вынеси цвета и шрифт кнопки в JSON-тему и подключи её через object_id

Как установить pygame

Вручную: положить файлы

.cursor/rules/pygame.mdc

Во frontmatter: description, globs, alwaysApply

По шагам, с командами для каждой платформы: Cursor rules: файлы .mdc, четыре режима и замена .cursorrules

Вопросы о pygame

Как установить правило pygame в Cursor?

Создайте файл .cursor/rules/pygame.mdc в корне проекта и вставьте в него содержимое правила. Cursor подхватит его для файлов по маске **/*.py.

Что делает правило pygame?

Задаёт структуру приложения: главный цикл с фиксированным FPS, один UIManager из pygame-gui, вёрстка на якорях и стили в JSON-теме. Внутри есть примеры «плохо» и «хорошо» для каждого пункта.

Нужен ли pygame-gui для этого правила?

Да, все примеры интерфейса построены на pygame-gui. Если вы используете другой UI-слой, готовые примеры не подойдут.

Исходный текст

pygame.mdc · CC0-1.0
---
description: Definitive guide for building modern, performant, and maintainable Pygame applications using `pygame-gui` for UI, focusing on structure, responsive layout, theme-driven styling, and performance best practices.
globs: **/*.py
---
# Pygame Best Practices

This guide outlines the essential patterns for building robust and visually appealing Pygame applications, leveraging `pygame-gui` for all UI interactions. Adhere to these principles for maintainable, performant, and scalable game development.

## 1. Core Application Structure

Always structure your Pygame application with a clear main loop, a single `UIManager`, and a fixed timestep. Separate game logic from UI logic.

❌ BAD: Scattered UI element creation, no `UIManager`, variable framerate.

```python
import pygame

pygame.init()
screen = pygame.display.set_mode((800, 600))
pygame.display.set_caption("Bad Example")

running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        # UI logic directly in main loop
        if event.type == pygame.MOUSEBUTTONDOWN:
            print("Mouse clicked!")

    screen.fill((0, 0, 0))
    # Draw game elements
    pygame.draw.rect(screen, (255, 0, 0), (100, 100, 50, 50))
    pygame.display.flip()
```

✅ GOOD: Dedicated `UIManager`, fixed timestep, clear event processing.

```python
import pygame
import pygame_gui
from pygame_gui.core.interfaces import IUIManagerInterface

class Game:
    def __init__(self, screen_size: tuple[int, int]):
        pygame.init()
        self.screen = pygame.display.set_mode(screen_size)
        pygame.display.set_caption("Good Example")
        self.manager: IUIManagerInterface = pygame_gui.UIManager(screen_size, 'data/themes/default.json')
        self.clock = pygame.time.Clock()
        self.is_running = True
        self.fps = 60

        # Example UI button
        pygame_gui.elements.UIButton(
            relative_rect=pygame.Rect((350, 275), (100, 50)),
            text='Click Me',
            manager=self.manager
        )

    def run(self):
        while self.is_running:
            time_delta = self.clock.tick(self.fps) / 1000.0
            self._handle_events()
            self._update(time_delta)
            self._draw()
        pygame.quit()

    def _handle_events(self):
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                self.is_running = False
            if event.type == pygame_gui.UI_BUTTON_PRESSED:
                print("Button pressed!")
            self.manager.process_events(event)

    def _update(self, time_delta: float):
        self.manager.update(time_delta)
        # Update game logic here

    def _draw(self):
        self.screen.fill((0, 0, 0))
        # Draw game elements
        pygame.draw.rect(self.screen, (255, 0, 0), (100, 100, 50, 50))
        self.manager.draw_ui(self.screen)
        pygame.display.flip()

if __name__ == '__main__':
    game = Game((800, 600))
    game.run()
```

## 2. UI Management with `pygame-gui`

`pygame-gui` is the definitive choice for polished, interactive UIs.

### 2.1. Initialize `UIManager` Once

Create a single `UIManager` instance early in your application lifecycle.

```python
# In your Game class or main setup
self.manager: IUIManagerInterface = pygame_gui.UIManager(screen_size, 'data/themes/default.json')
```

### 2.2. Responsive Layouts with `relative_rect` and Anchors

Always use `relative_rect` for UI element positioning. Leverage `anchors` for responsive designs that adapt to window resizing and container movement. Avoid hardcoding absolute pixel positions.

❌ BAD: Hardcoded absolute positions, no responsiveness.

```python
# Button position will be fixed regardless of window size or parent container
pygame_gui.elements.UIButton(
    relative_rect=pygame.Rect(50, 50, 100, 30), # Absolute position
    text='Button', manager=self.manager
)
```

✅ GOOD: Relative positioning and anchors for dynamic layouts.

```python
# Button anchored to the bottom-right of its container, with a 10px offset
pygame_gui.elements.UIButton(
    relative_rect=pygame.Rect(0, 0, 100, 30),
    text='Bottom Right',
    manager=self.manager,
    anchors={'right': 'right', 'bottom': 'bottom',
             'left': 'right', 'top': 'bottom'} # Stretch to maintain size
).set_relative_position((-110, -40)) # Offset from bottom-right corner

# Button centered in its container
pygame_gui.elements.UIButton(
    relative_rect=pygame.Rect(0, 0, 150, 50),
    text='Centered',
    manager=self.manager,
    anchors={'center': 'center'}
)
```

### 2.3. Theme-Driven Styling with JSON

Externalize all UI styling (colors, fonts, sizes) into JSON theme files. This enables rapid visual iteration without code changes.

❌ BAD: Hardcoded colors and fonts throughout the code.

```python
# In your code
pygame_gui.elements.UIButton(
    ...
    text='Red Button',
    manager=self.manager,
    object_id='#red_button' # Still needs object_id for theming, but no theme loaded
)
# No theme loaded, so default styles apply or you'd set them programmatically.
```

✅ GOOD: Load a JSON theme file and use `object_id` for specific styling.

```json
// data/themes/default.json
{
    "button": {
        "colours": {
            "normal_bg": "#25292e",
            "hovered_bg": "#35393e",
            "pressed_bg": "#15191e",
            "normal_text": "#FFFFFF"
        },
        "font": {
            "name": "fira_code",
            "size": "20",
            "bold": "0",
            "italic": "0"
        }
    },
    "#red_button": {
        "colours": {
            "normal_bg": "#FF0000"
        }
    }
}
```

```python
# In your Game class or main setup
self.manager: IUIManagerInterface = pygame_gui.UIManager(screen_size, 'data/themes/default.json')

# In your UI creation
pygame_gui.elements.UIButton(
    relative_rect=pygame.Rect((10, 10), (100, 30)),
    text='Themed Button',
    manager=self.manager,
    object_id='#red_button' # Applies styles from the theme file
)
```

## 3. Performance Considerations

### 3.1. Fixed Timestep

Always use `pygame.time.Clock().tick(FPS)` to cap your frame rate and calculate `time_delta`. This ensures consistent game speed across different hardware and is crucial for `pygame-gui` updates.

❌ BAD: No frame rate cap, variable `time_delta`.

```python
# ...
while is_running:
    # No clock.tick(), game runs as fast as possible
    # time_delta would need to be calculated differently or omitted, leading to issues
    for event in pygame.event.get():
        # ...
    # ...
    pygame.display.update()
```

✅ GOOD: Consistent frame rate and `time_delta`.

```python
# ...
self.clock = pygame.time.Clock()
self.fps = 60
# ...
while self.is_running:
    time_delta = self.clock.tick(self.fps) / 1000.0 # Essential for consistent updates
    self.manager.update(time_delta) # UIManager relies on time_delta
    # ...
    pygame.display.update()
```

### 3.2. Avoid "Threaded Flip" Anti-pattern

Never call `pygame.display.flip()` or `pygame.display.update()` from a separate thread. All drawing operations must occur on the main thread to prevent crashes and undefined behavior.

## 4. Component Architecture

Encapsulate complex UI elements or game screens into their own classes. Each screen/component should manage its own `pygame-gui` elements and event handling.

```python
from pygame_gui.core.interfaces import IUIManagerInterface

class MainMenuScreen:
    def __init__(self, manager: IUIManagerInterface, screen_rect: pygame.Rect):
        self.manager = manager
        self.container = pygame_gui.elements.UIPanel(
            relative_rect=screen_rect,
            manager=manager,
            anchors={'left': 'left', 'right': 'right', 'top': 'top', 'bottom': 'bottom'}
        )
        self.start_button = pygame_gui.elements.UIButton(
            relative_rect=pygame.Rect(0, 0, 200, 50),
            text='Start Game',
            manager=self.manager,
            container=self.container,
            anchors={'center': 'center'}
        )
        self.exit_button = pygame_gui.elements.UIButton(
            relative_rect=pygame.Rect(0, 60, 200, 50), # Offset from start_button
            text='Exit',
            manager=self.manager,
            container=self.container,
            anchors={'centerx': 'centerx', 'top_target': self.start_button} # Anchor to another element
        )

    def process_event(self, event: pygame.event.Event) -> bool:
        if event.type == pygame_gui.UI_BUTTON_PRESSED:
            if event.ui_element == self.start_button:
                print("Start Game Pressed!")
                return True
            if event.ui_element == self.exit_button:
                print("Exit Game Pressed!")
                return True
        return False

    def hide(self):
        self.container.hide()

    def show(self):
        self.container.show()
```

## 5. Type Hints

Always use type hints for clarity, maintainability, and to leverage static analysis tools. This is especially important for `pygame` and `pygame-gui` objects.

```python
import pygame
from pygame_gui.core.interfaces import IUIManagerInterface
from typing import Tuple

def create_button(manager: IUIManagerInterface, rect: pygame.Rect, text: str) -> pygame_gui.elements.UIButton:
    """Creates a standard UI button."""
    return pygame_gui.elements.UIButton(relative_rect=rect, text=text, manager=manager)

def get_screen_size(screen: pygame.Surface) -> Tuple[int, int]:
    """Returns the width and height of the screen."""
    return screen.get_width(), screen.get_height()
```

## 6. `pygame-gui` vs `pygame-menu`

*   **`pygame-gui`**: Use for complex, interactive, in-game UIs (inventories, settings panels, dialogues). Its robust layout, theming, and event system are ideal for rich interfaces.
*   **`pygame-menu`**: Use for simple, quick-to-implement menus like start screens, pause overlays, or basic option screens where `pygame-gui` might be overkill. It offers a simpler API for common menu patterns.

For most projects, `pygame-gui` is the recommended default due to its flexibility and modern feature set.

## 7. Accessibility

Design your UI with accessibility in mind. Use clear, high-contrast themes, ensure interactive elements are sufficiently large, and provide keyboard navigation where appropriate. `pygame-gui` supports keyboard navigation and theme-driven text scaling, which are foundational for accessibility.

## 8. PEP 8 Adherence

Follow PEP 8 style guidelines rigorously. Consistent code is readable code. Use linters (e.g., Flake8, Black) to enforce this automatically.

© sanjeed5 · CC0-1.0 · sanjeed5/awesome-cursor-rules-mdc

Похожие правила IDE

Всё по теме «Геймдев и 3D: Unity, Unreal, Godot, Blender» →
pygame-core gamedev-skills Скилл собирает каркас игры на pygame: игровой цикл, движение с учётом delta-time, ввод, спрайты и коллизии. Пригодится, когда проект начинается с import pygame. CX Codex +1 5 100установок godot-ui Zate Скилл даёт агенту знания о Control-нодах, темах и типовых экранах Godot. Пригодится, когда собираешь меню, HUD или инвентарь. CX Codex +1 2 700установок game-designer OpusGameLabs Скилл для геймдизайна: разбирает браузерную игру и доводит её вид — фон, частицы, анимации, переходы между сценами. CX Codex +1 1 900установок build-game-changelog MengTo Скилл для проектирования и ведения внутриигрового чейнджлога: версии, провенанс деплоя, навигация по меню. CX Codex +1 1 200установок gaming-entertainment dylantarre Скилл для анимаций в игровых приложениях, стриминговых сервисах и интерактивных медиа: раскладывает 12 принципов Disney по элементам интерфейса. CX Codex +1 532установок arc-mastery dylantarre Скилл для анимации движения: объясняет, почему прямые линии выглядят механически, и как строить дуги в UI, персонажах и играх. CX Codex +1 523установок

Из того же набора69

react Правило для Cursor задаёт команде единые стандарты React: чистые компоненты, правила хуков, структура по фичам. Пригодится, когда в проекте несколько разработчиков и ИИ-агент пишет код вразнобой. ★ 3 579звёзд репо react-native Правило задаёт обязательные практики для React Native: feature-first структуру, функциональные компоненты, хуки и типизацию. Пригодится, когда проект растёт и файлы расползаются. ★ 3 579звёзд репо qwik Правило Cursor, которое подсказывает агенту, как писать Qwik-приложения: component$, useStore, QRL с суффиксом $ и загрузка данных через loader$. ★ 3 579звёзд репо pyramid Правило для Cursor с набором практик по Python-фреймворку Pyramid: структура проекта, конфигурация, транзакции и предикаты представлений. ★ 3 579звёзд репо prisma Правило для Cursor, которое задаёт агенту порядок работы с Prisma ORM: один клиент на приложение, выборки без лишних полей, аккуратные миграции. ★ 3 579звёзд репо playwright Правило задаёт Cursor стандарты написания end-to-end тестов на Playwright: официальный раннер, устойчивые локаторы, отказ от ручных задержек. ★ 3 579звёзд репо phoenix Правило для Cursor задаёт, как писать Phoenix-приложения на Elixir: контексты, форматирование, тесты. Пригодится, если агент уже правит ваш код. ★ 3 579звёзд репо pandas Правило для Cursor задаёт стиль работы с pandas: векторизация вместо циклов, явные .loc и .iloc, экономные типы данных. Пригодится, если агент часто пишет медленный код. ★ 3 579звёзд репо

Спонсоры проекта

Компании, которые помогают держать аналитику открытой