What if writing a small game could prove that architecture can be both clean and alive?
Letโs revisit the classic Snake game โ but built with Clprolf,
a paradigm that turns clarity into a coding language.
๐ง 1. From OOP to Clarity-Oriented Programming
Clprolf isnโt a framework. Itโs a language layer + methodology
that builds architectural meaning into Java itself.
| Annotation | Role |
|---|---|
@Agent |
Domain logic |
@Worker |
Technical performer (I/O, UI, OS, rendering) |
When you read Clprolf code, you see intent, not just syntax.
โ๏ธ 2. The Architecture of the Snake Game
The game has five layers โ all explicit:
SnakeGameScene (Agent)
โโโ SnakeImpl (Agent)
โโโ FoodExpertImpl (Agent)
โโโ SnakeGameSceneRendererImpl (Worker)
โโโ SnakeWindowImpl (Agent)
โโโ SnakeGamePanelImpl (Agent, Swing-based UI component)
Each one knows exactly what it should know, and nothing more.
For instance, the FoodExpert agent handles food positions โ
but knows nothing about the UI, keyboard, or rendering:
@Agent
public class FoodExpertImpl implements FoodExpert {
private SnakeGameScene scene;
public void positionFood() {
Random random = new Random();
...
food.setType(random.nextBoolean() ? FoodType.APPLE : FoodType.ORANGE);
foodList.add(food);
}
}
Meanwhile, the Worker handles technical events and visual updates:
@Worker
public class SnakeGameSceneRendererImpl implements SnakeGameSceneRenderer {
private SnakeGameScene scene;
public SnakeGameSceneRendererImpl( SnakeGameScene scene) {
this.scene = scene;
EventQueue.invokeLater(this); // Executed in AWT thread
}
@Override
public void run() {
window = new SnakeWindowImpl(this); // creates and starts rendering
}
}
๐ 3. Understanding the Flow of Life โ The Snake Logic
The magic happens in SnakeImpl.
It shows how Clprolf models living behavior:
sliding, growing, interacting โ without spaghetti code.
protected void continueSliding() {
if (this.lastSlidingType == SlidingType.STOPPED) return;
SnakeLink newHeadLink = computeHeadLink(this.links.get(0));
checkCollisionsForNewHead(newHeadLink);
Food foodAtNewHeadPlace = this.scene.getFoodExpert().getFoodAt(newHeadLink.x, newHeadLink.y);
updateBodyForSliding(foodAtNewHeadPlace != null, newHeadLink);
}
Each call represents an intention (โcontinue slidingโ, โhandle foodโ, โgrow bodyโ).
The structure itself communicates meaning.
๐จ 4. Rendering Without Losing the Model
The UI never controls the game directly.
The window only refreshes every 20 ms โ
and triggers the next logic step inside the paint cycle.
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
drawSnakes(g);
drawFood(g);
// End of long actions โ one physics step every few frames
this.gameWindow.getReal().getScene().getSnake().endLongActions();
this.gameWindow.getReal().getScene().getSnake_two().endLongActions();
}
So the render loop and game loop are naturally synchronized โ
without custom game threads or complex scheduling.
๐ก 5. What We Learn from This Example
- You can build a complete game architecture without losing clarity.
- Workers act as true performers, keeping the domain clean.
- The render loop stays synchronous, transparent, and elegant.
The result? A Snake thatโs both fun and architecturally explicit.
๐ Conclusion
We did not just implement Snake. We made its responsibilities visible: the scene owns the game state, agents express domain behavior, and workers perform technical execution.
Top comments (0)