1
Programming Questions / Re: GM 8.1 to Studio: colliding with playerKiller inside solid block
« on: April 23, 2015, 09:35:06 PM »
Thanks for your reply.
You're looking at the frame where the collision event fires, right? I wouldn't expect a big difference in the time the event takes, but in my understanding, the step event fires every frame, whereas the collision event fires only when collision is detected.
I don't know the way this is implemented; I'm just going by hearsay around the Internet.
Side note:
I have tried transplanting the code from collision events to the End Step event, as you describe, but have had difficulty reproducing the correct behavior.
When I work on this tomorrow I'll post code to illustrate the changes I made in transplanting it; maybe then we can debug the resultant behavior.
UPDATE:
This is the (relevant) code I'm currently using in the player's End Step event. It more or less produces the desired behavior, but I'd rather find a more optimized, more exact refactor (more on this below).
As you can see, I'm deactivating block instances in a loop (storing them on a stack for reactivation after the loop) so that successive calls to instance_place return unique instances IDs.
I've left the events for collision with block and platform alone.
The above is almost a true refactor, but completely ignores collision with a playerKiller on the frame where the player intersects a solid block. The original code running in GM 8.1 wouldn't ignore collision on this frame - instead, the end step code was running after x & y were set to xprevious & yprevious and after the collision events were processed (i.e., after the solid block had pushed the player out and the player had been moved up against the edge of the solid, and appropriate speeds zeroed). I've tried reproducing this in the End Step event with no success thus far; this is an approach I continue to consider.
Another possibility I'm considering (and will try next) is to wrap the end step logic to the next frame by putting it in the Begin Step event. This would guarantee it come after the collision events of the prior step, with the (small) downside that the player's death will occur one frame later, which I expect will be difficult to discern; I'll give it a go and see if it adversely affects the engine in other ways.
UPDATE:
Moving the playerKiller End Step logic (as it originally existed) into the Begin Step event, surprisingly, did not prevent the player from being killed by a spike embedded within a wall.
I had expected it would fix the issue, albeit perhaps creating new ones, since it would rectify the relative order of the position update, the block collision processing, and the playerKiller collision check.
You're looking at the frame where the collision event fires, right? I wouldn't expect a big difference in the time the event takes, but in my understanding, the step event fires every frame, whereas the collision event fires only when collision is detected.
I don't know the way this is implemented; I'm just going by hearsay around the Internet.
Side note:
I have tried transplanting the code from collision events to the End Step event, as you describe, but have had difficulty reproducing the correct behavior.
When I work on this tomorrow I'll post code to illustrate the changes I made in transplanting it; maybe then we can debug the resultant behavior.
UPDATE:
This is the (relevant) code I'm currently using in the player's End Step event. It more or less produces the desired behavior, but I'd rather find a more optimized, more exact refactor (more on this below).
Code: [Select]
var blockInstance = instance_place(x, y, block);
var collidingWithSolid = false;
while (blockInstance != noone)
{
if (blockInstance.solid)
{
collidingWithSolid = true;
break;
}
ds_stack_push(reactivationStack, blockInstance);
instance_deactivate_object(blockInstance);
blockInstance = instance_place(x, y, block);
}
while (!ds_stack_empty(reactivationStack))
{
instance_activate_object(ds_stack_pop(reactivationStack));
}
if (!collidingWithSolid)
{
if (place_meeting(x,y,playerKiller))
{
killPlayer();
}
}
As you can see, I'm deactivating block instances in a loop (storing them on a stack for reactivation after the loop) so that successive calls to instance_place return unique instances IDs.
I've left the events for collision with block and platform alone.
The above is almost a true refactor, but completely ignores collision with a playerKiller on the frame where the player intersects a solid block. The original code running in GM 8.1 wouldn't ignore collision on this frame - instead, the end step code was running after x & y were set to xprevious & yprevious and after the collision events were processed (i.e., after the solid block had pushed the player out and the player had been moved up against the edge of the solid, and appropriate speeds zeroed). I've tried reproducing this in the End Step event with no success thus far; this is an approach I continue to consider.
Another possibility I'm considering (and will try next) is to wrap the end step logic to the next frame by putting it in the Begin Step event. This would guarantee it come after the collision events of the prior step, with the (small) downside that the player's death will occur one frame later, which I expect will be difficult to discern; I'll give it a go and see if it adversely affects the engine in other ways.
UPDATE:
Moving the playerKiller End Step logic (as it originally existed) into the Begin Step event, surprisingly, did not prevent the player from being killed by a spike embedded within a wall.
I had expected it would fix the issue, albeit perhaps creating new ones, since it would rectify the relative order of the position update, the block collision processing, and the playerKiller collision check.