HELLCASTER

Role: Project Lead and Creative Director

Team Size: 12

Development Time: 11 Weeks

Tools: GitHub, Jira, Miro

Languages / Engine: C#, HLSL, Unity

Game Genre: FPS / Deck-builder / Rhythm

Play as a metalhead wizard, forged in the mosh pits of hells. Your scrolls are your song sheets, and your spell deck is the set list!



HELLCASTER is an adrenaline-fueled FPS game with real-time deck building system for the player's magic scrolls.



Make use of spell synergies and staying on music beat for your attacks to gain more power!

My Contributions

My Contributions

My Contributions

As the team lead and creative director, I was overlooking the entire project, both the artistic and technical sides.


Despite a large team of 12, and only 11 weeks of development, I think I've managed to bring the final result very close to my initial game vision!


The priority was to have HELLCASTER progress evenly throughout each aspect of development: art, design and code.


My main tasks were keeping the project on-track: design documents, UI and game layout concept art, and providing my team with all the necessary tools and additional references for clearer vision of the game. 



As the team lead and creative director, I was overlooking the entire project, both the artistic and technical sides.


Despite a large team of 12, and only 11 weeks of development, I think I've managed to bring the final result very close to my initial game vision!


The priority was to have HELLCASTER progress evenly throughout each aspect of development: art, design and code.


My main tasks were keeping the project on-track: design documents, UI and game layout concept art, and providing my team with all the necessary tools and additional references for clearer vision of the game. 



Particle Effects : Spells and Bloodsplatters

I’ve made almost all of the particle effects for spells and summoning circles, as well as different types of enemy blood splatter decals.

Diegetic Pause Menu: Shaders and DOTween

I used DOTween for an effective animation upon pause menu, as well as added various functionality within the menu, for example guitar sticker customization.


One of my favorite coding tasks on HELLCASTER were my shaders - both using shader graphs, and HLSL scripting (High-Level Shading Language).


I am especially proud of my animated outline shader written using HLSL, which could be applied to any 2D image. I have made the HLSL script compatible with URP and have converted the shader to use unscaled time, which allowed for the shader animation to run even while the game is paused and timescale is zero. The guitar script is continuously feeding unscaled time to the outline shader, so the animation never freezes.​

I have also written shaders for the game's overall visuals, such as pixelation, affine texture warping, dithering and simple cel shading for certain unique objects, such as crystals.


Shader "Custom/UI_UnscaledAnimatedOutline"
{
    Properties
    {
        _MainTex ("Sprite Texture", 2D) = "white" {}
        _Color ("Base Color", Color) = (1,1,1,1)

        _OutlineColor ("Outline Color", Color) = (0,0,0,1)
        _OutlineGapColor ("Outline Gap Color", Color) = (1,1,1,1)
        _OutlineThickness ("Outline Thickness", Float) = 2.0
        _OutlineDot ("Dot Spacing", Float) = 10.0
        _OutlineDot2 ("Dot Gap", Float) = 0.5
        _OutlineSpeed ("Dot Scroll Speed", Float) = 1.0

        _UnscaledTime ("Unscaled Time", Float) = 0
    }

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

        Pass
        {
            Name "UI_AnimatedOutline"
            Tags { "LightMode"="SRPDefaultUnlit" }
            Blend SrcAlpha OneMinusSrcAlpha
            ZWrite Off
            Cull Off

            HLSLPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"

            TEXTURE2D(_MainTex);
            SAMPLER(sampler_MainTex);

            float4 _Color;
            float4 _OutlineColor;
            float4 _OutlineGapColor;
            float _OutlineThickness;
            float _OutlineDot;
            float _OutlineDot2;
            float _OutlineSpeed;
            float _UnscaledTime;

            struct Attributes
            {
                float4 positionOS : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct Varyings
            {
                float4 positionCS : SV_POSITION;
                float2 uv : TEXCOORD0;
            };

            Varyings vert(Attributes v)
            {
                Varyings o;
                o.positionCS = TransformObjectToHClip(v.positionOS);
                o.uv = v.uv;
                return o;
            }

            float4 frag(Varyings i) : SV_Target
            {

                float4 col = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.uv) * _Color;

                if (col.a > 0.01){
                    return col;
                }
                    

                float2 uv = i.uv;


                float2 offsets[8] = {
                    float2(-1,0), float2(1,0),
                    float2(0,-1), float2(0,1),
                    float2(-1,-1), float2(-1,1),
                    float2(1,-1), float2(1,1)
                };

                float2 texelSize = _OutlineThickness / float2(512,512); 
                float maxNeighborAlpha = 0.0;

                for(int k=0;k<8;k++)
                {
                    float2 uvOff = uv + offsets[k]*texelSize;
                    float a = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uvOff).a;
                    maxNeighborAlpha = max(maxNeighborAlpha, a);
                }


                if (maxNeighborAlpha < 0.01){
                    discard;
                }
                    

                float2 pos = uv * _OutlineDot + _UnscaledTime * _OutlineSpeed;
                float pattern = sin(_OutlineDot * (pos.x + pos.y)) + _OutlineDot2;

                if (pattern >= 0.5){
                    return float4(_OutlineColor.rgb, _OutlineColor.a);
                }
                    
                else{
                    return float4(_OutlineGapColor.rgb, _OutlineGapColor.a);
                }
                    
            }

            ENDHLSL
        }
    }
}

Camera Movement and Screen Effects

I worked extensively on camera movement and screen effects such as wobble, shake, zoom and camera shift between first and third person perspectives.

Concept Art and Additional Contributions

Contact Me

+44 7546817029

olypann@gmail.com