More Lessons after Developing Academia: School Simulator

It’s been a couple of weeks since the release of Academia: School Simulator. A game that has been in development for 5 years – 4 of which was in Steam’s Early Access – and, as Marnel listed in his blog, there are a lot of lessons from those years of development.

The context of this blog is from my experience of having had part-time, freelance jobs in the game dev industry before joining Squeaky Wheel, my first permanent and regular job in the industry – and on programming a strategy game that has multiple systems running simultaneously and with hundreds of agents.

Below are shortcuts if you want to jump to a specific topic and as usual there are references at the end of the blog for further reading:

No-Garbage Programming

Well, not always but as much as possible. This is probably what I always oversee during my first years in the team (I still do every now and then) and you’ve probably seen these codes before. Garbage-generating code can look something like this:

public class GarbageExample : MonoBehaviour {

    public List<int> intList;

    public void Update(){
        if (Input.GetMouseButtonDown(0)){
            // Oops, garbage here every time the button is clicked
            this.intList = new List<int>();
        }
    }
}

Or a more common example with delegates:

public class DelegateExample : MonoBehaviour {

     // Applies different kind of damages to an entity
     private delegate void DamageEffect (int damage);

     public void Update() {
          // This generates garbage every frame
          ApplyDamage(PoisonDamage);
     }

     private void ApplyDamage (DamageEffect damageEffect){
          // Apply the damage here
     }

     private void PoisonDamage (int damageOverTime) {
          // Apply poison damage over time
     }
}

These blocks of code look harmless at first but; in the first one, a new object of type List is always being created every frame while the previous List is being released to be collected later by the Garbage Collector (GC); in the second example, what happens under the hood is a new delegate PoisonDamage is being created every frame and being passed to ApplyDamage(). Likewise with the first example, the previous delegate instance is being released to be collected later by the GC.

This is an issue because garbage collection is being done in the main thread and may look to the player as if the game was lagging if there are a lot of garbage to be collected in the current frame.

One of the ways of dealing with this is enabling Unity’s Incremental Garbage Collection. Another way is to improve your code. Here are a couple of guidelines that we follow to prevent garbage-generating codes:

  • Avoid these every frame or inside your Update method: GetComponent(), Find(), AddComponent(), Camera.main, transform, Debug.Log, and other built-in Unity methods
    • Reason being is that they are expensive and involves boxing. Solution here is to cache the return values of these methods
    • In the case of Debug.Log, these are still being called in the production build which may not be your intention. In our case, we remove these altogether after unit testing, or enclose these inside “#if UNITY_EDITOR” blocks
  • Pool your instances/objects and don’t instantiate/destroy objects every single frame. Cache the instances that you know you will reference multiple times in its lifetime
  • Move repeated computations that returns the same value outside of loops

These are just some of the examples and our ways of dealing with garbage-generating code and I’m sure there are a couple more. If you’re interested, Academia uses a signaling system to decouple different mechanics, and here’s one that Marnel made that doesn’t generate garbage.

Comment, Comment, Comment

This one I’ve realized midway into development when I was given bigger tasks that involve making systems from scratch. When I had to turn my attention to more urgent tasks such as bugs for hotfixes, then return to the system, I already forgot how half of the system works. Another benefit of adding comprehensive comments and summaries to your code, is this allows other programmers to understand your code without having to DM you about how a certain piece of code works. Sounds simple and will be beneficial in the long run.

Write your code as if it’s for the Asset Store

This is one of the first things that Marnel told me during our on-boarding period. This is related to the previous point of adding comments to your code. But not only that, your systems should work without a lot of dependencies with other systems. This is where design patterns come in. More specifically, the Component pattern or other decoupling patterns.

Writing your code in a way that they can be attached as components for Unity objects (or ECS entities) is a great way to decouple your codes and prevent spaghetti code and the infamous Gordian knot. This way of writing also allows programmers to work independently without worrying about breaking other programmer’s work.

Another way to separate systems from one another is creating a querying system and a signaling system for your game.

Read the code of existing systems

This one is crucial especially if you join the team in the middle of development – spend some time reading the backend codes of existing systems. I do this when I have extra time in-between tasks and when I’m curious on how a mechanic was implemented. This way, you will learn a lot about how your application works and thus, how best to implement and integrate new systems with existing ones.

In terms of communication, this also saves time when a question needs to be answered and your tech lead is not available.

Read and study new technologies

This might be daunting at first especially if you’ve been making the game for quite a while but, you don’t need to learn each and every new technology out there (you can if you want, though). You can skim over some of them, and study only those you are sure will help you improve your game. In our case, Unity’s new Data-Oriented Technology Stack or DOTS is definitely a need to speed up Academia’s simulations (Needs and Satisfaction, rendering, A* pathfinding, etc.).

Ask Questions – lots and lots of questions

So, you’ve been reading the backend of existing systems and reading about new technologies. That is all good and well. But, it’s sometimes better to start a discussion with your colleagues. Not only fellow programmers if you’re one, but, also with your designers and artists. This will open your mind to different disciplines in the industry and help you understand them a lot more.

By asking questions, I learned a lot from our designers which help me in designing code and tools that will help them create better content for Academia. Learning from our designers also helped me understand and visualize the mechanics in the game.

Be Clear and Specific in Communicating

Our CEO and artist, Ryan Sumo, wrote an article that pretty much sums up our daily communications. Basically, we avoid a lot of ambiguous and/or confusing definitions and terms that doesn’t translate well across different disciplines. When trying to explain programming pitfalls when we’re discussing new mechanics, I try not to use jargons that only programmers understand and explain implications in terms of actual in-game scenarios and examples. That’s just one way of making our conversations more streamlined, and there are more examples and tips in Ryan’s article.

Ask to be criticized every once in a while

This one is probably personal preference but, in order to further grow as a programmer and as a person in general, I ask my colleagues every once in a while how I’m doing in the company. Tangental to this, I take notes on common code review comments from our tech lead, usual terms and things that confuse our designers, and life advices I receive and observe from my colleagues.

This is not an exhaustive list of the lessons I learned from being part of Squeaky Wheel, developing Academia: School Simulator. But, I hope you picked up a thing or two from this list that may help you in your game dev journey.

That said, thank you and feel free to share this with your friends. Starting next week, I’ll start writing more programming-related blogs – See you in the next one!


References:

A Simple Generic Timer System for Unity ECS

Timers are used in different ways in video games such as to allow the players to fast forward in strategy games, or to be used by systems for computations like damage per minute type of effect, and much more. In my experiment project using Unity’s pure ECS, I needed a timer for setting how long an NPC will be on idle.

In this quick tutorial I’ll show you how I implemented this timer system. As usual, there are references at the end of the blog for further reading. Enjoy!

The Timer Component Tag

Let’s start with the Timer tag that we will add to the entities that we want the timer system to affect. Keep in mind that we will be implementing a generic system later that will take this timer tag as the system’s data type. The tag will look like this:

public struct Timer<T> : IComponentData where T : struct {
    // Note that we don't reset the values here since
    // we will remove this component when we're done anyways

    public float ElapsedTime;
    public float TargetDuration;

    public Timer(float targetDuration) : this() {
        SetDuration(targetDuration);
    }

    public bool IsDone {
        get {
            return this.ElapsedTime >= this.TargetDuration;
        }
    }

    private void SetDuration(float targetDuration) {
        this.ElapsedTime = 0;
        this.TargetDuration = targetDuration;
    }
}

I admit that this code looks weird because we introduce a type T, but never use it anywhere in the struct. But, this will help us differentiate the different timer systems later. This is done this way as a workaround to the fact that we can’t inherit structs and structs can’t derive from classes.

The Generic Timer System

For the system, we’ll implement a generic timer system. This will allow us to extend the timer system and have different timers for different parts of the game (such as animations, idle, game speed, etc.). This is what it looks like in code:

public class TimerBaseSystem<T> : SystemBase where T : struct, IComponentData {
    private EntityQuery timerQuery;
    private EntityCommandBufferSystem entityCommandBufferSystem;

    private const float TIME_SCALE = 1f;

    /// <summary>
    /// We set the TimeScale as virtual so that subclasses can have their own timescales if needed.
    /// A use case for this is for faster speeds or faster enemies in strategy games.
    /// </summary>
    protected virtual float TimeScale {
        get {
            return TIME_SCALE;
        }
    }

    /// <summary>
    /// This is the scaled time - applying the Timescale to the delta time.
    /// </summary>
    private float ScaledTime {
        get {
            return this.Time.DeltaTime * this.TimeScale;
        }
    }

    protected override void OnCreate() {
        base.OnCreate();

        this.entityCommandBufferSystem = this.World.GetOrCreateSystem<EntityCommandBufferSystem>();

        // The main idea here is that everything that has the Timer tag of type T will only be processed
        this.timerQuery = this.EntityManager.CreateEntityQuery(
            ComponentType.ReadWrite<Timer<T>>()
        );
    }

    protected override void OnUpdate() {
        UpdateTimerJob job = new UpdateTimerJob {
            EntityTypeHandle = GetEntityTypeHandle(),
            TimerTypeHandle = GetComponentTypeHandle<Timer<T>>(),
            CurrentTimeInterval = this.ScaledTime,
            CommandBuffer = this.entityCommandBufferSystem.CreateCommandBuffer().AsParallelWriter()
        };

        this.Dependency = job.ScheduleParallel(this.timerQuery, this.Dependency);
        this.entityCommandBufferSystem.AddJobHandleForProducer(this.Dependency);
    }

    // BURST IT!!! YAAS!
    [BurstCompile]
    private struct UpdateTimerJob : IJobChunk {
        [ReadOnly]
        public EntityTypeHandle EntityTypeHandle;

        [ReadOnly]
        public float CurrentTimeInterval;

        public ComponentTypeHandle<Timer<T>> TimerTypeHandle;

        public EntityCommandBuffer.ParallelWriter CommandBuffer;

        public void Execute(ArchetypeChunk chunk, int chunkIndex, int firstEntityIndex) {
            NativeArray<Entity> entities = chunk.GetNativeArray(this.EntityTypeHandle);
            NativeArray<Timer<T>> timers = chunk.GetNativeArray(this.TimerTypeHandle);

            for (int i = 0; i < entities.Length; ++i) {
                Timer<T> timer = timers[i];

                timer.ElapsedTime += this.CurrentTimeInterval;

                if (timer.IsDone) {
                    int sortKey = firstEntityIndex + i;
                    this.CommandBuffer.RemoveComponent<Timer<T>>(sortKey, entities[i]);
                }

                timers[i] = timer;
            }
        }
    }
}

Now, if you want to extend the timer system – say, you want another one with a faster timescale, it will look like this:

public struct FastTimeScaleTag : IComponentData {
}

public class FastTimeScaleTimerSystem : TimerBaseSystem<FastTimeScaleTag> {
    protected override float TimeScale {
        get {
            return 2f;
        }
    }
}

We first create a new tag that we will then use as the type for the new timer system. Then inside the timer system, we override the TimeScale and set it higher (faster) than the default 1 inside the base class.

A caveat however, if you run this now, you will get an ArgumentException error. This is because in ECS, all ComponentTypes should be known during compile time. To remedy this you can create a separate file, say AssemblyInfo.cs and add the following:

[assembly: RegisterGenericComponentType(typeof(Timer<NormalTimeScaleTag>))]
[assembly: RegisterGenericComponentType(typeof(Timer<FastTimeScaleTag>))]

You can also add this in the TimerBaseSystem class right after declaring your using directives if that is more convenient for you.

To further make it easier to track all the timer systems, we can make a separate system group for all the timers. Then update our timer systems inside that group.

// Depending on your use case, you can choose when your timers should update
[UpdateBefore(typeof(EndSimulationEntityCommandBufferSystem))]
public class TimerSystemsGroup : ComponentSystemGroup {
}

[UpdateInGroup(typeof(TimerSystemsGroup))]
public class TimerBaseSystem<T> : SystemBase where T : struct, IComponentData {
// Rest of the timer system code
}

Now, we are almost set. We just need to add the timer tags to our entities. My use case for this timer is for how long an NPC should wait (be idle) before moving. That said adding the components for me would look something like:

// This will make the NPC wait for 3 seconds at a normal time scale.
// More or less 3 seconds in real life.
this.CommandBuffer.AddComponent(firstEntityIndex, npcEntity,
    new Timer<NormalTimeScaleTag>(3f)
);

// This will make the NPC move earlier than the one above with a
// faster timescale which is twice of the normal time scale
// which is about 1.5 seconds in real life.
this.CommandBuffer.AddComponent(firstEntityIndex, npcEntity,
    new Timer<FastTimeScaleTag>(3f)
);

To demonstrate this I made the following setup:

  • Two NPCs with different time scales (1f and 2f), but the same idle wait time of 3 seconds; and,
  • A MovementSystem that would move the two NPCs after waiting

And it looks something like this (note that timing might differ since I just captured this with a screen to gif tool):

Unity Pure ECS Generic Timer System Example
Don’t worry, they still met in the end and lived happily ever after. *wink*

And there you have it. For further improvement, I’m thinking of adding a query in the base system that the subclasses can override, so that other parts of the game can get the scaled time from any respective timer systems. I already got it working and if you want to read more about query systems, Marnel from Squeaky Wheel wrote a simple query system. He made a better version of that system that doesn’t involve boxing but I can’t seem to find a reference about it online, maybe soon.

If you have questions you can reach me via Twitter or Instagram – That’s all for now and see you in the next one!

References:

P.S. It took a lot longer for me to release this blog because of something great happening soon – Academia: School Simulator is releasing in just a couple of weeks and boy are we nervous in Squeaky Wheel. Please check it out on Steam and let us know what you think. Thank you again, have a good one, and stay safe!

How I got into the Game Industry…

We now live in the time where video games or gaming in general is becoming more than just for entertainment. Games are now being used in different kinds of researches[1][2][3], we now have athletes who play videos games for a living[1][2], universities are now offering scholarships for esports athletes[1], and a lot more. Other fields are also starting to blend and are now becoming more involved in a game’s development process – expertise from programmers to psychologists[1][2].

But, how exactly do you even start in the industry? Here, I’ll share different tips that helped me land my first game dev job – these may not be applicable for everyone but these worked for me and might work for you too.

My Background

To give you more context on the tips ahead, note that I’ve been making games/prototypes since I was in elementary with Macromedia Flash, then with Unity in high school up to when I was in college. That said, let me briefly share with you my history in the industry so far (most of my previous works were in Unity and/or Blender):

  • I started freelancing last 2016 and my first job was a private tutor (basics of Unity)
  • 2D Animator
  • 3D Generalist
  • Writer for VGamerz
  • Game Programmer

And now, I’m a programmer with Squeaky Wheel working on Academia: School Simulator – which, by the way, is graduating out of early access next year! Please check our game out – we’re really excited…and nervous. Anyways, that out of the way let’s start with why would you even think of entering the game industry.

Why enter the Game Industry?

First – a great casual culture! Well, I can’t speak for all the studios and game development companies out there. But, in the ones I worked with, I never had to follow a strict dress code, nor do I have to work a fixed strict number of hours a day. Now, that doesn’t mean I can slack off and start work at 4 PM and logout at 6PM. What I mean is that we only have a specific time in the day – usually around 11 AM to 3PM – where you should be online just in case there are questions that needed to be answered or a team member needs help with a task. We also work from home which is a huge plus since travelling in Manila is not the easiest thing in the world. We do meet about 2-4 times a month depending on if there’s an urgent and important issue that should be discussed face-to-face.

Next reason to join the industry is the number of new technologies that you’ll get to try – virtual reality, augmented reality, new algorithms, and more! If you’re a really curious person that loves learning new technologies, you might find a home in the game industry.

That said, there are studios also that doesn’t develop games for the sole purpose of entertainment. As mentioned in the intro of this article, there are companies out there that are focused on using video games as a research tool[1]. There are even game designers being hired by healthcare companies to gamify their systems or applications[1][2].

Lastly, you’ll be making games! One of the things I love about this job is receiving comments/messages such as these,

Originally tweeted by Academia Game (@academia_game) on June 29, 2020.

My two personal favorites,

Originally tweeted by Academia Game (@academia_game) on January 1, 2020.
Originally tweeted by Academia Game (@academia_game) on November 24, 2019.

And of course, watching various YouTubers have fun!

Now, the tips!

  1. Don’t Stop Learning

True to almost any jobs in the tech industry, there are a lot of new technologies, techniques, and innovations in the games industry. Which is why, you should never limit yourself to what you already know – always be curious. But how?

Nowadays, there are a lot of information out there – forums, YouTube videos, online courses, etc. Whichever works for you – grab a copy, watch, or enroll to learn more about a technology or a skill that you feel you’re lacking. There are also workshops that you can attend to have a more hands-on learning opportunity.

Chatting with game development students during the Electronic Sports and Gaming Summit 2018

One more thing that I encourage you to do is to attend meetups. Most often than not, there will be people there showcasing their works, and you can learn from their progress. Meetups are also a great way to connect and meet with people in the industry. You can ask around about internships, job openings and other opportunities that you would otherwise not even hear anywhere.

Another thing I learned from Tobie Abad, the Creative Director of Taktyl Studios and a creator of table-top games, is to explore everything – including those that you hate. If you don’t like mobile matching games, still play them. You never know what you might learn from the game itself…and why you don’t like it.

Lastly, the best way to learn is – JUST. START. CREATING! Download your preferred game engine and start creating. I also encourage you to try out the different engines out there and choose the one that suits your workflow.

  1. Build Your Portfolio

Most often than not, your portfolio will speak louder than your CV. If you’re just starting out, don’t worry. You can use your personal projects (prototypes, game jams, etc.) for your portfolio as long as your work can show what you can do and show what you can provide for the company/studio. If you’re freelancing, include those as well.

Now, there are different kinds of portfolios for different roles:

  • If you’re an artist, fill your portfolio with the style that you are comfortable working on
  • For programmers, don’t worry if your games lack a specific art style. Just show the different systems you worked on, the tools and languages you used, etc.
  • For the designers out there, include the different prototypes showcasing the different mechanics you worked on, and;
    • For the more specific design role, the level designers, include different levels that you worked on (platformer prototypes, gray boxing, etc.). Also, put what you think is your best work, first

Lastly, make your portfolio accessible and easy to navigate. The last thing you want is to make your potential employer click multiple links just to get to ONE of your works.

  1. Be Active in the Community

Now that you are working on your personal projects, share them with the community! If you’re afraid, here’s one thing that Gwendelyn Foster, the Regional Coordinator for IGDA APAC and the Business Development Director of Special Projects at SUPERHOT, told me when I told her that I didn’t feel confident sharing my knowledge, when I was asked to give a talk in a university, “No matter how little experience you think you have, it’s still experience. And experiences are worth sharing, especially if there are lessons to learn.”

That said, you should also start attending conventions (after the pandemic, please), seminars, workshops, etc. And, while you’re in one, don’t be afraid to ask questions to the different people attending the event.

If you can, you may also volunteer in your local game developer groups. They may need a helping hand in organizing different activities for the community. That’s a great way to be closer to the community and meet people in the industry.

Gam Jams – oh, the beauty of game jams (Ludum Dare, Global Game Jam, itch.io jams, etc.). I can’t express how much participating in game jams helped me challenge myself and harness my skills. One great thing about game jams is that you can also partner up with other game developers out there. You’re a programmer and in need of an artist? Just ask in the game jam board or discussion forum, and you’ll be surprised at the number of artists out there looking for a game jam buddy.

So, go out there and introduce yourself!

  1. Don’t Give Up

Like most things in life, this is not exactly going to be a walk in the park. But, let me share with you a list of why that “fear” you’re feeling is completely normal. From Dr. Susan Jeffers’s book, “Feel the Fear and do it anyways“:

  • If you feel fear, you’re growing.
  • You’ll feel better if you do it.
  • Everyone experiences it (fear).
  • Even if you fail and feel like you lost, it’s still better than feeling helpless or regret because you didn’t even try.

Ever since reading Dr. Jeffers’s book, I’ve always kept it in my mind not to give in to fear – with proper preparations, of course.

One instance was applying for my first freelance job. Yes, I did a lot of prototypes already during that time. But, I never had any experience in the industry yet. And for TWO WHOLE MONTHS, no one was accepting my proposals and job applications. This may sound cliche, but when I was about to give up, I received an email from someone looking for a private tutor for Unity.

Another instance is when I applied for another job, the job requirement stated “at least 2 years of experience developing games”. At that point in time, I’ve only been creating games professionally for a little more than a year. I was so nervous when I submitted my application but when they gave me a chance for an exam, I passed.

Just remember – all, if not most, of game developers out there experienced far worse than you will experience. Just do it and if you fail, then there’s a lesson to learn.

  1. After all of that, what to do next?

Do your homework regarding your target studio/company. Are you sure you like the games they make – the art style, the story, the gameplay, etc.? Also, not only about the ins and outs of the games they make or the tools they use but, familiarize yourself with their culture, feedback from former employees, mentorship opportunities, etc. You never know, maybe you’ll have to work with them for years. You have to make sure you can actually maintain your sanity with the studio/company.

Keep learning, and practice or train yourself to be a good team player. It’ll help you not only in your career, but in life. Learn to understand other people’s work ethics. That said, you should also be used to receiving criticisms. Yes, there will be people who will love your work from the bottom of their hearts. But, there will also be people who will curse you for even thinking of making such an abomination of a game. You should learn how to filter different criticisms and only take in those that can further improve you not only as a developer, but also as a person.

And there you have it. The tips and tricks that I did to get in the game industry. If you want to see the deck I used for seminars, here’s the link. If you have questions, you can reach me via Twitter or Instagram.

Thank you for reading – start creating, and stay safe out there!

Different game developers from the Philippines gathered to drink, share stories, play games, and have fun!