Drawing Multiple Sprites Of A Water Tank

Recently, I was pointed to a beautiful historical game for teaching simulation. It's a pipeline puzzle that also offers a way to evaluate the pressure in the pipeline depending on how the pipeline is connected.

Originally built in Smalltalk, it was recently ported to JavaScript. It works, but it stil had an issue: the tank icon always showed it was empty. That's because there were no sprites showing it filled in different stages.

We decided to remedy the situation using Glamorous Toolkit.

The challenge is to take this picture and draw multiple sprites with the tank with water inside. We start by loading the picture.

array := ZnClient new
	url: 'http://plumbin.ward.wiki.org/assets/pages/plumbin-in-wiki/tiles/tank.png'; get.
form := array readStreamDo: [:s | Form fromBinaryStream: s].
  

The first thing we need to do is to figure out where we should draw the blue square. So, we create a little tool based on BlDevCrossover BlEventListener subclass: #BlDevCrossover instanceVariableNames: 'crossover verticalLine horizontalLine topRightContainer mousePositionText targetElement' classVariableNames: '' package: 'Bloc-DevTool-Tools' to help us investigate. This is a decorator that can be added to any element and shows the position of the mouse within the bounds of the element:

element := form asElement.
BlDevCrossover on: element.
element asScalableElement
  

Once we know the coordinates, we an now try it. Ah, but how do we draw on a form? We first need a canvas. We know that the canvas can be instantiated by querying Bloc preferableSpartaCanvas. To learn how we draw on it, we can just search in the environment:

Ok, so we can use fill. Let's try it quickly:

canvas := Bloc preferableSpartaCanvas extent: 40@40.
form asElement drawMeWithEffectsOnCanvas: canvas.
canvas fill
	paint: Color blue;
	path: (7@6 corner: 33@32);
	draw.
canvas
  

Looks good. Now we can produce multiple canvases:

canvases := (6 to: 32) collect: [ :y |
	canvas := Bloc preferableSpartaCanvas extent: 40 @ 40.
	form asElement drawMeWithEffectsOnCanvas: canvas.
	canvas fill
		paint: Color blue;
		path: (7 @ y corner: 33 @ 32);
		draw.
	canvas ]
  

And now we can export them as PNGs:

canvases doWithIndex: [ :each :i | 
	PNGReadWriter
		putForm: each asForm
		onFileNamed: 'tank' , i asString , '.png' ].
'.' asFileReference
  

That's it. We started from a problem and we worked our way through it in the same uniform environment. Along the way, we constructed a custom tool to answer a question. We searched for similar examples. We prototyped and explored the results. All integrated.

This article is based on a Twitter thread I wrote recently.