Subscribe to GameFromScratch on YouTube Support GameFromScratch on Patreon

5. February 2014

I literally spent hours on this and it didn’t work.  So I decided to strip it down to absolute basics, create a barebones solution and figure out exactly what is going wrong.

 

The kicker is, the answer is nothing, it works exactly as expected.  Want to manipulate a bone in a Model in LibGDX and see the results propagated?  Well, this is how.

 

First I modelled the following in Blender:

BlobBlender

 

Its a simple mesh with a single animation attached.  If you read my prior tutorials, the how of it will be no problem.

 

Then I ran it with this code:

package com.gamefromscratch;

 

import com.badlogic.gdx.ApplicationListener;

import com.badlogic.gdx.Files.FileType;

import com.badlogic.gdx.Gdx;

import com.badlogic.gdx.Input;

import com.badlogic.gdx.InputProcessor;

import com.badlogic.gdx.graphics.GL10;

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.model.Node;

import com.badlogic.gdx.utils.JsonReader;

import com.badlogic.gdx.graphics.g3d.utils.AnimationController;

 

 

public class Boned implements ApplicationListener, InputProcessor {

    private PerspectiveCamera camera;

    private ModelBatch modelBatch;

    

    private Model blobModel;    

    private ModelInstance blobModelInstance;

    private Node rootBone;

    private Environment environment;

 

    private AnimationController animationController;

    

    @Override

    public void create() {        

        camera = new PerspectiveCamera(

                75,

                Gdx.graphics.getWidth(),

                Gdx.graphics.getHeight());

        

        camera.position.set(0f,3f,5f);

        camera.lookAt(0f,3f,0f);

        camera.near = 0.1f; 

        camera.far = 300.0f;

 

        modelBatch = new ModelBatch();

        

        JsonReader jsonReader = new JsonReader();

        G3dModelLoader modelLoader = new G3dModelLoader(jsonReader);

        blobModel = modelLoader.loadModel(Gdx.files.getFileHandle("data/blob.g3dj", FileType.Internal));

        blobModelInstance = new ModelInstance(blobModel);

        

        animationController = new AnimationController(blobModelInstance);

        animationController.animate("Bend",-1,1f,null,0f);

        

        rootBone = blobModelInstance.getNode("Bone");

        environment = new Environment();

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

        

        Gdx.input.setInputProcessor(this);

    }

 

    @Override

    public void dispose() {

        modelBatch.dispose();

        blobModel.dispose();

    }

 

    @Override

    public void render() {

        // You've seen all this before, just be sure to clear the GL_DEPTH_BUFFER_BIT when working in 3D

        Gdx.gl.glViewport(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());

        Gdx.gl.glClearColor(1, 1, 1, 1);

        Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);

        camera.update();

        animationController.update(Gdx.graphics.getDeltaTime());

        modelBatch.begin(camera);

        modelBatch.render(blobModelInstance, environment);

        modelBatch.end();

    }

 

    @Override

    public void resize(int width, int height) {

    }

 

    @Override

    public void pause() {

    }

 

    @Override

    public void resume() {

    }

 

@Override

public boolean keyDown(int keycode) {

if(keycode == Input.Keys.LEFT)

{

rootBone.translation.add(-1f, 0, 0);

returntrue;

}

else if(keycode == Input.Keys.RIGHT){

rootBone.translation.add(1f,0,0);

returntrue;

}

returnfalse;

}

 

@Override

public boolean keyUp(int keycode) {

// TODO Auto-generated method stub

returnfalse;

}

 

@Override

public boolean keyTyped(char character) {

returnfalse;

}

 

@Override

public boolean touchDown(int screenX, int screenY, int pointer, int button) {

// TODO Auto-generated method stub

returnfalse;

}

 

@Override

public boolean touchUp(int screenX, int screenY, int pointer, int button) {

// TODO Auto-generated method stub

returnfalse;

}

 

@Override

public boolean touchDragged(int screenX, int screenY, int pointer) {

// TODO Auto-generated method stub

returnfalse;

}

 

@Override

public boolean mouseMoved(int screenX, int screenY) {

// TODO Auto-generated method stub

returnfalse;

}

 

@Override

public boolean scrolled(int amount) {

// TODO Auto-generated method stub

returnfalse;

}

}

 

End result, you get this:

BonedBlob

 

Press the arrow keys and the root bone is translated exactly as you would expect!

 

Now, I spent HOURS trying to do this, and for the life of me I couldn’t figure out why the heck it doesn’t work.  Sometimes going back to the basics gives you a clue.

 

In my test I used two models, one an animated bending arm, somewhat like the above.  The other was an axe with a single bone for “attaching”.  The exactly same code above failed to work.  Somethings up here...

 

So after I get the above working fine, I have an idea… is it the animation?  So I comment out this line:

animationController.animate("Bend",-1,1f,null,0f);

 

BOOM!  No longer works.

 

So it seems changes you make to the bones controlling a Model only propagate if there is an animation playing.  A hackable workaround seems to be to export an empty animation, but there has to be a better way.  So at least I know why I wasted several hours on something that should have just worked.  Now I am going to dig into the code for animate() and see if there is a call I can make manually without requiring an attached animation.

 

EDIT:

Got it!

Gotta admit it took a bit of digging, but I figured out what I am missing.  Each time you make a change to the bones you need to call calculateTransforms() on the ModelInstance that owns the bone!  Change the code like so:

public boolean keyDown(int keycode) {

if(keycode == Input.Keys.LEFT)

{

  rootBone.translation.add(-1f, 0, 0);

  blobModelInstance.calculateTransforms();

  return true;

}

  else if(keycode == Input.Keys.RIGHT){

  rootBone.translation.add(1f,0,0);

  blobModelInstance.calculateTransforms();

  return  true;

}

 

  return false;

}

And presto, it works!

Just a warning, calculateTransforms() doesn’t appear to be light weight, so use with caution.

If you are curious where in the process calculateTransforms is called when you call animate(), it’s the end() call in BaseAnimationController.java called from the method applyAnimations().

Programming ,

4. February 2014

 

There are a number of solutions for developing iOS applications in a foreign language and creating a native binary.  For example there is RoboVM (Java), Xamarin (C#) and even Adobe Air (Flash/ActionScript).  To the best of my knowledge there are no solutions to going the other way.  How can you take your natively developer iOS Objective-C app and port it to Android?

 

Now there is a solution, or at least, soon there will be. Marmalade, the makers of a popular cross platform C++ game development kit, have recently announced Marmalade Juice.  This graphic probably explains it best of all.

 

Juice

 

 

So basically its Xamarin in reverse.  Write your code in ObjectiveC/XCode, then compile to a native Android binary using a mapping layer translating underlying calls via their Marmalade middleware layer.

 

Now why exactly anyone would actually want to write code in ObjectiveC I still don’t know… :)  This however could prove to be a heck of a boon for iOS developers looking to target Android but not wanting to rewrite portions of their game in C++ or Java. If you are interested in Marmalade Juice you can learn more here.  A beta is available for existing customers with full launch in 43 days ( as of today ).

4. February 2014

 

In my head this part of the process of creating a dynamically equipped character in 3D and rendering it to 2D was going to be a breeze.  Conceptually it went something like this...

 

  • Create a named bone in parent object where the weapon could attach.
  • Create a named bone in the child object where the weapon starts.
  • Find bone one, attach bone two.
  • Go enjoy a beer in smug satisfaction.

 

Sadly it doesn’t quite work like that.

 

There are a couple problems here.

1- LibGDX doesn’t have a SceneGraph.  A Scene Graph is basically a data structure that holds relationships in the world.  Essentially this is what scene2D actually is.  Well, LibGDX sorta has a SceneGraph in the form of Model, which is a graph of nodes that compose the model.  There however isn’t a layer above this for creating relationships between models.  This sadly means I can’t (out of the box) do something like myTank.attachObjectAt(turrent,(3,3,3));

 

2- Modifying bones in LibGDX doesn’t actually seem to do anything.  My first though was… well this is easy enough then, Ill just set the GlobalTransform of the child bone to the location of the parent bone.  This however doesn’t do anything.  I might be missing something here, in fact I probably am.  But I couldn’t get changes to a bone to propagate to the attached model.  This one is likely user error, but after playing around with it for a few days, I am still no further ahead.

 

3- Bones don’t have direction.  Well, that’s not accurate, bones don’t point in a direction.  Here for example is a sample hierarchy of bones exported in text readable format:

{"id": "Armature",
   "rotation": [-0.497507, 0.502480, -0.502480, 0.497507],
   "scale": [ 1.000000, 1.000000, 1.000000],
   "translation": [ 0.066099, 0.006002, -0.045762],
   

   "children": [
      {"id": "Bone_Torso",
      "rotation": [-0.498947, 0.501051, -0.501042, -0.498955],
      "scale": [ 1.000000, 1.000000, 1.000000],
   

      "children": [
         { "id": "Bone_UpArm",
        "rotation": [ 0.007421, -0.000071, -0.009516, 0.999927],
        "scale": [ 1.000000, 1.000000, 1.000000],
        "translation": [ 1.728194, 0.000000, -0.000000],

      "children": [
         {"id": "Bone_LowArm",
         "rotation": [ 0.999846, 0.012394, -0.000030, 0.012397],
         "scale": [ 1.000000, 1.000000, 1.000000],
         "translation": [ 1.663039, 0.000000, 0.000000],

      "children": [
         {"id": "Bone_Hand",
         "rotation": [ 0.999737, -0.016222, -0.000425, 0.016225],
         "scale": [ 1.000000, 1.000000, 1.000000],
         "translation": [ 1.676268, 0.000000, -0.000000]}
      ]}
   ]}
]}

As you can see, you have the Armature, which is basically the root of the skeleton.  It’s translation is the start location of the bones in local space ( of the model ).  Each bone within is therefore offset from the bone above it in the hierarchy.  What is lacking ( for me ), is a direction.  As an aside, I can actually confer the direction using the distance between (in this example) Bone_Hand and Bone_LowArm.  This of course requires two bones on both the parent and child models.

 

Consider this bad drawing.

 

You have a tank and a turret like so, with the red dots representing bone positions:

 

Tankexample1

 

So long as your tank and turret are modelled with consistent coordinate systems ( aka, both same scale, same facings, etc ), you can simply locate the tank bone and offset the turret relative, like so:

Tankexample2

 

In this simple example, it works perfectly!

 

Let’s consider a slightly more advanced situation however. Lets say we are diehard Warhammer fans and want to add sponsons to the side of our tank.

Once again, by modelling consistently with the tank and sponson, we can get:

TankExample3

 

Yay future tank now looks a hell of a lot like the world’s first tank…  but this is pretty much what we want.  Now lets mount one to the other side of the tank.

 

TankExample4

 

Ah shi… that’s not right.  Our second gun is INSIDE the tank.

 

The problem here is, we can’t depend on the coordinates of the both models matching up anymore.  We need to figure out direction when mounting the new weapon to the tank.  This means we need a facing direction for the bone, and this is something we don’t have.

 

Again, this problem has proven trickier then expected.  I will share some of my failed approaches shortly as this post got pretty long.

Design

31. January 2014

 

When I started Flexamail ages ago, I created a Twitter account and did all the social media promotional stuff you were supposed to do.  Early on, we caught some pretty positive press ( LifeHacker, MakeUseOf ) and it lead to a huge amount of exposure.  Then the Twitter-verse started promoting it.  At one point, I had a Twitterimage user with over 4 million followers tweeted a link to Flexamail and it was retweeted an amazing 4,000 times!  I was expecting the traffic to come rolling in!

 

To put it mildly, I was disappointed with the results.  A totally of perhaps 45 million people received a tweet with a link to my site… how many link clicks?  About 3000.  Of those 3000, it resulted in about 200 account sign ups.  For some perspective the LifeHacker link resulted in tens of thousands of clicks and I would estimate 4 – 5K sign ups.  At this point in time I decided the Twitter was a bunch of people talking and very few people listening.

 

Therefore a couple years ago when I started GameFromScratch  I pretty much ignored Twitter completely until about a year ago and what an idiot I was.  It’s all a matter of targeting I suppose.  Now if someone posts a link to GameFromScratch on Twitter, from my very unscientific observation, I would say about 20% of a persons followers follow the link on average.  So for example, if someone with a thousand follower posts a link, it results in about 200 visits, which is pretty darned good.  A stranger phenomenon, the person with less followers tends to have a much higher click through.  So if someone has around 100 followers, you would often see almost half click a given link.

 

According to Google Analytics, a random sampling of social traffic breaks down like:

image

 

Obviously Reddit tops the list.  Reddit is a wonderful place to post for a content site like GameFromScratch, but I really don't recommend it for plugging a product, there is a sincere distaste towards those kinds of posts.  That is unless of course you share genuinely useful information, then you are loved.  Postmortems and sharing sales data are always welcome and could be a huge traffic boost.  Or of course you could consider a promoted reddit post, something I intend to explore at some point.

 

Next in traffic though is Twitter, followed by Facebook and the oh so random StumbleUpon ( about a year ago got 18,000 visits from SU in a single day! ).  So Twitter is certainly worth considering.

 

Which got me to wondering, when I looked over at the side of Twitter earlier day, there was a link for, well, basically paying for Twitter followers from Twitter ( not those shady buy-a-thousand-followers-for-5$ services ).  I got curious, could this be an effective way to promote a game ( or in my case, book )?  So I took a look.

 

The form itself is clever.  You say what regions and genders you want to target, what type of followers you would like to target ( pick someone famous, or use your own followers as the example ).  Then you can select a Tweet from your history that can be promoted.  You also decide whether you would like to pay per new follower, or pay per action ( retweet, favoriting, etc ).  It all sounded pretty good… great in fact.

 

Then it came down to pricing.  You can set a maximum budget and a daily budget.  I went with 20$ and 20$, so basically I was saying I am willing to pay a total of 20$.  The fact it let me go in with so low of an amount is certainly good for those of us on a smaller budget.  Next up came the bid… this is where you say how much you are willing to bid for your account to be promoted.  This works just like banner ads, basically you say “I am wiling to pay X amount to show my Twitter profile” when someone matching your target demographic views Twitter.  If you are the high bid, you are shown, if you aren’t, you aren’t ( and it costs you nothing ).  Then it all falls apart!

image

 

Suggested bid… $2.50 to $3.50!!!!  Three bucks a follower?  Seriously???  That would mean it would cost me $2,500 to get to where I am now!

 

Ouch.  Maybe for large companies with huge budgeting, this is worthwhile.  In fact, it is probably cheap compared to other forms of advertising.  For example, if Coke was running a Twitter campaign, 3$ a follower is probably dirt cheap compared to say… a SuperBowl spot.  But for a small developer hoping to promote a game, good god no!

 

I am mildly curious to see what happens if you do a 1 cent bid, Twitter’s suggestions be damned!  At 3 bucks a follower though, is it worthwhile?  No, not really.

Totally Off Topic

28. January 2014

 

Back in August of 2012 we reported in a free PDF made available by Ryan Hawkins called Vertex.  It was a high detail guide to game art from various industry artists… oh, and it was completely free!

Now, Vertex2 has been released!

Photo: VERTEX 2 IS OFFICIALLY OUT!!!!! Share this link with your Facebook friends and please like us if you have not done so yet. We hope that you enjoy the second volume in the VERTEX series.

On our website below please visit the downloads section and download either book one or book two. Both are great reads and are unique to one another content wise. http://artbypapercut.com/

 

Basically, it’s more of the same!  Erm, I think.  Reality is, I haven’t been able to download it, their website is down.  Apparently hosting a large downloadable file on a sub-standard host isn’t a great idea.

 

You can keep trying that link above, or hopefully I will locate a mirror and share it here.  If you have a mirror, let me know and I will post it!  Once you do in fact get a download of the book, if you like it, be sure to like them on their facebook page or consider using the donation link at the end of the book.  Awesome high quality free content is certainly worth rewarding!

Art ,

Month List

Popular Comments

Godot Unity like game engine going open source
Subscribe to GameFromScratch on YouTube Support GameFromScratch on Patreon


5. January 2014

 

There is a new entrant in the game engine space, the Godot game engine from Okam Studio.  The engine was apparently used for in-house projects and is over a decade in the making.  The editor runs on Linux, Windows and OSX and can target desktop, mobile, consoles as well as HTML.

godot1

godotss2.png

godotss1.png

 

From observation, the engine appears to be similar to Unity, but powered by C++.  It uses a custom scripting language that appears LUA like.

 

In the developers own words:

We’ll be opening a game engine that has more than a decade of work (and several iterations) as MIT license soon.

It’s not an engine made by hobbyists, this is a production tool used to develop and publish plenty of games for PC, Consoles and Mobile. It’s currently in beta stage, meaning it’s feature complete and fully usable, but lacks very little fine tuning and testing. It has a similar feature set to Unity (little less stuff on 3D front, much more stuff on the 2D front, debugging). and runs on all the popular desktop and mobile platforms, as well as on the web (through asm.js).

Unlike almost any other game engine with this level of features, the editor runs fine in Linux, as well as Windows and OSX, and supports one click deploy.

 

Apparently the engine is being released under the MIT open source license ( a very generous license ) and is undergoing polish before complete release.  If you are interested in early access, contact juan@okamstudio.com.

 

I’ll be keep an eye on this one… a C++ powered Unity like engine is sure to be interesting to many.  Not sure exactly when it will drop but for now we are … Waiting for Godot.

 

Ok… that was bad.   More details as I get them.

News, Programming

blog comments powered by Disqus

Month List

Popular Comments