Гузариш ба мундариҷа
Мавзӯи 5 аз 6

Ҳодисаҳо ва идоракунӣ

Ин барои чӣ лозим аст

Бозӣ аз филми тасвирӣ бо он фарқ мекунад, ки ба бозингар ҷавоб медиҳад: пробелро пахш карданд — қаҳрамон ҷаҳид, P-ро пахш карданд — таваққуф, зер карданд — тир. Ҳамаи инро pygame ба барнома тавассути ҳодисаҳо хабар медиҳад. Аз он ки шумо онҳоро чӣ тавр коркард мекунед, вобаста аст, ки идоракунӣ қулай мешавад ё не: таваққуфе, ки фаъол мешавад ва фавран хомӯш мешавад, ё море, ки ба худ бармегардад, — хатоҳои маъмули коркарди ҳодисаҳоянд.

Дар ин мавзӯъ навбати ҳодисаҳо, фарқи байни «пахш карданд» ва «пахш карда нигоҳ доштанд», кор бо клавиатура ва муш ва тарзи навиштани қоидаҳои идоракуниро мебинем.

Қадами 1. Навбати ҳодисаҳо

Дар вақте ки барнома кадрро мекашад, бозингар чизе карда мерасонад: тугмаеро пахш кардан, мушро ҳаракат додан. pygame ин амалҳоро гум намекунад, балки онҳоро ба навбат мегузорад — мисли мактубҳо дар қуттии почта. Ҳар кадр барнома ҳамаи ҷамъшударо бо даъвати pygame.event.get() мегирад ва якто-якто ҷудо мекунад.

for event in pygame.event.get():
    if event.type == pygame.QUIT:
        running = False
    elif event.type == pygame.KEYDOWN:
        if event.key == pygame.K_SPACE:
            jump()
        elif event.key == pygame.K_ESCAPE:
            running = False
    elif event.type == pygame.MOUSEBUTTONDOWN:
        print("зеркунӣ дар", event.pos)

Ҳар ҳодиса навъ event.type ва майдонҳое дорад, ки аз навъ вобастаанд:

Навъ Кай меояд Майдонҳо
QUIT салиби равзана пахш шуд —
KEYDOWN тугмаро пахш карданд key — коди тугма
KEYUP тугмаро раҳо карданд key
MOUSEBUTTONDOWN тугмаи мушро пахш карданд pos, button (1 — чап, 3 — рост)
MOUSEBUTTONUP тугмаи мушро раҳо карданд pos, button
MOUSEMOTION муш ҳаракат кард pos, rel — чӣ қадар ҳаракат кард

Кодҳои тугмаҳо — доимиҳои pygame.K_…: K_a … K_z, K_0 … K_9, K_SPACE, K_RETURN (Enter), K_ESCAPE, тирчаҳо K_UP, K_DOWN, K_LEFT, K_RIGHT.

Қадами 2. Ҳодисаро худатон сохтан мумкин аст

Ҳодиса — объекти оддӣ аст. Онро бо даст тавассути pygame.event.Event(навъ, майдонҳо…) сохтан мумкин аст. Ҳамин тавр санҷидани коркардкунанда бе равзана ва бе пахши тугмаҳои воқеӣ қулай аст — санҷишҳо дар масъалаҳо маҳз ҳамин тавр кор мекунанд.

import pygame
e = pygame.event.Event(pygame.KEYDOWN, key=pygame.K_p)
print(e.type == pygame.KEYDOWN, e.key == pygame.K_p)
click = pygame.event.Event(pygame.MOUSEBUTTONDOWN, pos=(10, 20), button=1)
print(click.pos, click.button)

Натиҷа:

True True
(10, 20) 1

Номи навъҳоро бо функсияи pygame.event.event_name фаҳмидан мумкин аст:

import pygame
for t in (pygame.QUIT, pygame.KEYDOWN, pygame.KEYUP):
    print(pygame.event.event_name(t))

Натиҷа:

Quit
KeyDown
KeyUp

Қадами 3. Ҳодиса — ин тағйирот аст

Қоидаи муҳимтарин: ҳодиса дар бораи тағйирот хабар медиҳад. Як пахши тугма — маҳз ду ҳодиса аст: KEYDOWN дар лаҳзаи пахш ва KEYUP дар лаҳзаи раҳо кардан. То даме ки тугма танҳо пахш карда нигоҳ дошта шудааст, ҳодисаҳои нав нестанд.

Агар ба ҳар ду ҳодиса якбора ҷавоб диҳем, чӣ мешавад? Ҳисоб мекунем:

import pygame
events = [pygame.event.Event(pygame.KEYDOWN, key=pygame.K_m),
          pygame.event.Event(pygame.KEYUP, key=pygame.K_m)]
sound_on = True
for e in events:
    if e.type in (pygame.KEYDOWN, pygame.KEYUP) and e.key == pygame.K_m:
        sound_on = not sound_on
    print(sound_on)

Натиҷа:

False
True

Бозингар як маротиба M-ро пахш кард, то садоро хомӯш кунад, вале садо хомӯш шуд ва фавран боз фаъол шуд. Барои ивазкунакҳо (садо, таваққуф, меню) ҷавоб танҳо ба яке аз ду ҳодиса лозим аст.

Доми маъмули дигар — фаромӯш кардани санҷиши он ки кадом тугма пахш шуд. Шарти event.type == pygame.KEYDOWN бе санҷиши event.key ба ҳар тугма кор мекунад.

Қадами 4. Ҳолати бозӣ

Барои коркардкунандаи ҳодисаҳо тағйир додани луғати умумии ҳолат қулай аст: оё бозӣ дар таваққуф аст, оё барнома кор мекунад, кадом сатҳ. Луғат ба функсия дода мешавад ва функсия онро дар ҷояш тағйир медиҳад — ҳамин тавр тағйирот дар даври бозӣ низ намоён аст.

import pygame

def handle(event, state):
    if event.type == pygame.KEYDOWN and event.key == pygame.K_m:
        state["sound"] = not state["sound"]

state = {"sound": True}
for e in [pygame.event.Event(pygame.KEYDOWN, key=pygame.K_m),
          pygame.event.Event(pygame.KEYUP, key=pygame.K_m),
          pygame.event.Event(pygame.KEYDOWN, key=pygame.K_x)]:
    handle(e, state)
    print(state["sound"])

Натиҷа:

False
False
False

Акнун як пахши M — як иваз, тугмаи бегонаи X бошад ҳеҷ чизро тағйир намедиҳад. QUIT-ро низ фаромӯш накунед: агар коркардкунанда барои он масъул бошад, бе ин шох равзана пӯшида намешавад.

Қадами 5. Тугмаҳои пахшшуда

Барои ҳаракати ҳамвор ҳодисаҳо нороҳатанд: KEYDOWN як маротиба меояд ва қаҳрамон як қадам мекӯчад. Ҷавоб ба саволи «оё тугма ҳозир пахш аст» лозим аст. Онро pygame.key.get_pressed() медиҳад — маҷмӯе, ки дар он pressed[код] то даме ки тугма пахш аст, рост аст.

pressed = pygame.key.get_pressed()
if pressed[pygame.K_LEFT]:
    hero.x -= 5

get_pressed-ро ҳар кадр, одатан баъд аз ҷудо кардани навбати ҳодисаҳо, даъват мекунанд. Қиматҳо — True ва False, дар Python бошад инҳо 1 ва 0 мебошанд, бинобар ин онҳоро ҷамъ ва тарҳ кардан мумкин аст:

right, left = True, False
print(right - left, left - right, right - right, int(True))

Натиҷа:

1 -1 0 1

Тири y-ро дар хотир доред: «боло» — ин минус, «поён» — плюс.

Қадами 6. Якчанд тугма барои як амал

Аксар вақт як амалро бо ду тугма кардан мумкин аст: бо тирча ё ҳарф (WASD). Онҳоро бо or-и мантиқӣ муттаҳид мекунанд: «ба рост», агар тирчаи рост ё D пахш бошад. Агар онҳоро ҳамчун адад ҷамъ кунем, ҳангоми пахш будани ҳар ду тугма 2 ҳосил мешавад — қаҳрамон ду баробар тезтар меравад.

arrow, letter = True, True
print(arrow + letter)          # ҷамъ: дучанд шудан
print(int(arrow or letter))    # ё: боз ҳам 1

Натиҷа:

2
1

Қадами 7. Қоидаҳои идоракунӣ бо луғат

Коркардкунандаи ҳодисаҳо — ҷоест, ки қоидаҳои бозӣ зиндагӣ мекунанд: «таваққуф — танҳо бо тугмаи P», «тугмаҳои номаълум ҳеҷ кор намекунанд». Мувофиқати «тугма → амал»-ро дар луғат (dict) нигоҳ доштан қулай аст. Методи get None бармегардонад, агар калид набошад, — ҳамин тавр тугмаи «худӣ»-ро аз бегона фарқ кардан осон аст.

import pygame
MOVES = {pygame.K_w: "ба пеш", pygame.K_s: "ба қафо"}
for key in (pygame.K_w, pygame.K_q, pygame.K_s):
    action = MOVES.get(key)
    print(action if action is not None else "ҳеҷ чиз")

Натиҷа:

ба пеш
ҳеҷ чиз
ба қафо

Самти ҳаракатро дар майдони катакӣ бо ҷуфти (dx, dy) нигоҳ доштан қулай аст: ба рост (1, 0), ба боло (0, -1). Ду ҷуфт муқобил мебошанд, агар ҳар ду координатаашон муқобил бошанд: масалан, (1, 0) ва (-1, 0).

a, b = (0, -1), (0, 1)
print(a[0] + b[0] == 0 and a[1] + b[1] == 0)

Натиҷа:

True

Дар дохил чӣ тавр кор мекунад

Системаи амалиётӣ худаш клавиатура ва мушро назорат мекунад ва ба pygame дар бораи ҳар тағйирот хабар мефиристад. pygame онҳоро бо тартиби расидан ба навбат мегузорад. event.get() навбатро медиҳад ва тоза мекунад — бинобар ин онро ҳар кадр даъват кардан лозим аст. Агар даъват накунед, навбат пур мешавад ва система гумон мекунад, ки равзана «ҷавоб намедиҳад».

key.get_pressed() тарзи дигар сохта шудааст: pygame ҷадвали «кадом тугмаҳо ҳозир поёнанд»-ро нигоҳ медорад ва ҳангоми ҷудо кардани ҳодисаҳо онро нав мекунад. Бинобар ин get_pressed ҳолати дурустро танҳо вақте нишон медиҳад, ки ҳодисаҳои ин кадр аллакай гирифта шуда бошанд.

Хатоҳои маъмул

1. Ҷавоб ҳам ба KEYDOWN ва ҳам ба KEYUP. Ивазкунак ду маротиба кор мекунад ва ба ҳолати аввала бармегардад. Барои амали якдафъаина яке аз ду навъ лозим аст.

2. event.key санҷида нашуд. Таваққуф аз ҳар тугма фаъол мешавад. Ҳамеша ҳам навъ ва ҳам коди тугмаро муқоиса кунед.

3. QUIT фаромӯш шудааст. Агар коркардкунанда барои пӯшидани равзана масъул бошад, бе ин шох салиб кор намекунад.

4. Аломат аз рӯи y омехта шудааст. up - down ба ҷои down - up — қаҳрамон ҳангоми пахши боло ба поён меравад.

5. Тугмаҳои такрориро ҷамъ мекунанд. Тирча ва ҳарфе, ки якҷоя пахш шудаанд, суръатро дучанд мекунанд. Тавассути or муттаҳид кунед.

Варақаи ёддошт

Чӣ Код
ҳодисаҳои кадр for event in pygame.event.get():
навъи ҳодиса event.type == pygame.KEYDOWN / KEYUP / QUIT / MOUSEBUTTONDOWN
коди тугма event.key == pygame.K_p
муш event.pos, event.button
сохтани ҳодиса pygame.event.Event(pygame.KEYDOWN, key=pygame.K_p)
оё ҳозир пахш аст pressed = pygame.key.get_pressed(), pressed[pygame.K_LEFT]
самт int(right) - int(left); боло — минус
ду тугма барои як амал pressed[pygame.K_RIGHT] or pressed[pygame.K_d]
тугма → амал ACTIONS.get(event.key) (ё None)
Лозим Чӣ тавр
амали якдафъаина: таваққуф, тир, гардиши мор, меню KEYDOWN дар навбати ҳодисаҳо
ҳаракати бефосила, то даме ки тугма пахш аст key.get_pressed() ҳар кадр