Before jumping in! I want to clarify that this page is written from the perspective of leading a student engineering team. Some of these comments will also be applicable to professional settings, but it's important to note that all of these are taken from the student project perspective. I explicitly want to address common problems that arose in my time working in technical roles at USC.
Historically, I've always been an engineer, technical designer or engineering lead on projects at USC. Along the way, I picked up a lot of lessons on how to lead an engineering team in particular. I had a lot of ideas and processes that I wanted to test, and brought them into The Wind and the Wisp. I can confidently say it's the best run engineering team I've ever been on, and that purely comes from multiple iterations of how to structure engineering work. My hope is to pass on what worked well, and acknowledge what didn't work so that future student engineering teams can continue to improve! (shoutout to Anooj Vadodkar, Richard Ortega-Amezcua, Emma Leihe, Julia Wang, and Daniel Hu, my engineering goats! <3)
In school, "engineering" can kind of be a nebulous discipline. It can mean a lot of things, and it's super important to get clear about what is expected from an engineer.
Especially in a student setting, it can be really difficult to navigate what an engineer does, and it's easy to fall into the misconception that they are implementation monkeys. This is not true. Engineers are not there to implement and execute ideas, engineers are creative problem solvers to the project's systemic problems, such as:
Equipping other teams with tools to work more efficiently with less reliance on engineers.
Building (gameplay) systems for designers to use in their designs.
Facilitating pipelines.
An engineer's work does encapsulate implementation and execution, but to think that is one of their core responsibilities is a common fallacy, and a naive answer to "what does engineering do?".
When approaching an engineer with work, be really clear about what your ask is. Don't just say "I want the pinwheel to spin when the player blows", think broader, especially if it's core to systemic gameplay (and not a one-off interaction). Say something like: "I want to be able to detect if the player blows when near an object in the game world. If they do, it should produce some kind of output, for example, a pinwheel spins". This is a clearer ask, because the engineer understands the behaviors needed to produce an output. In my experience, I rarely care about the actual output (it could be a pinwheel spinning, or a balloon flying away, or a wind chime twinkling), I care about the input parameters needed to trigger a certain output, and what systems the input will be drawing information from.
There are two definitions here:
Ownership: What is the actual feature or system an engineer is working on? What will become "their baby"?
Task: The actual, finite list of things someone is doing (e.g. "create ribbon simulation").
Ask engineers up front: what do you want to do? What do you NOT want to do? This one is super important and generally a sign of maturity in engineers if they can answer both of these questions (again, I want to clarify this is especially important in school and volunteer settings, where you must find ways to harmonize helping people chase their passions with the practical reality of getting work done)! Engineering is such a diverse and widespread discipline that being a "generalist" in engineering doesn't apply in the same way it does for disciplines like art.
Creating ownership is the main creative work for anyone responsible for nurturing engineers... It takes a lot of working very closely with each engineer individually and understanding what their strengths are (what they're good at), what their interests are (what they like doing) and what their learning goals are (what they want to do). The goal is to allocate work for them that combines at least two of the three (and assembling exodia is combining all three).
(Again, I must clarify this is in the context of a student project, when people are at different stages of learning how to code).
The most important thing when it comes to approaching programming work is understand what the technical requirements are, and the systemic implications. These can be hard to break down into actionable tasks sometimes, because systemic implications can be far-reaching, and potentially require an engineer to go off the plan at times.
It's also important to understand: who is a problem solver, and who wants to write code? Not every engineer wants to be given an ambiguous feature request and figure out how to implement it. Likewise, not every engineer wants to be told what or how to program. Many engineers are one or both, but it's important to know who on your team is which, and it's important to have both. Newer, more inexperienced engineers usually lean towards writing code, and this is an important part of their growth. Give them simpler tasks that involve straightforward programming. Give the more complex problems to solve to more experienced engineers, but then point the younger engineers to these solutions to study. It's important for younger engineers to get exposure to clever solutions and clean code.
How does this play into tasks? For approaching programming-oriented tasks, they have clearer paths to the deliverable and breaking them down into granular tasks is easier. For example, what is something that's a concrete gameplay mechanic? One example in The Wind and the Wisp was the doors.
Door Behavior:
The Wisp enters a trigger, the door opens. The Wisp exits that trigger, the door closes.
The Wisp goes through the door, the scene fades to black, and transition to the next scene.
The game saves itself after the scene has faded to black.
Have a field in the inspector to control which scene it transitions to, how fast the door opens/closes, etc.
For problem-based tasks, these are really difficult to break down and scope out, because they are less deliverable oriented. They are behavior oriented and require a lot of negotiation based on how it interacts with other systems. Two examples of this in The Wind and the Wisp was the Microphone (behavior oriented task) and the Wisp (negotiation oriented task based on other systems). As you can see, the list for both of these can get absurdly long as we dig deeply into the implications.
Microphone Behavior:
Blow into the microphone to create an output.
Is it possible to control the strength and duration of the blow (big vs. small? Long vs. short?)
Is if possible to distinguish blowing from speech?
Will it be functional with any microphones or do we need a specific setup?
Wisp Behavior
The Wisp's ribbon moves dynamically.
The Wisp's cloth body has physics simulations.
The Wisp should play [x] animation in [y] situations.
The Wisp reacts to player Microphone Input.
The Wisp is controllable by the player via Keyboard/Controller.
This is the most common fallacy (that really got on my nerves) from non engineers. We have a lot of engineering work to get done? Just recruit more engineers. This works for some disciplines, but does not work for engineering in most cases. For example, you need a save system, and the engineer who will implement it says it will take 4 weeks. The solution is not to hire another engineer, and say "great, now it should take half the time between the two of you." The solution is to make time for that engineer to concentrate on the task at hand for 4 weeks. The number of engineers you need should be determined by how many systems or features the project needs, and how many systems or features each engineer can take ownership of.
For The Wind and the Wisp, our biggest, major systems were: Camera, Input, the Wisp, the Wind, the Microphone, UI, Audio, Saving/Loading, Gameplay - Flower Mechanics, Gameplay - Blowable Systems, Build. And to give a better idea of who did what:
Julia Wang: Microphone and Calibration
Emma Leihe: Saving/Loading, Gameplay - Blowable Systems, Gameplay - Flower Mechanics
Richard Ortega-Amezcua: Camera + Camera Tools, Wisp, Wind + Wind Tools, Graphics and Optimization
Daniel He: Saving/Loading, UI, Bug Fixing, Flexible
Anooj Vadodkar: Gameplay - Blowable Systems, Input, Flexible
Sammy Chuang: Build and Testing, Gameplay - Blowable Systems, Gameplay - Flower Mechanics, Bug Fixing, Flexible
(Our Audio Engineer, Ivan Pu, was part of the Audio Team).
This led to a minor issue that each system/feature only had one engineer who could really address issues on the system/feature they owned, but this is where excellent documentation came to our rescue! We rarely came up against issues that were so deep that another engineer couldn't look at and fix with a little time. So looking at a high level, we had 3 extremely specialized engineers, and then 3 engineers who were more flexible as backup for specialized systems.
A common problem I encountered at USC is that the Engineering Lead architects the code base, and implements gameplay from designers, and manages a team of engineers and allocates tasks, and communicates with other leads to understand their needs, and gets everyone coffee, and will file your taxes. Basically, anything you need done, name it! That was often thrown at the engineering lead.
It's simply too much work for a single person, so in my mind, engineering should have three people leading it: the engineering producer, the engineering lead, and the technical lead. The titles don't really matter, but in essence, three people to split up the following work:
Technical Lead: Write the most challenging code and tackle the most difficult bugs. This person has 0 management responsibilities.
Engineering Lead: Nurturing engineers, understanding each engineer's strengths and weaknesses, and supporting their learning goals.
Engineering Producer: Communicating with other disciplines to understand priorities.
Having a singular engineering lead who does task management AND writes code AND nurtures the team is too much work for one person. Do not do this to your engineering lead! Additionally, all three should be extremely capable engineers themselves. I believe that you cannot effectively produce an engineering team unless you are an engineer yourself.
This pipeline in particular is really difficult. Designers often have a (false) understanding that engineers should be implementing their design. This isn't true. Designers must be capable of working in engine on their own. Additionally, the lack of shared vocabulary between the two can be really difficult to navigate. Designers are great at pitching ideas and writing up cool concepts. However, it can easily get lost in translation and I've had a lot of experiences in which someone tells me about some great idea or concept--which I find really fascinating!--but at the end I still don't understand what they actually want (and even worse, leave the conversation feeling: "that was cool, but why did they tell me about that? Not really my wheelhouse to do that kind of thing...").
The way that we thought about it for The Wind and the Wisp was:
Engineers implement systems, and designers implement gameplay and output.
For example:
Engineers set up the microphone input and a script that says “when the player blows/the microphone picks up blow input, do X”. Designers then program a custom function that fills in the X.
An engineer writes the Save System, and a designer writes a script that says “after the player picks up this object, save the game” and in that script they can just call SaveSystem.SaveGame(). The underlying parts of how that saving actually happens is abstracted.
This pipeline can be tough, but is very solvable. It's extremely labor and resource intensive and just requires a lot of time for importing and getting everything set up correctly. All you really need is artists who are capable of working in engine. Since we used Unity, artists can implement their own work without relying too much on engineering. However, it's really important to be cognizant of the various quirks of Unity (like working with LODs, scaling and resolution).
For context, our art team had 2 artists capable of implementing 3D assets, 1 capable of implementing UI and working with funky Unity resolutions, and 1 technical artist. Our most difficult art/engineering implementation workflows was animation, because it needed a lot of setup in Unity's animator and also relied on a lot of code to trigger various states. For The Wind and the Wisp, we did not have many artists working in engine, mainly because we didn't want too many cooks in the kitchen. However, I wish we'd had a dedicated engineer for working with artists and implementation pipeline. Unfortunately, though, this might be a harder role to fill, because it begins to fall into "implementation monkey" territory. I'd recommend looking for artists specifically with Unity experience, and then finding engineers who are interested in technical art/animation engineering. I'd also recommend building art implementation time directly into the engineering schedule.
But all in all, art and engineering had very few bumps during development, just a lot of work to get done!
In reality, these should be distinct relationships, but for the purposes of a student project, anything related to build and testing fell into one big soup.
Builds and testing the entire game wasn't difficult. I made new builds every Friday, and QA could test them for bugs and with playtesters for feedback. Sometimes if Design only wanted one level tested, that was also fairly easy. Just include calibration and that particular level in the build, and we're good to go! (Fortunately we had our debugger as well, which helped us jump around levels as needed). It ended up being a tiny bit spaghetti at point, with using temporary scripts to bind keyboard buttons with specific hacks (unlock that door, teleport the player to x location), but all in all, the pipeline for testing specific levels wasn't too difficult.
The harder part of this pipeline was when they wanted to test other types of builds for specific features (e.g. A/B testing the narrative, a sandbox for testing microphone effectiveness, etc). We didn't really have a dedicated engineer who would help get these types of builds out, so a lot of that fell onto me. So if I were to do anything different, I would have had a dedicated Build Team made up of: a Build Engineer, a QA tester/Lead, and the Usability Lead. The Build Engineer would be responsible for working with the QA Lead, Usability Lead, and designers to understand test goals and find ways to create testable builds or test structures for those.
The Microphone Sandbox that I built for QA/Usability. (Volume warning, I die from coughing at one point :) )
Abstracting the Microphone.
The microphone was a really clear example of a system that needed an engineer to program, but a designer should never have to actually touch the microphone code. From a designer's perspective, all they really care about is: is the player blowing or not (and on occasion, for how long)? Due to this, engineering was able to program microphone input, and set up a simple prefab for a designer to plug in outputs based on if microphone input was received or not.
Excellent Technical Documentation
Every level, every bit of code, has been documented to some extent. Most of the documentation includes notes for engineers reading it in the future, as well as a "how to" section explicitly written for designers.
I think my favorite part about our TDD as well is that there are parts that explain why something was set up the way it was. It helps to explain broader implementation context, and became a teaching tool for designers.
Flexibility to do what people wanted and support learning goals/interests.
The engineering team had incredible team culture, and I believe the project was able to reach its level of technical polish due to a well composed team, with good leadership (shoutout to the Engineering Lead, Anooj Vadodkar!). When recruiting the team, I looked at what I knew we would need overall. We needed someone comfortable working with unique input (webcam, mic, arduinos, etc), and we needed people comfortable working in 3D.
In early engineering meetings, I spent a lot of time asking people what they wanted to do, what they didn't want to do, and then observing what work they seemed to really enjoy to better tailor task allocation. For example, one of the engineers is an insanely talented game programmer, but he mentioned he'd been getting into shaders and tech art. He became the primary owner of the Wisp, its gameplay implementation, and all of its visual components (the ribbon, the cloth body simulations, the vertex shaders, etc).
Better testing practices.
We did not have a standardized practice for testing code. More often than once, we would finish implementing a feature, test the base case, and move on. There should have been a procedure for implementing, testing and then merging as to not break the entire project. Additionally, we should have had a dedicated QA person and made better use of Unity's built in automated tests.
Fixing bugs as we go.
The last two months of the project, engineering spent a lot of time just bug fixing. Engineering ended up so far ahead on implementation that we realized we could've slowed down and taken time to fix bugs as they arose, instead of saying we will fix it later on. Fixing bugs later on is fine, but it made it more difficult because some people needed time to refresh their memories on how certain systems worked.
Transitioning from summer to autumn
A lot of spagehtti code was written during (summer) preproduction, in the interest of rapid prototyping. Instead of rewriting prototype code, we built on top of it However, the prototypes weren't built to be sustainable. We put more spaghetti on top of spaghetti, and should've made a commitment to rewrite all prototype code OR built them to be stable from the beginning.
Additionally, something that's worth experimenting in is actually having design prototype in different projects (instead of different scenes), then taking videos and sending those to engineering. That way, code would be built in a scalable way that's not referring to the original script.