Outline

현재 스테이지에 Catwalk 가 있기 때문에, Catwalk 아래로 내려가면 바닥에 플레이어가 가려져 보이지 않는다.
이를 해결하기 위해 다음과 같은 상황에서 outline 을 그려주었다.

플레이어가 바닥에 가려져 보이지 않을 때,

플레이어와 아래에 있는 오브젝트들의 outline 이 보이게 된다.
https://velog.velcdn.com/images/lutca1320/post/82008bb7-e2b7-464a-962c-c483e95790d2/image.gif

플레이어가 장애물에 가려져 보이지 않을 때

플레이어의 outline 이 보이게 된다.
https://velog.velcdn.com/images/lutca1320/post/53136bbb-dd47-4fb4-a02c-96a1b04d6a89/image.gif

EnemyRobot 이 바닥에 가려지면

그 EnemyRobot 의 outline 이 보인다.
https://velog.velcdn.com/images/lutca1320/post/6a4b2979-19c9-4464-a9e5-995810a1cc9c/image.gif

OutlineController.cs

1using System.Collections;
2using System.Collections.Generic;
3using System.Linq;
4using Mono.Cecil;
5using UnityEngine;
6
7public class OutlineController : MonoBehaviour
8{
9    private int outlineLayer;
10    private int objectLayer;
11    private int obstacleLayer;
12
13    private Camera camera;
14    private GameObject[] obstacleAry;
15    private GameObject[] enemyAry;
16
17    private void ShowPlayerOutline()
18    {
19        for (int i = 2; i < transform.childCount; i++)
20        {
21            transform.GetChild(i).gameObject.layer = outlineLayer;
22        }
23    }
24
25    private void ShowObstacleOutline()
26    {
27        foreach (GameObject o in obstacleAry)
28        {
29            SetLayerRecursive(o, outlineLayer);
30        }
31    }
32
33    private void SetEnemyRobotOutline()
34    {
35        foreach (var enemyRobot in enemyAry)
36        {
37            if (enemyRobot == null) continue;
38            Physics.Linecast(camera.transform.position, enemyRobot.transform.position, out RaycastHit hit,
39                1 << LayerMask.NameToLayer("Obstacle") | 1 << LayerMask.NameToLayer("Ground"));
40
41            for (int i = 4; i < enemyRobot.transform.childCount; i++)
42            {
43                enemyRobot.transform.GetChild(i).gameObject.layer = hit.collider ? outlineLayer : objectLayer;
44            }
45        }
46    }
47
48    private void HidePlayerOutline()
49    {
50        for (int i = 2; i < transform.childCount; i++)
51        {
52            transform.GetChild(i).gameObject.layer = objectLayer;
53        }
54    }
55
56    private void HideObstacleOutline()
57    {
58        foreach (GameObject o in obstacleAry)
59        {
60            SetLayerRecursive(o, obstacleLayer);
61        }
62    }
63
64    private void SetLayerRecursive(GameObject o, int layer)
65    {
66        o.layer = layer;
67        foreach (Transform child in o.transform)
68        {
69            child.gameObject.layer = layer;
70
71            Transform hasChildren = child.GetComponentInChildren<Transform>();
72            if (hasChildren != null) SetLayerRecursive(child.gameObject, layer);
73        }
74    }
75
76    private void Start()
77    {
78        outlineLayer = LayerMask.NameToLayer("Outlined");
79        objectLayer = LayerMask.NameToLayer("Object");
80        obstacleLayer = LayerMask.NameToLayer("Obstacle");
81
82        camera = GetComponent<PlayerCameraController>().mainCam;
83        obstacleAry = GameObject.FindGameObjectsWithTag("OutlineObstacle");
84        enemyAry = FindObjectsOfType<EnemyRobotAI>().Select(ai => ai.gameObject).ToArray();
85    }
86
87    private void Update()
88    {
89        Physics.Linecast(camera.transform.position, transform.position, out RaycastHit obstacleHit, 1 << LayerMask.NameToLayer("Obstacle"));
90
91        Physics.Linecast(camera.transform.position, transform.position, out RaycastHit groundHit, 1 << LayerMask.NameToLayer("Ground"));
92
93        HidePlayerOutline();
94        HideObstacleOutline();
95
96        if (groundHit.collider)
97        {
98            ShowPlayerOutline();
99            ShowObstacleOutline();
100        }
101        if (obstacleHit.collider)
102        {
103            ShowPlayerOutline();
104        }
105
106        SetEnemyRobotOutline();
107    }
108}
109