Reading Time: 12 mins

Is your Scratch sprite moving in jerky steps instead of gliding smoothly? Youβre not alone! This comprehensive guide shows you exactly how to move sprites smoothly in Scratch using proven techniques that create professional-looking animations and responsive game controls.
Smooth movement in Scratch happens when sprites transition between positions without visible jumps or stutters. The secret isnβt just one techniqueβitβs understanding three key factors:
The smooth movement formula:
Why it matters: Smooth movement makes games feel professional, animations look polished, and interactive projects more engaging for players.
when [right arrow] key pressed
change x by (50)
Problem: Sprite teleports 50 pixels each key press
when green flag clicked
forever
if <key [right arrow] pressed?> then
change x by (5)
end
end
Why it works: Continuous checking + smaller steps = smooth motion
This is the most reliable method for smooth sprite movement in Scratch.
Step 1: Create the forever loop
when green flag clicked
forever
if <key [right arrow] pressed?> then
change x by (5)
end
if <key [left arrow] pressed?> then
change x by (-5)
end
if <key [up arrow] pressed?> then
change y by (5)
end
if <key [down arrow] pressed?> then
change y by (-5)
end
end
Why this works:
Pro tip: The forever loop runs approximately 30 times per second in Scratch, giving you naturally smooth updates.
The glide block creates automatic smooth movement between two points.
when green flag clicked
glide (2) secs to x: (200) y: (100)
Perfect for:
Limitations:
when this sprite clicked
glide (1) secs to x: (mouse x) y: (mouse y)
Use case: Click-to-move games where the sprite walks to where you click.
This creates momentum, acceleration, and decelerationβthe technique used in professional games.
Step 1: Create variables
x velocity (for horizontal movement)y velocity (for vertical movement)Step 2: Set initial values
when green flag clicked
set [x velocity] to (0)
set [y velocity] to (0)
when green flag clicked
forever
// Acceleration
if <key [right arrow] pressed?> then
change [x velocity] by (2)
end
if <key [left arrow] pressed?> then
change [x velocity] by (-2)
end
// Apply friction/deceleration
set [x velocity] to ((x velocity) * (0.8))
// Move the sprite
change x by (x velocity)
end
What each part does:
Result: Sprite builds up speed when you press keys and smoothly stops when releasedβjust like real physics!
Create reusable smooth movement code with custom blocks.
Step 1: Make a Block
key (text), speed (number)Step 2: Define the Block
define smooth move (key) (speed)
if <key (key) pressed?> then
if <(key) = [right]> then
change x by (speed)
end
if <(key) = [left]> then
change x by ((0) - (speed))
end
if <(key) = [up]> then
change y by (speed)
end
if <(key) = [down]> then
change y by ((0) - (speed))
end
end
Step 3: Use the Block
when green flag clicked
forever
smooth move [right] (5)
smooth move [left] (5)
smooth move [up] (5)
smooth move [down] (5)
end
Advantages:
Create movement that slows down as it approaches the destinationβperfect for realistic animations.
when green flag clicked
repeat until <(round (distance to [mouse-pointer])) = (0)>
point towards [mouse-pointer]
move ((distance to [mouse-pointer]) / (8)) steps
end
go to [mouse-pointer]
How it works:
Result: Sprite appears to βeaseβ into its destination rather than stopping abruptly.
Symptoms: Canβt control sprite, moves across screen instantly.
Solution: Reduce step size
// Too fast
change x by (20)
// Better
change x by (5)
// Even smoother
change x by (2)
Rule of thumb: Start with 3-5 pixels per step, adjust based on your game.
Symptoms: Visible βteleportingβ between positions.
Cause: Using key press events instead of forever loop.
Wrong way:
when [right arrow] key pressed
move (10) steps
Right way:
when green flag clicked
forever
if <key [right arrow] pressed?> then
move (10) steps
end
end
Why the difference: when key pressed waits for keyboard repeat delay. Forever loop checks continuously.
Symptoms: Moving diagonally (pressing two arrow keys) makes sprite move faster than horizontally/vertically.
Cause: Adding both X and Y velocity without normalizing.
Solution: Limit maximum velocity
when green flag clicked
forever
// Movement input
if <key [right arrow] pressed?> then
change [x velocity] by (1)
end
if <key [up arrow] pressed?> then
change [y velocity] by (1)
end
// Limit speed
if <(x velocity) > [5]> then
set [x velocity] to (5)
end
if <(y velocity) > [5]> then
set [y velocity] to (5)
end
// Apply movement
change x by (x velocity)
change y by (y velocity)
// Friction
set [x velocity] to ((x velocity) * (0.9))
set [y velocity] to ((y velocity) * (0.9))
end
Symptoms: Delay between pressing key and sprite moving.
Causes:
glide for player control (blocks other code)wait blocksSolution: Use forever loop method
when green flag clicked
forever
// NO wait blocks here!
if <key [right arrow] pressed?> then
change x by (5)
end
end
Symptoms: Sprite flips upside down or rotates unexpectedly.
Cause: Using move block with wrong rotation style.
Solution: Set rotation style
when green flag clicked
set rotation style [left-right] // or [don't rotate]
forever
if <key [right arrow] pressed?> then
move (5) steps
end
end
Rotation styles:
Make your sprite walk, run, or animate while moving smoothly.
when green flag clicked
forever
if <key [right arrow] pressed?> then
change x by (5)
next costume
wait (0.1) seconds
end
end
Pro tip: Your sprite should have multiple costumes showing different walk/run frames.
when green flag clicked
set [animation timer] to (0)
forever
if <key [right arrow] pressed?> then
change x by (5)
change [animation timer] by (1)
if <(animation timer) > [5]> then
next costume
set [animation timer] to (0)
end
end
end
Why this works: Animation only updates every 5 frames, creating controlled walk cycle regardless of movement speed.
Features needed:
Code example:
when green flag clicked
set [y velocity] to (0)
set [x velocity] to (0)
forever
// Horizontal movement
if <key [right arrow] pressed?> then
change [x velocity] by (1)
end
if <key [left arrow] pressed?> then
change [x velocity] by (-1)
end
// Apply horizontal velocity
set [x velocity] to ((x velocity) * (0.8))
change x by (x velocity)
// Gravity
change [y velocity] by (-1)
change y by (y velocity)
// Ground collision (simplified)
if <touching [ground]?> then
set [y velocity] to (0)
// Allow jumping
if <key [space] pressed?> then
set [y velocity] to (15)
end
end
end
Features needed:
Code example:
when green flag clicked
forever
// Store old position
set [old x] to (x position)
set [old y] to (y position)
// Movement
if <key [right arrow] pressed?> then
change x by (4)
end
if <key [left arrow] pressed?> then
change x by (-4)
end
if <key [up arrow] pressed?> then
change y by (4)
end
if <key [down arrow] pressed?> then
change y by (-4)
end
// Collision response
if <touching [wall]?> then
go to x: (old x) y: (old y)
end
end
Features needed:
Code example:
when green flag clicked
set [speed] to (0)
set [direction] to (0)
forever
// Acceleration
if <key [up arrow] pressed?> then
change [speed] by (0.5)
end
if <key [down arrow] pressed?> then
change [speed] by (-0.5)
end
// Speed limits
if <(speed) > [10]> then
set [speed] to (10)
end
if <(speed) < [-5]> then
set [speed] to (-5)
end
// Steering (only when moving)
if <key [right arrow] pressed?> then
change [direction] by ((speed) / (2))
end
if <key [left arrow] pressed?> then
change [direction] by ((0) - ((speed) / (2)))
end
// Apply movement
point in direction (direction)
move (speed) steps
// Friction
set [speed] to ((speed) * (0.95))
end
Make sprites smoothly follow the mouse cursor.
when green flag clicked
forever
point towards [mouse-pointer]
move (5) steps
end
Problem: Sprite never stops, orbits around mouse.
when green flag clicked
forever
if <(distance to [mouse-pointer]) > [10]> then
point towards [mouse-pointer]
move ((distance to [mouse-pointer]) / (10)) steps
end
end
Why it works:
For custom blocks handling movement:
β
Enable "Run without screen refresh"
Why: Prevents screen flicker, increases performance.
Less efficient:
forever
// 20 different if statements checking everything
end
More efficient:
forever
check movement :: custom // Handle in custom block
check collisions :: custom // Separate custom block
end
// Create variable "move speed" set to 5
when green flag clicked
set [move speed] to (5)
forever
if <key [right arrow] pressed?> then
change x by (move speed)
end
end
Benefit: Easy to adjust speed in one place, experiment with values.
β Visual smoothness
β Responsiveness
β Control feel
β Technical performance
Donβt do this:
forever
if <key [right arrow] pressed?> then
move (5) steps
wait (0.1) seconds // DON'T!
end
end
Why: Creates choppy movement, introduces delay.
Donβt do this:
when [right arrow] key pressed
move (10) steps
Do this:
when green flag clicked
forever
if <key [right arrow] pressed?> then
move (10) steps
end
end
Donβt do this:
change x by (50) // Too much!
Do this:
change x by (5) // Smooth!
Rule: Keep steps between 2-10 pixels for most games.
Without friction:
if <key [right arrow] pressed?> then
change [x velocity] by (1)
end
change x by (x velocity)
// Sprite never stops!
With friction:
if <key [right arrow] pressed?> then
change [x velocity] by (1)
end
set [x velocity] to ((x velocity) * (0.8))
change x by (x velocity)
// Sprite gradually stops
Make the view follow the player smoothly (creates camera effect).
Requirements:
Player stays centered, background moves:
// Player sprite
when green flag clicked
forever
if <key [right arrow] pressed?> then
broadcast [scroll right]
end
if <key [left arrow] pressed?> then
broadcast [scroll left]
end
end
// Background sprite
when I receive [scroll right]
change x by (-5)
when I receive [scroll left]
change x by (5)
Result: Player appears to move through world as background scrolls.
Alternative control scheme for games.
when green flag clicked
forever
// Right (D key)
if <key [d] pressed?> then
change x by (5)
end
// Left (A key)
if <key [a] pressed?> then
change x by (-5)
end
// Up (W key)
if <key [w] pressed?> then
change y by (5)
end
// Down (S key)
if <key [s] pressed?> then
change y by (-5)
end
end
Why offer WASD: Many players prefer it, especially in action games.
Possible causes:
Solutions:
// Separate movement from heavy calculations
when green flag clicked
forever
handle movement :: custom
end
when green flag clicked
forever
check collisions :: custom
wait (0.1) seconds // Reduce collision check frequency
end
Problem: Smooth movement but no collision response.
Solution: Check collision AFTER movement, revert if touching
forever
set [old x] to (x position)
set [old y] to (y position)
// Movement code here
if <touching [wall]?> then
go to x: (old x) y: (old y)
end
end
Complete code for professional-feeling character movement.
// Variables needed:
// x velocity, y velocity, on ground
when green flag clicked
set [x velocity] to (0)
set [y velocity] to (0)
forever
// Horizontal input
if <key [right arrow] pressed?> then
change [x velocity] by (1)
end
if <key [left arrow] pressed?> then
change [x velocity] by (-1)
end
// Speed limit
if <(x velocity) > [8]> then
set [x velocity] to (8)
end
if <(x velocity) < [-8]> then
set [x velocity] to (-8)
end
// Apply horizontal movement
change x by (x velocity)
// Horizontal collision
if <touching [wall]?> then
change x by ((0) - (x velocity))
set [x velocity] to (0)
end
// Friction
set [x velocity] to ((x velocity) * (0.85))
// Gravity
change [y velocity] by (-1)
// Apply vertical movement
change y by (y velocity)
// Ground collision
if <touching [ground]?> then
set [y velocity] to (0)
set [on ground] to [true]
else
set [on ground] to [false]
end
// Jumping
if <<key [space] pressed?> and <(on ground) = [true]>> then
set [y velocity] to (12)
end
end
Features:
Essential principles:
The smooth movement formula:
Forever loop + Small steps + Velocity + Friction = Smooth movement
Common methods ranked:
Continue learning:
For young learners: At ItsMyBot, we teach these concepts through engaging, project-based courses designed for kids aged 5-15. Smooth movement is just the beginningβwe progress to advanced game mechanics, animations, and eventually text-based programming.
Now that you know how to move sprites smoothly, try building:
Beginner projects:
Intermediate projects:
Advanced projects:
Ready to master Scratch and beyond?
At ItsMyBot, we turn screen time into skill time through personalized, industry-level courses. From Scratch basics to Python, JavaScript, and roboticsβwe help kids aged 5-15 build real skills through hands-on creation.
π‘ More free tutorials: itsmybot.com/blog
π¨βπ©βπ§βπ¦ For parents: Track progress and stay involved every step of the way