string secretWord = "hangMan".ToUpper();
//C#에서는 string이 읽기 속성이기에 char[] 로 문자열을 관리해야된다.
//C#에서의 char[]과 string에 관련하여 TIL 작성하기
char[] guessWord = Enumerable.Repeat('_',secretWord.Length).ToArray(); // char[]을 '_'로 정답 글자수만큼 초기화하는 코드
int attepts = secretWord.Length;
bool wordGuessed = false;
string copySecretWord = secretWord;
for (int i = 0; i < attepts; i++)
{
//char[] -> string 변환 코드
string str = string.Concat(guessWord);
//'_'가 포함되어있으면 false , 포함되지 않으면 true
wordGuessed = !str.Contains('_');
//게임 클리어
if (wordGuessed)
{
Console.WriteLine("");
Console.WriteLine("축하합니다!! 단어 " + copySecretWord + " 를(을) 완성하셨습니다!! ");
Console.WriteLine("도전 횟수 " + i + "회에 통과하셨습니다!");
break;
}
//게임 안내
Console.WriteLine("도전 횟수 : " + (i+1) + "/" + attepts);
Console.WriteLine("[ " + str + " ]");
Console.Write("추측할 단어를 입력해 주세요 : ");
//글자 입력
string input = Console.ReadLine();
//글자 입력 체크 - 한개의 글자 체크
if(input.Length >= 2)
{
Console.WriteLine("");
Console.WriteLine("두 글자 이상이 입력되었습니다. 다시 입력해 주십시오.");
i--;
continue;
}
//글자 입력 체크 - 글자 영문 체크
else if ( !((input[0] >= 'A' && input[0] <= 'Z') || (input[0] >= 'a' && input[0] <= 'z')))
{
Console.WriteLine("");
Console.WriteLine("영어가 아닙니다. 다시 입력해 주십시오.");
i--;
continue;
}
//글자 소문자 고정
input = input.ToUpper();
//입력된 글자가 어디의 자리인지 체크
int result = secretWord.IndexOf(input);
do
{
if (result == -1)//없는 경우
{
Console.WriteLine("");
Console.WriteLine("해당 문자는 없습니다.");
break;
}
else
{
guessWord[result] = char.Parse(input);
char[] word = secretWord.ToCharArray(); //문자열을 수정 할 수 있게 char[] 로 변경
word[result] = '_'; //맞춘 글자를 '_' 처리함
secretWord = string.Concat(word); //char[]를 문자열로 다시 수정함
}
result = secretWord.IndexOf(input);
}
while (result != -1);
}
if (!wordGuessed)
{
Console.WriteLine("");
Console.WriteLine("실패하셨습니다!! 정답은 " + copySecretWord + " 입니다!! 다음기회에...");
}
5주차 숙제 게임개발
Run & Jump - 프로토타입 설명
1.마우스를 누르면 캐릭터 머리 위에 파워 게이지가 표시됨
2.마우스를 놓으면 놓은 방향으로 캐릭터가 빙글빙글 돌아가며 발판들을 넘어감
3.이미 한번 착지한 발판은 점수 x , 발판을 처음 밟을때만 점수 증가
구현 해야될것
1.각종 플레이어의 플레이를 방해할 장애물 추가 필요(화면을 날라다니는 오브젝트,발판 위의 가시 등등)
2.날라오는 블럭들이 지금 완전 랜덤 범위라서, 규격화가 필요함 ( 블럭이 겹쳐서 나오면 캐릭터가 피할 곳이 없음
버그
1.자기 발 밑에 바닥이 있는 상태로 아래를 향해 발사하면 캐릭터 착지하지 못한 판정이 되서 조작이 불가함
2.재시작(Scene 재로드)를 하면 GameManager에 있는 오브젝트들이 Mssing되어버림
싱글 톤 상태에서 Don'tDestroty를 했는데 Text 파일들이 Missing 됨
*Collider2D의 한 면만 충돌판정을 받게 하고 싶을때
//Blcok Class
private void OnCollisionEnter2D(Collision2D collision)
{
//플레이어한테 점수 부여가 안되있고 , 콜리더가 Player 태그일때
if (!isScore && collision.gameObject.CompareTag("Player"))
{
foreach (ContactPoint2D contact in collision.contacts)
{
if (contact.point.y > transform.position.y + 0.3f)
{
GameManager.Instance.AddScore(score);
isScore = true;
}
}
}
}
ContactPoint2D: 충돌 지점에 대한 정보를 나타내는 구조체로, 충돌한 두 물체의 접점 좌표, 충돌 방향(normal), 충돌 지점의 상대 속도 등을 포함합니다.
collision.contacts: 충돌이 발생했을 때, 해당 충돌에 관련된 모든 접점을 포함하는 배열입니다. 이 배열은 충돌이 발생한 각 접점에 대해 ContactPoint2D 객체를 담고 있습니다.
이 조건은 충돌 지점(Block의 윗면 = transform.positon.y +0.3f)의 y 좌표가 현재 객체(Player)의 y 위치보다 0.3 단위 이상 위에 있을 때만 참이 됩니다. 이 코드는 플레이어가 적을 위에서 밟았을 때 점수를 주는 식으로 사용할 수 있다.
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Advertisements;
using UnityEngine.SceneManagement;
public class RewardedAdsButton : MonoBehaviour, IUnityAdsLoadListener, IUnityAdsShowListener
{
//[SerializeField] Button _showAdButton; //버튼 오브젝트에 적용시킬거면 여기에 넣어 쓰면됨
//나는 글자를 버튼기능처럼 쓰려고 글자에 button 컴포넌트 넣고 주석처리함
[SerializeField] string _androidAdUnitId = "Rewarded_Android";
[SerializeField] string _iOSAdUnitId = "Rewarded_iOS";
string _adUnitId = null; // This will remain null for unsupported platforms
void Awake()
{
// Get the Ad Unit ID for the current platform:
#if UNITY_IOS
_adUnitId = _iOSAdUnitId;
#elif UNITY_ANDROID
_adUnitId = _androidAdUnitId;
#elif UNITY_EDITOR
_adUnitId = _androidAdUnitId;
#endif
// Disable the button until the ad is ready to show:
//_showAdButton.interactable = false;
}
// Call this public method when you want to get an ad ready to show.
public void LoadAd()
{
// IMPORTANT! Only load content AFTER initialization (in this example, initialization is handled in a different script).
Debug.Log("Loading Ad: " + _adUnitId);
Advertisement.Load(_adUnitId, this);
}
// If the ad successfully loads, add a listener to the button and enable it:
public void OnUnityAdsAdLoaded(string adUnitId)
{
Debug.Log("Ad Loaded: " + adUnitId);
if (adUnitId.Equals(_adUnitId))
{
// Configure the button to call the ShowAd() method when clicked:
//_showAdButton.onClick.AddListener(ShowAd);
// Enable the button for users to click:
//_showAdButton.interactable = true;
}
}
// Implement a method to execute when the user clicks the button:
public void ShowAd()
{
// Disable the button:
//_showAdButton.interactable = false;
// Then show the ad:
Advertisement.Show(_adUnitId, this);
}
// Implement the Show Listener OnUnityAdsShowComplete callback method to determine if the user gets a reward:
public void OnUnityAdsShowComplete(string adUnitId, UnityAdsShowCompletionState showCompletionState)
{
if (adUnitId.Equals(_adUnitId) && showCompletionState.Equals(UnityAdsShowCompletionState.COMPLETED))
{
Debug.Log("Unity Ads Rewarded Ad Completed");
// Grant a reward.
LoadAd(); // 광고 불러오기
SceneManager.LoadScene("MainScene"); //광고 다 보면 메인 씬으로 이동하기
}
}
// Implement Load and Show Listener error callbacks:
public void OnUnityAdsFailedToLoad(string adUnitId, UnityAdsLoadError error, string message)
{
Debug.Log($"Error loading Ad Unit {adUnitId}: {error.ToString()} - {message}");
// Use the error details to determine whether to try to load another ad.
}
public void OnUnityAdsShowFailure(string adUnitId, UnityAdsShowError error, string message)
{
Debug.Log($"Error showing Ad Unit {adUnitId}: {error.ToString()} - {message}");
// Use the error details to determine whether to try to load another ad.
}
public void OnUnityAdsShowStart(string adUnitId) { }
public void OnUnityAdsShowClick(string adUnitId) { }
void OnDestroy()
{
// Clean up the button listeners:
//_showAdButton.onClick.RemoveAllListeners();
}
}
4.광고 추가하고 Build 오류 대처법
강의를 보고 광고를 추가 했을때 Build가 되지않아서 계속 터졌었다.
원인은 Build 시에 resolving android dependencies 가 자꾸 멈춰버리는 현상이 있었다.
해당 코드는 C#의 Linq 라이브러리의 OrderBy(오름차순 정렬할 매개변수) 메서드 이다.
OrderBy는 복합 정렬을 기반으로 만들어진 정렬 알고리즘이다.
arr.OrderBy(x => Random.Range(0f, 4f)) 메서드를 사용하면 각 요소에 대해 Random.Range(0f, 4f)가 호출되면서 그 결과값을 기준으로 정렬이 진행됩니다. 이때 Random.Range()가 각 요소마다 다른 값을 반환하여 랜덤으로 정렬 하게 됩니다.
정렬한 arr를 Toarray() 함수를 이용하여 배열로 만들고 초기화 합니다.
구체적으로 설명하자면:
OrderBy는 배열의 각 요소에 대해람다 식 x => Random.Range(0f, 7f)를 실행하여 반환된 값을 기준으로 정렬합니다. 즉 , Random.Range(0f, 7f)는 호출될 때마다 0과 7 사이의 난수를 반환하므로, 배열의 각 요소에 대한 정렬 기준이 모두 다릅니다.
그러나 이 방법은 OrderBy가 Random.Range를 각 요소마다 몇 번 호출할지 제어할 수 없기 때문에, 성능이 중요한 경우 다른 방식의 섞기 알고리즘(Fisher-Yates shuffle)을 사용하는 것이 더 좋다.
나중에 Fisher-Yates shuffle를 공부를 해봐야겠다.
p.s 람다식이란 이름없는 함수로 간단하게 함수를 변수로 넣을때 사용된다. 하지만 이름이 없기에 재사용 할 수는 없으므로, 재사용 예정이면 따로 함수를 만들어 써야된다.
Assset에 있는 Prefeb을 월드에 올려놓고 테스트 및 수정시 변경하는 방법이 Override를 이용해서 Asset에 등록된 Prefeb의 내용을 현재 월드에서 변경한 내용으로 덮어 쓸 수 있다.
2.Rigidbody와 Collider
Rigidbody는GameObject가 물리 제어로 동작하게 합니다. 리지드바디는 힘과 토크를 받아 오브젝트가 사실적으로 움직이도록 해줍니다. 리지드바디가 포함된 모든 게임 오브젝트는 중력의 영향을 받아야 하며 스크립팅을 통해 가해진 힘으로 움직이거나 NVIDIA PhysX 물리 엔진을 통해 다른 오브젝트와 상호 작용해야 합니다.- Unity 메뉴얼 출처
콜라이더(Collider)컴포넌트는 물리 충돌 처리를 위한 오브젝트의 형태를 정의합니다. 콜라이더는 보이지 않는 요소이므로 오브젝트의 메시와 정확히 동일한 모양일 필요는 없으며, 실제로는 게임플레이 시에는 대략적인 근사치로도 크게 구분되지 않으며 더 효율적입니다. - - Unity 메뉴얼 출처
정리 : Rigidbody 컴포넌트는 GameObject에 물리를 적용 시킨다.
Collider는 물리충돌 처리의 유무 및 충돌처리의 범위를 제어하는데 사용하는 컴포넌트이다.
*충돌 시키고 싶은 오브젝트는 전부 Rigidbody 가 필요하고 Collider는 충돌시 특정코드를 동작 시키는 곳에만 필요하다.
3.Rigidbody 컴포넌트의 물리엔진 사용 X
Kinematic: 충돌시 특정 동작을 하고싶지만 물리현상을 적용시키지 않을때 사용된다. 하지만 옵션을 키면 물리영향을 빋지 않기에 OnTrigger 함수를 사용하여 코드를 작성하여아한다. (Collider의 is Trigger를 체크해야만 Kinematic에서 충돌처리가 작동한다)
4.UnityPackage 파일을 Assets - Resources에 Import 시키고 싶을때
디자이너나 Assest Store에서 받은 Package 파일을 드래그 앤 드랍으로 쉽게 Import 할 수 있다.
★★★ 5.RectTransform의 Anchor,Pivot (매우 중요 :: UI 위치 및 크기 설정에 필수로 들어가는 내용)
Canvas 오브젝트는 화면 해상도에 따라 크기가 조정된다. 간단히 정리하면 이미지는 Anchor를 기준으로 Pivot이 결정된다.
600 * 800 해상도에 좌측,상단으로부터 100씩 거리가 떨어져있는 이미지를 800*600 해상도로 변경해도 위치나 크기가 변경되지 않는다.
//화면 좌표를 게임 월드 내의 실제 위치로 변환
//매개변수로 현재 마우스 위치 좌표값을 주면 화면좌표 -> 월드좌표로 전환해주는 동작을 한다.
Vector2 mousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
transform.position = mousePos; ;
해당 메서드는 메인카메라에 포함되어있는 기능이고 Camera.main.ScreenToWorldPoint(구하고싶은 월드좌표)이며
화면에 있는 좌표를 Unity 속 월드 좌표로 바꿔주는 기능이다.
즉, 이 코드를 통해 현재 화면 위에있는 마우스 위치를 게임내 월드좌표로 변환하여 오브젝트를 마우스에 따라디니게 할수 있다.
p.s
//ScreenToViewPoint
//2D화면 좌표를 View포트 좌표로 변환하는기능 , View 포트는 우리가 실제로 보는 화면(카메라)화면을 나타냄
//view 포트에 대한 설명 TIL로 정리할것 -> 컴퓨터 그래픽스 내용 복습 필요
추가 내용으로 ViewPort라는 것이있는데 스크린좌표(화면)을 정규화(Normalize)한 좌표계이다.