خانه توسعهدهنده تکنولوژی بکاند پایتون آموزش ساخت بازی مار با پایتون در ۸ مرحله – تصویری و آسان
آموزش ساخت بازی مار با پایتون در ۸ مرحله – تصویری و آسان
تقریبا هیچکسی نیست که بازی معروف «مار» یا «Snake» را تجربه نکرده باشد. این بازی کلاسیک ساختاری بسیار ساده دارد، اما آنقدر درگیرکننده و جذاب است که دائما میخواهید به تجربهاش ادامه دهید و رکورد قبلی خود را بشکنید. اگر علاقهمند به آموزش برنامه نویسی یا به صورت دقیقتر، آموزش پایتون باشید، ساخت بازی مار تمرین خوبی است که هم باعث میشود خلاقیت به خرج بدهید و هم مهارتهای کامپیوتری خود را صیقل دهید. با کوئرا بلاگ و آموزش ساخت بازی مار با پایتون همراه باشید.
بازی مار چیست و چگونه آن را میسازیم؟
در این مقاله ساخت بازی Snake را یاد میگیریم که در آن، بازیکن کنترل یک مار را برعهده دارد. این مار در سراسر صفحه حرکت میکند و غذاهایی میخورد که او را درازتر میکنند. همینطور که مار دراز و درازتر میشود، باید به خوردن غذاها ادامه دهد و در عین حال، با لبههای صفحه یا بدن خودش برخورد نکند.
برای ساخت این بازی باید از یک رابط کاربری گرافیکی (Graphical User Interface | GUI) مانند Pygame یا Tkinter استفاده کنیم که هم در افزودن ابعاد بصری کمک میکند و هم قابلیتهایی مانند ثبت ورودی کاربر، حرکت مار، تشخیص برخورد، خوردن غذا و Game Over را در اختیارمان میگذارد.
پیشنیازهای ساخت بازی مار با پایتون
برای اینکه بتوانید این پروژه را به خوبی پیش ببرید، نیاز به آشنایی با مبانی برنامهنویسی و مبانی زبان پایتون دارید و موارد زیر نیز فرایند را بهینهتر و آسانتر خواهند کرد:
- مبانی پایتون: دانش راجع به متغیرها، انواع داده، شرطها، لوپها، توابع و کار با ورودیها و خروجیها
- برنامهنویسی شی گرا: درک مفاهیمی مانند کلاسها، اشیا و وراثت در برنامهنویسی شی گرا (Object-Oriented Programming | OOP) به نوشتن کدی ساختارمند کمک میکند.
- آشنایی با Pygame یا Tkinter: بسته به اینکه از کدام پکیج گرافیکی استفاده میکنید، لازم است با Pygame یا Tkinter آشنا باشید تا صفحه گرافیکی و وقایع بازی را بسازید.
- مدیریت ورودی کاربر: برای اینکه بشود مار را به حرکت درآورد، باید با نحوه ثبت و رسیدگی به ورودی کاربر یا User Input آشنا باشید.
- ایدههای بنیادین بازیسازی: برای ساخت بازی Snake باید لوپ بازیها، تغییرات وضعیت بازی، ساخت تصویر و ثبت برخوردارها را درک کنید.
- فهرستها و آرایههای دوبعدی: اگر نحوه کار با فهرستها و آرایههای دوبعدی را بدانید، میتوانید صفحه بازی را به نمایش درآورید و موقعیت مار را کنترل کنید.
اگرچه لازم نیست در تمامی این حوزهها تجربه کسب کرده باشید، هرچه دانش اولیه بیشتر باشد، قواعد بازی را راحتتر درک و پیادهسازی میکنید. ضمنا نصب یک محیط توسعه یکپارچه (Integrated Development Environment | IDE) مانند PyCharm ،Visual Studio Code یا IDLE هم ایده بدی نیست. به این ترتیب میتوانید کد پایتون را بنویسید و اجرا کنید.
بیشتر بخوانید: بهترین IDE پایتون
۱. نصب Pygame
اولین کاری که باید برای بازیسازی با پایتون انجام داد، نصب Pygame روی سیستم است. برای این کار فرمان زیر را وارد کنید:
pip install pygame
بعد از این، Pygame را ایمپورت و روند توسعه بازی را شروع میکنیم. اما قبل از اینکه به مرحله بعدی ساخت بازی مار با پایتون برویم، نگاهی به توابع کاربردی Pygame در این آموزش بیندازید:
توابع | کارکرد |
()init | راهاندازی تمام ماژولهای ایمپورتشده Pygame (موفقیت یا شکست در راهاندازی را با یک تاپل نشان میدهد) |
()display.set_mode | یک تاپل یا فهرست را به عنوان پارامتر ساخت سطح در نظر میگیرد |
()update | صفحه را بهروزرسانی میکند |
()quit | برای متوقف کردن همهچیز به کار میرود |
()set_caption | متن کپشن را در بالای صفحه نمایش قرار میدهد |
()event.get | فهرستی از تمام وقایع ارائه میکند |
()Surface.fill | سطح را با یک رنگ پر میکند |
()time.Clock | به پایش زمان کمک میکند |
()font.SysFont | با استفاده از فونتهای سیستم، یک فونت Pygame میسازد |
۲. ساخت صفحه بازی
برای ساخت صفحه یا Screen به کمک Pygame، باید از تابع ()display.set_mode استفاده کنیم. علاوه بر این، برای راهاندازی و متوقف کردن همهچیز در ابتدا و انتهای کد، نیاز به استفاده از متدهای ()init و ()quit خواهید داشت. از متد ()update هم برای بهروزرسانی هر تغییری در صفحه استفاده میشود. ناگفته نماند که متد دیگری به اسم ()flip نیز داریم که شبیه به تابع ()update عمل میکند. تفاوت در این است که ()update صرفا تغییرات را بهروزرسانی میکند، اما ()flip تمام صفحه را از نو میسازد.
کد:
import pygame
pygame.init()
dis=pygame.display.set_mode((400,300))
pygame.display.update()
pygame.quit()
quit()
خروجی:
وقتی این کد را اجرا میکنید، صفحه ظاهر اما فورا بسته میشود. برای حل این مشکل باید از While Loop برای ساخت لوپ بازی کمک بگیریم:
import pygame
pygame.init()
dis=pygame.display.set_mode((400,300))
pygame.display.update()
pygame.display.set_caption('Snake game by Edureka')
game_over=False
while not game_over:
for event in pygame.event.get():
print(event) #prints out all the actions that take place on the screen
pygame.quit()
quit()
وقتی این کد را اجرا میکنید، میبینید صفحهای که پیشتر مشاهده میکردید بسته نمیشود و ضمنا، تمام اکشنهایی را بازمیگرداند که روی آن انجام میشود. برای این کار از تابع ()event.get کمک گرفتهایم. با استفاده از تابع ()display.set_caption هم میتوانید یک نام برای صفحه خود بنویسید که در این مثال «Snake game by Edureka» است.
خروجی:
اکنون صفحه بازی Snake را میبینید، اما وقتی روی دکمه بستن یا Close کلیک میکنید، هیچ اتفاقی نمیافتد. به این خاطر که بسته شدن صفحه بعد از فشردن دکمه Close را تعریف نکردهاید. برای انجام این کار از رویدادی به نام «QUIT» در Pygame کمک میگیریم که باید به شکل زیر استفاده شود:
import pygame
pygame.init()
dis=pygame.display.set_mode((400,300))
pygame.display.update()
pygame.display.set_caption('Snake game by Edureka')
game_over=False
while not game_over:
for event in pygame.event.get():
if event.type==pygame.QUIT:
game_over=True
pygame.quit()
quit()
اکنون صفحه کاملا آماده است. در مرحله بعدی ساخت بازی مار با پایتون میبینیم که چطور میتوان شخصیت اصلی را هم به صفحه اضافه کرد.
۳. ساخت مار
برای ساخت مار ابتدا چند متغیر رنگی را وارد کار میکنیم تا بتوانیم برای مار، غذا، صفحه و تمام موارد اینچنینی رنگی داشته باشیم. Pygame از رنگهای «RGB» یا «Red Green Blue» پشتیبانی میکند. اگر تمام مقادیر را روی 0 بگذارید، رنگ مشکی میشود و اگر تمام مقادیر را روی 555 بگذارید، رنگ سفید به دست خواهید آورد. مار بازی ما در ابتدا چیزی جز یک مربع کوچک نیست. برای رسم مربع در Pygame، میتوانید از تابعی به نام ()draw.rect استفاده کنید که به ترسیم مربعی با رنگ و ابعاد دلخواه کمک میکند.
import pygame
pygame.init()
dis=pygame.display.set_mode((400,300))
pygame.display.set_caption('Snake game by Edureka')
blue=(0,0,255)
red=(255,0,0)
game_over=False
while not game_over:
for event in pygame.event.get():
if event.type==pygame.QUIT:
game_over=True
pygame.draw.rect(dis,blue,[200,150,10,10])
pygame.display.update()
pygame.quit()
quit()
خروجی:
همانطور که میبینید، سر مار به شکل یک مربع آبیرنگ ترسیم شده است. گام بعدی این خواهد بود که مار را به حرکت در بیاوریم.
۴. حرکت دادن مار
برای به حرکت در آوردن مار باید از رویدادهای موجود در کلاس KEYDOWN استفاده کنیم. رویدادهایی که اینجا به کار می گیریم K_LEFT ،K_UP ،K_DOWN و K_RIGHT خواهند بود تا بتوانیم مار را به ترتیب به جهات پایین، بالا، چپ و راست هدایت کنیم. ناگفته نماند که وقتی از متد ()fill استفاده میکنیم، رنگ صفحه از مشکی به سفید تغییر میکند.
متغیرهای جدیدی به نامهای x1_change و y1_change هم ساختهایم که مختصات بهروزرسانیشده x و y را در خود نگه میدارند.
import pygame
pygame.init()
white = (255, 255, 255)
black = (0, 0, 0)
red = (255, 0, 0)
dis = pygame.display.set_mode((800, 600))
pygame.display.set_caption('Snake Game by Edureka')
game_over = False
x1 = 300
y1 = 300
x1_change = 0
y1_change = 0
clock = pygame.time.Clock()
while not game_over:
for event in pygame.event.get():
if event.type == pygame.QUIT:
game_over = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
x1_change = -10
y1_change = 0
elif event.key == pygame.K_RIGHT:
x1_change = 10
y1_change = 0
elif event.key == pygame.K_UP:
y1_change = -10
x1_change = 0
elif event.key == pygame.K_DOWN:
y1_change = 10
x1_change = 0
x1 += x1_change
y1 += y1_change
dis.fill(white)
pygame.draw.rect(dis, black, [x1, y1, 10, 10])
pygame.display.update()
clock.tick(30)
pygame.quit()
quit()
خروجی:
۵. اتمام بازی با برخورد مار به لبههای صفحه
در این بازی Snake اگر بازیکن به لبههای صفحه برخورد کند، میبازد. برای پیادهسازی این قانون از Statement یا بیانیه «if» استفاده میکنیم که براساس آن، مختصات x و y مار باید کمتر از مختصات تمام صفحه یا مساوی با آن باشد. توجه داشته باشید که به جای کدهای سخت، از متغیرها استفاده میکنیم تا بعدا بتوانید تغییرات لازم را به آسانی در بازی خود پیاده کنید.
import pygame
import time
pygame.init()
white = (255, 255, 255)
black = (0, 0, 0)
red = (255, 0, 0)
dis_width = 800
dis_height = 600
dis = pygame.display.set_mode((dis_width, dis_width))
pygame.display.set_caption('Snake Game by Edureka')
game_over = False
x1 = dis_width/2
y1 = dis_height/2
snake_block=10
x1_change = 0
y1_change = 0
clock = pygame.time.Clock()
snake_speed=30
font_style = pygame.font.SysFont(None, 50)
def message(msg,color):
mesg = font_style.render(msg, True, color)
dis.blit(mesg, [dis_width/2, dis_height/2])
while not game_over:
for event in pygame.event.get():
if event.type == pygame.QUIT:
game_over = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
x1_change = -snake_block
y1_change = 0
elif event.key == pygame.K_RIGHT:
x1_change = snake_block
y1_change = 0
elif event.key == pygame.K_UP:
y1_change = -snake_block
x1_change = 0
elif event.key == pygame.K_DOWN:
y1_change = snake_block
x1_change = 0
if x1 >= dis_width or x1 < 0 or y1 >= dis_height or y1 < 0:
game_over = True
x1 += x1_change
y1 += y1_change
dis.fill(white)
pygame.draw.rect(dis, black, [x1, y1, snake_block, snake_block])
pygame.display.update()
clock.tick(snake_speed)
message("You lost",red)
pygame.display.update()
time.sleep(2)
pygame.quit()
quit()
خروجی:
۶. اضافه کردن غذا
در مرحله بعدی ساخت بازی مار با پایتون غذا را هم به صفحه اضافه و تعریف میکنیم که مار هر بار که غذا میخورد، پیامی (مثلا !Yummy) به نمایش درآید. تغییراتی کوچک هم در کد ایجاد میکنیم تا برای مثال بازیکن گزینهای برای خروج از بازی، یا بازی کردن دوباره بعد از هر شکست داشته باشد.
import pygame
import time
import random
pygame.init()
white = (255, 255, 255)
black = (0, 0, 0)
red = (255, 0, 0)
blue = (0, 0, 255)
dis_width = 800
dis_height = 600
dis = pygame.display.set_mode((dis_width, dis_height))
pygame.display.set_caption('Snake Game by Edureka')
clock = pygame.time.Clock()
snake_block = 10
snake_speed = 30
font_style = pygame.font.SysFont(None, 30)
def message(msg, color):
mesg = font_style.render(msg, True, color)
dis.blit(mesg, [dis_width/3, dis_height/3])
def gameLoop(): # creating a function
game_over = False
game_close = False
x1 = dis_width / 2
y1 = dis_height / 2
x1_change = 0
y1_change = 0
foodx = round(random.randrange(0, dis_width - snake_block) / 10.0) * 10.0
foody = round(random.randrange(0, dis_width - snake_block) / 10.0) * 10.0
while not game_over:
while game_close == True:
dis.fill(white)
message("You Lost! Press Q-Quit or C-Play Again", red)
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_q:
game_over = True
game_close = False
if event.key == pygame.K_c:
gameLoop()
for event in pygame.event.get():
if event.type == pygame.QUIT:
game_over = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
x1_change = -snake_block
y1_change = 0
elif event.key == pygame.K_RIGHT:
x1_change = snake_block
y1_change = 0
elif event.key == pygame.K_UP:
y1_change = -snake_block
x1_change = 0
elif event.key == pygame.K_DOWN:
y1_change = snake_block
x1_change = 0
if x1 >= dis_width or x1 < 0 or y1 >= dis_height or y1 < 0:
game_close = True
x1 += x1_change
y1 += y1_change
dis.fill(white)
pygame.draw.rect(dis, blue, [foodx, foody, snake_block, snake_block])
pygame.draw.rect(dis, black, [x1, y1, snake_block, snake_block])
pygame.display.update()
if x1 == foodx and y1 == foody:
print("Yummy!!")
clock.tick(snake_speed)
pygame.quit()
quit()
gameLoop()
خروجی:
۷. افزایش طول مار
کدی که در پایین آوردهایم باعث میشود هر بار که غذا میخورید، مار به اندازه یک مربع درازتر شود. علاوه بر این، اگر مار با بدن خودش برخورد کند نیز بازی به پایان میرسد و پیام «You Lost! Press Q-Quit or C-Play Again» به نمایش درمیآید. اساسا درازای مار را درون یک فهرست نگه میداریم و ابعاد اولیهای که برایش تعریف کردهایم هم تنها یک بلوک است.
import pygame
import time
import random
pygame.init()
white = (255, 255, 255)
yellow = (255, 255, 102)
black = (0, 0, 0)
red = (213, 50, 80)
green = (0, 255, 0)
blue = (50, 153, 213)
dis_width = 600
dis_height = 400
dis = pygame.display.set_mode((dis_width, dis_height))
pygame.display.set_caption('Snake Game by Edureka')
clock = pygame.time.Clock()
snake_block = 10
snake_speed = 15
font_style = pygame.font.SysFont("bahnschrift", 25)
score_font = pygame.font.SysFont("comicsansms", 35)
def our_snake(snake_block, snake_list):
for x in snake_list:
pygame.draw.rect(dis, black, [x[0], x[1], snake_block, snake_block])
def message(msg, color):
mesg = font_style.render(msg, True, color)
dis.blit(mesg, [dis_width / 6, dis_height / 3])
def gameLoop():
game_over = False
game_close = False
x1 = dis_width / 2
y1 = dis_height / 2
x1_change = 0
y1_change = 0
snake_List = []
Length_of_snake = 1
foodx = round(random.randrange(0, dis_width - snake_block) / 10.0) * 10.0
foody = round(random.randrange(0, dis_height - snake_block) / 10.0) * 10.0
while not game_over:
while game_close == True:
dis.fill(blue)
message("You Lost! Press C-Play Again or Q-Quit", red)
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_q:
game_over = True
game_close = False
if event.key == pygame.K_c:
gameLoop()
for event in pygame.event.get():
if event.type == pygame.QUIT:
game_over = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
x1_change = -snake_block
y1_change = 0
elif event.key == pygame.K_RIGHT:
x1_change = snake_block
y1_change = 0
elif event.key == pygame.K_UP:
y1_change = -snake_block
x1_change = 0
elif event.key == pygame.K_DOWN:
y1_change = snake_block
x1_change = 0
if x1 >= dis_width or x1 < 0 or y1 >= dis_height or y1 < 0:
game_close = True
x1 += x1_change
y1 += y1_change
dis.fill(blue)
pygame.draw.rect(dis, green, [foodx, foody, snake_block, snake_block])
snake_Head = []
snake_Head.append(x1)
snake_Head.append(y1)
snake_List.append(snake_Head)
if len(snake_List) > Length_of_snake:
del snake_List[0]
for x in snake_List[:-1]:
if x == snake_Head:
game_close = True
our_snake(snake_block, snake_List)
pygame.display.update()
if x1 == foodx and y1 == foody:
foodx = round(random.randrange(0, dis_width - snake_block) / 10.0) * 10.0
foody = round(random.randrange(0, dis_height - snake_block) / 10.0) * 10.0
Length_of_snake += 1
clock.tick(snake_speed)
pygame.quit()
quit()
gameLoop()
خروجی:
۸. نمایش امتیاز
و در نهایت نوبت به نمایش امتیاز بازیکن میرسد. برای اضافه کردن این ویژگی، تابعی جدید به نام «Your_score» ساختهایم. این تابع، طول مار را تقسیم بر ۱ نشان میدهد، چون ۱ را اندازه اولیه مار تعریف کردهایم.
import pygame
import time
import random
pygame.init()
white = (255, 255, 255)
yellow = (255, 255, 102)
black = (0, 0, 0)
red = (213, 50, 80)
green = (0, 255, 0)
blue = (50, 153, 213)
dis_width = 600
dis_height = 400
dis = pygame.display.set_mode((dis_width, dis_height))
pygame.display.set_caption('Snake Game by Edureka')
clock = pygame.time.Clock()
snake_block = 10
snake_speed = 15
font_style = pygame.font.SysFont("bahnschrift", 25)
score_font = pygame.font.SysFont("comicsansms", 35)
def Your_score(score):
value = score_font.render("Your Score: " + str(score), True, yellow)
dis.blit(value, [0, 0])
def our_snake(snake_block, snake_list):
for x in snake_list:
pygame.draw.rect(dis, black, [x[0], x[1], snake_block, snake_block])
def message(msg, color):
mesg = font_style.render(msg, True, color)
dis.blit(mesg, [dis_width / 6, dis_height / 3])
def gameLoop():
game_over = False
game_close = False
x1 = dis_width / 2
y1 = dis_height / 2
x1_change = 0
y1_change = 0
snake_List = []
Length_of_snake = 1
foodx = round(random.randrange(0, dis_width - snake_block) / 10.0) * 10.0
foody = round(random.randrange(0, dis_height - snake_block) / 10.0) * 10.0
while not game_over:
while game_close == True:
dis.fill(blue)
message("You Lost! Press C-Play Again or Q-Quit", red)
Your_score(Length_of_snake - 1)
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_q:
game_over = True
game_close = False
if event.key == pygame.K_c:
gameLoop()
for event in pygame.event.get():
if event.type == pygame.QUIT:
game_over = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
x1_change = -snake_block
y1_change = 0
elif event.key == pygame.K_RIGHT:
x1_change = snake_block
y1_change = 0
elif event.key == pygame.K_UP:
y1_change = -snake_block
x1_change = 0
elif event.key == pygame.K_DOWN:
y1_change = snake_block
x1_change = 0
if x1 >= dis_width or x1 < 0 or y1 >= dis_height or y1 < 0:
game_close = True
x1 += x1_change
y1 += y1_change
dis.fill(blue)
pygame.draw.rect(dis, green, [foodx, foody, snake_block, snake_block])
snake_Head = []
snake_Head.append(x1)
snake_Head.append(y1)
snake_List.append(snake_Head)
if len(snake_List) > Length_of_snake:
del snake_List[0]
for x in snake_List[:-1]:
if x == snake_Head:
game_close = True
our_snake(snake_block, snake_List)
Your_score(Length_of_snake - 1)
pygame.display.update()
if x1 == foodx and y1 == foody:
foodx = round(random.randrange(0, dis_width - snake_block) / 10.0) * 10.0
foody = round(random.randrange(0, dis_height - snake_block) / 10.0) * 10.0
Length_of_snake += 1
clock.tick(snake_speed)
pygame.quit()
quit()
gameLoop()
خروجی:
چند ایده برای تکمیل ساخت بازی مار با پایتون
در حال حاضر یک بازی Snake کامل داریم، اما اگر دوست داشتید میتوانید ویژگیهای دیگری هم به آن اضافه کنید تا سرگرمکنندهتر شود. در ادامه چند پیشنهاد برایتان داریم:
- مراحل مختلفی بسازید و میزان چالش را به مرور افزایش دهید: همینطور که مراحل بازی پیش میروند، میتوانید موانعی به صفحه اضافه کنید یا سرعت حرکت مار را افزایش دهید.
- Power-Up طراحی کنید: پاور آپ به معنی تواناییهای موقتی اما ارزشمند برای بازیکن است، مثلا میتوانید مار را درازتر کنید یا اجازه دهید از میان دیوارها رد شود.
- غذاهای مخصوص: غذاهایی خاصتر طراحی کنید که هر چند وقت یکبار ظاهر میشوند و برای مثال امتیازی اضافه یا قدرتی بهخصوص به بازیکن میدهند.
- پایش بالاترین امتیازها: راهی برای پایش امتیازها و ردهبندی آنها پیدا کنید. میتوانید امتیازها را درون یک فایل یا دیتابیس نگه دارید و به ترتیبهای مختلف نشان دهید.
- افکت صوتی و موسیقی: برای وقایع بازی – مثلا زمانی که غذا میخورید، با بدن خودتان برخورد میکنید یا مرحله را به اتمام میرسانید – افکت صوتی در نظر بگیرید. موسیقی پسزمینه هم بازی را لذتبخشتر میکند.
- گزینههای سفارشی: به بازیکن اجازه دهید تنظیمات گوناگون را تغییر دهد، مثلا سرعت مار، ابعاد صفحه و رنگبندیها.
- حالت دو نفره: حالتی بسازید که در آن دو نفر میتوانند روی صفحهای واحد با یکدیگر بازی کنند و هرکدام، کنترل ماری مجزا را برعهده بگیرند.
- انیمیشن Game Over: با انیمیشنها و افکتهای بصری مختلف مثل انفجار یا صفحهای که امتیاز نهایی را نشان میدهد، پایان بازی را اعلام کنید.
- چالشهای اضافه: چالشها و مینیگیمهایی به بازی اضافه کنید که بازیکن با رسیدگی به آنها، امتیاز بیشتری دریافت میکند.
- نسخه موبایل: تنظیمات و ساختار بازی را بهگونهای تغییر دهید که کاملا با نمایشگرهای لمسی سازگار باشد.
+ منبع: Edureka