Archives for posts with tag: developer

A new interview is here! Let’s talk with Fuglesang:

20160220-Splashjam 2016-36-3

Tell us who you are and what do you do on the team.

Hi, I’m Andreas. I’m the CEO but also work as a programmer. I co-founded Moondrop in late 2009 and took over the role as CEO in 2011.

 

What is the most difficult part of your job?

Since I function as two roles in the company, it can be hard to juggle priority between tasks. Sometimes both roles require immediate attention which in turn makes everything just take more time.

 

And the part you enjoy the most?

My heart lies with programming so that is definitely the part I enjoy the most. Finding simple solutions to complicated problems and writing understandable and maintainable code is what I strive for. Over the years I’ve become less tolerant of over-engineered code unless it has a known purpose in the future and must be that way. I mostly thank attending Game Jams for this as it helps me stay pragmatic.

 

You made your own engine in the past, and now you are using Unity. What are the pros and cons of one way and the other?

Today, 3rd party game engines are so mature that there are few reasons to write your own. There are even different engines for various skill level and ambitions. The big disadvantage of using 3rd party engines is the potentially long wait for bugs to get fixed and features to be added, and that can delay your own progress. But it’s insignificant compared to the time it takes to write your own engine. I think you should only write your own because of these reasons:

  • To learn about the inner workings of a game engine.
  • Your game needs a feature that a 3rd party engine doesn’t have and can’t support.
  • You have the knowledge and skill required to make an engine (you probably don’t).
  • You have a lot of time and money, and one of the above is true.

 

What IDE (Integrated development environment) you use? What are your favorite add-ons and for it? How do they help you on your task?

With Unity, I use Visual Studio because of its no-fuzz integration. Just install them and start working. But my favorite ones to use for everything else is Sublime Text and Atom. I like how bare-boned they are and that you can simply add the features you need. Amphora was written using only Sublime Text.

My favorite add-ons:

 

What feature of Degrees of Separation do you feel more proud of?

There is no particular feature I feel more proud of as I think most of it is (and forever will be) half-finished. If anything it might be what I call “SimpleState” which is in practice a state machine. It’s simple (hence the name) but has a lot of utility if used correctly, especially to write maintainable code.

using UnityEngine;
using System;

[Serializable]
public class SimpleState<T> where T : struct, IComparable, IConvertible, IFormattable
{
	[SerializeField]
	private int _state = 0;
	[SerializeField]
	private int _previous_state = 0;

	public int value { get { return _state; } }
	public int previousValue { get { return _previous_state; } }
	public int count { get { return _Count( _state ); } }
	public int previousCount { get { return _Count( _previous_state ); } }

	public EnumState( )
	{
		//--
	}

	public EnumState( T state_ )
	{
		Set( state_ );
	}

	public void Clear( )
	{
		_previous_state = _state;
		_state = 0;
	}

	public void Set( T state_ )
	{
		_previous_state = _state;
		_state = Convert.ToInt32( state_ );
	}

	public void Add( T state_ )
	{
		_previous_state = _state;
		_state |= Convert.ToInt32( state_ );
	}

	public void Remove( T state_ )
	{
		_previous_state = _state;
		_state &= ~Convert.ToInt32( state_ );
	}

	public void Toggle( T state_ )
	{
		_previous_state = _state;
		_state ^= Convert.ToInt32( state_ );
	}

	public bool Is( T state_ )
	{
		return (_state & Convert.ToInt32( state_ )) != 0 ? true : false;
	}

	public bool IsOnly( T state_ )
	{
		return _state == Convert.ToInt32( state_ ) ? true : false;
	}

	public bool IsNone( )
	{
		return _state == 0 ? true : false;
	}

	public bool Was( T state_ )
	{
		return (_previous_state & Convert.ToInt32( state_ )) != 0 ? true : false;
	}

	public bool WasOnly( T state_ )
	{
		return _previous_state == Convert.ToInt32( state_ ) ? true : false;
	}

	public bool Any( )
	{
		return _state != 0 ? true : false;
	}

	public bool WasAny( )
	{
		return _previous_state != 0 ? true : false;
	}

	new public string ToString( )
	{
		char[] b = new char[32];
		int pos = 31;
		int i = 0;

		while( i < 32 )
		{
			b[pos] = (_state & (1 << i)) != 0 ? '1' : '0'; pos--; i++; } return new string( b ); } private int _Count( int state_ ) { int i = state_; i = state_ - ((i >> 1) & 0x55555555);
		i = (i & 0x33333333) + ((i >> 2) & 0x33333333);
		return (((i + (i >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
	}
}

using UnityEngine;
using System.Collections;

public enum PlayerStates
{
	None = 0,
	Idle = 1<<0,
	Walk = 1<<1,
	Jump = 1<<2
}

public class EnumStateTest : MonoBehaviour
{
	private EnumState<PlayerStates> _state;

	private void Start( )
	{
		_state = new EnumState<PlayerStates>( PlayerStates.Idle );
	}

	private void Update( )
	{
		// Check if player wants to/can jump
		// Check if player wants to/can move

		if( _state.Is( PlayerStates.Jump ) )
		{
			if( _HasLanded( ) )
			{
				if( _PlayerWantsToMove( ) )
				{
					_SetAnimation( PlayerStates.Walk );
					_state.Set( PlayerStates.Walk );
				}
				else
				{
					_SetAnimation( PlayerStates.Idle );
					_state.Set( PlayerStates.Idle );
				}
			}
			else
			{
				_ApplyDrag( );
			}
		}
		else if( _state.Is( PlayerStates.Walk ) )
		{
			if( _PlayerStoppedMoving( ) )
			{
				_SetAnimation( PlayerStates.Idle );
				_state.Set( PlayerStates.Idle );
			}
			else
			{
				_ApplyMovement( );
			}
		}
		else if( _state.Is( PlayerStates.Idle ) )
		{
			if( _PlayerWantsToJump( ) )
			{
				_AddJumpForce( );
				_SetAnimation( PlayerStates.Jump );
				_state.Set( PlayerStates.Jump );
			}
			else if( _PlayerWantsToMove( ) )
			{
				_ApplyMovement( );
				_SetAnimation( PlayerStates.Walk );
				_state.Set( PlayerStates.Walk );
			}
		}
	}
}

 

What is that amazing thing about Degrees of Separation you love the most?

The broad range of people that can play the game. It’s purposefully designed this way since we take inspiration from how Disney, Pixar, Nintendo and others make their products, and how well the concept works for this is amazing.

I also have high expectation of the combination of how the exploration and the puzzles will work together. This has not been fulfilled quite yet and I’m excited to see when we get closer to completing the game.

 

Share a screenshot you love, and tell us why. It can be inside Unity Editor, in-game, or showing your favorite software tool!

IMG_07012014_012104

The original character art made by Monica Rong (http://monicarong.no/) in cooperation with Owe has been my favorite one since we started with the concept. To me, it perfectly portrays the vision, and it’s the soul of the game.

Hi, friends! Wanna have another shader session?

Today, we want to show you our approach to make colored fog in Degrees of Separation. You can use this tutorial to make your own fog in your 2D game.

This is not only regular fog that makes objects disappear with distance, but an artistic technique to make your scenery acquire beautiful color tones: Maybe you want to warm it up, making orange fog, or you wish to add a layer of mystery using fog with green tones. You can also use gray tones that will apply normal fog to the scene.

To make the fog happen, we will make a component with adjustable parameters, and a second component that gathers information about the object on which we will apply the fog. Then we’ll send all that to a shader that will change the colors of that object depending on the parameters entered and the position of the object in 3D space.

Setting up a scene

Let’s start with an empty scene. Add any kind of sprite in the center. One sprite is enough for the moment.

We also need an empty game object that can work as a game manager. We will add the component to change our fog settings to this object.

The Fog Data Script

The following script makes up the component for FogData. It will be added to the game manager object. It is a Singleton, by the way, so we can call it without getting a reference, since it would be unique:

using System;
using UnityEngine;

//http://wiki.unity3d.com/index.php/Singleton
public class FogData : Singleton&amp;amp;amp;amp;amp;lt;FogData&amp;amp;amp;amp;amp;gt;
{
#if UNITY_EDITOR
	#region Actions
	public event Action OnChange;
	#endregion Actions	
#endif

	#region InspectorFields	
		
	[Header( "Boundaries" )]
	public Vector2 fogBack = new Vector2( 0f, 50f );
	public Vector2 fogFront = new Vector2( 0f, 1f );
	public Vector2 verticalSplit = new Vector2( 0f, 1f );

	[Header( "Fog Map" )]
	public bool useTexture = true;
	//Texture should be 4 pixels width, the order of columns should be backBottom, backTop, frontBottom, frontTop
	public Texture2D fogRampTexture;

	
	[Header( "Colors" )]
	public Gradient backBottom;
	public Gradient backTop;
	public Gradient frontBottom;
	public Gradient frontTop;
	
	public int colorsResolution = 100;
	#endregion InspectorFields

	#region PrivateFields
	private Texture2D _generated_texture;
	#endregion

	#region Accessors
	//This tell us if we should activate or deactivate the effect.
	//Not only enabling or disabling the component acts on the effect activation; 
	//for example, if fog back minimum is higher than maximum, the effect gets deactivated automatically.
	public bool Activated
	{ get; set; }
	#endregion Accessors

	#region Unity
#if UNITY_EDITOR
	//Calling something changed if the component is activated or deactivated, so we can see the effect right away on the scene
	private void OnEnable( )
	{
		if( OnChange != null )
		{
			OnChange( );
		}

		OnChange += _UpdateFogFromSettings;
	}

	private void OnDisable( )
	{
		if( OnChange != null )
		{
			OnChange( );
		}

		OnChange -= _UpdateFogFromSettings;
	}
#endif

	private void Awake( )
	{
		_UpdateFogFromSettings( );
    }
	#endregion Unity

	//This makes sense only in editor.
#if UNITY_EDITOR
	#region Events
	//This will be called from the editor script when something in the inspector changes
	public void CallOnChangeEvent( )
	{
		if( OnChange != null )
		{
			OnChange( );
		}
	}

	//Redo the texture and recheck if the component should be activated or not
	private void _UpdateFogFromSettings( )
	{
		if( !useTexture )
		{
			_MakeTextureFromColors( );
			fogRampTexture = _generated_texture;
		}

		_UpdateActivated( );
	}
	#endregion Events
#endif

	#region LocalMethods
	private void _UpdateActivated( )
	{
		bool fog_back_min_bigger_than_max = fogBack.x &amp;amp;amp;amp;amp;gt;= fogBack.y;
		bool fog_front_min_bigger_than_max = fogFront.x &amp;amp;amp;amp;amp;gt;= fogFront.y;

		if( !fogRampTexture || fog_back_min_bigger_than_max || fog_front_min_bigger_than_max )
		{
			Activated = false;
		}
		else
		{
			Activated = true;
		}
	}

	private void _MakeTextureFromColors( )
	{
		if(!_generated_texture)
		{
			_generated_texture = new Texture2D( 4, colorsResolution, TextureFormat.ARGB32, false );
		}

		//Properties to make the texture work properly
		_generated_texture.wrapMode = TextureWrapMode.Clamp;
		_generated_texture.anisoLevel = 0;
		_generated_texture.filterMode = FilterMode.Point;

		//Correct order to make the columns in the texture. If we make a manual texture we should follow the same structure.
		Gradient[] colors = { backBottom, backTop, frontBottom, frontTop };

		//Create a 4 by colorsResolution pixel texture, running through all gradients with the order above.
		for( int j = 0; j &amp;amp;amp;amp;amp;lt; 4; j++ )
		{
			Gradient current = colors[j];

			for( int i = 0; i &amp;amp;amp;amp;amp;lt; colorsResolution; i++ )
			{
				_generated_texture.SetPixel( j, i, current.Evaluate( 1 - ( i / (float)colorsResolution ) ) );
			}
		}

		//Apply changes to the texture
		_generated_texture.Apply( );
	}
	#endregion LocalMethods
}

After adding this script, we will have some parameters in the inspector, like this:

We can make it more organized, and hide the gradients if we toggled on Use Texture, since we won’t use them in that case. We can hide the texture also if it’s toggled off.
Apart from that, we need to catch when a change is made in the inspector to refresh the effect while the game is being played in the editor to test on the fly. We should call CallOnChangeEvent method that is in FogData when a change is made. Let’s do all that in an Editor Script, FogDataEditor. We don’t need to add this script anywhere, but we need to put it inside a folder called Editor for Unity to understand that the script is an editor extension:

using UnityEditor;

[CanEditMultipleObjects]
[CustomEditor( typeof( FogData ) )]
public class FogDataEditor : Editor
{
	//Boundaries
	private SerializedProperty fogBack_prop;
	private SerializedProperty fogFront_prop;
	private SerializedProperty fogVertical_prop;

	//Toggle
	private SerializedProperty useTexture_prop;

	//Texture
	private SerializedProperty fogRampTexture_prop;

	//Colors
	private SerializedProperty colorsResolution_prop;

	private SerializedProperty backBottom_prop;
	private SerializedProperty backTop_prop;
	private SerializedProperty frontBottom_prop;
	private SerializedProperty frontTop_prop;

	//target
	private FogData _data;

	#region Unity
	private void OnEnable( )
	{
		_data = target as FogData;

		//Boundaries
		fogBack_prop = serializedObject.FindProperty( "fogBack" );
		fogFront_prop = serializedObject.FindProperty( "fogFront" );
		fogVertical_prop = serializedObject.FindProperty( "verticalSplit" );

		//Toggle
		useTexture_prop = serializedObject.FindProperty( "useTexture" );

		//Texture
		fogRampTexture_prop = serializedObject.FindProperty( "fogRampTexture" );

		//Colors
		colorsResolution_prop = serializedObject.FindProperty( "colorsResolution" );

		backBottom_prop = serializedObject.FindProperty( "backBottom" );
		backTop_prop = serializedObject.FindProperty( "backTop" );
		frontBottom_prop = serializedObject.FindProperty( "frontBottom" );
		frontTop_prop = serializedObject.FindProperty( "frontTop" );
	}

	public override void OnInspectorGUI( )
	{
		serializedObject.Update( );

		EditorGUI.BeginChangeCheck( );

		//Boundaries
		EditorGUILayout.PropertyField( fogBack_prop );
		EditorGUILayout.PropertyField( fogFront_prop );
		EditorGUILayout.PropertyField( fogVertical_prop );

		//Toggle
		EditorGUILayout.PropertyField( useTexture_prop );

		//Hide and show depending on the toggle
		if( useTexture_prop.boolValue )
		{
			//Texture
			EditorGUILayout.PropertyField( fogRampTexture_prop );
		}
		else
		{
			//Colors
			EditorGUILayout.PropertyField( colorsResolution_prop );

			EditorGUILayout.PropertyField( backBottom_prop );
			EditorGUILayout.PropertyField( backTop_prop );
			EditorGUILayout.PropertyField( frontBottom_prop );
			EditorGUILayout.PropertyField( frontTop_prop );
		}

		if( EditorGUI.EndChangeCheck( ) )
		{
			serializedObject.ApplyModifiedProperties( );
			_data.CallOnChangeEvent( );
		}
	}
	#endregion Unity
}

Now, your inspector should look like this:

Use Texture toggled off

Use Texture Toggled on

You may have seen that we have 2 types of fog. Fog Back is for objects that are behind in the scene. Fog Front is for objects that are between the camera and the main part of the scene.

So, now, the inspector shows all these options for us to tweak:

  • Fog Back and Fog Front (Vector2): The fog in the back starts in X and finishes in Y. If we had a gradient that goes from green to red, everything with a z coordinate of the X value of the vector or less will be green; everything with a Z coordinate of the Y value of the vector or more will be red, and everything with a Z coordinate that is between X and Y will follow the gradient.
  • Vertical Split (Vector2): We have 2 colors that blend for both fogs. Everything that has an Y coordinate of X or below will have bottom color, everything that has a coordinate of Y or higher will have top color. Everything between X and Y will blend top and bottom colors like a gradient.
  • Use Texture (bool): If this is on, we can add a texture that will be made manually. The texture should have a width of 4, being each column a fog in this order: fogBackBottom, fogBackTop, fogFrontBottom, fogFrontTop. If the toggle is off, we can select these 4 colors with gradients.
  • Fog Ramp Texture (Texture2D): If Use Texture is on, we set here the texture we made manually.
  • Back Bottom, Back Top, Front Bottom, Front Top (Gradient): We choose the colors that will be used in the texture. In the back fog, the gradient left part is the closest to the camera, the right part is the further. In the front fog goes to the other direction, from the action towards the camera. These will be visible only if Use Texture is off.
  • Colors Resolution (int): This sets how many Y pixels our texture has. The more pixels, the smoother the gradient for the fog will be. It only works if Use Texture is off.

Fog is always applied between Fog Back or Fog Front vector elements (x and y). The gradient will then act depending on the position between the components of the vector. The alpha of the gradient will decide how much fog is applied. An alpha of 0 is not applying fog at all, an alpha of 255 is applying Fog and removing all colors and details of the object. A normal thing to do is to put Alpha 0 to the left side of the gradient, and Alpha 255 to the right.

Applying fog to objects

Of course, this is doing nothing by itself. We now need a script that will be added to every object that we want to be affected by fog.This script will send the Fog Texture and the position to the shader. The Z position is pre-calculated based on the values from FogData so we avoid spending time on that in the shader. Add this script as a component to all objects (with sprites) you want to be affected by fog. It just gets FogData options, make proper calculations depending on the Z position of the object, pack everything in a Vector3 and send it to the shader together with the fog map that has been dynamically created or manually made:

using UnityEngine;

public class Fog : MonoBehaviour
{
	#region Const
	const string ON_KEYWORD = "_FOG_ON";
	const string OFF_KEYWORD = "_FOG_OFF";
	#endregion

	#region PrivateFields
	//Shader Property Ids. It's always better to use id's than to send strings to the shader.
	private int _01_fog_depth_verticals_prop;
	private int _fog_texture_prop;

	//We use this to update fog if an object changes Z position.
	private float _previous_z;

	private Renderer _rend;
	private Material[] materials;

	private bool previous_activation_state;
	#endregion PrivateFields

#region Unity
#if UNITY_EDITOR
	//We subscribe to OnChange to update Fog if the inspector had changes. This only makes sense in Editor.
	private void OnEnable( )
	{
		if( FogData.HasInstance )
		{
			FogData.Instance.OnChange += _UpdateFog;
		}
	}

	private void OnDisable( )
	{
		if( FogData.HasInstance )
		{
			FogData.Instance.OnChange -= _UpdateFog;
		}
	}
#endif

	private void Awake( )
	{
		_01_fog_depth_verticals_prop = Shader.PropertyToID( "_01FogDepthVerticals" );
		_fog_texture_prop = Shader.PropertyToID( "_FogTexture" );

		_rend = GetComponent&amp;amp;amp;amp;amp;lt;Renderer&amp;amp;amp;amp;amp;gt;( );
		materials = _rend.materials;

		_UpdateFog( );
	}

	private void Update( )
	{
		//If the z changed, update fog
		if( _previous_z != transform.position.z )
		{
			_UpdateFog( );
		}
	}

	private void LateUpdate( )
	{
		_previous_z = transform.position.z;
	}
#endregion Unity

#region LocalMethods	
	private bool _IsFogSetAndEnabled( )
	{
		return FogData.HasInstance &amp;amp;amp;amp;amp;amp;&amp;amp;amp;amp;amp;amp; FogData.Instance.Activated &amp;amp;amp;amp;amp;amp;&amp;amp;amp;amp;amp;amp; FogData.Instance.isActiveAndEnabled;
	}

	private void _UpdateFog( )
	{
		if( !_IsFogSetAndEnabled( ) )
		{
			SwitchEffectInShader( false );
		}
		else
		{
			FogData fog_data = FogData.Instance;
			float object_z = Mathf.Abs( transform.position.z );

			//If object is behind we consider front fog, otherwise we consider back fog
			Vector2 fog_limits = fog_data.fogBack;
			float depth_01 = 1;

			//If we our z position is less than 0, we use fog front.
			if( transform.position.z &amp;amp;amp;amp;amp;lt; 0 ) { fog_limits = fog_data.fogFront; depth_01 *= -1; } //Send properties if object is in fog boundaries. bool in_fog_zone = object_z &amp;amp;amp;amp;amp;gt;= fog_limits.x;
			if( in_fog_zone )
			{
				Texture2D fog_tex = fog_data.fogRampTexture;
				Vector2 fog_vertical = fog_data.verticalSplit;

				//This calculates the absolute coordinates for depth depending on FogBack and FogFront, and Z position of the object.
				depth_01 *= Mathf.Clamp01( 1f / ( fog_limits.y - fog_limits.x ) * ( object_z - fog_limits.x ) );

				//Send these properties to the shader, compressed in a Vector3, plus the texture
				_SetShaderFogProperties( new Vector3( depth_01, fog_vertical.x, fog_vertical.y ), fog_tex );
			}
			else
			{
				//If we are out the fog zone, deactivate the shader.
				SwitchEffectInShader( false );
			}
		}
	}

	//This sends the properties to the shader. The Vector with 3 properties of fog boundaries and coordinates, and the texture.
	private void _SetShaderFogProperties( Vector3 fog_depth_verticals_, Texture2D fog_texture_ )
	{
		SwitchEffectInShader( true );

		foreach( Material material in materials )
		{			
			material.SetVector( _01_fog_depth_verticals_prop, fog_depth_verticals_ );
			material.SetTexture( _fog_texture_prop, fog_texture_ );
		}
	}

	//Just activate and deactivate the effect using multi compile, so it's not compiled if it's not necessary.
	public void SwitchEffectInShader( bool activate_ )
	{
		if(activate_ == previous_activation_state)
		{
			return;
		}

		foreach( Material material in materials )
		{

			if( activate_ )
			{
				material.DisableKeyword( OFF_KEYWORD );
				material.EnableKeyword( ON_KEYWORD );
			}
			else
			{
				material.DisableKeyword( ON_KEYWORD );
				material.EnableKeyword( OFF_KEYWORD );
			}
		}

		previous_activation_state = activate_;
    }
#endregion LocalMethods
}

There are different ways to add this script to all objects automatically. The one we use is to make an editor script for SpriteRenderer that will add the script just when the SpriteRenderer component is created.

The shader

We need now to make our shader, the golden piece of this process. This shader has to be applied to a material, and that material will be set in our objects. Our previous tutorial about foliage waver shows how to do this, if you don’t know.

Shader "Moondrop/Fog"
{
    Properties
	{
        _MainTex( "Warm Texture", 2D ) = "black" { }

		_01FogDepthVerticals( "Linear Depth 01 And Verticals(RO)", Vector ) = ( 0.0, 0.0, 0.0, 0.0 )
		_FogTexture( "Fog Ramp Texture (RO)", 2D ) = "black" { }

		_Color( "Tint", Color ) = ( 1, 1, 1, 1 )

		[MaterialToggle] PixelSnap( "Pixel snap", Float ) = 0
	}

	SubShader
	{
        Tags
		{
            "Queue" = "Transparent"
			"IgnoreProjector" = "True"
			"PreviewType" = "Plane"
			"CanUseSpriteAtlas" = "True"
			"RenderType"="Transparent"
		}

		Cull Off
		Lighting Off
		Blend One OneMinusSrcAlpha
		ZWrite Off

		CGPROGRAM

		#pragma surface surf Lambert vertex:vert nofog keepalpha
		#pragma target 3.0
		#pragma multi_compile _PIXELSNAP_ON

		//This is necessary to deactivate fog effects if they are not used.
		#pragma multi_compile _FOG_OFF _FOG_ON

		sampler2D _MainTex;
        fixed4 _Color;

        struct Input
		{
            float2 uv_MainTex;
            #if defined( _FOG_ON )					
				float worldPosY;
			#endif
            fixed4 color;
        };

		//Just normal stuff
        void vert( inout appdata_full v, out Input o )
		{
            #if defined( PIXELSNAP_ON )
				v.vertex = UnityPixelSnap( v_.vertex );
            #endif
			
			UNITY_INITIALIZE_OUTPUT( Input, o );
            o.color = v.color * _Color;

			#if defined( _FOG_ON )	
				o.worldPosY = mul( unity_ObjectToWorld, v.vertex ).y;
			#endif
        }

		#if defined( _FOG_ON )
			/****************************************************************************/
			/**********************************FOG***************************************/
			/****************************************************************************/

			fixed4 _01FogDepthVerticals;
			sampler2D _FogTexture;

			float4 FogProperties( float world_pos_y_, float tex_columns_ )
			{
				float fog_bottom_column = tex_columns_;
				float fog_top_column = tex_columns_ + 0.25;
				float fog_depth = abs( _01FogDepthVerticals.x );

				//If the depth is negative, we are using front fog.
				fog_bottom_column += step( 0.f, -_01FogDepthVerticals.x ) * 0.5f;
				fog_top_column += step( 0.f, -_01FogDepthVerticals.x ) * 0.5f;

				//Calculate positions depending on depth, bottom and top.
				float2 fog_position_bottom = float2( fog_bottom_column, 1 - fog_depth );
				float4 bottom_FogTexture = tex2D( _FogTexture, fog_position_bottom );

				float2 fog_position_top = float2( fog_top_column, 1 - fog_depth );
				float4 top_FogTexture = tex2D( _FogTexture, fog_position_top );

				//Vertical position
				float vertical_pos = clamp( ( world_pos_y_ - _01FogDepthVerticals.y) / (_01FogDepthVerticals.z - _01FogDepthVerticals.y ), 0, 1 );

				//Blend bottom and top.
				return lerp( bottom_FogTexture, top_FogTexture, vertical_pos );
			}

			fixed4 CalculateFog( float world_pos_y_ )
			{
				//Calculate the color, alpha is the amount of fog.
				float4 fog_tex = FogProperties( world_pos_y_, 0.125  );
				float factor = fog_tex.a;
				return lerp( 0, fog_tex, factor );
			}
		#endif

		/****************************************************************************/
		/****************************************************************************/
		/****************************************************************************/

		
		void surf( Input i, inout SurfaceOutput o )
		{
            fixed4 color = tex2D( _MainTex, i.uv_MainTex ) * i.color;

            #if defined( _FOG_ON )					
				fixed4 fog_color = CalculateFog( i.worldPosY );

				//We have to remove the actual color of the object, the more fog it has, because we will increase emission.
				color.rgb *= ( 1 - fog_color.a );

				//We add the fog as emission. 
				//Since fog is not affected by any type of lights we need emission to become the color of the object.
				o.Emission = fog_color * color.a;
            #endif						

			o.Albedo = color.rgb * color.a ;
            o.Alpha = color.a;
        }
			
		ENDCG
	}
			
	FallBack "Diffuse"
}

This surface shader is pretty much standard, it only plays with color and emission depending on the fog properties and the position in the world.

Final results

Ok, everything is ready now.

I recommend putting the camera to perspective to better understand the results.
Let’s set the parameters of GameManager’s FogData like this to see nice results:

Move the object along the Z coordinate. Bravo!

You have a fully functional fog that will make your scenes beautifully colored!

You can download an entire Fog Unity Package with all necessary things built and ready.

Continuing what we started a couple of weeks ago, we have a new interview today.
Next developer: Karoline Skoglund Olsen, our artist. Let’s get influenced by her talent!

KarolineTell us who you are and what do you do on the team.

I am Karoline, the team’s artist. I started working here in September 2015, not long before  Alex did. I make the game’s art together with Owe, our lead designer.

 

What is the most difficult part of your job?

When there is a lot of work to be done, and all inspiration seems to elude me… I also have days where everything I make turns out not the way I want it to.

 

And the one you enjoy the most?

I love the days when I’m really inspired and everything just flows. When I can just sit day and night creating pieces I can feel proud of. It’s a wonderful feeling when you draw something and you think to yourself: “hey, this isn’t half bad!”.

 

Tell us how you make the game’s art:

What is your gear?

I work with Photoshop CC, and I use my trusted Wacom 13HD Cintiq. I also have a Wacom Intuos Pro Medium that I use at the office.

 

How do you make yourself comfortable before starting to draw?

Being the creative weird person that I am, I usually put on my pajama pants (when working at home), get myself a cup of coffee and just start to draw. It’s also nice to have some noise like music or Netflix in the background.

 

Can you explain the process you follow when you create a new piece of art?

It varies, sometimes I find pictures or art that inspire me in some way; other times I just start to draw and it just turns into something.

 

What is that amazing thing of Degrees of Separation you love most?

I really like the atmosphere of the game, the music and the art style comes together making it an almost magical experience, like a fairytale.

 

Why do you think Degrees of Separation will be a great success?

I think it will become a success because it’s so approachable. I’ve seen fathers play our demo with their daughters, siblings working together to solve the puzzles and couples discussing why their chosen character in the game obviously is the best character. I think that this is a game everyone would like; even people who don’t really see themselves as gamers.

 

What room would you add to the castle, and which use would you love for it to have?

I don’t know if there is something special I would like to add in the castle, but maybe a hidden room or something where you could have the possibility to unlock certain features or special levels. We were joking at a meeting, not so long ago, that it would be fun to add the possibility to unlock the “googly eye” version of the game if you got all the collectables. The “googly eye” version would be the exact same game, just that everything now has googly eyes on them, and I mean everything…

 

Share a screenshot you love, and tell us why. It can be inside Unity Editor, in-game, or showing your favorite software tool!

This is one of my favorite places in the game so far, this is after Ember and Rime fall down after the bridge breaks and land in the deep forest. I love the way the tree log bends and dampen their fall.

Ember Met Rime

Picture 1 of 1