본문 바로가기
프로그래밍

Line Drawing 스크립트 설명

by HyunS_PG 2020. 5. 13.
반응형

 

 

※목차

1. 선, 공 그리기

2. 배경 이동

3. 플레이어 행동

4. 적과 탄환

5. 전체 스크립트 및 게임 다운로드

 

 

 

1. 선, 공 그리기              

마우스 왼쪽 클릭 후 드래그하면 선이 그려지며 플랫폼이 생성된다.

스크립트)

 1) CreateLine(),  UpdateLine() 함수

   - 마우스 드래그할 때 마우스의 좌표들을 List로 저장하여 Line Renderer를 이용해 그 정점들을 잇는 선을 그립니다.

     그리고 Edge Collider를 이용해 플레이어가 밟을 수 있는 플랫폼을 만듭니다.

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
   //선 생성 함수
    void CreateLine()
    {
        //선 생성 준비
        currentLine = Instantiate(linePrefab, Vector3.zero, Quaternion.identity);
        lineRenderer = currentLine.GetComponent<LineRenderer>();
        edgeCollider = currentLine.GetComponent<EdgeCollider2D>();
        fingerPositions.Clear();
 
        //선 생성
        line_StartPos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
        fingerPositions.Add(line_StartPos);
        fingerPositions.Add(line_StartPos);
        lineRenderer.SetPosition(0, fingerPositions[0]);
        lineRenderer.SetPosition(1, fingerPositions[1]);
        edgeCollider.points = fingerPositions.ToArray();
    }
 
    //선 그리기 함수
    void UpdateLine(Vector2 newFingerPos)
    {
        fingerPositions.Add(newFingerPos);
        lineRenderer.positionCount++;
        lineRenderer.SetPosition(lineRenderer.positionCount - 1, newFingerPos);
        edgeCollider.points = fingerPositions.ToArray();
    }
cs

 

 2) EraseLIne() 함수

   - RaycastHit와 LayerMask를 이용한 layerchk()함수를 사용하여 선 혹은 공인지 아닌지 구분합니다.

      그 후 선 혹은 공이면 마우스 우클릭으로 오브젝트 삭제가 가능합니다.

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
void Update()
{        
   (생략)    
   //마우스 오른쪽 버튼을 눌렀을 때
   else if (Input.GetMouseButtonDown(1))
   {
      if(!isRedBall)
         EraseLIne("Line");
      else
         EraseLIne("Ball");
   }
   (생략)
 
//선 지우기 함수
void EraseLIne(string layerName)
{
   RaycastHit2D hit = layerChk(layerName);
 
   if (hit.collider != null)
   {
      GameObject target = hit.collider.gameObject;
 
      if (!isRedBall)
         Destroy(target);
      else
         Destroy(target.transform.parent.gameObject);
   }
}
 
//특정 레이어의 RaycastHit2D를 반환하는 함수
RaycastHit2D layerChk(string layerName)
{
   Vector2 pos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
 
   int layerMask = 1 << LayerMask.NameToLayer(layerName);
   RaycastHit2D hit = Physics2D.Raycast(pos, Vector2.zero, 0f, layerMask);
 
   return hit;
}
cs

 

마우스 왼쪽 클릭 후 바로 마우스를 떼면 공이 생성되며 그 공을 클릭하면 크기가 커진다.

 3)선을 그릴 때와 공을 생성할 때를 구분하기 위해서 처음과 끝 마우스 좌표가 같으면 물리엔진이 작용하는 공이

    생성되도록 조건문을 사용했습니다.

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
void Update()
{
   (생략)
   //마우스 왼쪽 버튼을 땔 때 && 빨간 공이 아닐 때 && 연필심 양이 남았을 때
   else if (Input.GetMouseButtonUp(0&& !isRedBall && !isEmpty)
   {
      audio.Stop();
 
      //선 첫 지점과 끝 지점 위치가 같을 때 점에 중력이 작용
      if (Vector2.Distance(line_EndPos, line_StartPos) < 0.1f && lineRenderer.positionCount < 3)
      {
         PencilQuantity(-3); //연필심 양 -3
 
         currentLine.GetComponent<Rigidbody2D>().isKinematic = false;
         currentLine.GetComponent<EdgeCollider2D>().edgeRadius = 0.08f;
 
         FindObjectOfType<RendererToCollider>().EdgePosCreate();
 
         #region 빨간색 버튼
         //빨간색 버튼 생성
         GameObject go = Instantiate(ballPrefab, line_EndPos, Quaternion.identity);
 
         //선을 빨간색 공의 부모로 설정
         go.transform.SetParent(currentLine.transform);
         #endregion
      }
      isDrawing = false;
 
      player.GetComponent<Animator>().SetBool("Drawing"false);
   }
}
cs

 

 4) RaycastHit와 layerChk() 함수를 사용하여 공인지 아닌지 구분 후 공이면 크기와 질량이 커질 수 있도록

    RedBall.cs의 ScaleUp() 함수를 사용했습니다.

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
public class DrawLine : MonoBehaviour
{
    (생략)
    //커서가 빨간공 위에 있는지 체크하는 함수
    void RedBallChk()
    {
        RaycastHit2D hit = layerChk("Ball");
 
        if (hit.collider != null)
            isRedBall = true;
        else
            isRedBall = false;
    }
}
 
 
 
public class RedBall : MonoBehaviour
{
    (생략)
    //공 크기 커지게 하는 함수
    public void ScaleUp(Transform hitCollider)
    {
        if (hitCollider.localScale.x < 3.5)     //공 최대 크기 3.5
        {
            hitCollider.localScale = new Vector2(hitCollider.localScale.x * 1.5f, hitCollider.localScale.y * 1.5f);
            transform.parent.GetComponent<Rigidbody2D>().mass *= 1.6f;
        }
    }
}
cs

 

 

 

 

 

 

2. 카메라와 배경 이동              

플레이어 위치에 따라 배경이 제한된 범위에서 이동합니다.

스크립트)

 1) Reposition() 함수를 사용해 방향값 dir만 가져와서 카메라 위치에 따라 배경 이미지를 앞뒤로 이동시킵니다.

 2) CameraMove클래스에서 조건문으로 맵 밖으로 나가지 않게 하기 위해 카메라 이동에 제한을 둡니다.

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
public class BackgroundScroll : MonoBehaviour
{
    Transform camera_Tran;
    Transform player;
    float width;
 
    void Awake()
    {
        BoxCollider2D backgoundCollider = GetComponent<BoxCollider2D>();
        width = backgoundCollider.size.x;
    }
 
    void Start()
    {
        player = GameObject.Find("Player").transform;
        camera_Tran = GameObject.Find("Main Camera").transform;
    }
    
    void Update()
    {
        transform.position = new Vector2(transform.position.x, camera_Tran.position.y);
        
        //배경이 움직이는 방향
        if (camera_Tran.position.x - transform.position.x >= width)
            Reposition(1);
        else if (transform.position.x - camera_Tran.position.x > width)
            Reposition(-1);
    }
 
    //배경 이동 함수
    void Reposition(int dir)
    {
        Vector2 offset = new Vector2(width * 2f * dir, 0);
        transform.position += (Vector3)offset;
    }
}
 
 
 
public class CameraMove : MonoBehaviour
{
    Transform player;
    void Start()
    {
        player = GameObject.Find("Player").transform;    
    }
    void Update()
    {
        transform.position = new Vector3(player.position.x, player.position.y, -10);
 
        //카메라 이동 x축 제한
        if(transform.position.x < 0f)
        {
            transform.position = new Vector3(0, transform.position.y, -10);
        }
 
        //카메라 이동 y축 제한
        if (transform.position.y < 0f)
        {
            transform.position = new Vector3(transform.position.x, 0f, -10);
        }
        else if (transform.position.y > 3f)
        {
            transform.position = new Vector3(transform.position.x, 3f, -10);
        }
    }
}
 
cs

 

 

 

 

 

 

3. 플레이어 행동              

스크립트)

 1) 조건문을 사용하여 선을 그리는 중에 이동하지 못하도록 제약을 뒀습니다.

 2) PlayerFoot에 Circle Collider를 만들고 GroundCheck.cs 스크립트로 점프할 때 땅 위에 있는지 없는지

    체크하도록 만들었습니다.

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
public class PlayerController : MonoBehaviour
{
    (생략)
    //플레이어 이동
    void playerMove()
    {
        //플레이어가 죽은 상태가 아니고 그리는 중이 아닐 때 움직일 수 있다는 조건
        if (!isDead && !FindObjectOfType<DrawLine>().isDrawing)
        {
            //횡이동
            int horizontal = (int)Input.GetAxisRaw("Horizontal");
 
            //이동할 때
            if (horizontal != 0)
            {
                transform.localScale = new Vector3(horizontal, 11);
 
                rb2D.velocity = new Vector2(walk_Speed * horizontal * Time.deltaTime, rb2D.velocity.y);
 
                //땅위에 있으면
                if (isGrounded)
                    animator.SetBool("Walk"true);
            }
            //움직이지 않을 때
            else
            {
                rb2D.velocity = new Vector2(0, rb2D.velocity.y);
                animator.SetBool("Walk"false);
            }
 
            //점프할 때
            if (Input.GetKeyDown(KeyCode.Space) && jumpCount < 1 && isGrounded)
            {
                isGrounded = false;
                jumpCount++;
 
                rb2D.velocity = new Vector2(00);
                rb2D.AddForce(transform.up * jump_Force);
 
                animator.SetBool("Jump"true);
            }
        }
    }
}
 
 
 
public class GroundCheck : MonoBehaviour
{
    public GameObject player;
 
    private void OnCollisionEnter2D(Collision2D collision)
    {
        //땅이나 선에 닿을시
        if (collision.transform.tag == "Line" || collision.transform.tag == "Ground")
        {
            player.GetComponent<PlayerController>().animator.SetBool("Jump"false);
        }
    }
 
    private void OnCollisionStay2D(Collision2D collision)
    {
        //땅이나 선에 서있을 때
        if (collision.transform.tag == "Line" || collision.transform.tag == "Ground")
        {
            player.GetComponent<PlayerController>().jumpCount = 0;      //점프한 횟수 초기화
            player.GetComponent<PlayerController>().isGrounded = true;  //땅위에 있는 상태 true
        }
    }
    private void OnCollisionExit2D(Collision2D collision)
    {
        //땅이나 선에서 떨어졌을 때
        if (collision.transform.tag == "Line" || collision.transform.tag == "Ground")
        {
            player.GetComponent<PlayerController>().isGrounded = false//땅위에 있는 상태 false
        }
    }
}
cs

 

 3) 플레이어가 그리는 도중에도 자연스러운 동작이 되도록 DrawingReady와 IdleToDrawing 애니메이션을 따로

    만들었습니다.

그리는 시간에 따른 플레이어 동작
Animator 화면

 

 

 

 

 

4. 적과 탄환             

스크립트)

 1) Time.deltaTime을 사용하여 발사 시간을 조절했습니다.

 2) Instantiate로 탄환을 생성하고 탄환은 생성될 때 적(parent)이 바라보고 있는 방향으로 발사되도록 했습니다.

 3) 탄환이 환경 오브젝트하고 충돌하면 탄환만 삭제하도록 했고, 선이나 공과 충돌하면 선과 공까지 같이

     삭제되도록 했습니다.

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
public class BulletSpawner : MonoBehaviour
{
    public GameObject bulletPrefab;
 
    float delta = 0;
    public float spawnTime = 3f;
    
    void Update()
    {
        delta += Time.deltaTime;
 
        //발사 시간 간격
        if(delta > spawnTime)
        {
            delta = 0f;
 
            Vector3 x = new Vector3(1.75f, 00);
 
            //총알 생성
            GameObject bullet = Instantiate(bulletPrefab, transform.position + (x * transform.localScale.x), transform.rotation);
            bullet.transform.SetParent(transform);
        }
    }
}
 
 
 
public class CannonBullet : MonoBehaviour
{
    public float speed;
 
    Rigidbody2D rb2D;
    
    void Start()
    {
        rb2D = GetComponent<Rigidbody2D>();
 
        //적이 바라보고 있는 방향으로 등속도 발사
        transform.localScale = new Vector3(-transform.localScale.x * transform.parent.localScale.x, 11);
        rb2D.velocity = transform.parent.localScale.x * transform.right * speed;
    }
 
    private void OnCollisionEnter2D(Collision2D collision)
    {
        //선이나 공에 닿을 때
        if(collision.collider.tag == "Line" || collision.collider.tag == "Ball")
        {
            Destroy(collision.gameObject);  //선이나 공 삭제
            Destroy(gameObject);            //자기 자신 삭제
        }
        //오브젝트, 땅, 플레이어와 닿을 때
        else if(collision.collider.tag == "Object" || collision.collider.tag == "Ground" || collision.collider.tag == "Player")
        {
            Destroy(gameObject);    //자기 자신 삭제
        }
    }
}
cs

 

 

 

 

 

 

5. 전체 스크립트 및 게임 다운로드              

 

전체 스크립트 : https://nemesis32.tistory.com/111

 

Line Drawing 전체 스크립트

DrawLine.cs 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..

nemesis32.tistory.com

 

스크립트 다운로드 : drive.google.com/file/d/1dsq-0ReAjvYbUKretr7Uh3xTyjqQ3XTe/view?usp=sharing

 

Google 드라이브 - 모든 파일을 한 곳에서

하나의 계정으로 모든 Google 서비스를 Google 드라이브로 이동하려면 로그인하세요.

accounts.google.com

 

게임 다운로드 : https://drive.google.com/open?id=1EyiiJnlTkhNiJ7smA9tstt4pcB7HBB8G

 

Line Drawing.zip

 

drive.google.com

 

반응형

'프로그래밍' 카테고리의 다른 글

Zombie Survive 스크립트, 기능 설명  (0) 2020.06.01
Zombie Survive 전체 스크립트  (0) 2020.06.01
Line Drawing 전체 스크립트  (0) 2020.05.13
DigDog 스크립트 설명  (0) 2020.05.08
DigDog 전체 스크립트  (0) 2020.05.07