ZIM BITS TUTORIAL

<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>ZIM BITS - Side Scroller Backing Animation Loop</title>

<!-- Welcome to ZIM at https://zimjs.com - Code Creativity!              	        -->
<!-- ZIM runs on the HTML Canvas powered by JavaScript and CreateJS https://createjs.com -->
<!-- Founded by Inventor Dan Zen - http://danzen.com - Canadian New Media Award Winner 	-->
<!-- ZIM is free to use. You can donate to help improve ZIM at http://zimjs.com/donate 	-->

<script src="https://zimjs.org/cdn/1.3.4/createjs.js"></script>
<script src="https://zimjs.org/cdn/01/zim_min.js"></script>
<!-- use zimjs.com/distill for minified individual functions! -->

<script src="https://zimjs.com/bits/footer10.js"></script><!-- you will not need this -->

<script>

// SCALING OPTIONS
// scaling can have values as follows with full being the default
// FIT	sets canvas and stage to dimensions and scales to fit inside window size
// FILL	sets canvas and stage to dimensions and scales to fit outside window size
// FULL	sets stage to window size with no scaling
// "tagID"	add canvas to HTML tag of ID - set to dimensions if provided - no scaling

const scaling = FIT; // this will resize to fit inside the screen dimensions
const width = 1000;
const height = 800;
const color = darker;
const outerColor = dark;
// 1. prepare a list of assets and a path
const assets = [
	"sceneForeground.png",
	"sceneRoad.png",
	"sceneBacking.png",
	"car.png"
];
const path = "assets/";
// 2. create a Waiter for the the asset loading
const waiter = new Waiter();

new Frame(scaling, width, height, color, outerColor, ready, assets, path, waiter);
function ready() {

	// given F (Frame), S (Stage), W (width), H (height)

	// ZIM BITS - Side Scroller Backing Animation Loop (2016 - updated 2022)

	// sidescrollers are fun! Flinstones @Hanna-Barbera in this case, I am sure!
	// Scroller is a background animator for horizontal or vertical scrolling
	// you can dynamically set the speed and direction but
	// the background is a long display object often a Bitmap
	// it needs to be seamless at the ends so wrapping is not noticed
	// the background gets automatically cloned and placed for looping
	// and needs to be longer than the direction you are going


	// STEPS
	// 1. prepare a list of assets and a path
	// 2. create a Waiter for the the asset loading
	// 3. optionally we can set up a shape for a mask of the Scroller
	// 4. create a container for all the objects being scrolled (optional)
	// 5. add the background pic to the stage and position or scale
	// 6. create a Scroller and set the background pic as the background
	// 7. optionally, make more than one scroller for a parallax effect
	// 8. make an object that is "moving" in the scene
	// 9.  we are going to make a CheckBox to handle masking or not
	// 10. we are going to make a slider to controll the speed of the Scrollers
	// 11. add sliders to Accelerator to control all at once with slider


	// 3. optionally we can set up a shape for a mask of the Scroller
	const rect = new Rectangle(500, 350, null, null, null, 50);

	// 4. create a container for all the objects being scrolled (optional)
	const animation = new Container(W, H).addTo()

	// 5. add the background pic to the stage and position or scale
	const backgroundPic = new Pic("sceneBacking.png")
		.sca(.5)
		.loc(0, 200, animation);

	// 6. create a Scroller and set the background pic as the background
	// gapFix just joins the seam together a little more when dynamically changing speed
	const background = new Scroller({backing:backgroundPic, speed:1, gapFix:1});

	// 7. optionally, make more than one scroller for a parallax effect
	const roadPic = new Pic("sceneRoad.png")
		.sca(.5)
		.loc(0, 200, animation);
	const road = new Scroller({backing:roadPic, speed:3.8, gapFix:1});

	// 8. make an object that is "moving" in the scene
	const car = new Pic("car.png")
		.sca(.5)
		.reg(100, 320)
		.center(animation)
		.mov(-80)
		.animate({props:{y:"2"}, time:.2, rewind:true, loop:true}) // note, relative y animation with quotes
		.tap(function() {
			car.animate({obj:{rotation:-30}, time:.4, rewind:true, rewindWait:.3, override: false});
		});

	const foregroundPic = new Pic("sceneForeground.png");
	foregroundPic // restart chain because need height of foregroundPic
		.sca(.5)
		.loc(0, roadPic.y + (roadPic.height-foregroundPic.height)+1, animation); // note heights now include scale
	const foreground = new Scroller({backing:foregroundPic, speed:4.3, gapFix:1});

	// 9.  we are going to make a CheckBox to handle masking or not
	const checkBox = new CheckBox({
		size:26,
		label:new Label("MASK", 24, null, "#999")
	})
		.center()
		.mov(-120, 200);
	let mask;
	checkBox.on("change", function() {
		if (checkBox.checked) {
			rect
				.center(S, 0)
				.mov(0, -20);
			const m = animation.setMask(rect);
		} else {
			animation.setMask(null);
			S.removeChild(rect);
		}
	});

	// 10. we are going to make a slider to controll the speed of the Scrollers
	const slider = new Slider({
		min:-20,
		max:300,
		barLength:200,
		button:new Button({
			width:25,
			height:25,
			backing:new Circle(13, green),
			rollBacking:new Circle(13, blue),
			label:""
		})
	});
	slider	// restart chain because need the slider height
		.loc(checkBox.x + 170, checkBox.y + slider.height/2);
	slider.currentValue = slider.max / 3;

	// 11. add sliders to Accelerator to control all at once with slider
	// the old way is down below, before there was an Accelerator
	const accelerator = new Accelerator([background, road, foreground]);
	slider.change(function () {
		accelerator.percentSpeed = slider.currentValue
	})

	// // 11. set ProportionDamp objects to convert the slider to the desired speed
	// // each Scroller is going at a different speed
	// // this is a pretty easy calculation but ProportionDamp removes the thinking ;-)
	//
	// // baseMin, baseMax, targetMin, targetMax, damp, factor, targetRound
	// // could have set to 0 or small positive amount but thought it might be fun to reverse
	// const backgroundPD = new ProportionDamp(slider.min, slider.max, -background.speed*.2, background.speed*3, .05);
	// const roadPD = new ProportionDamp(slider.min, slider.max, -road.speed*.2, road.speed*3, .05);
	// const foregroundPD = new ProportionDamp(slider.min, slider.max, -foreground.speed*.2, foreground.speed*3, .05);
	//
	// Ticker.add(function(){
	// 	background.speed = backgroundPD.convert(slider.currentValue);
	// 	road.speed = roadPD.convert(slider.currentValue);
	// 	foreground.speed = foregroundPD.convert(slider.currentValue);
	// });


	const title = "Scroller";
	new Label(title, 30, null, "#666")
		.pos(40, 40);

	const docItems = "Frame,Container,Circle,Rectangle,Label,Button,CheckBox,Waiter,Slider,tap,change,animate,cur,pos,mov,reg,sca,addTo,center,setMask,Scroller,Accelerator,ProportionDamp,zog,Ticker";
	makeFooter(S, W, H, null, docItems); // ZIM BITS footer - you will not need this

} // end of ready

</script>

<meta name="viewport" content="width=device-width, user-scalable=no" />

</head>

<body>
<!-- canvas with id="myCanvas" is made by zim Frame -->
</body>
</html>