BUG REPORT: Dragged on IOS

Unless I'm doing something wrong, I think this is a bug...

Emulator, Windows 10, Chrome
IOS Emulator, iPhone 13max

PROBLEM:

Two different ImageSprites have a DRAGGED procedure written where currentX and currentY are used to update the positions of the ImageSprites. When run in the emulator, both ImageSprites move independently. When run on IOS, dragging on either ImageSprite causes both to use the SAME currentX and currentY and merge together.

CODE USED:
image

BUG ON IOS CANVAS BY MOVING ONLY ONE IMAGESPRITE:

BEFORE: (image sprites in original positions)
image

AFTER: (dragging either one causes their positions to "merge")
image

1 Like

I have never used iOS, but I notice this looks like Sprite Cannibalism.

Maybe the sprites overlap in one platform, but not the other, due to different screen sizes or sprite placement.

The general way you eliminate Sprite Cannibalism is by adding a global variable DraggedSprite, initially blank text.

When TouchUp anywhere, set DraggedSprite to empty text.

When TouchDown on any Sprite you might want to drag,
   if global DraggedSprite is blank then
       set global DraggedSprite  to the component block of the Sprite that had the TouchDown
   else
       ignore the TouchDown

When Dragged on any Sprite,
  if (the component block of the Sprite that had the Dragged event) = global DraggedSprite 
  then
     move that Sprite
  else
     ignore the drag event

3 Likes

Thanks ABG for that info.

Yea, I guess we could "if statement" around it, but I do believe it's a bug since it doesn't show up in the emulator or on Android. I will work with the student to "work around" it for now using your suggestion.

As an FYI, I believe this is a duplicate bug report of this post from May 2021:

>>The general way you eliminate Sprite Cannibalism is by adding a global variable DraggedSprite

Thanks again ABG for your sage advice. This is what I will be sharing with the student, using your suggestions, since it seems to work on iOS, Android, and the emulator:

Here is an excerpt from an old project written before generic drag events were available:

(I post it here because your sample code requires an if/then/else branch for every Sprite, which should not be necessary if you have lots of sprites and keep them in a list.)

Note: The swap at touch up is specific to the sample app, and is overkill for your application.

When P1.Dragged

P1_Dragged.PNG

Each of the 9 sprites has a Dragged event block. They all call the common procedure handle_drag, passing it that Sprite component, and the currentX and currentY of the drag event.

(This was written before generic Events became available - ABG)

handle_drag

handle_drag.png

This procedure contains code to avoid sprite cannibalism, where extra sprites try to follow your finger as you drag another sprite near them. The two tests handle that - a global true/false value dragging to indicate that we are in the middle of a drag operation, and a global variable dragged_sprite to hold the component that we decided to drag when we started a drag operation.

If this sprite is the currently dragged sprite, then we move it, with some adjustments so it doesn’t get obscured by our finger as it’s dragged.

If a drag operation starts while the dragging variable is false, then we handle it like it was a touchDown event, and call procedure handle_touchDown.

handle_touchDown

handle_touchDown.png

This procedure is called at the start of a drag sequence. We announce in the global dragging variable that a drag has started, and save the current sprite parameter in the global dragged_sprite. We also save the X and Y values of this sprite in the two globals dragged_start_X and dragged_start_Y, for the snapBack operation when we let go of the drag.

To show the dragged sprite better, we raise its Z value.

When P1.TouchUp

when_P1_touchUp.PNG

The drag operation ends when we release the dragged sprite, signalling a TouchUp event for that sprite. We pass the component to procedure handle_touchUp.

handle_TouchUp

handle_touchUp.png

This procedure also protects against sprite cannibalism in the surrounding IF/THEN test, to insure it will happen only for the currently dragged sprite, and only during a drag operation.

If the two tests are satisfied, it sets the global dragging variable false, and resets the Z of the sprite to 1. Since the drag might stop outside of any other sprite, or on the overlap of two sprites, we have to go through all the other sprites and check for overlap, using the procedure is_inside, collecting the result in local list landing_sprites. If there are no landing sprites, there’s nothing to swap, and nothing to save. We take the first landing sprite in the result list to settle any tie, and call swap_pictures to swap pictures with that sprite, and save_sprite_pictures to save the new picture order in TinyDB for any future load operation. Either way, we snap the dragged sprite back to its original position using routine snap_back.

is_inside

is_inside.png

This procedure tests if a dragged sprite is inside a target sprite, judging by the center of the dragged sprite and the four walls of the target sprite. That comes out to 2 tests by X, and 2 tests by Y.

1 Like

And from Scott Ferguson (2015)
https://groups.google.com/g/app-inventor-developers-library/c/iQpSbdyYfkA