Час 5 - релативно задавање координата и димензија¶
Померање објеката по екрану¶
Често цртеж који нацртамо није на одговарајућој позицији и желимо да га померимо. Прилагоди наредни пример тако да се сви објекти који сачињавају цртеж кућице помере за 100 пиксела на горе тако да цртеж кућице буде центриран (као када притиснеш дугме „Прикажи пример”).
Пре него што пређеш на решавање тог задатка, подсети се још једном каква је веза између промене положаја објеката и промене њихових координата тако што ћеш одговорити на наредна питања.
Q-40: Желимо да померимо цртеж који се састоји од неколико облика надесно за 100 пиксела. Означи тачна тврђења.
У складу са овим, промени координате тако да се кућица помери.
import pygame as pg
import pygamebg
(sirina, visina) = (300, 300) # otvaramo prozor
prozor = pygamebg.open_window(sirina, visina, "Помери објекте")
prozor.fill(pg.Color("white"))
pg.draw.rect(prozor, pg.Color("red"), (100, 200, 100, 100))
pg.draw.circle(prozor, pg.Color("blue"), (150, 250), 30)
pg.draw.circle(prozor, pg.Color("yellow"), (150, 250), 5)
pg.draw.polygon(prozor, pg.Color("green"), [(100, 200), (200, 200), (150, 150)])
# prikazujemo prozor i čekamo da ga korisnik isključi
pygamebg.wait_loop()
(pomeranje_objekata)
Дакле, померање објеката по екрану није тешко (своди се на увећавање или умањивање неких координата), међутим, да би се цео цртеж померио потребно је променити координате свих објеката који чине цртеж, што може бити мукотрпно ако се цртеж састоји од великог броја објеката.
Повећавање и смањивање објеката¶
Често цртеж желимо да прилагодимо тако што ћемо га скалирати (смањити или повећати). Ако желимо да нацртамо двоструко већи круг, потребно је навести двоструко већи полупречник, а ако је потребно нацртати двоструко већи правоугаоник, потребно је навести двоструко већи већу дужину и ширину. Испробај ово на следећем цртежу тако што ћеш смањити димензије правоугаоника на 50, а полупречник круга на 25.
import pygame as pg, pygamebg
(sirina, visina) = (300, 300) # otvaramo prozor
prozor = pygamebg.open_window(sirina, visina, "Центрирани правоугаоник и елипса")
prozor.fill(pg.Color("white"))
pg.draw.rect(prozor, pg.Color("red"), (100, 100, 100, 100))
pg.draw.circle(prozor, pg.Color("blue"), (150, 150), 50)
# prikazujemo prozor i čekamo da ga korisnik isključi
pygamebg.wait_loop()
(povecavanje_i_smanjivanje_objekata)
Као што видиш, објекти су се смањили, али круг више није уписан у правоугаоник и цртеж не изгледа више како би требало да изгледа (центар круга и горње лево теме правоугаоника су остали непромењени). Скалирање дужи и многоуглова је још теже, јер се у њима не користе димензије, већ само координате тачака.
Дакле, да бисмо смањили или повећали цртеж, потребно је да мењамо и димензије, али и координате које одређују положај објеката. Испробај шта би се десило када би сваки од бројева који се користе приликом цртања био помножен или подељен истим бројем.
Q-42: Сви бројеви који се односе на координате и на величине у једном цртежу су подељени са 2. Како ће тиме да се промени цртеж?
Множењем свих аргумената функција истим бројем, дакле, успешно скалирамо цртеж, међутим, цртеж уједно бива померен, што је понекад непожељно. Скалирање цртежа уз задржавање положаја генерално није једноставно учинити, међутим, у наставку ћемо видети како да цртеже направимо тако да их лако можемо и померати и скалираити.
Израчунавање координата у односу на главну тачку и димензију¶
У досадашњим примерима смо у функцијама за цртање координате задавали навођењем конкретних бројевних вредности (на пример, 100, 50, 20). За такве цртеже рећи ћемо да су задати коришћењем апсолутних координата. У наставку ћемо видети да је често и лакше и боље да се координате представљају променљивама и то тако да се све координате израчунавају само на основу координата једне карактеристичне тачке коју ћемо називати главна тачка или сидро (енгл. anchor) и на основу димензије цртежа. То ће нам омогућити да цео цртеж померамо само изменама координата главне тачке и да га скалирамо само променом димензије, али и да лако нацртамо више идентичних цртежа чији се положај и величина може разликовати. За такве цртеже рећи ћемо да су задати коришћењем релативних координата.
Слово М¶
Напиши програм који помоћу дужи исцртава слово M.
Приликом цртања слова А координате смо очитали са цртежа и директно унели у програм. Сада ћемо нацртати слово М. Да би дужи биле лепо поравнате, потребно је да две горње тачке буду на истој висини и да две доње тачке буду на истој висини, да су две леве тачке на истој ширини и да су две десне тачке на истој ширини и да је средња тачка по ширини тачно на средини између левих и десних тачака.

Ако мало боље проучимо положај 5 карактеристичних тачака можемо видети
да све оне користе само три могуће вредности координате x (на
пример, 50, 100 и 150) и само три могуће вредности координате
y (на пример, 50, 120 и 150). Ове вредности можемо представити
променљивама gore
, dole
, levo
, desno
, sredina_x
и
sredina_y
, које на почетку програма иницијализујемо (постављамо)
на одговарајуће вредности. Предност оваквог писања кода је у томе да
ако буде потребе да се промени положај или величина слова М можемо то
постићи изменом вредности променљивих којима су координате описане
(промена на једном месту). Прва усправна дуж која гради слово М
задата је координатама (levo, gore)
и (levo, dole)
. Права
паралелна овој дужи описана је координатама (desno, gore)
и
(desno, dole)
, а унутрашње дужи са (levo, gore)
, (sredina_x,
sredina_y)
и (desno, gore)
.
import pygame as pg
import pygamebg
(sirina, visina) = (200, 200) # otvaramo prozor
prozor = pygamebg.open_window(sirina, visina, "Слово М")
# bojimo pozadinu prozora u sivo
prozor.fill(pg.Color(???))
# debljina linije
debljina = 10
# horizontalne koordinate tačaka
levo = 50
sredina_x = 100
desno = 150
# vertikalne koordinate tačaka
gore = 50
sredina_y = 120
dole = 150
# leva vertikalna linija
pg.draw.line(prozor, pg.Color("white"), (???, ???), (???, ???), debljina)
# kosa linija
pg.draw.line(prozor, pg.Color("white"), (???, ???), (???, ???), debljina)
# kosa linija
pg.draw.line(prozor, pg.Color("white"), (???, ???), (???, ???), debljina)
# desna vertikalna linija
pg.draw.line(prozor, pg.Color("white"), (???, ???), (???, ???), debljina)
# prikazujemo prozor i čekamo da ga korisnik isključi
pygamebg.wait_loop()
(slovoM)
Можемо отићи и један корак даље и све координате израчунати само на основу положаја једне карактеристичне тачке цртежа и његове димензије. На пример, за карактеристичну тачку можемо узети тачку у средини, у којој се спајају две косе линије. Тако одабране карактеристичне тачке цртежа називају се сидра.
import pygame as pg
import pygamebg
(sirina, visina) = (200, 200) # otvaramo prozor
prozor = pygamebg.open_window(sirina, visina, "Слово М")
# bojimo pozadinu prozora u sivo
prozor.fill(pg.Color(???))
# debljina linije
debljina = 10
# sidro - tačka na kojoj se susreću kose linije
sredina_x = 100
sredina_y = 120
# dimenzija slova
dim = 100
# vertikalne koordinate tačaka
gore = sredina_y - 0.7 * dim
dole = sredina_y + 0.3 * dim
# horizontalne koordinate tačaka
levo = sredina_x - 0.5 * dim
desno = sredina_x + 0.5 * dim
# leva vertikalna linija
pg.draw.line(prozor, pg.Color("white"), (???, ???), (???, ???), debljina)
# kosa linija
pg.draw.line(prozor, pg.Color("white"), (???, ???), (???, ???), debljina)
# kosa linija
pg.draw.line(prozor, pg.Color("white"), (???, ???), (???, ???), debljina)
# desna vertikalna linija
pg.draw.line(prozor, pg.Color("white"), (???, ???), (???, ???), debljina)
# prikazujemo prozor i čekamo da ga korisnik isključi
pygamebg.wait_loop()
(slovoM_sve_relativno)
Сада вома једноставно можемо да променимо димензију и положај слова
М. Поиграј се мало са вредношћу променљивих dim
, sredina_x
и
sredina_y
и посматрај како се мења нацртано слово. Дакле, када је
цртеж нацртан релативно, у односу на неко сидро и димензију, он се
лако може померати по екрану и скалирати, само тако што му се промени
вредност сидра. Ово нам омогућава да цртање издвојимо у функцију која
као параметре прихвата координате сидра и димензију и тако можемо лако
нацртати неколико појављивања истог облика.
import pygame as pg
import pygamebg
(sirina, visina) = (200, 200) # otvaramo prozor
prozor = pygamebg.open_window(sirina, visina, "Слово М")
def slovo_M(x, y, dim):
# debljina linije
debljina = 5
# vertikalne koordinate tačaka
gore = y - 0.7 * dim
dole = y + 0.3 * dim
# horizontalne koordinate tačaka
levo = x - 0.5 * dim
desno = x + 0.5 * dim
# leva vertikalna linija
pg.draw.line(prozor, pg.Color("white"), (levo, gore), (levo, dole), debljina)
# kosa linija
pg.draw.line(prozor, pg.Color("white"), (levo, gore), (x, y), debljina)
# kosa linija
pg.draw.line(prozor, pg.Color("white"), (desno, gore), (x, y), debljina)
# desna vertikalna linija
pg.draw.line(prozor, pg.Color("white"), (desno, gore), (desno, dole), debljina)
# bojimo pozadinu prozora u sivo
prozor.fill(pg.Color("gray"))
# crtamo 3 slova M
slovo_M(50, 100, 50)
slovo_M(110, 100, 40)
slovo_M(160, 100, 30)
# prikazujemo prozor i čekamo da ga korisnik isključi
pygamebg.wait_loop()
(slovoM_sve_relativno_funkcija)
Облак¶
Круговима можемо нацртати и неке занимљиве облике. Нацртајмо сунце и облак на плавом небу.
Облак
# bojimo pozadinu u plavo
prozor.fill(pg.Color("skyblue"))
# crtamo sunce
pg.draw.circle(prozor, pg.Color("yellow"), (100, 100), 80)
# crtamo oblak od tri kruga
pg.draw.circle(prozor, pg.Color("white"), (200, 200), 80)
pg.draw.circle(prozor, pg.Color("white"), (120, 200), 50)
pg.draw.circle(prozor, pg.Color("white"), (280, 200), 50)
(oblak)
Данас се мало наоблачило. На основу претходног програма дефинисаћемо функцију која исцртава облак на задатој позицији, задате величине, у задатој нијанси сиве боје, а затим ћемо је неколико пута позвати да бисмо нацртали неколико облака.
Приметимо да смо облак нацртали помоћу три круга и да су координате и полупречници ових кругова задати апсолутно, помоћу конкретних бројева. Да бисмо омогућили цртање неколико облака различитог положаја и величине, потребно је да пређемо на релативно задате координате. Природно је да за сидро узмемо центар средишњег круга, а да за димензију облака узмемо његов полупречник. Из претходног примера се може видети да се полупречник мањих кругова добија множењем већег полупречника са 58. Такође, видимо да су центри тих кругова на истој висини као центар великог круга и да се налазе на кружници. Стога, ако претпоставимо да велики круг има центар у тачки (x,y) и да му је полупречник r, тада први мали круг има центар у тачки (x−r,y), а други у тачки (x+r,y) и оба имају полупречник 5r8.

На основу овога можемо једноставно дефинисати функцију која црта облак и затим је неколико пута позвати.
import pygame as pg
import pygamebg
(sirina, visina) = (400, 400) # otvaramo prozor
prozor = pygamebg.open_window(sirina, visina, "Облаци")
# bojimo pozadinu u plavo
prozor.fill(pg.Color("skyblue"))
# crtamo sunce
pg.draw.circle(prozor, pg.Color("yellow"), (100, 100), 80)
# procedura koja crta oblak na datoj poziciji, date velicine u datoj
# nijansi sive boje
def oblak(x, y, r, siva):
# nijansa sive boje
boja = [???, ???, ???]
# crtamo oblak od tri kruga
# centralni veliki krug oblaka
pg.draw.circle(???, ???, ???, ???)
# poluprecnik levog i desnog, manjeg kruga oblaka
r_malo = round(5 * r / 8)
# levi manji krug oblaka
pg.draw.circle(???, ???, ???, ???)
# desni manji krug oblaka
pg.draw.circle(???, ???, ???, ???)
# crtamo nekoliko oblika razlicite velicine i nijanse
oblak(240, 200, 40, 180)
oblak(270, 250, 50, 210)
oblak(230, 100, 50, 230)
oblak(80, 80, 30, 150)
oblak(110, 320, 60, 255)
# prikazujemo prozor i čekamo da ga korisnik isključi
pygamebg.wait_loop()
(oblaci)
Домаћи задатак - глава робота¶
Нацртај наранџасту главу робота квадратног облика, која има црне очи и уста правоугаоног облика.
Глава робота
prozor.fill(pg.Color("white"))
pg.draw.rect(prozor, pg.Color("orange"), (50, 50, 200, 200))
pg.draw.rect(prozor, pg.Color("black"), (90, 90, 40, 40))
pg.draw.rect(prozor, pg.Color("black"), (170, 90, 40, 40))
pg.draw.rect(prozor, pg.Color("black"), (110, 170, 80, 40))
(glava_robota)
Претходни програм приказује тражену главу робота. Желимо да глава буде центрирана унутар прозора. Такође, желимо да уста центрирамо хоризонтално унутар главе. Подсетимо се зато, за почетак, како то можемо нацртати правоугаоник ако су му познате координате центра (овај пут помоћу релативних координата).
Q-43: Знаш да желиш да нацрташ правоугаоник ширине a и висине b тако да му је центар у тачки cx и cy. Коју наредбу можеш да употребиш за то?
Прикажимо математичке операције којима смо израчунали све потребне координате када смо цртеж задавали у апсолутним координатама. Прозор је димензија 300 пута 300 пиксела, а глава робота 200 пута 200 пиксела. То значи да на маргине одлази по 50 пиксела и стога се горње лево теме главе робота налази у тачки са координатама (50,50). Можемо приметити да су ширина два ока и ширина размака око очију (размаци од ивице главе до очију и размак између очију) једнаки. Дакле, укупно 5 ширина ока тј. размака испуњава ширину главе робота, одакле следи да су и ширина ока и ширина размака око очију једнаке петини ширине главе, тј. 40 пиксела. Претпоставићемо да је то уједно и висина ока (јер су очи квадратног облика), као и димензија размака од горње ивице главе робота до горње ивице очију, тако да ће се горње лево теме левог ока налазити у тачки са координатама (90,90) (величина размака је додата на обе координате горњег левог темена главе), а горње лево теме десног ока налазити у тачки са координатама (170,90) (на координату x горњег левог темена левог ока која је једнака 90 додата је ширина ока од 40 пиксела и ширина размака између очију која је такође 40 пиксела). Претпоставићемо да су уста исте висине као и око, али двоструко шира од њега, да је размак од дна уста до дна главе исти као размак између врха главе и врха очију и да су уста хоризонтално центрирана. Пошто је вертикална средина екрана на линији са координатом x која је једнака 150, координате горњег левог темена уста су (110,170) (прва је добијена тако што је од координате x средине прозора одузета половина ширине уста, а друга је добијена тако што је од координате y дна уста одузета величина размака и висина уста).
Програм можемо прилагодити тако да се све координате аутоматски
рачунају на основу правила које смо применили у претходној рачуници,
на основу сидра (cx, cy)
постављеног у средиште прозора и на
основу димензије екрана. Тиме ћемо постићи да цео цртеж робота може
лако да мења величину и свој положај на екрану (величина ће зависити
само од димензије главе, а положај само од координата центра главе тј.
сидра које је за почетак постављено у центар прозора).

Допуни наредни програм, а затим мењај димензију главе и њен центар и посматрај како се мења слика на екрану.
import pygame as pg
import pygamebg
(sirina, visina) = (300, 300) # otvaramo prozor
prozor = pygamebg.open_window(sirina, visina, "Глава робота")
prozor.fill(pg.Color("white"))
# sidro je u centru ekrana
(cx, cy) = (sirina / 2, visina / 2)
# dimenzija glave robota je 200x200 piksela
glava_dim = 200
# gornje levo teme glave određujemo tako da je centar glave u tački (cx, cy)
glava_x = cx - glava_dim / 2
glava_y = ???
pg.draw.rect(prozor, pg.Color("orange"), (???, ???, glava_dim, glava_dim))
# relativna dimenzija oka u odnosu na dimenziju glave
oko_dim = glava_dim / 5
# dimenzija razmaka oko očiju i oko usta
razmak = glava_dim / 5
# gornje levo teme levog oka u odnosu na gornje levo teme glave
levo_oko_x = ???
levo_oko_y = ???
pg.draw.rect(prozor, pg.Color("black"), (levo_oko_x, levo_oko_y, ???, ???))
# gornje levo teme desnog oka u odnosu na gornje levo teme levog oka
desno_oko_x = ???
desno_oko_y = ???
pg.draw.rect(prozor, pg.Color("black"), (???, ???, oko_dim, oko_dim))
# dimenzije usta u odnosu na dimenziju oka
usta_visina = oko_dim
usta_sirina = 2 * oko_dim
# gornje levo teme usta u odnosu gornje levo teme glave
usta_x = ???
usta_y = glava_y + glava_dim - ???
pg.draw.rect(prozor, pg.Color("black"), (???, ???, ???, ???))
# prikazujemo prozor i čekamo da ga korisnik isključi
pygamebg.wait_loop()
(glava_robota_promenljive)
Домаћи задатак - Роботица Мица¶
Ако ти је претходни задатак био интересантан и желиш још мало да вежбаш рад са координатама, настави у истом духу и реши и наредни задатак.
Напиши програм који исцртава целу роботицу Мицу (као што је
приказано на слици). Tело (труп) јој је квадратног облика, центар
му се налази у центру екрана, а димензија му је задата променљивом
telo
. Остале димензије су већ задате у програму који треба да
допуниш, а ти треба да одредиш неке недостајуће координате.

import pygame as pg
import pygamebg
(sirina, visina) = (400, 400) # otvaramo prozor
prozor = pygamebg.open_window(sirina, visina, "Роботица Мица")
# definišemo boje koje cemo koristiti
SIVA = (250, 250, 250)
CRVENA = (255, 0, 0)
PLAVA = (0, 0, 255)
# debiljina linije
debljina = 3
prozor.fill(SIVA)
# koordinata sredine prozora
(cx, cy) = (sirina / 2, visina / 2)
# telo
telo = 120
telo_x = ???
telo_y = cy - telo / 2
pg.draw.rect(prozor, PLAVA, (telo_x, telo_y, telo, telo), debljina)
# haljina
haljina_x = telo_x
haljina_visina = telo / 8
haljina_y = ???
pg.draw.rect(prozor, CRVENA, (haljina_x, haljina_y, telo, haljina_visina))
# glava
glava = 3 * telo / 4
glava_x = ???
glava_y = ???
pg.draw.rect(prozor, PLAVA, (glava_x, glava_y, glava, glava), debljina)
# oci
oko = glava / 5
zenica = oko / 3
oko_y = ???
levo_oko_x = ???
desno_oko_x = cx + oko / 2
pg.draw.rect(prozor, CRVENA, (levo_oko_x, oko_y, oko, zenica), 1)
pg.draw.rect(prozor, CRVENA, (desno_oko_x, oko_y, oko, zenica), 1)
# zenice
pg.draw.rect(prozor, CRVENA, (levo_oko_x + zenica, oko_y, zenica, zenica))
pg.draw.rect(prozor, CRVENA, (desno_oko_x + zenica, oko_y, zenica, zenica))
# usta
usta_sirina = glava / 3
usta_visina = usta_sirina / 3
usta_y = ???
pg.draw.rect(prozor, CRVENA, (glava_x + usta_sirina, usta_y, usta_sirina, usta_visina))
# noge
noga_sirina = telo / 3
noga_duzina = noga_sirina * 3
leva_noga_x = ???
leva_noga_y = telo_y + telo
desna_noga_x = ???
desna_noga_y = ???
pg.draw.rect(prozor, PLAVA, (leva_noga_x, leva_noga_y, noga_sirina, noga_duzina), debljina)
pg.draw.rect(prozor, PLAVA, (desna_noga_x, desna_noga_y, noga_sirina, noga_duzina), debljina)
# ruke
ruka_sirina = telo / 6
ruka_duzina = ruka_sirina * 4
ruka_y = ???
leva_ruka_x = ???
desna_ruka_x = ???
pg.draw.rect(prozor, PLAVA, (leva_ruka_x, ruka_y, ruka_duzina, ruka_sirina), debljina)
pg.draw.rect(prozor, PLAVA, (desna_ruka_x, ruka_y, ruka_duzina, ruka_sirina), debljina)
# prikazujemo prozor i čekamo da ga korisnik isključi
pygamebg.wait_loop()
(robot)
Програм је могао бити можда мало једноставнији да смо наводили апсолутне координате (конкретне бројеве), међутим, чињеница да смо све координате рачунали на основу датих координата центра и величине тела робота нам омогућава да исти програмски кôд употребимо за цртање неколиико робота. Потребно је да цртање издвојимо у функцију, чији ће параметри бити центар и димензија тела робота.
import pygame as pg
import pygamebg
(sirina, visina) = (800, 400) # otvaramo prozor
prozor = pygamebg.open_window(sirina, visina, "Роботица Мица")
# definišemo boje koje cemo koristiti
SIVA = (250, 250, 250)
CRVENA = (255, 0, 0)
PLAVA = (0, 0, 255)
# debiljina linije
debljina = 3
prozor.fill(SIVA)
def robot(cx, cy, telo):
???
cy = visina // 2
robot(120, cy, 100)
robot(400, cy, 120)
robot(680, cy, 100)
# prikazujemo prozor i čekamo da ga korisnik isključi
pygamebg.wait_loop()
(roboti)