Persistent collision detection for unused sprite
danielgholmes opened this issue · 2 comments
Hi,
I came across this issue after upgrading to Tilengine v2.8.4. I'm using the Python bindings, but it seems the issue is with Tilengine itself, I thought it would be best to post the issue here.
What I am finding is that collision detections seems to persist even for sprites that have been disabled. For example, in the game I am making, a projectiles sprites registers a collision with an enemy sprite, and the projectile sprite is subsequently disabled. Then when creating a new projectile using TLN_GetAvailableSprite
, it uses the previously disabled one for a new projectile. This is expected. But what I have found is that the collision detection on the original sprite persists, so that the new sprite immediately registers a collision and gets disabled.
The Python code below reproduces the issue:
from tilengine import *
HORIZONTAL_RES = 480
VERTICAL_RES = 270
NUMBER_OF_SPRITES = 5
class Enemy(object):
def __init__(self, x, y):
self.sprite = engine.sprites[0]
spriteset = Spriteset.fromfile("enemy")
self.sprite.setup(spriteset)
self.sprite.enable_collision(True)
self.sprite.set_position(x, y)
class Projectile(object):
def __init__(self, sprite_index):
self.sprite = engine.sprites[engine.get_available_sprite()] # reuses an available sprite
# self.sprite = engine.sprites[sprite_index] # always uses a new sprite
spriteset = Spriteset.fromfile("projectile")
self.sprite.setup(spriteset)
self.sprite.enable_collision(True)
print(self.sprite, self.sprite.check_collision())
self.x = 100
self.sprite.set_position(self.x, 100)
def setup_layer(layer, name):
tilemap = Tilemap.fromfile(name)
layer.setup(tilemap)
engine.set_background_color(tilemap)
engine = Engine.create(HORIZONTAL_RES, VERTICAL_RES, 0, NUMBER_OF_SPRITES, 0)
engine.set_load_path("assets")
window = Window.create()
window.disable_crt_effect()
window.define_input_key(PLAYER1, Input.BUTTON4, 100) # move right
x = 0
projectiles = []
fire_delay = 50
sprite_index = 1
enemy = Enemy(300, 100)
while window.process():
if window.get_input(Input.RIGHT): # press and hold to fire
fire_delay -= 1
if fire_delay == 0:
projectiles.append(Projectile(sprite_index))
fire_delay = 50
sprite_index += 1
for projectile in list(projectiles):
if projectile.sprite.check_collision():
print('collision!')
projectile.sprite.disable()
projectiles.remove(projectile)
del projectile
else:
projectile.x += 1
projectile.sprite.set_position(projectile.x, 100)
If I use a separate sprite index variable so that a new index is used each time, there is no problem. Obviously this is not a suitable solution because sprite indices need to be reused. But I included it here to help illustrate the issue.
I have been able to reproduce the issue on macOS 10.15.6 and Ubuntu 20.04. I'm using the latest version of the Python bindings.
Please advise if I am missing something or if this is a genuine bug.
Hi! Thanks for the detailed report. It's a genuine bug, introduced after implementing active sprites as a linked list. Only active sprites get collision flag cleared at the beginning of each frame. So if you disable a sprite and reassign it in the same frame, it doesn't get its collision flag cleared. That's easy to fix.
Great! Thanks for your assistance!