Subscribe to GameFromScratch on YouTube Support GameFromScratch on Patreon

12. December 2012

In our prior tutorial we looked at using an axis aligned bounding box to perform collision testing.  One big downside was the handling of sprite rotation.  Today, we will look at using a circle instead of a rectangle for our collision detection. The circle has the obvious advantage of being the same size no matter how much you rotate it.  It is also extremely fast to calculate and test for collisions.  Although as you can see from the application to the right, it isn't extremely accurate.

 

Just the Math

Calculating the bounding circle radius:

function getBoundingCircleRadius(sprite){

    return Math.sqrt(((sprite.image.width/2 * sprite.image.width/2)

            + (sprite.image.height/2 * sprite.image.height/2)));

 

}

 

Checking for an intersection between circles


function circlesIntersect(c1X,c1Y,c1Radius, c2X, c2Y, c2Radius){

    var distanceX = c2X - c1X;

    var distanceY = c2Y - c1Y;

 

    var magnitude = Math.sqrt(distanceX * distanceX + distanceY * distanceY);

    return magnitude < c1Radius + c2Radius;

}


 

 

Description

As mentioned earlier, a bounding circle removes the complexity of dealing with rotation.  This is a bit of a double edge sword though.  An axis aligned bounding box can be tighter and more accurate than a bounding circle, but as it rotates it quickly becomes less so.  The following application illustrates the same shape bounded by both a bounding box and a bounding circle.  As you can see, at some points the bounding box is a great deal more accurate, but as it rotates, it becomes a great deal less accurate:

 The calculations for the bounding circle are however a great deal easier to perform.  Let's take a look at them now.

Math.sqrt(((sprite.image.width/2 * sprite.image.width/2)

            + (sprite.image.height/2 * sprite.image.height/2)));

First we start off by calculating the radius of our sprite's image.  This is a matter of calculating the length of furthest point from the centre, giving us the smallest possible radius that encompasses our sprite.  The process is rather straight forward and is calculated using pythagorean theorem again.  We are essentially calculating the magnitude (or distance) from the centre of our sprite to the corner, we do this by forming a right angle triangle.

For a bit of a refresher on pythagorean theorem (which is used A LOT), consider this diagram I stole:

pythagorean theorem

 

a is the X coordinate of our corner, b is the Y coordinate of our corner, therefore the distance or magnitude ( the second is the correct term mathematically ) between those two points is c, which you can calculate by taking the square root of the square of a plus the square of b.  Or using our actual variable names, distance = square root( x * x + y * y).  The resulting value of this equation is the distance between x and y.  So, how did we come up with the values for x and y?  That part was simple, since our pivot is at the centre of our sprite, x is simply half the width of the image, while y is half the height.

If that just confused the hell out of you, the following diagram might help a bit.  It illustrates how pythagorean theorem is being applied to our actual jet sprite to calculate the distance to the corner.

DistanceToCorner

 

So, now we have the distance to the corner, which we can now use it as our circle's radius.  Now we need to figure out how to determine if an intersection occurs.

var distanceX = c2X - c1X;

var distanceY = c2Y - c1Y;

 

var magnitude = Math.sqrt(distanceX * distanceX + distanceY * distanceY);

return magnitude < c1Radius + c2Radius;

This again is a simple and quick equation.  Actually, its the exact same formula again, this time though, we calculate x and y by measuring the magnitude ( distance ) between each of our circles centre points.  Once we have calculate the magnitude between the two circles, we simply check to see if that distance value is less than the total radius of both circles.  If the magnitude is less than the radius of both circles combined, they intersect, otherwise they don't.

One thing you should be aware of ( but not too concerned with initially ) is the square root operation is an expensive one and generally something you want to avoid.  A square root is many times slower to perform than a multiplication or division.  In this situation, it is a very easy to eliminate, you simply square both sides, like so:

function circlesIntersect(c1X,c1Y,c1Radius, c2X, c2Y, c2Radius){

    var distanceX = c2X - c1X;

    var distanceY = c2Y - c1Y;     

    var magnitudeSquared = distanceX * distanceX + distanceY * distanceY;

    return magnitudeSquared < (c1Radius + c2Radius) * (c1Radius + c2Radius);

}

 

If you are still struggling with the math though, these kinds of optimizations can happen later if they are needed at all.  It's often easier to optimize after the fact anyways, so don't worry too much about being fast quite yet.  It's far too easy to get caught up optimizing prematurely.

 

Complete Code

<!DOCTYPE html>

<html>

<head>

    <script src="http://code.createjs.com/easeljs-0.5.0.min.js"></script>

    <script>

        var jetSprite,jetSprite2;

        var boundingCircle1, boundingCircle2;

        var actualBounds;

 

        var stage;

 

        document.addEventListener('DOMContentLoaded', demo,false);

 

 

        function getBoundingCircleRadius(sprite){

            return Math.sqrt(((sprite.image.width/2 * sprite.image.width/2)

                    + (sprite.image.height/2 * sprite.image.height/2)));

 

        }

 

        function createBoundingCircle(sprite,useMaxExtents){

            var g = new createjs.Graphics();

            g.setStrokeStyle(2);

            g.beginStroke(createjs.Graphics.getRGB(0,0,255));

            var radius = getBoundingCircleRadius(sprite);

            g.drawCircle(sprite.x,sprite.y,radius);

            return new createjs.Shape(g);

        }

 

        function circlesIntersect(c1X,c1Y,c1Radius, c2X, c2Y, c2Radius){

            var distanceX = c2X - c1X;

            var distanceY = c2Y - c1Y;

 

            var magnitude = Math.sqrt(distanceX * distanceX + distanceY * distanceY);

            return magnitude < c1Radius + c2Radius;

            // Note, sqrt is a slow operation, square both sides for better performance

            // var magnitudeSquared = distanceX * distanceX + distanceY * distanceY;

            // return magnitudeSquared < (c1Radius + c2Radius) * (c1Radius + c2Radius);

        }

 

        function demo(){

            stage = new createjs.Stage("theCanvas");

 

            jetSprite = new createjs.Bitmap("jetsprite.small.png");

            jetSprite.regX = 30; // Half image width

            jetSprite.regY = 40; // Half image height

            jetSprite.y = 200;

            jetSprite.x = 100;

 

            jetSprite.image.onload = function(){

                boundingCircle1 = createBoundingCircle(jetSprite);

                stage.addChild(boundingCircle1);

            }

 

            stage.addChild(jetSprite);

 

 

 

            jetSprite2 = new createjs.Bitmap("jetsprite.small.png");

            jetSprite2.regX = 30; // Half image width

            jetSprite2.regY = 40; // Half image height

            jetSprite2.y = 200;

            jetSprite2.x = 300;

 

            jetSprite2.image.onload = function(){

                boundingCircle2 = createBoundingCircle(jetSprite2);

                stage.addChild(boundingCircle2);

            }

 

 

            stage.addChild(jetSprite2);

 

            //And go...

            stage.update();

 

            // onFrame will be called each "tick". Default is 50ms, or 20FPS

            createjs.Ticker.addListener(onFrame);

        }

 

        function onFrame(elapsedTime) {

            jetSprite.x++;

            jetSprite.rotation = jetSprite.rotation+1;

            stage.removeChild(boundingCircle1);

            boundingCircle1 = createBoundingCircle(jetSprite);

 

            stage.addChild(boundingCircle1);

            stage.addChild(boundingCircle2);

 

            if(circlesIntersect(jetSprite.x, jetSprite.y, getBoundingCircleRadius(jetSprite),

                    jetSprite2.x, jetSprite2.y, getBoundingCircleRadius(jetSprite2)))

            {

                jetSprite.x = 100;

            }

 

            stage.update();

        }

    </script>

 

</head>

<body>

<canvaswidth=400height=400id="theCanvas"style="background-color:black"/>

</body>

</html>

 

 

See Also

See Collision Detection using an axis-aligned bounding box for details on bounding boxes.

 

If you are still struggling with the use of triangles, you really need to wrap your head around this concept.  This Youtube video ( with horrible audio ), gives a good example of pythagorean theorem in action:

 

 

Programming

10. December 2012

 

I don’t throw around words like ‘Nanny State’ often or lightly, but when it comes to epically stupid “think of the children” laws effecting video games I take notice.  This one is a whopper though.  When I think Nanny State… there are a few countries and companies I think of, Germany and Nintendo nearly topping both of those lists ( well.. and Australia…  they’ve mastered the art of stupid law making in the name of protecting children ).  When Germany and Nintendo combine, the results are some epic stupidity.

 

As of right now you can’t buy games online in Europe that have a PEGI 18 rating, unless it’s after 11PM and before 3AM.  So, if you want to buy Assassin's Creed or ZombieU online and aren’t a night owl, you can’t.

 

Here is a quote from Nintendo in response to Eurogamer:

“At Nintendo we always aim to provide a safe gaming experience for fans of all ages and ensure that we comply with applicable legal age restriction requirements across Europe,” a Nintendo spokesperson told Eurogamer.

“Legal age restriction requirements vary across a number of European countries. Since Nintendo of Europe is based in Germany, Nintendo eShop is complying with German youth protection regulation which therefore applies to all our European markets. Under German law, content rated 18+ must be made available only at night.

“Therefore the accessibility of 18+ content in Nintendo eShop is limited to [USK: 22:00 UTC until 4:00 UTC] [PEGI: 23:00 UTC until 3:00 UTC].”

 

So, Germany has a downright stupid child protection law on the books, and Nintendo Europe’s offices are based out of Germany, so they are applying the law TO ALL OF EUROPE.

 

So, Germany get’s the stupid prize for enacting a law that makes not a lick of sense.  It’s modeled in the mode of television restrictions where adult content can’t be played until a certain time window, which itself is completely ignorant of 10 years of progress in digital distribution rendering the entire concept archaic and mostly pointless.  Not to mention the fact… what are the demographic that are up between 11 and 3?  Outside the university crowd…  that’s basically insomniacs, people working nights and….  well, students under the age of 18!  Buying *ANY* content on the app store already requires users submit their age, making the entire scheme redundant anyways.  All you are doing is annoying your users.

 

Nintendo obviously takes their share of the blame here.  They have a history of stupidity when it comes to online, "protecting” users behind those god awful friend codes being the most glaring example.  This just seems to be another example of them being pretty out of touch with online reality.  Now it may be a legal requirement due to their office location, but this doesn’t absolve them of responsibility.  First off, basing your European operations out of the most legally anti-video game country in Europe is a downright stupid decision to start with.  The fact they can’t seem to work their way around a problem that EVERY other online retailer solved years ago… well, that’s 100% on Nintendo.  It would take their lawyers about 20 minutes to spin the eStore European division off as a subsidiary and open an unmanned office in a more legally friendly country.  Instead they took the lazy and downright stupid approach of applying this bad restriction to all of their customers.

 

I imagine in time common sense will prevail… at least, I certainly hope it does.

 

This post isn’t as off topic as it might seem.  These kind of legal hassles, especially as it applies to digital distribution, should be of concern to all indie game developers.  When or if you register your company, you should be exceptionally mindful of your host countries laws and how they can impact your legal rights and liabilities.

Totally Off Topic, News ,

9. December 2012

 

Things have been ultra quite on the Unity book front, perhaps the market was over saturated with books.  Today however I have added the first new book in a couple months and the first book covering Unity 4, Beginning 3D Game Development with Unity 4 by Sue Blackman.  If that author or book title sound familiar, they should, Sue already released the book Beginning 3D Game Development with Unity, the very first book on the list.

 

Now the catch… the book’s release date isn’t until March.   All the same, it’s nice to see some Unity 4 books starting to show up on the radar.

 

As of right now, I don’t have Table of Contents information to share, but the following is the book description from the publishers website.

 

Beginning 3D Game Development with Unity is perfect for those who would like to come to grips with programming Unity. You may be an artist who has learned 3D tools such as 3ds Max, Maya, or Cinema 4D, or you may come from 2D tools such as Photoshop and Illustrator. On the other hand, you may justBeginning 3d Game Development With Unity: All-in-one, Mult-platform Game Development want to familiarize yourself with programming games and the latest ideas in game production.


This book introduces key game production concepts in an artist-friendly way, and rapidly teaches the basic scripting skills you'll need with Unity. It goes on to show how you, as an independent game artist, can create casual interactive adventure games in the style of Telltale's Tales of Monkey Island, while also giving you a firm foundation in game logic and design.

  • The first part of the book explains the logic involved in game interaction, and soon has you creating game assets through simple examples that you can build upon and gradually expand.

  • In the second part, you'll build the foundations of a point-and-click style first-person adventure game—including reusable state management scripts, load/save functionality, a robust inventory system, and a bonus feature: a dynamically configured maze and mini-map.

  • With the help of the provided 2D and 3D content, you'll learn to evaluate and deal with challenges in bite-sized pieces as the project progresses, gaining valuable problem-solving skills in interactive design.

 

By the end of the book, you will be able to actively use the Unity 3D game engine, having learned the necessary workflows to utilize your own assets. You will also have an assortment of reusable scripts and art assets with which to build future games.

 

So, if you are looking for a Unity 4 book, consider checking out this one.

Programming ,

7. December 2012

 

Yesterday the cocos2d community announced the first coordinated release of the cocos2d products.  What products comprise this family?

 

  • CocosBuilder v3.0-alpha0
  • cocos2d-html5 v2.1
  • cocos2d-iphone v2.1-beta4
  • cocos2d-x v2.1beta3-x–2.1.0

 

So what is the relationship between these products?  Well, this gets a bit confusing…  cocos2d is the original library, an Objective-C port of the original cocos2D Python library.  cocos2d-x is the C++ port of this library.  cocos2d-html5 is the JavaScript (HTML5) port, while CocosBuilder is… well, its new.

 

 

CocosBuilder is, in their own words:

 

CocosBuilder is a free tool (released under MIT-licence) for rapidly developing games and apps. CocosBuilder is built for Cocos2d’s Javascript bindings, which means that your code, animations, and interfaces will run unmodified on iPhone, Android and HTML 5. If you prefer to go native all the way, there are readers available for cocos2d-iphone and cocos2d-x.

Testing your game on a mobile device has never been quicker or easier, just install CocosPlayer on your device (or in Simulator) and CocosBuilder will push your code over wifi in just a few seconds. Hit the publish button and your game will be saved instantly to a html5 web page. CocosBuilder has a rich set of functions, including boned animations, nestling of interface files, support for multiple resolutions and automatic scaling of your assets.

 

 

Basically, they’ve bundled all the various products together into a standardized release.  I’ve not had a chance to sit down with CocosBuilder, but it sounds like a cool idea.  We have a number of Cocos2D HTML tutorials on this site if you are interested in seeing a cocos2D application in action.

News , , , ,

6. December 2012

 

 

You may notice that the number of posts around here have dropped off recently and will drop off for a bit longer.  First off, let me just say sorry.  I know I personally hate it when I check on a website in my daily rotation if there isn’t any new updates. 

 

So why so quite?

 

Well, there are a couple reasons. 

 

First, the industry is a bit quite this time of year, no news means nothing to talk about.

 

Second, I am just coming to the end of a large project I’ve been working on that I can announce more details about shortly.

 

Third, well, it’s the holidays in my parts.  Oddly enough, all of my celebrations are early this year and the holidays are nothing if not time consuming. There is an ironic flipside to this… later in the month, when the actual holidays approach, well I will have tons of free time, so expect to see new content then by the truckload… at least, if its a very small truck.

 

So, let me wish you an early Happy Holidays and say, don’t worry… new content is in the works… it will just be a bit slow to appear.

Totally Off Topic

Month List

Popular Comments