Gamieon is a privately owned entertainment software development company located in Tampa, Florida. Since October of 2004, we have aimed to provide quality video game software which emphasizes both intellectual and action-driven challenge to the gaming community. Gamieon depends on the talent of individuals working as a team to develop video games and video game engines with a focus on exceptional game play and surrealism.

Blog RSS Feed Report abuse My First Unreal Editor Soccer AI Simulation

0 comments by Gamieon on Sep 16th, 2014

Though I'm still new to the Unreal Editor and behavior trees, I wanted to create a primitive soccer simulation for a game I'm prototyping. You can get the code in its current form at:

Github.com


Getting Started

The first part of my journey was learning how "Blueprints" work in the Unreal Editor. I consider a blueprint to be a graphical representation of code. By graphical I mean both pixels-on-the-screen and boxes-connected-to-other-boxes-by-pointy-arrows. You can learn more about how they work at:

Docs.unrealengine.com

The second part of my journey was learning how "Behavior Trees" work. Buried in Google search results full of complicated papers and tutorials that blew my mind, I managed to find this little gem:

Indiedb.com

That article clicked with me and I felt like I understood the basics after just one read.


Setting the Rules

My first step into creating a soccer simulation was to establish a purpose and basic rules for the simulation:

  • The objective is to get the soccer ball into the enemy goal.
  • Each team has eleven players on the field at a time.
  • Each player is confined to an area on the field which I call "action zone."
  • Each player's purpose is to contribute to the objective for their team.
  • A player's only interaction with the soccer ball is to kick it into the goal or to a teammate.

Seen here is the reference I chose for assigning field positions for a soccer game

Sportspectator.com


Entities

With the rules established, I made a list of the different entities on the field that need to be tracked by a single player:

  • Ball
  • Enemy goal
  • Teammates
  • Enemy players

Note the absence of the role of the friendly goal. After several failed attempts at developing the behavior tree, I decided to create a tree that was to be used by every player; everyone from the goalie to the offensive players. I'm not going for perfect; I'm going for simple until I get better at this. Since none of my tree logic factors in the friendly goal, I'm not counting it as an entity here.

Binary Decision tree

I'm new to behavior trees but not to basic problem solving. After several failed attempts, I came up with a simple decision tree that I could apply to every player on the field:

code:
- Is the ball in a goal?
  Yes
  - Is it in your goal?
    Yes
    A. Celebrate
    No
    B. Shrug
  No
  - Do you possess the ball?
    Yes
    - Are you close to the goal?
      Yes
      - Is there an obstacle in the kick line?
        No
        C. Take a shot
        Yes
        - Is it an enemy?
          Yes
          - Is another nearby teammate not close to any enemies and unobstructed?
            Yes
            D. Pass the ball toward the teammate
            No
            E. Run around enemy toward goal
          No
          F. Run around obstacle toward goal
      No
      - Is another teammate in front of you closer to the goal, not close to any enemies and unobstructed?
        Yes
        G. Pass the ball toward the player
        No
        H. Run toward goal
    No
    - Does a player on your team have possession of the ball?
      Yes
      - Are there enemies within a close distance to the player?
        Yes
        I. Pursue enemy closest to player
        No
        J. Run in parallel direction to friendly possessor up to the goal
      No
      - Does an enemy possess the ball?
        Yes
        K. Pursue enemy
        No
        - Is an enemy in the line between you and the ball?
          Yes
          L. Pursue obstructing enemy
          No
          M. Pursue ball

Notice how the farther down in the tree you go, the farther away you are from the purpose of the simulation which is to get the ball into the enemy goal. Here's a summary view of it in reverse order; note how it generally follows the progression of a soccer game:

  1. Go after the ball
  2. Pursue the enemy who possesses the ball
  3. Have the team maintain ball control and work with teammates to get the ball to the goal
  4. Kick the ball into the goal
  5. Celebrate the goal


What Does "Pursue" Mean?

When a player pursues the ball, all they're doing is running to it. Once the player overlaps the ball's collision sphere, the game assigns them possession and the ball will always be in front of their feet no matter how they turn or run. The only way that a player can lose possession is if they or an enemy player kicks the ball away.

When a player pursues an enemy, all they do is run up to them and kick the ball away if they have possession. As I plan for this game to involve on-field fighting ala League of Legends or Diablo 3, I'm purposefully not doing anything more with player pursuits until I design the battle system.


Leaf actions (tasks)

Once I had a decision tree I was content with, I turned my attention to the leaf actions in the tree and grouped them by purpose:

code:
1. GoalFanfare (Is the ball in a goal?)
  A. Celebrate
  B. Shrug
2. ScoreGoal (Do you possess the ball?)
  C. Take a shot
  D. Pass the ball toward the teammate
  E. Run around enemy toward goal
  F. Run around obstacle toward goal
  G. Pass the ball toward the player
  H. Run to goal
3. DefendPossessor (Does a teammate possess the ball?)
  I. Pursue enemy closest to player
  J. Run in parallel direction to friendly possessor
4. AttackPossessor (Does an enemy possess the ball?)
  K. Pursue enemy possessor
  L. Pursue obstructing enemy
5. Pursue the ball (Nobody possesses the ball)
  M. Pursue ball

This list helped define the general shape and traversal of my behavior tree:

The behavior tree would have a root node with five children below the root. Each child node would have one or more children of its own called "leaf" nodes since they themselves have no children. The tree traversal would start at the root node, then go through the child nodes from left to right until it finds one that is true. From there all of the leaf nodes (which from hereon I'll call "tasks") for that child are traversed from left to right until an action is decided on and performed by the player.


Spltting up Tasks

Now that my behavior tree prototype was done, I had to make some decisions: Should I split any tasks into new subtrees with their own tasks? What functions do I need to write? Would I share data between tasks?

I decided to start by breaking up the tasks by modularity. In Unreal Editor a task is a standalone function which you may create and use in more than one place in a behavior tree. Tasks have access to shared variables stored in a "blackboard" which any task can read or write from. I looked at what tasks I could possibly modularize:

code:
1. GoalFanfare (Is the ball in a goal?)
  A. Celebrate
  B. Shrug
2. ScoreGoal (Do you possess the ball?)
  C. Take a shot
  D. ** Pass the ball **
  E. ** Run to goal (use Unreal's internal pathfinding to avoid obstacles) **
  F. ** Run to goal (use Unreal's internal pathfinding to avoid obstacles) **
  G. ** Pass the ball **
  H. ** Run to goal (use Unreal's internal pathfinding to avoid obstacles) **
3. DefendPossessor (Does a teammate possess the ball?)
  I. ** Pursue enemy **
  J. Run in parallel direction to friendly possessor
4. AttackPossessor (Does an enemy possess the ball?)
  K. ** Pursue enemy **
  L. ** Pursue enemy **
5. Pursue the ball (Nobody possesses the ball)
  M. Pursue ball

I broke every task with ** in two: One is the modular task that can be used in multiple places in the tree, and the other is the task that calculates what data to give to that modular task. I changed my behavior tree to look like this:

code:
1. GoalFanfare (Is the ball in a goal?)
  A. Celebrate
  B. Shrug
2. ScoreGoal (Do you possess the ball?)
  C. Take a shot
  D1. Find a nearby teammate we can pass to
  D2. ** Pass the ball **
  E1. Determine if an enemy is obstructing our route to the goal
  E2. ** Run to goal **
  F1. Determine if a non-enemy actor is obstructing our route to the goal
  F2. ** Run to goal **
  G1. Determine if there is a player closer to the goal we can pass to
  G2. ** Pass the ball **
  H. ** Run to goal **
3. DefendPossessor (Does a teammate possess the ball?)
  I1. Determine if an enemy is near the possessor
  I2. ** Pursue enemy **
  J. Run in parallel direction to friendly possessor
4. GetPossession (Ball is still in play but nobody on our team possesses it)
  K1. Determine if an enemy possesses the ball
  K2. ** Pursue enemy **
  L1. Determine if an enemy is in the way between you and the ball
  L2. ** Pursue enemy **
  M. Pursue ball

I needed only two Blackboard variables for passing data from one task to another:

  • KickTargetActor (read by "Pass the ball" and "Take a shot")
  • PursuitActor (read by "Pursue enemy" and "Pursue ball")

Task Development

I won't bore you with how I developed the blueprint for each task here, but I will say that I tried to keep all of them small and modular where possible. I thought about posting screenshots but that would be like posting random snippets of code with no context. Instead you can see a screenshot of the final behavior tree here.

You may notice that the child nodes have "blue things" on them. Those are Unreal Editor-specific elements called "decorators." You can use them as a switch to tell the traversal whether it should iterate through the tasks for that child node. Here's the complete blueprint for my decorator that informs the traversal whether the soccer ball is in a goal:

Task Testing

While developing tasks I bounced back and forth between blueprinting and testing to make sure all my changes worked. It was after all the tasks were written that I got the idea to write manual "Unit Tests." I would create one scene for each behavior tree traversal to verify it worked through manual observation. This definitely helped because two of the "Unit Tests" revealed bugs that would have been much harder to pin down in a full simulation. Here are some poorly lit screenshots of:

  • A player kicking the ball into the net
  • A player passing to a teammate that is farther away from a row of enemies than another teammate
  • A 2v2 clump of players pursuing the ball


I'm aware that in Test-Driven development one is supposed to write unit tests first rather than later...so to all you developers I've offended out there by writing them last: Deal with it! Posted Image

Final Product

Here are some screens and a video of more test scenes and a single team on a field. The screens go in progression from the start of the simulation to the end:


Implementation concerns

  • In the game the tree traversal always goes through all child nodes instead of stopping at the first one whose decorator returns true. I need to fix that.
  • I created a class inherited from GameMode as a hub for global functions and variables (such as the soccer ball). I suspect I'm not supposed to do this but I don't know a better place for them.
  • In each task I cast the owning actor input variable to an AI controller, then call GetControlledPawn, then cast that result to a BotTeammate to get the actual character on the field. It seems like a lot of work to get access to that character class...
  • I really wanted the human characters and bots to have identical interfaces so I wouldn't have to do "if (bot) {} else if (player) {}" branches, but haven't figured out how yet.
  • The editor recently acquired an incessant desire to rebuild the navigation area every time I start a simulation. It happens after a fresh launch of the editor after I start modifying blueprints.
  • This: Answers.unrealengine.com . I resolved my issues by having traces only look for pawns. If I ever decide to add static obstacles to the field I'll have to come back to this.

What's next?

Now that I'm satisfied I can develop a basic soccer simulation, the next step is to start designing the game as a whole. As I wrote previously, I intend to have opposing players fight each other for ball possession. Fighting may include melee attacks, ranged attacks, and magic. It may involve launching attacks from a distance, or even team tactics where one player freezes an opponent before the other launches a localized lightning storm at them.

There's also the matter of letting players accumulate resources to spend on armor, weapon and skill upgrades for themselves and their bot teammates. At first I was thinking a Warcraft 3-like deal where you build structures and kill creeps...but decided it would make more sense to have creeps on the field and possibly special item shops (concession stands) on team sidelines. Regular shops could appear in-between matches. Should I have player leveling? Should I allow for instant action matches where all players start at the same level and no items for a competition of pure skill?

There's even the matter of configuring the bot teammates: Team captains could arrange the bot positions in defensive or offensive formations as well as define the aggression level for each bot. Perhaps a team captain would prefer that human players pursue the ball while bots do nothing but attack enemy players for example.

I should probably find some people to help me design all this; preferably those who have a lot of experience with MOBA's and balancing.

Check out my homepage and social feeds

And my projects!

Report abuse My First Excursion Into the Unreal Editor

0 comments by Gamieon on Aug 18th, 2014

While in-between major projects that use the Unity game engine, I decided to give the Unreal Editor a spin to see what all the hype was about. For those of you who just want to see the cool stuff first, here's a video of my first playable Gauntlet-like dungeon crawl prototype finished in about twenty five hours of work.

The assets were all imported from Unreal's marketplace. All I did was put everything together.

Getting Started

After getting through the first hour of "I have no idea what is going on" and then watching Unreal's tutorial videos, I started setting little goals for myself to learn how to do things. The first of these was figuring out how to turn off "Realtime" editor rendering since I didn't like my computer fans going full blast while I was idle. The second was to resign myself to do something simple yet neat looking.

Spotlight Test

My first accomplishment was adding a spotlight to a third-person tutorial scene and having it follow the player character. If the character stood on top of a button, the spotlight would turn off. If they got off, the spotlight turned back on. I briefly thought about developing an evade/infiltrate kind of game, but was more interested in making my own Mineralz/LoL/Tower Defenese game that took place in the old Wild West. Lets just call it "Lone Star Guns."

Lone Star Guns

The next accomplishment was prototyping the home base for Lone Star Guns. The heart of the base was a campfire. Surrounding the base and taking up most of the playfield would be rocks that you carve out to expand your base and create additional lanes for enemy zombies to come in from (thereby relieving pressure on the default lane). For prototyping purposes, I added only a few rocks around the base. There are also three resources you can have workers "mine" from: Food (crops), wood (trees), and a mine (metal). My interest faded after making a basic inanimate scene; I felt like I was borrowing too many ideas from other games and I wasn't doing any serious development anyway. I then decided to help my friend with a prototype for his version of "Gauntlet" by creating my own prototype first.

Gauntlet Clone

I set a goal to make my Gauntlet prototype resemble a Diablo 3 level. This was done by creating a landscape and carving out paths in it. I failed to make the landscape look like the bottom half of a cave (I'm pretty sure it wasn't designed for that) so I did a Google search for anything related to the Unreal Editor and caves. Lucky me, I found that Unreal had a Cave Effects demo on their marketplace. It was beautiful, and I wanted those assets in my scene! As I downloaded it I also noticed the Mixamo Animation Pack for character prototyping on the marketplace as well...PERFECT.

To keep a long story short: I replaced the landscape with a collection of rocks, added neat looking particle effects and materials all over the place, figured out how to make a flaming sword and put it in a character's hand, make the character throw fireballs, and make enemies spawn and get hit by fireballs.

After about twenty-five hours of playing with the Unreal Editor since installing it, I actually had a functional gauntlet-like prototype! I admit I took a real hack-and-slash approach to learning, but I wanted to see what I could accomplish by tinkering with the Unreal Editor at my own pace.

What's next?


Though I'm tempted to finish developing a game in Unreal, I'll be going back to Unity development once the studio I'm working with finalizes the design document for the new Paper Cowboys. Until then I'll probably do one or more of the following in my free time:

  • Look at what other features UE4 has to offer and put them in my own list with two measures: One for "difficulty level" and one for "coolness factor."
  • Look at UE4's asset importing. I'd like to know more about what file formats it supports and its thought process when importing meshes with textures
  • Learn more about materials and particle systems
  • Learn more about landscape generation
  • Create some basic AI
     

Check out my homepage and social feeds

And my projects!

Report abuse Unity Windows Phone 8 In-App Purchase Integration

0 comments by Gamieon on Jul 7th, 2014

The focus of this journal entry is on how I integrated In-App purchase capabilities into my Unity game. I'm not going to discuss strategies for earning money from players, or how I used the IAP assets once they were integrated.

Unity Setup for Zaubersee

I began by purchasing a Windows Phone 8 IAP Unity package by Zaubersee at Assetstore.unity3d.com to get things going. Like with other third-party Windows Phone 8 assets I've used, it didn't work out of the box. I also struggled a bit with my interpretation of the documentation. After creating a new Unity test project, importing the asset, and deploying to my Windows Phone, I got this error in the status window of the demo scene:

Exception from HRESULT: 0x805A0194

I overcame this error by submitting the test project as a beta app to the Windows Phone Dev Center. I believe the asset developer tried to explain this in the documentation, but I thought that submitting a beta version of the app was merely a suggestion.

Here's what I did to build a functional test project:

  • I created a beta version of Hamster Chase on the Windows Phone Dev Center.
  • For the beta version, I made a duplicate of every In-App product that already existed for the main version. I used the same product ID's.
  • I made a new Unity project, imported the In-App purchase asset, and built the project for Windows Phone 8.
  • I opened VS 2013 to the Windows Phone 8 project I built from the previous step, then opened WMAppManifset.xml under the Properties folder.
  • I went to the packaging tab and updated the ProductID and PublisherID values to be those of Hamster Chase Beta.
  • I made a Master build of the app, and submitted it to Windows Phone Dev Center. I made absolutely sure it was a beta, and not an app to be shown in public.
  • About an hour later I got an e-mail from Microsoft with the download link. I went there from my phone, installed the app, and the purchases worked!
  • Cleanup: From my phone, I went to the home screen, then Apps, then Games to find and uninstall the test app.

Taking this idea a step further, I opened the VS 2013 project for the real Hamster Chase, set the product ID to be that of the beta app, and then deployed it in debug mode to the device.

Since the test app worked well, I figured it would work the first time in my game...but it did not. The app crashed after the app was restored upon me dismissing Microsoft's purchase screen.

My guess is that in the onWP8inAppPurchased callback, I wasn't supposed to do stuff with Unity objects like changing TextMesh text values or calling Transform.GetChild(). I proceeded to move all that code into a function called DoStuffAfterPurchaseFinished(), and then I call Invoke("DoStuffAfterPurchaseFinished", 0.2f) within the callback. The crash went away after that.

Unity Setup for Prime31

I was about to move on entirely when I discovered that Prime31 was offering a free Windows Phone 8 In-App package (while the offer lasted) at Prime31.com . I've worked with Prime31's assets before, and I like their brand.

I decided to make a test app with Prime31's IAP package. Using the lessons learned from integrating Prime31's WinPhoneAds package and the Zaubersee package; I was able to quickly get a functional Prime31 In-App demo app.

I then imported the Prime31 package into the official Hamster Chase app, and tested it. To my surprise, I had the same crash I had with the Zaubersee asset when trying to manipulate GameObjects within the purchase completion callback. As before, the Invoke workaround made the crash go away.

Conclusion

In the end I got both the Zaubersee and Prime31 assets to work; but I decided to stick with the Prime31 asset primarily out of brand loyalty and the expectation of continued upkeep.

Check out my homepage and social feeds

And my projects!

Report abuse Unity Windows Phone 8 Ad Integration

0 comments by Gamieon on Jul 2nd, 2014

In one effort to monetize Hamster Chase, I wanted to have ads appear in it. It took me a while to decide where to put the ads; the articles at Inneractive.jira.com and Streetfightmag.com were helpful with my decision making. I decided to have ads appear briefly at the end of each level, and at random in the hamster cage in the form of a comic strip balloon coming out of a hamster's mouth.

Ad Portal Setup

I created an AdDuplex account on Adduplex.com . AdDuplex treated me as both someone who wanted ads in their game, and someone who wanted to put their own ads in other games. They wouldn't let me submit my game before it was published.

I created a Microsoft pubCenter account on Pubcenter.microsoft.com . I was able to create one "ad unit" (which is a fancy way of saying "an ad banner to appear in the game" I think), but I had trouble changing it later and adding more ad units. I was informed by an online help desk representative that I couldn't do those things until my game was published.

Unity Setup for AdRotator

My journey with Ad integration began with AdRotator v2 beta at Getadrotator.com . AdRotator supports multiple ad providers; a list is available at Getadrotator.com .

I made a new test project in Unity and imported the AdRotator Unity package into it. The first thing I noticed was the AdRotatorDemo scene had no AdRotator components in it. I figured out which ones belonged, and added them manually. Later on I discovered the menu item to do it: GameObject => Create Other => AdRotator. I clearly glazed right over "this will appear in the game object create menu" in their documentation; but in my defense I'm used to the vendor having the demo scene all set up for me.

I was puzzled by the setup: On the pubCenter and AdDuplex portals, I could choose the size of my ads. In the AdRotatorManagement script was a dropdown where I could choose the size of the banners; but none of the selections matched the sizes I assigned in the portals! I decided to just leave all the component settings unchanged.

My attention turned to defaultAdSettingsWP8. It's the file in the Unity project where you set up all your ad portal identities. I discovered I could comment out the elements corresponding to providers that I did not sign up for, and they would not be included in the rotation of served ads. I like how the developer filled everything in with demo values; it made it easier to confirm that the values I would replace them with were formatted correctly.

I then proceeded to Build and Run the project on my phone...and of course, no ads appeared. My first inkling was that I glazed over something else important in the documentation.

I opened the VS 2013 solution and ran it again. I got at least one System.IO.FileNotFound exception. Between seeing that, and revisiting the documentation, I found that I was missing several assemblies. I made sure to have the following References in my project:

  • AdDuplex.WindowsPhone
  • AdRotator
  • AdRotator.Core
  • Microsoft Advertising SDK for Windows (Silverlight)
  • Microsoft.Advertising.Mobile
  • Microsoft.Advertising.Mobile.Common
  • Microsoft.Advertising.Mobile.UI

I deployed the project to my phone again, and the only ads that would appear were test ads for AdDuplex. The debug log reported once that it successfully got a pubCenter ad, but I don't think it ever appeared. Subsequent attempts to get pubCenter ads failed with no error description ever since. It could have been that pubCenter simply had no ads available at that moment; I never figured out what happened in the end.

Unity Setup for Prime31

I was about to settle for only using AdDuplex ads when I discovered that Prime31 was offering a free Windows Phone 8 Unity package for pubCenter ads (while the offer lasted) at Prime31.com . I've worked with Prime31's assets before, and I like their brand. I grabbed it right away and built a test app with it. There was one issue I had trying to get it working: I got this message trying to complete a purchase:

System.UnauthorizedAccessException: Invalid cross-thread access.
at MS.Internal.XcpImports.CheckThread()

They quickly gave me a resolution which you can read at Support.prime31.com .

The test app worked fine after that; I was able to see pubCenter test ads. I understand that a provider doesn't want to feed live ads to a developer's test environment, but one of my peeves as a developer is not seeing a component work in live mode before the project is published. Right after the game was published, the test ads were replaced with live ads automatically.

Conclusion

In the end, I decided to run with Prime31 and pubCenter ads. I'd like to see AdRotator 2 mature a bit more before I consider using its capabilities. I don't know which ad provider is the best for my game, so I'm going to start with pubCenter. I won't be able to measure its effectiveness on Hamster Chase until the press release has been out for a while and more than a handful of people are playing it. Eventually I may try switching providers or my integration strategy to see if I can improve revenue.


Check out my homepage and social feeds

And my projects!

Report abuse Unity Windows Phone 8 Facebook integration

1 comment by Gamieon on Jun 30th, 2014

I wanted to add Facebook integration to Hamster Chase for Windows Phone 8 in an effort to have players get word out of the game through social media in exchange for a reward.

A search on Google led me to Chillster's Facebook SDK at Forum.unity3d.com . It was free and also fairly new. I had a fair bit of trouble getting it to do what I wanted because of limitations I wouldn't accept, and because of my interpretations of the instructions. Ultimately I got it working. Here's a walkthrough I would have presented:

Facebook Setup

1. First you need to add your Windows Phone 8 app to your Facebook developer dashboard. Do this by going to Developers.facebook.com and clicking on Apps at the top. If your app doesn't exist, use Create a New App and fill the proceeding form out.

2. If your app already exists (like you wrote your game for iOS/Android first), you still need to set it up. On the left side of the app's dashboard page on Facebook is a menu item for Settings. Click on it. Hidden beneath your existing platform listings is a "+ Add Platform" button. I swear I went to this page half a dozen times and never saw that button. Click on it and add your app product ID (which you get from your Windows Phone Dev Center account) to the second line. Remove the dashes and make sure you don't have curly brackets.

Phone Setup

I had to install the Facebook app on my phone before I could use Facebook integration.

Unity Setup

1. Add Chillster's Facebook SDK asset to your Unity project (or better yet make a test project).

2. Look up at your Unity menu bar (File, Edit, Assets...). There should now be a Facebook menu. Go there and choose "Edit Settings" and fill those out.

3. Now go to the link I mentioned at the start of this section (http://forum.unity3d.com/threads/facebook-sdk-for-unity-plus-windows-phone-8.217907/ ), and read Chillster's official documentation for getting set up starting with step 2.1. You've already done step 2.3, so you can skip that step.

Unity Usage

My goal was to make it so users could send app requests to friends which invited them to download my game. So when I found this in the code comments:

"... throw new UnityException("There is no Facebook AppRequest on Windows Phone 8"); ... "

I thought it was just an asset limitation. For a while I tried using FB.API() to get the job done starting with getting a friends list. I simply could not get that to work until I finally called"FB.API("me\friends"...)" (note the direction of the slash), and making sure to include the "user_friends" permission at the login. Then I tried a number of ideas to send an app request by using FB.API(); all failed. I ultimately settled for just doing a post on a player's feed by calling:

csharp code:
var wwwForm = new WWWForm();
wwwForm.AddField("link", "http://www.gamieon.com/hamsterchase");
wwwForm.AddField("linkName", "Hamster Chase for Windows Phone 8!");
wwwForm.AddField("linkCaption", myCaption);
FB.API("me/feed", Facebook.HttpMethod.POST, fb_OnFeedComplete, wwwForm);
 

It doesn't show the link name or caption in my feed; but I'm going to leave those in anyway in case they someday appear through either asset or Facebook-side updates.

Conclusion

I ultimately released Hamster Chase with Facebook integration. It works for posting to Facebook feeds, and it was nice to see it work without having to publish the game first (unlike other assets I integrated with). I'm sure it won't be long before future versions of Facebook integration assets are released with easier setups and more features; including app requests.


Check out my homepage and social feeds

And my projects!

Report abuse Porting Hamster Chase to Windows Phone 8 (Unity 4.5)

0 comments by Gamieon on Jun 1st, 2014

A couple weeks ago, a friend tipped me off to a free Microsoft Unity workshop that was held in Orlando, FL. Though reluctant at first, I decided to go. I needed to get out of my lone wolf developer cave, meet other folk, and see what Microsoft could do to help me port my mobile games to Windows Phone 8. Long story short, it was a good experience and I was on my way to getting those games ported.

Having released Hamster Chase for iOS and Android already, I figured getting it deployed to my Windows Phone would be a breeze...but it wasn't.

Upgrading the project to Unity 4

The first step was to make a branch of Hamster Chase for Unity 4. Right away I got a number of new compiler warnings; mostly about the GameObject.active setter being deprecated for GameObject.SetActive(). After fixing and re-testing all of the related code, I found another issue: in Unity 3.x, I would set certain objects to be "static" (motionless) objects at runtime when they wouldn't move, and then unset the static flag before they were to move again. I thought this would provide an optimization in rendering, and possibly with the physics too. In unity 4.5 at least, it would seem that once an object is static, it is always static and would never move again. I fixed this by simply never setting the static flag in the first place.

Those were the only two issues I dealt with during the upgrade process. With all the compiler warnings and static behavior fixed, I was ready to change the platform to Windows Phone 8.

Fun With Frameworks

After changing the platform, I attempted to build the project. Right away, I got errors related to my Prime31 Android & iOS plugins. Prime31 is an organization that develops plugins which enable developers to implement social network check-ins, ads and in-app purchases. It's a shame they also don't include a 'Monetization for dummies' manual with those plug-ins, but I digress. I wish I had retained the exact error messages for others to find on Google, but alas, I didn't think of it at the time. I ultimately fixed the errors by deleting all of the Prime31 plug-ins, and changing my side of the code to only look for them in the iOS and Android platforms.

My next build attempt gave me these more memorable error messages:

  • Error: 'WriteAllBytes' is not a member of 'System.IO.File'
  • Error: type `System.Xml.XmlDocument` doesn't exist in target framework.
  • Error: `System.Security.Cryptography.MD5CryptoServiceProvider` doesn't exist in target framework

There are three ways you can deal with these:

  1. In Unity, go to File => Build Settings => Player Settings. In your Inspector window, expand Other Settings, and change your API Compatibility Level to .NET 2.0. (Note: I had already fixed System.IO and my MD5CryptoServiceProvider compatibility issues before trying this, but I think it should work)
  2. Find an existing implementation that you can copy into your project.
  3. Write your own code to replace the functions provided by those frameworks.

I opted to do 3 to keep the binary size at a minimum; of course that took a fair bit of time to do.

A "Successful" Build?

After fixing all that, I managed to get Hamster Chase to deploy to an emulator. I noticed the splash screen was of Unity and not from the game; nor was there a setting to change the splash screen in the Player settings. I hope to deal with that from the Visual Studio project itself later. I was happy...

...and then my happiness was shattered once I got it deployed onto my new Nokia Lumia 521. I was barely getting 15 FPS on the device! The game was choppy, overlays that should have faded in instead went straight to fully visible, and popup menu animations were even choppier than the game.

After attaching the Unity profiler to my phone via IP address (it takes like 45 seconds to connect), I pinned the main problem to a GameObject.FindObjectsOfType being called in every frame. After fixing that, the game was slightly faster. It was still far from the silky smoothness I see in most mobile games. The main culprit is now transparent rendering which is taking up over half the workload each frame. In the main menu alone it takes 18ms per frame. I had the same problem with Hyperspace Pinball; and it took months to optimize it just enough to even be releasable. I am not going through that again.

Thinking the problem was that the VertexLit shader was slow on mobile, I decided to try my hand at writing two transparent mobile shaders:

Unlit Shader

code:
Shader "Mobile/Transparent/Unlit" {
    Properties {
        _MainTex ("Base (RGB) Transparency (A)", 2D) = "" {}
    }
    SubShader {
        Pass {
            // Only render pixels with an alpha larger than 50%
            AlphaTest Greater 0.5
            SetTexture [_MainTex]
            {
              combine texture
            }
        }
    }
}

Simple lit Shader:

code:
Shader "Mobile/Transparent/Simple" {
    Properties {
        _MainTex ("Base (RGB) Transparency (A)", 2D) = "" {}
        _IlluminCol ("Self-Illumination color (RGB)", Color) = (1,1,1,1)
    }
    SubShader {
        Pass {
            // Only render pixels with an alpha larger than 50%
            AlphaTest Greater 0.5
            SetTexture [_MainTex]
            {
              constantColor [_IlluminCol]
              combine texture * constant
            }
        }
    }
}

After using these on the most prominent main menu objects, I didn't get a visible performance gain.

What's next?

It occurs to me that Hamster Chase was developed before Unity had Sprites and Sprite Renderers. In Hamster Chase, the existing "Sprites" are rendered using regular MeshRenderers and VertexLit shaders on simple squares. I think if I changed my "Sprites" to be actual Unity Sprites, things would render faster. I'll have to ponder if and how I would accomplish that because it could easily be a ton of work.

I still have trouble wrapping my head around the fact the game is this slow as is using out of the box shaders on such a sophisticated piece of equipment. It's notably faster on both iOS and Android; what am I missing here?


Check out my homepage and social feeds

And my projects!

Report abuse Skillz iOS, Unity 3, and I

0 comments by Gamieon on Feb 24th, 2014

In December 2013 I entered into a small "venture" with the Skillz team to make a simple game called Tiltz Tournament where players could compete for game coins or real money. I developed the core game, and they provided the tools for matchmaking and account management. Here I write about my experiences in hopes other Skillz developers can benefit, find solutions to issues, and avoid the mistakes I made. This entry is laid out in six parts:

  • Getting the Unity project set up for Skillz
  • Getting the XCode project set up for Skillz
  • Setting up Parameters and Tournaments on the Developer Portal
  • Completing the Skillz integration in Unity
  • Completing the Skillz Integration in XCode
  • Testing production mode

If you're the impatient type like I am, just go to QUICK BUILDING REFERENCE to see how to build a Skillz-enabled game for your iPhone.

Getting the Unity project set up for Skillz

After the core game was created in Unity 3 and tested on my iPhone, I followed the instructions on the Skillz homepage to integrate their SDK into the Unity side of the game. Upon trying to import the Unity package, Unity crashed. This was because the package I got was exported from Unity 4 and is not compatible with Unity 3. My project would no longer open in Unity 3. I fixed it by doing the following:

1. Going into Finder and deleting the SkillzDelegate prefab from the project's folder.
2. Starting Unity
3. Making my own Skillz prefab by:

A. Making a new empty game object
B. Adding the Skillz and SkillzDelegate scripts to it.
C. In my Unity Project tab, click on Create, select Prefab.
D. Drag and drop the game object to the prefab.

Before continuing the integration, I wanted to make sure I could still build the project and deploy it to my iPhone. Since Skillz requires iOS 7, I had to go into my Unity project settings and make sure I maxed out my iOS version settings. Unity's deployment target only went up to 6.1, so I had to change the app deployment target to 7 from XCode later on. I also had to make sure my project was set up for iPhone only. I then proceeded to build the project from Unity so it would generate the XCode project.


Getting the XCode project set up for Skillz

XCode didn't open automatically because Unity 3 doesn't know how. Still, the iPhone assets were created, and I was good to move forward.

The first thing that tripped me up in XCode was that the deployment target (at the top left next to the Play and Stop buttons) was set to the simulator, so I got a bunch of build errors. I plugged in my iPhone 4 and made sure the deployment target was my iPhone.

I went to the General tab of the project, made sure the deployment target was iOS 7, and that the Device Orientation was only Portrait. Scrolling down further I noticed that some app icons were missing. Again, Unity 3 didn't know to put them there. I had to generate icons in the missing dimensions using The Gimp, and import them into my XCode project folder. Then I assigned them to the icons in the General tab.

I then followed Skillz' instructions to integrate their SDK into the XCode project.

After that, I tried building using the Command-B button. I got several linker errors indicating the std library was missing, and some Game Center-related functions were missing. A little puzzling, but I found the solutions. Under the Build Settings tab, I selected (All) and (Combined) at the top. Then I scrolled to the section called "Apple LLVM 5.0 - Language - C++." There was an entry for "C++ Standard Library." I set it to "libstdc++" and that fixed the std linker errors. After that, I went to the Capabilities section and turned on Game Center (it is bound to my Apple account so you may not have this problem).

I then attempted to build the app again, and it succeeded. I was then able to deploy it to my iPhone 4. Of course I did not actually invoke Skillz functionality in the project, so the app behaved just as it did before.

At the top of the screen was the pesky status bar (battery life, time, etc.). I made it go away in subsequent builds by going to info.plist, adding "View controller-based status bar" and setting it to NO.


Setting up Parameters and Tournaments on the Developer Portal

The next step was to set up the tournaments on the Skillz developer portal. My journey began on the page where I had to enter Parameters. It took me a while to realize that the Parameter list was a collection of every possible unique property of a game for any tournament, and the Parameter list values are the DEFAULT values that the tournament-specific parameters get populated with on the developer portal in the next page. In my game, the Parameters which defined a unique game were the duration of the game and the existence of obstacles. So on my developer portal, Tiltz Tournament has a grand total of two parameters called "TimeLimit" and "Obstacles". TimeLimit has no whitespace because I got errors trying to fetch "Time Limit" from the parameter dictionary from Skillz, and decided I didn't want to deal with it. The value of "Obstacles" is "On" because most tournaments have them turned on. The value of "TimeLimit" is "90" for the same reason.

As for the Tournament list, I could not add or remove entries. I could only change existing ones. Furthermore, the entry fee and player counts seem to be linked. I'm cool with that. I also decided I didn't need more tournaments than they had existing; having more than eight would be overwhelming to the player I think. I ended up using 5 tournament slots for myself, and renaming the other 3 tournaments to N/A so the Skillz team knew not to include them. One of the N/A tournaments was a special developer tournament where I made "TimeLimit" a value of 5. This enabled me to test the game ending due to the clock running out without having to wait 90 seconds.

By the way, after you fill out the Parameters and Tournament List, you go into sandbox mode automatically. Another important bit: You can ALWAYS GO BACK AND CHANGE YOUR TOURNAMENTS, PARAMETERS, AND MOST ANYTHING ELSE. I find that to be a particularly helpful facet of the Skillz developer portal.

Completing the Skillz integration in Unity

What threw me off the most was not understanding the flow that Skillz had intended for the game. The flow is basically this:

  1. Main Menu
  2. Skillz Interface - Game selection / matchmaking
  3. Game
  4. Skillz Interface - Game completion
  5. Skillz Interface - Game selection / matchmaking
  6. Game
  7. (repeat 4-6)
  8. Main Menu

The main menu is the launch point for a continuous back-and-forth between your game and Skillz. If a player quits from Skillz, only then should they be taken back to your main menu.

As I implemented the Skillz functionality into my game, I learned that the Skillz package doesn't seem to like Unity calling Application.LoadLevel from a Skillz callback; at least in Unity 3. When you write your game in Unity 3, you should make sure you have a reset function in one of your scene components so that you can effectively "reload" the scene without actually reloading it. Even if it doesn't crash for you like it did for me, you save yourself the time of reloading all the scene assets. Be sure that your reset function also pauses the music.

One thing I was not a fan of were the developer TODO comments in the Skillz scripts where I had to write my own code. This is because if I download a new package, I could overwrite their old scripts and therefore my changes to them. I wrote my own static class with functions to be called from Skillz's callbacks to minimize any pain of re-importing their scripts.

Completing the Skillz Integration in XCode

After finishing the Skillz integration on the Unity side, I was ready to take a test drive in sandbox mode on my iPhone. After building and running it, and learning the lessons that I wrote about above, I was able to get it working smoothly with two exceptions.

First, there was a bug where if you tilt your iPhone in a way ideal for landscape, and you quit the game, the Skillz interface would get all glitchy and messed up looking. I fixed this by opening Classes/AppController.mm, going to the function

(NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *window)

and commenting out the landscape enumerations so that they were not included in the return value.

Secondly, I noticed my app icon was missing from the Skillz interface next to the "Go back to " button. I never did figure out how to fix that.

Testing production mode

Now it was almost time to make the release. I turned off sandbox mode, uploaded an App Store-provisioned .ipa file to my Skillz developer portal, clicked the Sync button on the Skillz developer portal, then clicked on the Play button in XCode to build and deploy it to my iPhone. I kept getting this error when going into Skillz: "Sign Up Error - Invalid client serv request." After going back and forth with the Skillz team, I figured out that the problem was the manner in which I installed the app onto my phone. I fixed it by deleting the app from my iPhone, and then adding the .ipa file (the one I uploaded to Skillz) to my iPhone by using XCode Organizer. After doing that, the error was gone, and testing seemed to work out.

In subsequent builds, I got the same Sign Up error again because I had forgotten to upload and Sync my latest .ipa to the Skillz portal.

I also asked the Skillz team to help me test because I only have one device, and they have several they could test with at the same time. Besides that, it's also in their best interests that the game is solid Posted Image.

After all that, I had Skillz help me with the app description and the app rating. I then submitted the game to the App Store.

Post production

The first release of my app was with the Skillz 2.x SDK. I summarily made a new build with a 3.x version of the SDK. None of the Unity-side scripts appeared to change, though I made sure all of the non-Unity assets were updated.

I accidentally tested on a device that was not connected at the time. Once the game attempted to enter the Skillz portal, I got a notification that the device was not on the internet. Nothing happened after that for an indefinite period of time. This will be a cause of frustration for players, so in a subsequent update I will use Unity's functionality to determine whether the device is online when the player taps the play button. Keep in mind the device could still lose connection in the game (like if they're playing and get on an elevator, or they go out of wi-fi range). I informed my contact over at Skillz about it.


QUICK BUILDING REFERENCE (Dec 2013)

Here is the process I would undertake doing a build with Unity 3 from scratch in December 2013:

1. Follow the Skillz instructions for importing Skillz assets into your Unity game (but don't import any prefabs unless you're 100% sure they're Unity 3)
2. In Unity, make sure your build target is iPhone only and using the most recent iOS version settings possible. Make sure your orientation is Portrait.
3. In Unity, do a Build and Run. Select the Replace option (since I assume you want to build from scratch).
4. After Unity finishes what it's doing, open XCode to the created project if it's not there already.
5. Follow the Skillz instructions for integrating the Skillz SDK
6. Make sure your deployment target is iOS 7.0
7. Make sure your orientation is Portrait.
8. Make sure all your icons in the General tab of XCode are assigned.
9. Make sure all your necessary capabilities are assigned in the Capabilities tab of XCode.
10. Open Classes/AppController.mm, go to the function

- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *window)

and comment out the landscape enumerations so that they are not included in the return value.

11. Under Build Settings, scroll to the section called "Apple LLVM 5.0 - Language - C++." There is an entry for "C++ Standard Library." Set it to "libstdc++"
12. Go to info.plist, add "View controller-based status bar appearance" and set it to NO.
13. Connect an iPhone to your machine and make sure XCode is set to build and deploy to it.
14. Go to the Product menu and select Clean
15. Click on the Play button to build and run.

Check out my homepage and social feeds

And my projects!

Report abuse Fast Diamond Shader For Unity Android

0 comments by Gamieon on Nov 14th, 2013

When developing Domino Arena, I experimented with using diamond/crystal shaders for the dominoes while deciding the look and feel of the game. I found a mobile diamond shader at  Wiki.unity3d.com by BurningThumb. It worked great for most PC's (there was one report of the dominoes not rendering however), but it was slow on my Asus EEE tablet. I could not get a frame rate better than 30 fps during normal game play.

The Unity profiler revealed that much of the time spent working in each frame was with transparent rendering; partly because of the dominoes, and partly because I called GUI.DrawTexture() way too much (which I fixed).

I'm very inexperienced with shader development, but I figured the least I could try was commenting out all code in the shader that had the word "Transparent" in it. To my surprise it actually had the desired effect: The frame rate went back up to 60 fps, and the diamond dominoes still looked like diamond dominoes with an unexpected caveat: They look transparent where they did not before. I don't exactly know why (again, I'm not an experienced shader developer) but it wasn't a big deal since dominoes don't obstruct each other during normal game play anyway.

Here's the shader code I ended up with (you can tell which parts I commented out):

code:
Shader "FX/Diamond Mobile"
{
  Properties {
    _Color ("Color", Color) = (1,1,1,1)
    _Fog("Fog", Color) = (0,0,0,0)
    _ReflectTex ("Reflection Texture", Cube) = "dummy.jpg" {
      TexGen CubeReflect
    }
    _RefractTex ("Refraction Texture", Cube) = "dummy.jpg" {
      TexGen CubeReflect
    }
    _RefractTexlow ("Refraction LowGPU", 2D) = "dummy.jpg" {
      TexGen SphereMap
    }
    _ReflectTexlow ("Reflect LowGPU", 2D) = "dummy.jpg" {
      TexGen SphereMap
    }

    _Shininess ("Shininess", Range (0.01, 1)) = 0.7
        _SpecColor ("Specular", Color) = (1,1,1,1)
        _Emission ("Emissive", Color) = (1,1,1,1)
  }

  SubShader {
    //Tags {
    //"Queue" = "Transparent"
    //}
    // First pass - here we render the backfaces of the diamonds. Since those diamonds are more-or-less
    // convex objects, this is effectively rendering the inside of them
    Pass {
      Color (0,0,0,0)
      Offset  -1, -1
      Cull Front
      ZWrite Off
      SetTexture [_RefractTex] {
        constantColor [_Color]
        combine texture * constant, primary
      }
      SetTexture [_ReflectTex] {
        combine previous, previous +- texture
      }
    }

    // Second pass - here we render the front faces of the diamonds.
    Pass {
      Fog { Color (0,0,0,0)}
      ZWrite on
      Blend One One
      SetTexture [_RefractTex] {
        constantColor [_Color]
        combine texture * constant
      }
      SetTexture [_ReflectTex] {
        combine texture + previous, previous +- texture
      }
    }
  }

  // Older cards. Here we remove the bright specular highlight
  SubShader {
    //Tags{"Queue" = "Transparent"}
    // First pass - here we render the backfaces of the diamonds. Since those diamonds are more-or-less
    // convex objects, this is effectively rendering the inside of them
    Pass {
      Color (0,0,0,0)
      Cull Front
      SetTexture [_RefractTex] {
        constantColor [_Color]
        combine texture * constant, primary
      }
    }

    // Second pass - here we render the front faces of the diamonds.
         
    Pass {
      Fog { Color (0,0,0,0)}
      ZWrite on
      Blend DstColor Zero  
      SetTexture [_RefractTex] {
        constantColor [_Color]
        combine texture * constant
      }
    }
  }

/////////// Start iphone code////////////////
//This will cause a nice gem texture to be rendered using the low-GPU textures defined in the inspector//
//This section of the code is provided by BURNING THUMB SOFTWARE, 2010//

  SubShader {
        Pass {
         
    Lighting On
            SeparateSpecular On
         
      Color (0,0,0,0)
    //  Offset  -1, -1
      Cull Front
      //Blend OneMinusSrcAlpha One
      SetTexture [_ReflectTexlow] {
        constantColor [_Color]
        combine texture * constant, primary
      }
    }

    // Second pass - here we render the front faces of the diamonds.
    Pass {
   

      Fog { Color [_Fog]}
      ZWrite on
      Blend One One
      SetTexture [_RefractTexlow] {
        constantColor [_Emission]
        combine texture * constant
      }
    }
             
  }
 
  // We need this for shadows
  FallBack "Diffuse" 
}


If you want to see it in action, just check out my game Domino Arena when it comes to Android!

Check out my homepage and social feeds

And my projects!

Report abuse A Unity PlayerPrefs wrapper

0 comments by Gamieon on Nov 13th, 2013

With every new project I try to make better tools to carry into my future projects. One of them has to do with the game configuration and PlayerPrefs. There are two issues I have with PlayerPrefs:

  • Using PlayerPrefs.Get... is slow in an Update() or an OnGUI() function (at least it was for me on mobile), and you have to grab the value in Awake() or Start() into a member variable and use that to avoid the issue.
  • No PlayerPrefs.GetBool() for yes/no toggling.

So I decided to make my own static class that not only addresses both issues, but does so in a way that I find convenient for organization. I call this class the "ConfigurationDirector."


The Preference Cache

For those of you who learn by staring at code first, or just want to copy it into your project, here you go:

csharp code:
public static class ConfigurationDirector
{
  #region Preference Cache
 
  static Dictionary<string,float> cachedFloatProps = new Dictionary<string, float="">();
  static Dictionary<string,string> cachedStringProps = new Dictionary<string, string="">();
  static Dictionary<string,int> cachedIntProps = new Dictionary<string, int="">();
 
  public static float GetFloat(string prefName, float defaultValue)
  {
    if (!cachedFloatProps.ContainsKey(prefName))
    {
      cachedFloatProps.Add(prefName, PlayerPrefs.GetFloat(prefName, defaultValue));
      PlayerPrefs.SetFloat(prefName, PlayerPrefs.GetFloat(prefName, defaultValue));
    }
    return cachedFloatProps[prefName];
  }
 
  public static void SetFloat(string prefName, float newValue)
  {
    PlayerPrefs.SetFloat(prefName, newValue);
    if (!cachedFloatProps.ContainsKey(prefName))
    {
      cachedFloatProps.Add(prefName, newValue);
    }
    else
    {
      cachedFloatProps[prefName] = newValue;
    }
   
    if ("Audio.MusicVolume" == prefName)
    {
      AudioDirector.MusicVolume = newValue;
    }
  }
 
  public static string GetString(string prefName, string defaultValue)
  {
    if (!cachedStringProps.ContainsKey(prefName))
    {
      cachedStringProps.Add(prefName, PlayerPrefs.GetString(prefName, defaultValue));
      PlayerPrefs.SetString(prefName, PlayerPrefs.GetString(prefName, defaultValue));
    }
    return cachedStringProps[prefName];
  }
 
  public static void SetString(string prefName, string newValue)
  {
    PlayerPrefs.SetString(prefName, newValue);
    if (!cachedStringProps.ContainsKey(prefName))
    {
      cachedStringProps.Add(prefName, newValue);
    }
    else
    {
      cachedStringProps[prefName] = newValue;
    }
  }
 
  public static int GetInt(string prefName, int defaultValue)
  {
    if (!cachedIntProps.ContainsKey(prefName))
    {
      cachedIntProps.Add(prefName, PlayerPrefs.GetInt(prefName, defaultValue));
      PlayerPrefs.SetInt(prefName, PlayerPrefs.GetInt(prefName, defaultValue));
    }
    return cachedIntProps[prefName];
  }
 
  public static void SetInt(string prefName, int newValue)
  {
    PlayerPrefs.SetInt(prefName, newValue);
    if (!cachedIntProps.ContainsKey(prefName))
    {
      cachedIntProps.Add(prefName, newValue);
    }
    else
    {
      cachedIntProps[prefName] = newValue;
    }
  }
 
  public static bool GetBool(string prefName, bool defaultValue)
  {
    return (GetInt(prefName, (defaultValue) ? 1 : 0) == 0) ? false : true;
  }
 
  public static void SetBool(string prefName, bool newValue)
  {
    SetInt(prefName, newValue ? 1 : 0);
  }
 
  #endregion
}


In short, what I do is call PlayerPrefs functions when I need values that are not cached in memory, and just read from memory at each subsequent Get. When I Set values however, I have to write to both cache and PlayerPrefs. Setting is, however, a fairly rare event.

Doing a dictionary lookup at each frame is of course not as fast as just grabbing the preference value in Awake() or Start() into a member variable and using that member variable in Update() or OnGUI(); but I don't notice the speed hit even on an iPhone 3GS and I like knowing that the preference is always up to date so long as I use the ConfigurationDirector properly.


Contexts


So you need to track your player's name, their high score, the class they're using for the current game, the color of their uniform, the game difficulty level, the music volume, the IP address of the most recent server they played on....and that's just the beginning!

I chose to bring order to that chaos by having my own system:

csharp code:
public static class ConfigurationDirector
{

  /// <summary>
  /// Player configuration settings
  /// </summary>
  public static class Player
  {
    /// <summary>
    /// Gets or sets the player name.
    /// </summary>
    /// <value>
    /// The name.
    /// </value>
    public static string Name
    {
      get {
        return GetString("Player.Name", "");
      }
      set {
        SetString("Player.Name", value);
      }
    }
   
    /// <summary>
    /// Gets the default hue.
    /// </summary>
    /// <value>
    /// The default hue.
    /// </value>
    public static float DefaultHue { get { return 62f; } }

    /// <summary>
    /// Gets or sets the player hue. This is a floating precision number between and including
    /// 0 and 360.
    /// </summary>
    /// <value>
    /// The player hue.
    /// </value>
    public static float Hue
    {
      get {
        return GetFloat("Player.Hue", DefaultHue);
      }
      set {
        SetFloat("Player.Hue", value);
      }
    }
   
    /// <summary>
    /// Sets the color of the player.
    /// </summary>
    /// <value>
    /// The color of the player.
    /// </value>
    public static Color PlayerColor
    {
      get
      {
        return ColorDirector.HSL2RGB(Hue / 360.0, 0.7, 0.5);
      }
    }
   
    /// <summary>
    /// Gets or sets a value indicating whether this player has seen tutorial.
    /// </summary>
    /// <value>
    /// <c>true</c> if this player has seen tutorial; otherwise, <c>false</c>.
    /// </value>
    public static bool HasSeenTutorial
    {
      get {
        return GetBool("Player.HasSeenTutorial", false);
      }
      set {
        SetBool("Player.HasSeenTutorial", value);
      }
    }
  }
 
  /// <summary>
  /// Audio configuration settings
  /// </summary>
  public static class Audio
  {
    /// <summary>
    /// Gets the default SFX volume.
    /// </summary>
    /// <value>
    /// The default SFX volume.
    /// </value>
    public static float DefaultSFXVolume { get { return 0.5f; } }

    /// <summary>
    /// Gets or sets the SFX volume.
    /// </summary>
    /// <value>
    /// The SFX volume.
    /// </value>
    public static float SFXVolume
    {
      get {
        return GetFloat("Audio.SFXVolume", DefaultSFXVolume);
      }
      set {
        SetFloat("Audio.SFXVolume", value);
      }
    }
   
    /// <summary>
    /// Gets the default music volume.
    /// </summary>
    /// <value>
    /// The default music volume.
    /// </value>
    public static float DefaultMusicVolume { get { return 0.4f; } }
   
    /// <summary>
    /// Gets or sets the music volume.
    /// </summary>
    /// <value>
    /// The music volume.
    /// </value>
    public static float MusicVolume
    {
      get {
        return GetFloat("Audio.MusicVolume", DefaultMusicVolume);
      }
      set {
        SetFloat("Audio.MusicVolume", value);
      }
    }
  }
 
  /// <summary>
  /// Network configuration settings
  /// </summary>
  public static class NetworkSettings
  {
    /// <summary>
    /// Gets or sets the game name.
    /// </summary>
    /// <value>
    /// The name.
    /// </value>
    public static string GameName
    {
      get
      {
        return GetString("Network.GameName", "My Game");
      }
      set
      {
        SetString("Network.GameName", value);
      }    
    }
   
    /// <summary>
    /// Gets the default port.
    /// </summary>
    /// <value>
    /// The default port.
    /// </value>
    public static int DefaultPort { get { return 12345; } }
 
    /// <summary>
    /// Gets or sets the port.
    /// </summary>
    /// <value>
    /// The port.
    /// </value>
    public static int Port
    {
      get
      {
        return GetInt("Network.Port", DefaultPort);
      }
      set
      {
        SetInt("Network.Port", value);
      }
    }
  }
 
  /// <summary>
  /// Current level settings.
  /// </summary>
  public static class CurrentSession
  {
    /// <summary>
    /// Gets or sets the difficulty.
    /// </summary>
    /// <value>
    /// The difficulty.
    /// </value>
    public static LevelDifficulty Difficulty
    {
      get
      {
        return (LevelDifficulty)GetInt("CurrentSession.Difficulty", (int)LevelDifficulty.Normal);
      }
      set
      {
        SetInt("CurrentSession.Difficulty", (int)value);
      }
    }
   
    /// <summary>
    /// Determines whether we are in table top mode
    /// </summary>
    /// <value>
    /// True if we are in table top mode; otherwise false
    /// </value>
    public static bool InTableTopMode
    {
      get {
        return GetBool("CurrentSession.InTableTopMode", false);
      }
      set {
        SetBool("CurrentSession.InTableTopMode", value);
      }    
    }
  }
 
  /// <summary>
  /// Unlocks.
  /// </summary>
  public static class Unlocks
  {
    /// <summary>
    /// Determines whether unlocks are enabled
    /// </summary>
    /// <value>
    /// True if unlocks are enabled
    /// </value>
    public static bool Enabled
    {
      get
      {
        return GetBool("Unlocks.Enabled", false);
      }
      set
      {
        SetBool("Unlocks.Enabled", value);
      }    
    }
  }
 
}


If I want to get the player's name, I do:

string name = ConfigurationDirector.Player.Name;

Doing this has two advantages: No more remembering the key you assigned to that preference from outside the ConfigurationDirector, and you know from the context (Player) that it's a player-specific preference. I also know that anything following "PlayerPrefs.CurrentSession" applies to the game in progress, and anything following "PlayerPrefs.Audio" must be related to volume controls. I'll let auto-complete do the walking for me.

Conclusion

This is how I manage configurations in my recent games, and it works well for my purposes. If you're not happy with how you maintain your game's configuration, or you forgot the preference key for the player name for the 8th time, it might be worth looking into doing something like this.

Check out my homepage and social feeds

And my projects!

Report abuse Unity: The referenced script on this behaviour is missing during LoadLevel

0 comments by Gamieon on Oct 17th, 2013

For the past few days I've been dealing with a puzzling issue in Unity: Every time I called Application.LoadLevel to change the scene in my game, this would appear in my console window:

The referenced script on this behaviour is missing!

This is despite the fact that I had no missing scripts! Based on my own logging, I determined this was happening before the next scene was loaded. I ultimately found that there was an internal issue with the prefabbed objects in the scene that was to be loaded (the ones that show in blue in the hierarchy window).

I was able to eliminate the warning by:

1. From the editor, open the scene that was to be loaded during the game.
2. Go through every prefabbed object and Revert to the original prefab state.
3. Go through every prefabbed object and change all the object properties back to the way I wanted them.

It was a bit of tedious work, but the warning stopped appearing after that. My guess is this happened because I deleted a script without detaching it from some of my prefab assets first.

I hope this helps someone out there who may be experiencing the same problem and just can't pin it down!


Check out my homepage and social feeds

And my projects!