반응형

기본적인 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
:

[Godot] Wall Jump 벽 점프

Godot 2023. 10. 2. 16:53 |
반응형

벽을 타고 점프해 보자.

 

바닥, 벽, 캐릭터를 적당히 배치한다. 캐릭터에는 스크립트를 추가하자.

 

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
using Godot;
 
public partial class CharacterBody2D : Godot.CharacterBody2D
{
    public const float Speed = 300.0f;
    public const float JumpVelocity = -400.0f;
 
    public float gravity = ProjectSettings.GetSetting("physics/2d/default_gravity").AsSingle();
 
    public override void _PhysicsProcess(double delta)
    {
        Vector2 velocity = Velocity;
 
        if (!IsOnFloor())
            velocity.Y += gravity * (float)delta;
        
        if (Input.IsActionJustPressed("ui_accept"&& IsOnFloor())
            velocity.Y = JumpVelocity;
 
        if (Input.IsActionJustPressed("ui_accept"&& IsOnWallOnly())
            velocity.Y = JumpVelocity;
 
        Vector2 direction = Input.GetVector("ui_left""ui_right""ui_up""ui_down");
        if (direction != Vector2.Zero)
        {
            velocity.X = direction.X * Speed;
        }
        else
        {
            velocity.X = Mathf.MoveToward(Velocity.X, 0, Speed);
        }
 
        Velocity = velocity;
        MoveAndSlide();
    }
}
 

 

 

IsOnWallOnly() 함수를 사용한 스크립트를 작성한다. 

 

벽을 타고 wall jump가 가능하다.

 

※ 참고

CharacterBody2D

Using CharacterBody2D/3D

 

반응형
Posted by J-sean
:
반응형

캐릭터의 더블 점프를 구현해 보자.

 

CharacterBody2D 노드를 이용해 캐릭터를 만든다.

 

● CharacterBody2D - control.cs 스크립트를 추가

● Sprite2D - Texture 지정

● CollsionShape2D - Shape 속성 설정

 

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
using Godot;
 
public partial class control : CharacterBody2D
{
    public const float Speed = 300.0f;
    public const float JumpVelocity = -400.0f;
 
    // Get the gravity from the project settings to be synced with RigidBody nodes.
    public float gravity = ProjectSettings.GetSetting("physics/2d/default_gravity").AsSingle();
 
    private bool isFirstJump = false;
 
    public override void _PhysicsProcess(double delta)
    {
        Vector2 velocity = Velocity;
 
        // Add the gravity.
        if (!IsOnFloor())
            velocity.Y += gravity * (float)delta;
 
        // Handle First Jump.
        if (Input.IsActionJustPressed("ui_accept"&& IsOnFloor())
        {
            velocity.Y = JumpVelocity;
            isFirstJump = true;
        }
        // Handle Second Jump.
        else if (Input.IsActionJustPressed("ui_accept"&& isFirstJump == true)
        {
            velocity.Y = JumpVelocity;
            isFirstJump = false;
        }
 
        // Get the input direction and handle the movement/deceleration.
        // As good practice, you should replace UI actions with custom gameplay actions.
        Vector2 direction = Input.GetVector("ui_left""ui_right""ui_up""ui_down");
        if (direction != Vector2.Zero)
        {
            velocity.X = direction.X * Speed;
        }
        else
        {
            velocity.X = Mathf.MoveToward(Velocity.X, 0, Speed);
        }
 
        Velocity = velocity;
        MoveAndSlide();
    }
}
 

 

 

더블 점프 구현을 위한 control.cs 스크립트는 위와 같이 작성한다.

 

Node2D 노드를 이용해 Ground 를 만든다.

 

● StaticBody2D

● Sprite2D - Texture 지정(ground.jpg)

● CollisionShape2D - Shape 속성을 Sprite2D 땅 부분에 맞게 설정

 

gound.jpg
0.20MB

 

Node 노드를 이용해 전체 게임을 구성한다.

 

위에서 만든 캐릭터와 그라운드를 Node 노드의 자식노드로 추가한다. (Instantiate Child Scene)

 

 

배경 이외의 부분이 보이지 않도록 윈도우 사이즈를 적당히 조절한다.

 

게임을 실행하고 이중 점프를 테스트 한다.

 

※ 참고

Using CharacterBody2D/3D

CharacterBody2D

2D movement overview

 

반응형
Posted by J-sean
:
반응형

캐릭터 이동 방법을 몇 가지 알아보자.

 

씬을 준비한다.

CharacterBody2D 노드를 생성하고 Sprite2D, CollisionShape2D 노드를 자식노드로 추가한다.

● CharacterBody2D - control.cs 스크립트 추가

● Sprite2D - Texture 지정

● CollisionShape2D - Shape 속성 설정

 

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
using Godot;
 
public partial class control : CharacterBody2D
{
    private int speed = 200;
 
    public override void _PhysicsProcess(double delta)
    {
        LookAt(GetGlobalMousePosition());
        if(Input.IsKeyPressed(Key.Up))
        {
            Velocity = new Vector2(speed, 0).Rotated(Rotation);
            //Position += Velocity * (float)delta;
            //
            // When moving a CharacterBody2D, you should not set its
            // position property directly. Instead, you use the
            // move_and_collide() or move_and_slide() methods.These
            // methods move the body along a given vector and detect
            // collisions.
 
            MoveAndSlide();
        }
        if(Input.IsKeyPressed(Key.Down))
        {
            Velocity = new Vector2(-speed, 0).Rotated(Rotation);
            //Position += Velocity * (float)delta;
            MoveAndSlide();
        }
    }
}
 

 

 

위와 같이 스크립트를 작성한다.

 

게임을 실행하고 위, 아래 키를 누르면 캐릭터가 마우스를 따라 움직인다.

 

이번엔 마우스를 클릭한 지점으로 움직이는 캐릭터를 만들어 보자.

 

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
using Godot;
 
public partial class control : CharacterBody2D
{
    private int speed = 200;
    private Vector2 target = new Vector2();
 
    public override void _PhysicsProcess(double delta)
    {
        LookAt(GetGlobalMousePosition());
 
        if(Input.IsMouseButtonPressed(MouseButton.Left))
        {
            target = GetGlobalMousePosition();
        }
 
        Velocity = Position.DirectionTo(target) * speed;
        //Position += Velocity * (float)delta;
        //
        // When moving a CharacterBody2D, you should not set its
        // position property directly. Instead, you use the
        // move_and_collide() or move_and_slide() methods.These
        // methods move the body along a given vector and detect
        // collisions.
        if(Position.DistanceTo(target) > 2)
            MoveAndSlide();
    }
}
 

 

 

control.cs 스크립트를 위와 같이 작성한다.

 

 

마우스가 클릭된 지점을 따라 캐릭터가 움직인다.

 

※ 참고

Using CharacterBody2D/3D

CharacterBody2D

2D movement overview

 

반응형
Posted by J-sean
:
반응형

캐릭터를 움직여 보자.

 

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
import pygame
 
pygame.init()
pygame.display.set_caption("Super fun game development")
screen = pygame.display.set_mode((640480))
clock = pygame.time.Clock()
running = True
 
player = pygame.image.load("player.png").convert()
player.set_colorkey(player.get_at((00)))
player_size = (player.get_width()*1.5, player.get_height()*1.5)
player = pygame.transform.scale(player, player_size)
player_pos = player.get_rect()
player_pos.center = (screen.get_width()/2, screen.get_height()/2)
player_speed = 4
# 플레이어 이동 속도
player_direction = -1
# 플레이어 이동 방향
 
sound = pygame.mixer.Sound("music.mp3")
sound.play()
 
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        elif event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
            running = False
 
    keys = pygame.key.get_pressed()
    # 모든 키의 상태를 확인한다.
    if keys[pygame.K_LEFT]: # 왼쪽키가 눌렸다면..
        if player_direction > 0:
            player = pygame.transform.flip(player, TrueFalse)
            player_direction = -1
            # 플레이어가 오른쪽으로 이동중이었다면 왼쪽으로 반전한다.
        player_pos.move_ip(-player_speed, 0)
    if keys[pygame.K_RIGHT]: # 오른쪽키가 눌렸다면..
        if player_direction < 0:
            player = pygame.transform.flip(player, TrueFalse)
            player_direction = 1
            # 플레이어가 왼쪽으로 이동중이었다면 오른쪽으로 반전한다.
        player_pos.move_ip(player_speed, 0)
        # 플레이어를 player_speed 만큼 x축으로 이동한다.
 
    screen.fill("black")
    screen.blit(player, player_pos)
    
    pygame.display.flip()
    clock.tick(60)
 
pygame.quit()
 

 

 

캐릭터가 좌우로 움직인다.

 

반응형
Posted by J-sean
: