Slime Sprite:
Three Languages, One Algorithm
The same animated sprite — identical movement, identical breathing trick, identical boundary clamping — in JavaScript (p5.js), Java Processing, and Python Processing. Five concepts that cross language boundaries.
Five Concepts — Three Languages
These five ideas appear in all three sketches. The concept is the same in every language; only the mechanism the language provides to express it differs. Find each one in the code panels below.
All three versions poll key state every frame inside draw().
The mechanism each language provides differs significantly.
Java and Python fire keyPressed() / keyReleased()
events and maintain a snapshot set. The in operator in Python
replaces contains() in Java. Python uses discard()
instead of remove() so a missed release event never crashes.
JS and Java use PVector objects with .x and .y
fields and an add() method. Python uses plain floats — the library
support is absent, but the math is identical.
The braking mechanism is the same in all three: zero the velocity at the end of every frame so the slime stops the instant a key is released. The concept travels. The container is language-specific.
The 9-parameter image() is NOT identical across languages.
The destination parameters are the same; the source region parameters differ.
The fix is one extra line in Java and Python:
srcX2 = srcX + idle.height computes the bottom-right x.
Frame 0 (srcX=0) silently produces the same result either way, so this bug
only appears when the second frame is displayed — exactly the kind of
off-by-one that is very hard to spot.
Every magic number in the sketch is replaced with a named constant. The three languages express “this value should not change” with different mechanisms:
JS: const PLAYER_SIZE = 50 Java: final float PLAYER_SIZE = 50; Python: PLAYER_SIZE = 50.0 # ALL_CAPS convention
Java enforces immutability at compile time — the compiler rejects
any assignment to a final field. JavaScript’s
const prevents reassignment in the same scope. Python uses
UPPER_CASE as a signal to human readers; nothing prevents reassignment
in the runtime.
All three versions define a Player class with position, velocity,
a frame counter, and two methods: drawPlayer() and
update(). The lifecycle is identical: constructed once in
setup(), updated every frame in draw().
Java and Python are single-file sketches (the class lives at the bottom).
The JavaScript version separates the class into a companion
Player.js file — a design choice, not a requirement.
The two-frame animation is the central teaching concept of this project. The algorithm is completely identical across all three languages.
ANIM_SPEED = 0.05 → 40 steps to cycle ≈ 0.67 s floor(frame) / (int)frame / int(frame) srcX = idle.height * frameIndex (all three)
The frame counter advances every call to update()
regardless of whether a key is pressed, so the slime is always
alive at rest. The floor/truncate operation converts the smooth counter
to a 0-or-1 frame index that selects which half of the sprite sheet to crop.
This is the algorithm. It does not depend on the language.
All Three Sketches, Side by Side
Yellow paper = JavaScript (sketch.js) • Blue paper = Java (.pde, single file incl. Player class) • Green paper = Python (.py, single file incl. Player class). Each panel scrolls independently. Scroll to the bottom to see the Player class syntax in each language.
What’s the Same — and What’s Different
- JS / Java / Python: velocity math, braking, boundary checking, and the breathing trick counter are word-for-word identical in logic across all three languages.
-
constrain(): same function name and semantics in all three —
constrain(vel.x, -SPEED, SPEED) -
pushMatrix() / popMatrix() + scale(-1,1):
the left-facing mirror flip technique is identical in Java and Python;
JS uses
push() / pop()(which also saves style — a minor behavioral difference documented in the chat log). - colorMode(HSB, 360, 100, 100, 100): identical in all three. imageMode(CENTER): identical in all three.
-
Java only:
import java.util.HashSetrequired for the held-keys set.new PVector()for position/velocity. -
Python only:
global idle, back, bg, playerrequired insetup()when reassigning module-level variables. Plain floatspos_x/pos_y/vel_x/vel_yreplace PVector. - The 9-param image() surprise: p5.js uses offset + size for source crop; Java and Python use top-left + bottom-right corner. See Session 9 in the chat log for the full explanation.