반응형

기본적인 2D 캐릭터 컨트롤러. 2D 테스트에 활용 할 수 있다.

빈 오브젝트에 스프라이트 렌더러 정도만 추가하고 사용하면된다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
using UnityEngine;
 
[RequireComponent(typeof(Rigidbody2D))]
[RequireComponent(typeof(CapsuleCollider2D))]
[RequireComponent(typeof(PlatformEffector2D))]
 
public class CharacterController2D : MonoBehaviour
{
    public float maxSpeed = 3.0f;
    public float jumpHeight = 6.0f;
    public float gravityScale = 1.5f;
 
    float moveDirection = 0.0f;
    float collisionCheckRadius = 0.0f;
    bool facingRight = true;
    bool isGrounded = false;
    bool isJumping = false;
 
    Rigidbody2D rigidBody;
    CapsuleCollider2D mainCollider;
    PlatformEffector2D platformEffector;
 
    Vector3 cameraPos;
    public Camera mainCamera;
 
    void Start()
    {
        rigidBody = GetComponent<Rigidbody2D>();
        mainCollider = GetComponent<CapsuleCollider2D>();
        platformEffector = GetComponent<PlatformEffector2D>();
 
        rigidBody.freezeRotation = true;
        // Freeze rotation: Prevents the Rigidbody2D from rotating due to collisions or physics forces.
        rigidBody.collisionDetectionMode = CollisionDetectionMode2D.Continuous;
        // Collision Detection Mode: Continuous - Rigidbody2D will use continuous collision detection
        // to prevent fast-moving objects from passing through colliders.
        rigidBody.gravityScale = gravityScale;
 
        mainCollider.usedByEffector = true;
        platformEffector.useOneWay = false;
        platformEffector.useSideFriction = false;
        // PlatformEffector없이 Collider만 사용하면 캐릭터가 점프 후 벽에 붙는 효과가 발생한다. 마찰력 때문이다.
        // platformEffector.useSideFriction을 false로 설정하면 벽에 붙는 효과를 제거할 수 있다.
 
        facingRight = transform.localScale.x > 0.0f;
        collisionCheckRadius = mainCollider.size.x * 0.6f * Mathf.Abs(transform.localScale.x);
 
        if (mainCamera)
        {
            cameraPos = mainCamera.transform.position;
        }
    }
 
    void Update()
    {
        //if ((Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.D)) && (isGrounded || Mathf.Abs(rigidBody.linearVelocity.x) > 0.01f))        
        if (Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.D)) // 위 조건문으로 변경하면, 점프만 했을때 좌우로 움직이지 않게 된다.
        {
            moveDirection = Input.GetKey(KeyCode.A) ? -1 : 1;
        }
        else if (isGrounded || rigidBody.linearVelocity.magnitude < 0.01f)
        {
            moveDirection = 0.0f;
        }
 
        // Jumping logic. 키 입력 확인이 FixedUpdate()에서 처리되면 제대로 감지되지 않을때가 있다.
        if (Input.GetKeyDown(KeyCode.W) && isGrounded)
        {
            isJumping = true;
        }
 
        // Change facing direction
        if (moveDirection != 0)
        {
            if (moveDirection > 0 && !facingRight)
            {
                facingRight = true;
                transform.localScale = new Vector3(Mathf.Abs(transform.localScale.x), transform.localScale.y, transform.localScale.z);
            }
            else if (moveDirection < 0 && facingRight)
            {
                facingRight = false;
                transform.localScale = new Vector3(-Mathf.Abs(transform.localScale.x), transform.localScale.y, transform.localScale.z);
            }
        }
    }
 
    void FixedUpdate()
    {
        Vector3 groundCheckPos = mainCollider.bounds.min + new Vector3(mainCollider.size.x * 0.5f, mainCollider.size.x * 0.5f, 0.0f);
 
        // Check if player is grounded. OverlapCircleAll(): Get a list of all Colliders that fall within a circular area.
        Collider2D[] colliders = Physics2D.OverlapCircleAll(groundCheckPos, collisionCheckRadius);
 
        isGrounded = false;
 
        // 플레이어 콜라이더가 아니면 벽 또는 바닥 콜라이더라 가정하고 점프 할 수 있도록 충돌체크한다.
        // 벽을 타고 멀티 점프가 가능하다.
        if (colliders.Length > 0)
        {
            for (int i = 0; i < colliders.Length; i++)
            {
                if (colliders[i] != mainCollider)
                {
                    isGrounded = true;
                    break;
                }
            }
        }
 
        if (isJumping)
        {
            // Apply jump force            
            rigidBody.linearVelocity = new Vector2(rigidBody.linearVelocity.x, jumpHeight);
            //rigidBody.AddForce(new Vector2(0.0f, jumpHeight * rigidBody.mass), ForceMode2D.Impulse);
            isJumping = false;
        }
        else
        {
            // Apply movement velocity
            rigidBody.linearVelocity = new Vector2(moveDirection * maxSpeed, rigidBody.linearVelocity.y);
        }
 
        // OverlapCircleAll() 이 커버하는 범위를 시각적으로 표시하기 위해 디버그 라인 그리기.
        Debug.DrawLine(groundCheckPos, groundCheckPos - new Vector3(0.0f, collisionCheckRadius, 0.0f), isGrounded ? Color.green : Color.red);
        Debug.DrawLine(groundCheckPos, groundCheckPos + new Vector3(collisionCheckRadius * (facingRight ? 1 : -1), 0.0f, 0.0f), isGrounded ? Color.green : Color.red);
    }
 
    private void LateUpdate()
    {
        // Ensure the camera follows the player smoothly
        if (mainCamera)
        {
            // 카메라의 y, z 좌표는 고정하고, x 좌표만 플레이어의 x 좌표로 설정.
            mainCamera.transform.position = new Vector3(transform.position.x, cameraPos.y, cameraPos.z);
        }
    }
}
 

 

 

반응형
Posted by J-sean
: