Early Access without Steam?

Looking at 6 months of early access sales on itch.io for Nowhere Prophet

For most people Early Access is synonymous with Steam. But with me being a solo-developer and Steam being such a big and important marketplace, I did not want to start with my game there. So instead, I launched Nowhere Prophet on itch.io.

Now, 6 months later I can say it was the right decision. So far I’ve made more than $10,000 in gross revenue on and a noticeable amount of that is from voluntary tips and the kickstarter-like rewards I offer, things that would not have been possible on Steam.

However Steam still plays a role, even when you’re selling elsewhere. Nowhere Prophet has been on Steam ever since the death of greenlight and a visible chunk of traffic and purchases comes from Steam, but more importantly: The sales spikes on itch.io correlate with increased wishlist additions, a key factor for launch success on Steam.

So, read on to find out what I did and how it all shakes out. Including all the interesting numbers for Nowhere Prophet. And as a little bonus: I’ve got some sales data from other itch.io titles for comparison, so you can look forward to even more graphs!

Continue reading


Nowhere Prophet in First Access

Nowhere Prophet, our single-player post-apocalyptic card game has just launched on itch.io. Starting today Nowhere Prophet is available in “First Access”: Imagine if Kickstarter and Early Access had a baby: You can get it early, and you can get special rewards and become a part of the game while you’re at it.

Get Nowhere Prophet Now!

Nowhere Prophet is a single player deck-building game for desktop computers. It is set in a post-apocalyptic world inspired by Indian culture and sci-fi literature. Build a loyal band of followers and survive the journey across a broken world. Barely.

On the trail through the procedurally generated wasteland you will have to fight your enemies in the genre-mix that combines card games, roguelike elements and a tactical turn-based combat system. If you survive you can recruit new followers, find loot and improve your deck to better face the rising challenges ahead.

The game is designed to be a challenging trip through a strange world. Across multiple attempts the player can unlock different classes and convoys until finally they reach the Crypt and unlocks its mysteries.

Get Nowhere Prophet Now!


Devs Discuss: Random Events

If you’re curious about random events in games, you might want to check out this discussion between Johannes from Curious Expedition, Marco from Picaresque Studio and me where we discuss just that. The three of us are all developing travel-games with random events, so that topic fit quite well.

Inspired by a throwaway twitter comment, this improvised chat is just over an hour long and features a bunch of interesting points about the goals and design of these events. So if you’re into that sort of thing, check it out!

– Martin


Unity UI ScrollRect Tools

Working on Nowhere Prophet I built two quick tools for the ScrollRect. I wanted to briefly post them here so maybe someone else can get some use out of them.

One called the ScrollRectTweener can take control over a ScrollRect and smoothly scroll it to a given normalized target position. If the player moves the view while the tweener is acting, then it aborts it’s movement, but you have the option to lock out the player drag when it is working.

The second is the ScrollRectLinker. This component can be put on one scrollRect to link its normalized position to the normalized position of another scrollRect. That way simple parallax scrolling can be quickly set up.

ScrollRectTweener.cs

using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using System.Collections;

[RequireComponent(typeof(ScrollRect))]
public class ScrollRectTweener : MonoBehaviour, IDragHandler {

	ScrollRect scrollRect;
	Vector2 startPos;
	Vector2 targetPos;

	bool wasHorizontal;
	bool wasVertical;

	public float moveSpeed = 5000f;
	public bool disableDragWhileTweening = false;

	void Awake() {
		scrollRect = GetComponent<ScrollRect>();
		wasHorizontal = scrollRect.horizontal;
		wasVertical = scrollRect.vertical;
	}

	public void ScrollHorizontal(float normalizedX) {
		Scroll(new Vector2(normalizedX, scrollRect.verticalNormalizedPosition));
	}

	public void ScrollHorizontal(float normalizedX, float duration) {
		Scroll(new Vector2(normalizedX, scrollRect.verticalNormalizedPosition), duration);
	}
	
	public void ScrollVertical(float normalizedY) {
		Scroll(new Vector2(scrollRect.horizontalNormalizedPosition, normalizedY));
	}
	
	public void ScrollVertical(float normalizedY, float duration) {
		Scroll(new Vector2(scrollRect.horizontalNormalizedPosition, normalizedY), duration);
	}
	
	public void Scroll(Vector2 normalizedPos) {
		Scroll(normalizedPos, GetScrollDuration(normalizedPos) );
	}

	float GetScrollDuration(Vector2 normalizedPos) {		
		Vector2 currentPos = GetCurrentPos();
		return Vector2.Distance( DeNormalize(currentPos), DeNormalize(normalizedPos) ) / moveSpeed;
	}
	
	Vector2 DeNormalize(Vector2 normalizedPos) {
		return new Vector2(normalizedPos.x * scrollRect.content.rect.width, normalizedPos.y * scrollRect.content.rect.height);
	}

	Vector2 GetCurrentPos() {
		return new Vector2(scrollRect.horizontalNormalizedPosition, scrollRect.verticalNormalizedPosition);
	}
	
	public void Scroll(Vector2 normalizedPos, float duration) {
		startPos = GetCurrentPos();
		targetPos = normalizedPos;
		
		if (disableDragWhileTweening) 
			LockScrollability();
		
		StopAllCoroutines();
		StartCoroutine(DoMove(duration));	
	}

	IEnumerator DoMove(float duration) {

		// Abort if movement would be too short
		if (duration < 0.05f)
			yield break;

		Vector2 posOffset = targetPos - startPos;

		float currentTime = 0f;
		while (currentTime < duration) {
			currentTime += Time.deltaTime;
			scrollRect.normalizedPosition = EaseVector(currentTime, startPos, posOffset, duration);
			yield return null;
		}

		scrollRect.normalizedPosition = targetPos;

		if (disableDragWhileTweening) 
			RestoreScrollability();
	}

	public Vector2 EaseVector(float currentTime, Vector2 startValue, Vector2 changeInValue, float duration) {
		return new Vector2(
			changeInValue.x * Mathf.Sin(currentTime/duration * (Mathf.PI/2)) + startValue.x,
			changeInValue.y * Mathf.Sin(currentTime/duration * (Mathf.PI/2)) + startValue.y
			);
	}

	public void OnDrag(PointerEventData eventData) {
		if (!disableDragWhileTweening)
			StopScroll();
	}
	
	void StopScroll() {
		StopAllCoroutines();
		if (disableDragWhileTweening) 
			RestoreScrollability();
	}
	
	void LockScrollability() {
		scrollRect.horizontal = false;
		scrollRect.vertical = false;
	}
	
	void RestoreScrollability() {
		scrollRect.horizontal = wasHorizontal;
		scrollRect.vertical = wasVertical;
	}

}

ScrollRectLinker.cs

using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using System.Collections;

[RequireComponent(typeof(ScrollRect))]
public class ScrollRectLinker : MonoBehaviour {

	public bool clamp = true;

	[SerializeField] ScrollRect controllingScrollRect;
	ScrollRect scrollRect;

	void Awake () {
		scrollRect = GetComponent<ScrollRect>();
		if (controllingScrollRect != null)
			controllingScrollRect.onValueChanged.AddListener(MirrorPos);
	}

	void MirrorPos(Vector2 scrollPos) {

		if (clamp) 
			scrollRect.normalizedPosition = new Vector2( Mathf.Clamp01(scrollPos.x), Mathf.Clamp01(scrollPos.y) );
		else
			scrollRect.normalizedPosition = scrollPos;
	}

}

Enjoy!

– Martin


Unity Editor: Enum Flags as Toggle Buttons

Note: We’ve since cleaned up this code, added view options and released it as a cheap plugin on the Unity Asset Store.

Working on the content tools for our current project I needed enum flags, unfortunately the Unity Editor doesn’t natively support those. Looking around I found a few implementations of enum flags as dropdowns similar to the layer mask dropdown in Unity itself. While that’s pretty neat it has the disadvantage that you don’t have a quick overview over which flags are on and which are off. To that end I’ve built a new custom PropertyDrawer that displays EnumFlags as a neat row of toggle buttons:

Toggle Buttons in Action

Toggle Buttons in Action

All you need is two scripts and an attribute. Also note that your enum needs to start with 1, not 0 and that each value needs to be a power of two (1, 2, 4, 8 etc.)

And here’s the code:

EnumFlagAttribute.cs

This file needs to go in a regular scripts folder (not Editor!). It creates the [EnumFlags] attribute.

using UnityEngine;

public class EnumFlagAttribute : PropertyAttribute
{
	public EnumFlagAttribute() {}
}

EnumFlagDrawer.cs

This one goes into an Editor folder. It manages the display of fields that have the [EnumFlags] attribute.

using System;
using UnityEditor;
using UnityEngine;

[CustomPropertyDrawer(typeof(EnumFlagAttribute))]
public class EnumFlagsAttributeDrawer : PropertyDrawer
{

	public override void OnGUI(Rect _position, SerializedProperty _property, GUIContent _label)
	{
		int buttonsIntValue = 0;
		int enumLength = _property.enumNames.Length;
		bool[] buttonPressed = new bool[enumLength];
		float buttonWidth = (_position.width - EditorGUIUtility.labelWidth) / enumLength;

		EditorGUI.LabelField(new Rect(_position.x, _position.y, EditorGUIUtility.labelWidth, _position.height), _label);

		EditorGUI.BeginChangeCheck ();

		for (int i = 0; i < enumLength; i++) {

			// Check if the button is/was pressed 
			if ( ( _property.intValue & (1 << i) ) == 1 << i ) {
				buttonPressed[i] = true;
			}

			Rect buttonPos = new Rect (_position.x + EditorGUIUtility.labelWidth + buttonWidth * i, _position.y, buttonWidth, _position.height);

			buttonPressed[i] = GUI.Toggle(buttonPos, buttonPressed[i], _property.enumNames[i],  "Button");

			if (buttonPressed[i])
				buttonsIntValue += 1 << i;
		}

		if (EditorGUI.EndChangeCheck()) {
			_property.intValue = buttonsIntValue;
		}
	}
}

I hope you enjoy it. And if you’ve got comments or ideas, let me know!

– Martin

Update: Note about the Unity Asset Store release of an updated version of this code added.


Tooltips with the new Unity UI (uGUI)

Since I needed tooltips to test something really quick I went to see if there was an implementation in the new uGUI system. Unfortunately there were none but a few custom made solutions from other devs. None of those suited me though, so I quickly built my own, very rough version. It consists of two scripts and a view that is the tooltip.

Tooltip Demo

Tooltip Demo

TooltipTrigger

This script is put on all the objects you want to trigger the tooltip. It contains the text that should be shown as a public variable. Everything else is handled by the TooltipView.

using UnityEngine;
using UnityEngine.EventSystems;
using System.Collections;

namespace Sharkbomb.View {
	public class TooltipTrigger : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler, ISelectHandler, IDeselectHandler {

		public string text;

		public void OnPointerEnter(PointerEventData eventData)
		{
			StartHover(new Vector3(eventData.position.x, eventData.position.y - 18f, 0f));
		}	
		public void OnSelect(BaseEventData eventData)
		{
			StartHover(transform.position);
		}
		public void OnPointerExit(PointerEventData eventData)
		{
			StopHover();
		}
		public void OnDeselect(BaseEventData eventData)
		{
			StopHover();
		}

		void StartHover(Vector3 position) {
			TooltipView.Instance.ShowTooltip(text, position);
		}
		void StopHover() {
			TooltipView.Instance.HideTooltip();
		}

	}
}

TooltipView

This script is put on a separate uGUI object that is the actual visible tooltip. It’s a singleton so the many TooltipTriggers can access it quickly and easily.

using UnityEngine;
using System.Collections;

namespace Sharkbomb.View {
	public class TooltipView : MonoBehaviour {
		
		public bool IsActive {
			get {
				return gameObject.activeSelf;
			}
		}
		//public CanvasGroup tooltip;
		public UnityEngine.UI.Text tooltipText;

		void Awake() {
			instance = this;
			HideTooltip();
		}

		public void ShowTooltip(string text, Vector3 pos) {
			if (tooltipText.text != text)
				tooltipText.text = text;

			transform.position = pos;

			gameObject.SetActive(true);
		}
		
		public void HideTooltip() {
			gameObject.SetActive(false);
		}
		
		// Standard Singleton Access 
		private static TooltipView instance;
		public static TooltipView Instance
		{
			get
			{
				if (instance == null)
					instance = GameObject.FindObjectOfType<TooltipView>();
				return instance;
			}
		}
	}
}

As said, it’s a very simple script. There’s a bunch of things it doesn’t do and a few things to be aware of:

– It doesn’t wait a second before showing the tooltip.
– It currently places the tooltip over the object when selecting it via keyboard
– The tooltip can leave the boundaries of the screen and become (partially) invisible
– The tooltip doesn’t move with the cursor – that means it can block raytraces and cause flickering as it blocks the ray to the hovered object, disappearing and reappearing in a new pos


Fast ScriptableObject Creation in Unity

ScriptableObjects can be a very useful feature of Unity but they’re a hassle to create. Here’s a way to do this quickly:

Scriptable Object Context Menu

Scriptable Object Context Menu

In the stock interface there is no way to create ScriptableObjects. Most solutions I found solve this by adding a MenuItem to the top bar. This item then creates a ScriptableObject .asset file of a specific class. This is works but it requires you to adjust the script for each project so it points to a class of that pr oject. It also requires you to create a specific script for each of your classes, even if that might otherwise not be neccessary.

Our ScriptableObjectContextEditor script avoids these problems. Instead of the clumsy menu, it allows you to create .asset files directy from the project pane, where you’d expect it. Not only that, it also has an implementation that allows you to select a script file from which to create an asset, so you don’t need to adjust the script for each project. However if you want to do that you can make use of a generic function provided to create additional pulldown options for specific classes of your own.


Art Direction for Video Games

Art Direction Crash Course!

Art Direction Crash Course!

This Saturday, September 27th the stupendous Anjin Anhut and I will stream another crash course. This time it’s three hours of art direction for video games. You will be able to watch it live on the Sharkbombs Google+ Page.

Target Audience:

This course is intended for small developers, indie developers, students, freelancers and hobbyists who would like to learn more about how to create cohesive and appealing visuals and how to make them work within production requirements and technical limitations. This course provides methods and practices to find and define your artistic vision and to execute that vision alone or in teams.

Content:

We will cover research, working with references, establishing of visual language and style, style guide creation and art review.

All tipps and tricks work for a wide range of styles and many practices apply not only to video games but to comics and animation as well.

When you are joining live, you can ask questions or comment on what you see via the chat. The stream will be in an interview/lecture format in which I will hold the lecture and provide the content, while Martin will be in the role of student. We hope this conversation style format will create a helpful pacing and allow for a fun but also comprehensive course.

When:

2pm German time. Here’s a handy widget to help you figure out your local time:

Time converter at worldtimebuddy.com

Where:

You can watch the video live on the Sharkbombs Google+ Page.
If you miss it you will be able to catch a recording on the Sharkbomb YouTube Channel.

We hope to see you there.

– Martin and Anjin

P.S.: While you wait you can take a look at our first Crash Course: Unity Basics.


Different

So a few weeks ago I released Different, a short game about self-consciousness and first impressions. It’s a personal piece anchored in my experiences and perceptions.

Different Title

Different Title

At it’s core it’s a game about growing up as a non-white person in a predominantly white environment and how one’s perception of race changes slowly. In my case it’s the story of how constant encounters with casual racism made me more and more aware of the fact that I do look decidedly different from the “regular German”.

The most German kiddie picture of me I could find

The most German kiddie picture of me I could find

As a kid I was hardly ever confronted with racism of any kind, but the few instances that I did made the experience stand out strongly. Later in life the occurences have become a lot more frequent, if subtle. Nowadays it’s very common for me to meet someone for the first time, and then, within the first minutes, get asked about my origins.

It is this constant barrage of seemingly innocent questions (“Where are you from?”) and off-putting compliments (“Your German is really good!”) that has solidified in me the awareness of looking different. In the mind of my younger self, there was nothing that clearly separated me from anyone else. We were all different from one another, all in our own way.

In recent years these questions have started to frustrate me more and more, up to the point that I knew I wanted to build the game. It took a while from idea to execution but I am very happy with it. It’s an abstract game, that tries to recreate that experience and that slowly dawning realization, that you are seen as different.

Different Screenshot

Different Screenshot

With my growing awareness also came a frustration at being reduced to this part of me. This found it’s outlet in my answers to these remarks becoming increasingly curt and gruff. Something I’m struggling to let go again. Maybe the game is part of the process.