Subscribe to GameFromScratch on YouTube Support GameFromScratch on Patreon
31. мая 2016

 

Defold is a cross platform 2D focused Lua powered game engine created by King and available for free.  If you want to learn more about Defold, check the video review out below.  Today they just announced the release of Defold 1.2.82.  This release brings improved editor performance on OSX and Windows, increase GUI layer counts and improved account management options, including the ability to delete your account if required.  The full release notes:

Engine

  • DEF-1769 - Added: Crash handling support for HTML5.
  • DEF-1861 - Changed: OSX and Windows builds now use a higher optimization level.
  • DEF-1875 - Changed: Increase max number of GUI layers to 16.
  • DEF-1873 - Changed: Input on HTML5 will now only work if the canvas element is active.
  • DEF-1796 - Changed: HTML5 builds use project name for engine JS file.
  • DEF-1867 - Fixed: Ability to toggle persistent store on HTML5.
  • DEF-1870 - Fixed: HTML5 progress bar did not work if "Content-Length" header was missing.
  • DEF-1869 - Fixed: sys.open_url was missing in HTML5 implementation.
  • DEF-1871 - Fixed: html5.custom_heap_size is now correctly used in HTML5 builds.
  • DEF-1872 - Fixed: Windows bundling dialog showed incorrect text.

Web

  • Added: Ability to delete accounts.
  • Added: Users can change ownership of projects.

GameDev News

31. мая 2016

 

The news of the day out of Unity’s Unite Developer Conference is no doubt the Unity price changes.  However there were a few other announcements during this rather lackluster keynote.  Some talk about Unity Ads, AR/VR and various web services but perhaps the gem of the announcement is the Unity Connect beta.  From the Unity blog:

Lastly, we introduced Unity Connect, a new talent marketplace bringing together Unity artists, developers and creators with opportunities at studios and Connectcompanies of all sizes. Users can establish a professional presence, message others, and discover jobs and projects. Studios in need can quickly and easily find developers with the just the right skillset. Unity Connect is currently in closed beta, but you can pre-register for the next beta phase here: http://response.unity3d.com/ConnectBeta

 

This is an interesting move.  Essentially Unity Connect is going to serve as a middle man for job seekers and employers looking for Unity work(ers).  Coupled with their recently launched Unity Certification Program it’s quite clear Unity wants to build an ecosystem around their software.  Frankly it makes a great deal of sense and is a great opportunity for Unity to increase customer lock in, while at the same time providing a service to both developers and creators.  The service is in closed beta now, but it will be interesting to see how this all turns out.

GameDev News

31. мая 2016

 

Krita is a free and open source 2D sketching and painting application released under the GPL license.  They just announced a milestone with the release of version 3.  The focus of Krita 3 is animation, with the following animation focused features:

You can now do proper frame-by-frame animation in Krita. Multiple layers, all sorts of playback speeds, onion skinning, on top of all of Krita’s existing paint tools: It’s enough to make any animator’s fingers itch!Kiki_Krita_86

  • Animatable raster layers – Animated raster images with frames, and use the time-line docker to order them. Works in all color spaces and depths as well!
  • Onion skinning – This allows you to have an overlay of the previous and next frames, an important assistant when going from rough animation to smooth animation!
  • Importing image sequence – Import any set of images as an animated layer, automatically sorted by naming scheme.
  • Exporting image sequence – Export the whole animation as an image sequence, for further processing in other programs.
  • New dockers – timeline docker, animation docker, and animation workspace
  • CSV import and export – for layered animation, for use with TV-paint, or Blender via a plugin, courtesy of Laszlo Fazekas
  • Spriter scml exporter – Make the base image in Krita and then export it to this powerful cut-out animation tool for games.

 

(Image author link)

 

Of course, this is only a small subsection of the new functionality in Krita 3.  Krita 3 also adds Instant Preview,  improved layering functionality, an improved layering UI, better shortcuts, a unified grid UI, improved filters and much more.  For the full release notes click here.  Or you can preview the new features in the view embedded below.

GameDev News

31. мая 2016

 

Today at the Unite Europe, Unity announced some pretty substantial pricing changes.  Let’s start off by looking at the existing price structure:

 

image

image

 

What I didn’t show above was the personal license.  The Personal license is free, requires you to display a Made With Unity splash screen and has a revenue limitation of $100,000USD a year.  The personal license supported all platforms.

So essentially Unity pro (no splash screen, no revenue limitations, some additional cloud features ) cost $75 a month for Desktop/HTML5/Windows Store/Windows Phone, then an addition $75 a month for Android and $75 a month for iOS.  On top you could outright purchase Unity for $1,500 and an additional $1,500 per mobile platform.

 

Now let’s look at today’s pricing.

image

 

The Personal tier is mostly unchanged, but they have created a new tier called Plus.  This tier has the same limitations as Personal ( $100K revenue + splash ), but gives access to the cloud features from Pro and a couple other perks such as Unity Store assets.  The Pro tier is where the massive changes have occurred.  It is now a flat rate $125/month, regardless to platforms.  This means if you were only making desktop or HTML games before, Unity just almost doubled in price today.  If on the other hand, you were using Unity for iOS and Android development, you are now paying $100 a month less.

 

The big negative in this entire announcement?  Well...

Subscribers can stay on their current subscriptions until June, 2018. Customers with perpetual licenses can continue on their current licenses for as long as they like, but we will stop supporting Unity 5 perpetual licenses with new features and updates by March 3, 2017.

Basically the ability to buy Unity outright is going away very soon.  You can read more about the announcement here.

I also put together a video covering the subject in more detail available here or embedded below.

GameDev News

30. мая 2016

 

The following is a recap of major events in the world of game development for the week ending May 30h, 2016.  I do a weekly video recapping the news available here with this week’s video embedded below.  This post is a collection of links mentioned in the recap.

 

 

The Video

GameDev News

 

Popular Comments

GameDev math recipes: Collision detection using an axis-aligned bounding box part 2.
Subscribe to GameFromScratch on YouTube Support GameFromScratch on Patreon
28. November 2012

In a prior recipe, we looked at how to handle collisions using an axis aligned bounding box, but there was one major problem.  If our bounding box is axis aligned, how do we handle rotation?  As you can probably tell by gigantic spoiler of a rotating jet to our right, the answer is we resize the bounding box to match the new extents of the rotated sprite.  Let's look at how:

 

Just the Math

if(createjs.Bitmap.prototype.getBoundingRect == null){

createjs.Bitmap.prototype.getBoundingRect = function(){

var bb =  new createjs.Rectangle(

        this.x - this.image.width/2,

        this.y - this.image.height/2,

        this.image.width,

        this.image.height);

 

var corners = new Array();

corners[0] = new createjs.Point(bb.x,bb.y); //Top left

corners[1] = new createjs.Point(bb.x + bb.width,bb.y); //Top right

corners[2] = new createjs.Point(bb.x,bb.y + bb.height); // Bottom Left

corners[3] = new createjs.Point(bb.x + bb.width,bb.y + bb.height); //Bottom Right

 

var midPoint = new createjs.Point(this.x,this.y);

 

for(var i = 0; i < corners.length; i++){

    corners[i] = rotatePoint(corners[i],midPoint,this.rotation);

}

 

var minX,minY,maxX,maxY;

minX = maxX = corners[0].x;

minY = maxY = corners[0].y;

 

for(var i =1; i < corners.length; i++){

    if(corners[i].x < minX) minX = corners[i].x;

    if(corners[i].x > maxX) maxX = corners[i].x;

    if(corners[i].y < minY) minY = corners[i].y;

    if(corners[i].y > maxY) maxY = corners[i].y;

}

 

bb.width = maxX - minX;

bb.height = maxY - minY;

bb.x = this.x - bb.width/2;

bb.y = this.y - bb.height/2;

 

return bb;

}

}

 

Controls:
Click on the box to focus and press B to toggle the blue box from being displayed.

Description

That code excerpt makes it look more complicated than it actually is, not the version at the bottom of this post in the Complete Code section is more heavily commented.

Essentially as our underlying sprite rotates, the bounding box around it changes in size.  Now when we are creating our bounding box, we have to take the rotation into consideration.  Please note, there are a number of opportunities to optimize this code for performance, I favoured readability over performance, although I did note a few of the opportunities for improvement in the code comments.

First thing we have to do is get the original, untranslated bounding box of the sprite.  This is simply the image dimensions of our source sprite.  Unfortunately EaselJS doesn't provide a mechanism for defining a rectangle about it's mid point, like we have with our sprite, so we need to calculate the x and y values of our bounding box, which is at the top left corner of the rectangle.  This value is calculated by subtracting half the sprites width and height from it's location ( at it's mid point ).  If your library of choice allows you to specify a rectangle using it's mid point, width and height, you can remove some of this ugliness.

Now that we have our untranslated bounding box, we want to apply the sprite's rotation to each corner of the sprite.  We accomplish by applying a rotation around the centre of the sprite to each corner of the bounding box, see the See Also section for more details about rotation.  Note, this is one of those areas you could easily optimize for performance down the road.   

Now that all 4 corners have been rotated, we need to figure out what the smallest rectangle that will encompass our translated points is.  To determine this, we loop through each point in our array, looking for the largest and smallest values in the X and Y axis.  Once we have determined what the new boundaries our, we construct our newly resized bounding box using these values.  Once again, we can't specify a rectangle using it's centre point in EaselJS, so once again we need to calculated the top left corner using the same logic as before.

If you turn off the blue debug lines I've drawn around the translated shape ( click the window and press B to toggle ), you will notice there is a ton of empty space as the sprite rotates, making it easy for collisions to appear to happen even though the space is actually empty.  You are very correct, and this is one of the biggest downsides to using AABBs.  There are however options for dealing with this, some of which we will discuss later on.

When looking at the complete code below, realize that a great deal of it is for rendering debug information on screen and wouldn't normally be required in your collision detection code.

Complete Code

<!DOCTYPE html>

<html>

<head>

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

    <script>

        var jetSprite;

        var stage;

 

        // Actual bounds is the Shape used to store the drawn blue bounding lines

        var actualBounds;

        // hideActualBounds is a toggle for making the debug lines visible or not

        var hideActualBounds = false;

 

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

        document.onkeydown = function(e){

            switch(e.keyCode)

            {

                case 66: // up arrow

                    hideActualBounds = !hideActualBounds;

                    break;

            }

        }

        function rotatePoint(point, center, angle){

            angle = (angle ) * (Math.PI/180); // Convert to radians

            var rotatedX = Math.cos(angle) * (point.x - center.x) - Math.sin(angle) * (point.y-center.y) + center.x;

            var rotatedY = Math.sin(angle) * (point.x - center.x) + Math.cos(angle) * (point.y - center.y) + center.y;

 

            return new createjs.Point(rotatedX,rotatedY);

        }

 

 

        if(createjs.Rectangle.prototype.intersects == null){

            createjs.Rectangle.prototype.intersects = function(rect){

                return (this.x <= rect.x + rect.width &&

                        rect.x <= this.x + this.width &&

                        this.y <= rect.y + rect.height &&

                        rect.y <= this.y + this.height);

            }

        }

 

        if(createjs.Bitmap.prototype.getBoundingRect == null){

            createjs.Bitmap.prototype.getBoundingRect = function(){

                var bb =  new createjs.Rectangle(

                        this.x - this.image.width/2,

                        this.y - this.image.height/2,

                        this.image.width,

                        this.image.height);

 

                // Get the 4 corners of the bounding box, order doesn't matter since they can potentially change

                // Note, you could optimize this two only require the top left and bottom right corners

                var corners = new Array();

                corners[0] = new createjs.Point(bb.x,bb.y); //Top left

                corners[1] = new createjs.Point(bb.x + bb.width,bb.y); //Top right

                corners[2] = new createjs.Point(bb.x,bb.y + bb.height); // Bottom Left

                corners[3] = new createjs.Point(bb.x + bb.width,bb.y + bb.height); //Bottom Right

 

                var midPoint = new createjs.Point(this.x,this.y);

                // Now apply the rotation of the sprite to the corners of the bounding box

                // This loop could be merged with the min/max loop for optimization purposes

                // But for readability I keep it separate for now.

                for(var i = 0; i < corners.length; i++){

                    corners[i] = rotatePoint(corners[i],midPoint,this.rotation);

                }

 

                // Draw the rotated shape for debug reasons

                // This draws a rectangle as 4 lines around the actual rotated image bounding area

                if(actualBounds){

                    stage.removeChild(actualBounds);

                }

                if(!hideActualBounds){

                    var g = new createjs.Graphics();

                    g.setStrokeStyle(1);

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

                    g.moveTo(corners[0].x,corners[0].y);

                    g.lineTo(corners[1].x,corners[1].y);

                    g.lineTo(corners[3].x,corners[3].y);

                    g.lineTo(corners[2].x,corners[2].y);

                    g.lineTo(corners[0].x,corners[0].y);

 

                    actualBounds = new createjs.Shape(g);

                    stage.addChild(actualBounds);

                }

 

                // These variables hold the smallest and largest X and Y values found in the Point array

                var minX,minY,maxX,maxY;

 

                // Small optimization here, start assuming first point is correct to eliminate a loop iteration

                minX = maxX = corners[0].x;

                minY = maxY = corners[0].y;

 

                // Loop through Points determining the boundaries of our newly rotated rectangle

                for(var i =1; i < corners.length; i++){

                    if(corners[i].x < minX) minX = corners[i].x;

                    if(corners[i].x > maxX) maxX = corners[i].x;

                    if(corners[i].y < minY) minY = corners[i].y;

                    if(corners[i].y > maxY) maxY = corners[i].y;

                }

 

                // We now have the four extreme points of our new bounding box, update bb with new box dimensions

                bb.width = maxX - minX;

                bb.height = maxY - minY;

                bb.x = this.x - bb.width/2;

                bb.y = this.y - bb.height/2;

 

                return bb;

            }

        }

 

        // This function is responsible for actually drawing the bounding box on screen

        function updateBoundingBox(){

            // Draw the bounding rect and create a new Shape with it

            var g = new createjs.Graphics();

            g.setStrokeStyle(1);

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

 

            var bb = jetSprite.getBoundingRect();

            g.drawRect(bb.x,bb.y,bb.width,bb.height);

 

            if(jetSprite.boundingBox){

                stage.removeChild(jetSprite.boundingBox);

            }

            jetSprite.boundingBox = new createjs.Shape(g);

            stage.addChild(jetSprite.boundingBox);

        }

 

        function demo(){

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

 

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

            jetSprite.boundingBox = null;

            actualBounds = null;

 

            stage.addChild(jetSprite);

 

            // Add a Image load handler, as image.width and image.height are meaningless until

            // load is done and DOMContentLoaded doesn't seem to take into account dynamic images

            jetSprite.image.onload = function(e){

            jetSprite.y = 200;

            jetSprite.x = 200;

            jetSprite.regX = jetSprite.image.width/2;

            jetSprite.regY = jetSprite.image.height/2;

            updateBoundingBox();

            }

 

            //And go...

            stage.update();

 

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

            createjs.Ticker.addListener(onFrame);

        }

 

        function onFrame(elapsedTime) {

            // Convert from milliseconds to fraction of a second

            var delta = elapsedTime /1000;

 

            jetSprite.rotation = jetSprite.rotation + 1;

            if(jetSprite.rotation > 360) jetSprite.rotation = 0;

            updateBoundingBox();

            stage.update();

        }

    </script>

 

</head>

<body>

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

</body>

</html>

 

 

See Also

See Collision Detection using an axis-aligned bounding box for part one of this recipe.

See Rotating one point around another point for more information on the code used to rotate the bounding box.

 

Programming

blog comments powered by Disqus
 

Month List

Popular Comments