LoginLogin
Nintendo shutting down 3DS + Wii U online services, see our post

Sprite Dragging

Root / Programming Questions / [.]

WuulfCreated:
Could someone help me find out how to drag sprites on the touchscreen?, I already know how to do simple dragging, but I'm talking about how to drag the sprite from the point at which I touch the sprite, instead of the middle of said sprite?

Could someone help me find out how to drag sprites on the touchscreen?, I already know how to do simple dragging, but I'm talking about how to drag the sprite from the point at which I touch the sprite, instead of the middle of said sprite?
You wouldn't need anything else, a single Sprite is like one coordinate.

I mean so im not always dragging the sprite from the direct middle

Or wherever the sprite's home is

I mean so im not always dragging the sprite from the direct middle
uhh last time I checked it doesn't matter, whether you do the middle or not.

A while ago I made some code to do this (with a technique stolen from kantackistan). Doesn't really account for rotation, etc. but it works well enough. Added a few a lot of comments, but feel free to ask questions if you need more info.
' Here's the demonstration...

ACLS

XSCREEN 3

' Sample scene. A bunch of random objects
' you can drag around.
DISPLAY 1
DRAG_CURSOR
FOR I%=0 TO 31
 J%=SPSET(I%)
 SPOFS J%,RND(304)+8,RND(224)+8
 SPHOME J%,8,8
 DRAG_ITEM J%
 SPSCALE J%,RND(3)+1,RND(3)+1
NEXT I%

WHILE 1
 VSYNC
 CALL SPRITE
WEND

' ...and here's the library portion.

' Makes a very small (1x1 px) sprite that functions
' as a cursor and stores sprite dragging state.
' Only call it once!
DEF DRAG_CURSOR
 ' I set the UV to 4, 4 but it doesn't really matter.
 VAR I%=SPSET(4,4,1,1,1)
 
 ' We aren't dragging any sprite yet.
 SPVAR I%,0,-1
 
 ' Make sure this sprite collides with draggable sprites.
 SPCOL I%,0,256
 
 ' Set the callback up.
 SPFUNC I%,"DRAG_CURSOR_SPR"
END

' Makes a sprite draggable.
DEF DRAG_ITEM ID%
 SPCOL ID%,1,256
END

' The callback for the cursor sprite.
' This should run every frame, via CALL SPRITE.
DEF DRAG_CURSOR_SPR
 VAR T%,X%,Y%
 TOUCH OUT T%,X%,Y%
 
 ' Move the cursor to where we are touching the screen.
 SPOFS CALLIDX,X%,Y%
 
 IF T% THEN
  ' If we are touching the screen...
  
  IF SPVAR(CALLIDX,0)>-1 THEN
   ' If we already are dragging a sprite, just
   ' move that sprite (var #0) by the offset (vars #1 and #2)
   SPOFS SPVAR(CALLIDX,0),X%+SPVAR(CALLIDX,1),Y%+SPVAR(CALLIDX,2)
  ELSE
   ' Otherwise, we need to look for if a sprite hit the cursor.
   
   ' Get what sprite the cursor hit.
   ' If it's -1, we didn't hit anything.
   VAR H%=SPHITSP(CALLIDX)
   
   ' If you just started touching the screen
   ' (as indicated by touch time (T%) being 1, the first frame)
   ' and you touched a sprite
   ' (as indicated by hit sprite (H%) being not -1)
   ' then store some info about it.
   IF T%==1 && H%>-1 THEN
    VAR OX%,OY%
    ' Before we move anything, where is the hit sprite?
    SPOFS H% OUT OX%,OY%
    ' And we can notify it that it's being dragged by setting its
    ' 7th variable to 1.
    SPVAR H%,7,1
    
    ' Also, store the ID of that sprite so we can use it later.
    SPVAR CALLIDX,0,H%
    
    ' Also, store the offset of the cursor vs. the hit sprite.
    SPVAR CALLIDX,1,OX%-X%:SPVAR CALLIDX,2,OY%-Y%
   ENDIF
  ENDIF
 ELSE
  ' If we aren't touching the screen
  ' but we still have a sprite stored,
  ' release the sprite.
  
  IF SPVAR(CALLIDX,0)>-1 THEN
   ' Let the other sprite know it's no longer being dragged.
   SPVAR SPVAR(CALLIDX,0),7,0
   
   ' And we don't need to know about the other sprite's ID anymore.
   SPVAR CALLIDX,0,-1
  ENDIF
 ENDIF
END

My god thanks sooo much, I'm trying to make a game similar to "Papers, Please" except more of a kind of endless mode game. I wanted to make moving the papers around look a bit better and somewhat easier.

I tried offsetting the point at which the sprite got moved to by the distance from the middle of the sprite to where I touched the sprite, but it barely worked. the closest I've gotten did not move correctly half the time.

How could I do this with a sprite bigger than 16x16?

Would this be possible with a sprite of custom size?

A while ago I made some code to do this (with a technique stolen from kantackistan). Doesn't really account for rotation, etc. but it works well enough. Added a few a lot of comments, but feel free to ask questions if you need more info.
show very messy code
' Here's the demonstration...

ACLS

XSCREEN 3

' Sample scene. A bunch of random objects
' you can drag around.
DISPLAY 1
DRAG_CURSOR
FOR I%=0 TO 31
 J%=SPSET(I%)
 SPOFS J%,RND(304)+8,RND(224)+8
 SPHOME J%,8,8
 DRAG_ITEM J%
 SPSCALE J%,RND(3)+1,RND(3)+1
NEXT I%

WHILE 1
 VSYNC
 CALL SPRITE
WEND

' ...and here's the library portion.

' Makes a very small (1x1 px) sprite that functions
' as a cursor and stores sprite dragging state.
' Only call it once!
DEF DRAG_CURSOR
 ' I set the UV to 4, 4 but it doesn't really matter.
 VAR I%=SPSET(4,4,1,1,1)
 
 ' We aren't dragging any sprite yet.
 SPVAR I%,0,-1
 
 ' Make sure this sprite collides with draggable sprites.
 SPCOL I%,0,256
 
 ' Set the callback up.
 SPFUNC I%,"DRAG_CURSOR_SPR"
END

' Makes a sprite draggable.
DEF DRAG_ITEM ID%
 SPCOL ID%,1,256
END

' The callback for the cursor sprite.
' This should run every frame, via CALL SPRITE.
DEF DRAG_CURSOR_SPR
 VAR T%,X%,Y%
 TOUCH OUT T%,X%,Y%
 
 ' Move the cursor to where we are touching the screen.
 SPOFS CALLIDX,X%,Y%
 
 IF T% THEN
  ' If we are touching the screen...
  
  IF SPVAR(CALLIDX,0)>-1 THEN
   ' If we already are dragging a sprite, just
   ' move that sprite (var #0) by the offset (vars #1 and #2)
   SPOFS SPVAR(CALLIDX,0),X%+SPVAR(CALLIDX,1),Y%+SPVAR(CALLIDX,2)
  ELSE
   ' Otherwise, we need to look for if a sprite hit the cursor.
   
   ' Get what sprite the cursor hit.
   ' If it's -1, we didn't hit anything.
   VAR H%=SPHITSP(CALLIDX)
   
   ' If you just started touching the screen
   ' (as indicated by touch time (T%) being 1, the first frame)
   ' and you touched a sprite
   ' (as indicated by hit sprite (H%) being not -1)
   ' then store some info about it.
   IF T%==1 && H%>-1 THEN
    VAR OX%,OY%
    ' Before we move anything, where is the hit sprite?
    SPOFS H% OUT OX%,OY%
    ' And we can notify it that it's being dragged by setting its
    ' 7th variable to 1.
    SPVAR H%,7,1
    
    ' Also, store the ID of that sprite so we can use it later.
    SPVAR CALLIDX,0,H%
    
    ' Also, store the offset of the cursor vs. the hit sprite.
    SPVAR CALLIDX,1,OX%-X%:SPVAR CALLIDX,2,OY%-Y%
   ENDIF
  ENDIF
 ELSE
  ' If we aren't touching the screen
  ' but we still have a sprite stored,
  ' release the sprite.
  
  IF SPVAR(CALLIDX,0)>-1 THEN
   ' Let the other sprite know it's no longer being dragged.
   SPVAR SPVAR(CALLIDX,0),7,0
   
   ' And we don't need to know about the other sprite's ID anymore.
   SPVAR CALLIDX,0,-1
  ENDIF
 ENDIF
END
It gives me a error in else var h%=sphitsp(callidx)

Do you know if dragging a sprite of a custom size like this is possible through possibly another method instead?

A while ago I made some code to do this (with a technique stolen from kantackistan).
Hey cool! Glad to see the technique caught on.
Do you know if dragging a sprite of a custom size like this is possible?
Yes, you should be able to drag any sprite of any size. When SPHITSP() is triggered between your draggable sprite and your cursor sprite, save the difference in position as two values, X and Y. That's how it will remember where exactly on the sprite you grabbed. If you want to cheat, you could also just SPLINK the draggable sprite to your cursor (and SPOFS it by -X, -Y) until the drag is finished, then unlink it.

Will using SPLINK look weird? if not then i may use that, whatever is easiest.

Will using SPLINK look weird?
No idea. Only one way to find out!

I was trying for a while to figure out how implement the difference correctly but I was never able to but I was finally able to I just need the difference to be defined once at the start of the drag but i had it defining it throughout the entire drag