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>