Skip to content

Instantly share code, notes, and snippets.

@smallrice45
Last active December 28, 2015 22:48
Show Gist options
  • Save smallrice45/d5fd0d2edeb04798e8af to your computer and use it in GitHub Desktop.
Save smallrice45/d5fd0d2edeb04798e8af to your computer and use it in GitHub Desktop.
Unity 2D CharacterController
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);
}
}
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);
}
}
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);
}
}
}
}
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);
}
}
}
}
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