Jump to content
  • Advertisement
  • entries
    112
  • comments
    236
  • views
    136210

About this blog

Still making games...

Entries in this blog

 

Reducing Unity game file size

Hello,

I've been busy porting Twitchy Thrones to Unity. The game was originally programmed in Objective-C, using XCode and the Cocos2D framework. Cocos2D is a great framework but if you want to publish your game for iPhone, Android and PC you have to use C++ and Cocos2D-X. Setting up Cocos2D-X isn't trivial and using C++, of course, implies losing comforts like automated memory management.

As for Objective-C, it's almost exclusively used by Apple and thus can't be used, as far as I know, to port a game to other platforms. This is actually a Good Thing, since it is a monolithic programming language, full of unnecessarily verbose syntax and lacking modern programming language features such as generics, real encapsulation, string operators, etc.

So I turned to Unity and C# to publish Twitchy Thrones on Android and PC. I'm finding Unity amazing, except for a few quirks. If I knew before what I know now I would have started the project in Unity to begin with.

Everything was going well, except... When the Objective-C/Cocos2D version was originally published to the App Store it occupied 17.3 MB on my iPhone. After most features were implemented in the Unity version I installed it on my iPhone expecting a similar file size. Nope. 156 MB! In these days where most games are free or freemium, a big file size can change someone's mind when it comes to downloading your game.

What follows is information I found scattered across the web to solve the problem of Unity's output file size, which I hope will be more useful gathered in one place.

As mentioned in Unity's own article about reducing file size (http://docs.unity3d.com/Manual/ReducingFilesize.html), the editor log provides a summary of the size of each of your assets after you perform a build of your project. This is what I got for mine:
[quote]
[font=arial]Textures 65.2 mb [/font][font=arial] 79.6% [/font]
[font=arial]Meshes 0.0 kb 0.0% [/font]
[font=arial]Animations 113.1 kb 0.1% [/font]
[font=arial]Sounds 10.2 mb 12.5% [/font]
[font=arial]Shaders 42.9 kb 0.1% [/font]
[font=arial]Other Assets 543.3 kb 0.6% [/font]
[font=arial]Levels 92.8 kb 0.1% [/font]
[font=arial]Scripts 439.5 kb 0.5% [/font]
[font=arial]Included DLLs 5.2 mb 6.4% [/font]
[font=arial]File headers 99.8 kb 0.1% [/font]
[font=arial]Complete size 81.9 mb 100.0% [/font]

[font=arial]Used Assets, sorted by uncompressed size: [/font]
[font=arial]6.1 mb 7.5% Assets/Sound/Songs/ThemeSong.mp3 [/font]
[font=arial]2.7 mb 3.3% Assets/Menus/WorldMap/WorldMapBirdFlockMiddle.png [/font]
[font=arial]2.7 mb 3.3% Assets/Menus/WorldMap/WorldMapBirdFlockBottom.png [/font]
[font=arial]2.7 mb 3.3% Assets/Menus/WorldMap/WorldMapBirdFlockTop.png [/font]
[font=arial]2.1 mb 2.5% Assets/Maps/Map16/HelpPanel6.png [/font]
[font=arial]2.0 mb 2.4% Assets/Fonts/Resources/Fonts.png [/font]
[font=arial]1.3 mb 1.5% Assets/Menus/Main/BannerFinalChallenge.png [/font]
[font=arial]1.3 mb 1.5% Assets/Menus/Main/BannerFinal.png [/font]
[font=arial]1.0 mb 1.3% Assets/Maps/Map16/Map16Background.png [/font]
[font=arial]1.0 mb 1.2% Assets/Menus/WorldMap/WorldMapClouds2.png [/font]
[font=arial]1.0 mb 1.2% Assets/Fonts/Resources/MenuFonts.png [/font]
[font=arial]946.8 kb 1.1% Assets/Menus/Settings/SettingsFinal.png [/font]
[font=arial]946.8 kb 1.1% Assets/Cutscenes/Cutscene2/Cutscene2Banner.png [/font]
[font=arial]946.8 kb 1.1% Assets/Cutscenes/Cutscene1/Cutscene1Banner2.png [/font]
[font=arial]946.8 kb 1.1% Assets/Cutscenes/Cutscene1/Cutscene1Banner1.png [/font]
[font=arial]946.8 kb 1.1% Assets/Cutscenes/Cutscene2/Cutscene2Cup.png [/font]
[font=arial]768.3 kb 0.9% Assets/Menus/WorldMap/WorldMapClouds3.png [/font]
[font=arial]768.3 kb 0.9% Assets/Menus/WorldMap/WorldMapClouds1.png [/font]
[font=arial]710.3 kb 0.8% Assets/Menus/WorldMap/WorldMapBackgroundLand3_2.png [/font]
[font=arial]710.3 kb 0.8% Assets/Menus/WorldMap/WorldMapBackgroundLand3_1.png [/font]
[font=arial]710.3 kb 0.8% Assets/Menus/WorldMap/WorldMapBackgroundLand3_0.png [/font][/quote]

[font=arial]Except for the theme song, all my biggest assets were textures. The problem is, while XCode uses the compressed .png images and even compresses them further with pngcrush (https://developer.apple.com/library/ios/qa/qa1795/_index.html), Unity uses the raw texture data, resulting in enormous file sizes. [/font][font=arial]In Twitchy Thrones' case, a 2D pixel art game, reducing the texture quality wasn't an option since any blurry texture stood out from the rest of the game.[/font]

[font=arial]The first solution I came across was bypassing Unity's content pipeline and loading the textures from the .png files in real time. If you change an asset's extension to .bytes, Unity treats it as binary data (http://docs.unity3d.com/Manual/class-TextAsset.html) and doesn't unpack it, thus the asset won't bloat your file size. Here's Unity's code sample from loading a texture from a .bytes file:[/font]//Load texture from diskTextAsset bindata= Resources.Load("Texture") as TextAsset;Texture2D tex = new Texture2D(1,1);tex.LoadImage(bindata.bytes);
A script component was added to each GameObject containing a SpriteRenderer using the offending giant texture and on the Awake() function the texture was loaded using code very similar to the above. A sprite was then created with the texture and this sprite was set to the GameObject's SpriteRenderer. Problem solved, I thought. But when I booted the game on iPhone, a screen that took less than 1 sec to load before now took more than 10 secs! The performance of Texture.LoadImage is simply terrible.

Luckily, someone with the same problem lead to the solution, the WWW api (http://answers.unity3d.com/questions/511268/texture2dloadimage-too-slow-for-use-ios.html). The game ran perfectly on Unity's editor, but when running on iOS I got an "unsupported URL" error.

Back to Google. Most threads referring the same error warned that the URL is case sensitive and spaces need to be replaced with "%20" as with any URL, but that was not the problem. My problem was, Unity packs the assets in its own format and doesn't keep the original file structure, so the file I was trying to load in the URL didn't exist in iOS. Fortunately Unity provides a way to keep the original assets in their original form in the final build, the "StreamingAssets" folder (http://docs.unity3d.com/ScriptReference/Application-streamingAssetsPath.html).

Note that unlike "Resources" folders, which can be placed anywhere in the hierarchy of the "Assets" folder, the "StreamingAssets" folder must be placed in the root of the "Assets" folder. After placing the textures in the new folder, with their extension changed to .bytes for the reason mentioned above, I changed my GameObjects and respective scripts.

Here's one of the final GameObjects (The Sprite should be set to "None" in the SpriteRenderer):



And a link to the SpriteTextureLoader script (Sorry for not putting it here but the formatting got messed up when I tried):

http://www.onceabird.com/tt/code.txt

A couple of notes:
The main downside of this method is that the sprites won't be visible in the Editor when the game's not running. But then again in most cases this method should only be implemented when the game is nearly done, as premature optimization is the root of all evil.
Although I haven't experimented, this method should work with other asset types, such as textures for models in a 3D game.
I chose to create a script component for each GameObject where needed, but obviously this code can be used to load all textures in a loading screen if needed.

I only changed the biggest textures so far, but right now Twitchy Thrones occupies 87 MB on my iPhone, which is 55% of the original size.

EDIT: Fixed linked SpriteTextureLoader script to work on Android.

Demosthenes

Demosthenes

 

Twitchy Thrones is out now!

Twitchy Thrones is out now for iPhone. It's free until November 5th: https://itunes.apple.com/us/app/twitchy-thrones/id898649182?l=pt&ls=1&mt=8

Here's the release trailer:



And some screenshots:






Demosthenes

Demosthenes

 

I quit my job...

...To make games full-time.

Yes, this is going to be one of those posts.

My name is Ricardo Moura, Once a Bird is made of myself and my cousin. I do the programming and "art" and he does the music and sound effects.

I quit my job at the end of July but only left it mid-September. It had been making me sick for years and seemed to be going nowhere. The job consisted of programming various pieces of the back-end of a stock-broker / bank, It was well paid but I very rarely did any interesting stuff.

If you have been following this journal, you're probably wondering at this point how can this guy quit his job when all his games so far were commercial failures. If you didn't, now you know all the games we made so far were commercial failures.

The answer is, I've been working as a programmer for 12 years now and for about 5 years I've been doing games in my spare time. I consistently enjoyed making games more than programming "corporate" software. When you reach a certain point in life you realize that it's very easy to spend most of your waking hours working on stuff that you don't like (and doesn't really matter much to you) just so you can make a living (this realization probably comes earlier for most people).

Also, I realized I could survive some time with the money I saved.

So, games. Fold was our latest and best-selling game, it was released in June for iPhone and sold 1016 copies so far. If you want to take a look, the app store link: https://itunes.apple.com/pt/app/fold/id645248522

Although it didn't sell much, Fold had very positive reviews, including a glowing review by tuaw.com: http://www.tuaw.com/2013/07/13/daily-iphone-app-fold-is-the-most-original-ios-puzzler-in-years/...

In September I entered the Ludum Dare 48-hour compo alone and made Twitchy Thrones, a real-time strategy game parodying Game of Thrones. Here's a link to the post-mortem: http://www.ludumdare.com/compo/2013/09/12/twitchy-thrones-post-mortem/.

For our first full-time game, we decided to remake Twitchy Thrones for iPhone. Right now I'm doing pixel art for it:

A map:



A knight's death animation:



Thanks for reading, let us know what you think! Art critiques in particular would be very welcome. :)

Demosthenes

Demosthenes

 

Fold

So Fold was released on the iOS app store:

https://itunes.apple.com/us/app/fold/id645248522?ls=1&mt=8

EDIT - Here's the release trailer:

Here's a screenshot:



So what is Fold anyway? Fold is a puzzle game where you have blocks that collapse into each other in a chain reaction. The goal is to finish each level with just one block of each color. Right now there are 3 worlds, each world introduces a new concept.

Fold was written in Objective-C. The game is free to play, but you only have access to half the levels on each world. A single in-app purchase unlocks all the levels in the current version and all future updates.

Here's another screenshot:


Demosthenes

Demosthenes

 

Beta version!

[color=rgb(41,47,51)][font=Arial] The beta version of Twitchy Thrones is ready! If you have an iPhone and want to help us test/improve it please go here: [/font][/color]http://tflig.ht/1w0mXSn

More information about the game here:
http://forums.toucharcade.com/showthread.php?t=211741

Here's the game in motion:

Demosthenes

Demosthenes

 

The pixels of Twitchy Thrones

Twitchy Thrones is the first game where I'm trying my hand at pixel art. Fold took advantage of Retina iPhone's resolution of 1136x640 by making all the art vectorial and creating resources for both hi and low resolutions. In Twitchy Thrones the pixel resolution is always 568x320, cropped to 480x320 in devices prior to iPhone 5.

Twitchy Thrones is an ultra-fast strategy game where you control knights, sending them to conquer enemy territories or defend your own. This is the first knight pixel art (2x actual size):



And this is the first knight pixel art in the first map:



I couldn't see it at first, but the knights were too small and hard to tell from the background. Eventually I went back to [s]Photoshop[/s] the drawing board (2x size):



Some time after the second attempt I found myself thinking it could look better. It still looked too small and the contours were not very defined. So came the third and latest attempt (2x size):



And a screenshot of the game at the moment on an iPhone 4s:



The map's landmarks, such as the bridges and the trees were also modified to reflect the knight's size change. Contours were also made more visible with darker colors.

What did I learn from this? Perception changes over time (duh!). A seasoned artist would be able to point the flaws in the first attempt right away, but I could only do it weeks/months later. Obviously even the art I have right now is flawed but for now I reached the point where I don't know how to significantly improve it.

Demosthenes

Demosthenes

 

Box2D.XNA and ear clipping...

The first difficulty I ran across in OMA was importing polygons into the game. The polygons in Box2D.XNA must be convex and are limited to 8 vertexes (for performance reasons), which means that when using complex polygons you have to divide them into simpler polygons. One of the authors of Box2D.XNA suggested ear clipping, an algorithm to divide polygons into triangles. The algorithm described in that paper is more optimized than the implementation I went with, because since I only partition the polygons during game initialization, performance isn't that important.

As mentioned in the paper, "an ear of a polygon is a triangle formed by three consecutive vertices Vi0, Vi1, and Vi2 for which no other
vertices of the polygon are inside the triangle." The basic algorithm consists of taking the initial polygon vertex list and removing ears one by one until only one triangle remains. The paper suggests using a double-linked list to store the polygon vertexes because it's a data structure that allows quick access to both current, previous and next elements when iterating the list, as well as fast removal and insertion.

Additionally, a circular list would be even more useful so that no boundary checks would be necessary. In the .Net C# framework, the double-linked list implementation doesn't allow for circular lists, meaning that the last element on the list will always be null, instead of the first element. You also can't change this pointer on the list, because a node can only be inserted in the list once. So I did my own generic circular list implementation, which is basically the same as all circular list implementations: :)


public class CircularListNode
{
public CircularListNode previous, next;
public T value;
}

public class CircularList
{
public CircularListNode first, last;

public void Add(T value)
{
CircularListNode node;

node = new CircularListNode();
node.value = value;

if(first == null)
{
first = node;
last = node;
}
else
{
last.next = node;
node.previous = last;

last = node;
first.previous = last;
last.next = first;
}
}

public void Remove(CircularListNode node)
{
if(first == null)
{
return;
}

node.previous.next = node.next;
node.next.previous = node.previous;

if(node == first)
{
first = node.next;
}

if(node == last)
{
last = node.next;
}
}
}


(Note that this implementation in particular isn't meant to be used outside of this context: the node removal doesn't check if the list is empty because in our particular case it should never be.)

Next, the ear clipping algorithm:


public class GeometryFactory
{
public static List> EarClip(CircularList vertices)
{
List> ears;
CircularListNode node1, node2;
bool isEar;

ears = new List>();

node1 = vertices.first;
while(node1.previous.previous != node1.next)
{
isEar = (InternalAngle(ref node1.previous.value, ref node1.value, ref node1.next.value)
if(isEar)
{
node2 = node1.next.next;
while(node2 != node1.previous)
{
if(PointInsideTriangle(ref node2.value,
ref node1.previous.value, ref node1.value, ref node1.next.value))
{
isEar = false;
break;
}

node2 = node2.next;
}

if(isEar)
{
ears.Add(new List { node1.previous.value, node1.value, node1.next.value });

node2 = node1.next;
vertices.Remove(node1);
node1 = node2;
}
}

if(!isEar)
{
node1 = node1.next;
}
}

ears.Add(new List { node1.previous.value, node1.value, node1.next.value });

return ears;
}


The EarClip function receives the vertex circular list (The vertexes must be ordered in anti-clockwise order). It then iterates it, looking for ears. The first check is done by the InternalAngle function, which verifies if the angle formed by the current vertex and its siblings is convex or concave. If it's concave, it can't be an ear and there's no need to do the next step: verifying if any of the other vertexes is inside the triangle formed by the current vertex (the "ear tip") and its siblings (which is done using the PointInsideTriangle function). Each time a ear is found the triangle it forms is added to the output ear list. The "ear tip" vertex is removed and the iteration continues. The iteration stops when there are only 3 elements on the list, which are the final triangle.

The InternalAngle function:

private static float InternalAngle(ref Vector2 v1, ref Vector2 v2, ref Vector2 v3)
{
Vector2 a, b;
float angle;

a = v2 - v1;
b = v3 - v2;

angle = (float)Math.Atan2(b.Y, b.X) - (float)Math.Atan2(a.Y, a.X);
if(angle {
angle += (float)Math.PI * 2;
}

return angle;
}



The PointInsideTriangle function (if you're interested in how it's derived go here):

private static bool PointInsideTriangle(ref Vector2 p, ref Vector2 a, ref Vector2 b, ref Vector2 c)
{
Vector2 v0, v1, v2;
float dot00, dot01, dot02, dot11, dot12,
invDenom, u, v;

// Compute vectors
v0 = c - a;
v1 = b - a;
v2 = p - a;

// Compute dot products
Vector2.Dot(ref v0, ref v0, out dot00);
Vector2.Dot(ref v0, ref v1, out dot01);
Vector2.Dot(ref v0, ref v2, out dot02);
Vector2.Dot(ref v1, ref v1, out dot11);
Vector2.Dot(ref v1, ref v2, out dot12);

// Compute barycentric coordinates
invDenom = 1 / (dot00 * dot11 - dot01 * dot01);
u = (dot11 * dot02 - dot01 * dot12) * invDenom;
v = (dot00 * dot12 - dot01 * dot02) * invDenom;

// Check if point is in triangle
return (u > 0) && (v > 0) && (u + v }


The List> returned by the EarClip function can be used to add each triangle to a Box2D.Xna shape:


Body body;
BodyDef bd;
PolygonShape shape;
Fixture f;

CircularList vertices;
List> triangles;

vertices = new CircularList();
// Build the polygon vertex list here

bd = new BodyDef();
// Set additional body properties here

triangles = GeometryFactory.EarClip(vertices);
foreach(List triangle in triangles)
{
shape = new PolygonShape();
shape.Set(triangle.ToArray(), triangle.Count);
f = body.CreateFixture(shape, 1.0f);
// Set additional fixture properties here
}


And that's it.

Demosthenes

Demosthenes

 

Haiku update

DreamBuildPlay contest deadline June 12.

Here's a video of when a player grabs a new item:
[media] [/media]


Here's a video of the game intro:
[media][/media]

Demosthenes

Demosthenes

 

Graveyard Shift

Like Matt Damon in the Jimmy Kimmel Show, Super Ninja Kung-Fu Puzzle is the project that keeps getting bumped for another. This time for the...





What's it about this time? Graveyard Shift is a thumbstick shooter / tower defense hybrid set in a zombie-infested graveyard. The player builds his base during the day and at night the zombies attack. The game has been in development for some months now.


The player kills the zombies with guns. Instead of towers the player lays down tiles on the ground . Zombies spawn out of the ground but never on a player tile, although they can walk over them.

Tiles cost money, which the player gets by killing zombies and grabbing the coins they drop. Tiles can also be upgraded to benefit the player or affect the zombies. In the video below the player is setting down tiles and upgrading them to slow down the zombies:

[media] [/media]

The game will also feature a co-op mode with up to 4 players. In the video below there are two players, one of which is reading the tombstones:

[media][/media]

Right now we have a basic prototype but there is much to be done: add all tile upgrades and guns, replace some of the art, add sound effects and music, etc.

Demosthenes

Demosthenes

 

Suit Suit Go is out now for iOS and Android!

Just realized now I didn't even talk about this game here before.

Suit Suit go is a puzzle/card game where you upgrade cards by making sequences. It was developed with Unity. It's free and our first game to be ad-supported. Please give it a try!

iOS:
https://itunes.apple.com/us/app/suit-suit-go/id1011220863?l=pt&ls=1&mt=8

Android:
https://play.google.com/store/apps/details?id=com.onceabird.suitsuitgo&hl=en


Demosthenes

Demosthenes

 

Twitchy Thrones is out now for Android!

Twitchy Thrones is out now for Android! And also iPad.

Google Play link: https://play.google.com/store/apps/details?id=com.onceabird.twitchythrones

App Store link: https://itunes.apple.com/us/app/twitchy-thrones/id898649182?mt=8


Demosthenes

Demosthenes

 

Developing a phone game...

Just a quick status update.

We got the phone from the DreamBuildPlayContest, it's a spiffy Lumia 900. The interface and screen is quite nice, shame about the apps.

Graveyard Shift is on a temporary hiatus as I'm developing a phone game by myself. The game is being developed in XNA, it's almost complete and running on the Lumia. I'm going to start porting it to Objective-C soon as the plan is to release it first to iPhone and then to Windows Phone and Android.

About the game itself I can't say much because it's a simple and easily duplicable concept. What I can say is that it's an original puzzle game and I never saw anything quite like it.

Demosthenes

Demosthenes

 

So... Here it is!

Bennu for PC is here and it's free!




From the non-existing box blurb:

"Bennu is an innovative physics-based puzzler. The player controls a ball and chain and progresses through the levels by swinging from place to place, all the while destroying the blocks on each level by swinging into them. Bennu features both single and cooperative gameplay.

Bennu placed in the top 20 of the 2008 DreamBuildPlay contest."

[size="3"]Download it at Once A Bird's website.

Demosthenes

Demosthenes

 

New Zombie Animations

My brother finished the new zombie animations. There are more frames for movement, attacking and dying. Video below:

[media][/media]

Also, merry Christmas everyone!

Demosthenes

Demosthenes

Making a website from your game, for your game

Hello there. As mentioned in a previous blog entry, we're developing an adventure game called Outsider, where every puzzle is different. Outsider is being developed in Unity using a plugin called SVG importer, meaning most graphics in the game are vectorial. In the past year, we have improved the graphics a lot: January 2018                     April 2019   Details were added to the graphics, the lighting was tuned and we also started using Unity's recent post-processing profiles. Meanwhile, the website we built for the game still used screenshots from the old version and looked ancient:                   The website was also minimal, consisting of just images and gifs from the game interspersed with minimal text. So, since all the recent browsers support SVG, we decided to use the graphics from this scene, directly from Unity, to create a new website: If you want to take a look, it's live at www.onceabird.com. So, on to the code. Unity supports extending the GUI of your behaviours, so we inherited the Editor class in a WebsiteGeneratorEditor class to create a single button to export the scene layout: [CustomEditor(typeof(WebsiteGeneratorScript))] public class WebsiteGeneratorEditor: Editor { public override void OnInspectorGUI() { DrawDefaultInspector(); serializedObject.Update(); WebsiteGeneratorScript websiteGeneratorScript = (WebsiteGeneratorScript)target; if(GUILayout.Button("Export Scene")) { websiteGeneratorScript.ExportScene(); } } } Each Editor class references another script as a target, in our case it's named WebsiteGeneratorScript. Here's the full source code: WebsiteGeneratorScript.cs, I'll go over it bit by bit. But first some context. The SVG plugin we're using creates an SVG Renderer component (as opposed to the normal Sprite Renderer or other Renderer components) on each behaviour that uses an SVG asset:                   Although some code here is specific to SVG Renderer, most of it is based on Unity's standard position, rotation and scale Transform, so it should be easy to adapt to your project. The exported scene's SVG Renderers are contained in a single root transform named Room: And here's how the WebsiteGeneratorScript component is configured in this scene:                                     We'll gloss over the details for now. The WebsiteGeneratorScript class contains a recursive method named ExportTransform: string transformText = ""; ExportTransform(GameObject.Find("Room").transform, ref transformText); The method searches for an SVGRenderer on each transform, starting from the Room root transform. The transformText variable contains the generated HTML text that will be inserted into an HTML file in the end. Not all the elements in the scene will be exported, so the first thing the method does is return if the transform is in the excludedTransforms list (the contents of which you can see in the WebsiteGeneratorScript component image above): private void ExportTransform(Transform transform, ref string transformText) { if(Array.IndexOf<Transform>(excludedTransforms, transform) >= 0) { return; } If an SVGRenderer component is found, it generates the corresponding HTML img tag: SVGRenderer renderer = transform.GetComponent<SVGRenderer>(); if(renderer != null && !transform.name.ToLower().Contains("interactive")) { float width = renderer.vectorGraphics.bounds.size.x * scale * transform.localScale.x; float height = renderer.vectorGraphics.bounds.size.y * scale * transform.localScale.y; float left = transform.position.x * scale - width / 2.0f - (renderer.vectorGraphics.pivotPoint.x - 0.5f) * width; float top = -transform.position.y * scale - height / 2.0f - (renderer.vectorGraphics.pivotPoint.y - 0.5f) * height; string[] pathParts = UnityEditor.AssetDatabase.GetAssetPath(renderer.vectorGraphics).Split(new char[] { '/' }); string path = ""; for(int i = 3; i < pathParts.Length - 1; i++) { path += pathParts[i] + "/"; } string fileName = pathParts[pathParts.Length - 1]; path += fileName.Substring(0, fileName.IndexOf(".")) + ".svg"; if(positionDifferencesDic.ContainsKey(path)) { Vector2 diff = positionDifferencesDic[path]; left += diff.x; top += diff.y; } string rotationText = transform.eulerAngles.z == 0.0f ? "" : "transform: rotate(" + (-transform.eulerAngles.z) + "deg);" + "transform-origin: " + (renderer.vectorGraphics.pivotPoint.x * 100) + "% " + (renderer.vectorGraphics.pivotPoint.y * 100) + "%;"; string className; if(cssClassesDic.ContainsKey(path)) { className = " " + cssClassesDic[path]; } else { className = ""; } transformText += "<img src='" + path + "' " + "class='transform-image" + className + "' " + "style='left: " + left + "%; top: " + top + "%; width: " + width + "%; height: " + height + "%; " + "z-index: " + renderer.sortingOrder + "; " + rotationText + "' />\n"; } Since we wanted the website to be responsive, the left, top, width and height style properties are calculated in percentage, and every HTML img element uses position absolute. Width and height are calculated first, using a scale variable that is applied to all exported SVG, determining the global exported website scale, the transform's local scale and the size of the SVG itself. If you're using sprites, the width and height of the base image should be used here. Next left and top are calculated. The scale variable is also used, as is the SVG Renderer's vectorGraphics.pivotPoint, which is the center point of any rotation. The path variable contains the URL to the SVG asset, which must be placed separately from this code on your website's file structure. The UnityEditor.AssetDatabase is used to find the file path on the Unity project and replicate it to the exported website path. An example exported HTML img tag looks like this: <img src='SVG/CeilingLamp.svg' id="ceiling-lamp-1" class='transform-image ceiling-lamp' style='left: -24.65349%; top: -58.18391%; width: 10.21898%; height: 38.1918%; z-index: 50;' /> Unity's sortingOrder corresponds to CSS's z-index. Here's the transform-image CSS class: .transform-image { position: absolute; overflow: visible; padding: 0px; margin: 0px; border: 0px; transform: translate3d(0,0,0); max-height: 100%; } (The rest of the source code for the webpage can be viewed on our website, none of the CSS or JS is minified or obscured.) The generated HTML was just the starting point:  We had to condense several SVGs into a single file to improve performance, since SVG rendering still has a way to go on most browsers. Some graphics were created just for the website, such as the social media links on the bottom right corner and the trophies. We used CSS animations and transitions to do zooms but these made the SVG blurry in the iOS version of Safari, so we had to upscale the "clickable" elements in relation to the rest of the elements on the page. The shaking effect was also done with CSS animations. To simulate lighting on the webpage we created a transparent SVG shaped like the lamp light and used blend modes to create the simulated effect.   If you want to know more about Outsider and/or our development process, please follow us on Twitter or Instagram ( or on www.onceabird.com ).
And if there's something unclear or missing in this article please let us know. Thanks for reading!

Demosthenes

Demosthenes

 

DreamBuildPlay 2012

So, we finished our entry on time. In the past two weeks we completed the intro sequence, the animations for when the player dies, built a new tip system and fixed a truckload of bugs.

As mentioned, we replaced last year's tutorial with a tip system. We felt the tutorial was too restrictive for experienced players who will probably guess how most of the game works on their own. The tip system works with question marks that are spread on the first two maps. The players can read these tips when they step on them or dismiss them.

The animation for when the player dies is... Well, you'll see for yourself in the game, it's not something that should be spoiled.

Even if we don't get anything else out of this, I can say contests are a great opportunity to establish goals for your project. We did work in the past two weeks that would otherwise, in our part-time work hours, easily take at least three months.

Here's the video we made for the contest, it was made in a hurry so the editing it's not that good, but...

[media] [/media]

Demosthenes

Demosthenes

 

Shadows & Highlights

A friend thought Twitchy Thrones' sprites were too flat so some shadows/highlights were added. Here's an Hollywood-plastic-surgery-style before/after comparison.

Before:



After:



Before:



After:


Demosthenes

Demosthenes

 

Grenades

We added grenades to the game. Like in most games, the grenade is a powerful and scarce weapon that should only be used in tight situations, giving the player a brief respite from a nasty situation. The player will never have more than a few grenades at a time and they will be very expensive.

Instead of the right trigger, which is used to fire the other weapons, the player throws a grenade with the left trigger. The grenade is only launched when the player releases the trigger, so that it can be cooked to explode earlier than normal. If the player doesn't release the trigger in time, the grenade explodes in the player's position, dealing him just a slight amount of damage. This way the player can use a grenade to get rid of zombies crowding him.

Visually, grenades were given a red "aura" because otherwise they wouldn't be easily visible at night. Also, I used a nearly untouched stock particle effect from the Mercury Particle Engine for the explosion.

Video here:


Demosthenes

Demosthenes

 

DreamBuildPlay 2012

Graveyard Shift made the top 20!

https://www.dreambui...in/winners.aspx



A reference: http://www.theverge.com/gaming/2012/8/20/3255885/dream-build-play-design-competition-announces-it-40-finalists

Demosthenes

Demosthenes

 

Try Bennu out...

The first release candidate of Bennu for PC is here. We're not sure it's finished, so if you want to try it out we're thankful for any bug found, suggestions or comments.

[size="7"][color="#FF0000"]Just don't say it's too hard.[/color]


[size="4"]Download link here.

Demosthenes

Demosthenes

 

Sigh...

http://indiegames.com/2012/02/uberzombie_usa_undead_tower_de.html

Demosthenes

Demosthenes

 

Upgrade Screens

There are two resources to collect in Graveyard Shift: Zombie souls and experience points. Zombie souls must be collected with soul sucker tiles while experience points are dropped by zombies where they die, ala Geometry Wars.

Zombie souls are the currency used to place tiles and enchant them, while experience points help the player gain experience levels. Every time the player goes up an experience level she gets skill points with which she can upgrade her weapons and tile enchantments. Here's a video of the upgrade screens where the player spends skill points:


Demosthenes

Demosthenes

 

New tile upgrade - Flame trail

Made a new tile upgrade that when the player steps on starts leaving behind a flame trail that damages zombies. The tile sprite is not final. Right now, the big red "X" represents a cooldown during which the player can't step on the tile again. Video here:

[media] [/media]

Demosthenes

Demosthenes

 

Blood pools

In order to maximize the "satisfaction per kill ratio" I added blood pools. The pools are made out of a maximum of 3 blood textures that are placed close to each other, rotated randomly and expanded at different rates, giving the sensation of multiple leaking wounds.

Video here:

[media] [/media]

Demosthenes

Demosthenes

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!