ב.5 — ציור צורות גאומטריות
בפרק הקודם למדנו למלא משטח שלם בצבע אחד. משחק, כמובן, צריך יותר מזה: כדור עגול, מחבט מלבני, מסלול מסומן בקווים, לוח חיים בפינת המסך. הרבה משחקים קלאסיים — פונג, נחש, פריצת לבנים — בנויים כולם מצורות פשוטות כאלה, ללא תמונה אחת. גם במשחקים שנבנה בהמשך הספר, שסוכני למידה ישחקו בהם, נסתפק פעמים רבות בצורות גאומטריות: הן קלות לציור וקל לחשב מהן את מצב המשחק.
קו, מעגל ומלבן מספיקים כדי לבנות תצוגות רבות. Pygame מספקת פעולות ציור תחת pygame.draw. לכל פעולה מציינים על איזה משטח לצייר, באיזה צבע, והיכן תופיע הצורה. אין צורך ליצור משטח נפרד לכל צורה: פעולת הציור משנה ישירות את הפיקסלים של המשטח שמעבירים לה, בדיוק כפי ש־fill() עשתה בפרק הקודם.
המצגת: מבוא ל־Pygame (עותק מקומי)
קו, מעגל וקו מתאר
נראה כיצד מציירים קו ומעגל, וכיצד עובי הקו משפיע על צורתם. נמשיך עם המשטחים header ו־main מהפרק הקודם. נוסיף את הפעולות הבאות אחרי צביעתם ולפני העתקתם למסך:
pygame.draw.line(main, (0, 0, 0),
(10, 10), (100, 100), 5)
pygame.draw.circle(main, (0, 180, 80),
(50, 50), 20, 2)
pygame.draw.circle(header, (230, 60, 80),
(150, 40), 30, 0)
בכל הפעולות שני הארגומנטים הראשונים זהים: המשטח שעליו מציירים והצבע. אחריהם באים נתוני הצורה. ב־line מעבירים נקודת התחלה, נקודת סיום ועובי הקו. ב־circle מעבירים מרכז, רדיוס ועובי. העובי 2 יוצר קו מתאר; העובי 0 ממלא את המעגל. המרכז נמדד במערכת הצירים של המשטח שעליו מציירים: המעגל האדמדם שצויר על header במיקום (150, 40) יופיע ברצועת הכותרת, ולא באזור התוכן.
מלבן, אליפסה ומצולע
נמשיך לצורות שמבוססות על מלבן. מלבן מתואר באמצעות ארבעה מספרים: (x, y, width, height). שני הראשונים הם מיקום הפינה השמאלית העליונה, ושני האחרונים הם הרוחב והגובה. האליפסה נפרשת בתוך המלבן המתאר אותה, ולכן מקבלת אותם ארבעה מספרים; מצולע מוגדר באמצעות רשימת קודקודים, ו־Pygame מחברת אותם בקווים לפי הסדר וסוגרת את הצורה. נצייר מלבן, אליפסה ומשולש על main, ליד המעגל והקו מהסעיף הקודם:
pygame.draw.rect(main, (35, 160, 175),
(150, 30, 100, 60))
pygame.draw.ellipse(main, (125, 90, 190),
(290, 30, 130, 60), 3)
pygame.draw.polygon(main, (245, 170, 45),
[(460, 90), (510, 20), (560, 90)])
כאשר משמיטים את העובי בצורות האלה, ברירת המחדל היא מילוי. בהמשך נכיר את המחלקה Rect, שתאפשר לשמור ולשנות בנוחות את נתוני המלבן.
דוגמה: בית מצורות פשוטות
נחבר את כל הצורות שהכרנו לציור אחד. הבית מורכב ממלבן לקירות, משולש לגג, מלבנים לדלת ולחלונות וקווים לשבכות החלונות; השמש היא מעגל, העץ הוא מלבן לגזע ואליפסה לצמרת, והדשא הוא מלבן ברוחב החלון. הפעם מציירים ישירות על screen, בלי משטחים נוספים. שימו לב לסדר: קודם הרקע והדשא, אחר כך הקירות, ורק אז הגג, הדלת והחלונות שמונחים עליהם. צבעים שחוזרים כמה פעמים שמורים בקבועים בעלי שמות, וכך קל לשנות למשל את צבע הגג במקום אחד.
import pygame
pygame.init()
screen = pygame.display.set_mode((640, 400))
pygame.display.set_caption("House")
SKY = (135, 206, 235)
GRASS = (80, 170, 90)
WALL = (240, 220, 170)
ROOF = (180, 60, 50)
DOOR = (110, 70, 40)
GLASS = (200, 230, 255)
SUN = (250, 210, 60)
TRUNK = (120, 80, 40)
LEAVES = (40, 130, 60)
BLACK = (0, 0, 0)
screen.fill(SKY)
pygame.draw.rect(screen, GRASS, (0, 300, 640, 100))
pygame.draw.circle(screen, SUN, (560, 70), 40)
pygame.draw.rect(screen, WALL, (200, 180, 240, 120))
pygame.draw.polygon(screen, ROOF,
[(180, 180), (320, 90), (460, 180)])
pygame.draw.rect(screen, DOOR, (300, 220, 40, 80))
pygame.draw.rect(screen, GLASS, (225, 205, 50, 40))
pygame.draw.rect(screen, GLASS, (365, 205, 50, 40))
pygame.draw.line(screen, BLACK, (250, 205), (250, 245), 2)
pygame.draw.line(screen, BLACK, (225, 225), (275, 225), 2)
pygame.draw.line(screen, BLACK, (390, 205), (390, 245), 2)
pygame.draw.line(screen, BLACK, (365, 225), (415, 225), 2)
pygame.draw.rect(screen, TRUNK, (90, 240, 20, 60))
pygame.draw.ellipse(screen, LEAVES, (60, 170, 80, 90))
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if not running:
break
pygame.display.update()
pygame.quit()
כל פעולות הציור נמצאות לפני הלולאה, כי הציור אינו משתנה. הלולאה עצמה רק קוראת אירועים ומרעננת את החלון. נסו לשנות מספרים בקוד: להזיז את השמש, להגביה את הגג או להוסיף חלון שלישי, ולראות איך כל שינוי משפיע על התמונה.
מתי מציירים?
נשאלת השאלה היכן בתוכנית למקם את פעולות הציור — לפני הלולאה או בתוכה. התשובה תלויה בשאלה אם הצורה משתנה. אם הצורות קבועות, אפשר לצייר אותן פעם אחת על המשטח לפני הלולאה ולהעתיק את המשטח בכל פריים. אם המיקום או הצבע משתנים, מנקים את המשטח ומציירים עליו מחדש בתוך הלולאה. הצורות אינן נשמרות כאובייקטים שנעים מעצמם: פעולת הציור משנה פיקסלים במשטח.
קוד להורדה: הדוגמה המלאה. דוגמת הבית.