I've made a small example of what I think it is you're after. Did my best to comment each piece and included the media I used. I'd set up things a little differently myself, but I didn't want to over-complicate the example. I actually wrote my own custom animation functions which provide a smoother feel, but that in itself is a whole other project.
// show all errors
SetErrorMode(2)
// set window properties
SetWindowTitle( "timfta" )
SetWindowSize( 1024, 768, 0 )
SetWindowAllowResize( 1 ) // allow the user to resize the window
// set display properties
SetVirtualResolution( 1024, 768 ) // doesn't have to match the window
SetOrientationAllowed( 1, 1, 1, 1 ) // allow both portrait and landscape on mobile devices
SetSyncRate( 30, 0 ) // 30fps instead of 60 to save battery
SetScissor( 0,0,0,0 ) // use the maximum available screen space, no black borders
UseNewDefaultFonts( 1 ) // since version 2.0.22 we can use nicer default fonts
loadimage(2,"ground.png")
// just some key constants
#CONSTANT VK_UP 38
#CONSTANT VK_DOWN 40
#CONSTANT VK_LEFT 37
#CONSTANT VK_RIGHT 39
#Constant TILE_SIZE 256 // tile sprite size
// Background tiles
// This example will use a single background image for all tiles.
// We hide it because we don't want to see this one, only the clones
// we'll make of it. (don't forget to unhide the clones!
Global _spr_ground
_spr_ground = createsprite(loadimage("ground.png"))
setSpriteVisible(_spr_ground, 0)
// Initialize an empty map
map as integer[0,0]
// Build our map.
// The map array is passed by reference so it can be altered.
// The other 4 parameters set the viewport dimensions which allows
// you to set the map to only a certain part of the screen.
buildMap(map, 200,200,824,568)
// map position
mapX = 0
mapY = 0
#CONSTANT ANI_WALK_RIGHT 1
#CONSTANT ANI_WALK_LEFT 2
#CONSTANT ANI_WALK_UP 3
#CONSTANT ANI_WALK_DOWN 4
Global _animations as integer[4,2]
// create the player
// source - https://opengameart.org/content/whispers-of-avalon-archer-sprite
spr_player = createsprite(loadimage("player.png"))
setSpriteAnimation(spr_player, 100, 100, 32)
setSpritePosition(spr_player, 462, 334)
_animations[ANI_WALK_RIGHT,1] = 17
_animations[ANI_WALK_RIGHT,2] = 23
_animations[ANI_WALK_LEFT,1] = 25
_animations[ANI_WALK_LEFT,2] = 31
_animations[ANI_WALK_UP,1] = 9
_animations[ANI_WALK_UP,2] = 15
_animations[ANI_WALK_DOWN,1] = 1
_animations[ANI_WALK_DOWN,2] = 7
lastDirection = 0
do
// A flag to only trigger if the player is moving, otherwise reset to 0
moving = 0
// arrow keys to move
if getRawKeyState(VK_RIGHT)
dec mapX, 3
if lastDirection <> VK_RIGHT then setPlayerAnimation(spr_player, ANI_WALK_RIGHT)
moving = 1
endif
if getRawKeyState(VK_LEFT)
inc mapX, 3
if lastDirection <> VK_LEFT then setPlayerAnimation(spr_player, ANI_WALK_LEFT)
moving = 1
endif
if getRawKeyState(VK_DOWN)
dec mapY, 3
if lastDirection <> VK_DOWN then setPlayerAnimation(spr_player, ANI_WALK_DOWN)
moving = 1
endif
if getRawKeyState(VK_UP)
inc mapY, 3
if lastDirection <> VK_UP then setPlayerAnimation(spr_player, ANI_WALK_UP)
moving = 1
endif
// keep track of what key we're pressing. We only want to change the animation if
// the direction changes, otherwise we'll be resetting the animation to the beginning
// of the sequence every frame and it won't animate.
lastDirection = GetRawLastKey()
// If player isn't moving, stop the animation.
// Also reset lastDirection flag. If you don't reset this flag, then the player won't
// resume animation if you stop then start again in the same direction.
if moving = 0
lastDirection = 0
stopSprite(spr_player)
endif
// reposition the map
positionMap(map, mapX, mapY)
// exit on escape key
if getRawKeyPressed(27) = 1 then quitGame()
Sync()
loop
function setPlayerAnimation(sprite, animation)
playSprite(sprite, 10, 1, _animations[animation,1], _animations[animation, 2])
endfunction
// Pass the map array containing the sprite IDs for the map tiles
// and the offset coordinates for the map position.
// Function will reposition all the map tiles.
function positionMap(map as integer[][], mx, my)
for x = 0 to map.length-1
for y = 0 to map[0].length-1
setSpritePosition(map[x,y], mx + x*256, my + y*256)
next y
next x
endfunction
// Build the initial map
// map is an array and passed by reference so it's size can be altered
function buildMap(map ref as integer[][], x1, y1, x2, y2)
// dimensions for this map. I use fixed numbers simply for example.
xCount = 8
yCount = 6
// Change the map array's size
map.length = xCount
for i = 0 to xCount-1
map[i].length = yCount
next i
// Clone the ground sprite for each tile in the map and position accordingly.
// This is also where we clip the sprite's view so it can't be drawn outside
// our viewport region. Only useful if you don't want your map extended to all
// edges of the screen.
for x = 0 to xCount-1
for y = 0 to yCount-1
map[x,y] = cloneSprite(_spr_ground)
setSpritePosition(map[x,y], x*256, y*256)
setSpriteVisible(map[x,y], 1)
setSpriteScissor(map[x,y], x1, y1, x2, y2)
next y
next x
endfunction
// Exits the game
// Calling a separate function allows you to perform other actions
// in an organized manner before ending the application.
function quitGame()
end
endfunction
"I like offending people, because I think people who get offended should be offended." - Linus Torvalds