Last active
December 28, 2015 22:48
-
-
Save smallrice45/d5fd0d2edeb04798e8af to your computer and use it in GitHub Desktop.
Unity 2D CharacterController
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
using System.Collections; | |
using System; | |
public class CharacterAttribute : MonoBehaviour { | |
[Serializable] | |
public class CommonAttribute{ | |
public float lifeTime; | |
public GameObject groundedOn = null; | |
public GameObject lastgroundedLadderGround = null; | |
public GameObject ladderOn = null; | |
public bool isGrounded = false; | |
public float someThreshold = 0.25f; | |
public Rigidbody2D mRigidbody2D; | |
public Transform mTransform; | |
} | |
[Serializable] | |
public class InputAttribute{ | |
public Vector2 moveDir; | |
public bool getClimb = false; | |
public bool getJump = false; | |
} | |
[Serializable] | |
public class MovementAttribute{ | |
public bool canMove; | |
public float moveSpeed = 10.0f; | |
} | |
[Serializable] | |
public class ClimbAttribute{ | |
public bool canClimb; | |
public bool isClimbing; | |
public bool onLadderTrigger; | |
public bool onLadderGround; | |
public bool hasLadderGroundDown; | |
} | |
[Serializable] | |
public class JumpAttribute{ | |
public bool canJump; | |
public bool isJumping; | |
public int jumpMaxTimes = 1; | |
public int jumpCount = 1; | |
public float jumpVerticalSpeed; | |
public float lastJumpButtonTime = -10.0f; | |
public float maxHeight; | |
public float timeOut = 0.1f; // 間隔時間,防止短時間內重複跳躍 | |
public float lastStartHeight; // 跳躍時最後的高度 | |
public float normalHeight = 0.25f; // 按下跳躍鍵即刻所跳的高度 | |
public float extraHeight = 1.0f; // 按住跳躍鍵最高跳的高度 | |
} | |
public CommonAttribute mCommonAttribute = new CommonAttribute(); | |
public InputAttribute mInputAttribute = new InputAttribute(); | |
public MovementAttribute mMovementAttribute = new MovementAttribute(); | |
public ClimbAttribute mClimbAttribute = new ClimbAttribute(); | |
public JumpAttribute mJumpAttribute = new JumpAttribute(); | |
void OnCollisionEnter2D(Collision2D other){ | |
foreach(ContactPoint2D contact in other.contacts) | |
{ | |
if(contact.normal.y > mCommonAttribute.someThreshold) | |
{ | |
mCommonAttribute.isGrounded = true; | |
mCommonAttribute.groundedOn = other.gameObject; | |
break; | |
} | |
} | |
} | |
void OnCollisionExit2D(Collision2D other){ | |
if(other.gameObject == mCommonAttribute.groundedOn){ | |
mCommonAttribute.groundedOn = null; | |
mCommonAttribute.isGrounded = false; | |
} | |
} | |
/// <summary> | |
/// 爬梯頂部向上 | |
/// </summary> | |
public bool OnLadderGroundClimbUp(){ | |
if (mClimbAttribute.onLadderGround && | |
mInputAttribute.moveDir.y > 0.1f){ | |
return true; | |
}else{ | |
return false; | |
} | |
} | |
/// <summary> | |
/// 爬梯頂部向下 | |
/// </summary> | |
public bool OnLadderGroundClimbDown(){ | |
if (mClimbAttribute.onLadderGround && | |
mInputAttribute.moveDir.y < -0.1f){ | |
return true; | |
}else{ | |
return false; | |
} | |
} | |
/// <summary> | |
/// 爬梯底部向下移動 | |
/// </summary> | |
public bool OnLadderTriggerGroundedClimbDown(){ | |
if (mCommonAttribute.isGrounded && | |
mClimbAttribute.onLadderTrigger && | |
!mClimbAttribute.onLadderGround && | |
mInputAttribute.moveDir.y < -0.1f){ | |
return true; | |
}else{ | |
return false; | |
} | |
} | |
public void CharacterIgnoreCollisionObject2D(bool isIgnore,GameObject characterObject, GameObject targetObject){ | |
Physics2D.IgnoreCollision(characterObject.GetComponent<CircleCollider2D>(), targetObject.GetComponent<BoxCollider2D>(), isIgnore); | |
Physics2D.IgnoreCollision(characterObject.GetComponent<BoxCollider2D>(), targetObject.GetComponent<BoxCollider2D>(), isIgnore); | |
} | |
public float CalculateJumpVerticalSpeed ( float jumpHeight,float gravity) { | |
return Mathf.Sqrt(2 * jumpHeight * -gravity); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
using System.Collections; | |
public class CharacterContoler2D : CharacterAttribute { | |
void Start () { | |
mCommonAttribute.mRigidbody2D = GetComponent<Rigidbody2D>(); | |
mCommonAttribute.mTransform = GetComponent<Transform>(); | |
mJumpAttribute.jumpVerticalSpeed = CalculateJumpVerticalSpeed ( mJumpAttribute.normalHeight, Physics2D.gravity.y * mCommonAttribute.mRigidbody2D.gravityScale); | |
} | |
public void OnMove(Vector2 moveDir) { | |
mInputAttribute.moveDir = moveDir; | |
} | |
public void OnJump(bool isPress) { | |
if (isPress){ | |
mInputAttribute.getJump = true; | |
mJumpAttribute.lastJumpButtonTime = mCommonAttribute.lifeTime; | |
}else{ | |
mJumpAttribute.isJumping = false; | |
mInputAttribute.getJump = false; | |
} | |
} | |
public void OnTriggerLadder(bool isTriggerEnter, GameObject other, GameObject ladderGround){ | |
if (isTriggerEnter){ | |
// 進入爬梯空間,設置可爬梯與爬梯物件資訊 | |
mClimbAttribute.canClimb = true; | |
mClimbAttribute.onLadderTrigger = true; | |
mClimbAttribute.hasLadderGroundDown = false; | |
mCommonAttribute.ladderOn = other; | |
mCommonAttribute.lastgroundedLadderGround = ladderGround; | |
}else{ | |
// 離開爬梯空間,清除可爬梯與爬梯物件資訊 | |
mClimbAttribute.onLadderTrigger = false; | |
mClimbAttribute.canClimb = false; | |
if (!mClimbAttribute.onLadderGround){ | |
ExitClimb(); | |
mCommonAttribute.ladderOn = null; | |
mCommonAttribute.lastgroundedLadderGround = null; | |
} | |
} | |
} | |
public void OnCollisionLadderGround(bool isCollisionEnter, GameObject other, GameObject ladderTrigger){ | |
if (isCollisionEnter){ | |
mClimbAttribute.canClimb = true; | |
mClimbAttribute.onLadderGround = true; | |
mCommonAttribute.lastgroundedLadderGround = other; | |
mCommonAttribute.ladderOn = ladderTrigger; | |
}else{ | |
mClimbAttribute.onLadderGround = false; | |
// 於地面上移動離開方塊,取消觸發 | |
if (!mClimbAttribute.onLadderTrigger && | |
!mClimbAttribute.hasLadderGroundDown | |
){ | |
mClimbAttribute.canClimb = false; | |
} | |
// 於梯上離開或結束判斷,但仍保持爬梯狀態 | |
if (mCommonAttribute.isGrounded && | |
!mClimbAttribute.isClimbing && | |
!mClimbAttribute.onLadderTrigger){ | |
mCommonAttribute.ladderOn = null; | |
mCommonAttribute.lastgroundedLadderGround = null; | |
} | |
} | |
} | |
// Update is called once per frame | |
void Update () { | |
mCommonAttribute.lifeTime += Time.deltaTime; | |
ApplyMove(); | |
ApplyClimb(); | |
ApplyJump(); | |
ApplyGravity(); | |
} | |
/// <summary> | |
/// 應用所有位移的邏輯 | |
/// </summary> | |
void ApplyMove(){ | |
if (!mMovementAttribute.canMove && | |
!mClimbAttribute.isClimbing){ | |
mCommonAttribute.mRigidbody2D.velocity = new Vector2( mMovementAttribute.moveSpeed* mInputAttribute.moveDir.x, mCommonAttribute.mRigidbody2D.velocity.y); | |
} | |
} | |
void ApplyClimb(){ | |
if (mClimbAttribute.canClimb){ | |
if (mClimbAttribute.isClimbing){ | |
if (OnLadderGroundClimbUp()){ | |
ExitClimb(); | |
return; | |
// 踏在爬梯底部向下移動不觸發 | |
}else if(OnLadderTriggerGroundedClimbDown()){ | |
ExitClimb(); | |
return; | |
}else{ | |
EffectClimb(); | |
} | |
} | |
if (mInputAttribute.moveDir.y != 0.0f){ | |
DidClimb(); | |
} | |
} | |
} | |
/// <summary> | |
/// 應用跳躍邏輯 | |
/// </summary> | |
void ApplyJump(){ | |
if (mCommonAttribute.isGrounded) | |
{ | |
if ( mCommonAttribute.lifeTime < mJumpAttribute.lastJumpButtonTime + mJumpAttribute.timeOut) | |
{ | |
EffectJump(); | |
DidJump(); | |
} | |
}else{ | |
// 滯空且爬梯狀態時,觸發跳躍功能並取消爬梯狀態 | |
if ( mCommonAttribute.lifeTime < mJumpAttribute.lastJumpButtonTime + mJumpAttribute.timeOut && mClimbAttribute.isClimbing) | |
{ | |
ExitClimb(); | |
EffectJump(); | |
DidJump(); | |
} | |
} | |
} | |
/// <summary> | |
/// 應用重力判斷,進行攀爬、跳躍等邏輯 | |
/// </summary> | |
void ApplyGravity(){ | |
bool powerJump = mCommonAttribute.mRigidbody2D.velocity.y > 0.0f && mInputAttribute.getJump && mJumpAttribute.lastStartHeight+ mJumpAttribute.extraHeight > mCommonAttribute.mTransform.position.y; | |
if (powerJump) | |
{ | |
if (mJumpAttribute.isJumping){ | |
EffectJump(); | |
} | |
return; | |
}else if(mCommonAttribute.isGrounded){ | |
if (mJumpAttribute.isJumping){ | |
mInputAttribute.getJump = false; | |
mJumpAttribute.isJumping = false; | |
mJumpAttribute.jumpCount = mJumpAttribute.jumpMaxTimes; | |
} | |
}else{ | |
} | |
} | |
/// <summary> | |
/// 進行首次攀爬判斷 | |
/// </summary> | |
void DidClimb(){ | |
if (mClimbAttribute.canClimb && !mClimbAttribute.isClimbing){ | |
// 踏在爬梯頂部向上移動不觸發 | |
if (OnLadderGroundClimbUp()){ | |
return; | |
// 踏在爬梯底部向下移動不觸發 | |
}else if(OnLadderTriggerGroundedClimbDown()){ | |
return; | |
}else{ | |
if (OnLadderGroundClimbDown()){ | |
CharacterIgnoreCollisionObject2D(true, this.gameObject, mCommonAttribute.lastgroundedLadderGround); | |
mClimbAttribute.hasLadderGroundDown = true; | |
} | |
mCommonAttribute.mTransform.position = new Vector3( mCommonAttribute.ladderOn.transform.position.x, mCommonAttribute.mTransform.position.y, mCommonAttribute.mTransform.position.z); | |
mClimbAttribute.isClimbing = true; | |
mCommonAttribute.mRigidbody2D.gravityScale = 0.0f; | |
} | |
} | |
} | |
/// <summary> | |
/// 結束攀爬動作,開啟重力與樓梯上方方塊碰撞 | |
/// </summary> | |
public void ExitClimb(){ | |
mClimbAttribute.isClimbing = false; | |
mClimbAttribute.hasLadderGroundDown = false; | |
if (mCommonAttribute.lastgroundedLadderGround != null){ | |
CharacterIgnoreCollisionObject2D( false, this.gameObject, mCommonAttribute.lastgroundedLadderGround); | |
} | |
mCommonAttribute.mRigidbody2D.gravityScale = 2.0f; | |
} | |
/// <summary> | |
/// 進行首次跳躍邏輯判斷 | |
/// </summary> | |
void DidJump(){ | |
mJumpAttribute.jumpCount--; | |
mJumpAttribute.isJumping = true; | |
mJumpAttribute.lastStartHeight = mCommonAttribute.mTransform.position.y; | |
mJumpAttribute.lastJumpButtonTime = -10.0f; | |
} | |
/// <summary> | |
/// 觸發攀爬效果 | |
/// </summary> | |
void EffectClimb(){ | |
if (mClimbAttribute.hasLadderGroundDown&& | |
mInputAttribute.moveDir.y > 0.1f | |
){ | |
return; | |
}else{ | |
mCommonAttribute.mRigidbody2D.velocity = new Vector2( 0.0f, mMovementAttribute.moveSpeed* mInputAttribute.moveDir.y); | |
} | |
} | |
/// <summary> | |
/// 觸發跳躍效果 | |
/// </summary> | |
void EffectJump(){ | |
mCommonAttribute.mRigidbody2D.velocity = new Vector2( mCommonAttribute.mRigidbody2D.velocity.x, mJumpAttribute.jumpVerticalSpeed * mCommonAttribute.mRigidbody2D.gravityScale); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
using System.Collections; | |
using System.Collections.Generic; | |
public class LadderGroundCollison : MonoBehaviour { | |
private List<GameObject> enterTriggerObjects = new List<GameObject>(); | |
void OnCollisionEnter2D(Collision2D other){ | |
if (other.gameObject.tag == "Player"){ | |
foreach(ContactPoint2D contact in other.contacts) | |
{ | |
if(contact.normal.y < -0.25f) | |
{ | |
enterTriggerObjects.Add(other.gameObject); | |
other.gameObject.GetComponent<CharacterContoler2D>().OnCollisionLadderGround( true, this.gameObject, transform.parent.FindChild("Trigger").gameObject); | |
break; | |
} | |
} | |
} | |
} | |
void OnCollisionExit2D(Collision2D other){ | |
if (other.gameObject.tag == "Player"){ | |
enterTriggerObjects.Remove(other.gameObject); | |
if (!enterTriggerObjects.Contains(other.gameObject)){ | |
other.gameObject.GetComponent<CharacterContoler2D>().OnCollisionLadderGround( false, this.gameObject , null); | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
using System.Collections; | |
using System.Collections.Generic; | |
public class LadderTrigger : MonoBehaviour { | |
public List<GameObject> enterTriggerObjects = new List<GameObject>(); | |
void OnTriggerEnter2D (Collider2D other) { | |
if (other.tag == "Player"){ | |
enterTriggerObjects.Add(other.gameObject); | |
other.GetComponent<CharacterContoler2D>().OnTriggerLadder( true, this.gameObject, transform.parent.FindChild("TopGround").gameObject); | |
} | |
} | |
void OnTriggerExit2D (Collider2D other) { | |
if (other.tag == "Player"){ | |
enterTriggerObjects.Remove(other.gameObject); | |
if (!enterTriggerObjects.Contains(other.gameObject)){ | |
other.GetComponent<CharacterContoler2D>().OnTriggerLadder( false, null, null); | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
using System.Collections; | |
public class PlayerInputController : MonoBehaviour { | |
CharacterContoler2D m_CharacterContoller2D; | |
void Awake(){ | |
m_CharacterContoller2D = GetComponent<CharacterContoler2D>(); | |
} | |
void Update () { | |
if(Input.GetKeyDown(KeyCode.Space)){ | |
m_CharacterContoller2D.OnJump(true); | |
} | |
if(Input.GetKeyUp(KeyCode.Space)){ | |
m_CharacterContoller2D.OnJump(false); | |
} | |
if(Input.GetKeyDown(KeyCode.LeftArrow)){ | |
if(Input.GetKey(KeyCode.UpArrow)){ | |
m_CharacterContoller2D.OnMove(new Vector2( -1, 1)); | |
}else if(Input.GetKey(KeyCode.DownArrow)){ | |
m_CharacterContoller2D.OnMove(new Vector2( -1, -1)); | |
}else{ | |
m_CharacterContoller2D.OnMove(new Vector2( -1, 0)); | |
} | |
} | |
if(Input.GetKeyDown(KeyCode.RightArrow)){ | |
if(Input.GetKey(KeyCode.UpArrow)){ | |
m_CharacterContoller2D.OnMove(new Vector2( 1, 1)); | |
}else if(Input.GetKey(KeyCode.DownArrow)){ | |
m_CharacterContoller2D.OnMove(new Vector2( 1, -1)); | |
}else{ | |
m_CharacterContoller2D.OnMove(new Vector2( 1, 0)); | |
} | |
} | |
if(Input.GetKeyDown(KeyCode.UpArrow)){ | |
if(Input.GetKey(KeyCode.RightArrow)){ | |
m_CharacterContoller2D.OnMove(new Vector2( 1, 1)); | |
}else if(Input.GetKey(KeyCode.LeftArrow)){ | |
m_CharacterContoller2D.OnMove(new Vector2( -1, 1)); | |
}else{ | |
m_CharacterContoller2D.OnMove(new Vector2( 0, 1)); | |
} | |
} | |
if(Input.GetKeyDown(KeyCode.DownArrow)){ | |
if(Input.GetKey(KeyCode.RightArrow)){ | |
m_CharacterContoller2D.OnMove(new Vector2( 1, -1)); | |
}else if(Input.GetKey(KeyCode.LeftArrow)){ | |
m_CharacterContoller2D.OnMove(new Vector2( -1, -1)); | |
}else{ | |
m_CharacterContoller2D.OnMove(new Vector2( 0, -1)); | |
} | |
} | |
if( Input.GetKeyUp(KeyCode.RightArrow) || | |
Input.GetKeyUp(KeyCode.LeftArrow) || | |
Input.GetKeyUp(KeyCode.UpArrow) || | |
Input.GetKeyUp(KeyCode.DownArrow) | |
){ | |
if(Input.GetKey(KeyCode.LeftArrow)){ | |
if(Input.GetKey(KeyCode.UpArrow)){ | |
m_CharacterContoller2D.OnMove(new Vector2( -1, 1)); | |
}else if(Input.GetKey(KeyCode.DownArrow)){ | |
m_CharacterContoller2D.OnMove(new Vector2( -1, -1)); | |
}else{ | |
m_CharacterContoller2D.OnMove(new Vector2( -1, 0)); | |
} | |
}else if(Input.GetKey(KeyCode.RightArrow)){ | |
if(Input.GetKey(KeyCode.UpArrow)){ | |
m_CharacterContoller2D.OnMove(new Vector2( 1, 1)); | |
}else if(Input.GetKey(KeyCode.DownArrow)){ | |
m_CharacterContoller2D.OnMove(new Vector2( 1, -1)); | |
}else{ | |
m_CharacterContoller2D.OnMove(new Vector2( 1, 0)); | |
} | |
}else if(Input.GetKey(KeyCode.UpArrow)){ | |
if(Input.GetKey(KeyCode.RightArrow)){ | |
m_CharacterContoller2D.OnMove(new Vector2( 1, 1)); | |
}else if(Input.GetKey(KeyCode.DownArrow)){ | |
m_CharacterContoller2D.OnMove(new Vector2( -1, 1)); | |
}else{ | |
m_CharacterContoller2D.OnMove(new Vector2( 0, 1)); | |
} | |
}else if(Input.GetKey(KeyCode.DownArrow)){ | |
if(Input.GetKey(KeyCode.RightArrow)){ | |
m_CharacterContoller2D.OnMove(new Vector2( 1, -1)); | |
}else if(Input.GetKey(KeyCode.LeftArrow)){ | |
m_CharacterContoller2D.OnMove(new Vector2( -1, -1)); | |
}else{ | |
m_CharacterContoller2D.OnMove(new Vector2( 0, -1)); | |
} | |
}else{ | |
m_CharacterContoller2D.OnMove(new Vector2( 0, 0)); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment