Лекция · 5.4

Кейіпкерлерді анимациялау

Кейіпкер экранда тұр — енді оны ТІРІЛТЕЙІК! Қалай қозғалтамыз? Құпиясы қарапайым: ешнәрсе шын мәнінде «қозғалмайды». Мультфильм сияқты: суретші әр парақта кейіпкерді сәл басқа орынға салады, парақтарды жылдам парақтағанда — кейіпкер жүгіреді. Ойында да солай: әр кадрда координатаны аздап өзгертіп, экранды қайта саламыз. Бүгін кейіпкерді жүргіземіз, допты қабырғадан секіртеміз және барлық компьютерде бірдей жылдамдықты қамтамасыз етеміз.

Анимация принципі
Анықтама
Анимация — қозғалыс иллюзиясы: әр кадрда нысан координатасын аздап өзгертіп, экранды толық қайта салу.
x = 100
while running:
    ...
    x += 3                        # күй өзгерді
    screen.blit(fon, (0, 0))      # ескі кадрды фонмен «өшіру»
    screen.blit(hero, (x, 200))   # жаңа орынға салу
    pygame.display.update()

Назар аудар: фонды әр кадрда қайта салу МІНДЕТТІ — ол алдыңғы кадрдағы кейіпкерді «өшіреді». Фонсыз кейіпкер артында «із» қалдырып жүреді.

Нысанды «өшірудің» екі жолы бар: screen.fill(color) — бүкіл терезені фон түсімен толтырады (жоғарыдағы код осылай істейді); pygame.draw.rect(screen, color, [x, y, width, height], 0) — тек нысан тұрған тіктөртбұрышты аймақты ғана қайта бояйды, толық экранды қайта салмайды.

📒
Аналогия: дәптер бұрышына салынған мультфильм (флипбук): әр бетте доп сәл басқа жерде; беттерді тез парақтасаң — доп «ұшады». Ойын циклі — дәл сол парақтаушы, секундына 60 бет!
Жылдамдық және бағыт
Анықтама
Жылдамдық (speed) — бір кадрдағы жылжу шамасы, пикселмен: x += speed. Таңбасы — бағыт: оң speed — оңға, теріс — солға.
КодҚозғалыс
x += 5Оңға
x -= 5Солға
y += 5Төмен (Y төмен өседі!)
y -= 5Жоғары
x += 5 және y += 5Диагональ (оң-төмен)

speed мәні үлкен болса — қозғалыс жылдам, бірақ «секіргіш»; кіші болса — баяу әрі тегіс. Әдетте 2–8 пиксель/кадр қолайлы.

FPS және Clock
Анықтама
FPS (frames per second) — секундтағы кадр саны. pygame.time.Clock() — кадр жиілігін басқаратын «сағат»; циклдегі clock.tick(60) — «секундына 60 кадрдан асырма» дегені.
clock = pygame.time.Clock()   # циклден бұрын
while running:
    clock.tick(60)            # әр кадрда
    ...
⚠️
Неге маңызды: tick-сіз цикл компьютер қаншаға шамасы жетсе, сонша рет айналады: қуатты компьютерде кейіпкер «зымырап», әлсізде «еңбектеп» жүреді. clock.tick(60) ойын жылдамдығын БАРЛЫҚ құрылғыда бірдей етеді.

Кідірісті ұстаудың тағы бір жолы — pygame.time.delay(мс) (мысалы, pygame.time.delay(1000) — 1 секунд тоқтату): жақшадағы сан кіші болған сайын ойын жылдамырақ жаңарады. Бірақ ол кідірісті өзі есептемейді — сондықтан Clock ыңғайлырақ: секундына N кадрды автоматты түрде ұстап тұрады.

ФункцияҚызметі
pygame.display.flip()Бейнелі бетті толығымен жаңартады
pygame.display.update()Жадты үнемдеу үшін тек өзгерген бөлікті ғана жаңартады
Шекарадан серпілу

Доп экран шетінен шығып кетпеуі керек. Шешім: шетке жеткенде жылдамдықтың ТАҢБАСЫН аудару.

x, speed = 100, 5
while running:
    clock.tick(60)
    x += speed
    if x <= 0 or x >= 750:
        speed = -speed       # бағыт аударылды
    ...

Неге 750? Терезе ені 800, доп ені 50: доптың СОЛ жоғарғы бұрышы 750-ге жеткенде оң жақ шеті 800-ге тиеді. Шекара тексерісінде әрқашан нысанның ӨЛШЕМІН ескер!

🎾
Логика: speed = -speed — әмбебап трюк: 5 → −5 → 5... Доп оңға барады, қабырғаға тиеді, солға қайтады, тағы тиеді, тағы оңға. Мәңгілік пинг-понг — 3 жол код!

Серпілу екі бағытта да (X және Y) жүруі мүмкін — доп диагональ бойымен қозғалып, кез келген қабырғадан серпіледі:

speed = [3, 2]                 # [x_speed, y_speed]
ballrect = ball.get_rect()
while running:
    ballrect = ballrect.move(speed)
    if ballrect.left < 0 or ballrect.right > 800:
        speed[0] = -speed[0]        # X бағыты ауысты
    if ballrect.top < 0 or ballrect.bottom > 600:
        speed[1] = -speed[1]        # Y бағыты ауысты

ballrect.move(speed)Rect нысанын speed бойынша жылжытады; .left, .right, .top, .bottom — оның шеткі координаталары. Бұл тәсіл X және Y шекараларын БӨЛЕК тексереді, сондықтан доп бұрыштан да дұрыс серпіле алады.

Кадрлық анимация
Анықтама
Кадрлық анимация — жүру/ұшу эффектісі үшін бірнеше суретті кезектестіру: кадр-суреттер тізімде сақталып, кезекпен көрсетіледі.
kadrlar = [img1, img2, img3]   # 4-бөлімдегі ТІЗІМ!
nomer = 0
while running:
    ...
    nomer += 1
    kadr = kadrlar[nomer % len(kadrlar)]   # 0,1,2,0,1,2...
    screen.blit(kadr, (x, y))

Сиқырлы жол — nomer % len(kadrlar): қалдық 0, 1, 2, 0, 1, 2... болып айналады — тізім индексі ешқашан шегінен шықпайды. 4-бөлімдегі тізім білімі ойында осылай жұмыс істейді!

⚠️
Тек Атамұрада бар: кейіпкерді жеке класс ретінде де сипаттауға болады — pygame.sprite.Sprite класынан мұрагерлік арқылы (мысалы, Car класы). Бірнеше спрайтты pygame.sprite.Group() арқылы бір топқа біріктіріп, cars_list.draw(screen) командасымен бәрін бір мезгілде экранға шығаруға болады — көп кейіпкерлі ойындарда әрбірін жеке-жеке blit етудің орнына қолданылады.
🎯 ҰБТ байланысы
Анимация тақырыбының байланыстары:
1
Цикл + айнымалы өзгерісі: «n кадрдан кейін x неге тең?» — арифметикалық есеп.
2
% (қалдық) операторы — циклді индекстеу трюгі.
3
Күрделі шарттар (or) — шекара тексерісі.
Сабақ қорытындысы
  • Анимация = әр кадрда координата өзгерісі + толық қайта салу (фон ізді «өшіреді»).
  • speed — кадрдағы жылжу; таңбасы — бағыт; y += — төмен, y -= — жоғары.
  • clock.tick(60) — барлық компьютерде бірдей 60 FPS.
  • Серпілу: шетке жеткенде speed = -speed; нысан өлшемін ескер.
  • Кадрлық анимация: суреттер тізімі + nomer % len(kadrlar).