ב.7 — אינטראקציה עם המשתמש: עכבר ומקלדת
משחק נבדל מסרטון בכך שהוא מגיב לשחקן: הדמות זזה כשלוחצים על חץ, כדור נורה כשלוחצים על רווח, ופריט נבחר כשלוחצים עליו בעכבר. כל פעולה כזו של המשתמש מגיעה לתוכנית כאירוע — Event: הודעה קטנה שמתארת מה קרה (איזה מקש נלחץ, היכן היה הסמן) ומחכה בתור עד שהתוכנית קוראת אותה. בפרקים הקודמים כבר קראנו אירועים בלולאת האירועים וטיפלנו באירוע הסגירה QUIT; אותה לולאה תשמש אותנו גם לכל שאר סוגי הקלט.
חלון יכול להגיב למיקום שבו המשתמש לוחץ, למקש שהוא מקיש או למקש שהוא ממשיך להחזיק. ההבדל בין שני המצבים האחרונים חשוב: לחיצה בודדת היא אירוע חד־פעמי, ואילו מקש שמוחזק לאורך זמן דורש בדיקה בכל פריים. בפרק זה נבדוק סוגי אירועים נוספים באותה לולאת אירועים. נתחיל בעכבר, ואחריו נעבור למקלדת ולשליטה רציפה.
המצגת: מבוא ל־Pygame (עותק מקומי)
עכבר: לחיצה במיקום מסוים
הדבר הראשון שנרצה לדעת על העכבר הוא היכן המשתמש לחץ, למשל כדי להציב שם דמות או לבחור פריט. אירוע MOUSEBUTTONDOWN נוצר בעת לחיצה על כפתור עכבר. event.pos הוא מיקום הסמן בזמן האירוע (זוג קואורדינטות x ו־y בפיקסלים), ו־event.button מציין את הכפתור; 1 הוא הכפתור השמאלי. בקטע הבא, בתוך לולאת האירועים, נשמור את מקום הלחיצה:
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
x, y = event.pos
יש שתי דרכים לדעת היכן הסמן: pygame.mouse.get_pos() קוראת את מיקום הסמן הנוכחי, ברגע הקריאה, בלי קשר לאירוע כלשהו. אם רוצים את המיקום שבו התרחשה הלחיצה המסוימת שאנו מטפלים בה, משתמשים ב־event.pos, כי הסמן ייתכן שכבר זז מאז.
מקלדת: לחיצה ושחרור
אפשר להגיב בנפרד לרגע הלחיצה על מקש ולרגע השחרור שלו. KEYDOWN מציין לחיצה על מקש, ו־KEYUP מציין שחרור. בודקים את event.key מול קבוע כגון pygame.K_SPACE או pygame.K_RIGHT. בדוגמה, לחיצה על רווח תשנה צבע, ושחרורו יחזיר את הצבע הקודם.
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
color = (245, 170, 45)
elif event.type == pygame.KEYUP:
if event.key == pygame.K_SPACE:
color = (45, 190, 180)
דוגמה: מעגל שמגיב לקלט
לחצו בחלון כדי להזיז את מרכז המעגל. החזיקו רווח כדי לשנות את צבעו ושחררו כדי להחזירו. הטיפול באירועים משנה את המצב, ואז מציירים את התוצאה פעם אחת בפריים.
import pygame
pygame.init()
screen = pygame.display.set_mode((640, 400))
x, y = 320, 200
color = (45, 190, 180)
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
x, y = event.pos
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
color = (245, 170, 45)
elif event.type == pygame.KEYUP:
if event.key == pygame.K_SPACE:
color = (45, 190, 180)
if not running:
break
screen.fill((17, 43, 65))
pygame.draw.circle(screen, color, (x, y), 25)
pygame.display.update()
pygame.quit()
מקש שנשאר לחוץ
אירוע לחיצה מתאר שינוי: הוא נוצר פעם אחת ברגע הלחיצה, ולא שוב כל עוד המקש מוחזק. לכן, אם נזיז את הדמות רק בתגובה ל־KEYDOWN, היא תזוז צעד אחד ותיעצר. כדי להזיז עצם בכל פריים שבו מקש נשאר לחוץ, כפי שמקובל במשחקים, קוראים את מצב המקלדת אחרי לולאת האירועים, בתוך הלולאה הראשית. הפונקציה pygame.key.get_pressed() מחזירה את מצבם של כל המקשים ברגע הקריאה, ואנו בודקים בה את המקשים שמעניינים אותנו:
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
x -= 3
if keys[pygame.K_RIGHT]:
x += 3
אם מוסיפים זאת לדוגמה לפני הציור, החצים מזיזים את המעגל ברציפות. שימו לב שהמעגל זז מהר מאוד, ובמחשב מהיר הוא עלול לחלוף על פני החלון כמעט מיד: הלולאה רצה מהר ככל שהמחשב מאפשר, ובכל סיבוב שלה המעגל מתקדם שלושה פיקסלים. בפרק הבא נלמד להגביל את קצב הלולאה בעזרת שעון. ממשיכים לקרוא אירועים גם כשמשתמשים ב־get_pressed(), כדי לשמור על תגובת החלון ולאפשר סגירה.
תנועה ושחרור של העכבר
העכבר מספק מידע גם כשהסמן זז או כשכפתור משתחרר. אירועים אלה מאפשרים, למשל, לעקוב אחר גרירה.
| אירוע | מה אפשר לקרוא ממנו? |
|---|---|
MOUSEBUTTONDOWN |
מיקום הלחיצה pos והכפתור button |
MOUSEBUTTONUP |
מיקום השחרור והכפתור ששוחרר |
MOUSEMOTION |
המיקום pos, שינוי המיקום rel ומצב הכפתורים buttons |
למשל, בתוך לולאת האירועים אפשר להוסיף טיפול בשחרור או לגרום למעגל לעקוב אחר הסמן בזמן גרירה:
if event.type == pygame.MOUSEMOTION:
if event.buttons[0]:
x, y = event.pos
elif event.type == pygame.MOUSEBUTTONUP:
if event.button == 1:
color = (45, 190, 180)
שימו לב לעיקרון שחוזר בכל הדוגמאות בפרק: הטיפול באירוע רק מעדכן משתנים (מיקום, צבע), והציור נעשה בנפרד, פעם אחת בכל פריים. אין לצייר את המעגל בתוך טיפול האירוע ואז לצבוע עליו את כל הרקע, כי מילוי הרקע ימחק את מה שציירנו. נשמור את הקלט במשתנים, ולאחר מכן ננקה ונצייר לפי הסדר.
קוד להורדה: הדוגמה המלאה. בדוגמאות המשתמשות בתמונה, שמרו את הכוכב בתוך img/star.png לצד הקובץ והריצו מתוך התיקייה שלו.