Pages

Saturday, February 7, 2015

Hellenica Environments: Rhodes

It's now week two of post-PAX South life, and we're back into the swing of things. I'm currently in the middle of tweaking combat and building new levels, so it seemed like a good opportunity for an art update!

This week's travel destination is Rhodes, an elevated island city surrounded by a great wall on one side and staggering elevated docks on the other. Led by the so-called Mechanist-King Evagoras, the island nation is known for its theomechanical marvels as well as its generosity towards its allies and those in need.

We actually began work on Rhodes before Daniel, our environment artist, started working with us. At the time, we were still searching for the right partner, and we decided to give Collateral Damage Studios a trial run with Rhodes.

To start off, we wanted to work out the important elements unique to Rhodes. This meant figuring out how the steam-powered ship lift worked and what the Colossus of Rhodes may have looked like. We also knew we'd need to include some other elements for story reasons, so we tackled those as well. This exploratory part of the process is always my favorite.

 


A couple of the lifts relied on some questionable physics, so we decided on the rightmost implementation. In general, we were pleased with most variations of the other elements, though we really liked the mechanical solar system installation on the observatory.

With some more concrete details in mind for these elements, we started thinking about the composition of the scene.


We knew we wanted a dramatic view of the harbor that showcased the Colossus as well as the elevated docks. The first option actually worked the best for us, as it provided a nice vantage point from which to view the cityscape in the background. After a little more playing around with the finer points, we settled on option B from the second image. The airy, open feel of this composition provided a nice contrast to some of our other city locations that feel more cramped and urban.

Once that was settled, the artist took off towards the final image. CDS was great about keeping us posted on the various stages involved along the way.




This is where things stood at the end of our trial run with CDS. They exhibited an incredible attentiveness when it came to the fine details, and their transparency throughout the process was fantastic.  We were quite happy with how the final image turned out, but unfortunately the scheduling just didn't work out when it came to a continued partnership.

Now, jump ahead several months with me. Daniel had been on board for a while and was turning out great work on our other locations. We decided that we wanted him to go back over Rhodes and ensure it matched the style of his other pieces. This mostly entailed intensifying the lighting and shadows to match his preference for more dynamic lighting. Flip back and forth between the two images to see the differences.


Notice anything else that's different?

The Colossus and the boats are huge now! Unfortunately, we lost the staggering height that was critical to the island's identity during the transformation, as Daniel had dragged in the Colossus and resized the boats in the harbor due to a miscommunication on our part.

Luckily, this worked to our favor in the end. With a quick change to the horizon, a few additional ship elevators, and some architectural duct tape to help hold up the docks, Daniel was able to make the sense of scale even more pronounced than before.


So there you have it: Rhodes. And if you happen to be in town, don't forget to ask Evagoras about the elevators' auto-load balancers!

Friday, January 30, 2015

Notes from Bioware's PAX South panel

As Kurt mentioned in his last post, we were fortunate enough to spend this past weekend at PAX. We had a lot of fun there checking out different games and panels and even pulling aside a few unsuspecting attendees for usability tests (thanks, guys!). Particularly awesome was a Bioware panel we attended, where the developers largely eschewed the usual platitudes to give us some concrete details of writing techniques they used. I took notes on some of what they said and thought it would be neat to talk about how we arrived at some of the same ideas in the development of Hellenica.

(Story spoilers below.)

1. “Create a rough outline for your world and story first before you create your characters. That way you can ensure that your characters are all people with stakes in the story.”

We got the order of this one right, but our reasoning was different. One of our big goals was thematic cohesion through the world, so once we had arrived at our primary themes we sought to build them into the different political forces of our story. Then once those were in place, we started building our characters: Nephele became emblematic of the burgeoning exuberance of the steam revolution, Brasidas represents the confusion of having societal progress erode your deeply-held traditions, etc. Since our characters are so firmly grounded in our story’s themes, they definitely have stakes in what's happening, but I wonder if maybe we're missing something by tying characters to grand ideas and not focusing as much on an individual’s goals or prejudices.


2. “Write characters first and then introduce romantic relationships later, otherwise it becomes too easy for a character to becomes ‘just the love interest’."

You can ask Kurt about this, but early in development I fought HARD to make sure Diona and Brasidas wouldn't end up in a relationship. I was really worried it would distract from Diona's character and undermine her independence. After listening to the Bioware panel, I now think it could be done (after we've had 100+ pages of dialogue to define the characters) but even if I wasn't scared of writing romance dialogue, our game time’s already stuffed to the gills with story, so I don't see us adding any more.


3. “A good moral choice is one where even after you've seen the immediate consequences, you don't know if you made the right call. One way you can create this is by having the player commit to doing something, but then once she learns more about the situation, have a party member ask her to do something else.”

An early tenant of our writers has been that [uncertainty + conflicting goals = moral choice], which is a more programmer-ish way of conveying the same idea. That being said, where Dragon Age intentionally strives for verisimilitude and shades of moral gray, Hellenica's choices tend to focus more on giving the player exploration options. Although, sometimes certain paths are intrinsically tied to a specific character or story arc, in which case we almost feel a responsibility to add some narrative counter-balance, so the player doesn't just feel railroaded down a specific path.


I have a few other notes, but those don't tie in as directly to what we're trying to do with Hellenica. I'll post them though, if people are interested. Also, if I can track down a youtube video of the panel, I'll be sure to post that too.

Friday, January 23, 2015

Off to PAX South!

We're hopping in the dragonmobile this weekend to head up to the very first PAX South! (That's right, we'll be one of the few cars traveling north to reach the convention.) We don't have an official booth, but I'm hoping to get as many hands and eyes on Hellenica as I can manage in the two-day period.

To prepare, I've been polishing up one of the more unique levels in the game: the train ride to Thebes! I won't spoil the plot details, but suffice it to say that our party's in for a rather bumpy ride.

Unlike the combat stages in most tactics games, this particular stage is broken up into multiple parts (different train cars), and I'm really happy with how it turned out. Here are some shots of a few of the cars:




If you're going to be at PAX South this weekend, shoot us a note here or on twitter @thedragonloft! We'd be more than happy to show you the demo.

Thursday, January 15, 2015

A New Year in Sparta

Happy New Year!

(The following post contains moderate story spoilers.)

We've done a variety of sundry tasks since returning from our holiday, but my great white whale so far has been the implementation of level 6's Sparta. I've mentioned before that the cumulative weight of all the player’s previous choices makes writing later scenes more difficult, and Sparta's no exception. First off, multiple characters have baggage tied to this location. Brasidas in particular has a checkered history the player might have uncovered hints about in her previous adventures.

Additionally, the party comes to Sparta to deliver a warning, but the exact details of that warning vary depending on what the party's learned. Our dialogue system is awesome for this sort of thing, allowing us to easily accent a conversation depending on what details the player has learned. I've additionally started using what I'm calling "general knowledge (GK)" variables which track how much a party knows about a topic (as opposed to checking against various specific events). These GK variables work well when that information is likely to be mentioned and referenced in various paths; for example, one such variable is checked in Sparta (and elsewhere) to see if the party has specific knowledge about the enemies’ weapons.

From a narrative standpoint, sh6_sparta is exciting because the player gets a big reveal of a certain clandestine order. Though they're peripherally (and furtively) involved in a few other social hubs the player could have visited, this is the first time you can stop and ask questions about their philosophy and motivations.

Next Week: Hopefully something with more pictures and less spoilers.

Friday, December 19, 2014

Hellenica Characters: Anaxagoras

It's been a while since we revealed any new characters here on the devlog, and with Christmas coming up soon, I thought it only appropriate to introduce you to our very own Santa look-alike, Anaxagoras!

Anaxagoras is an inventor who has been at the forefront of the Greek industrial revolution for years. Our main goals in portraying him were to communicate his friendly, helpful nature and to echo the visual aesthetic that we had developed for Nephele, our other character strongly related to steam technology. Our basic approach included:
  • create a friendly facial expression and a non-threatening physique
  • add lots of tools and tool pockets
  • use brass gears and adornments
  • pick colors that match Nephele's outfit to further establish the image of the ancient Greek steam engineer


This first sketch was already quite close, but there were a few small details we wanted to revise. The pocket on the stomach felt impractical and probably uncomfortable. We also felt the device on his wrist was a bit too modern for Hellenica's time frame.


This new version looked great, so we moved on to coloring.

We wanted Anaxagoras to look right at home in the workshop, which meant using browns and oranges that blended in well with the metallic tones found there. We had already achieved a similar look with Nephele, so her palette served as a great starting point.


After that, it was just up to our partners over at YDY-CG to finish up the coloring of the sketch and add in the final details (wristband colors and pouch ornaments). As always, they did a great job executing on our direction, and we're super happy with how he turned out.

Happy holidays everyone!

Friday, December 12, 2014

Saving Hellenica

Saving games is one of the many aspects of game development that seems like it should be much easier than it is. For most games we've worked on, even though the mechanics of storing data are usually simple, the evolving state of the game means you're chasing a shifting goal and constantly at risk of breaking things. We've certainly had this experience with Hellenica as we progressed from just a linear prototype to a multifaceted narrative web. But Hellenica's unique story structure also presents a whole new set of challenges.

To start off, we're not locking the player in a single path. If after exploring the consequences of one choice for leaving a social hub she decides she's more interested in what would have happened on another path, she is free to rewind the game (via the narrative map) to the previous hub and make the other choice. However, a player's story doesn't depend just on the social hub she's in. There's a plethora of choices, both overt and subtle, which will influence the way the story is unfolding. For example, instead of just loading the player into sh4_athens, we also need to remember she came from Sparta and has talked to Alcibiades but not Xenophon and has eavesdropped on a mysterious pirate delivery. To keep track of all this, we create a mini save game for every hub the player visits. So instead of one save game, we have like 30.

A separate save game challenge came from aiming to release Hellenica on tablet platforms, where it's expected that the player can be a jerk and quit your game at ANY TIME without losing her progress. So we need to maintain a sort of perpetual saving process that keeps track of the player's progress throughout a level. And because loading it takes the player halfway through a level (sometimes even halfway through a conversation), this running save file needed to have its own share of custom data beyond the mini-save games that are tied to social hubs.

Going one step further, this is all built on a foundation of profiles, allowing the user to share Hellenica with a friend and not have her progress mucking up your own save map.

So at present a "savegame" in Hellenica consists of.
A profile, containing....
Up to 40 social-hub-specific saves, each containing a story path taken to get there and a plethora of other story variables.
Separate save data related to which combat paths are unlocked.
A running save file, which contains all the minutia of the player's progress through the current level (+extra details if it’s a combat level).
Achievements accrued and various playthrough statistics.
Party customization details concerning which abilities they player's unlocked and which abilities you’re actively using.

Thursday, December 4, 2014

A little combat art clean-up

 As we finish up more and more of the combat art, some of our old techniques for controlling sprites from the Age of Temp Art have started to bother me. This afternoon I tackled one such issue dealing with the facing of our actor sprites.

When we first started out, we plugged in some representative fantasy character sprites as place holders for our characters so that we could prototype combat mechanics without waiting for an artist. (There are a lot of great resources on the web for this purpose. Check out OpenGameArt.org or the Spriters' Resource as a start.) Here are some examples:


While this was great for communicating character strengths or attack potential, it didn't communicate character facing! The side-on view in these pictures made it difficult to determine which of the 4 possible directions a character was facing in our 3-D world.

To address this at the time, I fudged the sprite's rotation in the world to hint at the direction it was facing. Here's an example using our latest sprites:


Unfortunately, rotating the sprite relative to the camera guarantees that some of the pixels will be blended together to make the final image that makes it to your screen. This means less visual fidelity for our otherwise crispy pixel art.

What I want instead is to have the character sprites always orient themselves in such a way that the plane of their sprite is parallel to the camera's view plane (effectively, the player's screen).

Unity's Transform class provides a handy function called LookAt that gets us most of the way there. This function rotates the object's transform so that its forward vector points down the LookAt vector you provide, with an optional up vector hint. In our case, we tell each sprite to LookAt the camera's position. Here's the modified version:


If you compare this image with the previous one, you should notice that the sprites actually appear slightly larger, especially those near the center of the screen. The sprites are already much clearer, but there's still a slight problem.

Look closely at the three bandits at the top of that last image. Do they look a little different to you?

A naive application of that LookAt function I mentioned doesn't quite give us what we want. This is because our camera uses an orthographic projection instead of a normal perspective projection. (I won't go into this here, see this for the gory details.) As a sprite approaches an edge of the screen, it rotates more and more to face the camera's position. Basically, sprites look skinnier as they approach the left or right side of the screen and shorter as they approach the top or bottom of the screen. Not good!

To fix this, we tell the sprite to LookAt different points on the camera's view plane such that the sprite is perfectly parallel to the screen. Here's the end result:


All three bandits are now the same size!

(Some of you will note that there are slight differences between the three sprites. Our combat rendering is not pixel perfect, so at times a sprite pixel will land on a screen pixel boundary. I may address this in a future post if I get time.)

I can then flip the sprite to give an indication of its facing, which won't affect the rotation of the sprite at all.


For those that are interested, here's a quick code snippet from the component responsible for orienting the sprites. Let me know if you have any questions or suggestions!

private void LateUpdate()
{
// Project the targets position onto the camera's xy-plane
//  to get a look-at vector that is orthogonal to
//  to the camera's xy-plane. This will ensure that each
//  sprite is rotated at a similar angle, regardless of
//  its position relative to the camera

// world position of the sprite
Vector3 target_position = m_cached_transform.position;
// world position of the camera
Vector3 camera_position = m_camera_transform.position;

// direction vector from the camera to the target
Vector3 camera_to_target = target_position - camera_position;

// project the camera_to_target vector onto the camera's up/down vectors
float target_up = Vector3.Dot(camera_to_target, m_camera_transform.up);
float target_right = Vector3.Dot(camera_to_target, m_camera_transform.right);

// determine the position on the camera's xy-plane such that
//  (target_position - new_position).normalized == camera.forward
//  the new look-at vector is orthogonal to the camera's xy-plane
Vector3 look_at_point = camera_position + target_up * m_camera_transform.up + target_right * m_camera_transform.right;

// finally rotate the target to face the newly computed look-at point
m_cached_transform.LookAt(look_at_point, m_camera_transform.up);
}