So About Those Feedbacks…

TL;DR: forms and polls are good. Feedback from anonymous strangers are very important!

It’s been a few months since we started to develop Alchemist’s Castle and finally I am almost sure that all of the planned features are implemented and working! Up to this point, we were testing the game internally and we only showed it to our few close friends. Not because we were shy or anything, it’s just that there was not much to show and most of the stuff was buggy.

Before we begin to design levels, we thought that it would be a good idea to gather some feedback on the current state of the game. So, we quickly created few levels to see if people like the core of the game. Also, we created a Google Form for the convenience. We were not sure if anyone would actually bother to fill it in but we thought that it was worth to try anyway. While the number of participants was not “overwhelmingly high”, it was sufficient to get a general idea. Here are the results of the main questionaire:

After seeing the  results I was wery glad that we decided to conduct a survey! While the general responses were not bad, it is clear that the people we showed the game before were not “brutally” honest with us. So family and friends are not the best people to ask for a feedback. Hardly a shocking revelation.

Seeing that graphics were generally liked was a relief since it is the hardest part to change in this project. The tile set featured in the demo is not the only  one we have, and personally it is not my favorite either. After adding more varied and more colorful environments, I think the “average graphics score” will go up.

The “Controls” part is where we were deceived by our friends the most. All the feedback we got before this poll was quiet positive. Looking at the graph I can see that this part definitely needs some work.

Other two graphs didn’t surprise us and it is a good news!

Suggestions (most of them anyway)

Now, for the fun part! We also asked for a suggestions and here are some that I would like to about;

Q1: What kind of upgrades would you add to Alchemist’s Castle?

A: Melee weapon (and different weapons in general), teleport, dash, wall jump

We didn’t add melee weapon due to couple of reasons. The character we are playing is an alchemist’s apprintice. Basically a medieval geek and physical power is not his strongest virtue. Also we want to focus more on platforming, exploration and puzzle solving rather than combat.

Teleport is actually a good suggestion. Easy to implement and can be used as a puzzle solving element. I don’t know why we didn’t thought about it. It is possible that we will include it in the final version.

Dash is also a good suggestion, which I thought about. However it is hard to implement at this point.

Wall jump is a feature we already implemented but since double jump serves practically the same purpose we decided to discard it.

Q2: What kind of mechanics would you add to Alchemist’s Castle?

A: Swimming, limited ammo.

I agree that swimming would be nice. We also thought about manupulating water level in some rooms as a puzzle element. But we decided that it would be too much work for this project (scope is important).

We didn’t make the ammo limited since it is our only weapon. However, the more I think about it the more sense it makes. We may include this mechanic in the final version.

Q3: What did you hate the most in this demo?

A: It was short, unfitting music and absence of sound effects, jump.

We wanted to test the controller and see if people like the visual style of the game. Lenghty and challanging gameplay was not our priority. Don’t worry though, final game will be a couple hours long.

Current music is a placeholder and we didn’t include any sound effects yet.

Jump. I think this is why people didn’t like how it feels to control the character. I will work on it some more.

Q4: What did you like the most in this demo?

A: Graphics, it was fun to play, fast gameplay.

Most people praised different visual assets like the player character, the ghost or death of a bat.

Seeing that people also liked the gameplay as a whole was a relief since it means that the character controller is not too bad.

Q5: Anything we forgot to ask? Any suggestions?

A: Lore and story in general.

Don’t worry, there is a story! In fact there is a story for the prequel as well!

Conclusion

Despite the fact that there were not too many participants we managed to gather some valuable data. Perhaps we will do a similar poll before release of the game just to see if we can tweak something.

Again, thanks to you all who spear their time and checked out the demo, and double thanks to all who filled the form!

Stay tuned for further updates!

Anton

UI Programming in Unity3D

The first commercial project which I was involved in was a first-person puzzle game, Fabric. For the most part, I programmed a level editor. As you can imagine, UI was a very big part of it. The way I did it was… well let’s just say it was not a very good implementation. So for my next projects, I decided to develop a better system and here is what I come up with.

The first thing I thought was that there should be one class to rule them all. So I named it UIManager. This is the only UI – related class which other components will know about. It will bring requested UI elements to screen and tell them what to do. To easily switch between different UI states (main menu, in game, pause etc) I decided to create a canvas for each. Now I have MainMenuCanvas, InGameCanvas, and PauseCanvas in my hierarchy. As I mentioned above, the UIManager will only tell these panels what to do. Knowing how to do it should be their responsibility. For this reason, creating a script for each of these panels seems like a good idea. Also, I created an enum to use during the switching process.

Now I have a UIManager class which switches between panels and sometimes tells them what to do. Here is what it looks like:

using UnityEngine;

public enum Panel
{
    Main,
    InGame,
    Pause,
    None
}

public class UIManager : MonoBehaviour
{

    [SerializeField]
    private static MainMenuCanvas mainMenuCanvas;
    [SerializeField]
    private static InGameCanvas inGameCanvas;
    [SerializeField]
    private static PauseCanvas pauseCanvas;

    public static void SetPanel(Panel type)
    {
        mainMenuCanvas.gameObject.SetActive(type == Panel.Main);
        inGameCanvas.gameObject.SetActive(type == Panel.InGame);
        pauseCanvas.gameObject.SetActive(type == Panel.Pause);
    }
}

Now I can easily isolate functionality of each canvas. In case I need to call a specific method from a certain canvas it will be done through UIManager as well. For example, let’s create a “FadePanel”, which will be responsible for fading in and out on a request. Here is a code for that specific canvas:

using System;
using System.Collections;
using UnityEngine;

[RequireComponent(typeof(CanvasGroup))]
public class FadeCanvas : MonoBehaviour
{
    private CanvasGroup cGroup;
    public float fadeSpeed = 5;
    public float middleWaitTime = 0.5f;
    [HideInInspector]
    public bool inProgress = false;

    void Awake()
    {
        cGroup = GetComponent<CanvasGroup>();
    }

    public IEnumerator Fade(Action finalCallback, params Action[] callback)
    {
        inProgress = true;
        while (cGroup.alpha < 0.95f) 
        { 
            cGroup.alpha = Mathf.Lerp(cGroup.alpha, 1, Time.deltaTime * fadeSpeed);
            yield return null;
        } 
        cGroup.alpha = 1;
        if (callback != null)
            foreach (Action a in callback)
                a.Invoke();
        yield return new WaitForSeconds(middleWaitTime);
        
        while (cGroup.alpha > 0.05f)
        {
            cGroup.alpha = Mathf.Lerp(cGroup.alpha, 0, Time.deltaTime * fadeSpeed);
            yield return null;
        }

        if (finalCallback != null)
            finalCallback.Invoke();

        cGroup.alpha = 0;
        inProgress = false;
    }
}

Now we can call Fade() method from UIManager by adding couple lines of code:

using UnityEngine;

public enum Panel
{
    Main,
    InGame,
    Pause,
    Fade,
    None
}

public class UIManager : MonoBehaviour
{

    [SerializeField]
    private MainMenuCanvas mainMenuPanel;
    [SerializeField]
    private InGameCanvas inGamePanel;
    [SerializeField]
    private PauseCanvas pausePanel;
    [SerializeField]
    private FadeCanvas fadeCanvas;
    
    public void Fade(Action finalCallback, params Action[] callback)
    {
        StartCoroutine(fadeCanvas.Fade(finalCallback, callback));
    }

    public void SetPanel(Panel type)
    {
        mainMenuCanvas.gameObject.SetActive(type == Panel.Main);
        inGameCanvas.gameObject.SetActive(type == Panel.InGame);
        pauseCanvas.gameObject.SetActive(type == Panel.Pause);
    }
}

In order to call the fade out – fade in effect all I need is to call Fade() method on the UIManager.

I’ve been using this design in my last few projects and so far I have found it very useful, organized and easy to debug. Please let me know if this is a bad practice in some way or if it can be improved. I would like to learn a better approach to organize the UI if you know any.