Методы передвижения спрайта в библиотеке Arcade

Раздел: Игры -> Разработка игр

Работа с графической библиотекой Arcade в Python предоставляет простые инструменты для перемещения спрайтов на экране. Движение может управляться клавиатурой, мышью, автоматически или с помощью физического движка. В этой статье рассмотрены различные методы перемещения спрайта с подробными примерами кода и разбором типичных ошибок.

Основные способы перемещения спрайта

Как эффективно перемещать спрайт с помощью клавиатуры и дельты времени?

Наиболее распространённый способ – изменение координат спрайта в методе on_update() на основе нажатых клавиш и последующее обновление экрана в on_draw(). Для плавности движения используется умножение скорости на delta_time.


import arcade

SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
SPRITE_SPEED = 200

class MyGame(arcade.Window):
    def __init__(self):
        super().__init__(SCREEN_WIDTH, SCREEN_HEIGHT, 'Перемещение спрайта')
        self.player = arcade.Sprite(':resources:images/animated_characters/female_person/femalePerson_idle.png', scale=0.5)
        self.player.center_x = 400
        self.player.center_y = 300
        self.keys = set()

    def on_key_press(self, key, modifiers):
        self.keys.add(key)

    def on_key_release(self, key, modifiers):
        self.keys.discard(key)

    def on_update(self, delta_time):
        if arcade.key.LEFT in self.keys:
            self.player.center_x -= SPRITE_SPEED * delta_time
        if arcade.key.RIGHT in self.keys:
            self.player.center_x += SPRITE_SPEED * delta_time
        if arcade.key.UP in self.keys:
            self.player.center_y += SPRITE_SPEED * delta_time
        if arcade.key.DOWN in self.keys:
            self.player.center_y -= SPRITE_SPEED * delta_time

    def on_draw(self):
        self.clear()
        self.player.draw()

if __name__ == '__main__':
    window = MyGame()
    arcade.run()

Python с использованием библиотеки pygame (библиотека pygame в python)

Типичная ошибка: спрайт не двигается. Частая причина – забытый вызов arcade.run() или неверное имя ресурса изображения. Проверьте правильность пути к спрайту.

Проблема: спрайт движется рывками. Решение – использовать delta_time в расчётах скорости, как показано в примере. Без него движение зависит от частоты кадров.

Как перемещать спрайт к месту клика мыши?

Для перемещения спрайта по щелчку мыши можно обрабатывать событие on_mouse_press и задавать целевую точку. В on_update плавно двигаться к ней.


import arcade
import math

SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
MOVE_SPEED = 150

class Game(arcade.Window):
    def __init__(self):
        super().__init__(SCREEN_WIDTH, SCREEN_HEIGHT)
        self.player = arcade.Sprite(':resources:images/space_shooter/playerShip1_orange.png', 0.5)
        self.player.center_x = 400
        self.player.center_y = 300
        self.target_x = self.player.center_x
        self.target_y = self.player.center_y

    def on_mouse_press(self, x, y, button, modifiers):
        self.target_x = x
        self.target_y = y

    def on_update(self, delta_time):
        dx = self.target_x - self.player.center_x
        dy = self.target_y - self.player.center_y
        distance = math.hypot(dx, dy)
        if distance > 0:
            self.player.center_x += (dx / distance) * MOVE_SPEED * delta_time
            self.player.center_y += (dy / distance) * MOVE_SPEED * delta_time

    def on_draw(self):
        self.clear()
        self.player.draw()

Game()
arcade.run()

программы python игры (игры на python)

Проблема: спрайт не останавливается в точке клика, а продолжает дрожать. Это происходит из-за того, что при расстоянии меньше чем шаг, спрайт перескакивает цель. Решение – добавить условие остановки, когда расстояние меньше порога (например, 5 пикселей).

Как сделать автоматическое движение спрайта по кругу?

Используйте тригонометрические функции для расчёта координат на окружности.


import arcade
import math

class CircleMove(arcade.Window):
    def __init__(self):
        super().__init__(800, 600, 'Движение по кругу')
        self.player = arcade.Sprite(':resources:images/space_shooter/playerShip1_orange.png', 0.5)
        self.angle = 0
        self.radius = 200

    def on_update(self, delta_time):
        self.angle += 1 * delta_time  # 1 радиан в секунду
        self.player.center_x = 400 + self.radius * math.cos(self.angle)
        self.player.center_y = 300 + self.radius * math.sin(self.angle)

    def on_draw(self):
        self.clear()
        self.player.draw()

CircleMove()
arcade.run()

Ghjdthrf спрайта на экране arcade python (перемещение спрайта на экране с библиотекой arcade в python)

Как перемещать спрайт с помощью физического движка (PhysicsEngineSimple)?

Для учёта столкновений с препятствиями используйте arcade.PhysicsEngineSimple.


import arcade

class PhysGame(arcade.Window):
    def __init__(self):
        super().__init__(800, 600, 'Физика')
        self.player = arcade.Sprite(':resources:images/space_shooter/playerShip1_orange.png', 0.5)
        self.player.center_x = 100
        self.player.center_y = 100
        self.wall = arcade.Sprite(':resources:images/tiles/boxCrate_double.png', 0.5)
        self.wall.center_x = 400
        self.wall.center_y = 300
        self.physics = arcade.PhysicsEngineSimple(self.player, [self.wall])

    def on_key_press(self, key, modifiers):
        if key == arcade.key.LEFT:
            self.player.change_x = -200
        elif key == arcade.key.RIGHT:
            self.player.change_x = 200

    def on_key_release(self, key, modifiers):
        if key in (arcade.key.LEFT, arcade.key.RIGHT):
            self.player.change_x = 0

    def on_update(self, delta_time):
        self.physics.update()  # учитывает столкновения

    def on_draw(self):
        self.clear()
        self.player.draw()
        self.wall.draw()

PhysGame()
arcade.run()

Ошибка: спрайт проходит сквозь стены. Проверьте, что список препятствий передан верно, и что спрайты имеют корректные границы (self.player.collides_with_list можно использовать для отладки).

Плавное движение с ускорением и трением

В этом примере спрайт реагирует на клавиши не мгновенно, а набирает скорость постепенно, что делает управление более реалистичным.

Пример

import arcade

class AccelGame(arcade.Window):
    def __init__(self):
        super().__init__(800, 600)
        self.player = arcade.Sprite(':resources:images/space_shooter/playerShip1_orange.png', 0.5)
        self.player.center_x = 400
        self.player.center_y = 300
        self.velocity_x = 0
        self.velocity_y = 0
        self.acceleration = 400
        self.friction = 0.9

    def on_key_press(self, key, modifiers):
        if key == arcade.key.LEFT:
            self.velocity_x -= self.acceleration * 0.016
        elif key == arcade.key.RIGHT:
            self.velocity_x += self.acceleration * 0.016

    def on_key_release(self, key, modifiers):
        pass

    def on_update(self, delta_time):
        self.velocity_x *= self.friction
        self.velocity_y *= self.friction
        self.player.center_x += self.velocity_x * delta_time
        self.player.center_y += self.velocity_y * delta_time

Без ограничения скорости спрайт может разогнаться до бесконечности. Добавьте проверку: if abs(self.velocity_x) > MAX_SPEED: self.velocity_x = sign.

Перемещение по массиву точек (waypoints)

Спрайт последовательно переходит от одной заданной точки к другой, например, для патрулирования.

Пример

import arcade
import math

class WaypointMovement(arcade.Window):
    def __init__(self):
        super().__init__(800, 600)
        self.player = arcade.Sprite(':resources:images/space_shooter/playerShip1_orange.png', 0.5)
        self.waypoints = [(100,100), (700,100), (700,500), (100,500)]
        self.current_wp = 0
        self.speed = 150

    def on_update(self, delta_time):
        if self.current_wp >= len(self.waypoints):
            return
        wx, wy = self.waypoints[self.current_wp]
        dx = wx - self.player.center_x
        dy = wy - self.player.center_y
        dist = math.hypot(dx, dy)
        if dist < 5:
            self.current_wp += 1
        else:
            self.player.center_x += (dx / dist) * self.speed * delta_time
            self.player.center_y += (dy / dist) * self.speed * delta_time

Групповое движение спрайтов (мультипликация)

Одновременное перемещение нескольких спрайтов с одинаковым паттерном (например, враги в шеренге).

Пример

import arcade

class GroupMove(arcade.Window):
    def __init__(self):
        super().__init__(800, 600)
        self.enemies = arcade.SpriteList()
        for i in range(5):
            enemy = arcade.Sprite(':resources:images/space_shooter/playerShip1_orange.png', 0.3)
            enemy.center_x = 100 + i * 120
            enemy.center_y = 500
            self.enemies.append(enemy)
        self.direction = 1

    def on_update(self, delta_time):
        for enemy in self.enemies:
            enemy.center_x += 100 * delta_time * self.direction
        if self.enemies[0].center_x < 50 or self.enemies[-1].center_x > 750:
            self.direction *= -1

Движение по синусоиде (волнообразное)

Пример

import arcade
import math

class SinusoidalMove(arcade.Window):
    def __init__(self):
        super().__init__(800, 600)
        self.player = arcade.Sprite(':resources:images/space_shooter/playerShip1_orange.png', 0.5)
        self.player.center_x = 50
        self.player.center_y = 300
        self.time = 0

    def on_update(self, delta_time):
        self.time += delta_time
        self.player.center_x = 50 + self.time * 100
        self.player.center_y = 300 + 100 * math.sin(self.time * 2)

Перемещение спрайта с помощью геймпада

Библиотека Arcade поддерживает джойстики через arcade.get_joysticks().

Пример

import arcade

class JoystickMove(arcade.Window):
    def __init__(self):
        super().__init__(800, 600)
        self.player = arcade.Sprite(':resources:images/space_shooter/playerShip1_orange.png', 0.5)
        self.joystick = None
        joysticks = arcade.get_joysticks()
        if joysticks:
            self.joystick = joysticks[0]
            self.joystick.open()

    def on_update(self, delta_time):
        if self.joystick:
            x_axis = self.joystick.x
            y_axis = self.joystick.y
            self.player.center_x += x_axis * 200 * delta_time
            self.player.center_y += y_axis * 200 * delta_time

Ограничение движения в пределах экрана

Пример

    # В on_update:
    self.player.center_x = max(0, min(SCREEN_WIDTH, self.player.center_x))
    self.player.center_y = max(0, min(SCREEN_HEIGHT, self.player.center_y))

Результат: спрайт не выходит за границы окна.

Перемещение спрайта на экране с библиотекой Arcade в Python - comments

En
Ghjdthrf спрайта на экране arcade python (python)