UNITY RPG COMBAT SYSTEM TUTORIAL WITH STATE MACHINE JAVASCRIPT FULL CODE DOWNLOAD EXAMPLES
UNITY RPG COMBAT SYSTEM TUTORIAL WITH STATE MACHINE JAVASCRIPT FULL CODE DOWNLOAD EXAMPLES
PlayerController.js
[javascript]
/* WASD keyboard input player movement control with jump
and mouse rotation – Unity javascript Gameobject.net*/
#pragma strict
var charController:CharacterController ;
/* Create a variable of type CharacterController to store
our component and call it in the script */
var walkSpeed : float = 1 ;
var runSpeed : float = 1.8 ;
var rotationSpeed : float = 250 ;
var jumpForceDefault : float = 2 ;
var cooldown : float = 5 ;
private var jumpForce : float;
private var gravityPull : float = 1;
/* Jump action related costants */
private var isRunning : boolean ;
private var isWalking : boolean ;
private var isStrafing : boolean ;
private var isJumping : boolean ;
// CHANGE isAttacking to PUBLIC to access it from
// CombatBox script
public var isAttacking : boolean ;
private var isIdle : boolean ;
/* Create boolean status variables to identify animation
status, e.g. what am i doing right now? */
function Start (){
var cc : CharacterController;
cc = gameObject.AddComponent(“CharacterController”);
/* Adds a Character Controller component to gameobject */
charController = GetComponent(CharacterController);
/* Assigns it in the charController variable to use it */
// Set all animations to loop
animation.wrapMode = WrapMode.Loop;
// except shooting
animation[“attack”].wrapMode = WrapMode.Once;
// Put idle and walk into lower layers (The default layer is always 0)
// This will do two things
// – Since shoot and idle/walk are in different layers they will not affect
// each other’s playback when calling CrossFade.
// – Since shoot is in a higher layer, the animation will replace idle/walk
// animations when faded in.
animation[“attack”].layer = 1;
// Stop animations that are already playing
//(In case user forgot to disable play automatically)
animation.Stop();
}
function Update(){
charController.Move(transform.up * Time.deltaTime * -gravityPull * 1);
/* Gravity */
if(Input.GetAxis(“Vertical”) > 0){
/* If the Vertical input axis is positive (by default by
pressing W or up arrow) */
if(Input.GetButton(“Fire3”)){
isRunning = true ;
animation.CrossFade(“run”);
/* While Run button is pressed play run animation, with
Crossfade try to blend nicely different animations )*/
charController.Move(transform.forward*Time.deltaTime*runSpeed) ;
/* While Run button is pressed move faster !) */
/* Use the Move function, Time.deltatime makes things go
equally fast on different hardware configurations,
by moving in the forward direction with walkspeed */
isRunning = true ;
/* Set the isRunning flag as true since i am running */
Debug.Log(“isRunning value is” + ” ” + isRunning);
/* Tell me what i am doing now */
}
else{
isWalking = true ;
/* Else if i am moving forward and not running i walk */
animation[“walk”].speed = 1;
animation.CrossFade(“walk”);
/* While walk button is pressed play walk animation ! */
charController.Move(transform.forward*Time.deltaTime*walkSpeed) ;
//Debug.Log(“isWalking value is” + ” ” + isWalking);
/* Tell me what i am doing now */
}
}
else if(Input.GetAxis(“Vertical”) < 0){
isWalking = true ;
/* Do the same for the back direction, no back run! */
animation["walk"].speed = 0.5;
/* revert walk animation playback */
animation.CrossFade("walk");
charController.Move(transform.forward*Time.deltaTime*-walkSpeed/2) ;
/* Move function but in the opposite to forward
direction by using a negative (-) vector */
//Debug.Log("isWalking value is" + " " + isWalking);
/* Tell me what i am doing now */
}
else{
isWalking = false ;
isRunning = false ;
/* if not running or walking set these states as false */
}
if(Input.GetButtonDown("Jump") && !isJumping){
jumpForce = jumpForceDefault ;
isJumping = true ;
animation.Play("jump_pose") ;
/* Capture Jump input and prevent double air jump with
&& !isJumping, makes these lines working only while
not already in a Jump. */
}
if(isJumping){
charController.Move(transform.up * Time.deltaTime * jumpForce);
jumpForce -= gravityPull ;
Debug.Log("isJumping value is" + " " + isJumping);
/* If isJumping is true (i am in Jump state), move the
character up with jumpForce intensty, then gravityPull
kicks in and will take you on the ground. */
if(charController.isGrounded){
isJumping = false ;
/* Check if the character is touching the ground with
Unity default isGrounded function, if its grounded
end the Jumping action by setting isJumping false */
}
}
if(!isWalking && !isRunning && !isJumping){
animation.CrossFade("idle");
/* If i am not doing any action , play the idle anim */
}
if(Input.GetAxis("Horizontal") > 0){
charController.transform.Rotate(Vector3.up * Time.deltaTime * 20 * rotationSpeed, Space.World);
}
if(Input.GetAxis(“Horizontal”) < 0){
charController.transform.Rotate(Vector3.up * Time.deltaTime * 20 * -rotationSpeed);
}
/* rotate the character with left and right arrows */
charController.transform.rotation.y += Input.GetAxis("Mouse X") * Time.deltaTime * rotationSpeed ;
/* rotate the character with the mouse */
/* Play attack animation calling slash function
and make sure it isn calling more than once */
if(Input.GetButtonDown("Fire1") && !isAttacking){
slash() ;
}
/* If you wish to add STRAFE command just replicate the
code for the forward and back direction , i am not
doing this in this character controller tutorial
because the Constructor model is not provided
with the strafe animation. */
}
//Modify the attack Slash function to change the isAttacking
//state variable accordingly to the timing of the
//attack animation
function slash(){
isAttacking = true ;
animation.CrossFade("attack");
yield WaitForSeconds (animation["attack"].length);
isAttacking = false ;
}
[/javascript]
enemyAi.js
[javascript]
/* enemyAi.js - Unity rpg combat system tutorial - www.Gameobject.net */
/* Author : Piffa of www.Gameobject.net */
#pragma strict
/* delcaring states to pass to player gameobject */
public var isAttacking : boolean = false ;
public var enemyHealthPoints : int = 10 ; // Health pool for the enemy
public var enemyDamage : int = 1 ; // Damage dealt by enemy per hit
private var playAnim : boolean = true ;
function Update () {
if (playAnim){ //check if attack animation was played
WaitSeconds(); //wait random seconds for animation
}
//Destroy enemy if hp drops to zero and destroy it if so
if(enemyHealthPoints < 0){
Destroy(gameObject);
Debug.Log("Enemy is Dead !!!");
}
}
function WaitSeconds(){
playAnim = false;
var randomWait = Random.Range(0, 6);
print ("Wait" + randomWait + " seconds"); //debug
yield WaitForSeconds(randomWait); //Wait a random amount of time
isAttacking = true ; //set isAttacking state to true
animation.Play("punch"); //play attack animation
yield WaitForSeconds(animation["punch"].length) ;//wait for animation duration
isAttacking = false ;//set isAttacking state to false
playAnim = true ; // detect when anim is complete
}
//Function to call when hit by player
function TakeDamage(dmg : int){
enemyHealthPoints -= dmg ;
Debug.Log("Enemy suffered " + dmg +" damages");
}
[/javascript]
CombatSystem.js
[javascript]
/* CombatSystem.js - Unity rpg combat system tutorial - www.Gameobject.net */
/* Author : Piffa of www.Gameobject.net */
#pragma strict
/* Declaring and inizializing private variables to define collisions states */
public var isTouching : boolean = false; // player is touching an enemy collider box
public var wasTouching : boolean = false;// player was touching an enemy collider box
public var isEngaged : boolean = false; // player and enemy are engaged in combat
public var isHitting : boolean = false; // player is landing an hit and dealing dmg
public var isHitted : boolean = false ; // enemy is landing an hit to player
public var playerControllerScript : PlayerController ; //handle to access parent player gameobject
private var playerIsAttacking : boolean ; //read from Playercontroller.js if player is attacking
private var enemyIsAttacking : boolean ; //read from enemyAi.js if enemy is attacking
private var collidingEnemy : GameObject ; // reference to enemy gameobject we are colliding with
public var playerHealthPoints : int = 20 ; // player health pool
private var playerDamage : int = 2 ; // amount of damage dealt by player with 1 hit
function Start () {
playerControllerScript = transform.parent.gameObject.GetComponent(PlayerController);
//Get the PlayerController script in our parent gameobject and store in a variable
}
function Update () {
/* player is engaged in combat if for the first time is touching the enemy's collider */
if(!wasTouching && isTouching){
isEngaged = true;
};
/* player is not engaged anymore if was touching the enemy and now it's not anymore */
if(wasTouching && !isTouching){
isEngaged = false;
};
/* Store in a variable if the player is attacking */
playerIsAttacking = playerControllerScript.isAttacking;
/* Store in a variable if the enemy is attacking */
if(collidingEnemy){
enemyIsAttacking = collidingEnemy.GetComponent(enemyAi).isAttacking;
};
Debug.Log(enemyIsAttacking);
/* if player is attacking while engaged and in touch with the enemy apply damage
to the enemy by calling its takedamage function via sendmessage */
if(playerIsAttacking && isEngaged && isTouching){
if(isHitting==false){
isHitting=true;
collidingEnemy.SendMessage("TakeDamage",playerDamage);
}else if(!transform.parent.gameObject.animation.IsPlaying("attack")){
isHitting=false;
}
}
/* if player is attacking while engaged and in touch with the enemy apply damage
to the enemy by calling its takedamage function via sendmessage */
if(enemyIsAttacking && isEngaged && isTouching){
if(isHitted==false){
isHitted=true;
TakeDamage(collidingEnemy.gameObject.GetComponent(enemyAi).enemyDamage);
}
}else if(!enemyIsAttacking){
isHitted=false; //FIXARE PERCHE NON TORNA FALSE
}
}
/* The above state machine logic it's needed to avoid to call the takedamage function every frame
that verify the if statement thus applying more than needed. This way the function is called just
once for every hit landed as it should. */
/* Check for collision with enemy and flag states appropriately */
function OnTriggerEnter(col : Collider) {
if(col.gameObject.name =="demon"){
wasTouching = isTouching;
isTouching = true;
collidingEnemy = col.gameObject;
};
}
/* Check for collision with enemy and flag states appropriately */
function OnTriggerExit(col : Collider) {
Debug.Log("Colliding with : " + col.gameObject.name);
if(col.gameObject.name =="demon"){
wasTouching = isTouching;
isTouching = false;
};
}
//Function to call when hit by enemy
function TakeDamage(dmg : int){
playerHealthPoints -= dmg ;
Debug.Log("Player suffered " + dmg +" damages");
}
[/javascript]