رسم اشکال در Pygame - قسمت سوم

How to Draw Shapes in Pygame? Part 3

01 آبان 1400
How-to-Draw-Shapes-in-Pygame-Part-3

پیش گفتار

در این بخش می خواهیم کمی بیش تر با مستطیل ها کار کنیم و آن ها را با موس و کیبورد حرکت دهیم و با شی Rect نیز بیش تر آشنا می شویم.

کار با مستطیل ها

مستطیل یک شی بسیار مفید در برنامه نویسی گرافیکی است. کلاس Rect در Pygame برای کارکردن با یک ناحیه مستطیلی شکل استفاده می شود. با داشتن موارد زیر می توان یک شی Rect از کلاس Rect را ایجاد کرد:

  • 4 پارامتر سمت چپ، بالا، عرض و ارتفاع (left, top, width, height)
  • موقعیت و اندازه
  • شی ای که دارای ویژگی rect است
Rect(left, top, width, height)
Rect(pos, size)
Rect(obj)

متد هایی که موقعیت(position) یا اندازه(size) را تغییر می دهند، مانند move و inflate، مستطیل اصلی را دست نخورده باقی می گذارند و یک مستطیل را جدید بازگردانند.

ویژگی های دیگر مستطیل

شی Rect دارای ویژگی های دیگری نیز است که می تواند برای جابجایی و ترازبندی مستطیل استفاده شود. به کار گیری این ویژگی ها اندازه مستطیل را تغییر نمی دهد.این ویژگی ها در زیر آمده اند:

x, y
top, left, bottom, right
topleft, bottomleft, topright, bottomright
midtop, midleft, midbottom, midright
center, centerx, centery

استفاده از پنج ویژگی زیر، اندازه مستطیل را با حفظ موقعیت بالا چپ (top left) آن تغییر می دهد:

size, width, height, w, h

کد زیر ویژگی های معرفی شده در بالا را، در کنسول نمایش می دهد:

import pygame
from pygame.locals import *
SIZE = 500, 200
RED = (255, 0, 0)
GRAY = (150, 150, 150)
pygame.init()
screen = pygame.display.set_mode(SIZE)
rect = Rect(50, 60, 200, 80)
print(f'x={rect.x}, y={rect.y}, w={rect.w}, h={rect.h}')
print(f'left={rect.left}, top={rect.top}, right={rect.right}, bottom={rect.bottom}')
print(f'center={rect.center}')
running = True
while running:
    for event in pygame.event.get():
        if event.type == QUIT:
            running = False
    screen.fill(GRAY)
    pygame.draw.rect(screen, RED, rect)
    pygame.display.flip()
pygame.quit()

نقاط ویژه

کلاس Rect دارای چهار نقطه کناری، چهار نقطه میانی و یک نقطه مرکزی است.

کد رسم مستطیل بالا در زیر آمده است:

from rect import *
pts = ('topleft', 'topright', 'bottomleft', 'bottomright','midtop', 'midright', 'midbottom', 'midleft', 'center')
running = True
while running:
    for event in pygame.event.get():
        if event.type == QUIT:
            running = False
    screen.fill(GRAY)
    pygame.draw.rect(screen, GREEN, rect, 4)
    for pt in pts:
        pos = eval('rect.'+pt)
        draw_text(pt, pos)
        pygame.draw.circle(screen, RED, pos, 3)
    pygame.display.flip()
pygame.quit()

ترازبندی (alignment) افقی و عمودی

در مثال زیر از سه کلید برای ترازبندی افقی مستطیل استفاده می کنیم:

• L - left
• C - center
• R - right

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

• T - top
• M - middle
• B - bottom

from rect import *

rect = Rect(50, 60, 200, 80)

while running:
    for event in pygame.event.get():
        if event.type == QUIT:
            running = False

        if event.type == KEYDOWN:
            if event.key == K_l:
                rect.left = 0
            if event.key == K_c:
                rect.centerx = width//2
            if event.key == K_r:
                rect.right = width

            if event.key == K_t:
                rect.top = 0
            if event.key == K_m:
                rect.centery = height//2
            if event.key == K_b:
                rect.bottom = height

    screen.fill(GRAY)
    pygame.draw.rect(screen, BLUE, rect)
    pygame.display.flip()

pygame.quit()

حرکت مستطیل با کیبورد

متد move (v) یک مستطیل جدید ایجاد می کند که توسط بردار v حرکت کرده است. متد move_ip (v) یک مستطیل را در جای خود حرکت می دهد. برنامه زیر با استفاده از کلیدهای پیکانی یک مستطیل را به اطراف حرکت می دهد. مستطیل نازک و آبی مستطیل اصلی است، و مستطیل قرمز همان مستطیل آبی است که حرکت کرده است. ما از یک دیکشنری برای مرتبط کردن یک بردار حرکت برای هر یک از 4 کلید پیکانی استفاده می کنیم. در هر جهتی 5 پیکسل حرکت می کنیم:

dir = {K_LEFT: (-5, 0), K_RIGHT: (5, 0), K_UP: (0, -5), K_DOWN: (0, 5)}

from rect import *

rect0 = Rect(50, 60, 200, 80)
rect = rect0.copy()

while running:
    for event in pygame.event.get():
        if event.type == QUIT:
            running = False
        
        if event.type == KEYDOWN:
            if event.key in dir:
                v = dir[event.key]
                rect.move_ip(v)

    screen.fill(GRAY)
    pygame.draw.rect(screen, BLUE, rect0, 1)
    pygame.draw.rect(screen, RED, rect, 4)
    pygame.display.flip()

pygame.quit()

تغییر اندازه مستطیل

متد inflate (v) یک مستطیل را با بردار v بزرگ یا کوچک می کند و یک مستطیل جدید به وجود می آورد. متد inflate_ip (v) باعث بزرگ یا کوچک شدن یک مستطیل در جای خود می شود. برنامه زیر با استفاده از کلیدهای پیکانی اندازه مستطیل را تغییر می دهد. مستطیل قرمز تغییر یافته مستطیل آبی است.

from rect import *

rect0 = rect.copy()

while running:
    for event in pygame.event.get():
        if event.type == QUIT:
            running = False
        
        if event.type == KEYDOWN:
            if event.key in dir:
                v = dir[event.key]
                rect.inflate_ip(v)

    screen.fill(GRAY)
    pygame.draw.rect(screen, BLUE, rect0, 1)
    pygame.draw.rect(screen, RED, rect, 4)
    pygame.display.flip()

pygame.quit()

حرکت مستطیل با موس

اگر نقطه با مستطیل تماس پیدا کند، تابع rect.collidepoint (pos)  مقدار بولین True را برمی گرداند. از این مقدار برگشتی همراه با موقعیت موس استفاده می کنیم تا بفهمیم که آیا موس در داخل مستطیل کلیک کرده است یا نه. اگر کلیک رخ داده باشد، مستطیل را با موس حرکت می دهیم .متغیر moving هنگامی که دکمه موس در داخل مستطیل کلیک می شود، تنظیم می شود.این متغییر تا زمانی که دکمه بالا نرفته است،  True می ماند. مستطیل فقط زمانی حرکت می کند که موس در داخل مستطیل کلیک کرده باشد. در حالی که مستطیل در حال حرکت است، یک حاشیه آبی رنگ به دور مستطیل می افزاییم مانند تصویر زیر:

from rect import *

moving = False

while running:
    for event in pygame.event.get():
        if event.type == QUIT:
            running = False

        elif event.type == MOUSEBUTTONDOWN:
            if rect.collidepoint(event.pos):
                moving = True

        elif event.type == MOUSEBUTTONUP:
            moving = False

        elif event.type == MOUSEMOTION and moving:
            rect.move_ip(event.rel)
    
    screen.fill(GRAY)
    pygame.draw.rect(screen, RED, rect)
    if moving:
        pygame.draw.rect(screen, BLUE, rect, 4)
    pygame.display.flip()

pygame.quit()

مستطیل خود رونده

کد زیر یک مستطیل را با مقدار v حرکت می دهد:

rect.move_ip(v)

سپس  چهار حاشیه مستطیل را بررسی می کند و سرعت حرکت مستطیل را خارج از پنجره برنامه تنظیم می کند.

from rect import *

rect = Rect(100, 50, 50, 50)
v = [2, 2]

while running:
    for event in pygame.event.get():
        if event.type == QUIT:
            running = False

    rect.move_ip(v)

    if rect.left < 0:
        v[0] *= -1
    if rect.right > width:
        v[0] *= -1
    if rect.top < 0:
        v[1] *= -1
    if rect.bottom > height:
        v[1] *= -1
   
    screen.fill(GRAY)
    pygame.draw.rect(screen, RED, rect)
    pygame.display.flip()

pygame.quit()

نقاط برخورد (colliding points)

متد rect.collidepoint (p) بررسی می کند که آیا یک مستطیل با نقطه p برخورد می کند یا نه. در برنامه زیر صد نقطه تصادفی ایجاد می کنیم و اگر داخل مستطیل قرار بگیرند آن ها را قرمز رنگ می کنیم. با هر بار فشار دادن کلید  R صد نقطه تصادفی جدید ایجاد می شود.

from rect import *

points = random_points(100)

while running:
    for event in pygame.event.get():
        if event.type == QUIT:
            running = False
        
        if event.type == KEYDOWN:
            if event.key == K_r:
                points = random_points(100)
   
    screen.fill(GRAY)
    pygame.draw.rect(screen, GREEN, rect, 1)
    for p in points:
        if rect.collidepoint(p):
            pygame.draw.circle(screen, RED, p, 4, 0)
        else:
            pygame.draw.circle(screen, BLUE, p, 4, 0)
    
    pygame.display.flip()

pygame.quit()

مستطیل های برخورد کننده

متد rect.colliderect (r) بررسی می کند که آیا یک مستطیل با یک مستطیل دیگر برخورد می کند یا نه. در برنامه زیر پنجاه مستطیل تصادفی ایجاد کرده و در صورت برخورد با مستطیل سبز، آن ها را قرمز رنگ می کنیم. با هر بار فشار دادن کلید  R صد مستطیل تصادفی جدید ایجاد می شود.

from rect import *

n = 50
rects = random_rects(n)

while running:
    for event in pygame.event.get():
        if event.type == QUIT:
            running = False
        
        if event.type == KEYDOWN:
            if event.key == K_r:
                rects = random_rects(n)
   
    screen.fill(GRAY)
    pygame.draw.rect(screen, GREEN, rect, 1)

    for r in rects:
        if rect.colliderect(r):
            pygame.draw.rect(screen, RED, r, 2)
        else:
            pygame.draw.rect(screen, BLUE, r, 1)
    
    pygame.display.flip()

pygame.quit()

مستطیل های همپوش

متد rect.colliderect (r) بررسی می کند که آیا یک مستطیل با مستطیل دیگر برخورد می کند یا نه. اگر بخواهیم بدانیم که دو مستطیل با هم تداخل دارند، باید هر دو مستطیل را با یکدیگر مقایسه کنیم. تعداد مقایسه ها به طور توانی افزایش می یابد. هر بار که کلید R فشار داده می شود، 20 مستطیل تصادفی جدید ایجاد می شود.

from rect import *

n = 30
rects = random_rects(n)

while running:
    for event in pygame.event.get():
        if event.type == QUIT:
            running = False
        
        if event.type == KEYDOWN:
            if event.key == K_r:
                rects = random_rects(n)
   
    screen.fill(GRAY)

    intersecting = []
    for i in range(n-1):
        r0 = rects[i]
        for j in range(i+1, n):
            r1 = rects[j]
            if r0.colliderect(r1):
                intersecting.append(r0)
                intersecting.append(r1)
                break

    for i, r in enumerate(rects):
        color = RED if r in intersecting else BLUE
        pygame.draw.rect(screen, color, r)
        draw_text(str(i), r.topleft)
    
    pygame.display.flip()

pygame.quit()
تمام فصل‌های سری ترتیبی که روکسو برای مطالعه‌ی دروس سری بازی‌سازی با پایتون توصیه می‌کند:
نویسنده شوید

دیدگاه‌های شما

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