Проблема с пиксельным обнаружением столкновений в игре Kivy RunnerPython

Программы на Python
Ответить Пред. темаСлед. тема
Anonymous
 Проблема с пиксельным обнаружением столкновений в игре Kivy Runner

Сообщение Anonymous »

Я разрабатываю 2D-раннер с использованием Kivy и реализую точное по пикселям обнаружение столкновений. Я использовал свойство Keep_data = True, чтобы разрешить доступ к данным пикселей для моих спрайтов, и метод read_pixel() для проверки непрозрачных пикселей в перекрывающихся областях.
Проблема Описание:
  • Обнаружение столкновений работает нормально, когда передняя часть персонажа касается передней части монстра. Столкновение срабатывает только тогда, когда их непрозрачные пиксели перекрываются, что является ожидаемым поведением (как показано на изображении 1).
  • Однако, когда персонаж прыгает и приземляется на спину монстра, столкновение иногда срабатывает, даже если их пиксели на самом деле не соприкасаются, а именно тогда, когда соединительная рамка персонажа касается области пикселей монстра (как показано на изображении 2).
Изображение1
Изображение2
Обзор кода:
Вот соответствующая часть моего Класс CollisionMixin, который обеспечивает точное обнаружение столкновений:

Код: Выделить всё

class CollisionMixin:
def collide_widget(self, other):
# First, check if bounding boxes overlap
if not super().collide_widget(other):
return False

# Get the overlapping area between the bounding boxes
x1 = max(self.x, other.x)
y1 = max(self.y, other.y)
x2 = min(self.right, other.right)
y2 = min(self.top, other.top)

# Check pixel-perfect collision within the overlap
for y in range(int(y1), int(y2)):
for x in range(int(x1), int(x2)):
# Ensure that both widgets have non-transparent pixels at the same point
if self.pixel_collides_at(x, y) and other.pixel_collides_at(x, y):
return True
return False

def pixel_collides_at(self, x, y):
"""Check if the widget has a non-transparent pixel at (x, y)."""
if not super().collide_point(x, y):
return False

# Convert to local coordinates of the widget
x_local = int(x - self.x)
y_local = int(self.height - (y - self.y))

# Check if the pixel at (x_local, y_local) is non-transparent
try:
color = self._coreimage.read_pixel(x_local, y_local)
return color[3] >  0  # Check alpha channel for transparency
except:
return False
Вот фрагменты кода персонажа и монстра:

Код: Выделить всё

class Character(CollisionMixin, Image):
"""
some properties
"""

def __init__(self, **kwargs):
super(Character, self).__init__(**kwargs)
self.size_hint = (None, .18)
self.fit_mode = 'contain'
self.frame_index = 0
self.idle_frames = [f'assets/cat/idle/Idle_{i:02d}.png' for i in range(20)]
self.run_frames = [f'assets/cat/run/Run_{i:02d}.png' for i in range(30)]
self.jump_frames = [f'assets/cat/jump/Jump_{i:02d}.png' for i in range(20)]
self.source = self.idle_frames[0]
self.keep_data = True
self.current_animation = Clock.schedule_interval(self.update_idle_frame, 0.05)
self.ground_y = Window.height * 0.09

def start_running(self):
self.stop_current_animation()
self.current_animation = Clock.schedule_interval(self.update_running_frame, 0.029)

def stop_current_animation(self):
if self.current_animation:
self.current_animation.cancel()
self.frame_index = 0
self.current_animation = None

def update_running_frame(self, dt):
self.frame_index = (self.frame_index + 1) % len(self.run_frames)
self.source = self.run_frames[self.frame_index]

"""
Other functions for idle and jump movement, and jump logic
"""

class MonsterOne(CollisionMixin, Image):
"""
some properties
"""
def __init__(self, **kwargs):
super(MonsterOne, self).__init__(**kwargs)
self.size_hint = (None, .1)
self.fit_mode = 'contain'
self.frame_index = 0
self.walk_frames = [f'assets/monster1/Walk_{i:02d}.png' for i in range(20)]
self.source = self.walk_frames[0]
self.keep_data = True
self.current_animation = self.start_walking()

def start_walking(self):
self.stop_current_animation()
self.current_animation = Clock.schedule_interval(self.update_walk_frame, 0.05)

def stop_current_animation(self):
if self.current_animation:
self.current_animation.cancel()
self.frame_index = 0
self.current_animation = None

def update_walk_frame(self, dt):
self.frame_index = (self.frame_index + 1) % len(self.walk_frames)
self.source = self.walk_frames[self.frame_index]

"""
Function to handle movement
"""
Вот код функции, которая обновляет игру на GameScreen:

Код: Выделить всё

class GameScreen(Screen):
monsters = ListProperty([])
.
.
def __init__(self, **kwargs):
super(GameScreen, self).__init__(**kwargs)
self.update_event = None

def start(self):
.
.
.
self.update_event = Clock.schedule_interval(self.update, 1/60)

def update(self, dt):
# Logics for generating and moving monster

for monster in self.monsters:
# Check for pixel collision
if self.ids.character.collide_widget(monster):
print('Pixel-perfect collision detected!')
# Stop the current animation and movement for the character and the monster
self.ids.character.stop_current_animation()
monster.stop_current_animation()
Я пробовал:
Проверка ограничивающей рамки: Я проверил, что ограничивающая рамка Проверка рамок работает правильно — столкновение обнаруживается только тогда, когда ограничивающие рамки перекрываются.
Проверка столкновения пикселей: я использую read_pixel(), чтобы определить, есть ли не -прозрачные пиксели в области перекрытия. В большинстве случаев это работает, но, похоже, возникает проблема, когда персонаж приземляется на спину монстра.

Подробнее здесь: https://stackoverflow.com/questions/789 ... unner-game
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «Python»