Created Debug manager to quickly execute parts of the bosses Ai for easy reiteration.
//Initializion of debug buttons
public void Init(string a_Name, DebugMenu a_DebugMenu, DebugButtonType a_DebugButtonType, Method a_Method)
{
m_Name = a_Name;
m_ButtonText.text = a_Name;
m_DebugMenu = a_DebugMenu;
m_DebugbuttonType = a_DebugButtonType;
m_Method = a_Method;
// Using a Lamdba mixed with a Delegate so when the button is clicked it will execute the method
m_ReferenceToButton.onClick.AddListener(() => m_Method());
}
-----------------------------------------------------------------------------------------------------------------
//Setting A default debugging button
//Spawning the prefab of the button
DebugButton DebugButton = Instantiate(m_Prefab_DebugButton, m_MenuScreens[m_MenuScreens.Count - 1].gameObject.transform);
DebugButton.gameObject.transform.localPosition = new Vector3(ScreenX, ScreenY + i * Offset, 0);
//Hooking up the method this button will call
DebugButton.Init("Immortality On", this, DebugButton.DebugButtonType.DebugMenutype, m_Player.SetImmortalityToTrue);
-----------------------------------------------------------------------------------------------------------------
//Attaching the different Toad AI Move List gotten from the list of Enums
for (int i = 0; i < m_ToadAttackMoves.Length; i++)
{
ToadDebugButton toadbutton = Instantiate(m_Prefab_DebugToadButton, m_MenuScreens[m_MenuScreens.Count - 1].gameObject.transform);
toadbutton.gameObject.transform.localPosition = new Vector3(ScreenX, ScreenY + i * Offset, 0);
toadbutton.Init(i, m_ToadAttackMoves[i], m_ToadReference);
}
Shader "OdellWaterShader" {
Properties{
_Color("Color", Color) = (1,1,1,1)
_BlendColor("Blend Color", Color) = (1,1,1,1)
_MainTex("Albedo (RGB)", 2D) = "white" {}
_Glossiness("Smoothness", Range(0,1)) = 0.5
_Metallic("Metallic", Range(0,1)) = 0.0
_InvFade("Soft Factor", Range(0.01,3.0)) = 1.0
_FadeLimit("Fade Limit", Range(0.00,1.0)) = 0.3
_Scale("Scale", float) = 1
_Speed("Speed", float) = 1
_RipplePosition("Ripple Position", Vector) = (0, 0, 0, 0)
_WaterAlpha("WaterAlpha", float) = 0.9
_Amplitude("RippleStrength", float) = 5
_Wave("Wave", float) = 5
_Frequency("Frequency", float) = 1
_IsRippling("CanRipple", float) = 1
}
SubShader{
Tags{ "Queue" = "Transparent" "RenderType" = "Transparent" }
LOD 200
CGPROGRAM
// Physically based Standard lighting model, and enable shadows on all light types
#pragma surface surf Standard vertex:vert alpha:fade nolightmap
// Use shader model 3.0 target, to get nicer looking lighting
#pragma target 3.0
sampler2D _MainTex;
struct Input {
float2 uv_MainTex;
float4 screenPos;
float eyeDepth;
float3 customValue;
};
half _Glossiness;
half _Metallic;
fixed4 _Color;
fixed4 _BlendColor;
float _Scale;
float _Speed;
float _Frequency;
float _Amplitude;
float _Wave;
float _WaterAlpha;
sampler2D_float _CameraDepthTexture;
float4 _CameraDepthTexture_TexelSize;
float4 _RipplePosition;
float _FadeLimit;
float _InvFade;
float _IsRippling;
void vert(inout appdata_full v, out Input o)
{
//NormalWave
UNITY_INITIALIZE_OUTPUT(Input, o);
COMPUTE_EYEDEPTH(o.eyeDepth);
half offsetvert = ((v.vertex.x * v.vertex.x) + (v.vertex.z * v.vertex.z));
half offsetvert2 = v.vertex.x + v.vertex.z;
// Calculating the waves time speed and frequency
half value0 = _Scale * sin(_Time.w * _Speed * _Frequency + offsetvert2);
//Moving the vertex and normals to the new wave
v.vertex.y += value0;
v.normal.y += value0;
o.customValue += value0;
}
void surf(Input IN, inout SurfaceOutputStandard o) {
// Albedo comes from a texture tinted by color
fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color;
o.Albedo = c.rgb;
// Metallic and smoothness come from slider variables
o.Metallic = _Metallic;
o.Smoothness = _Glossiness;
//Gets the camera depth buffer to calculate the rim
float CameraDepth = SAMPLE_DEPTH_TEXTURE_PROJ(_CameraDepthTexture, UNITY_PROJ_COORD(IN.screenPos));
float SceneDepth = LinearEyeDepth(CameraDepth);
float partZ = IN.eyeDepth;
float fade = 1.0;
if (CameraDepth > 0.0) // Make sure the depth texture exists
//If the cameradepth is greater then create the rim
fade = saturate(_InvFade * (SceneDepth - partZ));
o.Alpha = c.a * fade; //(original line)
//Final Input
o.Alpha = _WaterAlpha;
if (fade < _FadeLimit)
o.Albedo = c.rgb * fade + _BlendColor * (1 - fade);
}
ENDCG
}
}
As Graphics Programmer I created a Water shader and used depth buffer and vertex disfered rendering to create the shader.
As a Gameplay Programmer I created intricate boss Ai. The bosses were designed with a giant state machine of the actions they will execute and a complex web of when they would accomplish those actions.
public KingShieldCharge(AIController aAIController) : base(aAIController)
{
m_KingChargeTimer = Services.TimerManager.CreateTimer("m_KingChargeTimer", ChargeDuration, false);
m_KingChargeDelayTimer = Services.TimerManager.CreateTimer("m_KingChargeDelayTimer", ChargeDelay, false);
}
-----------------------------------------------------------------------------------------------------------------------
public override void Start()
{
// Get the king's starting position
m_PreMovePosition = ((AIKingController)m_AIController).transform.position;
// Set hit and charging to false
m_AlreadyHit = false;
m_Charging = false;
// Setup the timers
m_KingChargeDelayTimer.Restart();
// Start the animation
((AIKingController)m_AIController).m_Animator.SetTrigger("Charge");
}
--------------------------------------------------------------------------------------------------------------------------
// Update is called once per frame
public override void Update()
{
// If the delay timer is running
if(m_KingChargeDelayTimer.IsRunning() == true)
{
// Turn to look at the player
((AIKingController)m_AIController).TurnToPlayer();
}
// If the delay is done and the king isin't charging
if (m_KingChargeDelayTimer.IsFinished() && m_Charging == false)
{
// Set charging to true and start the charge timer
m_Charging = true;
m_KingChargeTimer.Restart();
// Sets the target's position to the Player's position and
m_TargetPosition = ((AIKingController)m_AIController).transform.position + (((AIKingController)m_AIController).transform.forward * (((AIKingController)m_AIController).GetDistanceToPlayer() + m_ChargeDistanceBehindPlayer));
}
// If the king is charging
if (m_KingChargeTimer.IsRunning() && m_Charging == true)
{
// CHARGE!!!!!!
((AIKingController)m_AIController).transform.position = Vector3.Lerp(m_PreMovePosition, m_TargetPosition, m_KingChargeTimer.GetPercentage());
}
// If the king is done charging
if (m_KingChargeTimer.IsFinished() && m_Charging == true)
{
// If the animation is done
if (((AIKingController)m_AIController).m_Animator.GetCurrentAnimatorStateInfo(0).IsTag("ShieldEnd") && ((AIKingController)m_AIController).m_Animator.GetCurrentAnimatorStateInfo(0).normalizedTime >= 0.98f || ((AIKingController)m_AIController).m_Animator.GetCurrentAnimatorStateInfo(0).normalizedTime >= 1.0f)
{
// Attack is finished
((AIKingController)m_AIController).CurrentActionFinished();
}
}
// If the king is charging, hit the player and hasn't already hit the player
if (m_Charging == true && ((AIKingController)m_AIController).m_KingChargeTrigger.m_IsPlayerinside == true && m_AlreadyHit == false)
{
// Set hit to true
m_AlreadyHit = true;
// Deal Damage to player
Services.GameManager.Player.TakeDamage(Constants.KingSheildChargeDamage);
// Set the force and radius
float Force = 100;
// Push the player away
Services.GameManager.Player.MovementController.PushPlayer(((AIKingController)m_AIController).transform.position, Force);
}
}
}
Fallen Knight was a great project to work on that helped me grow as a programmer and as a person. Communicating with a large group of people with hierarchy was a challenge but in the end we persisted and created a great work that we can all be proud of.