Hi, I think that your problem can be modeled with a Finite State Machine. You may want to read up on them (
https://en.wikipedia.org/wiki/Finite_state_machine). Finite State Machines are used frequently in game development. In fact I think that Unity has a finite state machine editor they are so common. They are often used for enemy AI. A super simple one might be something like a traffic light that transitions from green to yellow to red and back to green again.
In this case it sounds like you have a state machine that travels around in a square of size 2n + 1 where n is an integer >= 0 and where n increases by one for every lap completed. In the example below I made a state machine that travels up then right then down then left (then up again). The tricky part is the up to right transition actually goes one step further than the rest and increases the "ring" size by one.
Please give it a look and let me know if you have any questions about the code or concepts. I tried to leave you a ton of comments to help.
OPTION STRICT
VAR SCREEN_W = 400, SCREEN_H = 240
VAR SPRITE_ID = 1076
VAR RING_SCALE = 16
VAR SPRITE_SPEED = 64
VAR SPRITE_DELAY = 0
VAR DELAY_MAX = 1000
VAR IDX_CENTER_X = 0
VAR IDX_CENTER_Y = 1
VAR IDX_STEPS_LEFT = 2
VAR IDX_STATE = 3
VAR IDX_RING = 4
VAR IDX_RING_COLOR = 5
VAR STATE_E = 0
VAR STATE_S = 1
VAR STATE_W = 2
VAR STATE_N = 3
VAR T1, T2, DT#
VAR GAME_OVER = FALSE, B
VAR SPID
ACLS
LOCATE 0, 0
COLOR #TWHITE, #TBLUE
PRINT "PRESS [B] TO EXIT";
COLOR #TWHITE, 0
T2 = MILLISEC - 8
WHILE GAME_OVER == FALSE
T1 = T2
T2 = MILLISEC
DT# = MAX(16, MIN(150, T2 - T1))
IF SPRITE_DELAY <= 0 THEN
SPID = NEW_SPIRAL_SPRITE(RND(SCREEN_W), RND(SCREEN_H), 100 + RND(1000), RGB(RND(256), RND(256), RND(256)))
SPRITE_DELAY = DELAY_MAX
ELSE
SPRITE_DELAY = SPRITE_DELAY - DT#
ENDIF
CALL SPRITE
B = BUTTON()
IF (B AND #B) != 0 THEN
GAME_OVER = TRUE
ENDIF
VSYNC
WEND
DEF NEW_SPIRAL_SPRITE(CENTER_X, CENTER_Y, STEPS_LEFT, TRAIL_COLOR)
VAR SP_ID
SPSET SPRITE_ID OUT SPID
IF SPID != -1 THEN
SPVAR SPID, IDX_CENTER_X, CENTER_X
SPVAR SPID, IDX_CENTER_Y, CENTER_Y
SPVAR SPID, IDX_STEPS_LEFT, STEPS_LEFT
SPVAR SPID, IDX_STATE, STATE_N
SPVAR SPID, IDX_RING, 0
SPVAR SPID, IDX_RING_COLOR, TRAIL_COLOR
SPFUNC SPID, "SPIRAL_SPRITE_UPDATE"
SPOFS SPID, CENTER_X, CENTER_Y
ENDIF
RETURN SPID
END
DEF SPIRAL_SPRITE_UPDATE
VAR X, Y, CENTER_X, CENTER_Y
VAR STEPS_LEFT, STATE, RING, RING_COLOR
VAR NEW_X, NEW_Y, NEW_STATE, RADIUS
VAR MOVEMENT
SPOFS CALLIDX OUT X, Y
CENTER_X = SPVAR(CALLIDX, IDX_CENTER_X)
CENTER_Y = SPVAR(CALLIDX, IDX_CENTER_Y)
STEPS_LEFT = SPVAR(CALLIDX, IDX_STEPS_LEFT)
STATE = SPVAR(CALLIDX, IDX_STATE)
RING = SPVAR(CALLIDX, IDX_RING)
RING_COLOR = SPVAR(CALLIDX, IDX_RING_COLOR)
MOVEMENT = MAX(((DT# * SPRITE_SPEED)/1000), 1)
NEW_STATE = STATE
RADIUS = RING * RING_SCALE
IF STATE == STATE_N THEN
NEW_X = CENTER_X - RADIUS
NEW_Y = Y - MOVEMENT
IF NEW_Y <= CENTER_Y - RADIUS - RING_SCALE THEN
NEW_Y = CENTER_Y - RADIUS - RING_SCALE
NEW_STATE = STATE_E
RING = RING + 1
ENDIF
GFILL NEW_X, NEW_Y, X + RING_SCALE, Y + RING_SCALE, RING_COLOR
ELSEIF STATE == STATE_E THEN
NEW_Y = CENTER_Y - RADIUS
NEW_X = X + MOVEMENT
IF NEW_X >= CENTER_X + RADIUS THEN
NEW_X = CENTER_X + RADIUS
NEW_STATE = STATE_S
ENDIF
GFILL X, Y, NEW_X + RING_SCALE, NEW_Y + RING_SCALE, RING_COLOR
ELSEIF STATE == STATE_S THEN
NEW_X = CENTER_X + RADIUS
NEW_Y = Y + MOVEMENT
IF NEW_Y >= CENTER_Y + RADIUS THEN
NEW_Y = CENTER_Y + RADIUS
NEW_STATE = STATE_W
ENDIF
GFILL X, Y, NEW_X + RING_SCALE, NEW_Y + RING_SCALE, RING_COLOR
ELSEIF STATE == STATE_W THEN
NEW_Y = CENTER_Y + RADIUS
NEW_X = X - MOVEMENT
IF NEW_X <= CENTER_X - RADIUS THEN
NEW_X = CENTER_X - RADIUS
NEW_STATE = STATE_N
ENDIF
GFILL NEW_X, NEW_Y, X + RING_SCALE, Y + RING_SCALE, RING_COLOR
ENDIF
SPOFS CALLIDX, NEW_X, NEW_Y
STEPS_LEFT = STEPS_LEFT - MOVEMENT
IF STEPS_LEFT <= 0 THEN
SPCLR CALLIDX
ELSE
SPVAR CALLIDX, IDX_STEPS_LEFT, STEPS_LEFT
SPVAR CALLIDX, IDX_STATE, NEW_STATE
SPVAR CALLIDX, IDX_RING, RING
ENDIF
END