Why is Writing for Games so Difficult?

Category : Design, Games, Writing · No Comments · by Aug 5th, 2015

link-animated

I’ve been watching walkthroughs for The Last Express. Funny that a concept I thought was innovative a year ago has in fact been done close to two decades ago.

As a game designer, I often find myself awkwardly maneuvering game elements in order to fit the story. Why is writing for stories so hard? I think the problem is interactivity.

Consider the traditional written or oral tale. In the story, not every minute gets assigned equal weight. Seconds, days, or years that are not essential gets skimmed over. This is the convention, without which both writing and reading would be unbearable. Movies embrace this convention through cuts.

In order fit a good story to a game, we naturally want to extend the above analogy to games, but interactivity works against this in three important ways:

1. Major gameplay sections usually do not support the “cut to the interesting part” structure.

2. Conventionally, gameplay sections must be engaging, which does not necessarily correlate with interest points within the story.

3. Gameplay affords the opportunity to deviate from a single storyline, often in so many ways that covering all scenarios is prohibitive in terms of cost.

In any given imaginary timeline, in order to seamlessly integrate story and gameplay, we must slice the timeline in a way that satisfies both the conventions for good story “cuts” and the conventions for good gameplay “cuts”. #2 and #3 are both difficult to account for while maintaining a good tempo for story, and #1 seems outright contradictory to the convention of a good story “cut”, unless the story or the game mechanics are somewhat special.  Writing and gameplay are not a true dichotomy, but it’s clear that extremely specific requirements must be met to optimize both simultaneously.

If the player is playing as a character in the game, then the “seamless integration” would also have to carefully avoid ludonarrative dissonance, a complex topic (and navigation) in its own right.

I think designers who write existing stories into their games are in a world of hurt, yet most games now still ship with an existing storyline. I think this is because for a long time, existing storyline is the only way of storytelling we know of.

So what are some potential solutions? The Last Express incorporates a highly interesting setting to sustain engagement throughout a stable timeline, while utilizing vast amounts of writing and technology to work around #3. Forgoing elaborate stories altogether may be a good choice (consider Threes and Angry Birds). Simple but well-crafted stories may be effective (Shadow of the Colossus) too. A sense of determinism can be built into the game to combat #3, which may also suitably evoke a sense of the tragic.

I think that increasingly, building the narrative out of player experiences rather than in-game story has become a popular choice. Games like Pokemon, League of Legends, and Journey have minimum built-in stories and rely on gameplay scenarios unique to each playthrough to generate evocative stories. One can think of this as analogous to “emergent gameplay”, expect instead we are designing for potent story scenarios – “emergent storytelling”.

Quick Summer 2015 Game Jam Postmortem

Category : Coding, Games, Reflections · No Comments · by Jul 24th, 2015

Screen Shot 2015-07-22 at 11.01.54 PM

Though UA GameDev Club’s summer jam was only 30 hours, I came out of the experience full of new insights.

What worked well:

  • The brainstorming process – I tried some free association at the very beginning and was organically led to an idea that’s both unique, technologically feasible, and has a lot of potential for quick polish. It was the most painless brainstorming session I ever had, and I suspect that two factors may be behind it: working solo, and keeping the most difficult constraints as the first ones I consider. Regarding the latter, I think recognizing the uniquely abundant affordances of using real-portraits early on was a big win.
  • Solutions bred from time constraints – the huge time constraint prompted me to make decisions that ironically benefitted the game itself. The game was originally intended to contain endless-levels, with each level a new room with new portraits. The lack of time to make animations and adjust difficulty forced me to constrain the entire game into one room with fading portraits. Narrative-wise it seems to make less sense, but I near the end of the project I knew instinctively that this approach would be better. I learnt that the logic of the game world is in fact as malleable as its graphics and sounds.
  • New tech requirements made the Jam a learning experience – Over the past two GJs I have been gradually inching out of the familiar territory of 2D games into 3D, but each time I made sure I only bite off as much as I can chew.
    The feeling of learning a lot of new skills AND finishing a nicely-designed concept is one of the most positive out there.
  • Game immersion – Perhaps by luck, I stumbled upon an idea that affords a lot of immersion. I think the idea of using memory and instilling panic as an integral part of the gameplay had somehow erased the boundary between the player and the avatar. The identity of the avatar as a powerless human character also helped covering up the fourth wall.
  • Built-in breaks – the knife-removal part of the game took longer than it should to implement, but I am happy with the break in tension and realism that it affords in the end. I was originally worried that the player would take too long of a break or find the task boring, but I think to a certain extent the human psyche is built in to continue the game at the optimal level of interest/arousal. To say simply – players make subtle attempts to stay in the flow state.

What went wrong:

  • Not really a team effort – The game was originally going to be an effort of a team of two. However, I think I was a bit intimidating initially in my ambition to create a really polished game and in my obsession over details that later on seemed relatively minor, especially since my potential teammate was much less experienced in game jams. The teammate did not return the second day, despite promising twice that he would contact me.
    I think during the jam I was struggling between knowing that I would likely construct a higher-quality game on my own and the sense that I should pick up less-experienced developers to learn about both social skills and team-management. I initially wanted to work solo but wavered during the team-forming phase. I think in later jams, I should commit to either solo or team options right away and stick to it till the end.
  • I didn’t compose the music – I think it’s better idea to not even consider composing for a GJ entry.
  • Didn’t finish the introduction and the ending – thinking back to the GJ, I don’t actually recognize any point when I could have done more to mitigate this problem without hurting the game in some other way.
  • Players didn’t have much motivation to stay – from the intro, the players know that there will be four levels and that the levels will generally be the same. For this reason, several players decided that they don’t need to see what’s beyond the first. I think that the issue lies in the game progression rather than the introduction though, and that I can probably add later hooks to keep the player engaged.

Other thoughts:

  • Negative thoughts during GJ – while I felt extremely good upon completion of the GJ, during the day of the competition my thoughts often lapsed into pessimism – “perhaps I should have picked a different idea after all”, “at this pace I will never finish”, “shouldn’t have slept for so long”.
    I began to realize that pessimism can occur in perhaps all but the most magnificent game projects, and that it’s a significant cost of working solo.
  • Don’t underestimate other players’ entries – being an extremely competitive person, I had thought that the game will likely be the best entry from the Jam. But looking at the final entries, I don’t think that this is actually the case, and was a bit ashamed for putting so much pride into the game.
    But then again, perhaps this is required to combat the pessimism outlined above.
    After all, Orson Scott Card once said something to the effect that “as you write, you should think of your writing as simultaneously the worst thing and the best thing ever written.”

In the next week or so, I will take a day to polish the game and add the features that didn’t make it on time. Stay tuned for the release!

Don't trust the loudest voice in the room

Category : Communication, Reflections · No Comments · by Jul 16th, 2015

One curious pattern I’ve observed during college is that as a person’s verbal promise grows in magnitude and audacity, the actions corresponding to the promises tend to be more subdued.

In other words, if you hear a person proclaim that “I will change the world!” Then it would be a favorable to bet that the person is very unlikely to change the world. On a smaller scale, the more enthusiastic someone agrees to a gathering or a collaboration later, the more we are right suspect that the person will bail when the time comes.

Several possible explanations to this phenomenon comes to mind. One is a version self-licensing effect that doesn’t deal with just morals but actions to require some self-discipline to deal out in general. The rush of euphoria that comes with a bold statement may trick the speaker into believing that concrete measures are being taken to advance the goal. In fact, nothing concrete is done until something concrete is actually done.

The second explanation may be that the style of the statement itself tends to arise from episode of emotional swings. Even more so than mental illness, I observe that the swings comes from two places: an innate emotional temperament and/or unstable self-esteem. In both cases, perhaps influenced by the need to aggrandize oneself on from of an observer, the proclaimer makes an exorbitant remark and forgets it shortly after.

Finally, it may be possible that holding such statements within can actually channel energies towards the desired goals. Speaking is a means of self-expression, but the expression could be substituted with action through a process somewhat like sublimation. I realize that this is the less scientific-sounding than the previous two, but from personal experience, I feel that it might bear some weight.

Self constraint, overt optimism, and lack of intermediate goals are all additional factors that could explain the phenomenon. But at least for me, the course of action is clear- never make big promises without much prior thought.

For those who are reading, please don’t, without a proper context, tell me that you will be that next “changer”.

Disabling Youtube Front Page Recommendations

Category : Coding · No Comments · by Jul 2nd, 2015

Youtube’s front page recommendations have always been a distraction for me. Due to reasons I can only interpret as political, the Chrome store has no extension to disable front page recommendations on Youtube. Thus I wrote a quick and dirty script to remove the recommendations.

Note that since Youtube uses a JS framework that prevents me from disabling the recommendations once and for all, I had to settle for the solution where the recommendations are cleared every half a second. The cost this incurs in the browser should be negligible. Please let me know if you find a better way!

The script was tested on the Tampermonkey extension in chrome. Install the script here.

Let me know if you run into any issues!

Short Story: Paper Boats

Category : Books, Writing · No Comments · by Jun 21st, 2015

I updated the bookshelf on this site last night to include books I read before October 2010, the month I started tracking my readings. The quantity of books came as a genuine surprise to me, especially the amount of books on fantasy.

What struck me as more interesting is that in the meantime, I never felt a desire to write something of my own. Simply traversing another reality was enough for me. It would be a lie to say that I never entertained for a moment the possibility of writing a story, but calling it a “desire” is definitely too strong.

But one day that unfamiliar sense of desire did strike, and I sat down and wrote “Paper Boats”. I remembered that Raymond Carver usually puts his first draft away for weeks in order to make final adjustments with a fresh eye, and that is what I did.

And this is what I wrote:
Paper Boats

I feel that out of any media, writing is one I especially like to see feedback on. If you took some moments to read the story, I would appreciate an extra moment for feedback. As usual, no pressures.

Writing in such a way was fun, though I’m sure unreliable too. But it’s strange and exciting to regard my own unexpected creations, and I hope that there will be future stories to come.

Unity3D General Tricks and Gotchas

Category : Coding, Games · No Comments · by Jun 13th, 2015

This is a continuation of Unity 2D Tips and Tricks, some of which are adaptable to 3D as well.

Tricks:

1. Translate or Rotate relative to world space
Unity3D’s API doesn’t advertise the optional parameters Translate and Rotate functions as much as their importance merits. By default, translations and rotations are conducted in the local transform space. This is usually convenient, but can be annoying when parent/children relationships are used for their convenience in referencing each other. The optional RelativeTo parameter in Translate and Rotate takes either Space.World or Space.Self, saving us from nasty workarounds.

2. Choosing random enums
Stolen from the Unity Answers thread, a shortcut function to pick a random enum is not provided by Unity3D, but is immensely helpful for fighting technical debt while rapid prototyping.

3. Use a Tweening Engine
Tweening refers to the action of exercising fine-tuned control over the transition of variables, often done through existing mathematical functions. See an example here (automatic-audio warning).

In the context of a game, it is a invaluable time-saving tool for two reasons. Firstly, tweening adds a great amount of polish to a game in very little time; Secondly, tweening engines usually comes with timeline functionalities that dramatically simplify potentially annoying tasks.

For example, consider simulating a ball that bounces once, then stops, fades, and gets destroyed one second after fading. Using Update, we must hand-write the sine function to approximate the trajectory each frame, keeping track of the amplitude and the phase of the function. We must keep variables that track time since bouncing started, whether the ball has finished bouncing, the alpha value of the ball, and amount of time elapsed since the fading has finished. The result is ~20 lines of ugly code that is inflexible to change.

Using something like DOTWeen, we can simply do:

Sequence mySequence = DOTween.Sequence();
mySequence.Append(transform.DOMoveY(100, 0), timeToMove / 2f).SetEase(Ease.InSine);
mySequence.Append(transform.DOMoveY(0, 100), timeToMove / 2f).SetEase(Ease.OutSine);
mySequence.AppendInterval(1);
mySequence.Append(DOTween.ToAlpha(()=> renderer.color, x=> renderer.color = x, 0, 1);
mySequence.AppendCallback(Destroy);

 

Note that the alpha-tweaking line has some fancy syntax for referring to getters and setters, it will be well worth your time to learn this notation, if only for giving you more power in using the tweening engine.
Note that using a tweening engine, the code is much shorter and more readable, and it’s easier to tweak for different types of effects.

Gotchas:
1. Rounding
Unity’s Math.Round function has an odd behavior, from the API:

If the number ends in .5 so it is halfway between two integers, one of which is even and the other odd, the even number is returned.

Here is a more minimalistic round function that behaves according to expectation.

public static int Round(float value){
	return Mathf.FloorToInt(value + .5f);
}

 

2. Photoshop Color Management
Unity’s texture import feature does not account for color profile settings in photoshop, as seen here.

The difference looks something like this:
Screen Shot 2015-06-13 at 1.13.29 PM

This is a small detail that could cause massive headaches in reworking textures if not properly dealt with.
To prevent it, select “Don’t color manage this file” on all graphic assets intended for import through Unity.

3. Corrupt Prefabs via Git
As late as Unity 4.6, saving a prefab without saving the scene the prefab is in transmits a corrupt version of the prefab to the remote git server. This is one more reason to attend to the good practice of always saving the scene before a git push.

4. Viewport Space, Screen Space, and World Space
Unity’s Camera class provides a wide variety of useful functions to convert between dimension measurements on the screen, in the view port, and in the game’s world. Distinguish between these carefully:

      The Screen space provides the dimension of the game in pixels. The bottom left of the camera is (0, 0), the top right is (Camera.pixelWidth, Camera.pixelHeight), respectively the width and the height of the camera in pixels. The Z value is the distance of a particular point in the world from camera.

The Viewport space is normalized. The bottom-left of the camera is (0, 0), and the top right is (1, 1). The Z value is the distance of a particular point in the world from camera. This is useful for positioning GUI elements.

The World space is the global positioning space that Transform components inhabit.

Note that when converting between any two spaces, we are not confined within the screen or the port. It’s perfectly valid to ask the Camera to convert from (2, 2, 0) in Viewport space to world space, in this case, we will obtain a point in the world that is about one camera outside of the current camera.

When working within 2D, it’s tempting to use the dimensions of the camera to determine the positioning of GUI elements. I find viewport space to be more reliable, since it’s immutable to both camera size changes and game screen resize.

5. OnDestroy in Child Transform
OnDestroy is a convenient callback, but beware that when a child is destroyed due to it’s parent being destroyed, the OnDestroy function on the child is not called.

6. Proper way of checking whether an object has been destroyed
Due to Unity’s gameObject implementation, checking whether an object has been destroyed in not very obvious. The correct way to do so is:

if(target == null || target.Equals(null)){
	//Assume that target has been destroyed.
}

This is a handful of code to type for each destruction check, so consider writing a static function under some utility class to handle the check instead.

7. Unity Canvas Crossfade
The new canvas GUI system in Unity seems very powerful, but UI.Graphic.CrossFade and UI.Graphic.CrossFadeAlpha are broken in the sense that both will not work if the color of the Graphic element was change right before them.
The solution turned out to again be Tweens. Example code that I used:

menu.color = new Color(1f, 1f, 1f, 0f);
Color c = new Color(1f, 1f, 1f, 0.7f);
menu.DOColor(c, 3f);

This code shifts the menu’s color from completely transparent to a transparent white in 3 seconds.

Unity 2D Tips and Tricks

Category : Coding, Design, Games, Productivity · (1) Comment · by May 28th, 2015

While the 2D features in Unity3D gets a lot less love than the rest of the engine, Unity3D is still a very powerful tool for rapid prototyping in 2D given some customization. Since the 2D features leverage design decision catered toward 3D, there are occasional gotchas in 2D as well to be aware of. Here I detail some of the tricks and gotchas I noticed while working with 2D in Unity.

In general, it is a VERY GOOD IDEA to extend the given MonoBehavior class to create shortcuts for verbose but necessary instructions. The shortcuts can be implemented by way of C# properties. This reduces clutter in code and leads to less bugs. In fact, all but one of the “tricks” uses this to simplify 2D programming.

Tricks:
1. Barring very special cases, most of your objects are going to have the SpriteRenderer component. When extending MonoBehavior, you can implement a shortcut to access spriteRenderer:

private SpriteRenderer _spriteRenderer;
public SpriteRenderer spriteRenderer{
	get{
		if(_spriteRenderer == null){
			_spriteRenderer = GetComponent();
		}
		return _spriteRenderer;
	}
}

The _spriteRenderer in this code caches the spriteRenderer to skip extraneous costly GetComponent calls.
Now, monoExtendedObj.GetComponent() can essentially be replaced with monoExtendedObj.spriteRenderer.

2. Angle manipulation in 2D is usually limited to rotation on the Z axis. However, to specify Z rotation you must go through Quaternions, which are necessary for 3D rotations. We can shove the messy quaternion operations under the rug by defining a custom “angle” property:

public float angle {
	set {
		Quaternion rotation = Quaternion.identity;
		rotation.eulerAngles = new Vector3(0, 0, value);
		transform.rotation = rotation;
	}
	get {
		return transform.rotation.eulerAngles.z;
	}
}

Note that when getting a value from this property, you will always obtain a value between 0f and 360f. If this is undesirable, consider defining a private variable that stores the non-moded angle value.

3. Alpha (opaqueness) values require dealing with colors property of the spriteRenderer – an extremely verbose operation even with the existing spriteRenderer shortcut. This property lets you set transparency of the spriteRenderer easily

public float alpha {
	set {
		if(spriteRenderer != null){
			Color _color = spriteRenderer.color;
			spriteRenderer.color = new Color(_color.r, _color.g, _color.b, value);
		}
	}
	get {
		if(spriteRenderer != null){
			return spriteRenderer.color.a;
		}
		else return 0;
	}
}

An alpha value of 1 or more is fully opaque; 0 or less is fully transparent. The values are not clamped between getting and setting so that the alpha may double as a transparency counter/timer. However you might want to use a Tweener to achieve timing effects more gracefully.

Tips:
1. Most graphic bugs from your 2D game will come from drawing order or faulty z-values. Unity3D’s ordering scheme for 2D sprites is versatile but also confusing. The determining factors for sprite ordering are (from highest to lowest priority):
-Sorting Layers (Bottom ones in the Unity UI are drawn on top)
-Order in Layer (Higher orders are drawn on top, negative values are possible)
-Z value (Closer in camera line-of-sight (LoS) drawn on top)

By default, the camera is at a height of 10 with LoS pointing downward. This implies that without changing the camera, higher Z values are drawn on top. HOWEVER, the camera also has a near-clipping plane of 0.3, meaning that it will not see anything closer than 0.3 units away from the plane perpendicular to the camera LoS (using default values, any Z-value > 9.7).

Finally, note that Order in Layer is a signed short ranging from -32,768 to 32,767. Attempts to utilize numbers outside of this range will likely mess up your drawing order.

There are several takeaways from this. The first is that you should be careful with modifying default camera values unless you are certain about how camera works in 2D. The next is that while working with dynamic Order in Layer and/or Z values are convenient, you will be working with their respective constraints. In general, Z values are better for handling cases where many more layer values than 64,000 are needed (this does occasionally happen), but can cause sprite to disappear if you are not careful. Z value is also a float, so keep rounding errors in mind.

2. Unity3D’s particle and trail renderers do not have their “sorting layer” field exposed, and that’s terrible because suddenly you cannot control the drawing order of your particles and trails.
To fix this, write a custom component that has the below code and attach to your particle or trail renderer:

void Start () {
        //Change Foreground to the layer you want it to display a particle
        //system on, otherwise particles will not show up.
        GetComponent().GetComponent().sortingLayerName = "YOUR_LAYER_NAME";
}

Note that this will set your object’s drawing layer to a static layer called “YOUR_LAYER_NAME”. If this is not your wish, or you prefer to select the drawing layer in the Unity3D UI, check here to obtain a list of drawing layers and work from there.

3. As these reddit users have found, Unity3D’s 2D collision detection system will make your life very tough if you do not use physics. This is problematic for a lot of simple 2d games where physics would either be a overkill or make debugging difficult.

I have found that the 3D collision detection system has much less stringent requirements. You must still have at least one rigidbody per collision detection, but if you tightly control the z values of your objects (usually by clamping it to 0), you can get around a lot of weird issues that arises in 2D collision detection without physics.

Note that doing both this and ordering with Z value can get hairy fast. Avoid one or the other.

4. Often it is useful to know the dimensions of the sprite either at import time or after stretching, the variables below have very similar names, but only some will be correct:

SpriteRenderer.sprite.rect will specify the size of the sprite in pixels.
SpriteRenderer.sprite.bounds.size will provide the rectangle bounding box of your sprite before scaling in game units. The size of this bound is usually SpriteRenderer.sprite.rect divided by it’s “pixel per unit” under the sprite import settings.
SpriteRenderer.bounds.size will provide a rectangle bounding box of your (sprite)render as it appear in the game, which means after stretching SpriteRenderer.sprite.bounds.size through transforms.

All .size can be replaced by .extents to obtain a box with each dimension halved, this is a useful shortcut when only the size of half the bound box is required.

These are all I have regarding 2D, for now! I’m planning on starting a general Unity3D tips and tricks post soon, and most of that post will apply to 2D as well, so stay tuned!

CS425- Virtual OSPF Router Postmortem

Category : Coding, Design, Reflections · No Comments · by May 21st, 2014
CS425- Virtual OSPF Router Postmortem

I have redeemed myself from the disgrace that is Networking homework! Through approaching the program in a systematic manner, I…

R.I.P.- Networking Program 1

Category : Coding, Reflections · No Comments · by Mar 13th, 2014
R.I.P.- Networking Program 1

Image Courtesy of UOTTAWA   My first mission for Computer Networking is the implementation of the Sliding Window Protocol (SWP)…