가이드란과 비교해서 그 위해 이미지를 덮고 이미지와 텍스트를껐다켰다하며 실제와 같은지 비교하고 조정한다.
조정할 것으로는 이미지크기, 텍스트, 색상 같은 것들이 있다.
UI들을 관리해줄 빈오브젝트 생성 후 스크립트 어싸인
이런식으로 직접 할당해줄수 있지만 나중에 컴포넌트들이 많으면 관리하기가 힘들고
혹시나 나중에 디자이너들과 협업을 할때 쉽게 건들여질 수 있는 부분으로 권장하지 않는다.
따라서 초기화
이런식으로 인스펙터에서 할당하지 않아도 클릭하면 인지될 수 있도록 코드를 구현할 것이다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class BlueButton : MonoBehaviour
{
[SerializeField] public Button blueButton;
private void Start()
{
this.blueButton.onClick.AddListener(() => {
Debug.Log("Blue Button Clicked!");
});
}
}
이제 Inputfield를 만들 것인데 버튼과 마찬가지로 필요한 텍스쳐들을 찾아낸다.
칼라도 잊지말고 찾자
Allignment는 사실 크게 신경쓰지 않아도 된다.
위에 있는 것들은 버튼을 만들때 필요했던 것들 아래는 이번에 만들 인풋필드에 필요한 것들이다.
.
기존에 인풋필드에서 사용하는 폰트는 한글이 없으므로 설치후
window - textmeshpro - font asset creator
글자는 각 숫자로 정리 되어있는데 이것은 한글 범위를 찾아서 넣어줘고 제너레이트 해야 한다.
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
public class InputField : MonoBehaviour
{
[SerializeField] public TMP_InputField inputField;
void Start()
{
this.inputField.onValueChanged.AddListener((word) =>
{
Debug.LogFormat("{0}", word);
});
}
}
이제 입력을 하고 버튼을 누르면 출력되게 할 것이다.
using UnityEngine;
using UnityEngine.UI;
public class BlueButton : MonoBehaviour
{
public Button blueButton;
private ShowText showText;
void Start()
{
this.showText = GetComponent<ShowText>();
blueButton.onClick.AddListener(() =>
{
showText.ShowMessage();
});
}
}
using TMPro;
using UnityEngine;
public class ShowText : MonoBehaviour
{
public TMP_InputField inputField;
public void ShowMessage()
{
Debug.Log(inputField.text);
}
//public void SubscribeToInputFieldChange()
//{
// inputField.onValueChanged.AddListener((word) =>
// {
// });
//}
}
item 스크립트에 퍼블릭으로 string으로 선언하고 각 아이템의 이름을 직접 적어줄 것이다.
물체가 잘 내려오는지 확인
이제 애니메이션을 넣어줄것이다.
다른 오브젝트들도 똑같이 애니메이션을 만든다.
테스트
아이템 태그 부착
플레이어가 아이템을 먹어야하기에 onTriggerEnter2D를 사용할 것이다.
그런데 파워는 이미 선언되어 있고
파워 아이템을 먹으면 공격력이 증가되어야 하기에 변수를 따로 하나 더 선언
파워가 맥스 파워보다 증가되면 안되므로 조건을 걸어주고
맥스파워가 되면 보통 슈팅게임처럼 점수만 올려줄 것이다.
이제 Boom을 만들 것이다.
붐스킬 이미지를 가져오면 다른 오브젝트를 덮어버리는데
이는 order in layer로 층을 바꾸면 된다
현재 모두 0 이고 배경은 -1 이므로
배경은 -2로 붐스킬은 -1로 변경
그 후 붐스킬도 똑같이 애니메이션을 만들어 준다.
나중에 아이템 먹을 시 활성화 할것이므로 현재는 비활성화
그럼 플레이에게 따로 값을 주면된다.
플레이에게 퍼블릭으로 인스턴스를 만들어주고 어싸인
Boom을 먹으면 스킬을 활성화 하고 평상시에는 4초후 이펙트가 꺼지게 설정
적들은 배열로 관리하여 배열에서 찾아서 제거해준다.
퍼블릭으로 변경
플레이어의 파워와 맥스파워 설정
보통 슈팅게임에서 아이템을 먹으면 저장을 하고
원하는 시기에 폭탄을 쏠 수 있도록 조정해야 한다.
그러므로 폭탄 개수를 저장할 변수 선언
폭탄도 파워와 같이 한계를 정할 것이므로 maxBoom까지 두개를 만들 것이다.
이제 Boom메소드를 만들것인데
아까 구현해던
이것을 다 긁어서 붐 메소드 안에 넣어줄 것이다.
붐 메서드에 기능은 이제 따로 빼두었는데
붐도 파워처럼 먹었을때에 대한 설정을 다시 지정해준다.
초기화
붐 아이콘도 라이프 아이콘을 복사해서 앵커의 위치를 바꾸어 준다.
게임 매니저에서 라이프 아이콘을 관리했던 것 처럼 복사해서
붐으로 만든 메소드에 집어 넣는다.
플레이어에서 게임매니저를 가져오고 업데이트하기 위해 메소드를 넣어준다.
알베도의 값을 0으로 줄인다.
만들어진 아이템 프리팹화
에너미가 사라진 곳에 아이템이 생성될 것이다.
어싸인
플레이 해보면 하나에서 아이템 2개가 나오는 오류?가 생긴다.
따라서 예외처리해야하는데
코드를 잘 살펴보면 디스트로이 되기 전에 온히트가 2번이라는 것을 알 수 있다.
이 코드만 추가해주면 예외처리가 된다.
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel.Design;
using System.Net.Http.Headers;
using UnityEngine;
public class Player : MonoBehaviour
{
public bool isTouchTop;
public bool isTouchBottom;
public bool isTouchRight;
public bool isTouchLeft;
public int life;
public int score;
public int speed;
public int power;
public int boom;
public int maxBoom;
public float maxPower;
public float maxShotDelay; //실제 딜레이
public float curShorDelay; //한발 쏜 후 딜레이
public GameObject bulletObjA;
public GameObject bulletObjB;
public GameObject boomSkill;
public GameManager manager;
public bool isHit;
public bool isBoomTime;
private Animator anim;
private void Awake()
{
anim = GetComponent<Animator>();
}
void Move()
{
float h = Input.GetAxisRaw("Horizontal");
if ((isTouchRight && h == 1) || (isTouchLeft && h == -1))
h = 0;
float v = Input.GetAxisRaw("Vertical");
if ((isTouchTop && v == 1) || (isTouchBottom && v == -1))
v = 0;
Vector3 curPos = this.transform.position;
Vector3 nextPos = new Vector3(h, v, 0) * speed * Time.deltaTime;
transform.position = curPos + nextPos;
if (Input.GetButtonDown("Horizontal") ||
Input.GetButtonDown("Vertical"))
{
anim.SetInteger("Input", (int)h);
}
}
private void Update()
{
Move();
Fire();
Boom();
Reload();
}
void Fire()
{
if (!Input.GetButton("Fire1"))
return;
if (curShorDelay < maxShotDelay)
return;
switch (power)
{
case 1://Power One
GameObject bullet = Instantiate(bulletObjA, transform.position, transform.rotation);
Rigidbody2D rigid = bullet.GetComponent<Rigidbody2D>();
rigid.AddForce(Vector2.up * 10, ForceMode2D.Impulse);
break;
case 2:
GameObject bulletR = Instantiate(bulletObjA, transform.position + Vector3.right * 0.1f, transform.rotation);
GameObject bulletL = Instantiate(bulletObjA, transform.position + Vector3.left * 0.1f, transform.rotation);
Rigidbody2D rigidR = bulletR.GetComponent<Rigidbody2D>();
Rigidbody2D rigidL = bulletL.GetComponent<Rigidbody2D>();
rigidR.AddForce(Vector2.up * 10, ForceMode2D.Impulse);
rigidL.AddForce(Vector2.up * 10, ForceMode2D.Impulse);
break;
case 3:
GameObject bulletRR = Instantiate(bulletObjA, transform.position + Vector3.right * 0.3f, transform.rotation);
GameObject bulletCC = Instantiate(bulletObjB, transform.position, transform.rotation);
GameObject bulletLL = Instantiate(bulletObjA, transform.position + Vector3.left * 0.3f, transform.rotation);
Rigidbody2D rigidRR = bulletRR.GetComponent<Rigidbody2D>();
Rigidbody2D rigidCC = bulletCC.GetComponent<Rigidbody2D>();
Rigidbody2D rigidLL = bulletLL.GetComponent<Rigidbody2D>();
rigidRR.AddForce(Vector2.up * 10, ForceMode2D.Impulse);
rigidCC.AddForce(Vector2.up * 10, ForceMode2D.Impulse);
rigidLL.AddForce(Vector2.up * 10, ForceMode2D.Impulse);
break;
}
curShorDelay = 0;
}
void Reload()
{
curShorDelay += Time.deltaTime;
}
void Boom()
{
if (!Input.GetKeyDown(KeyCode.Space))
return;
if (boom == 0)
return;
boom--;
isBoomTime = true;
manager.UpdateBoomIcon(boom);
if (isBoomTime)
{
boomSkill.SetActive(true);
Invoke("OffBoomSkill", 4f);
GameObject[] enemies = GameObject.FindGameObjectsWithTag("Enemy");
for (int index = 0; index < enemies.Length; index++)
{
Enemy enemyLogic = enemies[index].GetComponent<Enemy>();
enemyLogic.OnHit(1000);
}
GameObject[] bullets = GameObject.FindGameObjectsWithTag("EnemyBullet");
for (int index = 0; index < bullets.Length; index++)
{
Destroy(bullets[index]);
}
}
}
private void OnTriggerEnter2D(Collider2D collision)
{
if(collision.gameObject.tag == "Border")
{
switch(collision.gameObject.name)
{
case "Top":
isTouchTop = true;
break;
case "Bottom":
isTouchBottom = true;
break;
case "Right":
isTouchRight = true;
break;
case "Left":
isTouchLeft = true;
break;
}
}
else if(collision.gameObject.tag == "Enemy" || collision.gameObject.tag == "EnemyBullet")
{
if (isHit)
{
return;
}
isHit = true;
life--;
manager.UpdateLifeIcon(life);
if(life == 0)
{
manager.GameOver();
}
else
{
manager.RespawnPlayer();
}
gameObject.SetActive(false);
}
else if(collision.gameObject.tag == "Item")
{
Item item = collision.gameObject.GetComponent<Item>();
switch(item.type)
{
case "Coin":
score += 1000;
break;
case "Power":
if(power == maxPower)
{
score += 500;
}
else
{
power++;
}
break;
case "Boom":
if (boom == maxBoom)
{
score += 500;
}
else
boom++;
manager.UpdateBoomIcon(boom);
break;
}
Destroy(collision.gameObject);
}
}
void OffBoomSkill()
{
boomSkill.SetActive(false);
isBoomTime = false;
}
private void OnTriggerExit2D(Collider2D collision)
{
switch (collision.gameObject.name)
{
case "Top":
isTouchTop = false;
break;
case "Bottom":
isTouchBottom = false;
break;
case "Right":
isTouchRight = false;
break;
case "Left":
isTouchLeft = false;
break;
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Bullet : MonoBehaviour
{
public int dmg;
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.gameObject.tag == "BorderBullet")
Destroy(gameObject); //모노비헤이어에 들어 있는 자체 함수 => 매개변수 오브젝트를 삭제하는 함수
}
}
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel.Design;
using UnityEngine;
public class Enemy : MonoBehaviour
{
public string enemyName;
public int enemyScore;
public float speed;
public int health;
public Sprite[] sprites;
public float maxShotDelay; //실제 딜레이
public float curShorDelay; //한발 쏜 후 딜레이
public GameObject bulletObjA;
public GameObject bulletObjB;
public GameObject itemCoin;
public GameObject itemPower;
public GameObject itemBoom;
public GameObject player;
SpriteRenderer spriteRenderer;
Rigidbody2D rigid;
private void Awake()
{
spriteRenderer = GetComponent<SpriteRenderer>();
rigid = GetComponent<Rigidbody2D>();
rigid.velocity = Vector2.down * speed;
}
private void Update()
{
Fire();
Reload();
}
void Fire()
{
if (curShorDelay < 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); // 방향 벡터를 정규화하여 힘을 가하는 부분 수정
}
curShorDelay = 0; // 발사 후 딜레이 초기화는 발사 이후에 처리되도록 이동
}
void Reload()
{
curShorDelay += Time.deltaTime;
}
public void OnHit(int dmg)
{
if (health <= 0)
return;
health -= dmg;
spriteRenderer.sprite = sprites[1]; //피격시 1번
Invoke("ReturnSprite", 0.1f);
if (health <= 0)
{
Player playerLogic = player.GetComponent<Player>();
playerLogic.score += enemyScore;
//#.Random.Ratio Item Drop
int ran = Random.Range(0, 10);
if (ran < 3)
{
Debug.Log("No Item");
}
else if (ran < 6) { //Coin 30%
Instantiate(itemCoin, transform.position, itemCoin.transform.rotation);
}else if (ran < 8) { //Power 20%
Instantiate(itemPower, transform.position, itemPower.transform.rotation);
}else if(ran < 10) { //Boom 20%
Instantiate(itemBoom, transform.position, itemBoom.transform.rotation);
}
Destroy(gameObject);
}
}
void ReturnSprite()
{
spriteRenderer.sprite = sprites[0];
}
private 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);
}
}
}
using JetBrains.Annotations;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
public class GameManager : MonoBehaviour
{
public GameObject[] enemyObjs;
public Transform[] spawnPoints;
public float maxSpawnDelay;
public float curSpawnDelay;
public GameObject player;
public Text scoreText;
public Image[] lifeImage;
public Image[] boomImage;
public GameObject gameOverSet;
private void Update()
{
curSpawnDelay += Time.deltaTime;
if (curSpawnDelay > maxSpawnDelay)
{
SpawnEnemy();
maxSpawnDelay = Random.Range(0.5f, 3f);
curSpawnDelay = 0;
}
//UI Score
Player playerLogic = player.GetComponent<Player>();
scoreText.text = string.Format("{0:n0}", playerLogic.score);
}
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); //z축으로 90도
rigid.velocity = new Vector2(enemyLogic.speed * (-1), -1);
}else if(ranPoint == 7 || ranPoint == 8)
{
enemy.transform.Rotate(Vector3.forward * 90); //z축으로 90도
rigid.velocity = new Vector2(enemyLogic.speed, -1);
}
else
{
rigid.velocity = new Vector2(0, enemyLogic.speed * (-1));
}
}
public void UpdateLifeIcon(int life)
{
//UI Init Disable
for (int index = 0; index < 3; index++)
{
lifeImage[index].color = new Color(1, 1, 1, 0);
}
//UI Life Active
for (int index = 0; index < life; index++)
{
lifeImage[index].color = new Color(1, 1, 1, 1);
}
}
public void UpdateBoomIcon(int boom)
{
//UI Init Disable
for (int index = 0; index < 3; index++)
{
boomImage[index].color = new Color(1, 1, 1, 0);
}
//UI Life Active
for (int index = 0; index < boom; index++)
{
boomImage[index].color = new Color(1, 1, 1, 1);
}
}
public void RespawnPlayer()
{
Invoke("RespawnPlayerExe", 2f);
}
private void RespawnPlayerExe()
{
player.transform.position = Vector3.down * 3.5f;
player.SetActive(true);
Player playerLogic = player.GetComponent<Player>();
playerLogic.isHit = false;
}
public void GameOver()
{
gameOverSet.SetActive(true);
}
public void GameRetry()
{
SceneManager.LoadScene(0);
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Item : MonoBehaviour
{
public string type;
private Rigidbody2D rigid;
void Start()
{
rigid = GetComponent<Rigidbody2D>();
rigid.velocity = Vector3.down * 3f; //아이템이 떨어지는 속도
}
void Update()
{
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
public float speed = 3f;
public bool isTouchTop;
public bool isTouchLeft;
public bool isTouchRight;
public bool isTouchBottom;
public float maxShortDelay = 0.1f;//실제 딜레이
public float curShortDelay;//한발 쏜 딜레이
public GameObject bulletObjA;
private Animator anim;
void Start()
{
anim = GetComponent<Animator>();
}
void Update()
{
Move();
Fire();
Reload();
}
void Move()
{
Vector3 curPos = this.transform.position;
float h = Input.GetAxisRaw("Horizontal");
if ((isTouchRight && h == 1) || (isTouchLeft && h == -1))
h = 0;
float v = Input.GetAxisRaw("Vertical");
if ((isTouchTop && v == 1) || (isTouchBottom && v == -1))
v = 0;
Vector3 nextPos = new Vector3(h, v, 0) * speed * Time.deltaTime;
this.transform.position = curPos + nextPos;
if(Input.GetButtonDown("Horizontal") || Input.GetButtonDown("Vertical"))
{
anim.SetInteger("Input", (int)h);
}
}
void Fire()
{
if (curShortDelay < maxShortDelay)
return;
if (Input.GetKey(KeyCode.Space))
{
GameObject bullet = Instantiate(bulletObjA, transform.position, transform.rotation);
Rigidbody2D rigid = bullet.GetComponent<Rigidbody2D>();
rigid.AddForce(Vector2.up * 10, ForceMode2D.Impulse);
curShortDelay = 0f;
}
}
void Reload()
{
curShortDelay += Time.deltaTime;
}
private void OnTriggerEnter2D(Collider2D collision)
{
if(collision.gameObject.tag == "Border")
{
switch (collision.gameObject.name)
{
case "Top":
isTouchTop = true;
break;
case "Bottom":
isTouchBottom = true;
break;
case "Left":
isTouchLeft = true;
break;
case "Right":
isTouchRight = true;
break;
}
}
}
private void OnTriggerExit2D(Collider2D collision)
{
switch (collision.gameObject.name)
{
case "Top":
isTouchTop = false;
break;
case "Bottom":
isTouchBottom = false;
break;
case "Left":
isTouchLeft = false;
break;
case "Right":
isTouchRight = false;
break;
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Bullet : MonoBehaviour
{
public int dmg;
private void OnTriggerEnter2D(Collider2D collision)
{
if(collision.tag == "BorderBullet")
{
Destroy(gameObject);
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Enemy : MonoBehaviour
{
public float speed;
public int health;
public Sprite[] sprites;
SpriteRenderer spriteRenderer;
Rigidbody2D rigid;
public GameObject explosionPrefab;
void Start()
{
spriteRenderer = GetComponent<SpriteRenderer>();
rigid = GetComponent<Rigidbody2D>();
rigid.velocity = Vector2.down * speed;
}
void ReturnSprite()
{
spriteRenderer.sprite = sprites[0];
}
public void OnHit(int dmg)
{
health -= dmg;
spriteRenderer.sprite = sprites[1];
Invoke("ReturnSprite", 0.1f);
if (health <= 0)
{
GameObject explosion = Instantiate(explosionPrefab, transform.position, Quaternion.identity);
Destroy(explosion, 1.0f); // 폭발 효과는 1초 후에 파괴
Destroy(gameObject); // 적도 파괴
//Destroy(gameObject, 0.2f);
}
}
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.gameObject.tag == "BorderBullet")
{
Destroy(gameObject);
}
else if (collision.gameObject.tag == "Bullet")
{
Bullet bullet = collision.gameObject.GetComponent<Bullet>();
OnHit(bullet.dmg);
Destroy(collision.gameObject);
}
}
}
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, 5);
Instantiate(enemyObjs[ranEnemy],
spawnPoints[ranPoint].position,
spawnPoints[ranPoint].rotation);
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Explosion : MonoBehaviour
{
private Animator anim;
public void OnEnable()
{
anim = GetComponent<Animator>();
StartCoroutine(CoExplosion());
}
IEnumerator CoExplosion()
{
yield return new WaitForSeconds(0.5f);
Destroy(gameObject);
}
}
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEditor.Experimental.GraphView;
using UnityEngine;
public class PlayerCtrl : MonoBehaviour
{
private Transform tr;
public float moveSpeed = 10.0f;
public float turnSpeed = 80.0f;
private Animation anim;
private readonly float initHp = 100f;
public float currentHp;
public delegate void PlayerDieHandler(); //대리자 정의
public static event PlayerDieHandler OnPlayerDie; //이벤트 변수 정의
private void Awake()
{
//제일먼저 호출되는 함수
//스크리브가 비활성화되있어도 호출되는 함수
}
private void OnEnable()
{
//두번째로 호출되는 함수
//스크립트가 활성화 될때마다 호출되는 함수
}
IEnumerator Start()
{
this.currentHp = this.initHp;
// 세번째로 호출되는 함수
//Update함수가 호출되기 전에 호출되는 함수
//코루틴으로 호출될수 있는 함수
//예)
//IEnumerator Start(){}
tr = GetComponent<Transform>();
this.anim = GetComponent<Animation>();
//이름으로 실행 하거나
this.anim.Play("Idle");
//이름으로 가져와서 플레이 하거나
//this.anim.clip = this.anim.GetClip("Idle");
//this.anim.Play();
this.turnSpeed = 0f;
yield return new WaitForSeconds(0.3f);
this.turnSpeed = 80f;
}
private void FixedUpdate()
{
//일정간격으로 호출되는 함수 (기본값은 0.02초)
//물리엔진의 계산 주기와 일치
}
void Update()
{
//프레임마다 호출되는 함수
//호출 간격이 불규칙하다
//화면의 렌더링 주기와 일치 함
float h = Input.GetAxis("Horizontal"); // -1.0 ~ 0 ~ 1
float v = Input.GetAxis("Vertical"); // -1.0 ~ 0 ~ 1
float r = Input.GetAxis("Mouse X");
//Debug.Log("h=" + h);
//Debug.Log("v=" + v);
Debug.Log("r=" + r);
//this.tr.Translate(Vector3.forward * 1 * 0.01f , Space.Self); //로컬좌표 기준으로 이동
//this.tr.Translate(Vector3.forward * 1 * Time.deltaTime, Space.World); //월드좌표 기준으로 이동
//매 프레임마다 1유닛씩 이동 => 0.02초
//this.tr.Translate(Vector3.forward * 1 * Time.deltaTime);
//매 초마다 1유닛씩 이동
//프레임 레이트가 서로다른 기기에서도 개발자가 지정한 일정한 속도로 이동하기 위함
//this.tr.Translate(Vector3.forward * v * Time.deltaTime * moveSpeed); //방향 * 속도 * 시간 => forward = (0,0,1) // v => -1~ 1 사이의 값 => v를 사용해서 앞뿐만이 아닌 뒤로도 이동가능
//전후좌우 이동방향 벡터 계산
Vector3 moveDir = (Vector3.forward * v) + (Vector3.right * h); // right = (1,0,0)
//방향 * 속도 * 시간
this.tr.Translate(moveDir.normalized * moveSpeed * Time.deltaTime);
//Vector3.up 축으로 turnSpeed만큼
this.tr.Rotate(Vector3.up * r * this.turnSpeed);
//캐릭터 애니메이션 실행
PlayerAnim(h, v);
}
private void LateUpdate()
{
//Update함수가 종료된 후 호출 되는 함수
}
private void PlayerAnim(float h, float v)
{
//키보드 입력값을 기준으로 동작할 애니메이션 실행
if (v >= 0.1f)
{
//0.25f초간 이전 애니메이션과 실행할 애니메이션을 보간
this.anim.CrossFade("RunF", 0.25f); //전진 애니메이션 실행
}
else if (v <= -0.1f)
{
this.anim.CrossFade("RunB", 0.25f);//후진
}
else if (h >= 0.1f)
{
this.anim.CrossFade("RunR", 0.25f);//오른쪽
}
else if (h <= -0.1f)
{
this.anim.CrossFade("RunL", 0.25f);//왼쪽
}
else
{
this.anim.CrossFade("Idle", 0.25f);//기본
}
}
private void OnTriggerEnter(Collider other)
{
if(this.currentHp >= 0f && other.CompareTag("Punch"))
{
this.currentHp -= 10f;
Debug.Log($"Player hp = {currentHp / initHp}");
if (this.currentHp <= 0f)
{
this.PlayerDie();
}
}
}
private void PlayerDie()
{
Debug.Log("Player Die!");
////Monster 태그를 가진 오브젝트들을 검색
//GameObject[] monsters = GameObject.FindGameObjectsWithTag("Monster");
////모든 몬스터의 OnplayerDie함수실행
//foreach(GameObject monster in monsters)
//{
// monster.SendMessage("OnPlayerDie", SendMessageOptions.RequireReceiver);
//}
PlayerCtrl.OnPlayerDie(); //ㄷ대리차 호출(이벤트 발생 Dispatch)
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BulletCtrl : MonoBehaviour
{
public float damage = 20.0f;
public float force = 1500f;
private Rigidbody rb;
void Start()
{
this.rb = this.GetComponent<Rigidbody>();
this.rb.AddForce(this.transform.forward * force);
Destroy(gameObject, 3f);
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FollowCam : MonoBehaviour
{
public Transform targetTr;
private Transform camTr;
//대상으로 부터 떨어질 거리
[Range(2.0f, 20.0f)]
public float distance = 10.0f;
//Y축으로 이동할 높이
[Range(0.0f, 10.0f)]
public float height = 2.0f;
//반응속도
public float damping = 10f;
//SmoothDamp에 사용할 속도 변수
private Vector3 velocity = Vector3.zero;
//카메라 LookAt OffSet
public float targetOffset = 2.0f;
void Start()
{
this.camTr = GetComponent<Transform>(); //Transform 객체 캐싱
}
private void LateUpdate()
{
//추적할 대상의 뒤쪽 distance만큼 이동
//높이를 height만큼 이동
Vector3 pos = this.targetTr.position +
(-targetTr.forward * distance) +
(Vector3.up * height);
//구면 선형 보간 함수를 사용해 부드럽게 위치를 변경
//시작위치, 목표 위치, 시간
//this.camTr.position = Vector3.Slerp(this.camTr.position, pos, Time.deltaTime * damping);
//시작위치, 목표위치, 현재속도, 목표 위치까지 도달할 시간
this.camTr.position = Vector3.SmoothDamp(this.camTr.position, pos, ref velocity, damping);
//Camera를 피벗 좌표를 향해 회전
this.camTr.LookAt(this.targetTr.position + (targetTr.up * targetOffset));
}
}
그런데 플레이를 하다가 한번에 두발을 맞으면 체력이 2가 줄어드는 곳을 볼 수 있는데 이것을 수정할 것이다.
bool 변수를 다시 초기화 하는 부분도 꼭 구현해야한다.
using System.Collections;
using System.Collections.Generic;
using System.Net.Http.Headers;
using UnityEngine;
public class Player : MonoBehaviour
{
public bool isTouchTop;
public bool isTouchBottom;
public bool isTouchRight;
public bool isTouchLeft;
public int life;
public int score;
public float speed;
public float power;
public float maxShotDelay; //실제 딜레이
public float curShorDelay; //한발 쏜 후 딜레이
public GameObject bulletObjA;
public GameObject bulletObjB;
public GameManager manager;
public bool isHit;
private Animator anim;
private void Awake()
{
anim = GetComponent<Animator>();
}
void Move()
{
float h = Input.GetAxisRaw("Horizontal");
if ((isTouchRight && h == 1) || (isTouchLeft && h == -1))
h = 0;
float v = Input.GetAxisRaw("Vertical");
if ((isTouchTop && v == 1) || (isTouchBottom && v == -1))
v = 0;
Vector3 curPos = this.transform.position;
Vector3 nextPos = new Vector3(h, v, 0) * speed * Time.deltaTime;
transform.position = curPos + nextPos;
if (Input.GetButtonDown("Horizontal") ||
Input.GetButtonDown("Vertical"))
{
anim.SetInteger("Input", (int)h);
}
}
private void Update()
{
Move();
Fire();
Reload();
}
void Fire()
{
if (!Input.GetButton("Fire1"))
return;
if (curShorDelay < maxShotDelay)
return;
switch (power)
{
case 1://Power One
GameObject bullet = Instantiate(bulletObjA, transform.position, transform.rotation);
Rigidbody2D rigid = bullet.GetComponent<Rigidbody2D>();
rigid.AddForce(Vector2.up * 10, ForceMode2D.Impulse);
break;
case 2:
GameObject bulletR = Instantiate(bulletObjA, transform.position + Vector3.right * 0.1f, transform.rotation);
GameObject bulletL = Instantiate(bulletObjA, transform.position + Vector3.left * 0.1f, transform.rotation);
Rigidbody2D rigidR = bulletR.GetComponent<Rigidbody2D>();
Rigidbody2D rigidL = bulletL.GetComponent<Rigidbody2D>();
rigidR.AddForce(Vector2.up * 10, ForceMode2D.Impulse);
rigidL.AddForce(Vector2.up * 10, ForceMode2D.Impulse);
break;
case 3:
GameObject bulletRR = Instantiate(bulletObjA, transform.position + Vector3.right * 0.3f, transform.rotation);
GameObject bulletCC = Instantiate(bulletObjB, transform.position, transform.rotation);
GameObject bulletLL = Instantiate(bulletObjA, transform.position + Vector3.left * 0.3f, transform.rotation);
Rigidbody2D rigidRR = bulletRR.GetComponent<Rigidbody2D>();
Rigidbody2D rigidCC = bulletCC.GetComponent<Rigidbody2D>();
Rigidbody2D rigidLL = bulletLL.GetComponent<Rigidbody2D>();
rigidRR.AddForce(Vector2.up * 10, ForceMode2D.Impulse);
rigidCC.AddForce(Vector2.up * 10, ForceMode2D.Impulse);
rigidLL.AddForce(Vector2.up * 10, ForceMode2D.Impulse);
break;
}
curShorDelay = 0;
}
void Reload()
{
curShorDelay += Time.deltaTime;
}
private void OnTriggerEnter2D(Collider2D collision)
{
if(collision.gameObject.tag == "Border")
{
switch(collision.gameObject.name)
{
case "Top":
isTouchTop = true;
break;
case "Bottom":
isTouchBottom = true;
break;
case "Right":
isTouchRight = true;
break;
case "Left":
isTouchLeft = true;
break;
}
}
else if(collision.gameObject.tag == "Enemy" || collision.gameObject.tag == "EnemyBullet")
{
if (isHit)
{
return;
}
isHit = true;
life--;
manager.UpdateLifeIcon(life);
if(life == 0)
{
manager.GameOver();
}
else
{
manager.RespawnPlayer();
}
gameObject.SetActive(false);
}
}
private void OnTriggerExit2D(Collider2D collision)
{
switch (collision.gameObject.name)
{
case "Top":
isTouchTop = false;
break;
case "Bottom":
isTouchBottom = false;
break;
case "Right":
isTouchRight = false;
break;
case "Left":
isTouchLeft = false;
break;
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Bullet : MonoBehaviour
{
public int dmg;
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.gameObject.tag == "BorderBullet")
Destroy(gameObject); //모노비헤이어에 들어 있는 자체 함수 => 매개변수 오브젝트를 삭제하는 함수
}
}
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel.Design;
using UnityEngine;
public class Enemy : MonoBehaviour
{
public string enemyName;
public int enemyScore;
public float speed;
public int health;
public Sprite[] sprites;
public float maxShotDelay; //실제 딜레이
public float curShorDelay; //한발 쏜 후 딜레이
public GameObject bulletObjA;
public GameObject bulletObjB;
public GameObject player;
SpriteRenderer spriteRenderer;
Rigidbody2D rigid;
private void Awake()
{
spriteRenderer = GetComponent<SpriteRenderer>();
rigid = GetComponent<Rigidbody2D>();
rigid.velocity = Vector2.down * speed;
}
private void Update()
{
Fire();
Reload();
}
void Fire()
{
if (curShorDelay < 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); // 방향 벡터를 정규화하여 힘을 가하는 부분 수정
}
curShorDelay = 0; // 발사 후 딜레이 초기화는 발사 이후에 처리되도록 이동
}
void Reload()
{
curShorDelay += Time.deltaTime;
}
private void OnHit(int dmg)
{
health -= dmg;
spriteRenderer.sprite = sprites[1]; //피격시 1번
Invoke("ReturnSprite", 0.1f);
if(health <= 0)
{
Player playerLogic = player.GetComponent<Player>();
playerLogic.score += enemyScore;
Destroy(gameObject);
}
}
void ReturnSprite()
{
spriteRenderer.sprite = sprites[0];
}
private 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);
}
}
}
using JetBrains.Annotations;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
public class GameManager : MonoBehaviour
{
public GameObject[] enemyObjs;
public Transform[] spawnPoints;
public float maxSpawnDelay;
public float curSpawnDelay;
public GameObject player;
public Text scoreText;
public Image[] lifeImage;
public GameObject gameOverSet;
private void Update()
{
curSpawnDelay += Time.deltaTime;
if (curSpawnDelay > maxSpawnDelay)
{
SpawnEnemy();
maxSpawnDelay = Random.Range(0.5f, 3f);
curSpawnDelay = 0;
}
//UI Score
Player playerLogic = player.GetComponent<Player>();
scoreText.text = string.Format("{0:n0}", playerLogic.score);
}
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); //z축으로 90도
rigid.velocity = new Vector2(enemyLogic.speed * (-1), -1);
}else if(ranPoint == 7 || ranPoint == 8)
{
enemy.transform.Rotate(Vector3.forward * 90); //z축으로 90도
rigid.velocity = new Vector2(enemyLogic.speed, -1);
}
else
{
rigid.velocity = new Vector2(0, enemyLogic.speed * (-1));
}
}
public void UpdateLifeIcon(int life)
{
//UI Init Disable
for (int index = 0; index < 3; index++)
{
lifeImage[index].color = new Color(1, 1, 1, 0);
}
//UI Life Active
for (int index = 0; index < life; index++)
{
lifeImage[index].color = new Color(1, 1, 1, 1);
}
}
public void RespawnPlayer()
{
Invoke("RespawnPlayerExe", 2f);
}
private void RespawnPlayerExe()
{
player.transform.position = Vector3.down * 3.5f;
player.SetActive(true);
Player playerLogic = player.GetComponent<Player>();
playerLogic.isHit = false;
}
public void GameOver()
{
gameOverSet.SetActive(true);
}
public void GameRetry()
{
SceneManager.LoadScene(0);
}
}
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEditor.Experimental.GraphView;
using UnityEngine;
public class PlayerCtrl : MonoBehaviour
{
private Transform tr;
public float moveSpeed = 10.0f;
public float turnSpeed = 80.0f;
private Animation anim;
void Awake()
{
//제일먼저 호출되는 함수
//스크리브가 비활성화되있어도 호출되는 함수
}
private void OnEnable()
{
//두번째로 호출되는 함수
//스크립트가 활성화 될때마다 호출되는 함수
}
private void Start()
{
//세번째로 호출되는 함수
//Update함수가 호출되기 전에 호출되는 함수
//코루틴으로 호출될 수 있는 함수
//예)
//IEnumerator Start(){}
tr = GetComponent<Transform>();
anim = GetComponent<Animation>();
this.anim.Play("Idle");
//this.anim.clip = this.anim.GetClip("Idle");
//anim.Play();
}
private void FixedUpdate()
{
//일정간격으로 호출되는 함수 (기본값은 0.02초)
//물리엔진의 계산 주기와 일치
}
void Update()
{
//프레임마다 호출되는 함수
//호출 간격이 불규칙하다
//화면의 렌더링 주기와 일치 함
float h = Input.GetAxis("Horizontal"); // -1.0 ~ 0 ~ 1
float v = Input.GetAxis("Vertical"); // -1.0 ~ 0 ~ 1
float r = Input.GetAxis("Mouse X");
//Debug.Log("h=" + h);
//Debug.Log("v=" + v);
Debug.Log("r=" + r);
//this.tr.Translate(Vector3.forward * 1 * 0.01f , Space.Self); //로컬좌표 기준으로 이동
//this.tr.Translate(Vector3.forward * 1 * Time.deltaTime, Space.World); //월드좌표 기준으로 이동
//매 프레임마다 1유닛씩 이동 => 0.02초
//this.tr.Translate(Vector3.forward * 1 * Time.deltaTime);
//매 초마다 1유닛씩 이동
//프레임 레이트가 서로다른 기기에서도 개발자가 지정한 일정한 속도로 이동하기 위함
//this.tr.Translate(Vector3.forward * v * Time.deltaTime * moveSpeed); //방향 * 속도 * 시간 => forward = (0,0,1) // v => -1~ 1 사이의 값 => v를 사용해서 앞뿐만이 아닌 뒤로도 이동가능
//전후좌우 이동방향 벡터 계산
Vector3 moveDir = (Vector3.forward * v) + (Vector3.right * h); // right = (1,0,0)
//방향 * 속도 * 시간
this.tr.Translate(moveDir.normalized * moveSpeed * Time.deltaTime);
//Vector3.up 축으로 turnSpeed만큼
this.tr.Rotate(Vector3.up * r * this.turnSpeed);
//캐릭터 애니메이션 실행
PlayerAnim(h, v);
}
private void LateUpdate()
{
//Update함수가 종료된 후 호출 되는 함수
}
private void PlayerAnim(float h, float v)
{
//키보드 입력값을 기준으로 동작할 애니메이션 실행
if (v >= 0.1f)
{
//0.25f초간 이전 애니메이션과 실행할 애니메이션을 보간
this.anim.CrossFade("RunF", 0.25f); //전진 애니메이션 실행
}
else if (v <= -0.1f)
{
this.anim.CrossFade("RunB", 0.25f);//후진
}
else if (h >= 0.1f)
{
this.anim.CrossFade("RunR", 0.25f);//오른쪽
}
else if (h <= -0.1f)
{
this.anim.CrossFade("RunL", 0.25f);//왼쪽
}
else
{
this.anim.CrossFade("Idle", 0.25f);//기본
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BulletCtrl : MonoBehaviour
{
public float damage = 20.0f;
public float force = 1500f;
private Rigidbody rb;
void Start()
{
this.rb = this.GetComponent<Rigidbody>();
this.rb.AddForce(this.transform.forward * force);
Destroy(gameObject, 3f);
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FollowCam : MonoBehaviour
{
public Transform targetTr;
private Transform camTr;
//대상으로 부터 떨어질 거리
[Range(2.0f, 20.0f)]
public float distance = 10.0f;
//Y축으로 이동할 높이
[Range(0.0f, 10.0f)]
public float height = 2.0f;
//반응속도
public float damping = 10f;
//SmoothDamp에 사용할 속도 변수
private Vector3 velocity = Vector3.zero;
//카메라 LookAt OffSet
public float targetOffset = 2.0f;
void Start()
{
this.camTr = GetComponent<Transform>(); //Transform 객체 캐싱
}
private void LateUpdate()
{
//추적할 대상의 뒤쪽 distance만큼 이동
//높이를 height만큼 이동
Vector3 pos = this.targetTr.position +
(-targetTr.forward * distance) +
(Vector3.up * height);
//구면 선형 보간 함수를 사용해 부드럽게 위치를 변경
//시작위치, 목표 위치, 시간
//this.camTr.position = Vector3.Slerp(this.camTr.position, pos, Time.deltaTime * damping);
//시작위치, 목표위치, 현재속도, 목표 위치까지 도달할 시간
this.camTr.position = Vector3.SmoothDamp(this.camTr.position, pos, ref velocity, damping);
//Camera를 피벗 좌표를 향해 회전
this.camTr.LookAt(this.targetTr.position + (targetTr.up * targetOffset));
}
}