Notice
Recent Posts
Recent Comments
Link
«   2024/11   »
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
Archives
Today
Total
관리 메뉴

codingfarm

상속 본문

Unity3d

상속

scarecrow1992 2022. 2. 21. 22:51

 

데미지를 입는 오브젝트가 있다고 하자.

이 오브젝트에 총알이 닿으면, 충돌체의 종류에 알맞은 이벤트가 발생할것이다.

생명체의 경우엔 데미지를 입은 후, HP가 바닥너면 죽어서 사라질것이다.

장애물은 파괴되어 산산이 흩어질것이다.

게이트라면 문이 열릴것이다.

그리고 각 오브젝트는 자신들이 총알에 닿았을때 발동시킬 함수를 다 가지고 있다.

총알은 자신과 닿은 오브젝트의 종류를 파악한 후, switch 문으로 분기점을 형성하여 각기 다른 함수를 호출해도 된다.

 

하지만 총알은 자신이 닿은 오브젝트가 무엇인지 신경 쓰지 않고 그냥 파괴 효과를 주는것이 더 효율 적일것이다.

이런 경우, 상속이 매우 유용히 쓰일 수 있다.

총알의 경우 충돌이 발생했을 때, 상대방에게 IDamageable 컴포넌트가 있는지만 조사하여, 참일경우 충돌체의 TakeHit 함수를 호출 시키면 된다.

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
using UnityEngine;
using System.Collections;
 
public class Projectile : MonoBehaviour {
 
    public LayerMask collisionMask;
    float speed = 10;
    float damage = 1;
 
    public void SetSpeed(float newSpeed) {
        speed = newSpeed;
    }
    
    void Update () {
        float moveDistance = speed * Time.deltaTime;
        CheckCollisions (moveDistance);
        transform.Translate (Vector3.forward * moveDistance);
    }
 
 
    void CheckCollisions(float moveDistance) {
        Ray ray = new Ray (transform.position, transform.forward);
        RaycastHit hit;
 
        if (Physics.Raycast(ray, out hit, moveDistance, collisionMask, QueryTriggerInteraction.Collide)) {
            OnHitObject(hit);
        }
    }
 
    void OnHitObject(RaycastHit hit) {
        IDamageable damageableObject = hit.collider.GetComponent<IDamageable> ();
        if (damageableObject != null) {
            damageableObject.TakeHit(damage, hit);
        }
        GameObject.Destroy (gameObject);
    }
}
 
cs

 

 

IDamageable와 자식클래스들을 작성하는 예는 아래와 같다.

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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
//================================================================
//IDamageable.cs
 
using UnityEngine;
 
public interface IDamageable {
 
    void TakeHit (float damage, RaycastHit hit);
 
}
 
 
//================================================================
// LivingEntity.cs
 
using UnityEngine;
using System.Collections;
 
public class LivingEntity : MonoBehaviour, IDamageable {
 
    public float startingHealth;
    protected float health;
    protected bool dead;
 
    protected virtual void Start() {
        health = startingHealth;
    }
 
    public void TakeHit(float damage, RaycastHit hit) {
        health -= damage;
 
        if (health <= 0 && !dead) {
            Die();
        }
    }
 
    protected void Die() {
        dead = true;
        GameObject.Destroy (gameObject);
    }
}
 
 
 
 
//================================================================
// Plater.cs
 
using UnityEngine;
using System.Collections;
 
[RequireComponent (typeof (PlayerController))]
[RequireComponent (typeof (GunController))]
public class Player : LivingEntity {
 
    public float moveSpeed = 5;
 
    Camera viewCamera;
    PlayerController controller;
    GunController gunController;
    
    protected override void Start () {
        base.Start ();
        controller = GetComponent<PlayerController> ();
        gunController = GetComponent<GunController> ();
        viewCamera = Camera.main;
    }
 
    void Update () {
        // Movement input
        Vector3 moveInput = new Vector3 (Input.GetAxisRaw ("Horizontal"), 0, Input.GetAxisRaw ("Vertical"));
        Vector3 moveVelocity = moveInput.normalized * moveSpeed;
        controller.Move (moveVelocity);
 
        // Look input
        Ray ray = viewCamera.ScreenPointToRay (Input.mousePosition);
        Plane groundPlane = new Plane (Vector3.up, Vector3.zero);
        float rayDistance;
 
        if (groundPlane.Raycast(ray,out rayDistance)) {
            Vector3 point = ray.GetPoint(rayDistance);
            //Debug.DrawLine(ray.origin,point,Color.red);
            controller.LookAt(point);
        }
 
        // Weapon input
        if (Input.GetMouseButton(0)) {
            gunController.Shoot();
        }
    }
}
 
 
 
 
//================================================================
// Enemy.cs
 
using UnityEngine;
using System.Collections;
 
[RequireComponent (typeof (NavMeshAgent))]
public class Enemy : LivingEntity {
 
    NavMeshAgent pathfinder;
    Transform target;
 
    protected override void Start () {
        base.Start ();
        pathfinder = GetComponent<NavMeshAgent> ();
        target = GameObject.FindGameObjectWithTag ("Player").transform;
 
        StartCoroutine (UpdatePath ());
    }
 
    void Update () {
 
    }
 
    IEnumerator UpdatePath() {
        float refreshRate = .25f;
 
        while (target != null) {
            Vector3 targetPosition = new Vector3(target.position.x,0,target.position.z);
            if (!dead) {
                pathfinder.SetDestination (targetPosition);
            }
            yield return new WaitForSeconds(refreshRate);
        }
    }
}
 
 
 
 
//================================================================
// Obstacle.cs
 
using UnityEngine;
using System.Collections;
 
public class Obstacle : MonoBehaviour, IDamageable {
    public int startingCnt;
    protected int cnt;
    protected bool destruct;
 
    protected virtual void Start() {
        cnt = startingCnt;
    }
 
    public void TakeHit(float damage, RaycastHit hit){
        cnt--;
        
        if(cnt <= 0 && !destruct) {
            Destruct();
        }
    }
 
    protected void Destruct(){
        destruct = true;
        Bloken();
    }
}
 
 
 
//================================================================
// Gate.cs
 
using UnityEngine;
using System.Collections;
 
using UnityEngine;
using System.Collections;
 
public class Gate : MonoBehaviour, IDamageable {
    public int startingCnt;
    protected int cnt;
    protected bool destruct;
    protected virtual void Start() {
        cnt = startingCnt;
    }
    public void TakeHit(float damage, RaycastHit hit){
        cnt--;
        
        if(cnt <= 0 && !destruct) {
            GateOpen();
        }
    }
    protected void GateOpen(){
        destruct = true;
        PlayOpenAnimation();
    }
}
 
cs

 

파괴 가능한 오브젝트의 클래스는 무조건 IDamageable을 상속받는다.

IDamageable은 함수의 선언만 가진다, 모호성을 없애야 하므로 필드는 일체 가지지 않는다.

인터페이스 내에서 선언된 함수는 무조건 자식클래스에서 정의해야한다.

Player와 Enemy는 둘다 LivingEntity를 상속받는다. 그런데 3개의 클래스 모두 Start 함수를 가진다. 이 경우, LivingEntity는 자식 클래스에 대해 공통으로 설정하기 위한 코드를 자신의 Start 함수 내에 작성하게 되는데, 자식 클래스에서는 이 부모의 Start 함수를 호출 하기 위해 Base.Start() 구문을 포함해야한다. 그리고 부모의 함수는 virtual로, 자식의 함수는 override로 설정해준다.

 

 

 

 

 

 

'Unity3d' 카테고리의 다른 글

애니메이션  (0) 2022.02.22
네비게이션 메쉬(Navigation Mesh)  (0) 2022.02.22
시간  (0) 2022.02.21
생성  (0) 2022.02.21
이동  (0) 2022.02.21
Comments