Project Type | Team Project/University |
Software Used | Unity |
Languages Used | C# |
Primary Role(s) | Game Programming and Assisting Colleagues |
Managing My Collegues and helping them to continue developing the game, we are using Trello to assign the tasks.
Creating Character Class that drives our Player
Character Class includes: the animator control, capsule collision for damage, movement properties, NavMesh Agent properties
Weapon System for both EnemyAI and Character ( Our Player )
PlayerController that drives our character movement by using Raycast from the Mouse (Like in League of legends, Dota, Diablo...)
Special Abilities for the player
Using Scriptable Objects to have multi weapons with Multi Stats such as range, damage, hit per second... etc
Using Also Scriptable objects to Create abilities the Abilities
Creating Waypoint System to use with Enenmies and NPCs
Creating Enemy A.I with Different States.
Having the ability to create multiple enemies with multiple stats as well, such as (Archer, Thief, thug, minion, Knight, ..etc)
We are currently working on Dialogue, Save/Load, Quest Systems and improving other things :) so Anything in here might change!
[Header("Audio")] [Range(0.0f, 1.0f)] [SerializeField] float audoiSourceSpatialBlend = 0.5f; [Space] [Header("Animator")] [SerializeField] RuntimeAnimatorController animatorController; [SerializeField] AnimatorOverrideController animatorOverrideController; [SerializeField] Avatar characterAvatar; [SerializeField] [Range(0.1f, 1.0f)] float animForwardCap = 1.0f; [Space] [Header("Capsule Collider")] [SerializeField] Vector3 colliderCenter = new Vector3(0.0f, 0.8f, 0.0f); [SerializeField] float capsuleRadius = 0.2f; [SerializeField] float capsuleHeight = 1.6f; [Space] [Header("Movement")] [SerializeField] float moveSpeedMultiplier = 0.5f; [SerializeField] float moveThreshold = 1.0f; [SerializeField] float movingTurnSpeed = 360; [SerializeField] float stationaryTurnSpeed = 180; [SerializeField] float runCycleLegOffset = 0.2f; [SerializeField] float animSpeedMultiplier = 1.5f; [Space] [Header("Nav Mesh Agent")] [SerializeField] float speed = 1.0f; [SerializeField] float angularSpeed = 120.0f; [SerializeField] float acceleration = 8.0f; [SerializeField] float stoppingDistance = 1.3f; [SerializeField] float obstcleAvoidanceRadius = 0.1f; //====Private Section==== float turnAmount; float forwardAmount; NavMeshAgent navMeshAgent; Rigidbody myRigidBody; Animator animator; bool isAlive = true;
namespace RPG.Characters { public abstract class AbilityBehaviour : MonoBehaviour { protected AbilityConfig config; const float PARTICLE_CLEAN_UP_DELAY = 20.0f; const string ATTACK_TRIGGER = "Attack"; const string DEFAULT_ATTACK = "DEFAULT ATTACK"; public void SetConfig(AbilityConfig configToSet) { config = configToSet; } public abstract void Use(GameObject target = null); protected void PlayParticleEffect() { var particlePrefab = config.GetParticlePrefab(); var particleObject = Instantiate(particlePrefab, transform.position, particlePrefab.transform.rotation); particleObject.transform.parent = transform; particleObject.GetComponent().Play(); StartCoroutine(DestroyParticleWhenFinished(particleObject)); } IEnumerator DestroyParticleWhenFinished(GameObject particlePrefab) { while (particlePrefab.GetComponent ().isPlaying) { yield return new WaitForSeconds(PARTICLE_CLEAN_UP_DELAY); } Destroy(particlePrefab); yield return new WaitForEndOfFrame(); } protected void PlayAbilityAnimation() { var animatorOverrideController = GetComponent ().GetAnimatorOverride(); var animator = GetComponent (); animator.runtimeAnimatorController = animatorOverrideController; animatorOverrideController[DEFAULT_ATTACK] = config.GetAbilityAnimation(); animator.SetTrigger(ATTACK_TRIGGER); } protected void PlayAbilitySound() { var abilitySound = config.GetRandomAbilitySound(); var audioSource = GetComponent (); audioSource.PlayOneShot(abilitySound); } } }
namespace RPG.Characters { public abstract class AbilityConfig : ScriptableObject { [Header("Special Ability General")] [SerializeField] float energyCost = 10f; [SerializeField] GameObject particlePrefab = null; [SerializeField] AnimationClip abilityAnimation = null; [SerializeField] AudioClip[] audioClips = null; protected AbilityBehaviour behaviour; public abstract AbilityBehaviour GetBehaviourComponent(GameObject objectToAttachTo); public void AttachAbilityTo(GameObject objectToAttachTo) { AbilityBehaviour behaviourComponent = GetBehaviourComponent(objectToAttachTo); behaviourComponent.SetConfig(this); behaviour = behaviourComponent; } public void Use(GameObject target) { behaviour.Use(target); } public float GetEnergyCost() { return energyCost; } public GameObject GetParticlePrefab() { return particlePrefab; } public AnimationClip GetAbilityAnimation() { return abilityAnimation; } public AudioClip GetRandomAbilitySound() { return audioClips[Random.Range(0, audioClips.Length)]; } } }
IEnumerator Patrol() { state = State.patrolling; while(patrolPath != null) { //work out where to go next Vector3 nextWaypointPos = patrolPath.transform.GetChild(nextWaypointIndex).position; //tell character to go there character.SetDestination(nextWaypointPos); //cycle waypoints CycleWaypointWhenClose(nextWaypointPos); //wait at a waypoint float randWaypointDwellTime = UnityEngine.Random.Range(waypointDwellTimeMin, waypointDwellTimeMax); yield return new WaitForSeconds(randWaypointDwellTime); } } IEnumerator ChasePlayer() { state = State.chasing; while (distanceToPlayer >= currentWeaponRange) { character.SetDestination(player.transform.position); yield return new WaitForEndOfFrame(); } } IEnumerator AttackPlayer() { state = State.attacking; while(distanceToPlayer <= currentWeaponRange) { weaponSystem.AttackTarget(player.gameObject); yield return new WaitForEndOfFrame(); } } private void CycleWaypointWhenClose(Vector3 nextWaypointPos) { if(Vector3.Distance(transform.position, nextWaypointPos) <= waypointTolerance) { nextWaypointIndex = (nextWaypointIndex + 1) % patrolPath.transform.childCount; } }