일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 4월
- 7월
- todolist
- 개인 프로젝트
- 10월
- 단계별로 풀어보기
- 다이나믹 프로그래밍
- 골드메탈
- 개인 프로젝트 - 런앤건
- 2024년
- 2월
- 5월
- 코딩 테스트
- 3월
- 백준
- 유니티
- 2025년
- 입문
- 게임 엔진 공부
- 유니티 심화과정
- 코딩 기초 트레이닝
- 2022년
- 자료 구조
- 수학
- 2023년
- C/C++
- 기초
- c++
- 1월
- 프로그래머스
- Today
- Total
기록 보관소
[Unity/유니티] 기초-2D 종스크롤 슈팅: 적 전투와 피격 이벤트 만들기[B30] 본문
개요
유니티 입문과 독학을 위해서 아래 링크의 골드메탈님의 영상들을 보며 진행 상황 사진 또는 캡처를 올리고 배웠던 점을 요약해서 적는다.
현재는 영상들을 보고 따라하고 배우는 것에 집중할 것이며, 영상을 모두 보고 따라한 후에는 개인 프로젝트를 설계하고 직접 만드는 것이 목표다.
https://youtube.com/playlist?list=PLO-mt5Iu5TeYI4dbYwWP8JqZMC9iuUIW2
유니티 강좌 기초 채널 Basic
유니티 개발을 처음 시작하시는 입문자 분들을 위한 기초 채널. [ 프로젝트 ] B00 ~ B12 (BE1) : 유니티 필수 기초 B13 ~ B19 (BE2) : 2D 플랫포머 B20 ~ B26 (BE3) : 2D 탑다운 대화형 RPG B27 ~ B37 (BE4) : 2D 종스크롤
www.youtube.com
2D 종스크롤 슈팅: 적 전투와 피격 이벤트 만들기[B30]
1. 적 생성 추가
//GameManager 스크립트 파일
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameManager : MonoBehaviour {
public GameObject[] enemyObjs;
public Transform[] spawnPoints;
public float maxSpawnDelay;
public float curSpawnDelay;
void Update() {
curSpawnDelay += Time.deltaTime;
if (curSpawnDelay > maxSpawnDelay) {
SpawnEnemy();
maxSpawnDelay = Random.Range(0.5f, 3f);
curSpawnDelay = 0;
}
}
void SpawnEnemy() {
int ranEnemy = Random.Range(0, 3);
int ranPoint = Random.Range(0, 9);
GameObject enemy = Instantiate(enemyObjs[ranEnemy], spawnPoints[ranPoint].position, spawnPoints[ranPoint].rotation);
Rigidbody2D rigid = enemy.GetComponent<Rigidbody2D>();
Enemy enemyLogic = enemy.GetComponent<Enemy>();
if (ranPoint == 5 || ranPoint == 6) { //오른쪽 포인트
enemy.transform.Rotate(Vector3.back * 90); //적 기체 스프라이트 돌리기
rigid.velocity = new Vector2(enemyLogic.speed * (-1), -1);
}
else if (ranPoint == 7 || ranPoint == 8) { //왼쪽 포인트
enemy.transform.Rotate(Vector3.back * (-90)); //적 기체 스프라이트 돌리기
rigid.velocity = new Vector2(enemyLogic.speed, -1);
}
else { //중앙 앞쪽 포인트
rigid.velocity = new Vector2(0, enemyLogic.speed * (-1));
}
}
}
//Enemy 스크립트 파일
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Enemy : MonoBehaviour {
public float speed;
public int health;
public Sprite[] sprites;
SpriteRenderer spriteRenderer;
void Awake() {
spriteRenderer = GetComponent<SpriteRenderer>();
}
void onHit(int dmg) {
health -= dmg;
spriteRenderer.sprite = sprites[1]; //평소 스프라이트 0, 피격시 스프라이트 1
Invoke("ReturnSprite", 0.1f);
if (health <= 0)
Destroy(gameObject);
}
void ReturnSprite() {
spriteRenderer.sprite = sprites[0];
}
void OnTriggerEnter2D(Collider2D collision) {
if (collision.gameObject.tag == "BorderBullet") //맵의 경계로 가게되면
Destroy(gameObject);
else if (collision.gameObject.tag == "PlayerBullet") { //플레이어 총알에 닿으면
Bullet bullet = collision.gameObject.GetComponent<Bullet>();
onHit(bullet.dmg);
Destroy(collision.gameObject); //플레이어 총알 삭제
}
}
}
- 이제 포인트가 옆에도 추가되었으므로, 포인트를 관리하는 GameManager에서 랜덤하게 주어지는 포인트 범위를 늘려야하며, 더이상 적 기체가 무조건 아래로만 내려가도록 하면 안되고 옆으로 이동할 수 있도록 해야한다. 그래서 Enemey 스크립트 파일에서 무조건 아래로 이동했던 로직을 아예 다 지우고, GameManager에서 이들을 불러와 포인트 위치에 따라 스프라이트와 이동 방향을 바뀌게 한다.
2. 적 공격
//GameManager 스크립트 파일
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameManager : MonoBehaviour {
public GameObject[] enemyObjs;
public Transform[] spawnPoints;
public GameObject player;
public float maxSpawnDelay;
public float curSpawnDelay;
void Update() {
curSpawnDelay += Time.deltaTime;
if (curSpawnDelay > maxSpawnDelay) {
SpawnEnemy();
maxSpawnDelay = Random.Range(0.5f, 3f);
curSpawnDelay = 0;
}
}
void SpawnEnemy() {
int ranEnemy = Random.Range(0, 3);
int ranPoint = Random.Range(0, 9);
GameObject enemy = Instantiate(enemyObjs[ranEnemy], spawnPoints[ranPoint].position, spawnPoints[ranPoint].rotation);
Rigidbody2D rigid = enemy.GetComponent<Rigidbody2D>();
Enemy enemyLogic = enemy.GetComponent<Enemy>();
enemyLogic.player = player;
if (ranPoint == 5 || ranPoint == 6) { //오른쪽 포인트
enemy.transform.Rotate(Vector3.back * 90); //적 기체 스프라이트 돌리기
rigid.velocity = new Vector2(enemyLogic.speed * (-1), -1);
}
else if (ranPoint == 7 || ranPoint == 8) { //왼쪽 포인트
enemy.transform.Rotate(Vector3.back * (-90)); //적 기체 스프라이트 돌리기
rigid.velocity = new Vector2(enemyLogic.speed, -1);
}
else { //중앙 앞쪽 포인트
rigid.velocity = new Vector2(0, enemyLogic.speed * (-1));
}
}
}
//Enemy 스크립트 파일
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Enemy : MonoBehaviour {
public string enemyName;
public float speed;
public int health;
public float maxShotDelay;
public float curShotDelay;
public GameObject bulletObjA;
public GameObject bulletObjB;
public GameObject player;
public Sprite[] sprites;
SpriteRenderer spriteRenderer;
void Awake() {
spriteRenderer = GetComponent<SpriteRenderer>();
}
void Update(){
Fire();
Reload();
}
void Fire() {
if (curShotDelay < maxShotDelay) //장전 중이라면
return;
if (enemyName == "S") {
GameObject bullet = Instantiate(bulletObjA, transform.position, transform.rotation);
Rigidbody2D rigid = bullet.GetComponent<Rigidbody2D>();
Vector3 dirVec = player.transform.position - transform.position; //목표물로 방향 = 목표물 위치 - 자신의 위치
rigid.AddForce(dirVec.normalized * 10, ForceMode2D.Impulse);
}
else if (enemyName == "L") {
GameObject bulletR = Instantiate(bulletObjB, transform.position + Vector3.right * 0.3f, transform.rotation);
GameObject bulletL = Instantiate(bulletObjB, transform.position + Vector3.left * 0.3f, transform.rotation);
Rigidbody2D rigidR = bulletR.GetComponent<Rigidbody2D>();
Rigidbody2D rigidL = bulletL.GetComponent<Rigidbody2D>();
Vector3 dirVecR = player.transform.position - (transform.position + Vector3.right * 0.3f);
Vector3 dirVecL = player.transform.position - (transform.position + Vector3.left * 0.3f);
rigidR.AddForce(dirVecR.normalized * 10, ForceMode2D.Impulse);
rigidL.AddForce(dirVecL.normalized * 10, ForceMode2D.Impulse);
}
curShotDelay = 0;
}
void Reload() {
curShotDelay += Time.deltaTime;
}
void onHit(int dmg) {
health -= dmg;
spriteRenderer.sprite = sprites[1]; //평소 스프라이트 0, 피격시 스프라이트 1
Invoke("ReturnSprite", 0.1f);
if (health <= 0)
Destroy(gameObject);
}
void ReturnSprite() {
spriteRenderer.sprite = sprites[0];
}
void OnTriggerEnter2D(Collider2D collision) {
if (collision.gameObject.tag == "BorderBullet") //맵의 경계로 가게되면
Destroy(gameObject);
else if (collision.gameObject.tag == "PlayerBullet") { //플레이어 총알에 닿으면
Bullet bullet = collision.gameObject.GetComponent<Bullet>();
onHit(bullet.dmg);
Destroy(collision.gameObject); //플레이어 총알 삭제
}
}
}
- Vector3 Vec.normalized : 벡터가 단위 값(1)로 변환된 변수. 방향은 그대로 유지하되 크기는 1로 단위 벡터가 된다.
- Player를 GameManager에 굳이 넣어서 연결시켜준 이유는, 프리펩은 이미 Scene에 올라온 오브젝트에 접근이 불가능하기 때문이다. 따라서 GameManager를 통해서 적이 생성된 후에 플레이어를 넘겨줌으로써 해결해준다.
3. 피격 이벤트
//GameManager 스크립트 파일
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameManager : MonoBehaviour {
public GameObject[] enemyObjs;
public Transform[] spawnPoints;
public GameObject player;
public float maxSpawnDelay;
public float curSpawnDelay;
void Update() {
curSpawnDelay += Time.deltaTime;
if (curSpawnDelay > maxSpawnDelay) {
SpawnEnemy();
maxSpawnDelay = Random.Range(0.5f, 3f);
curSpawnDelay = 0;
}
}
void SpawnEnemy() {
int ranEnemy = Random.Range(0, 3);
int ranPoint = Random.Range(0, 9);
GameObject enemy = Instantiate(enemyObjs[ranEnemy], spawnPoints[ranPoint].position, spawnPoints[ranPoint].rotation);
Rigidbody2D rigid = enemy.GetComponent<Rigidbody2D>();
Enemy enemyLogic = enemy.GetComponent<Enemy>();
enemyLogic.player = player;
if (ranPoint == 5 || ranPoint == 6) { //오른쪽 포인트
enemy.transform.Rotate(Vector3.back * 90); //적 기체 스프라이트 돌리기
rigid.velocity = new Vector2(enemyLogic.speed * (-1), -1);
}
else if (ranPoint == 7 || ranPoint == 8) { //왼쪽 포인트
enemy.transform.Rotate(Vector3.back * (-90)); //적 기체 스프라이트 돌리기
rigid.velocity = new Vector2(enemyLogic.speed, -1);
}
else { //중앙 앞쪽 포인트
rigid.velocity = new Vector2(0, enemyLogic.speed * (-1));
}
}
public void RespawnPlayer() {
Invoke("RespawnPlayerExe", 2f);
}
void RespawnPlayerExe() {
player.transform.position = Vector3.down * 3.5f; //플레이어 위치 초기화
player.SetActive(true);
}
}
//Enemy 스크립트 파일
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Enemy : MonoBehaviour {
public string enemyName;
public float speed;
public int health;
public float maxShotDelay;
public float curShotDelay;
public GameObject bulletObjA;
public GameObject bulletObjB;
public GameObject player;
public Sprite[] sprites;
SpriteRenderer spriteRenderer;
void Awake() {
spriteRenderer = GetComponent<SpriteRenderer>();
}
void Update(){
Fire();
Reload();
}
void Fire() {
if (curShotDelay < maxShotDelay) //장전 중이라면
return;
if (enemyName == "S") {
GameObject bullet = Instantiate(bulletObjA, transform.position, transform.rotation);
Rigidbody2D rigid = bullet.GetComponent<Rigidbody2D>();
Vector3 dirVec = player.transform.position - transform.position; //목표물로 방향 = 목표물 위치 - 자신의 위치
rigid.AddForce(dirVec.normalized * 3, ForceMode2D.Impulse);
}
else if (enemyName == "L") {
GameObject bulletR = Instantiate(bulletObjB, transform.position + Vector3.right * 0.3f, transform.rotation);
GameObject bulletL = Instantiate(bulletObjB, transform.position + Vector3.left * 0.3f, transform.rotation);
Rigidbody2D rigidR = bulletR.GetComponent<Rigidbody2D>();
Rigidbody2D rigidL = bulletL.GetComponent<Rigidbody2D>();
Vector3 dirVecR = player.transform.position - (transform.position + Vector3.right * 0.3f);
Vector3 dirVecL = player.transform.position - (transform.position + Vector3.left * 0.3f);
rigidR.AddForce(dirVecR.normalized * 4, ForceMode2D.Impulse);
rigidL.AddForce(dirVecL.normalized * 4, ForceMode2D.Impulse);
}
curShotDelay = 0;
}
void Reload() {
curShotDelay += Time.deltaTime;
}
void onHit(int dmg) {
health -= dmg;
spriteRenderer.sprite = sprites[1]; //평소 스프라이트 0, 피격시 스프라이트 1
Invoke("ReturnSprite", 0.1f);
if (health <= 0)
Destroy(gameObject);
}
void ReturnSprite() {
spriteRenderer.sprite = sprites[0];
}
void OnTriggerEnter2D(Collider2D collision) {
if (collision.gameObject.tag == "BorderBullet") //맵의 경계로 가게되면
Destroy(gameObject);
else if (collision.gameObject.tag == "PlayerBullet") { //플레이어 총알에 닿으면
Bullet bullet = collision.gameObject.GetComponent<Bullet>();
onHit(bullet.dmg);
Destroy(collision.gameObject); //플레이어 총알 삭제
}
}
}
- 적 기체에 닿거나 적 총알에 맞게되면 Player가 비활성화되므로 GameManager를 통해서 플레이어를 복귀 시키는 함수를 만들어 실행시킨다. Invoke 함수를 통해서 2초정도의 부활 시간을 주었다.
'유니티 프로젝트 > 2D 종스크롤 슈팅' 카테고리의 다른 글
[Unity/유니티] 기초-2D 종스크롤 슈팅: 아이템과 필살기 구현하기[B32] (0) | 2022.03.04 |
---|---|
[Unity/유니티] 기초-2D 종스크롤 슈팅: UI 간단하게 완성하기[B31] (0) | 2022.03.03 |
[Unity/유니티] 기초-2D 종스크롤 슈팅: 적 비행기 만들기[B29] (0) | 2022.02.28 |
[Unity/유니티] 기초-2D 종스크롤 슈팅: 총알발사 구현하기[B28] (0) | 2022.02.27 |
[Unity/유니티] 기초-2D 종스크롤 슈팅: 플레이어 이동 구현하기[B27] (0) | 2022.02.26 |