Bloodirony Blog


Blog

INSIGHTS, TUTORIALS AND DIRTY SECRETS

Viewing entries in
Development

How to support multiple languages in Unity

4 Comments

How to support multiple languages in Unity

Together with our Publisher Noodlecake we have decided to translate Shooting Stars in order to boost the reach of the game.  For the initial release we have decided to go with the 7 most common (AppStore) languages English, German, Italian, French, Spanish, Portuguese and Russian.

To implement more than one language without a lot of fuzz, we wanted to find a solution that perfectly fits our workflow.  After a couple of experiments we have decided to create a custom Text component that allows our designer to easily build localized interfaces without the need to write a single line of code. To keep things simple, we are using simple .txt files to store our internationalized strings as key-value pairs. 

For example:

key=This is a test text

So there is a .txt file for every language we support, with same keys and translated values. To prevent lags during gameplay I load the right language file in a static Dictionary on app start. As a fallback I also load the english version in a separate Dictionary in case of a missing key.

Next step was the actual display of the translated text. Therefore I have overridden the built in Text component and added a key field to my new component.

This is how I load the strings from the file into a Dictionary:

private void LoadLanguage(string lang){
    fields.Clear();
    TextAsset textAsset=Resources.Load("I18N/"+lang);
    string allTexts="";
    if(textAsset==null){
        textAsset=Resources.Load("I18N/en");
    }
    allTexts=textAsset.text;
    string[] lines=allTexts.Split(new string[] { "\r\n", "\n" },
        StringSplitOptions.None);
    string key, value;
    for(int i=0;i < lines.Length;i++){
        if(lines[i].IndexOf("=") >= 0 && !lines[i].StartsWith("#")){
            key=lines[i].Substring(0, lines[i].IndexOf("="));
            value=lines[i].Substring(lines[i].IndexOf("=")+1,
                    lines[i].Length-lines[i].IndexOf("=")-1).Replace("\\n", Environment.NewLine);
            fields.Add(key, value);
        }
    }
}
    

The custom Text component:

public class TextI18N : Text {

    public string i18NKey;

    void Awake(){
        Refresh();
    }

    public void Refresh(){
        text=I18N.Instance.Get(i18NKey, false);
    }
}

UPDATE

After posting this tutorial on reddit, the user justaghostofanother wrote a super detailed do's and don'ts about localization which can be found in the /r/unity3d thread.

4 Comments

How to create a random tileset in Unity2D

2 Comments

How to create a random tileset in Unity2D

When it comes to the background, classic shmups usually use something like infinite scrolling. Because we are not making a normal shmup with spaceships and other flying stuff we wanted to handle this completely different.

Therefore we created a static background, which is not moving during the actual battle. To give the user some feedback regarding progress, we also move the background after defined waves or a boss fight.

To avoid creating hundreds of full sized background assets we thought of randomly create these backgrounds out of a tileset image.


This is actually quite easy, the only thing you need is a image with a defined grid of single tiles. Next thing you will need is something to draw the tiles on. I used the unity plane component with a mesh renderer for that.

First step, initialize the mesh:

int numTiles = size_x * size_y;
int numTris = numTiles * 2;

int vsize_x = size_x + 1;
int vsize_y = size_y + 1;
int numVerts = vsize_x * vsize_y;

Vector3[] vertices = new Vector3[ numVerts ];
Vector3[] normals = new Vector3[numVerts];
Vector2[] uv = new Vector2[numVerts];

int[] triangles = new int[ numTris * 3 ];

int x, z;
for(z=0; z < vsize_y; z++) {
    for(x=0; x < vsize_x; x++) {
        vertices[ z * vsize_x + x ] = new Vector3( x*tileSize, 0, -z*tileSize );
        normals[ z * vsize_x + x ] = Vector3.up;
        uv[ z * vsize_x + x ] = new Vector2( (float)x / size_x, 1f - (float)z / size_y );
    }
}

for(z=0; z < size_y; z++) {
    for(x=0; x < size_x; x++) {
        int squareIndex = z * size_x + x;
        int triOffset = squareIndex * 6;
        triangles[triOffset + 0] = z * vsize_x + x +           0;
        triangles[triOffset + 2] = z * vsize_x + x + vsize_x + 0;
        triangles[triOffset + 1] = z * vsize_x + x + vsize_x + 1;

        triangles[triOffset + 3] = z * vsize_x + x +           0;
        triangles[triOffset + 5] = z * vsize_x + x + vsize_x + 1;
        triangles[triOffset + 4] = z * vsize_x + x +           1;
    }
}

// Create a new Mesh and populate with the data
Mesh mesh = new Mesh();
mesh.vertices = vertices;
mesh.triangles = triangles;
mesh.normals = normals;
mesh.uv = uv;

// Assign our mesh to our filter/renderer/collider
MeshFilter mesh_filter = plane.GetComponent();
MeshCollider mesh_collider = plane.GetComponent();

mesh_filter.mesh = mesh;

 

Next step, split your background image into single tiles:

private Color[][] SplitTiles() {
    int numTilesPerRow = texture.width / tileResolution;
    int numRows = texture.height / tileResolution;

    Color[][] tiles = new Color[numTilesPerRow*numRows][];

    for(int y=0; y < numRows; y++) {
        for(int x=0; x < numTilesPerRow; x++) {
            tiles[y*numTilesPerRow + x] = texture.GetPixels( x*tileResolution , y*tileResolution, tileResolution, tileResolution );
        }
    }

    return tiles;
}


Final step, draw your random tiles on the mesh:

int texWidth = size_x * tileResolution;
int texHeight = size_y * tileResolution;
Texture2D newTexture = new Texture2D(texWidth, texHeight,texture.format, false);

Color[][] tiles = SplitTiles();

for(int y=0; y < size_y; y++) {
    for(int x=0; x < size_x; x++) {
        Color[] p = tiles[Random.Range(0, 30)];
        newTexture.SetPixels(x*tileResolution, y*tileResolution, tileResolution, tileResolution, p);
    }
}
newTexture.anisoLevel=1;
newTexture.mipMapBias=0f;
newTexture.filterMode = FilterMode.Point;
newTexture.wrapMode = TextureWrapMode.Clamp;
newTexture.Apply();

MeshRenderer mesh_renderer = _plane.GetComponent();
mesh_renderer.sharedMaterials[0].mainTexture = newTexture;

With a shader on top the final result looks like this

Download Unity 5 Sample Project

As with every previous tutorial, we provide you with a sample project for Unity 5.

2 Comments

How to create a Lightning Strike in Unity2D

3 Comments

How to create a Lightning Strike in Unity2D

After creating some Sci-Fi attacks like the Rainbow Lazer or the Ro-Cat-Paw Launcher we thought the next special attack should be something more RPG like. So this Blogpost is about how I created a cool chaining lightning strike.

The main idea behind the lightning is to have some line renderers between enemies and generate random line renderer points to get some movement into it. To get amount of points I callculate the distance from the lightning source to its target and split it into segments. After that i know how much points I need. To get the distance between our hero and the enemies I maintain a list of all alive enemies. Just add some randomness and you are almost done.

To make the line renderers look like lightnings I used a texture with a gradient. To make it even more better looking I added one more line renderer simulating a light.

For creating single lightning Bolts I created a separate class:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class ChainLightning : MonoBehaviour{
    [Header("Prefabs")]
    public GameObject lineRendererPrefab;
    public GameObject lightRendererPrefab;

    [Header("Config")]
    public int chainLength;
    public int lightnings;

    private float nextRefresh;
    private float segmentLength=0.2f;

    private List LightningBolts{get; set;}
    private List Targets{get; set;}

    void Awake(){
        LightningBolts=new List();
        Targets=new List();

        LightningBolt tmpLightningBolt;
        for(int i=0;i < chainLength;i++){
            tmpLightningBolt=new LightningBolt(segmentLength, i);
            tmpLightningBolt.Init(lightnings, lineRendererPrefab, lightRendererPrefab);
            LightningBolts.Add(tmpLightningBolt);
        }
        BuildChain();
    }

    public void BuildChain(){
        //Build a chain, in a real project this might be enemies ;)
        for(int i=0;i < chainLength;i++){
            Targets.Add(new Vector2(Random.Range (-2f, 2f), Random.Range (-2f, 2f)));
            LightningBolts[i].Activate();
        }
    }

    void Update(){
        //Refresh the LightningBolts
        if(Time.time>nextRefresh){
            BuildChain();
            for(int i=0;i < Targets.Count;i++){
                if(i==0){
                    LightningBolts[i].DrawLightning(Vector2.zero, Targets[i]);
                }else{
                    LightningBolts[i].DrawLightning(Targets[i-1], Targets[i]);
                }
            }
            nextRefresh=Time.time+0.01f;
        }
    }
}

To draw the actual lightning segments I created another class:

using UnityEngine;
using System.Collections;

public class LightningBolt {

    public LineRenderer[] lineRenderer{get; set;}
    public LineRenderer lightRenderer{get; set;}

    public float SegmentLength{get; set;}
    public int Index{get; private set;}
    public bool IsActive{get; private set;}

    public LightningBolt(float segmentLength, int index){
        SegmentLength=segmentLength;
        Index=index;
    }

    public void Init(int lineRendererCount, 
            GameObject lineRendererPrefab, GameObject lightRendererPrefab){
        //Create the needed LineRenderer instances
        lineRenderer=new LineRenderer[lineRendererCount];
        for(int i=0;i < lineRendererCount;i++){
            lineRenderer[i]=(GameObject.Instantiate(lineRendererPrefab) as GameObject)
                .GetComponent();
            lineRenderer[i].enabled=false;
        }
        lightRenderer=(GameObject.Instantiate(lightRendererPrefab) as GameObject)
            .GetComponent();
        IsActive=false;
    }

    public void Activate(){
        //Active this LightningBolt with all of its LineRenderers
        for(int i=0;i < lineRenderer.Length;i++){
            lineRenderer[i].enabled=true;
        }
        lightRenderer.enabled=true;
        IsActive=true;
    }

    public void DrawLightning(Vector2 source, Vector2 target){
        //Calculated amount of Segments
        float distance=Vector2.Distance(source, target);
        int segments=5;
        if(distance > SegmentLength){
            segments=Mathf.FloorToInt( distance / SegmentLength)+2;
        }else{
            segments=4;
        }

        for(int i=0;i < lineRenderer.Length;i++){
            // Set the amount of points to the calculated value
            lineRenderer[i].SetVertexCount(segments);
            lineRenderer[i].SetPosition(0, source);
            Vector2 lastPosition=source;
            for(int j=1;j < segments-1;j++){
                //Go linear from source to target
                Vector2 tmp=Vector2.Lerp(source, target, (float)j / (float)segments);
                //Add randomness
                lastPosition=new Vector2(tmp.x+Random.Range(-0.1f, 0.1f), 
                    tmp.y+Random.Range(-0.1f, 0.1f));
                //Set the calculated position
                lineRenderer[i].SetPosition(j, lastPosition);
            }
            lineRenderer[i].SetPosition(segments-1, target);
        }
        //Set the points for the light
        lightRenderer.SetPosition(0, source);
        lightRenderer.SetPosition(1, target);
        //Set the color of the light
        Color lightColor=new Color(0.5647f, 0.58823f, 1f, Random.Range (0.2f, 1f));
        lightRenderer.SetColors(lightColor, lightColor);
    }
}

The Result

DOWNLOAD UNITY 5 SAMPLE PROJECT

As usual, we want to share a sample project with you – so, it's much easier to understand what we are talking about. Same as last time, be fair and please don't use the graphic assets in your own games.  

3 Comments

How to create a Mega-Rainbow-Lazer in Unity2D

4 Comments

How to create a Mega-Rainbow-Lazer in Unity2D

Every time we thought about cool special attacks we could include in Shooting Stars, the mighty Mega-Rainbow-Lazer came into our minds first. So now I will describe how we created that awesome piece of destruction.

When I thought about how to build that weapon, I feared that it will be quite complicated. My first approach was to use a LineRenderer with an animated texture for the lazer itself. But here we stumpled upon some difficulties by combining animated textures with a dynamic lazer height. After some tests with the LineRenderer we realized that we don't necessarily need an expandable lazer which made things a lot easier. So, I decided to switch to a Sprite Renderer that is stretched bigger than our screen will ever get.

But we still had a problem with the animated lazer "stripe"-thingies to give the lazer more juicyness. The easiest solution to solve that was to handle those white stripes (haha) like bullets that even deal damage to enemies – which fortunately solved the problem on how we deal damage to enemies on the fly. 

Basically the solution I used for the lazer is to create a stretched Game Object with a Sprite Renderer that renders the rainbow texture and just move the bullets up on the rainbow sprite. The dynamic lightning is created by a Sprite Renderer behind the actual lazer with a mobile/particle/additive shader. To give the lazer some additional dynamics I changed the width and opacity of the sprites randomly.

To pimp the launch area of the lazer a bit, I simply used a white circle with colored border and animated the strength of the border. 

Our lazer consists of five main parts:

Here is the code that adds the mentioned dynamic effect to our fancy lazer:

float scaleX=Random.Range (0.8f, 1.2f);
laserGO.transform.localScale=new Vector3(scaleX, 1f);

float lightOpacity=Random.Range (-0.1f, 0f);
Color newColor=lightMiddleSpriteRenderer.color;
newColor.a=startLightOpacity+lightOpacity;

lightMiddleSpriteRenderer.color=newColor;
lightStartSpriteRenderer.color=newColor;

Everything mixed together results in a cool looking Mega-Rainbow-Lazer:

Update #1 
gobgobs asked us:

"Is it possible if you can expand a little on the light created?"

Sure, creating the dynamic light was pretty easy. 

  1. Create a new GameObject, add a Sprite Renderer with a Sprite like the Rainbow Light Texture from above. Your object will look like #1.
  2. Create a new Material, in our case we named it "AdditiveLight", and set the Shader to "Particles/Additive (Soft)" or "Mobile/Particles/Additive". Now all you have to do is to drag the new material into the material slot at the Sprite Renderer (replace the "Sprite-Default" material) The rendered GameObject will look like #2.
  3. Since we are using a black/white Sprite we can make use of the "Color" option to tint the Sprite in whatever color we prefer. Play around with the color and opacity settings and you get an effect like #3

In our case we just scaled the light a lot up and turned the alpha channel of the "color" option pretty low. While shooting the lazer beam we dynamically randomize the width of the lazer which gives us this nice dynamic light effect. (see the script above)

We are using the same technique quite often, e.g. as a permanent light effect for our main character Tscherno or to give our bullets and rockets more atmosphere.

Update #2
We've been asked on Reddit to share a sample project on how to create the lazer and the dynamic light. There is nothing we love more than to share what we've learned in the last couple of months. – Please be fair and don't use our graphic assets in your own project. 

4 Comments

The Art of Screenshake in Unity2D

Comment

The Art of Screenshake in Unity2D

Due to the fact that our Big Bad Bearded Boss is a huge Vlambeer fan, my first task was to watch the presentation of Vlambeers Jan Willem Nijman Gamefeel. JW showed 30 little tricks to make your action game more fun. This post is about how to implement some of this tricks in Unity for our upcoming game Shooting Stars.

Screenshake

Let's start with the screenshake effect. The main approach is to shake the camera randomly in special moments of the game. For example on a bullet impact or an explosion. My first attempt to get this done was using iTweens ShakePosition(). The effect itself was really cool, BUT there was a problem with multiple screenshakes at the same time using ShakePosition(), so I started to implement my own solution:

private Vector3 cameraStartPosition;
private float shakeAmountX;
private float shakeAmountY;
private float time;
bool reset=true;

public void Init () {
    cameraStartPosition=Camera.main.gameObject.transform.position;
    InvokeRepeating("CameraShake", 0, .01f);
}

public void ScreenShake(float amountX, float amountY, float _time){
    if(amountX>shakeAmountX){
        shakeAmountX = amountX;
    }

    if(amountY>shakeAmountY){
        shakeAmountY = amountY;
    }
    if(_time>time){
        time=_time;
    }
    reset=false;    
}

public void ScreenShake(float amount, float _time){
    if(amount>shakeAmountX && amount>shakeAmountY){
        shakeAmountX = amount;
        shakeAmountY = amount;
    }
    if(_time>time){
        time=_time;
    }
    reset=false;
}

void CameraShake(){
    if(shakeAmountX>0 && shakeAmountY>0 && time>0) {
        time-=.01f;
        float quakeAmtX = UnityEngine.Random.value*Mathf.Sin( shakeAmountX)*2 - shakeAmountX;
        float quakeAmtY = UnityEngine.Random.value*Mathf.Sin(shakeAmountY)*2 - shakeAmountY;
        Vector3 pp = cameraStartPosition;
        pp.y+= quakeAmtY; // can also add to x and/or z
        pp.x+= quakeAmtX;
        Camera.main.transform.position = pp;
    }else if(!reset){
        Camera.main.transform.position=cameraStartPosition;
        reset=true;
    }
}

Kickback on Shoot

Another thing I wanted to implement is a little kickback whenever our main character is shooting lazers, bullets or whatever. Due to the fact that our game is a vertical shootemup this was quite easy to implement. Whenever our main character is shooting I manipulate his y position by a small random amount:

targetPosition.y=targetPosition.y-UnityEngine.Random.Range (0.1f, 0.3f);

Permanence

I also thought about implementing some permanence. So I decided to make our “lazer shells” permanent. First of all I created a flight path for our shells by using iTweens MoveTo(). Not really satisfied with the result I added some rotation to the shells by using RotateBy(). After the movement of our shells is over the GameObjects will stay whereever they moved to. The problem is, that after some minutes of constantly shooting, you have a lot of shells lying around. This is not a problem for the PC or Mac version, but will be a problem for mobile devices due to limited amount of available Memory. So for performance reasons I have to destroy the shells (or move them back to a pool) after some time.

float height=UnityEngine.Random.Range (0.2f, 0.7f);
iTween.MoveTo(gameObject, iTween.Hash("path",new Vector3[]{
    new Vector3(transform.position.x+0.4f,transform.position.y+height,0), 
new Vector3(transform.position.x+height+0.2f,transform.position.y-0.4f,0)}, "time",1,"easetype",iTween.EaseType.linear));
iTween.RotateBy(gameObject, iTween.Hash(
    "name", "ShellRotation", "looptype",iTween.LoopType.none, "z", Random.Range(-6f, 6f), "time",  0.9f));
Destroy (gameObject, 10f);

What's next?

Because of problems with permanence, missing image effects, etc. we consider switching from the free version to Unity Pro. Come back soon, if you want to know which way we will go.

Comment