Shooting

injjoy153
|2025. 3. 11. 10:07

Assets

1.Map_ Simple Low Poly Nature pack

2.Sky_ Customizable skybox

3.Player_ Battle Royale Duo Playart PBR

4.Enemy_ RPG Monster Duo PBR Polyart

5.Effect_ War FX

pdf file

슈팅게임1-1.pdf
2.27MB
슈팅게임1-2.pdf
0.98MB
슈팅게임2-1.pdf
1.80MB

C# Code

Player

Player의 이동

더보기
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Player : MonoBehaviour
{
    // 플레이어 키보드 상하좌우 이동

    public float moveSpeed = 5;  // 이동속도
    public float jumpPower = 4;   // 점프력
    public float rotSpeed = 600;   // 회전속도

    int jumpCount = 0;   // 점프횟수

    Rigidbody rb;
    Animator anim;

    void Start()
    {
        rb = GetComponent<Rigidbody>();
        anim = GetComponent<Animator>();
    }
   
    void Update()
    {
        float h = Input.GetAxis("Horizontal");
        float v = Input.GetAxis("Vertical");

        Vector3 dir = new Vector3(h, 0, v);
        dir.Normalize();  // 모든 방향의 속도가 동일하도록 정규화
        // 플레이어를 기준으로 방향 조절
        dir = transform.TransformDirection(dir);


        // 방향*속도*시간(모든 기기에서 동일한 속도)
        // transform.position += dir * moveSpeed * Time.deltaTime;
        // tr.position, tr.Translate() / rb.position, rb.MovePosition,
        // rb.velocity, rb.Addforce(), rb.AddRelativeForce()
        // 이동시 물리 작용 적용
        rb.MovePosition(rb.position + (dir * moveSpeed * Time.deltaTime));

        // 이동하는 속도를 velocity 변수에 할당하여 애니메이션 전환
        anim.SetFloat("velocity", dir.magnitude);

        // 점프(2단점프)-스페이스키 누른 순간, 점프횟수가 2회 미만이라면
        if (Input.GetKeyDown(KeyCode.Space) && jumpCount < 2)
        {
            // 위로 순간적인 힘 발생
            rb.AddForce(Vector3.up * jumpPower, ForceMode.Impulse);

            // jump 애니메이션 실행
            anim.SetTrigger("jump");
            anim.SetBool("isJump",true);
            
            // 점프할 때마다 점프횟수 증가
            jumpCount++;
        }

        // 마우스의 좌우움직임 입력 받아서 마우스가 움직인만큼 Y축 회전
        float mouseMoveX = Input.GetAxis("Mouse X");
        transform.Rotate(0, mouseMoveX * rotSpeed * Time.deltaTime, 0);
    }

    // 플레이어가 바닥에 닿으면 다시 점프할 수 있도록 준비
    private void OnCollisionEnter(Collision collision)
    {
        if (collision.gameObject.tag == "Ground")
        {
            jumpCount = 0;

            // 점프 애니메이션 종료
            anim.SetBool("isJump", false);
        }
    }
}

PlayerFire

더보기
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerFire : MonoBehaviour
{
    public GameObject bulletPrefab; // 총알프리팹 담아둘 변수

    public float firePower = 8;   // 총알 발사하는 힘

    void Start()
    {
        // 마우스 커서 안보이게하고,
        // 마우스 커서가 게임화면을 벗어나지 못하도록 잠금
        Cursor.visible = false;
        Cursor.lockState = CursorLockMode.Confined;
    }

    void Update()
    {
        // 마우스 왼쪽 클릭 시 총알 공장에서 총알을 생성
        // -> 플레이어의 위치보다 조금 앞에서 순간적적인 힘 발생
         
        if (Input.GetMouseButtonDown(0))
        {
            GameObject bullet = Instantiate(bulletPrefab, transform.position + transform.forward, Quaternion.identity);
            
            bullet.GetComponent<Rigidbody>().AddForce(transform.forward * firePower, ForceMode.Impulse);
        }        
    }
}

PlayerFire2

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerFire2 : MonoBehaviour
{
    // 총효과 프리팹을 담아둘 변수
    public GameObject shootEffectPrefab;

    Animator anim;

    void Start()
    {
        anim = GetComponent<Animator>();

        // 마우스 커서 안보이게하고,
        // 마우스 커서가 게임화면을 벗어나지 못하도록 잠금
        Cursor.visible = false;
        Cursor.lockState = CursorLockMode.Confined;
    }
    void Update()
    {
        // 화면 가운데에 조준점을 만들고, 마우스 왼쪽 클릭 시
        // Ray를 발사해서 Ray에 맞은 물체는 hit 변수에 저장하고 그 이름을 출력한다.
        if (Input.GetMouseButtonDown(0))
        {

            anim.SetTrigger("shoot");

            // 화면 가운데에서 시작하는 Ray 생성
            Ray ray = Camera.main.ViewportPointToRay(new Vector2(0.5f, 0.5f));
            // Ray에 맞은 물체를 담아둘 변수 선언
            RaycastHit hit;

            // Ray를 발사하고, Ray에 맞은 물체는 hit에 저장, 맞은 물체가 있을 때만
            if(Physics.Raycast(ray, out hit))
            {
               // Instantiate(shootEffectPrefab, hit.point, Quaternion.LookRotation(hit.normal));
                // 맞은 위치에, 맞은 표면의 수직이 되는 각도로 총 효과 프리팹의 복사본 생성
                GameObject shootEffect = Instantiate(shootEffectPrefab, hit.point + hit.normal * 0.01f, Quaternion.LookRotation(hit.normal));

                // 총알 자국을 맞은 오브젝트의 자식으로 설정
                shootEffect.transform.SetParent(hit.transform);

                // Ray에 맞은 물체가 Enemy(적)이라면 적에게 10만큼 데미지를 받으라고 전달
                if (hit.transform.tag == "Enemy")
                {
                    hit.transform.SendMessage("Damaged", 10);
                }
            }
        }
    }
}

 

에디터에서 Shoot Effect Prefab라는 항목에 Shoot Effect Prefab을 찾아서 넣어두어야 한다.


CameraTotate

카메라의 움직임과 관련된 코드

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CameraRotate : MonoBehaviour
{
    public float rotSpeed = 600;   // 회전속도

    // eulerAngles.x의 값을 저장할 변수
    float tempX;

    void Update()
    {
        // 마우스의 위아래움직임 입력 받아서 마우스가 움직인만큼 X축 회전
        float mouseMoveY = Input.GetAxis("Mouse Y");
        transform.Rotate(-mouseMoveY * rotSpeed * Time.deltaTime, 0, 0);

        // print(transform.eulerAngles.x);// -10도=350도(오일러각),-10=270도
        // 위아래 회전 범위를 -30~+30도로 제한
        // 각도가 180도가 넘으면 360을 빼서 각도변환, 아니면 그 값 그대로 저장
        if (transform.eulerAngles.x > 180)
        {
            tempX = transform.eulerAngles.x - 360;
        }
        else
        {
            tempX = transform.eulerAngles.x;
        }

        // 변환한 각도에서 -30~+30도 제한(Mathf.Clamp()) -> 오일러값으로 저장
        tempX = Mathf.Clamp(tempX, -30, 30);
        transform.eulerAngles = new Vector3(tempX, transform.eulerAngles.y, transform.eulerAngles.z);
    }
}

Billboard

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Billboard : MonoBehaviour
{
    
    void Update()
    {
        //카메라가 바라보는 방향대로 내가 바라보는 방향 설정
        transform.forward = Camera.main.transform.forward;
    }
}

Enemy

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;   // UI 관련 클래스를 사용하기 위해 추가
using UnityEngine.AI;   // AI 관련된 클래스를 사용하기 위해 네임스페이스 영역 추가


public class Enemy : MonoBehaviour
{
    NavMeshAgent agent; // NavMeshAgent 컴포넌트를 변수로 사용

    // 적이 가질 수 있는 상태 목록
    public enum EnemyState
    {
        Idle,     // 기본(대기)
        Walk,     // 이동
        Attack,   // 공격
        Damaged,  // 피격
        Dead,     // 죽음
    }

    // 상태를 저장할 변수 생성(기본값은 Idle로 지정)
    public EnemyState eState = EnemyState.Idle;

    public float hp = 100;   // 적의 체력
    public Slider hpBar;     // 적의 체력바

    Transform player;   // 플레이어
    float distance;    // 플레이어와의 거리


    // 공격받는 기능
    void Damaged(float damage)
    {
        // 공격받은 데미지만큼 체력 감소
        hp -= damage;

        hpBar.value = hp;

        agent.isStopped = true;     // 이동 중단
        agent.ResetPath();          // 경로 초기화

        if (hp > 0)  // 체력이 남아있다면 피격 상태로 전환
        {
            eState = EnemyState.Damaged; 
        }
        else  // 체력이 남아있지않으면 죽음 상태로 전환
        {
            eState = EnemyState.Dead;
        }
    }

    void Start()
    {
        // Player 컴포넌트로 찾은 플레이어의 Transform 컴포넌트 가져오기
        player = FindObjectOfType<Player>().transform;

        // 나의(Enemy의) NavMeshAgent 컴포넌트 가져오기
        agent = GetComponent<NavMeshAgent>();
    }

    void Update()
    {
        // 적과 플레이어 사이의 거리 계산
        distance = Vector3.Distance(transform.position, player.position);
        print(distance);

        // 기본, 이동, 공격 상태일 때 할 일 나누기
        switch (eState)
        {
            case EnemyState.Idle: Idle(); break;
            case EnemyState.Walk: Walk(); break;
            case EnemyState.Attack: Attack(); break;
        }
    }
    // 플레이어와의 거리가 8
    void Idle()  // 기본 상태일 때 계속 할 일
    {
        // 플레이어와의 거리가 8이하면 이동 상태로 전환
        if (distance <= 8)
        {
            eState = EnemyState.Walk;
            agent.isStopped = false;    // 이동 시작한다.
        }
    }

    void Walk()  // 이동 상태일 때 계속 할 일
    {
        // 플레이어와의 거리가 8보다 크면 기본 상태로 전환
        // 플레이어와의 거리가 2이하면 공격 상태로 전환
        if (distance > 8)
        {
            eState = EnemyState.Idle;
            agent.isStopped = true; // 이동 중단
            agent.ResetPath();      // 경로 초기화
        }
        else if (distance <= 2)
        {
            eState = EnemyState.Attack;
            agent.isStopped = true; // 이동 중단
            agent.ResetPath();      // 경로 초기화
        }
        else
        {
            agent.SetDestination(player.position);
        }
    }

    void Attack()  // 공격 상태일 때 계속 할 일
    {
        // 플레이어와의 거리가 2보다 크면 이동 상태로 전환
        if (distance > 2)
        {
            eState = EnemyState.Walk;
            agent.isStopped = false;    // 이동 시작
        }
    }
}

에디터에 있는 E State은 열거형 변수이고

Hp Bar는 안에 HpBarSlider를 넣어야 한다.