Header

GAMES BLOG ABOUT Follow 2TonStudios on Twitter Like 2TonStudios on Facebook
May 2017
Unity Animation: Specific Start / End -frame Playback

I often find it useful to be able to preview an animation from a specific frame to a specific frame, or play an animation once, without looping. For instance, I want to see an attack animation play once from start to end, without looping. Unfourtunately this is not supported through Unity's standard features. With some help from Aedous (Eitr dev) we hacked up this solution. If you have questions let me know.

Animation Window - Preview Animation with specific Start and End frames (Unity Forums)


May 2017
VS Code on Mac

I wrote a guide to help get VS Code up and running with Unity on Mac. By following its steps you should be able to get VS Code working as your default editor for Unity with full debugging support and intellisense. Hopefully it works for you as well.

VS Code - Setup on Mac for Unity (Google Doc)


March 2014
Unity3D: Skinning + 2D Sprites #ForReal

Yesterday I posted what I thot was a solution for skinning with 2D sprites sheets. That solution turned out to be a flop, only working in the Unity Edtior and not in any other build (Web, PC, iOS, etc). So basically pretty lame and useless.

However, after a bit more hacking I do have a solution that works. The premise is the same as the first one: use the loaded sprite renderers as "cut out" references for any new sprite sheet you want to load. The code is below. Enjoy!

// new stuff
using System;

// standard
using UnityEngine;
using System.Collections;

public class SkinController : MonoBehaviour 
{
    public string activeSkin;

    // Use this for initialization
    void Awake () 
    {
        // default loaded sprites
        SpriteRenderer[] loadedRenderers = GetComponentsInChildren <SpriteRenderer>(true);

        Texture2D atlas = Resources.Load (activeSkin, typeof(Texture2D)) as Texture2D;

        for (int i = 0; i < loadedRenderers.Length; i++)
        {
            try
            {
                // replace the current sprite with the desired sprite, but using the 
                // loaded sprite as a cut out reference via 'rect'
                loadedRenderers[i].sprite = 
                    Sprite.Create (atlas, loadedRenderers[i].sprite.rect, new Vector2 (0.5f, 0.5f));

                // update name, main texture and shader, these all seem to be required... 
                // even thou you'd think it already has a shader :|
                loadedRenderers[i].sprite.name = loadedRenderers[i].name + "_sprite";
                loadedRenderers[i].material.mainTexture = atlas as Texture;
                loadedRenderers[i].material.shader = Shader.Find ("Sprites/Default");
            }
            catch (Exception e) {}
        }
    }
}
                


March 2014
Unity3D: Skinning + 2D Sprites

NOTE: This solution relies on AssetDatabase. As a result it only works when you are in the editor. Any build outside the editor will not work. For a solution that does work, see above.

Supporting multiple skins for the same base character type is pretty common in games, especially RPGs. Lets say you want to support two kinds of dwarves: Mountain and Duergar. Often the only difference is the colouring of their clothes, skin, etc., but the base model and animations remain the same. A common way to do this is build two different sprite sheets, and then apply the right sheet based on the type of dwarf you want.

Here's the trouble, Unity's 2D sprite system, although killer in many regards, makes this insanely difficult when using Sprites with Sprite Mode set to Multiple aka 2D sprite sheets. The sprite API just doesn't seem to have any support for accessing a sprite's "parent" sprite sheet - never mind doing this at some kind of higher level. Of course this sucks. If you want to make games of a certain scale, you really need to be able to swap skins on things. It's just not practical to copy-paste an object and manually replace all of the sprites on it every time you want some kind of variant - my main character currently has 181 distinct sprites on it :|.

So, after some digging I found a way around this. I began by looking through the Unity forums, where I came across what I thought was a solution. This rather ingenious method uses something called MaterialPropertyBlock to alter the Texture behind a sprite - in case you're wondering using material.SetTexture() doesn't seem to do anything. The bummer is that this doesn't seem to work if you run Animator animations on the things you're trying to skin. Animator simply replaces the texture added with MaterialPropertyBlock, to the one that was loaded at startup. (I haven't dug into this, but it seems that Unity loads some kind of hidden reference to the "parent" sprite sheet and ensures that continues to get used/reapplied when Animator is running - this probably has something to do with the ability to override a sprite manually within an animation.) Sadly, this was a dead end.

The "solution" I came up with is a bit hacky, but does seem to work. First, you need to add a few using statements to the top of your code.

// new stuff
using System.Linq; // allows you to use TypeOf()
using System; // allows you to use Exception e for try catch
using UnityEditor; // allows you to use AssetDatabase

// standard stuff
using UnityEngine;
using System.Collections;
                

Then, you want to get all of the SpriteRender objects under the thing you want to skin. These are the things we are going to replace with our desired sprites.

// default loaded sprites, we use true in GetComponentsInChildren because we want inactive ones
SpriteRenderer[] loadedRenderers = GetComponentsInChildren (true);
                

Next, you want all of the sprites from the desired skin - the texture that contains the sprites you want to replace the loaded sprites with.

// sprites we want
Sprite[] sprites = AssetDatabase.LoadAllAssetRepresentationsAtPath("Assets/Sprites/" + "BeardQuest_DarkDwarf" + ".png").OfType().ToArray();
                

You'll want to replace "Assets/Sprites/" with the relative path of your desired texture, same goes for "BeardQuest_DarkDwarf" and ".png". You'll want that to be whatever texture you wish to load. For instance if you wanted to load a texture called "GreenGoblin.png" located in "Assets/Monsters/Textures" then you'd use the following code.

// sprites we want
Sprite[] sprites = AssetDatabase.LoadAllAssetRepresentationsAtPath("Assets/Monsters/Textures" + "GreenGoblin" + ".png").OfType().ToArray();
                

Lastly, we want to look through all of the items in sprites and for each one find the matching sprite in our already loaded character. I'm sure there are a number of ways to do this matching, but I found that looking for the x and y offset (UVs in 3D) of the sprite in the sprite sheet is easiest - it avoids having to look up names, it's gauranteed to be unique, and simple requires that both sprite sheets have the same offsets for sprites. You do this by comparing the rect.x and rect.y variables of each sprite.

// loop through all of the sprites, stopping at each one to find the matching loaded sprite
for (int i = 0; i < sprites.Length; i++)
{
    replaceMatchingSprite (loadedRenderers, sprites[i]);
}

// helper function to replace the matching, loaded sprite
void replaceMatchingSprite (SpriteRenderer[] loaded, Sprite newSprite)
{
    for (int i = 0; i < loaded.Length; i++)
    {
        try
        {
            if (loaded[i].sprite.rect.x == newSprite.rect.x && loaded[i].sprite.rect.y == newSprite.rect.y)
            {
                // we found a match, replaced loaded with new, we can have multiple matches as we reuse sprites
                loaded[i].sprite = newSprite;
            }
        }
        catch (Exception e) 
        {
            // do nothing, we seem to get a few null values when looking through the loaded sprites... but seems we can safely ignore them :).
        }
    }
}
                

You'll notice I have a try-catch around the matching condition, for some reason I was getting rather random null object errors when comparing sprites. I'm sure there is a good reason for this, and if I find out what it is, I'll update this, but, for now this works without a hitch.

So that's it, skin swapping! I broke this out into a seperate script that simple runs the above inside of Awake(), of course you can put it wherever it makes sense for you. If you have multiple skins that you want to swap through and you'd find it useful to set the sprites that are loaded through the editor you can use something like the below. As always, if you have any questions or suggestions please don't hesitate to contact me feedback@2tonstudios.com. Cheers!

// new stuff
using System.Linq;
using System;
using UnityEditor;

// standard
using UnityEngine;
using System.Collections;

public class SkinController : MonoBehaviour {

    // drop all the "skins" you want to be swappable here, these are the multi-sprite textures in your Assets
    public Texture2D[] skins;
    
    // the skin you want to use, you could add a public accessor so this can be changed at runtime.
    public int activeSkin;

    // Use this for initialization
    void Awake () 
    {
        // default loaded sprites
        SpriteRenderer[] loadedRenderers = GetComponentsInChildren (true);

        // sprites we want
        Sprite[] sprites = AssetDatabase.LoadAllAssetRepresentationsAtPath("Assets/Sprites/" + skins[activeSkin].name + ".png").OfType().ToArray();

        for (int i = 0; i < sprites.Length; i++)
        {
            replaceMatchingSprite (loadedRenderers, sprites[i]);
        }
    }

    void replaceMatchingSprite (SpriteRenderer[] loaded, Sprite newSprite)
    {
        for (int i = 0; i < loaded.Length; i++)
        {
            try
            {
                if (loaded[i].sprite.rect.x == newSprite.rect.x && loaded[i].sprite.rect.y == newSprite.rect.y)
                {
				    // we found a match, replaced loaded with new, we can have multiple matches
				    loaded[i].sprite = newSprite;
                }
            }
            catch (Exception e) 
            {
                // do nothing, we seem to get a few null values when looking through the loaded sprites, but seems we can safely ignore them :).
            }
        }
    }
}
                


March 2014
Devlog 1: Beard Quest

I have three active projects, Beard Quest is the most recent. Here's what I'm thinking: simple controls, deep combat (a mix between Zelda and Dark Souls); new take on dynamically generated areas, quests and secrets; and a NPC reputation / reaction system that I think is exciting. This will be my first RPG since Shadow Spire -- the first real game I ever built.

Everything is still early, very much at the concept phase. But here's how I'm thinking when it comes to story and setting. A small town will act as the adventuring hub, here you will meet NPCs, move along the story, blah, blah, standard stuff. The world will be ruled by 4 bosses, each possessing one of the sacred beards, beards so profound they are legends in and of themselves. Your quest will be to get the whiskers from each of these beards in the hopes of creating the Great Beard Oil! An oil so potent no mortal can resist its charms. Why are you doing all this? Love of course. Perhaps with the Great Beard Oil you'll finally beable to win the love of the Princess and live happily ever after.

I want the art to feel like a children's storybook, but with action-adventure undertones: fantastic and magical, but serious as well. Solid tones, basic shapes, simple lighting and a bold color palette will hopefully get me there.

For the procedurally generated areas I'm going to try and thwart the problem of walkthroughs ruining a game experience by making the experience entirely random. I think this will require a slightly different approach from what we see in a Diablo, Dungeon Defenders or Heroes of Loot, and... it might not work, but I have some solid ideas that I'm excited to try out.

Lastly, the reaction system is something I came up with 8+ years ago. It's all about making your interactions with the world and its NPC feel more real, and have a more realistic impact on your adventure. I'll hold off on saying more about this for now, but if I can make it happen it really could be a great technical step for game immersion.

So that's it for now. I'm going to start by focusing on combat, with any luck I'll have a demo out by the end of next week. If you have any questions, ping me on twitter or at feedback@2tonstudios.com. Cheers!


March 2013
Unity3D: 2D Character Controller

I've seen a ton of people struggling with implementing a 2D Character Controller in Unity. If you've tried and stuggled you know what I'm talking about if you don't then here is a quick summary. Unity is fundamentally a 3D engine, so of course it has a Character Controller optimized for 3D. This controller has a capsule collider - that means it's bottom is round. For a classic 2D platformer ala Meat Boy, Mario, Mega Man, etc you don't want a capsule, you want a block. A block that doesn't bounce, slide off edges and can balance on a platform as long as 1px of it is making contact.

For NinjaBoy I hacked up a version of the Character Controller and got it working well enough to ship, but it wasn't perfect. In a few edge cases Tadeo (the game's hero) would get auto-pushed off of a platform, or slide off the edge of a platform after a perfectly vertical jump - neither would be acceptable in a classic platformer. Given that our next game is also going to be a 2D platformer, I decided to spend the afternoon building a new Character Controller, one that actually works like it should.

I started by searching the web and found WS Barth's code. Although it's a fantastic jumping off point, it doen't handle the rounded bottom issue. So after a few hours I ended up with the code below. I feel it's a solid starting point for a 2D controller -- there is of course a lot more you could do to it like adding double jump, invisible step jump, etc. By the way, I am in no way the world's best programmer, so there are probably much smarter ways to write this.

In addition to the source, here is a link to a Unity Web Demo of the 2D Char Controller in action. I hope you find some of the useful and of course if you find any bugs please ping me on Twitter or Facebook (links above) - thanks in advance.

using UnityEngine;
using System.Collections;

public class HeroController : MonoBehaviour
{
    public float Gravity = 21f;	//downward force
    public float TerminalVelocity = 20f; //max downward speed
    public float JumpSpeed = 10f;
    public float MoveSpeed = 10f;

    private Vector3 MoveVector { get; set; }
    private float VerticalVelocity { get; set; }

    private Vector3 LeftSideStart, LeftSideEnd, RightSideStart, RightSideEnd;

    private Transform _transform;
    private CharacterController _characterController;
    private bool fauxGrounded = false, leftSide, rightSide;
    private RaycastHit leftSideHit, rightSideHit;
    private float sideHitLength = 0.7f;
    private float fauxY;

    bool isGrounded
    {
        get
        {
            bool ret = false;

            // first we check to see if the character controller thinks we are grounded
            ret = _characterController.isGrounded;

            // test the left and right side of the character controller capsule
            // these two tests effectively extend the sides of the capsule to be square, 
            // rather than rounded
            //
            // OPTIONAL: 
            // For NinjaBoy I put in an 'invisible step' which made it easier to pull off 
            // some of the harder jumps. Basically it means that the hero can walk in the 
            // air a bit and still perform a jump. You can accomplish that effect by simply 
            // widening the 'X' position of the left and right linecasts if the hero is running.
            // If they are standing still then you keep them snug to their body.
            //
            leftSide = Physics.Linecast(_transform.position + LeftSideStart, 
                _transform.position + LeftSideEnd, out leftSideHit);
            rightSide = Physics.Linecast(_transform.position + RightSideStart, 
                _transform.position + RightSideEnd, out rightSideHit);

            // if either side is touching then we're colliding with the 'faux' ground and 
            // should be standing on it
            if (leftSide || rightSide)
            {
                ret = true;

                // draw lines are debugging sugar, don't need these
                if (leftSide) Debug.DrawLine(_transform.position + LeftSideStart, 
                    _transform.position + LeftSideEnd, Color.green, 0.2f);
                else Debug.DrawLine(_transform.position + LeftSideStart, 
                    _transform.position + LeftSideEnd, Color.red, 0.2f);
                if (rightSide) Debug.DrawLine(_transform.position + RightSideStart, 
                    _transform.position + RightSideEnd, Color.green, 0.2f);
                else Debug.DrawLine(_transform.position + RightSideStart, 
                    _transform.position + RightSideEnd, Color.red, 0.2f);

                // reset the faux ground, we want to always be able to fall off an edge                
                fauxGrounded = false;

                // if we moving downward, then we want to snap the hero up, rather than 
                // letting them slide down the edge of a platform because their collision 
                // really has a rounded bottom
                if (MoveVector.y < -0.1f)
                {
                    if (leftSide && rightSide) fauxY = rightSideHit.distance < 
                        leftSideHit.distance ? rightSideHit.distance : leftSideHit.distance;
                    else if (leftSide) fauxY = leftSideHit.distance;
                    else if (rightSide) fauxY = rightSideHit.distance;
                    
                    fauxY = (sideHitLength - fauxY) - 0.17f;
                    fauxY = _transform.position.y + fauxY;

                    fauxGrounded = true;

                    Debug.Log("rt: " + rightSideHit.distance + ", lt: " + 
                        leftSideHit.distance + ", fauxY: " + fauxY);
                }
            }
            else
            {
                fauxGrounded = false;
            }

            return ret;
        }
    }

    // Use this for initialization
    void Awake()
    {
        _characterController = gameObject.GetComponent("CharacterController") as CharacterController;
        _transform = _characterController.transform;

        LeftSideStart = new Vector3(0.5f, 0, 0);
        LeftSideEnd = new Vector3(0.5f, -sideHitLength, 0);

        RightSideStart = new Vector3(-0.5f, 0, 0);
        RightSideEnd = new Vector3(-0.5f, -sideHitLength, 0);
    }

    // Update is called once per frame
    void Update()
    {
        checkMovement();
        HandleActionInput();
        processMovement();
    }

    void checkMovement()
    {
        //move l/r
        var deadZone = 0.1f;
        VerticalVelocity = MoveVector.y;
        MoveVector = Vector3.zero;

        if (Input.GetAxis("Horizontal") > deadZone || Input.GetAxis("Horizontal") < -deadZone)
        {
            MoveVector += new Vector3(Input.GetAxis("Horizontal"), 0, 0);
        }
    }

    void HandleActionInput()
    {
        if (isGrounded &&
            Input.GetKeyDown (KeyCode.Space))
        {
            jump();
        }
    }

    void processMovement()
    {
        // transform moveVector into world-space relative to character rotation
        MoveVector = transform.TransformDirection(MoveVector);

        //normalize moveVector if magnitude > 1
        if (MoveVector.magnitude > 1)
        {
            MoveVector = Vector3.Normalize(MoveVector);
        }

        // multiply moveVector by moveSpeed
        MoveVector *= MoveSpeed;

        // reapply vertical velocity to moveVector.y
        MoveVector = new Vector3(MoveVector.x, VerticalVelocity, MoveVector.z);

        // apply gravity
        applyGravity();

        // move character in world-space
        _characterController.Move(MoveVector * Time.deltaTime);

        if (fauxGrounded)
        {
            _transform.position = new Vector3(_transform.position.x, fauxY, 
                _transform.position.z);
        }
    }

    void applyGravity()
    {
        if (MoveVector.y > -TerminalVelocity)
        {
            MoveVector = new Vector3(MoveVector.x, (MoveVector.y - Gravity * Time.deltaTime), 
                MoveVector.z);
        }

        if (isGrounded && MoveVector.y < -1)
        {
            MoveVector = new Vector3 (MoveVector.x, (-1), MoveVector.z);
        }

        // this handles head hits, you can tweak the 'Y' value to have a slower of 
        // faster decent a value of -1.0f, felt right to me
        if ((_characterController.collisionFlags & CollisionFlags.Above) != 0)
        {
            MoveVector = new Vector3(MoveVector.x, -1.0f, MoveVector.z);
        }
    }    

    public void jump()
    {
        if (isGrounded)
        {
            resetFauxGround();
            VerticalVelocity = JumpSpeed;
        }
    }

    private void resetFauxGround()
    {
        fauxY = 0;
        fauxGrounded = false;
    }
}
                


Older
The Imp

Winged guardians of Master Sentaro's Tower. Taking many forms, these devious little suckers will stop at nothing to protect their master's home.

Sentaro's Tower will be the first endless area added to NinjaBoy. We'll be taking lots of inspiration from the classic "3 lives" style games, but putting a modern spin on things. The Imp is the first of several monster concepts we'll be revealing over the next few weeks.

Also planned for the update: Game Center, tons of new Easter Eggs, new Ninja Suits, an unlockable Hero, and if time allows a new Story Area.

If you haven't already checked out NinjaBoy jump over to iTunes and grab it. Our sales suck :) but reviewers love it, so help spread the word!

NinjaBoy - 2 Ton Studios

Indie Game Magazine 85%
Arcade Life 95%
Slide to Play: Under The Radar - Game of the Week
iPhone Life 8/10
App Shack 8/10


Older
NinjaBoy ships!

After 8 hard months of work, NinjaBoy has passed the Apple review process and is now available world-wide on iTunes!

We put a ton of effort into this version of the game. Moving to iOS meant a completely new game. We added 30 new levels, redid all the art, animations, sound fx and music. Reworked much of the game, pacing and level design. And, added a fantastic new shop, where you can spend money earned after each level to buy ninja suits, trinkets and potions. It's everything from the WP7 version that got us 190,000 downloads and an average rating of 8.7 / 10 from 4,000+ users, and then way way more :).

NinjaBoy - 2 Ton Studios


Older
Trailer - NinjaBoy iOS!

With any luck NinjaBoy will be available for iPhone and iPad world wide in the next few weeks. Check out the trailer below.

NinjaBoy is a puzzle-platformer. It's about avoiding traps, collecting stars, solving puzzles, and out-smarting enemies.

Guide young Tadeo through all 80 levels and defeat Lord Hito. Challenge yourself by avoiding all the traps, sneaking around all the enemies, mastering Dragon Chop, and gathering all the stars to unlock the Yellow Jumpsuit. Strive for elite gamer status by earning 80 Grandmaster Badges and unlocking the Shadow Guise Ninja Suit.

The Kingdom has fallen. Lord Hito now rules with an iron fist. During the battle, Master Minoru and his youngest pupil, Tadeo, managed to escape. Hidden away in a forgotten temple, the young ninja trains in hopes of defeating the Dark Lord and restoring freedom to the Kingdom.


Older
NinjaBoy iOS coming soon!

I know we've been very silent for several months, but I'm here to say we're back and couldn't be more excited about where we're at. NinjaBoy, now just under 200,000 downloads and 5,000 reviews on Windows Phone 7 is coming to iPhone and iPad!

This is our first iOS game and we really tried to step-up our game for the very competitive platform. NinjaBoy iOS is a complete rewrite of NinjaBoy WP7. Everything from the in-game art, to level design, to the monsters have been reworked. We now feature now a rich story complete with cut scenes, in-game magic shop where you can use gold earned after each level to buy ninja suits, potions and trinkets, 80 carefully crafted levels, voice overs, a new sound track, completely new sound effects, and ninja rankings for each level.

We poured a ton of effort into this version of NinjaBoy and really hope you enjoy it; below are some in-game screen shots. In the next few days I'll be posting a gameplay trailer as well as a dev diary on the journey of going from WP7 to iOS, the tools we used, etc.

Before I sign off, I just wanted to say thanks to everyone that supported us in making this release happen. A special thanks to all the Windows Phone 7 fans, whose feedback has been invaluable, Mika Mobile for pointing us in the direction of the amazing Unity 3D, Rocket 5 Tutorials for helping us build our first iOS platfomer, our friends and family that did such an amazing job with game testing, sound effects, and music, and, the incredibly helpful community of indie gamers that make it possible for two brothers to realize ideas on their own.

One last note to our Windows Phone fans. As soon as Unity supports Windows Phone we will make sure the new and improved NinjaBoy is available for you guys.


Older
Concept art - Space Commander

Check out some of our concept art for our next game Space Commander. We're confident that in-game visuals will be as good if not better than the concept art, but we can't officially claim that yet, because we haven't started writing code :). Below is the concept work for our hero, to see a fuller set of concept art, including level mockups, check out our In the Works section. Enjoy!


Older
Progress Update - NinjaBoy

Wanted to let you guys know how we're progressing on our NinjaBoy update. Firstly, it's gone very slowly, our day jobs have been insane. One of us had 6 months of required overtime and 6-7 day work weeks trying to land our company's latest product.

In addition, we continue to learn about and evaluate alternative technologies and platforms for our games. At the end of the day there is still very little money to be made on WP7. It's sad but true. We love the phone and still believe it has lots of potential, but it hasn't grown nearly as fast as we'd hoped. As a result things like iOS and Android become more interesting.

We have currently landed on using Unity for porting NinjaBoy and future projects. We'll let you know how it goes and hope to get back to NinjaBoy WP7 soon. Cheers.


Older
Sneak Peek - Howling Rise

After getting swept away by our day jobs and working hard to explore other revenue opportunities for our games, we're back to focusing on our next content update for NinjaBoy.

We're happy to say that our work to find other revenue opportunities has paid dividends and we're very close to announcing the availability of NinjaBoy on platforms beyond WP7. Expect to hear something about that effort in the next few weeks.

Although we've still got a fair amount of work ahead of us before we finish NinjaBoy's next WP7 content update, we wanted to let you guys know what we're up to. Since you've been so great about downloading, reviewing and sharing NinjaBoy, we felt it was only right to give you an early preview of what to expect with our next update.

The aside image provides a sneak peek of Howling Rise, the first of two new adventure areas we have planned. In addition to all new art, Howling Rise will feature two new enemies, a new ability for Tadeo, and what we hope are a great set of challenging but enjoyable puzzles. Like the original two areas, Howling Rise will be home to 25 unique handcrafted levels, and like Hito's Yard the final level will pit you against the master of the area in a challenging boss battle.

Although we don't want to reveal too much at this point, we did want to assure you that we're putting a lot of energy into this update, expect a ton of exciting new gameplay mechanics and puzzle elements. In Howling Rise many of these mechanics will revolve around the dark arts, shadow magic and necromancy. Taking center stage will be our two new enemies the Necromancer and Ethereal Ninja.

As many of you know a necromancer is a master of the undead and spirit world. His ability to manipulate the unseen world around him will factor heavily into the types of challenges and opportunities he poses to Tadeo.

The Ethereal Ninja is the second new enemy and we're very exicted about what he brings to the experience. Of physical form but powered by the spirts of the underwold, he blurs the line between living and undead. This ability to be a "living ghost" opens up the possibilty for puzzles and gameplay mechanics that we think will be very cool.

Aside from Howling Rise, the next content update will feature a fourth area which we're pretty far along on, but aren't ready to talk about just yet, as well as some other new gameplay experiences that we hope you'll really enjoy.

I'd love to give a firm date as to when the next update will ship, but that just wouldn't be fair to anyone. Trust that we'll work as hard and as fast as we can to deliver an expeirence that live's up to the 2 Ton name and we very much hope you'll agree was worth the wait.

Cheers!


Older
Level up? NinjaBoy reaches 100k downloads

Just as we annouce our sneak peek of new content, NinjaBoy hits 100k downloads! Thanks to all our fans for getting us to this very cool milestone. Cheers!


Older
BLiTTER + TWiSTED interviews 2 Ton Studios

An exclusive interview with the very cool and comprehensive tech, gaming and entertainment blog BLiTTER + TWiSTED has just gone live. Learn about my favorite games, how I got into gaming, my first cell phone, WP7 development and my thots on XBL :). Cheers and a special thanks to BLiTTER + TWiSTED for contacting us and being so darn great about putting it together!


Older
NinjaBoy on sale

We're putting the paid, ad free, version of NinjaBoy on sale this weekend. You can now get it for 99 cents on the Marketplace. At the end of the day we think 99 cents is the right price for this and most of the other WP7 games, but the higher priced XBL tiles strongly encourged us to price it higher. Rather than play the if you can't beat 'em, join 'em game, we're going to sell it for 99 cents and see if we can't start a bit of a trend :). Cheers and enjoy!


Older
NinjaBoy reviewed - Windows Phone Daily

NinjaBoy just got a great 9/10 review from Windows Phone Daily. A big thanks to this up and coming WP7 blog for taking the time to not just review the game, but play it from start-to-finish so they could fairly evaluate all of the hard work we put into it.


NinjaBoy hits 30k Downloads older

The new numbers are out and NinjaBoy just hit 30,000 downloads! Thanks to everyone that has downloaded, shared and reviewed NinjaBoy. Getting to 30k at all is fantastic, making it there so quickly really means a lot. So again, thanks!


Older
NinjaBoy - close after level complete

The source of the bug in NinjaBoy that causes the game to close after you complete a level has been located. It has to do with region and language settings. If you switch to en-US the issue goes away. This has now been confirmed by 2 players in different non-US countries.

I realize this is not a true fix, but at best a workaround. The bummer is there is little I can do about it - nothing in my code is region specific :|. I'm pinging Microsoft everyday to try and get some help here, but have yet to make much headway. As soon as I have a real fix or update from Microsoft I will post info here.

Again, so sorry for the hassle and thanks for understanding. Cheers!


Older
NinjaBoy reaches 10k downloads

Just a quick post to thank everyone for getting NinjaBoy to 10,000 downloads in just two days! We're very happy that so many people are enjoying NinjaBoy and look forward to deliver heaps of great content over the next few months. Cheers!


Older
NinjaBoy hits 1,000 reviews

Thanks so much for all the great reviews! This morning we hit 1,000 worldwide reviews for NinjaBoy with an average rating of 9.2/10. Hitting this in less than a week really makes us proud.

As indie developers reviews are really the best way for other people to see our hard work. To date we've made almost no money on our games, so we can't afford things like marketing. Any marketing we do get comes as a result of our fans sharing with friends and giving us reviews. Again, thanks so much, we really appreciate it and hope to deliver more great content in the near future!


Older
NinjaBoy rated #2 overall

The accolades for NinjaBoy keep pouring in and it's all thanks to our fantastic fans!

Earlier this week NinjaBoy made it all the way up to the #2 rated game on the entire phone (games or otherwise) based on Bing Visual Search for WP7.

This truly blew us away! To make it that high after less than a week on the marketplace is just so cool. It really lets us know that what we're doing is truly valued.

Thanks so much to everyone that has reviewed, downloaded and shared NinjaBoy with others. We put a ton of work into this one and it's really great to see it so well recieved.


Older
NinjaBoy ships!

NinjaBoy is in the marketplace! We're especially proud of our work with this one. Our goal was to make a ninja game that focused on the non-combat side of ninjadom :). Sure NinjaBoy still has combat elements, but we feel its obstacles, monsters, platforming and puzzles are it's best attributes. We really hope you'll agree it's a good twist on things.

You'll notice that the first version ships with two areas. The first, the "Dojo" intros you to the core gameplay mechanics. "Hito's Yard" (the second area, unlocked after getting 70+ stars) showcases the richer gameplay mechanics, specifically with monsters, that we hope to continue in future areas. Over the next year we will release many more areas, and look forward to unfolding the entire NinjaBoy journey for you guys.


Older
Akiak v1.4

Akiak version 1.4 just shipped! We've added a new course, Easter Forest as well as a new present, the Swimming Fin, to the classic Arctic Dash course. v1.4 also sees us switch to in-game Ads - rather than just at the gameover screen. After much consideration, we've decided that this is the best way to monitize Akiak. We hope you agree that displaying Ads in-game while still allowing it to be free is a good way to go. Of course we'd love to hear what you think about this change, so feel free to mail us at feedback@2tonstudios.com. Thanks!


Older
Akiak hits 1,000 reviews

We're proud to announce that Akiak hit 1,000 worldwide reviews earlier today, with an average review score of 8.7/10. Thanks to everyone that gave us a review, they help a lot and let us know we're heading in the right direction with our games!


Older
Akiak hits 20k downloads

We're happy to say Akiak passed 20k downloads this week. Thanks to all of you that supported us and keep spreading the word... maybe we can get to 40k :).