رسم یک پنجره ساده با Pygame

?How to Create A Simple Window with Pygame

How-to-Create-A-Simple-Window-with-Pygame

پیش گفتار

در این بخش با رسم پنجره و در قسمت بعدی با تغییر رنگ آن آشنا می شویم.این برنامه نخستین برنامه ما با pygame است.

پنجره ساده با pygame

در این بخش از یادگیری pygame می خواهیم با هم یک پنجره ساده را که به شکل بالا است، رسم کنیم. این بخش از بخش های پیشین اندکی طولانی تر است، پس توصیه می کنم هر وقت که زمان داشتید آن را بخوانید. همچنین از سرسری خواندن آن بپرهیزید زیرا در این بخش قرار است درس های مهمی را فرا گیریم. نکته دیگر این که اگر در خواندن آن ابهام داشتید دوباره و چندباره آن را بخوانید، چون این مفاهیم برای کسانی که pygame را برای اولین یاد می گیرند تازگی دارد و ممکن است که با یک بار خواندن این مفاهیم را به درستی یاد نگیرند.

پیش از رسم کردن پنجره بیایید کمی با مفهوم CLI و GUI آشنا شویم.

آشنایی با CLI و GUI

برنامه هایی را که با توابع پایتون می نویسیم تنها می توانند با متن هایی کار کنند که با توابع print و input دریافت و چاپ شده اند. برنامه شما می تواند متن های گوناگونی را نمایش دهد و کاربر هم چنین می تواند متن دل خواه خود را با صفحه کلید بنویسد. اینگونه از برنامه ها دارای رابط خط فرمان یا CLI(command line interface) هستند. این برنامه ها تا اندازه ای محدود هستند چون نمی توانند اشکال مختلف را ترسیم کنند، رنگ داشته باشند یا از موس استفاده کنند. برنامه های CLI تنها می توانند ورودی را با تابع input دریافت کنند. پس از این که برنامه ورودی را دریافت کرد، کاربر باید Enter را بزند تا برنامه بتواند ورودی بعدی را دریافت کند.از این گفته ها می توان این نتیجه را گرفت که ساخت بازی های واکنشی بی درنگ با CLI ناممکن است.

Pygame با داشتن توابع مخصوص برای ساخت برنامه هایی با رابط کاربری گرافیکی یا GUI(graphical user interface) همه مشکل های گفته شده در بالا را حل می کند. برنامه های ساخته شده با GUI برخلاف CLI می توانند پنجره ای را با تصاویر و رنگ های مختلف نشان دهند.

رسم یک پنجره ساده با pygame (برنامه Hello World  با پایتون)

در انتهای این نوشته می خواهیم یاد بگیریم که چگونه پنجره زیر را رسم کنیم:

پنجره ساده با pygame

نخستین برنامه ای که با pygame می نویسیم برنامه کوچک بالا است که نام آن "!Hello World" است.برای شروع کار یک ویرایشگر کد را باز کنید. یک فایل جدید با نام helloworld.py ایجاد کنید و کدهای زیر را در آن بنویسید و سپس آن را ذخیره کنید. می توانید از هر ویرایشگر متنی که خواستید استفاده کنید. پیش از این که یاد بگیریم چگونه پنجره بالا را رسم کنیم بیایید نگاهی به کد آن بیندازیم.

import pygame, sys
from pygame.locals import *

pygame.init()
DISPLAYSURF = pygame.display.set_mode((400, 300))
pygame.display.set_caption('Hello World!')
while True: # main game loop
    for event in pygame.event.get():
        if event.type == QUIT:
            pygame.quit()
           sys.exit()
    pygame.display.update()

وارد کردن کتابخانه ها و ثابت های ماژول locals

همان طور که از پیش می دانیم برای استفاده از یک کتابخانه خارجی در پایتون باید آن را وارد برنامه کنیم یعنی آن را import کنیم. به عنوان نمونه اگر بخواهیم از ماژول math استفاده بکنیم باید آن را با دستور import math وارد برنامه کنیم.پس برای استفاده از pygame و sys باید آن ها را import کنیم. مانند زیر:

import pygame,sys

خط بالا در هر برنامه pygame وجود دارد. این خط یک import ساده است که ماژول های pygame و sys را وارد برنامه می کند تا برنامه ما بتواند از توابع موجود در آن ها استفاده کند. همه تابع های pygame که با گرافیک، صدا و... سر و کار دارند در ماژول pygame هستند. تنها چیزی که در مورد ماژول sys باید بدانید این است که حاوی متغیرها و توابع مربوط به مفسر پایتون است.

در خط بعدی pygame.locals را وارد برنامه می کنیم:

from pygame.locals import *

دلیل استفاده از pygame.locals این است که به ثابت های موجود در آن نیاز داریم. ماژول pygame.locals شامل 280 ثابت است. قرار دادن این عبارت در ابتدای برنامه، همه آن ها را وارد برنامه می کند. مانند QUIT که در برنامه خود از آن استفاده کرده ایم.

initialize کردن pygame

با خط زیر در واقع می خواهیم به پایتون بفهمانیم که قصد استفاده از pygame را داریم. برای این کار باید pygame را مقداردهی اولیه یا initialize کنیم. اگر این کار را نکنیم pygame کار نخواهد کرد. کد pygame.init همیشه باید بعد از ماژول pygame و قبل از سایر تابع ها بیاید. لازم نیست بدانید که این تابع چه کاری انجام می دهد، فقط بدانید برای این که توابع pygame بتوانند به درستی کار کنند، این تابع باید قبل از آن ها فراخوانی شود. پس داریم:

()pygame.init

تعیین اندازه پنجره و نام آن

خط بعدی فراخوانی تابع display.set_mode است که شی ای به نام pygame.Surface را برای پنجره برمی گرداند. (اشیا Surface در  بخش های بعدی این سری آموزش توضیح داده خواهد شد پس نگران نباشید). در واقع set_mode یک شی Screen را برای نمایش پنجره مقداردهی می کند. یک تاپل دوتایی از دو عدد صحیح را به تابع می فرستیم: (400,300). این تاپل مشخص می کند که تابع set_mode برای ساخت پنجره باید چه مقدار طول و عرض داشته باشد. (400,300) یک پنجره با طول 400 پیکسل و عرض 300 پیکسل می سازد. پس عدد اول برای طول و عدد دوم برای عرض است و هر دو حتما باید صحیح یا int باشند.

از این دو عدد به تنهایی در تابع set_mode  استفاده نکنید و مطمئن شوید که آن ها را در یک تاپل یا یک آرایه قرار می دهید. روش درست برای فراخوانی این تابع مانند زیر است:

DISPLAYSURF=pygame.display.set_mode((400,300))

استفاده از کد بالا به صورت pygame.display.set_mode(400, 300) باعث ایجاد خطایی به صورت زیر می شود:

خطای TypeError

خطای بالا می گوید که آرگومان ارسالی به تابع باید یک تاپل دوتایی یا یک آرایه با دو مقدار صحیح باشد. پس همیشه بیاد داشته باشید که اندازه پنجره را در یک تاپل یا آرایه قرار بدهید و سپس آن را در set_mode استفاده کنید. شی بازگشت داده شده از set_mode در متغیری به نام DISPLAYSURF ذخیره می شود.

در خط زیر با تابع pygame.display.set_caption نام پنجره را تعیین کرده ایم. نام پنجره در بالای آن ظاهر می شود. این تابع یک رشته را به عنوان پارامتر می گیرد. رشته '!Hello World'  به این تابع فرستاده داده شده است:

pygame.display.set_caption('Hello World!')

نام پنجره

حلقه و وضعیت بازی

while True: # main game loop
    for event in pygame.event.get():

خط بالا یک حلقه while است که شرط آن True است. این حلقه هرگز متوقف نمی شود مگر این که شرط آن False شود. تنها راه خروج از حلقه این است که یک break یا ()sys.exit اجرا شود. همه بازی های این سری آموزشی این حلقه  while را دارند. به این حلقه حلقه اصلی بازی یا main loop می گوییم. کار آن اجرای بازی تا هنگام بستن شدن پنجره است. درون main loop حلقه ای دیگر قرار دارد که به آن حلقه مدیریت رویداد می گوییم. این حلقه مهم ترین بخش یک برنامه واکنشی مانند بازی ها است.حلقه مدیریت رویداد سه کار را انجام می دهد:

  1. رویدادها را کنترل می کند مانند کلیک کردن موس یا فشار دادن دکمه ای روی صفحه کلیک و...
  2. وضعیت بازی را به روزسانی یا ویرایش می کند.
  3. وضعیت بازی را روی صفحه نشان می دهد.

به شکل زیر خوب نگاه کنید تا بهتر متوجه نوشته های بالا شوید:

وظایف Game Loop

وضعیت بازی یا game state چیست؟

اگر تا به حال بازی انجام داده اید که به شما امکان ذخیره کردن مرحله های بازی را می دهد و در هر بار بازی کردن مجبور نیستید که از مرحله اول شروع کنید، می توانم بگویم که شما با وضعیت بازی آشنایی مختصری دارید.

وضعیت بازی راهی ساده برای مراجعه به همه متغیرهای موجود در یک بازی است. در بسیاری از بازی ها، وضعیت بازی مقادیر متغیرها را در خود دارد مانند تعداد جان ها، موقعیت بازیکنان و موقعیت دشمنان که معمولا در بالا یا پایین صفحه با شکلی ویژه نشان داده می شوند. هرگاه رویدادی مانند آسیب دیدن بازیکن (که یکی از جان های او را کم می کند)، حرکت کردن دشمن یا ... که مقدار متغیرهای بازی را تغییر می دهد رخ دهد، می گوییم وضعیت بازی تغییر کرده است.

وضعیت بازی در نقطه ای می ماند که شما آن را ذخیره کرده اید. در بیش تر بازی ها، درنگ در بازی یا pause کردن آن وضعیت بازی را تغییر نخواهد داد. از آن جایی که معمولا وضعیت بازی در پاسخ به رویدادها (مانند کلیک ماوس یا فشار دادن صفحه کلید) یا گذشت زمان به روز می شود، حلقه بازی باید در هر ثانیه برای هر رویداد جدیدی که رخ داده است، بررسی هایی را انجام دهد. pygame، این بررسی را با تابع pygame.event.get انجام می دهد. حلقه event (رویداد) کدی دارد که بر اساس رویداد ایجاد شده، وضعیت بازی را به روز می کند. به این کار رسیدگی به رویدادها یا مدیریت رویدادها گفته می شود. پس نام حلقه رویداد از کاری که انجام می دهد می آید.

شی های pygame.event.Event (بررسی رویدادها و مدیریت آن ها)

هربار که کاربر چند کار را با هم انجام می دهد مانند فشار دادن صفحه کلید یا حرکت موس روی پنجره برنامه، یک شی pygame.event.Event توسط کتابخانه pygame ایجاد می شود تا این رویدادها را ثبت کند. (شی Event در ماژول event است و خود ماژول event در ماژول pygame قرار دارد.) با فراخوانی تابع ()pygame.event.get می توانیم بفهمیم که کدام رویدادها رخ داده اند. این تابع آرایه ای از اشیا pygame.event.Event را برمی گرداند.

اعضای این آرایه دو حالت خواهند داشت :(دو جمله زیر را چندبار بخوانید)

  1. در حالت اول اعضای آن برابر با رویدادهایی است که از آخرین فراخوانی تابع  pygame.event.get رخ داده اند.
  2. اگر pygame.event.get هرگز فراخوانی نشده باشد، رویدادهایی که از ابتدای برنامه اتفاق افتاده اند اعضای آرایه را تشکیل خواهند داد.

حلقه for در آرایه event که توسط تابع  pygame.event.get برگردانده شده است، حلقه می زند یعنی یک سری دستور را چندین بار تکرار می کند. در هر تکرار حلقه for، متغیر event رویدادی را در آرایه event مشخص می کند. آرایه event رویدادها را به همان ترتیبی که اتفاق افتاده اند برمی گرداند. (توجه کنید که متغیر event و آرایه event با هم تفاوت دارند.)

اگر کاربر روی موس کلیک کند و سپس یک کلید صفحه کلید را فشار دهد، شی event برای کلیک شدن موس عضو اول در آرایه و برای فشرده شدن صفحه کلید عضو دوم خواهد بود. یعنی:

شی رویداد برای کلیک شدن موس = [0]event

شی رویداد برای فشرده شدن دکمه = [1]event

اگر هیچ رویدادی رخ نداده باشد pygame.event.get یک آرایه خالی را برمی گرداند.

رویداد QUIT و تابع pygame.quit

if event.type==QUIT:
    pygame.quit()
    sys.exit()

اشیا event یک ویژگی به نام type دارند که مشخص کننده نوع رویداد است. pygame برای هر یک از این انواع موجود در ماژول pygame.locals یک ثابت دارد. خط کدبالا بررسی می کند که آیا نوع رویداد برابر با مقدار ثابت QUIT است یا نه.اگر یک رویداد quit داشته باشیم، آنگاه توابع pygame.quit و sys.exit فراخوانی می شوند. تابع pygame.quit به نوعی مخالف تابع pygame.init است.این تابع کدی را اجرا می کند که کتابخانه pygame را غیرفعال می کند.

تابع pygame.quit همیشه باید قبل از sys.exit باشد. در این جا هیچ شرطی برای بقیه رویدادها مانند حرکت موس و... نداریم بنابراین اگر روی پنجره کلیک کنید یا یکی از دکمه ها را فشار دهید، هیچ اتفاقی نمی افتد.

pygame.display.update()

تابع update(به روز آوری وضعیت بازی) 

خط آخر تابع pygame.display.update را فراخوانی می کند. این تابع شی ای را که توسط pygame.display.set_mode برگردانده می شود، نمایش می دهد (به یاد داشته باشید که ما این شی را در متغیر DISPLAYSURF ذخیره کرده ایم). از آن جایی که شی DISPLAYSURF در بازی تغییر نمی کند، هر بار که تابع pygame.display.update  فراخوانی می شود، همان تصویر سیاه دوباره نشان داده می شود. پس از اجرا شدن خط آخر، حلقه while دوباره کار خود را که نمایش پنجره سیاه است تکرار می کند. برای بسته شدن پنجره باید از گوشه پنجره روی دکمه X کلیک کنیم.

در آخر باید بگویم که همه برنامه های نوشته شده با pygame دارای سه بخش کلی و ثابت هستند:

  1. وارد کردن کتابخانه ها و مقداردهی pygame با pygame.init
  2. تعریف متغیرها و ثابت ها
  3. حلقه اصلی بازی

این سه بخش در تصویر زیر نشان داده شده اند:

بخش های اصلی هر برنامه با pygame

تا این جا دیدیم که چگونه سه کار اصلی حلقه رویداد که بررسی رویدادها،  مدیریت آن ها و به روزرسانی وضعیت بازی بود انجام شد. این همه داستان رسم یک پنجره ساده با pygame بود. در این قسمت با سه بخش اصلی هر برنامه pygame نیز آشنا شدیم. در بخش بعدی در مورد رنگ ها نکاتی را یاد می گیریم و می فهمیم که چگونه رنگ پنجره را تغییر دهیم. سپس یاد می گیریم که چگونه با زدن یک دکمه خاص رنگ پنجره و هم چنین نام آن را تغییر دهیم.

تمام فصل‌های سری ترتیبی که روکسو برای مطالعه‌ی دروس سری بازی‌سازی با پایتون توصیه می‌کند:
نویسنده شوید
دیدگاه‌های شما

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.