Rect ва ҳаракат
Ин барои чӣ лозим аст
Ҳама чизе, ки дар бозӣ ҳаракат мекунад — бозингар, тир, платформа, душман, ҳатто тугмаи меню, — бо росткунҷа тасвир кардан қулай аст. Росткунҷа мавқеъ ва андоза дорад, онро кӯчонидан, санҷидани он ки аз экран баромадааст ё не ва бо дигаре бархӯрдааст ё не, осон аст. Дар pygame барои ин синфи pygame.Rect ҳаст.
Ҳаракат дар бозӣ «парвози» ҳамвор нест, балки ҳар кадр кӯчиши хурди координатаҳост. Дар ин мавзӯъ мебинем, ки Rect чӣ тавр сохта шудааст, чӣ тавр онро бо суръат ҳаракат додан, аз ҳудуди майдон набаровардан ва ҷаҳишро бо ҷозиба сохтан мумкин аст.
Қадами 1. Rect чист
pygame.Rect(x, y, w, h) — росткунҷа: кунҷи чапи боло (x, y), бар w ва баландӣ h. Худи он чизе намекашад — ин танҳо «қуттии ададҳо» аст, ки баъд ба pygame.draw.rect дода мешавад ё барои ҳисобҳо истифода мешавад.
import pygame
r = pygame.Rect(10, 20, 30, 40) # x, y, бар, баландӣ
print(r.x, r.y, r.w, r.h)
print(r.right, r.bottom) # x + w, y + h
print(r.center, r.topleft)
Натиҷа:
10 20 30 40
40 60
(25, 40) (10, 20)
Диққат диҳед: right — ин x + w, яъне сутуни аввал баъд аз росткунҷа. Худи росткунҷа сутунҳоро аз left то right - 1 ишғол мекунад.
Қадами 2. «Дастаҳо»-и росткунҷа
Rect бисёр нуқтаҳо ва тарафҳои номдор — «дастаҳо» дорад:
| Даста | Ин чист |
|---|---|
left, right |
тарафи чап ва рост (x ва x + w) |
top, bottom |
боло ва поён (y ва y + h) |
centerx, centery |
миёна аз рӯи x ва y |
center |
марказ (centerx, centery) |
topleft, bottomright, midbottom… |
кунҷҳо ва миёнаи тарафҳо |
width, height, size |
андозаҳо |
Онҳоро на танҳо хондан, балки таъин кардан ҳам мумкин аст. Он гоҳ росткунҷа пурра мекӯчад, андозааш бошад тағйир намеёбад:
import pygame
r = pygame.Rect(0, 0, 10, 20)
r.bottom = 100 # тарафи поён дар 100
print(r.y)
r.center = (50, 50) # марказ дар нуқтаи (50, 50)
print(r.topleft)
r.right = 0 # тарафи рост дар 0 — росткунҷа аз экран чаптар
print(r.x)
Натиҷа:
80
(45, 40)
-10
Ин аз ҳисоб кардани x ва y бо даст қулайтар аст: «ба замин гузоштан» — яъне тарафи поёнро таъин кардан, на ҳисоб кардани y тавассути баландӣ. Арифметикаи камтар — хатои камтар.
Координатаҳои Rect ададҳои бутун мебошанд: қисми касрӣ партофта мешавад.
import pygame
r = pygame.Rect(1.7, 2.9, 10, 10)
print(r.x, r.y)
Натиҷа:
1 2
Қадами 3. Ҳаракат — кӯчиш дар ҳар кадр
Агар ҳар кадр ба x як адади якхеларо илова кунем, объект баробар ҳаракат мекунад. Ин адад — суръат бо пиксел дар як кадр аст. Ҳангоми 60 кадр дар сония суръати 5 — ин 300 пиксел дар сония аст.
import pygame
r = pygame.Rect(0, 0, 10, 10)
for frame in range(4):
r.x += 5
print(r.x, end=" ")
Натиҷа:
5 10 15 20
Якбора аз рӯи ду тир бо методи move_ip(dx, dy) кӯчонидан мумкин аст. move(dx, dy) бошад росткунҷаи нави кӯчонидашударо бармегардонад ва кӯҳнаро намерасонад:
import pygame
r = pygame.Rect(10, 10, 5, 5)
r2 = r.move(3, -4) # нусха, r тағйир намеёбад
print(r.topleft, r2.topleft)
r.move_ip(3, -4) # худи r-ро кӯчонидан
print(r.topleft)
Натиҷа:
(10, 10) (13, 6)
(13, 6)
Охири _ip маънои in place — «дар ҷояш»-ро дорад. Ҷуфтҳои clamp / clamp_ip, inflate / inflate_ip низ ҳамин тавр сохта шудаанд. Хатои маъмул — r.move(3, -4) навиштан ва ҳайрон шудан, ки чизе накӯчид: натиҷа танҳо партофта шуд.
Қадами 4. Идора бо тирчаҳо
Дар даври бозӣ донистани он ки кадом тугмаҳо ҳозир пахш карда нигоҳ дошта шудаанд, қулай аст: pygame.key.get_pressed() маҷмӯи байрақчаҳоро бармегардонад, ки дар он ҳар тугма True ё False дорад. Агар байрақчаҳоро тарҳ кунем, самт ҳосил мешавад: 1, -1 ё 0.
right, left = True, False # гӯё танҳо тирчаи рост пахш шудааст
dx = (right - left) * 6
print(dx)
Натиҷа:
6
True - False 1 медиҳад, False - True -1 медиҳад, агар ҳар ду ё ҳеҷ кадом пахш нашуда бошад — 0. Ҳамин тавр як сатр чор if-ро иваз мекунад.
Қадами 5. Аз экран набаромадан
Майдон низ росткунҷа аст. Барои равзана онро screen.get_rect() медиҳад — ин Rect(0, 0, бар, баландӣ) аст. Rect барои сарҳадҳо методҳои тайёр дорад:
field.contains(r)—True, агарrпурра дар дохилиfieldбошад;r.clamp_ip(field)— агарrберун баромада бошад, онро ба дохил кӯчонида, ба канори наздиктарин часпонидан. Аз рӯи ҳар ду тир якбора, андоза тағйир намеёбад.
import pygame
field = pygame.Rect(0, 0, 100, 50)
r = pygame.Rect(90, -5, 20, 20) # аз рост ва боло баромадааст
print(field.contains(r))
r.clamp_ip(field)
print(r, field.contains(r))
Натиҷа:
False
<rect(80, 0, 20, 20)> True
Росткунҷа зич часпид: тарафи росташ дар 100, болояш дар 0. Ҳамин чизро бо даст тавассути max ва min навиштан бо хато осон аст: яке аз тирҳоро фаромӯш кардан, тарафи нодурустро муқоиса кардан ё ба як пиксел хато кардан.
Қадами 6. Суръат ва ҷозиба
Агар суръати объект доимӣ бошад, он баробар ҳаракат мекунад. Барои он ки ҳаракат табиӣ намояд — суръатгирӣ, суст шудан, афтидан, — суръат-ро дар тағйирёбандаи алоҳида нигоҳ медоранд ва онро ҳар кадр тағйир медиҳанд.
Ҷозиба — ин илова кардани доимӣ ба суръати амудӣ аст: ҳар кадр объект каме тезтар меафтад. Ҷаҳиш — танҳо суръати манфӣ аст (боло — ин кам шудани y). Минбаъд ҷозиба худаш баромаданро суст мекунад, қаҳрамонро дар нуқтаи болоӣ нигоҳ медорад ва ба поён бармегардонад.
y, vy = 100, -6 # ҷаҳиш: суръат ба боло
GRAVITY = 2
for frame in range(7):
vy += GRAVITY
y += vy
print(y, vy)
Натиҷа:
96 -4
94 -2
94 0
96 2
100 4
106 6
114 8
Дида мешавад, ки чӣ тавр баромадан суст мешавад, дар кадри сеюм суръат 0 мешавад (нуқтаи болоӣ), баъд объект торафт тезтар меафтад. Бе замин он бепоён ба поён мерафт.
Қадами 7. Замин
Барои он ки қаҳрамон дар замин истад, баъд аз кӯчиш месанҷанд, ки оё ӯ аз сатҳи замин поёнтар нарафтааст. Агар рафта бошад — ӯро маҳз ба замин бармегардонанд ва суръатро хомӯш мекунанд. Дар ин ҷо «дастаҳо»-и Rect ба кор меоянд: сатҳи заминро бо тарафи поёнии қаҳрамон муқоиса мекунанд, зеро маҳз бо пойҳо ӯ дар замин меистад.
import pygame
FLOOR = 50
box = pygame.Rect(0, 30, 10, 10)
print(box.bottom, box.bottom >= FLOOR)
box.y += 15
print(box.bottom, box.bottom >= FLOOR)
Натиҷа:
40 False
55 True
Баъд аз кӯчиши дуюм қуттӣ 5 пиксел «фурӯ рафт»: онро бояд тавре боло бардорем, ки поёнаш бо FLOOR мувофиқ ояд. Инчунин муҳим аст, ки функсияи физика хабар диҳад, ки оё қаҳрамон дар замин истодааст: ҷаҳидан танҳо аз замин мумкин аст, вагарна парвоз дар ҳаво ҳосил мешавад.
Қадами 8. Гузариш аз канор
Дар бозиҳои аркадӣ объекте, ки аз канори экран гузашт, аксар вақт аз тарафи дигар пайдо мешавад. Дар ин ҷо ду саволро ҳал кардан лозим:
- Кай гузаронидан — вақте ки объект танҳо ба канор расид ё вақте ки пурра пинҳон шуд?
- Ба куҷо гузоштан — тавре ки он аз тарафи дигар ҳамвор ба экран дарояд, на якбора пурра пайдо шавад?
Бубинем, ки тарафҳои росткунҷаи ҳаракаткунанда дар канори экрани бараш 100 чӣ тавр тағйир меёбанд:
import pygame
car = pygame.Rect(60, 0, 30, 10)
for frame in range(3):
car.x += 20
print(car.left, car.right)
Натиҷа:
80 110
100 130
120 150
Дар кадри аввал right аллакай аз 100 калонтар аст — мошин танҳо нисфан аз канор гузаштааст, қисми он ҳанӯз намоён аст. Вақте ки left ба 100 расид, мошин пурра пинҳон шуд. Кадом тарафро бо чӣ муқоиса кардан аз он вобаста аст, ки ба бозӣ чӣ лозим аст.
Дар дохил чӣ тавр кор мекунад
Rect ҳамагӣ чор адади бутунро нигоҳ медорад: x, y, w, h. Ҳамаи «дастаҳо»-и дигар аз онҳо дар ҳамон лаҳза ҳисоб карда мешаванд: right — ин x + w, centery — y + h // 2. Вақте ки шумо ба даста қимат медиҳед, pygame масъалаи баръаксро ҳал мекунад: масалан, барои r.bottom = 100 ӯ y = 100 - h мегузорад.
Ҳаракат бо суръат ва ҷозиба — симулятсияи қадам ба қадам аст: бозӣ формулаи траекторияро намедонад, ӯ танҳо ҳар кадр «суръат += шитоб, мавқеъ += суръат» мекунад. Физикаи қариб ҳамаи бозиҳо ҳамин тавр сохта шудааст.
Хатоҳои маъмул
1. move ба ҷои move_ip. r.move(5, 0) росткунҷаи навро бармегардонад, r бошад дар ҷояш мемонад. r.move_ip(5, 0) ё r = r.move(5, 0) лозим аст.
2. Ба ҷои bottom y таъин шуд. player.y = GROUND болои қаҳрамонро дар сатҳи замин мегузорад — ӯ ба тамоми баландии худ зери замин мемонад. Дастаи ҳамон тарафе лозим аст, ки ба замин мерасад.
3. Суръат ба сифр баробар карда нашуд. Қаҳрамонро ба замин гузоштанд, вале vy калон монд. Дар кадри навбатӣ ӯ боз «фурӯ меравад», ҷаҳиш бошад бо суръати аҷиб сар мешавад. Баъд аз фуруд суръатро хомӯш мекунанд.
4. Муқоисаи қатъӣ ё ғайриқатъӣ. > ва >= маҳз дар як ҳолат фарқ мекунанд — вақте ки объект дақиқ дар сарҳад меистад. Маҳз чунин ҳолатҳоро тестҳо месанҷанд. Фикр кунед, ки вақте тараф дақиқ дар канор аст, чӣ бояд рух диҳад.
5. Танҳо як тир маҳдуд карда шуд. Канори чап ва рост санҷида шуд, вале боло ва поён фаромӯш шуд — бозингар ба боло аз экран меравад. clamp_ip ҳар ду тирро якбора маҳдуд мекунад.
Варақаи ёддошт
| Чӣ | Код |
|---|---|
| сохтан | r = pygame.Rect(x, y, w, h) |
| тарафҳо | r.left, r.right (x + w), r.top, r.bottom (y + h) |
| марказ | r.center, r.centerx, r.centery |
| аз рӯи тараф гузоштан | r.bottom = 100, r.right = 0, r.center = (x, y) |
| худашро кӯчонидан | r.move_ip(dx, dy) ё r.x += dx |
| нусхаи кӯчонидашуда | r2 = r.move(dx, dy) |
| росткунҷаи равзана | field = screen.get_rect() |
| пурра дар дохил? | field.contains(r) |
| ба дохил даровардан | r.clamp_ip(field) |
| тугмаҳои пахшшуда | keys = pygame.key.get_pressed(), keys[pygame.K_LEFT] |
| ҷозиба | vy += GRAVITY, баъд r.y += vy |
| ҷаҳиш | vy = JUMP (адади манфӣ), танҳо аз замин |