Subscribe to GameFromScratch on YouTube Support GameFromScratch on Patreon

8. April 2015

 

The first tutorial in the Unreal Engine vs Unity tutorial series is now live.  In this tutorial we look at using Unreal Engine.  It’s an introduction to Unreal Engine, a guided tour around the editor, then we create a simple Hello World application using Blueprints.

 

I will be creating a companion text tutorial to go along with this video shortly.

 

You can see the video in full 1080p here.

 

The Video

 

Programming , , ,

7. April 2015

 

In this video tutorial we continue to look at 3D programming in LibGDX.  First we look at how to convert a 3D model to work with LibGDX using fbx-conv.  We then write the code to display that model and look at displaying animations.  The fbx-conv application can be downloaded here.

 

The data file used in this example can be downloaded here (zip format).  If you are interested in learning more about the process of creating the model click here.

 

The video is available in HD here.

 

The source code, and an embedded copy of the video, are available below.

 

 

Source Code

 

package com.gamefromscratch;

import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Files;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.PerspectiveCamera;
import com.badlogic.gdx.graphics.g3d.Environment;
import com.badlogic.gdx.graphics.g3d.Model;
import com.badlogic.gdx.graphics.g3d.ModelBatch;
import com.badlogic.gdx.graphics.g3d.ModelInstance;
import com.badlogic.gdx.graphics.g3d.attributes.ColorAttribute;
import com.badlogic.gdx.graphics.g3d.loader.G3dModelLoader;
import com.badlogic.gdx.graphics.g3d.utils.AnimationController;
import com.badlogic.gdx.utils.UBJsonReader;

public class ModelTest extends ApplicationAdapter {
    private PerspectiveCamera camera;
    private ModelBatch modelBatch;
    private Model model;
    private ModelInstance modelInstance;
    private Environment environment;
    private AnimationController controller;

    @Override
    public void create() {
        camera = new PerspectiveCamera(75,Gdx.graphics.getWidth(),Gdx.graphics.getHeight());

        camera.position.set(0f,100f,100f);
        camera.lookAt(0f,100f,0f);

        camera.near = 0.1f;
        camera.far = 300.0f;

        modelBatch = new ModelBatch();

        UBJsonReader jsonReader = new UBJsonReader();

        G3dModelLoader modelLoader = new G3dModelLoader(jsonReader);
        model = modelLoader.loadModel(Gdx.files.getFileHandle("model.g3db", Files.FileType.Internal));
        modelInstance = new ModelInstance(model);

        environment = new Environment();
        environment.set(new ColorAttribute(ColorAttribute.AmbientLight,0.8f,0.8f,0.8f,1.0f));

        controller = new AnimationController(modelInstance);
        controller.setAnimation("Mixamo.com", -1, new AnimationController.AnimationListener() {
            @Override
            public void onEnd(AnimationController.AnimationDesc animation) {
            }

            @Override
            public void onLoop(AnimationController.AnimationDesc animation) {
                Gdx.app.log("INFO","Animation Ended");
            }
        });
    }

    @Override
    public void dispose() {
        modelBatch.dispose();
        model.dispose();
    }

    @Override
    public void render() {
        Gdx.gl.glViewport(0,0,Gdx.graphics.getWidth(),Gdx.graphics.getHeight());
        Gdx.gl.glClearColor(1,1,1,1);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT|GL20.GL_DEPTH_BUFFER_BIT);

        camera.update();
        controller.update(Gdx.graphics.getDeltaTime());

        modelBatch.begin(camera);
        modelBatch.render(modelInstance);
        modelBatch.end();
    }
}

 

Video

 

Programming , , ,

3. April 2015

 

The open source, C++ based, cross platform game engine and editor Godot have just released version 1.1 beta.  GameFromScratch.com has a fair bit of contentNewImage about the Godot engine, including this ongoing tutorial series, if you wish to learn more.

 

 

So, what’s new in 1.1 Beta?

 

 

Well, I’ll use their own words:

 

 

Godot 1.1 Beta is Out!

Time to get serious again!

After three months of hard work, our first new release is out! This beta prepares the road for the 1.1 release, expected sometime in late April.

New features include:

  • Rewritten Auto-Completion in the Code-Editor. Supports a lot of scenarios and perform smart-completion of node types if a scene where the script is being used is open.
  • Visual Shader Editor (Edit shaders connecting nodes)
  • New API in OS for managing the screens and window, with multi-monitor support.
  • Largely rewritten 2D engine, with support for:
    • Shaders (Visual and Code)
    • 2D Materials
    • 2D Independent Z ordering per-node.
    • 2D Lights
    • 2D Shadows with Polygonal Occluders
    • 2D Normal Mapping
    • Back-Buffer compositing for shaders that read from screen (allows all sorts of post-processing effects).
    • Improved Isometric TileMap Support (proper Z ordering of tiles and children nodes).
    • Distance-Field font support.
  • New 2D Navigation Polygon support, for efficient 2D pathfinding. Navigation Polygons can be edited visually and combined, disabled, etc.
  • Improved Usability in 2D Physics API:
    • Area2D and RigidBody2D can receive input events
    • Area2D can detect overlap with another Area2D
  • New Dark Theme
  • Large amount of bug fixes and smaller improvements.

Please remember that this new version is BETA, so this is your time to report everything that doesn’t work to GitHub as Issues, contribute PRs with fixes or annoy Juan and Ariel to fix what is not working for you.

Godot 1.1 Beta1 can be obtained in the Downloads section, or source cloned at GitHub.

Happy Testing!

 

 

Very cool stuff!  

 

There are actually some pretty major changes in this release.  The improved auto completion is certainly nice, but the rewritten 2D engine is probably the biggest change.  One of the major components of this is the Visual Shader Editor.  As someone who hates writing shaders, this is a welcome addition.  Here it is in action:

ShaderEdit

 

 You can build shader networks by connecting nodes together.  Of course the new 2D navigation stuff is an excellent addition.  I’ll be looking in to this new functionality closer in the near future.

 

You can download Godot here.  The complete source code is available on Github.  As mentioned earlier, to get started there is a complete tutorial series on this very site.

Programming

2. April 2015

 

Overlap2D, a 2D Level/UI editor built over LibGDX has recently gone open source.  We hosted a tutorial here on Gamefromscratch on using Overlap2D several months back.

 

From the announcement:

Overlap2D is now open source!

So yeah, after intense re-factoring, we are finally ready to give Overlap2D sources to our fantastic community!

Github URL: https://github.com/UnderwaterApps/overlap2d

From now on, you will be able to fix or add anything and for everyone.

We are going to see tons of new features in near time, starting from bug proof editor with performance improvements and finishing with crazy addons like terrain editor, custom shaders, polygons, advanced asset manager and much more. With so much going on, you may be asking yourself – how can I help?

And seriously, we really need your help. 

So, here are some ideas you can try out if you feel generous:

We hope this will make editor better, and that in turn will enable you to make amazing 2D games!

Head to github, fork us, explore the code and make some pull requests!

 

Nope, this is not a late April fools joke.  You can see Overlap2D in action in the video below:

 

 

Very cool news guys!

Design, News, Programming

31. March 2015

 

Today I suppose, the new tutorial series covering creating a 2D game in both Unreal and Unity officially kicked off.  I just finished publishing this videoUntitled 7 ( embedded below ) to YouTube.

 

In many ways the video covers the same topics as the earlier announcement post.  Additionally it also goes into a bit of the differences between Unity 5 and Unreal Engine 4, especially from a licensing perspective, and area where Unity and Unreal differ a great deal.

 

We also cover some of the similarities and differences between Unity and Unreal Engine, which are probably more alike than you realize.  We go into the languages and platforms supported by each engine.  Of course we also describe the goals of this entire series.  If you are already familiar with Unity and Unreal and read the last posts, there isn’t really anything new here.

 

Once again, your comments and feedback will shape how I continue, so the earlier you can get suggestions in to me, the more likely I am to be able to cover them! Next up I will be doing a learning resources post for each engine, then we will jump in to the technical details, so stay tuned!

 

Unity vs Unreal Engine Tutorial Series –The Series Introduction

 

This space left intentionally vague.

Programming

Month List

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