Full credit goes to Takuan Daikon (of DFGUI), but we happen to share a mailing list, and this is worth spreading.
Throw this script in an Editor folder in your project, and anytime you save and switch back to Unity, it’ll automatically stop playing.
We’ve been slowly working towards a build pipeline. The code below expects that you have your project organized in a specific way.
With this build pipeline setup, you’ll get:
Note: Someone pointed out on Reddit that this is Pro-only. (I’ve always been a Pro-user, so I wasn’t keen to look out for those things. I’ll try to do that more in the future.)
Import ZapdotBuildTools.unitypackage to get started.
For most of this to work, my scripts expect the folder hierarchy to mimic what is described here. (Mainly that BuildTools and Unity exist in the same folder.)
If you’re going to be putting builds of a game in development into the hands of testers frequently, keeping track of what build they’re playing with can be crucial to tracking down bugs. For the most part, you might be able to tell a build by a major new feature or other visual change. As those builds become more frequent though, especially between strictly bugfix builds, you’re going to have a much harder time determining what build the user has without explicit definition somewhere.
What you could do is simply throw a static string in some class, and update it every time you kick a new build out. You could also stick your hand on a hot oven. Neither of those options sound very fun to me, though.
I create a static class that I call AppInfo. In this class I have a bunch of strings and ints that don’t change very often, if ever:
With this, I can easily create build scripts or UIs that use this information. The most important string that I’ve got in this class is AppInfo.fullVersion, which includes the major version, minor version, build date, and build count.
The build date is formatted YYMMDD (for sorting purposes) and the build count is simply an incremented integer to differentiate multiple builds on the same date.
I want the data to be easily available to both the editor and the built project. I’d also prefer that the user cannot easily access the data of this file to edit it and potentially introduce confusion with bug submission. To accomplish this, I store the data in a comma-separated format within the Resources directory.
Throw AppInfo.cs in Scripts/ProjectSpecific/AppInfo.cs
Whenever you need to increment the stored build number, call the following function (editor only):
Whenever you want to print or display the full version, simply print or display this string:
What do you get, when you do a game jam, in one* hour, with thirteen people?
An hell of a time, for one.
We spent a Frunch at the Collective pulling together a game. Everyone had something to do — art, audio, PR, programming, design… and we not only ended up with a game for you to enjoy, we ended up with a documentary too.
* I was the only one in Unity, so I actually spent about 2.5-3 hours on the game, integrating the assets, and getting gameplay in. Next time we need a tech artist. :)
This past July, I was one of the organizers for the Boston-area MolyJam. This year, the prompt was from a selection of quotes from Peter Molyneux himself.
I was worried I might be pulled off due to duties that organizing the event might entail, so I decided to whip something up on my own.
I’m not punishing you for button mashing; I’m rewarding you for not button mashing, and that is a really big distinction.
I took some heavy inspiration from the humor that QWOP evokes from making movement difficult. Multiplayer games like WrestleJump are very easy to pick up, and a blast to play. What if there was a Western-style duel game, where you had really floppy arms?
After a short amount of time, I had some joint constraints working:
Thanks to the magic of the Unity Asset Store, I quickly whipped together a scene:
After a little bit of work on the joints, it was simply too easy to get the player to manipulate the shoulder/elbow joints. I decided to switch gameplay to be a bit more based on timing.
After a weekend of work, I ended up with a finished game. I don’t think I’ll pursue the idea much further — through this little experiment it became pretty obvious that much of the challenge and enjoyment of QWOP and Wrestle Jump come from balancing against gravity.
I spent a few hours this weekend fixing up a build script to drop into some prototypes that I’m working on. Much of the work originates from the lessons I’ve learned shipping multiple Unity titles to various storefronts. I started writing a post to describe it all, but it had so many various dependencies that it made a bit more sense to break it up and go a bit more in-depth when needed.
Over the next few weeks, we’ll look at how I’ve crafted this build script. If it goes well, I may continue the series with more “Best Practices” that I’ve picked up over the past few years.
Cooking is a pretty big hobby of mine. In the same ways that drive my infatuation with games — I’ve had some incredible experiences with some incredible meals, and I couldn’t simply leave them to hand-wavy magic. There was talent and knowledge behind the preparation of the food I was eating, so I set out to learn what it took to make a good meal or three.
One of the first cooking lessons that you should learn is a simple concept called “mise en place”. It’s French for “put in place”, and it refers to the constant organization of your kitchen. Time is incredibly valuable, especially in a professional kitchen, so efficiency must be at it’s highest point wherever possible. Keep your knives, measuring utensils, spices, and cookware in the exact same location, and preparation becomes quicker, allowing the chef to put their time and effort into the creation of their dish, not the assembly.
This applies to game development too. Spend the majority of your time on your craft. Don’t waste your time looking for the damned cinnamon.
Here’s how I currently set up my projects. Certain things get moved around and changed as I find slightly better ways to consider the organization, but after a few projects, I’ve arrived at this.
From here, I add everything except the “Builds” folder to version control, and I’m on my way. Since the BuildTools will be included, and I can find all the included tools via relative paths, *any* computer that syncs to version control will be able to run the build on their machine.
My “Scripts” folder gets broken up a bit more, but that’s a bit dependent on the project . For instance, with Ugly Baby, level generation and PCG were very important, so there was a “Level” folder with a dozen or so scripts related to that.
The “External” folder is generally where I put all the plugins and assets I grab from the Asset Store, GitHub, and the ilk. If there is some unmanaged code that I’m compiling on my own to include as a plugin, I’ll put the source in a folder of its own at the same depth of the Unity and Build_____ folders.
“Builds” and “BuildIncludes” follow the exact same folder structure. (StoreName/BuildTarget) This is important, but I’ll get to it in a later post.
I still haven’t found a perfect solution for my “Art” folder. I’ve previously separated things into Models, Prefabs, and Textures, but that doesn’t work well when you have many assets for a 2D game. With the new 2D system from Unity in beta right now, I imagine that might change how I deal with sprites going forward.
As Dave and I begin working on Ugly Baby with Dejobaan, we had the opportunity to throw the Unity project in our version control system of choice. Coming off the heels of a couple projects versioned with Unity’s Asset Server, I was definitely looking forward to working with something slightly more robust.
Perforce, in a previous life, was very expensive to use ($700+/user). Their free licensing restrictions used to only allow a handful of users/workspaces, which wouldn’t be enough for a small team with a few dev computers. That being said, they have recently changed their terms to allow for up to 20 users/workspaces and unlimited files, or unlimited users, and a limit of 1000 files. Jumping into a game that’s closing in on it’s third or fourth year of iterative development, I decided the former would be the best option for us.
On top of that, it turns out to be very easy to get everything setup for yourself at absolutely no cost.
Normally, you’d have to worry about getting a server hosted somewhere, worry about the bandwidth, the disk space, the uptime. Turns out Amazon allows for small servers hosted on their huge EC2 backbone at absolutely no cost.
You have two options here, setup an instance on your own, or use BitNami to do the management of the Amazon EC2 server instance. I have played with both, and ended up sticking with BitNami because I had it setup a server with a base installation of some task management software I wanted to try. BitNami also sends you estimates of what your monthly payment will be with regards to your past week’s activity. It’s a good way to get a heads up if you’re pushing your instance a bit too hard.
This section of the setup will be a little bit sparse, as it’s been a few weeks since I setup my own server, and I did not take notes at the time. If I run through it with a friend, I’ll come back and update the post.
What’s important though, is you setup a server with either Debian or Ubuntu. Having the apt-get package manager makes our lives a bit easier. Realize that if you screw up along the way, and want to start over, simply terminate and delete your server instance off of Amazon’s backend, and start over.
sudo apt-get install daemon
chmod +x p4 p4d
sudo mv p4 /usr/local/bin sudo mv p4d /usr/local/bin
sudo addgroup p4admin
sudo adduser perforce
perforce ALL = ALL
sudo mkdir /perforce_depot sudo chown perforce:p4admin /perforce_depot
sudo mkdir /var/log/perforce sudo chown perforce:p4admin /var/log/perforce
# Perforce Settings export P4JOURNAL=/var/log/perforce/journal export P4LOG=/var/log/perforce/p4err export P4PORT=localhost:1666 export P4ROOT=/perforce_depot export P4USER=perforce
#!/bin/sh -e export P4JOURNAL=/var/log/perforce/journal export P4LOG=/var/log/perforce/p4err export P4ROOT=/perforce_depot export P4PORT=1666 PATH="/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin" . /lib/lsb/init-functions p4start="p4d -d" p4stop="p4 admin stop" p4user=perforce case "$1" in start) log_action_begin_msg "Starting Perforce Server" daemon -u $p4user $p4start; ;; stop) log_action_begin_msg "Stopping Perforce Server" daemon -u $p4user $p4stop; ;; restart) /etc/init.d/perforce stop /etc/init.d/perforce start
start ;; *) echo "Usage: /etc/init.d/perforce (start|stop|restart)" exit 1 ;; esac exit 0
sudo update-rc.d perforce defaults
cd ~ sudo /etc/init.d/perforce start
sudo /etc/init.d/perforce restart
Before Perforce can be used by a team there are two housekeeping task that need to be done – creating the journal and closing a security hole.
sudo p4d –d
sudo p4d –jc
sudo p4 protect
sudo p4 admin stop
I would suggest that you protect your Perforce connection by logging into it over SSL, rather than the plaintext connection that acts as a default.
sudo mkdir /perforce_ssl sudo chown perforce:p4admin /perforce_ssl
export P4PORT=ssl:1666 export P4SSLDIR=/perforce_ssl
# C: Country Name - 2 letter code (default: US) C = # ST: State or Province Name - full name (default: CA) ST = # L: Locality or City Name (default: Alameda) L = # O: Organization or Company Name (default: Perforce Autogen Cert) O = # OU = Organization Unit - division or unit OU = # CN: Common Name (usually the DNS name of the server) # (default: the current server's DNS name) CN = # EX: number of days from today for certificate expiration # (default: 730, e.g. 2 years) EX = # UNITS: unit multiplier for expiration (defaults to "days") # Valid values: "secs", "mins", "hours" UNITS =
sudo chmod 700 /perforce_ssl/
It’s also important to setup the typemap for Perforce, to ensure that the files that are being checked out are properly marked as text, binary, and binary exclusive.
In order to do this, type:
You’ll want to paste in the following typemap, and be sure to save.
text //....js text //....cs text //...shader text //....meta text+l //....cm text+l //....proc text+l //....md5mesh text+l //....md5anim text+l //....ma binary //....dll binary //....exe binary //....response binary //....lib binary //....pdb binary //....u binary //....ini binary //....stub binary //....ip binary+l //....prefab binary+l //....mb binary+l //....mat binary+l //....psb binary+l //....mp3 binary+l //....fbx binary+l //....unity binary+l //....asset binary+l //....aas binary+l //....tga binary+l //....jpg binary+l //....lwo binary+l //....wav binary+l //....ogg binary+l //....demo binary+l //....roq binary+l //....doc binary+l //....xls binary+l //....celtx binary+l //....pdf binary+l //....odt binary+l //....ods binary+l //....ppt binary+l //....skp binary+lS //....dds binary+lS //....bnk binary+lS //....light binary+lS //....shadow binary+lS //....ibl binary+lS //....bik binary+lS //....upk
The majority of the credit for this knowledge is not my own. Thanks to the following sites that contained most of this information:
Found a quote today, and tried to track down it’s origins. Rather than the quote, I prefer this small anecdote I found from
The Beggar King and the Secret of Happiness by Joel Ben Izzy.
The Secret of Happiness
Nasrudin is known as much for his wisdom as his foolishness, and many are those who have sought out his teaching.
One devotee tracked him down for many years before finding him in the marketplace sitting atop a pile of banana peels–no one knows why.
“Oh great sage, Nasrudin,” said the eager student. “I must ask you a very important question, the answer to which we all seek: What is the secret to attaining happiness?”
Nasrudin thought for a time, then responded. “The secret of happiness is good judgment.”
“Ah,” said the student. “But how do we attain good judgement?”
“From experience,” answered Nasrudin.
“Yes,” said the student. “But how do we attain experience?”
Reading about the Mulla was quite humorous as well.
Learned a super awesome trick today for Canon DSLRs that get a hot/dead/stuck pixel on the sensor. It’s not foolproof and might not fix the issue, but it turns out that it has fixed the problem for many people including a friend of mine today, so that’s good enough for me!
Should we call it an excerpt from the NecronomiCanon? ;)