*The site has been experiencing some issues with the embedded Gists. Please refresh the page if they do not show.
Concrete Rose Callback System
using System.Collections; | |
using System.Collections.Generic; | |
using UnityEngine; | |
[System.Serializable] | |
public class Card : CardBase | |
{ | |
public GenreType.MusicGenre genre; | |
public ElementType.elements primaryElement; | |
public ElementType.elements subElement; | |
public CardActionType.actionType actionType; | |
public UsageType.Usage usageType; | |
public UsageType.UsageClass usageClass; | |
public ExpenseData expense; | |
public StatusEffectData statusEffectType; | |
public int strength; | |
public int force; | |
public int range; | |
public string description; | |
} |
using System; | |
using System.Collections; | |
using System.Collections.Generic; | |
using System.Threading.Tasks; | |
using UnityEngine; | |
public class ToggleReflector : MonoBehaviour | |
{ | |
public bool active = false; | |
public float timeActive = 0.5f; | |
public TurntableController activeRecord; | |
public int damageMultiplier = 1; | |
public float reflectSpeed = 10; | |
public ElementType.elements element = ElementType.elements.Earth; | |
[SerializeField] | |
private bool ignoreSpriteRenderer = true; | |
[SerializeField] | |
private Collider2D objectCollider; | |
[SerializeField] | |
private SpriteRenderer spriteRenderer; | |
private ParticleSystem reflectorPFX; // should this be serialized? | |
private void Start() | |
{ | |
if (!objectCollider) | |
{ | |
objectCollider = gameObject.GetComponent<Collider2D>(); | |
} | |
if (!spriteRenderer) | |
{ | |
spriteRenderer = gameObject.GetComponent<SpriteRenderer>(); | |
} | |
reflectorPFX = gameObject.GetComponentInChildren<ParticleSystem>(); | |
reflectorPFX.enableEmission = false; | |
} | |
public void ToggleReflectorOn(Collider2D playerCollider, int timeMultiplier, TurntableController turntable) | |
{ | |
active = true; | |
activeRecord = turntable; | |
damageMultiplier = turntable.GetMultiplier(); | |
element = turntable.attackData.primaryElement; | |
objectCollider.enabled = true; | |
spriteRenderer.enabled = ignoreSpriteRenderer ? false : true; | |
//reflectorPFX.enableEmission = true; | |
SetTimer(playerCollider, timeMultiplier); | |
} | |
public virtual async Task SetTimer(Collider2D playerCollider, int timeMultiplier) | |
{ | |
await TimeSpan.FromSeconds(DetermineTimeActive(timeMultiplier)); | |
ToggleOffImeediate(); | |
} | |
public void ToggleOffImeediate() | |
{ | |
objectCollider.enabled = false; | |
spriteRenderer.enabled = false; | |
reflectorPFX.enableEmission = false; | |
active = false; | |
} | |
protected virtual float DetermineTimeActive(int timeMultiplier) | |
{ | |
return timeActive * timeMultiplier; | |
} | |
} |
using System.Collections; | |
using System.Collections.Generic; | |
using UnityEngine; | |
public class TurnTableActionManager : MonoBehaviour | |
{ | |
public static TurnTableActionManager instance; | |
public Collider2D playerCollider; | |
public CrossfadeController crossFader; | |
public ToggleReflector actionReflector; | |
private AudioSource scratchSound; | |
private void Awake() | |
{ | |
if (instance == null) | |
{ | |
instance = this; | |
} | |
else | |
{ | |
Destroy(this.gameObject); | |
} | |
} | |
private void Start() | |
{ | |
if (scratchSound == null) | |
{ | |
scratchSound = gameObject.GetComponent<AudioSource>(); | |
} | |
} | |
/// <summary> | |
/// Logic to determine which type of action to take on turntable press | |
/// </summary> | |
/// <param name="turntable"></param> | |
public void TriggerTurntableAction(TurntableController turntable) | |
{ | |
Card card = turntable.attackData; | |
var actionType = card.usageClass; | |
switch (actionType) | |
{ | |
case UsageType.UsageClass.Action: | |
OnActionTypeFound(turntable); | |
Debug.Log("Action type called"); | |
break; | |
case UsageType.UsageClass.Support: | |
Debug.Log("Support type called"); | |
//TODO IMPLEMENT | |
break; | |
case UsageType.UsageClass.Movement: | |
Debug.Log("Movment type called"); | |
//TODO IMPLEMENT | |
break; | |
default: | |
break; | |
} | |
} | |
public void OnActionTypeFound(TurntableController turntable) | |
{ | |
actionReflector.ToggleReflectorOn(playerCollider, crossFader.DetermineMultiplier(turntable), turntable); | |
scratchSound.Play(); | |
} | |
} |
using System.Collections; | |
using System.Collections.Generic; | |
using UnityEngine; | |
public class TurntableController : MonoBehaviour | |
{ | |
public Card attackData; | |
public bool isLeft = false; | |
public CrossfadeController crossfader; | |
[SerializeField] | |
private int multiplier = 1; | |
[SerializeField] | |
private CombatCharacterController player; | |
private ActionTimer actionBar; | |
// Start is called before the first frame update | |
void Start() | |
{ | |
if (player == null) | |
{ | |
player = PlayerInfoHolder.instance.gameObject.GetComponent<CombatCharacterController>(); | |
} | |
if (player != null) | |
{ | |
player = crossfader.player; | |
if (isLeft) | |
{ | |
player.onLeftTurntableButtonPressed.AddListener(delegate { OnTurntableActivate(); }); | |
} | |
else | |
{ | |
player.onRightTurntableButtonPressed.AddListener(delegate { OnTurntableActivate(); }); | |
} | |
actionBar = gameObject.GetComponentInChildren<ActionTimer>(); | |
} | |
else | |
{ | |
Debug.LogError("Player Is null !!!!"); | |
} | |
} | |
public void OnTurntableActivate() | |
{ | |
int multiplier = crossfader.DetermineMultiplier(this); | |
//Only act if the actionbar is full and the crossfader is not on the opposite side | |
if (actionBar.CanAct && multiplier > 0) | |
{ | |
TurnTableActionManager.instance.TriggerTurntableAction(this); | |
actionBar.ResetActionBar(); | |
} | |
} | |
public int GetMultiplier() | |
{ | |
return multiplier * crossfader.DetermineMultiplier(this); | |
} | |
} |
For Concrete Rose, we needed a flexible system that can support multiple types of actions on a single button press, depending on JSON data feed into the combat scene. This set up allows us to populate card data from JSON (Not shown) and then use that data in a series of callbacks attached to singleton managers. Classes can subscribe to the managers’ functions without having to get an instance of them stored in memory. In this example, the TurnTableActionManager stores a reference to a reflector. When either turn table action wants to activate that reflector, they ask the manager to do so by providing their own data from their card. This in turn allows the reflector to know what properties, such as elements and strength, it needs to activate with.
Fenced AI State Example
I needed a dynamic AI system that could detect the player and make important decisions. Using a state machine, Unity's event system, and some basic pathfinding, I was able to create a set of scripts that allows the AI state manager to call a During() function that varies by state. Each state also has a TransitionTo() function which tells the state manager to enter this new state, dropping the other one.
MasterHero Power Up Interface
This code was used in the game MasterHero to create a dynamic power up system. Since players could drag and drop their powers around in various slots mapped to different number keys, I had to have each number key use powers on key down agnostic of the power in the slot. I used an interface to accomplish this.
Power-Up Interface in C++
I wanted to draw off my interface experience with power ups before. C++ does not have support for interfaces, but Unreal does have a solution for that. Here is my implementation of that. I did not write any of the power ups themselves, just the architecture for using them. I may write a power up in the future as this project is on going.
Beat Detection
For this assignment I had to create a rhythm game. Using a BPM analyzer and some help from Gamasutra I was able to create an algorithm that could allow the player to fire but only on the down beat.
Swap Function
For Project Imp our core mechanic revolves around swapping positions with clones of yourself that you can spawn around the world. Swapping positions with an enemy in the middle allows you to steal some of their power. This is the base of that system that I designed.