Frog Dodgeball |
I used a class-based detection strategy similar to what I learned while using Crafty to make my entry for the GitHub Game Off 2015. Any element that should be checked for collisions with other objects should have the "collision" class applied to it. There isn't necessarily any special CSS associated with that class - it just has to be on the element. The element should also define a value for the field "collidesWith" that will be the name of another class. Only elements that have that class will be checked for collisions. I used a simple circle-based intersection formula for speed, so elements that can collide with other should define a value for the "collisionRadius" field as well. Finally, the elements should specify a function, hit, to be called if a collision is detected. The function will be passed an array of objects that are in collision.
Here is an example of how I set up the ball elements.
var ball = $('#ball'); var newBall = ball.clone()[0]; $(newBall).addClass("collision"); newBall.collisionRadius = $(newBall).width() / 2; newBall.collidesWith = "frog"; newBall.hit = handleHit;
All balls are clones of a master ball element (line 2). I add the "collision" class, set the radius, specify what kinds of elements with which the balls collide, and specify the function to call if there is a hit. Here is an example of the handleHit function:
function handleHit(elemArray) { $(this).removeClass("collision"); // this ball won't hit anything else // make the element hit (assumes only 1 in this case) // semi-transparent for half a second $(elemArray[0]).css("opacity", "0.5"); setTimeout(function() { $(elemArray[0]).css("opacity", "1"); }, 500); }
So that's the setup. But of course I had to add the collision-checking code to the comic framework. I already had a function that handled the animation, so I added a call to checkCollisions after each position update.
function checkCollisions() { $("img.collision").each(function(idx, elem) { if (elem.collidesWith) { var cx1 = Number($(elem).css('left').replace('px', '')); var ox1 = cx1 + ($(elem).width() / 2); var cy1 = Number($(elem).css('top').replace('px', '')); var oy1 = cy1 + ($(elem).height() / 2); var hits = []; $("img." + elem.collidesWith).each(function(idx2, elem2) { var cx2 = Number($(elem2).css('left').replace('px', '')); var ox2 = cx2 + ($(elem2).width() / 2); var cy2 = Number($(elem2).css('top').replace('px', '')); var oy2 = cy2 + ($(elem2).height() / 2); var distX = (ox2) - (ox1); var distY = (oy2) - (oy1); var magSq = distX * distX + distY * distY; if (magSq < (elem.collisionRadius + elem2.collisionRadius) * (elem.collisionRadius + elem2.collisionRadius)) { hits.push(elem2); } }); if (hits.length > 0 && elem.hit) { elem.hit(hits); } } }); }
My function iterates over all images that have the "collision" class. If those elements have a "collidesWith" defined, I get the X and Y coordinates for the center of the image. I'll need these for the collision check. Then I iterate over all the image elements that have the class specified by the "collidesWith" field and get their centers. The collision check starts on line 22. Basically, it makes two circles at the center-points of the images with the specified radii. A collision is detected if the circles overlap at all. If they do, I add that element to the hits array. At the end I call the hit function, passing the array, if there were any hits.
It all worked pretty well, and now I'll have it all ready for the next time I want to add a pointless game to a comic!
Amphibian.com comic for 22 April 2015 |
No comments:
Post a Comment