ZIM BITS TUTORIAL

<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>ZIM BITS - Hit Tests (hitTest)</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 = dark; // or any HTML color such as "violet" or "#333333"
const outerColor = light;

new Frame(scaling, width, height, color, outerColor, ready);
function ready() {
	
	// given F (Frame), S (Stage), W (width), H (height)

	// ZIM BITS - Hit Tests (hitTest) (2016 - updated 2022)

	// CreateJS has a hitTest() method on display objects
	// that check if the object is hitting a point in the parent of the object
	// there needs to be some localToLocal work, etc. to help this out in a few cases
	// and often we want to check if objects are hitting each other - not just a point

	// ZIM provides a number of hitTests to expand CreateJS hitTest functionality
	// hitTestPoint() is the same as CreateJS hitTest() but always checks a global point
	// hitTestReg() checks to see if an object is hitting the registration point of another object
	// hitTestRect() checks to see if an object is hitting points around the bounding rect of another object
	// hitTestCircle() checks to see if an object is hitting points of a circle defined by the bounding rect of another object
	// hitTestPath() checks to see if a shape is hitting points along a Squiggle or Blob path
	// hitTestBounds() FAST - checks to see if two objects' bounding rects are hitting
	// hitTestCircles() FAST - checks to see if two circles are hitting
	// hitTestCirclesRect() FAST - checks to see if a circle is hitting a rectangle
	// hitTestGrid() FAST - checks to see if a point is hitting a grid area

	// the Rect and Circle also take a parameter of the number of points to check - the more the more processing
	// all the hitTests take into account rotation, scaling and nesting
	// use the Circle if one of your objects is a circle or approximates a circle
	// use the Rect if one of your objects is a rectangle
	// use the Bounds if both your objects are rectangles

	// STEPS - HIT TESTS

	// 1. create objects to apply hitTests to
	// 2. use a ZIM Ticker function - or CreateJS Ticker or pressmove / pressup event function, etc.
	// 3. inside the function do a conditional for the hitTest
	// 4. if testing hitting or not then can set a check variable to remember the state

	// this example has a couple moving rectangles (like cars)
	// that when hitting change color
	// they also move inside a mask - here is the rectangle for the mask
	const backing = new Rectangle(800, 550, grey)
		.pos(100, 100);

	// 1. create objects to apply hitTests to
	// here we make a circle that we can drag around and check hitTests
	const circle = new Circle(30, brown, green, 10)
		.loc(475, 450)
		.drag()
	// cache the circle for better performance
		.cache()
		.setMask(backing);

	const car1 = new Rectangle(200, 100, dark, blue, 15, 40)
		.centerReg()
		.loc(-100, 250)
		.animate({obj:{x:W+100}, time:9, ease:"linear", loop:true})
		.cache()
		.setMask(backing);


	const car2 = new Rectangle(100, 200, dark, pink, 15, 40)
		.centerReg()
		.loc(700, H+100)
		.animate({obj:{y:-100}, time:7, ease:"linear", loop:true})
		.cache()
		.setMask(backing);

	const triangle = new Triangle(60, 60, 60, orange, null, null, null, -10)
		.centerReg(S, 1)
		.loc(290, 325);


	// 2. use a ZIM Ticker function - or CreateJS Ticker or pressmove / pressup event function, etc.
	Ticker.add(function() {

		// 3. inside the function do a conditional for the hitTest
		if (car1.hitTestBounds(car2)) {
			if (!car1.hit) {
				// 4. if testing hitting or not then can set a check variable (hit) to remember the state
				// otherwise we would constantly be changing the color and updating the cache
				// now we only do this once per change
				// check variables can be confusing but are very important for logic
				// so make sure you get what we are doing here:
				// a. when we start, car1.hit is null so !car1.hit is true
				// b. we then know the car has just been hit so we record that
				// c. change whatever we need to change
				car1.hit = true; // we only need to keep track on one of the cars as they are hitting each other
				car1.color = purple;
				car1.updateCache();
				car2.color = purple;
				car2.updateCache();
			}
			// d. once the car1.hit is true, it will not repeat the changes made above
		} else {
			// e. if the cars are no longer we check to see if we still think they are
			// f. if we do think they are hitting then set car1.hit to false as we are no longer hitting
			// g. make the changes we need
			if (car1.hit) {
				car1.hit = false;
				car1.color = dark;
				car1.updateCache();
				car2.color = dark;
				car2.updateCache();
			}
			// h. when we are not hitting and have set the car1.hit to false we avoid duplicating the changes
			// i. so either d. and h. locations run constantly in the Ticker loop function
			// j. but cache is updated only when there is a change to the hitting status
			// k. we repeat this for all the other hitTests too
		}

		// 3. inside the function do a conditional for the hitTest
		if (triangle.hitTestRect(car1)) {
			// 4. if testing hitting or not then can set a check variable to remember the state
			if (!triangle.hit) {
				triangle.hit = true;
				triangle.animate({obj:{rotation:3*360}, time:4, call:function(){triangle.hit = false; triangle.rotation=0;}});
			}
		}

		// 3. inside the function do a conditional for the hitTest
		if (triangle.hitTestCircle(circle, 12)) {
			// 4. if testing hitting or not then can set a check variable to remember the state
			if (!circle.hit) {
				circle.hit = true;
				circle.color = purple;
				circle.updateCache();
			}
		} else {
			if (circle.hit) {
				circle.hit = false;
				circle.color = brown;
				circle.updateCache();
			}
		}
		if (car1.carry) circle.loc(car1);
		if (car2.carry) circle.loc(car2);

	});


	// the next hitTest happens only when we drop the circle
	// yet we will animate the circle if the circle has hit the center of either car
	// we use a check variable (carry) to indicate if we need to animate the circle
	// we could just add the circle to the car but it creates complications with dragging
	// when we drag the circle off the car, we would have to removeChild the circle from the car
	// and that messes up the drag unless we go through some hoops (See ZIM BITS Dragging Copy example)
	// so it is easier to just move the car in the Ticker function above if the carry check const is true
	// whenever we mousedown again on the circle we set the carry check const to false
	// then if in the pressup event function we hit the reg of a car, we set the carry check const to true
	circle.on("mousedown", function() {
		car1.carry = car2.carry = false;
	});

	circle.on("pressup", function() {
		// 3. inside the function do a conditional for the hitTest
		if (circle.hitTestReg(car1)) {
			// 4. if testing hitting or not then can set a check variable to remember the state
			car1.carry = true;
			S.addChildAt(circle, S.getChildIndex(car1)+1); // make sure circle goes under car2 as they cross
		}
		if (circle.hitTestReg(car2)) {
			car2.carry = true;
		}
	});



	const title = "HitTests - Bounds, Rect, Circle, Reg";
	new Label(title, 30, null, "#666")
		.pos(40, 40);

	const instruction = "Drag circle to center of a rectangle";
	new Label(instruction, 30, null, dark)
		.pos(140, 570);


	const docItems = "Frame,Circle,Rectangle,Triangle,Label,drag,hitTestPoint,hitTestReg,hitTestRect,hitTestCircle,hitTestBounds,hitTestGrid,animate,pos,centerReg,setMask,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>