[iOS] Xcode objective-c 디버그 방법 (브레이크 포인트 걸리지 않는 경우)

[iOS] Xcode objective-c 디버그 방법 (브레이크 포인트 걸리지 않는 경우)

맥에 아이폰을 연결하여 Xcode 에서 프로젝트 디버그를 시도했을 때, Xcode 에 걸어놓은 디버그용 브레이크 포인트에 걸리지 않는 경우.

Edit Scheme 메뉴에서 Build Configuration 값을 Debug 로 변경하고, [Debug executable] 체크박스를 체크하면 앱이 디버그 모드로 실행되어 브레이크 포인트에 걸린다.

1. Xcode 상단의 [프로젝트명] 클릭한다. (Run 아이콘과 Stop 아이콘 우측에 위치함)

2. [Edit Scheme…] 클릭한다.

 

3. 좌측의 [Run] 항목 선택 – 우측 내용의 Build Configuration 콤보박스 값을 [Debug] 로 변경한다.

이어서 [Debug executable] 체크박스를 체크하면 된다.

 

이후 만약 Could not launch “ProjectName” 오류가 발생한다면 Debug executable 체크박스를 해제하도록 한다.

관련내용은 https://blog.naver.com/bb_/221644098450 주소에 포스팅해두었다.

ex) Project has denied the launch request. Internal launch error: process launch failed: failed to get the task for process 803 ​

[iOS] Xcode objective-c NSLog 콘솔에 찍히지 않을 때 / NSLog 출력되지 않는 경우

[iOS] Xcode objective-c NSLog 콘솔에 찍히지 않을 때 / NSLog 출력되지 않는 경우 

NSLog 내용이 콘솔에 찍히지 않을 때 / NSLog 출력되지 않는 경우 Edit Scheme 메뉴에서 Build Configuration 값을 Debug 로 변경하면 값이 표시된다.

1. Xcode 상단의 [프로젝트명] 클릭한다. (Run 아이콘과 Stop 아이콘 우측에 위치함)

2. [Edit Scheme…] 클릭한다.

 

3. 좌측의 [Run] 항목 선택 – 우측 내용의 Build Configuration 콤보박스 값을 [Debug] 로 변경한다.


참고로 NSLog는 아래와 같이 사용한다.

ex 1)

NSLog(@”문자열”);

ex 2)

NSString *strTemp = @”문자열”;

NSLog(@”값 : %@”, strTemp);

[Unity] Unity 기초강의 내용 정리 (3-10강 ~ 3-11강)

[Unity] Unity 기초강의 내용 정리 (3-10강 ~ 3-11강)

educast 나동빈 님의 <Mobile Defence Game 제작으로 배우는 Unity 기초> 강의를 듣고 내용 정리.

———-

3-10. Button Practice

PlayerPrefs[플레이어 프립스] 기능 배우기 (게임 세이브 데이터 저장/로드 기능)

1. 좌측 하이어라키 뷰에 캔버스를 생성

Render Mode : Screen Space – Camera

카메라는 메인카메라 선택

2. 텍스트를 하나 만들고 Anchors 중앙으로 설정 (Alt 키 누르고 중앙 클릭)

이름을 Main Text 로 지정

크기 : 800 x 200

글자 중앙 정렬

Vertical OverFflow : overflow

Text 내용 : 현재 레벨은?

폰트 사이즈 80

3. 캔버스 안에 버튼을 생성

크기 : 600 x 200

색상을 빨간색으로 수정

Text 내용 : Level Up

폰트 사이즈 80

글자 중앙 정렬

버튼을 좌측 상단으로 이동시키기

4. 버튼을 복사해서 4개로 만든다.

버튼을 좌측 상단부터 배치한다.

(북서) Save

(북동) Level Up

(남서) Saved Data Reset

(남동) Load

버튼 객체명과 Text 내용을 동일하게 변경한다.

5. Scripts 폴더를 만들고 PlayerPrefTest 라는 이름의 C# 스크립트 생성

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

using UnityEngine.UI;

public class PlayerPrefTest : MonoBehaviour {

    public int level;

   

 void Start () {

        level = 0; 

 }

 

 void Update () {

  

 }

    public void LevelUp() {

        // using UnityEngine.UI; 임포트 해야 GetComponent<Text>() 사용 가능

        level += 1;

        gameObject.GetComponent<Text>().text = “현재 레벨은” + level + “입니다.”;

    }

    public void Save() {

    }

    public void Load() {

    }

    public void ResetAll() {

    }

}

6. 각 버튼에 해당하는 함수를 매핑한다.

좌측 하이어라키 뷰에서 버튼을 선택하고 우측 인스펙터 뷰 OnClick 항목 하단 [+] 버튼을 클릭.

오브젝트에 Main Text를 드래그앤드랍해서 넣고 Function 은 각 버튼에 맞게 선택해주면 됨.

ex) Saved Data Reset 버튼은 PlayerPrefTest – ResetAll()

7. 저장

PlayerPrefs.Set자료형(문자열키값, 저장하려는값)

ex 1) PlayerPrefs.SetInt(“내마음의비밀번호”, 486);

ex 2) PlayerPrefs.SetString(“내마음의비밀번호”, 486);

ex 3) PlayerPrefs.SetFloat(“내마음의비밀번호”, 4.86f);

PlayerPrefs.GetInt(문자열키값, 기본값);

ex 1) PlayerPrefs.GetInt(“내마음의비밀번호”, 0);

플레이어 프립스는 보안성이 높지는 않음.

보통 자동 로그인을 위한 아이디 등을 저장함.

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

using UnityEngine.UI;

public class PlayerPrefTest : MonoBehaviour {

    public int level;

   

 void Start () {

        level = 0; 

 }

 

 void Update () {

  

 }

    public void LevelUp() {

        // using UnityEngine.UI; 임포트 해야 GetComponent<Text>() 사용 가능

        level += 1;

        gameObject.GetComponent<Text>().text = “현재 레벨은 ” + level + “입니다.”;

    }

    public void Save() {

        PlayerPrefs.SetInt(“nowLevel”, level);

    }

    public void Load() {

        level = PlayerPrefs.GetInt(“nowLevel”, 0);

        gameObject.GetComponent<Text>().text = “현재 레벨은 ” + level + “입니다.”;

    }

    public void ResetAll() {

        // PlayerPrefs 에 있는 모든 데이터 삭제

        PlayerPrefs.DeleteAll();

    }

}

———-

3-11. Interaction Component – Input Field

1. 좌측 하이어라키 뷰에 캔버스를 생성

Render Mode : Screen Space – Camera

카메라는 메인카메라 선택

2. 캔버스 안에 인풋필드 만들기

크기 : 600 x 200

Anchors 중앙으로 설정 (Alt 키 누르고 중앙 클릭)

폰트사이즈 : 80

가운데 정렬

플레이스 홀더 : 플레이어에게 어떤 값을 넣으라고 알려주는 지시자 역할을 함. [힌트]라고도 불림.

Placeholder 텍스트 : 아이디를 입력해주세요.

3. 캔버스 안에 텍스트를 만든다.

크기 : 600 x 200

인풋필드 아래에 위치시킨다.

(겹치는 것이 아니라 아래 위치시키기)

4. Scripts 폴더 안에 InputCheckTest 라는 이름의 C# 스크립트 생성

해당 스크립트를 텍스트 오브젝트에 드래그앤드랍하여 Add Component 한다.

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

using UnityEngine.UI;

public class InputCheckTest : MonoBehaviour {

    public InputField idInputField;

   

    void Start () {

  

 }

 

 

 void Update () {

  

 }

    public void InputCheck() {

        if (idInputField.text.Length < 6) {

            gameObject.GetComponent<Text>().text = “아이디는 최소한 6자 이상 입력해주세요.”;

        } else {

            gameObject.GetComponent<Text>().text = “아이디의 길이가 적절합니다.”;

        }

    }

}

5. 메인카메라 배경색을 하얀색으로 변경

6. InputField 의 On Value Changed 에 Text 객체를 드래그앤드랍해서 매핑하자.

Text 에 드래그앤드랍 또는 Add Component 로 InputCheckTest 스크립트를 추가하자.

7. Text 선택하고 우측 하이어라키 뷰에서 InputField 값 채워준다.

하이어라키 뷰의 InputField 를 드래그앤드랍하면 된다.

On Value Changed : 인풋필드의 입력값이 바뀌었을 때

On End Edit : 텍스트 입력을 마치고 엔터키를 눌렀을 때 실행

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

using UnityEngine.UI;

public class InputCheckTest : MonoBehaviour {

    public InputField idInputField;

   

    void Start () {

  

 }

 

 

 void Update () {

  

 }

    // On Value Changed : 인풋필드의 입력값이 바뀌었을 때

    public void InputCheck() {

        if (idInputField.text.Length < 6) {

            gameObject.GetComponent<Text>().text = “아이디는 최소한 6자 이상 입력해주세요.”;

        } else {

            gameObject.GetComponent<Text>().text = “아이디의 길이가 적절합니다.”;

        }

    }

    // On End Edit : 텍스트 입력을 마치고 엔터키를 눌렀을 때 실행

    public void IdCheck() {

        if (idInputField.text == “handsome”) {

            gameObject.GetComponent<Text>().text = “로그인 성공!”;

        }

    }

}

[Xcode] 파일이 존재하는데도 file not found 오류 발생 시

[Xcode] 파일이 존재하는데도 file not found 오류 발생 시

파일이 분명히 올바른 위치에 존재하는데도 Xcode 에디터 상에서 file not found 오류가 발생하는 경우. (검색어 : xcode file not found but it’s there)

⌘(command) + alt + shift + k 키를 누르면 프로젝트가 clean 이 되면서 file not found 오류가 사라진다.

참고사이트 : https://stackoverflow.com/questions/19447860/xcode-file-not-found

[IOS] objective-c 아이폰 디바이스 토큰(device notification token) 가져오기

[IOS] objective-c 아이폰 디바이스 토큰(device notification token) 가져오기

IOS 13 미만에서는 device notification token 을 가져올 경우 아래와 같은 형태였다.

<124686a5 556a72ca d808f572 00c323b9 3eff9285 92445590 3225757d b83997ba>

여기서 특수문자 <, >, 그리고 띄어쓰기를 제거해서 사용하면 됐다.

IOS 13 이상에서는 device notification token 을 가져오면 아래와 같은 형태로 나온다.
{ length = 32, bytes = 0xd3d997af 967d1f43 b405374a 13394d2f … 28f10282 14af515f }

IOS 13 이상에서 제대로 된 device notification token 문자열을 가져오려면 NSData 타입의 deviceToken 변수로 NSString 을 얻어내야 한다. 코드는 다음과 같다.

-(NSString *)stringFromDeviceToken:(NSData *)deviceToken {

    NSUInteger length = deviceToken.length;

    if (length == 0) {

        return nil;

    }

    const unsigned char *buffer = deviceToken.bytes;

    NSMutableString *hexString  = [NSMutableString stringWithCapacity:(length * 2)];

    for (int i = 0; i < length; ++i) {

        [hexString appendFormat:@”%02x”, buffer[i]];

    }

    return [hexString copy];

}

실제 코드 수정은 기존 코드를 살리는 방식으로 했다.

(1) 기존 코드로 디바이스 토큰을 가져오되 (2) 가져온 디바이스 토큰이 length 라는 문자열을 포함할 경우 stringFromDeviceToken 메서드를 사용하도록 수정했다. 코드는 다음과 같다.

// bb_ 200527 ios13 이상에서 디바이스 토큰 가져오지 못하는 오류 수정

#define contains(str1, str2) ([str1 rangeOfString: str2].location != NSNotFound)

(중략)

    // bb_ 200527 ios13 이상에서 디바이스 토큰 가져오지 못하는 오류 수정

    // ios13 미만 : <124686a5 556a72ca d808f572 00c323b9 3eff9285 92445590 3225757d b83997ba>

    // ios13 이상 : { length = 32, bytes = 0xd3d997af 967d1f43 b405374a 13394d2f … 28f10282 14af515f }

    if (tokenHex != nil && contains(tokenHex, @”length”)) {

        NSString *ios13deviceToken = [self stringFromDeviceToken:deviceToken];

        NSLog(@”ios13deviceToken = %@”, ios13deviceToken);

        tokenHex = [ios13deviceToken mutableCopy];

       

        // 꺽쇠 제거 및 공백 제거

        if (tokenHex != nil) {

            [tokenHex replaceOccurrencesOfString:@”<” withString:@”” options:0 range:NSMakeRange(0, [tokenHex length])];

            [tokenHex replaceOccurrencesOfString:@”>” withString:@”” options:0 range:NSMakeRange(0, [tokenHex length])];

            [tokenHex replaceOccurrencesOfString:@” ” withString:@”” options:0 range:NSMakeRange(0, [tokenHex length])];

        }

    }

참고사이트 : https://effectivecode.tistory.com/1211

[IOS] objective-c NSString indexOf

[IOS] objective-c NSString indexOf

objective-c 에서 NSString 의 문자열 포함관계(contains) 확인하는 방법

#define contains(str1, str2) ([str1 rangeOfString: str2].location != NSNotFound)

(중략)

// using

NSString a = @”PUC MINAS – BRAZIL”;
NSString b = @”BRAZIL”;

if (contains(a,b)) {

    // 내용

}

출처 : https://stackoverflow.com/questions/256460/nsstring-indexof-in-objective-c

아래처럼 포함관계를 판단해도 된다.

NSString* str1 = @”Hello World!”;

NSRange range1 = [str1 rangeOfString:@”World”];

NSUInteger foundLen = range1.length;

if ((int)foundLen > 0) {

    // 내용

}

포함관계를 판단하고 싶은게 아니라 정확한 위치를 얻고 싶다면(indexOf), 아래처럼 쓴다.

NSString* str1 = @”Hello World!”;

NSRange range1 = [str1 rangeOfString:@”World”];

NSUInteger idx = range1.location;

if ((int)idx > –1) {

    // 내용

}

[Unity] Unity 기초강의 내용 정리 (3-6강 ~ 3-9강)

[Unity] Unity 기초강의 내용 정리 (3-6강 ~ 3-9강)

educast 나동빈 님의 <Mobile Defence Game 제작으로 배우는 Unity 기초> 강의를 듣고 내용 정리.

———-

3-6. Interaction Component – How to make Button

(1) 하이어라키 뷰에서 UI – Canvas 로 캔버스 만들기

(2) 캔버스 안에 UI – Button 만들기 (이름 : Button)

Making a Button

1. Hierarchy View – 우클릭 – UI – Button

(Image + Button) Component + 자식으로 Text가 존재.

2. Hierarchy View – 우클릭 – UI – Image

Image Component 만 생김. 이후 Button Component 추가. Image 를 Button 처럼 사용.

3. Hierarchy View – 우클릭 – UI – Text

Text Component 만 생김. 이후 Button Component 추가. Text 를 Button 처럼 사용.

Normal Color : 일반 색상

Highlighted Color : 마우스 호버 시 색상

* 오래된 유니티 버그가 있음. 버튼을 마구 클릭하다 보면 마우스 호버 하지 않아도 하이라이티드 색상이 남아있음.

Disabled Color : 버튼을 비활성화 했을 때 색상 (Interactable 체크박스 해제 시 색상)

<버튼 비활성화하기 스크립트 예제>

(1) 프로젝트 뷰에 ButtonDisabledTest 라는 이름의 C# 스크립트 생성

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

using UnityEngine.UI;

public class ButtonDisabledTest : MonoBehaviour {

   

 void Start () {

  // using UnityEngine.UI; 코드 필요

        GetComponent<Button>().interactable = false;

    }

 

 void Update () {

  

 }

}

(2) 하이어라키 뷰의 Button 에 드래그앤 드랍으로 ButtonDisabledTest 컴포넌트를 add 처리

OnClick 의 과정

0. OnClick 아래의 + 버튼

1. 클릭 동작을 어떤 오브젝트에 연결할지 결정 (Monster, BlueThing, GameObject …)

2. 오브젝트의 어떤 컴포넌트에 접근할지 결정 (Sprite Renderer, ButtonTest, Transform …)

3. 해당 컴포넌트의 어떠한 함수에 접근할지 결정 (Sprite 등)

4. 그 함수의 매개변수를(필요하다면) 설정 (monster2 Sprite)

(1) 하이어라키 뷰에서 마우스 우클릭 – 2D Sprite – Sprite 클릭해서 스프라이트 오브젝트 생성

(2) 이름을 Blue Thing 으로 변경

(3) 프로젝트 뷰의 Blue_button 이미지 파일을 인스펙터 뷰의 Sprite 항목에 드래그앤드랍하여 Blue Thing의 모양을 파란색 버튼 모양으로 변경

(4) 하이어라키 뷰에서 버튼을 선택하고, 인스펙터 뷰의 On Click() 아래의 + 버튼 클릭

(5) 인스펙터 뷰의 On Click() 항목 내에 있는 None(Object) 부분에 Blue Thing 을 드래그앤드랍하기

(6) 인스펙터 뷰의 On Click() 항목 내에 있는 No Function 을 클릭하고 Sprite Renderer – Sprite sprite 선택

(7) None (Sprite) 부분에 몬스터 스프라이트를 드래그앤드랍하기

(8) 게임 실행해서 버튼을 클릭하면, 기존 Blue Thing 의 모양이 몬스터로 바뀌는 것을 확인 가능

———-

3-7. Interaction Component – Button & Script

(1) 하이어라키 뷰에서 UI – Canvas 로 캔버스 만들기

(2) 캔버스 안에 UI – Button 만들기 (이름 : Button)

(3) 인스펙터 뷰의 Source Image 에 Red_button 을 드래그앤드랍해서 이미지 적용하기

(4) 앵커 프리셋을 가운데로 설정 (alt 키 누르고 클릭)

(5) 프로젝트 뷰에 ButtonTest 라는 이름의 C# 스크립트 생성

(6) Sprite 폴더의 몬스터를 씬 뷰에 드래그앤드랍하여 Monster_1 오브젝트 생성

(7) 하이어라키 뷰의 몬스터 오브젝트에 ButtonTest 드래그앤드랍하여 스크립트 부여

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

public class ButtonTest : MonoBehaviour {

 

 void Start () {

  

 }

 

 void Update () {

  

 }

    public void Fury() {

        Debug.Log(“Fury!”);

    }

}

(8) 하이어라키 뷰에서 버튼 클릭하고 우측 인스펙터 뷰에서 On Click() 아래의 + 버튼 클릭

(9) None (Object) 부분에 몬스터를 드래그앤드랍

(10) No Function 클릭해서 ButtonTest() – Fury() 선택

=> 이제 버튼을 클릭하면 콘솔에 “Fury!” 메시지 출력

(11) 다시 ButtonTest 파일 내용 수정

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

public class ButtonTest : MonoBehaviour {

 

 void Start () {

  

 }

 

 void Update () {

  

 }

    public void Fury() {

        Debug.Log(“Fury!”);

    }

    public void ChangeColor() {

        GetComponent<SpriteRenderer>().color = Color.red;

    }

}

(12) 하이어라키 뷰에서 버튼 클릭하고 우측 인스펙터 뷰에서 On Click() 아래의 우측 콤보박스 클릭해서 ButtonTest() – ChangeColor() 선택

=> 이제 버튼을 클릭하면 몬스터가 빨간색으로 변함

혹은 아래와 같이 코드를 짜면, 특정 오브젝트(예를 들어 몬스터 오브젝트)를 쉽게 조작할 수 있음.

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

public class ButtonTest : MonoBehaviour {

    // 다른 오브젝트에 접근할 수 있게 변수 설정. 인스펙터 뷰에서 몬스터 오브젝트를 넣어주면 됨.

    public GameObject monster = null;

   

 void Start () {

  

 }

 

 void Update () {

  

 }

    public void Fury() {

        Debug.Log(“Fury!”);

    }

    public void ChangeColor() {

        GetComponent<SpriteRenderer>().color = Color.red;

    }

}

———-

3-8. Interaction Component – Button & Layer

(1) 캔버스를 생성

(2) 렌더 모드를 카메라 모드로 바꾸고, 카메라를 메인 카메라로 설정해서 영역이 겹치도록 하자.

(3) UI – Image 를 만들고 Red_button 이미지를 부여. Add Component 로 Button 을 추가

(4) UI – Image 를 만들고 Blue_button 이미지를 부여. Add Component 로 Button 을 추가

(5) 프로젝트 뷰의 Red_button, Blue_button 을 각각 선택하고 우측 인스펙터 뷰의 Sprite Editor 를 눌러서 9등분을 잘해주자.

그림을 확대했을 때 중간 부분만 확대되고 상하좌우 테두리의 크기는 얇게 유지하도록 하려면 이러한 Sprite Editor 작업이 필요하다.

(6) 버튼 2개를 겹쳐보면, 겹쳐진 부분은 앞에 있는 버튼만 클릭 가능하다.

* 보통 하이어라키 뷰 상에서 위쪽에 위치한 오브젝트가, 씬 뷰에서는 아래쪽에 위치하게 된다. 먼저 출력하기 때문.

(7) 블루 버튼 오브젝트를 선택하고, Reycast Target 을 체크해제하면 광선의 영향을 받지 않는다.

다시 말해서 UI 상 겹치게 되어도, 블루 버튼 뒤쪽이 클릭 가능해진다.

———-

3-9. Button Practice – Scene Management

게임은 여러 씬으로 구성되어 있음.

시작화면 – 게임화면 – 스테이지별 게임화면 – 엔딩화면 등

(1) Example_Scenes.unitypackage 패키지 파일을 다운로드

(2) 해당 패키지 파일을 프로젝트 뷰로 드래그앤드랍 – Import 버튼 클릭

(3) 씬 3개가 추가된 것을 볼 수 있음.

(4) 하이어라키 뷰에서 마우스우클릭 – UI – Button 을 이용하여 Button1, Button2, Button3 를 생성.

참고로 Button 1~3 은 Canvas 오브젝트의 자식 오브젝트여야 한다.

(5) Canvas 의 Render Mode 를 Screen Space – Camera로 설정,

Render Camera를 Main Camera 로 설정.

(6) 버튼 크기를 모두 600 x 200 으로 수정

(7) 버튼 내의 폰트 크기를 모두 100 으로 수정 (Button 각각 자식 오브젝트로 Text 가 있을 것임)

(8) 버튼의 텍스트 내용을 각각 Scene 1, Scene 2, Scene 3 으로 변경

(9) SceneController 라는 이름의 C# 스크립트 생성

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

using UnityEngine.SceneManagement;

public class SceneController : MonoBehaviour {

   

 void Start () {

  

 }

 

 void Update () {

  

 }

    public void MoveScene(string targetScene) {

        SceneManager.LoadScene(targetScene);

    }

}

(10) 빈 오브젝트를 생성 후 SceneChangeObject 로 이름 변경

(11) SceneChangeObject 에 Add Component 또는 드래그앤드랍으로 SceneController 컴포넌트를 add 처리

(12) 각 버튼을 선택하고 인스펙터 뷰에서 On Click() 아래의 + 버튼으로 온클릭 이벤트 생성.

오브젝트는 SceneChangeObject 를 고르고 메서드는 SceneController.MoveScene 선택

스트링은 버튼 1 ~ 3 각각 Example_Scene_1, Example_Scene_2, Example_Scene_3 라고 입력

=> 게임을 실행해보면 아래와 같은 오류 발생

Scene ‘Example_Scene_1’ couldn’t be loaded because it has not been added to the build settings or the AssetBundle has not been loaded.

To add a scene to the build settings use the menu File->Build Settings…

UnityEngine.SceneManagement.SceneManager:LoadScene(String)

SceneController:MoveScene(String) (at Assets/Scripts/SceneController.cs:17)

UnityEngine.EventSystems.EventSystem:Update()

(13) 씬이 빌드되어 있지 않기 때문에 위 오류가 발생한 것임.

상단 메뉴 File – Build Settings 윈도우를 열고,

프로젝트 뷰의 씬 3개를 Build Settings 윈도우 상단 Scenes In Build 박스 안에 드래그앤드랍할 것.

윈도우를 닫고 다시 게임을 실행해보면 잘된다.

* 씬 전환 주의사항

1. Using UnityEngine.SceneManagement; (씬 전환을 위한 라이브러리 임포트 필요)

2. Build를 한 Scene 끼리만 전환이 가능하다.

3. 스크립트명을 SceneManager 라고 짓지 말것. (라이브러리 이름임)

[Unity] Unity 기초강의 내용 정리 (2-18강 ~ 3-5강)

[Unity] Unity 기초강의 내용 정리 (2-18강 ~ 3-5강)

educast 나동빈 님의 <Mobile Defence Game 제작으로 배우는 Unity 기초> 강의를 듣고 내용 정리.

———-

2-18. 형변환

형변환(Type Conversion)

형변환 : 특정한 데이터를 다른 데이터 형으로 변환시키는 기법

대표적인 예시) 정수(int) -> 실수(float)

1) 정수/실수 -> 문자열 : 변수명.ToString();

2) 문자열 -> 정수 : int.Parse(변수명);

3) 문자열 -> 실수 : float.Parse(변수명);

프로젝트 뷰에 CastingTest 라는 이름의 C# 스크립트 생성

    float a = 5.5f;

    int b = 10;

   

    // 정수를 실수로 형 변환은 가능

    a = b;

    // 실수를 정수로 형 변환은 오류

    // b = a; 는 오류

    b = (int)a;

    Debug.Log(“a : ” + a);

    Debug.Log(“b : ” + b);

숫자를 문자열로 바꾸기

    string a = “777”;

    int b;

    float c;

   

    b = int.Parse(a);

    c = float.Parse(a);

    Debug.Log(“b : ” + b);

    Debug.Log(“c : ” + c);

문자열을 숫자로 바꾸기

    int b = 10;

    float c = 5.5f;

    string a1 = b.ToString();

    string a2 = c.ToString();

    Debug.Log(“a1 : ” + a1);

    Debug.Log(“a2 : ” + a2);

———-

Part3. UI

3-1. Canvas와 Render Mode

(1) Sprites 폴더 생성

Character_1.png, Monster_1.png 파일 프로젝트 뷰에 드래그앤드랍으로 넣기

(2) Images 폴더 생성

UI_Basic.png 파일 프로젝트 뷰에 드래그앤드랍으로 넣기

(3) 캐릭터 위치시키기

메인 카메라 영역에 Character_1.png, Monster_1.png 를 드래그앤드랍으로 가져다 놓을 것

(4) 좌측 하이어라키 뷰에서 마우스우클릭 – UI – Image 클릭

좌측 하이어라키 뷰에 Canvas, Image, EventSystem 이 생길 것이다.

Image : Canvas 안에 속해있다. 참고로 속해있는 구조를 <부모 자식 계층구조> 라고 한다.

EventSystem : 캔버스를 하나 만들면 자동으로 1개 만들어지는 것임. 캔버스를 n개 만들어도 1개 만들어짐.

(5) 하이어라키 뷰의 Image 를 더블클릭하면 흰색 네모가 보일 것임. 기본 이미지임.

캔버스는 UI 전용 카메라라고 생각하면 편하다.

게임을 실행해보면 (a)메인 카메라 영역과 (b)캔버스 영역이 겹쳐져서 보인다.

캔버스는 메인 카메라와 상관없이 배치하면 된다.

(6) UI_Basic(피망) 파일을 캔버스에 위치시키기. 캔버스 내의 이미지를 선택하고 우측의 인스펙터 뷰에서 UI_Basic(피망) 그림을 부여할 것.

(7) 캔버스의 내용은 메인 카메라 영역 내용보다 위쪽에 보이게 된다.

(8) 캔버스 렌더링 방식은 여러가지가 있다. 좌측 하이어라키 뷰에서 캔버스를 고르고, 우측 인스펙터 뷰의 Render Mode 콤보박스를 보자.

Canvas – Render Mode : UI를 렌더링하는 방식

1) Screen Space – Overlay : 다른 Object 들과 UI Object 들을 따로따로 작업할 때 유용. 카메라 영역과 Canvas 영역이 씬 뷰에서도 아예 다르게 표시됨.

2) Screen Space – Camera : 다른 Object 들과 UI Object 들을 씬 뷰에서 동시에 보고 작업할 때 사용. 카메라 영역과 Canvas 영역을 씬 뷰에서 같이 표시할 수 있음.

카메라와 사이즈를 같은 크기로 그려주게 되므로, 기준이 될 카메라를 선택해줘야 함.

잊지 말아야 할 것이 Plane Distance 를 바꿔야 함. 값을 10을 줘야 메인 카메라와 캔버스가 일치하게 됨. 이유는 메인 카메라의 인스펙터 뷰를 보면 Position의 Z 값이 -10 이기 때문임.

Screen Space – Overlay 와의 차이점은, Plane Distance 값을 수정하면 캔버스의 내용이 메인 카메라(캐릭터) 앞이나 뒤에 올 수 있도록 수정 가능하다.

캔버스 자체의 위치 변경 불가.

3) World Space : 다른 Object 들과 UI Object들을 동일한 Object 로 취급함.

캔버스 위치도 바꿀 수 있음. z값도 변경 가능.

———-

3-2. 부모자식 계층구조

Canvas 내에서,

부모 오브젝트가 이동 -> 자식 오브젝트도 이동

자식 오브젝트가 이동 -> 부모 오브젝트는 그대로임.

(1) 캔버스를 만든다.

(2) 캔버스의 Render Mode 를 World Space 로 바꾼다.

(3) 캔버스를 이동하면 자식 객체(Image)가 따라오는 것을 알 수 있다.

캔버스를 부모로, 이미지들을 자식으로 넣는 것이 권장됨.

(1) 피벗

Rect 툴(단축키 t) 선택했을 때

캔버스 가운데에 있는 파란색 동그라미가 보일 것임. 이것을 피벗이라고 부름. 중심이 되는 위치, 중심축이라는 뜻.

씬 뷰 위 쪽에 있는 Center 버튼을 한 번 더 눌러주면 피벗의 위치를 자유롭게 옮길수 있음.

캔버스 가장자리에 마우스를 갖다대고 드래그 하면 피벗을 중심으로 캔버스가 한 바퀴 돌아가게 됨.

실제로 캔버스의 피벗을 고치거나 캔버스를 회전하는 일은 거의 없음.

(2) Global, Local : 트랜스폼의 기준을 오브젝트로 할 것인지, 씬 전체로 할 것인지 결정 가능

씬 뷰 위쪽의 Local 버튼을 눌러서 Grobal 모드로 변경할 수 있음.

좌측 상단에 Local 이라고 쓰여 있으면 특정 오브젝트를 기준으로 삼는 것임.

좌측 상단에 Global 이라고 쓰여 있으면 씬 전체를 기준으로 삼는 것임.

피망 이미지를 회전시킨 후, Local로 해놓고 이동시켜보고 Global로 해놓고 이동시켜 보면서 이해할 것.

———-

3-3. Rect Transform, Anchors

캔버스의 인스펙터 뷰를 보면 Rect Transform 이라는 객체가 들어 있음.

그냥 Transform 이 아니라 Rect Transform 인 이유는 Anchor 개념이 있기 때문임.

이미지의 부모(캔버스)가 Rect Transform 을 갖고 있기 때문에, 이미지 오브젝트(피망)는 Anchor[앵커] 를 사용할 수 있음.

캔버스 중간에 보이는 바람개비 같은 것이 Anchor임.

인스펙터 뷰에서 Anchor를 고를 때, alt 키를 누르면 자식 오브젝트까지 다 같이 움직일 수 있음.

이미지를 우상단으로 마우스를 이용해 이동시키는 것과, Anchor로 우상단으로 위치시키는 것의 차이는 해상도를 변경했을 때 차이가 남.

Anchor로 이미지 위치를 잡아놓으면 해상도를 어떻게 바꾸더라도 화면에 따라 변경됨.

UI-Image 와 Sprite의 가장 큰 차이점임.

앵커를 선택할 때 보면 바람개비 모양이 한 점에 모이는 앵커도 있지만, 사방으로 확장되는 앵커도 있음.

부모(캔버스)의 크기에 따라 UI이미지의 크기를 변경해주는 것임.

해상도 상관없이 화면 가로 20%, 세로 50%를 차지하도록 이미지를 표시하려면 어떻게 해야할까?

인스펙터 뷰의 Anchors 항목 내 Min, Max, Pivot 값을 바꾸면 된다.

가로길이 20% 만들기

Min 의 X 를 0.4

Max 의 X 를 0.6

순서가 중요. 먼저 Anchors 항목 내의 X, Y 값들을 모두 지정한 후, Left, Top, Right, Bottom 값을 바꿔야 한다.

———-

3-4. Visual Components – Text

Visual Components : 실질적으로 보여지는 부분을 의미함.

비주얼 컴포넌트는 하나의 UI 안에 하나만 들어간다. 예를 들어서 피망콘(캔버스 내의 이미지)에 Add Component 로 Text를 추가하려면 안된다.

(1) 캔버스 안에 Text 컴포넌트를 새로 만들자.

하이어라키 뷰의 캔버스 위에서 마우스우클릭 – UI – Text

(2) 메인카메라 배경색을 흰색으로 바꾸자. 그래야 폰트가 잘 보인다.

(3) Font Size 크기를 늘린다.

(4) Font Size 를 늘리면 텍스트가 나오지 않을 것이다. Width와 Height를 늘려야 한다. 폰트 크기가 텍스트 영역보다 크면 표시되지 않는다.

Font Size 100 으로 설정

가로 가운데 정렬

세로 가운데 정렬

Width 1024

Height 720

(5) 앵커를 이용해 alt를 누른채 아래쪽에 앵커가 가도록 설정하자.

hp 등을 표시할 때 이러한 앵커 기술이 유용할 것이다. 해상도 상관없이 화면 아래쪽에 나와야 하기 때문이다.

(6) Add Component 로 Outline 을 추가해보고 색상을 바꿔보자.

(7) Anchors 의 X 값 Min 을 0.3, Max를 0.7, Y 값 Min 을 0.3, Max 를 0.7 로 설정해보자.

이후 Left, Top, Right, Botton 값을 0 으로 설정해보자.

(8) 텍스트를 어떻게든 간에 보이게 하려면 Horizontal Overflow 를 Overflow, Vertical Overflow 를 Overflow 로 설정한다.

(9) 해상도에 따라 글자 크기를 다르게 보여주려면, 스크립트를 이용해 Font Size를 바꿔주면 된다.

만약 비율 그대로를 유지하려고 한다면 Scale 값을 변경해서 텍스트 크기를 조절할 수도 있다.

단, Scale 값을 이용할 경우 텍스트 모양이 깨질 수 있다.

———-

3-5. Visual Components – Image & Panel

(1) 프로젝트 뷰에 Images 폴더 생성

(2) 프로젝트 뷰 Images 폴더 안에 Blue_button, Red_button 파일을 드래그앤드랍으로 추가

(3) 좌측 하이어라키 뷰에서 캔버스 생성 (UI – Canvas)

(4) 캔버스 안에 이미지 생성 (UI – Image)

(5) Canvas 의 Render Mode 를 Screen Space – Camera 로 변경

Render Camera 콤보박스 값을 Main Camera 로 선택

(6) 캔버스의 Plane Distance 값을 10 으로 수정하기

값을 10을 줘야 메인 카메라와 캔버스가 일치하게 됨. 이유는 메인 카메라의 인스펙터 뷰를 보면 Position의 Z 값이 -10 이기 때문임.

(7) 이미지의 Source Image 값을 Red_button 으로 지정

(8) Anchors 항목에서 alt 키 누르고 정중앙 선택

(9) Image Type 항목 선택

– Simple : 이미지 그대로 사용

– Sliced : Simple 과 아무런 차이가 없어보이지만 9개 이미지로 나누어져 있는 이미지의 경우 적용 가능함

원본 이미지

– Tiled : 반복출력

– Filed : 이미지를 비우거나 채우는 방식. HP 나 레벨업 바 등 진행척도를 알려줄 때 많이 사용하여 프로그레스 바라고도 불림.

Fill Method, Fill Origin, Fill Amount 등 수정 필요

* Sliced 이미지 만들기

– 프로젝트 뷰에서 Red_button 이미지 선택

– 인스펙터 뷰에서 Sprite Editor 클릭

– 주어진 선을 마우스로 드래그 하여 하나의 타일을 9조각으로 나누기

(10) Scripts 폴더 만들기

(11) 프로젝트 뷰에서 FillAmountTest 라는 이름의 C# 라이브러리 추가

(12) FillAmountTest 내용 수정

소스코드 상단에 다음 코드 넣기.

using UnityEngine.UI;

(13) 코드 작성

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

using UnityEngine.UI;

public class FillAmountTest : MonoBehaviour {

    public Image image;

    public float waitTime = 30.0f;

     

 void Start () {

  

 }

 

 void Update () {

        // 30초 동안 체력 감소구현

  if (image.fillAmount > 0) {

            image.fillAmount = image.fillAmount – 1.0f / waitTime * Time.deltaTime;

        }

 }

}

* Canvas 마우스우클릭 – UI – Panel

Panel 은 여러 개의 UI를 모아놓는 경우

크고, 투명도가 미리 적용된 UI 이미지라고 이해하면 됨.

[JAVA] HttpSessionBindingListener 구현과 valueBound, valueUnbound 메서드의 사용

[JAVA] HttpSessionBindingListener 구현과 valueBound, valueUnbound 메서드의 사용

HttpSessionBindingListener 를 implement 한 java 객체(ex : public class TestSession implements HttpSessionBindingListener)는 valueBound 메서드와 valueUnbound 메서드를 구현해야 한다.

보통 valueBound 메서드와 valueUnbound 메서드는 다음과 같이 구현할 수 있다.

public class TestSession implements HttpSessionBindingListener {

    private static Hashtable<HttpSession, String> userTable = new Hashtable<HttpSession, String>();

    private HttpSession httpSession = null;

   

    // 생성자

    public TestSession(HttpServletRequest request) throws Exception {
        httpSession = request.getSession(false);
    }

   

    public void valueBound(HttpSessionBindingEvent event) {
        userTable.put(event.getSession(), event.getName());
    }

    public void valueUnbound(HttpSessionBindingEvent event) {
        userTable.remove(event.getSession());
    }

}

여기서 userTable 변수는 static 으로 선언된 HashTable 이다.

참고로 HashTable을 쓰는 이유는 Thread-safe하기 때문이다. HashMap은 Thread-safe하지 못하다.

이 때 valueBound 메서드는 직접적으로 호출할 필요 없다(new TestSession().valueBound(event); 이런 식의 코드를 작성할 필요 없다는 뜻이다).

세션에 TestSession 객체 (HttpSessionBindingListener 를 implement 한 java 객체)를 setAttribute 하면 valueBound 메서드가 호출된다. 예를 들어 String userId = “admin”; session.setAttribute(userId, this); 이러한 코드를 수행할 때 valueBound 메서드가 호출된다. 그리고 valueBound 메서드는 userTable 에 HttpSession 객체(event.getSession()) 를 저장하도록 구현한다고 가정하자.

결국 세션을 생성할 때(사용자 로그인 시) session.setAttribute(userId, this); 코드를 수행하도록 작성하면, userTable 에 세션을 하나씩 저장할 것이다. 이렇게 해두면 유사시에 (ex : 동일한 아이디의 사용자가 상이한 아이피로 접속했을 때) userTable 을 size 만큼 loop 돌면서 세션들을 invalidate 시킬 수 있게 된다.

HttpSession session = null;

Enumeration e = userTable.keys();
while (e.hasMoreElements()) {
    session = (HttpSession) e.nextElement();
    if (userTable.get(session).equals(“admin”)) {
        session.invalidate();
    }
}

[Unity] Unity 기초강의 내용 정리 (2-16강 ~ 2-17강)

[Unity] Unity 기초강의 내용 정리 (2-16강 ~ 2-17강)

educast 나동빈 님의 <Mobile Defence Game 제작으로 배우는 Unity 기초> 강의를 듣고 내용 정리.

———-

2-16. Acceess Modifier

접근 한정자(Access Modifier)

public : 다른 스크립트에서 접근할 수 있도록 만들 때 사용

private : 현재 스크립트에서만 접근할 수 있도록 만들 때 사용

1. 프로젝트 뷰에 AcceessModifierTest 라는 이름의 C# 스크립트 생성하기

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

public class AccessModifierTest : MonoBehaviour {

    public string nickname;

    public int HP;

    private bool timerEnded = false;

    float timer = 3.0f;

   

 void Start () {

  

 }

 

 void Update () {

        // 정확히 3초 뒤 실행

        timer -= Time.deltaTime;

        if (timer <= 0 && timerEnded == false) {

            Debug.Log(“이름 : ” + nickname);

            Debug.Log(“체력 : ” + HP);

            timerEnded = true;

        }

 }

}

2. 좌상단 하이어라키 뷰의 캐릭터1(당근 캐릭터) 위에 드래그 앤 드롭하여 컴포넌트 add 처리하기.

3. 우측 인스펙터 뷰에서 public 변수들의 값을 볼 수 있다.

4. 스크립트 내부에 public 변수 값을 할당하더라도,

인스펙터 뷰에 입력한 변수 값이 우선된다.

예를 들어

public string nickname = “홍길동”;

public int HP = 200;

이라고 입력하더라도,

인스펙터 뷰에서 nickname 값을 “홍길동2”, HP 값을 300 을 대입하면

인스펙터 뷰의 값을 따른다.

(게임 실행 시 로그에 홍길동2와 300이 찍힘)

접근 한정자의 개념은 변수만이 아니라 함수에도 적용될 수 있다.

AccessModifierTest 스크립트에 아래 함수를 추가한다.

 public void Damaged(int power) {

        HP -= power;

        Debug.Log(“남은 체력 : ” + HP);

    }

OnCollisionTest 스크립트의 OnCollisionEnter2D 함수 내용을 수정한다.

참고로 OnCollisionTest 스크립트도 AccessModifierTest 처럼 캐릭터1(당근 캐릭터)에 부여된 스크립트이다.

 private void OnCollisionEnter2D(Collision2D other) {

        // 타일은 제거하지 않는다.

        if (other.gameObject.tag == “Monster”) {

            // 주인공과 닿은 오브젝트를 파괴한다.

            Destroy(other.gameObject);

            gameObject.GetComponent<AccessModifierTest>().Damaged(50);

        }

    }

 

캐릭터의 키입력 바꾸기

GetComponentAddForce 스크립트 내용 수정

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

public class GetComponentAddForce : MonoBehaviour {

    public float jumpPower = 200.0f;

    public KeyCode keyLeft;

    public KeyCode keyRight;

    public KeyCode keyJump;

    // Use this for initialization

    void Start () {

    }

 

 // Update is called once per frame

 void Update () {

        if (Input.GetKey(keyLeft)) {

            transform.Translate(Vector3.left * 0.1f);

        } else if (Input.GetKey(keyRight)) {

            transform.Translate(Vector3.right * 0.1f);

        }

        if (Input.GetKeyDown(keyJump)) {

            GetComponent<Rigidbody2D>().AddForce(Vector3.up * jumpPower);

        }

    }

}

이제 인스펙터 뷰에서 jumpPower, keyLeft, keyRight, keyJump 을 수정해본다.

요약

public 은 다른 스크립트에서 접근 가능, private 은 현재 스크립트에서만 접근 가능

———-

2-17. OnCollision과 Access Modifier 실습

GetComponent의 사용

* 어떠한 오브젝트에 속한 컴포넌트에 접근하기 위한 목적으로 사용함

* 대부분 모든 컴포넌트는 GetComponent를 활용함

(모든 오브젝트에 내장된 트랜스폼 컴포넌트는 예외임)

* 특정한 오브젝트의 중력값을 0 으로 만들어보는 실습

GetComponent<RigidBody2D>().gravityScale = 0;

Prefab

* Prefab은 프로젝트 전체에서 사용할 수 있는 Object의 “틀”

* Prefab을 사용해 Scene에 배치한 Object는 Prefab의 특성을 똑같이 가진 “복제품”

* 어떤 작업을 수행할 때, 그 대상이 Object냐 Prefab이냐는 큰 차이

* 혼란을 방지하기 위해 가급적 다른 이름을 사용하거나, 폴더를 따로 생성해서 관리

1. 프로젝트 뷰에 BulletScript 라는 이름의 C# 스크립트 생성

2. 하이어라키 뷰의 Bullet_1 위에 드래그앤드랍하여 컴포넌트 Add 처리

3. 충돌감지를 위해 Bullet_1에 Box Collider 2D를 추가하기

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

public class BulletScript : MonoBehaviour {

    float speed = 3.0f;

   

 void Start () {

  

 }

 

 void Update () {

        transform.Translate(Vector3.right * speed * Time.deltaTime);

 }

    private void OnCollisionEnter2D(Collision2D other) {

        if (other.gameObject.tag == “Monster”) {

            // 몬스터가 사라지도록 처리

            Destroy(other.gameObject);

            // 총알이 사라지도록 처리

            Destroy(gameObject);

        }

    }

}

4. 총알에 중력 적용을 위해 RigidBody2D 를 추가

* 메모리 관리를 위한 처리

(1) 화면 가장자리에 벽을 만들고 벽에 충돌됐을 때 총알 제거

(2) 일정 시간이 지나면 총알 제거

5. 하단의 타일에 Tag를 추가 (Tile 이라는 이름으로 지정)

6. 타일 크기를 좌우로 늘려서 총알이 꼭 닿도록 조정

7. 코드 수정

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

public class BulletScript : MonoBehaviour {

    float shotPower = 500.0f;

   

 void Start () {

        GetComponent<Rigidbody2D>().AddForce(Vector3.right * shotPower);

 }

 

 void Update () {

 }

    private void OnCollisionEnter2D(Collision2D other) {

        if (other.gameObject.tag == “Monster”) {

            // 몬스터가 사라지도록 처리

            Destroy(other.gameObject);

            // 총알이 사라지도록 처리

            Destroy(gameObject);

        } else if (other.gameObject.tag == “Tile”) {

            // 총알이 사라지도록 처리

            Destroy(gameObject);

        }

    }

}

8. 프리팹 만들기

8-1. 프로젝트 뷰에 Prefabs 폴더 생성

8-2. 하이어라키 뷰의 Bullet_1 을 Prefabs 폴더 안으로 드래그앤드랍

8-3. 씬 뷰의 Bullet_1은 삭제

9. 소스 코드 수정

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

public class BulletScript : MonoBehaviour {

    float shotPower = 500.0f;

   

 void Start () {

        if (transform.rotation.y == 0) {

            GetComponent<Rigidbody2D>().AddForce(Vector3.right * shotPower);

        } else {

            GetComponent<Rigidbody2D>().AddForce(Vector3.left * shotPower);

        }

       

 }

 

 void Update () {

 }

    private void OnCollisionEnter2D(Collision2D other) {

        if (other.gameObject.tag == “Monster”) {

            // 몬스터가 사라지도록 처리

            Destroy(other.gameObject);

            // 총알이 사라지도록 처리

            Destroy(gameObject);

        } else if (other.gameObject.tag == “Tile”) {

            // 총알이 사라지도록 처리

            Destroy(gameObject);

        }

    }

}

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

public class GetComponentAddForce : MonoBehaviour {

    public float jumpPower = 200.0f;

    public KeyCode keyLeft;

    public KeyCode keyRight;

    public KeyCode keyJump;

    public KeyCode keyAttack;

    // 외부에서 프리팹을 주입 가능하도록 변수 선언

    public GameObject bullet;

    // Use this for initialization

    void Start () {

    }

 

 // Update is called once per frame

 void Update () {

        if (Input.GetKey(keyLeft)) {

            transform.eulerAngles = new Vector3(0, 180, 0);

            transform.Translate(Vector3.right * 0.1f);

        } else if (Input.GetKey(keyRight)) {

            transform.eulerAngles = new Vector3(0, 0, 0);

            transform.Translate(Vector3.right * 0.1f);

        }

        if (Input.GetKeyDown(keyJump)) {

            GetComponent<Rigidbody2D>().AddForce(Vector3.up * jumpPower);

        }

        if (Input.GetKeyDown(keyAttack)) {

            if (transform.rotation.y == 0) {

                Instantiate(bullet, transform.position + Vector3.right * 1.0f, transform.rotation);

            } else {

                Instantiate(bullet, transform.position + Vector3.left * 1.0f, transform.rotation);

            }

        }

    }

}

10. 우측 인스펙터 뷰 keyAttack 항목에 키보드 q 대입

11. 우측 인스펙터 뷰 bullet 항목에 프리팹 폴더 내의 Bullet1을 드래그앤드랍하여 대입

[Unity] Unity 기초강의 내용 정리 (2-12강 ~ 2-15강)

[Unity] Unity 기초강의 내용 정리 (2-12강 ~ 2-15강)

educast 나동빈 님의 <Mobile Defence Game 제작으로 배우는 Unity 기초> 강의를 듣고 내용 정리.

———-

2-12. Instantiate

Instantiate(object);

게임 실행 도중에 object를 생성하도록 해주는 함수

(*동적 : ‘게임이 실행되는 도중에’라는 의미.)

* 미리 오브젝트를 만들지 않고, 게임이 실행된 이후 동적으로 오브젝트를 생성

* Instantiate 함수는 Start 함수나 Update 함수에서 그냥(조건없이) 사용하면 안됨!

메모리 과부하로 에러가 발생할 수 있음.

(1) 프로젝트 뷰 Assets 폴더 안에 Sprites 폴더를 만들고,

캐릭터 1(당근모양 캐릭터) 그림을 Sprites 폴더 안에 넣는다.

(2) 프로젝트 뷰 Assets 폴더 안에 Scripts 폴더를 만들고,

Instantiate 이라는 이름의 C# 스크립트 파일을 만든다.

(3) 하이어라키 뷰 캐릭터 1(당근 캐릭터) 위에 Instantiate 파일을 드래그 앤 드랍하여

컴포넌트를 add 처리한다. Add Component 버튼을 이용해도 된다.

(4) 인스펙터 뷰에서 Add Component 버튼을 이용하여 Rigidbody 2D와 Box Collider 2D를 넣어준다.

(5) 인스펙터 뷰에서 Box Collider 2D 항목 내의 Edit Collider 버튼을 이용하여 충돌박스를 조절한다.

(6) 당근 캐릭터 아래쪽에 타일 그림의 오브젝트를 넣고, Box Collider 2D 를 넣는다.

Start 함수는 오브젝트 생성시 한 번만 실행되는 함수이지만,

Start 함수 안에 조건 없이 Instantiate 함수를 만든다면, 해당 오브젝트가 복제되면서 또 다시 Start 함수가 실행되므로 무한루프에 빠짐.

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

public class Instantiate : MonoBehaviour {

 // Use this for initialization

 void Start () {

  

 }

 

 // Update is called once per frame

 void Update () {

  // 키입력 : 키보드 A를 누를 때마다 당근 캐릭터가 복제된다.

     if (Input.GetKeyDown(KeyCode.A)) {

            Copy();

        } 

 }

    void Copy() {

        Instantiate(gameObject);

    }   

}

———-

2-13. GetComponent와 AddForce

GetComponent<컴포넌트명>(). 컴포넌트의 값 혹은 함수

특정한 Object가 가지고 있는 컴포넌트 혹은 그 컴포넌트의 값에 접근하기 위한 함수

(예외적으로, GameComponent를 사용하지 않아도 되는 내장된 컴포넌트도 있음.)

아래와 같이 중력 값을 0 으로 고쳐서 캐릭터가 아래로 떨어지지 않게 수정할 수 있다.

GetComponent<RigidBody2D>().gravitySclae = 0;

* <> 가 의미하는 것은 <자료형> 임.

GetComponent<GameObject>();

이런 경우는 괄호안에 원래 bool 타입이 들어가야 함.

디폴트가 false로 되어 있는데, true를 넣으면 비활성화 된 오브젝트도 인식 가능.

* GetComponent 가 중요한 이유는 다른 오브젝트의 컴포넌트에도 접근할 수 있기 때문이다.

(ex : 주인공과 부딪힌 몬스터의 체력 조작)

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

public class GetComponentAddForce : MonoBehaviour {

 // Use this for initialization

 void Start () {

        GetComponent<Rigidbody2D>().gravityScale = 0;

    }

 

 // Update is called once per frame

 void Update () {

       

    }

}

* AddForce

GetComponent<RigidBody2D>().AddForce(Vector3.up[down,righ,left] * 숫자);

RigidBody2D 컴포넌트의 함수로, object에 힘을 가하여 움직이는 함수

* AddForce 는 RigidBody2D 컴포넌트 안에 내장되어 있는 함수. 많이 사용하는 함수.

(1) 캐릭터를 화면 위쪽으로 보내기

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

public class GetComponentAddForce : MonoBehaviour {

 // Use this for initialization

 void Start () {

        float jumpPower = 50.0f;

        GetComponent<Rigidbody2D>().gravityScale = 0;

        GetComponent<Rigidbody2D>().AddForce(Vector3.up * jumpPower);

    }

 

 // Update is called once per frame

 void Update () {

       

    }

}

(2) 사용자가 스페이스 바를 눌렀을 때 점프 실행

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

public class GetComponentAddForce : MonoBehaviour {

    float jumpPower = 200.0f;

    // Use this for initialization

    void Start () {

    }

 

 // Update is called once per frame

 void Update () {

        if (Input.GetKeyDown(KeyCode.Space)) {

            GetComponent<Rigidbody2D>().AddForce(Vector3.up * jumpPower);

        }

    }

}

* 보통 점프 기능 구현 시 오브젝트가 지면에 닿아있을 때 한해서만 점프 가능하도록 구현함.

(3) 점프에 좌우 이동 기능까지 추가

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

public class GetComponentAddForce : MonoBehaviour {

    float jumpPower = 200.0f;

    // Use this for initialization

    void Start () {

    }

 

 // Update is called once per frame

 void Update () {

        if (Input.GetKey(KeyCode.LeftArrow)) {

            transform.Translate(Vector3.left * 0.1f);

        } else if (Input.GetKey(KeyCode.RightArrow)) {

            transform.Translate(Vector3.right * 0.1f);

        }

        if (Input.GetKeyDown(KeyCode.Space)) {

            GetComponent<Rigidbody2D>().AddForce(Vector3.up * jumpPower);

        }

    }

}

———-

2-14. 이벤트 함수 Start와 Update

이벤트 함수 : Unity에서 스크립트마다 일정 규칙에 의해 실행되도록 정의된 내장함수

(Start : 초기화 함수, Update : 매 프레임마다 실행되는 함수)

* 이벤트 함수는 우리가 직접 만든 함수와 다르게, 이미 그 목적과 실행 시점이 정해져 있음.

유니티 실행 순서 (사용자가 바꾸지 못하고 이미 정해져 있음)

1. Start() – 초기화(Initialization) 부분

2. … – 에디터(Editor) 부분 * 스크립트가 새롭게 적용되거나 리셋될 때 에디터에서 실행되는 부분. 실제 사용할 일은 드물다.

3. OnCollisionXXX – 물리 법칙(Physics) 부분

4. OnMouseXXX – 입력 이벤트(Input Events) 부분

5. Update() – 게임 로직 (Game Logic) 부분

6. … – 렌더링(Scene Rendering) 부분

1, 2는 오브젝트 초기화 시점에 실행되고, 3부터 6까지는 Destory 함수가 호출되기 전까지 무한반복된다.

———-

2-15. 이벤트 함수 OnCollision과 OnMouseDown

OnCollisionXXX : 다른 오브젝트와 충돌이 발생했을 때 이를 감지함.

OnMouseXXX : 마우스 클릭을 감지함.

OnCollisionXXX 함수의 댚적인 예제

OnCollisionEnter2D(Collision2D other) {

 // 충돌 처리;

}

* 2D 게임이므로 OnCollisionEnter2D 이며, 3D 게임이면 OnCollisionEnter 임.

* 함수명에 Enter 가 붙어있으므로, 충돌 중이나 충돌 이후가 아닌 충돌 처리 시작되는 시점임

* 충돌 처리를 위해서는 두 물체 중 한 개는 OnCollisionXXX 함수가 있어야 함.

* other는 충돌한 상대방 오브젝트를 의미함.

프로젝트 뷰에서 OnCollisionTest 라는 이름의 C# 스크립트를 만들고,

하이어라키 뷰에서 캐릭터 1(당근 캐릭터) 위에 드래그 앤 드랍하여 컴포넌트 추가.

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

public class OnCollisionTest : MonoBehaviour {

 // Use this for initialization

 void Start () {

  

 }

 

 // Update is called once per frame

 void Update () {

  

 }

    private void OnCollisionEnter2D(Collision2D other) {

        // 타일은 제거하지 않는다.

        if (other.gameObject.name != “tile1”) {

            // 주인공과 닿은 오브젝트를 파괴한다.

            Destroy(other.gameObject);

        }

    }

}

유니티는 태그 라는 개념을 제공함.

서로 다른 오브젝트라고 하더라도 태그를 동일하게 입력하여 분류할 수 있다.

(1) 하이어라키 뷰의 Monster 1을 복사하여 Monster 2를 만들자.

(2) 인스펙터 뷰 상단의 Tag 값을 Monster 로 지정한다.

(3) 코드를 아래와 같이 작성한다.

 private void OnCollisionEnter2D(Collision2D other) {

        // 타일은 제거하지 않는다.

        if (other.gameObject.tag == “Monster”) {

            // 주인공과 닿은 오브젝트를 파괴한다.

            Destroy(other.gameObject);

        }

    }

 

* OnMouseDown

(1) OnMouseDownTest 이라는 이름의 C# 스크립트 파일을 생성한다.

(2) 스크립트 파일(컴포넌트)를 몬스터 1(당근 캐릭터)에게 add 한다. (Add Component)

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

public class OnMouseDownTest : MonoBehaviour {

 // Use this for initialization

 void Start () {

  

 }

 

 // Update is called once per frame

 void Update () {

  

 }

    private void OnMouseDown() {

        Instantiate(gameObject);

    }

}

OnCollisionEnter2D : 충돌이 발생했을 때

OnCollisionStay2D : 충돌 상태가 유지되고 있을 때

OnCollisionEixt2D : 충돌 상태가 끝났을 때

OnMouseDown : 마우스 클릭이 발생했을 때

OnMouseOver : 마우스를 클릭 중일 때

OnMouseUp : 마우스 클릭이 끝났을 때

[윈도우] ㄱ 2번 누르면 ㄲ / 기역 2번 누르면 쌍기역 / 자음 2번 누르면 쌍자음 현상 문제해결

[윈도우] ㄱ 2번 누르면 ㄲ / 기역 2번 누르면 쌍기역 / 자음 2번 누르면 쌍자음 현상 문제해결

키보드의 자음을 두 번 누르면 쌍자음이 나오는 경우 문제해결.

예를 들어 ㄱ을 두 번 입력했을 때 ㄲ이 나오는 경우.

1. 윈도우 시작키 누르고 [언어]를 검색 – [언어 설정] 메뉴 클릭

 

2. 좌측의 [언어] 항목 선택 – 우측 한국어 항목에서 [옵션] 클릭

 

3. 키보드 항목의 Microsoft 입력기를 찾고 [옵션] 클릭

 

4. 터치 키보드 항목의 [두 번 탭하여 이중 자음/모음 입력] 을 해제.

 

5. 마지막으로 적용하려면 컴퓨터를 재시작해야 함.

이제 ㄱ을 두 번 입력하면 ㄱㄱ이 나올 것이다.

[Unity] Unity 기초강의 내용 정리 (2-7강 ~ 2-11강)

[Unity] Unity 기초강의 내용 정리 (2-7강 ~ 2-11강)

educast 나동빈 님의 <Mobile Defence Game 제작으로 배우는 Unity 기초> 강의를 듣고 내용 정리.

———-

2-7. Function

함수(Function) : 불필요한 소스코드의 반복을 없애기 위해 특정한 기능을 정의한 것

유니티는 스크립트 단독으로는 실행이 불가하다.

스크립트를 실행시키려면 빈 오브젝트라도 만들어서 스크립트를 추가해줘야 한다.

매개변수 => 함수 => 반환값

반환자료형 함수명(매개변수) {

 명령문;

 return 반환값;

}

* 함수는 매개변수가 없을 수도 있고, 반환값이 없을 수도 있다.

1. 프로젝트 뷰에 Scripts 폴더 생성, Sprites 폴더 생성하기

2. Sprites 폴더 안에 Monster_1, Monster_2, tile1 이미지 드래그 앤 드롭으로 가져다넣기

3. Scripts 폴더 안에 FunctionTest 라는 이름의 C# 스크립트 만들기

4. 하이어라키 뷰에서 Create Empty로 빈 오브젝트를 만들고, 프로젝트 뷰의 FunctionTest 를 해당 오브젝트 위에 드래그 앤 드랍하기

(유니티는 스크립트 단독으로는 실행이 불가하다.

스크립트를 실행시키려면 빈 오브젝트라도 만들어서 스크립트를 추가해줘야 한다.)

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

public class FunctionTest : MonoBehaviour {

    int add(int a, int b) {

        int sum = a + b;

        return sum;

    }

 

 // Use this for initialization

 void Start () {

        Debug.Log(add(3, 7));

 }

 

 // Update is called once per frame

 void Update () {

  

 }

}

* 매개변수가 없는 함수

반환값을 void로 적는다.

* 내장 함수 : 기본적으로 제공되는 함수

* 사용자 정의 함수 : 사용자가 직접 정의하여 사용할 수 있는 함수

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

public class FunctionTest : MonoBehaviour {

    int add(int a, int b) {

        int result = a + b;

        return result;

    }

    int substract(int a, int b) {

        int result = a – b;

        return result;

    }

    int multiply(int a, int b) {

        int result = a * b;

        return result;

    }

    int devide(int a, int b) {

        int result = a / b;

        return result;

    }

    // Use this for initialization

    void Start () {

        Debug.Log(add(3, 7));

        Debug.Log(substract(10, 3));

        Debug.Log(multiply(5, 3));

        Debug.Log(devide(10, 3));

    }

 

 // Update is called once per frame

 void Update () {

  

 }

}

———-

2-8. Vector3와 Translate

* 벡터 : 물체에 힘을 가할 때 어느 방향으로 얼마만큼의 힘을 가하는지를 나타내는 물리적 양.

(벡터 : 크기 + 방향)

* 스칼라 : ‘크기’만을 가지고 있는 물리적 양. 단순한 숫자값이라고 생각하면 된다.

a = <2,4>

한 번 움직일 때 X 좌표로 2, Y 좌표로 4만큼 이동하는 벡터

벡터의 곱셈

a = <1,2> 에 스칼라 2를 곱한다면?

a = <2,4>

* Vector3 : Unity에서 3차원 공간에서의 벡터를 표현하기 위해 사용.

Vector3.up : 벡터 <0, 1, 0>을 의미함.

Vector3.down : 벡터 <0, -1, 0>을 의미함.

Vector3.right : 벡터 <1, 0, 0>을 의미함.

Vector3.left : 벡터 <-1, 0, 0>을 의미함.

* Translate() : Object를 특정한 벡터만큼 이동시키는 함수.

트랜스레이트 함수의 매개변수는 벡터가 들어간다고 보면 된다.

transform : 유니티 모든 오브젝트에서 제공하는 변수.

내장함수로 Translate 함수를 제공함.

참고로 gameObjec도 모든 오브젝트에서 제공하는 변수임.

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

public class VectorTest : MonoBehaviour {

 // Use this for initialization

 void Start () {

  

 }

 

 // Update is called once per frame

 void Update () {

        transform.Translate(Vector3.right * 0.01f);

 }

}

———-

2-9. 조건문

* 조건문 : 조건에 따라서 프로그램 실행의 흐름을 결정하는 문법.

일반적으로 조건문은 if – else 문법을 사용합니다.

if (조건) {

 명령문;

} else if (조건) {

 명령문;

} else {

 명령문;

}

(1) Scripts 폴더 안에 ConditionTest 라는 이름의 C# Script 생성

(2) 빈 오브젝트를 만들어서 드래그 앤 드랍을 이용하여 ConditionTest 컴포넌트를 추가

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

public class ConditionTest : MonoBehaviour {

 // Use this for initialization

 void Start () {

        int a = 10;

        if (a >= 20) {

            Debug.Log(“a는 20보다 크거나 같습니다.”);

        } else if (a >= 10) {

            Debug.Log(“a는 10보다 크거나 같습니다.”);

        } else {

            Debug.Log(“a는 10보다 작습니다.”);

        }

 }

 

 // Update is called once per frame

 void Update () {

  

 }

}

조건은 다음 등과 같은 비교 연산자를 이용해서 제시할 수 있습니다.

A == B : A와 B가 일치하는 경우 TRUE, 그렇지 않으면 FALSE

A >= B : A가 B보다 크거나 같으면 TRUE, 그렇지 않으면 FALSE

A <= B : A가 B보다 작거나 같으면 TRUE, 그렇지 않으면 FALSE

여러 개의 조건을 합칠 때는 논리 연산자를 사용할 수 있습니다.

(1) (조건 1) && (조건2) : 조건 1과 조건 2과 모두 TRUE인 경우에만 TRUE

    => 앰퍼센트가 2개 붙어있는 것을 앤드 연산자 라고 한다.

(2) (조건 1) || (조건 2) : 조건 1과 조건 2 중에 하나만 TRUE이면 TRUE

* AND 연산자 테스트

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

public class ConditionTest : MonoBehaviour {

 // Use this for initialization

 void Start () {

        string job = “전사”;

        if (job == “전사” && level > 10) {

            Debug.Log(“환영합니다. 고급 전사님.”);

        } else {

            Debug.Log(“입장할 수 없는 던젼입니다.”);

        }

 }

 

 // Update is called once per frame

 void Update () {

  

 }

}

* OR 연산자 테스트

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

public class ConditionTest : MonoBehaviour {

    // Use this for initialization

    void Start() {

        string job = “전사”;

        if (job == “전사” || job == “마법사”) {

            Debug.Log(“입장할 수 있는 직업입니다.”);

        } else {

            Debug.Log(“입장할 수 없는 직업입니다.”);

        }

    }

    // Update is called once per frame

    void Update() {

    }

}

* 컴퓨터의 4칙 연산과 모듈로(%) 연산

A + B : A와 B를 더한 값.

A – B : A와 B를 뺀 값.

A * B : A와 B를 곱한 값.

A / B : A와 B를 나는 몫 값.

A % B : A와 B를 나는 나머지 값.

Empty Object에 Add Component 로 Sprite Renderer 를 추가하면 그림을 지정할 수 있다.

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

public class ConditionTest : MonoBehaviour {

    int frame = 0;

    // Use this for initialization

    void Start() {

       

    }

    // Update is called once per frame

    void Update() {

        // 일반적으로 60 FPS 이므로 아래처럼 작성하면 1초에 한 번 수행한다.

        frame = frame + 1;

        if (frame % 60 == 0) {

            transform.Translate(Vector2.right * 1.0f);

        }

    }

}

과제

몬스터 이미지 2개를 이용해, 두 개의 몬스터 Object가 양쪽에서 서서히 다가와 부딪히는 프로그램을 작성하세요.

이 때 Collider 와 Rigidbody2D를 활용하세요.

———-

2-10. GetKey

GetKey() : 해당되는 키를 누르고 있을 경우 TRUE 값을 계속 반환합니다.

GetKeyDown() : 해당되는 키를 눌렀을 때 TRUE 값을 1번 반환합니다.

GetKeyUp() : 해당되는 키를 눌렀다가 떼었을 때 TRUE 값을 1번 반환합니다.

if (Input.GetkeyDown(KeyCode.A)) {

 Debug.Log(“A를 눌렀습니다.”);

}

Input 이라는 라이브러리 안에 있음.

(1) 프로젝트 뷰의 Scripts 폴더 안에 GetKeyTest 라는 이름의 C# 스크립트 생성

(2) Monster2에 GetKeyTest 컴포넌트를 add 처리

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

public class GetKeyTest : MonoBehaviour {

 // Use this for initialization

 void Start () {

  

 }

 

 // Update is called once per frame

 void Update () {

  if (Input.GetKey(KeyCode.LeftArrow)) {

            transform.Translate(Vector3.left * 0.01f);

        } else if (Input.GetKey(KeyCode.RightArrow)) {

            transform.Translate(Vector3.right * 0.01f);

        }

    }

}

과제

방향키(상, 하, 좌, 우)를 눌러서 몬스터 Object를 이동시키는 프로그램을 작성하세요.

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

public class GetKeyTest : MonoBehaviour {

 // Use this for initialization

 void Start () {

  

 }

 

 // Update is called once per frame

 void Update () {

  if (Input.GetKey(KeyCode.LeftArrow)) {

            transform.Translate(Vector3.left * 0.01f);

        } else if (Input.GetKey(KeyCode.RightArrow)) {

            transform.Translate(Vector3.right * 0.01f);

        }

        if (Input.GetKey(KeyCode.UpArrow)) {

            transform.Translate(Vector3.up * 0.01f);

        } else if (Input.GetKey(KeyCode.DownArrow)) {

            transform.Translate(Vector3.down * 0.01f);

        }

    }

}

———-

2-11. Destory와 SetActive

Destroy(object);

게임이 진행되는 도중에 Scene에서 Object를 완전히 제거하는 함수

(슈팅게임에서 탄환, RPG 게임에서의 투사체 등)

gameObject.SetActive(true);

gameObject.SetActive(false);

게임이 진행되는 도중에 Scene에서 Object를 활성화/비활성화하는 함수

(RPG 게임에서 일정시간 지속되는 소환수 등)

(1) 프로젝트 뷰에서 DestroySetActive 라는 이름의 C# 스크립트 파일 생성

(2) 몬스터 스프라이트를 이용해 몬스터 오브젝트 생성

(3) 하이어라키 뷰의 몬스터 위로 DestroySetActive 스크립트 파일 드래그 앤 드랍하여 컴포넌트 Add 처리

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

public class DestroySetActive : MonoBehaviour {

    float timer = 180.0f;

 // Use this for initialization

 void Start () {

  

 }

 

 // Update is called once per frame

 void Update () {

        timer -= 1.0f;

        // 약 3초 뒤 몬스터 삭제

        if (timer <= 0) {

            Destroy(gameObject);

        }

 }

}

Time.deltaTime;

컴퓨터마다 FPS가 다른 문제를 해결하기 위해

1초를 ‘초당 프레임’만큼 나눈 값을 저장하는 변수

(예를 들어, 초당 프레임이 100회라면 Time.deltaTime이 약 0.01 정도로 산정됨)

* 간단히 말해서 Time.deltaTime 을 이용하면 컴퓨터 마다 성능이 달라도 정확한 시간(1초)를 구할 수 있다.

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

public class DestroySetActive : MonoBehaviour {

    float timer = 3.0f;

 // Use this for initialization

 void Start () {

  

 }

 

 // Update is called once per frame

 void Update () {

        timer -= Time.deltaTime;

        // 정확히 3초 뒤 몬스터 삭제

        if (timer <= 0) {

            Destroy(gameObject);

        }

 }

}

Destory(object, 3f);

3초 뒤에 object를 Destory 한다는 의미

* 이 명령어를 사용하면 편하다.

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

public class DestroySetActive : MonoBehaviour {

   

 // Use this for initialization

 void Start () {

        Destroy(gameObject, 3f);

 }

 

 // Update is called once per frame

 void Update () {

       

 }

}

Destory 와 SetActive의 차이

Destory 는 완전 삭제, SetActive는 비활성화 처리

기능적으로는 동일함. 씬에서 오브젝트를 다시 살릴 가능성이 있는 경우 SetActive 사용할 것.

Destroy(object);

게임이 진행되는 도중에 Scene에서 Object를 완전히 제거하는 함수

gameObject.SetActive(true);

gameObject.SetActive(false);

게임이 진행되는 도중에 Scene에서 Object를 활성화/비활성화하는 함수

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

public class DestroySetActive : MonoBehaviour {

    float timer = 3.0f;

 // Use this for initialization

 void Start () {

 }

 

 // Update is called once per frame

 void Update () {

        timer -= Time.deltaTime;

        // 3초 뒤 오브젝트 비활성화

        if (timer <= 0) {

            gameObject.SetActive(false);

        }

 }

}

[Unity] Unity 기초강의 내용 정리 (2-1강 ~ 2-6강)

[Unity] Unity 기초강의 내용 정리 (2-1강 ~ 2-6강)

educast 나동빈 님의 <Mobile Defence Game 제작으로 배우는 Unity 기초> 강의를 듣고 내용 정리.

———-

2-1. Script Basic

스크립트(Script) : 게임에서 다양한 연산을 처리할 수 있도록 해주는 소스코드

프로젝트 뷰의 Assets 폴더 내에 Scripts 폴더 만들기

Scripts 폴더 안에 C# 파일 생성하기. 파일명은 ShowInformation 으로 지정

참고로 유니티 2018년부터 모노 디벨롭을 지원하지 않는다. Visual Studio 지원.

프로젝트 뷰의 ShowInformation 스크립트를 드래그해서, 좌측 상단 씬 뷰의 Monster 위에 드롭한다.

* 개념

몬스터 -> 오브젝트 (사물)

스크립트 -> 컴포넌트 (기능 등)

Start() : 초기화 수행

Update() : 프레임 당 반복 수행

Start() 메서드 안에 Debug.Log(“Start”); 라고 써넣기

Ctrl + P : 유니티 게임 플레이 단축키

콘솔 창을 보면 “Start” 가 찍혀있다.

Update() 메서드 안에

Debug.Log(“gameObject.name : ” + gameObject.name); 라고 써넣기

gameObject 라는 변수가 제공됨.

Clear : 콘솔 비우기

Clear on Play : 플레이 시마다 콘솔 비우기

스크립트 내의 클래스명과, 파일명을 일치시켜야만 한다.

둘 중 하나를 변경할 경우, 다른 하나도 일치시켜줄 것.

———-

2-2. 개발환경 Setting

* 에디터 선택

상단메뉴 Edit – Prefarences – 좌측 탭 External Tools – External Script Editor 를 Visual Studio 2015 로 설정

메모장으로 설정해도 되지만 비효율적이므로 Visual Studio 추천

* 폰트 설정

Visual Studio 상단메뉴 [도구] – [옵션] – 좌측 [환경] – [글꼴 및 색] 에서 폰트 설정 가능

———-

2-3. Collision

충돌. 거의 모든 게임에서 발생하는 이벤트.

오브젝트와 오브젝트가 부딪치는 모든 행위를 충돌로 이해하자.

Collision[콜리전] 충돌

1. 충돌을 하는 두 Object는 모두 Collider(2D) Component를 가진다.

2. 두 Object 중에서 움직이는 Object는 반드시 RigidBody(2D) Component를 갖는다.

RigidBody(2D) : 충돌 오브젝트 둘 중 하나는 반드시 RigidBody(2D)를 가져야 한다.

Collider[콜라이더] : 충돌이 일어나는 범위를 설정하는 컴포넌트

1. Monster 클릭

2. Add Component

3. Box Collider 2D[박스 콜라이더]

우측 Box Collider 2D 항목 안의 Edit Collider 버튼을 클릭해서 초록색 박스 영역(콜라이더 영역)을 조절한다.

몬스터보다 살짝 작거나 같게 지정한다.

tile1.png 파일을 하단 프로젝트 뷰의 Sprites 폴더 안으로 드래그 앤 드롭한다.

Add Component 로 Collider 2D를 넣는다.

그러면 몬스터가 타일 위에 착지할 것이다.

몬스터 :  RigidBody(2D), Collider 2D 추가

타일 : Collider 2D 추가

* 트리거 충돌

콜리전 충돌과 다르게 충돌해도 지나간다. 충돌했는지 여부만 체크한다.

Box Collider 2D 항목 안의 Is Trigger 체크박스에 체크를 한다.

———-

2-4. Prefab

Prefab[프리팹]

동일한 몬스터를 하나의 맵에 여러 번 출력되도록 하려면 프리팹을 쓴다.

– Prefab은 프로젝트 전체에서 사용할 수 있는 Object들의 “틀”임.

– Prefab을 사용해 Scene에 배치한 Object는 Prefab의 특성을 똑같이 가진 복제품이라 생각할 수 있음.

– 어떤 작업을 수행할 때 그 대상이 Object냐 Prefab이냐는 아주 큰 차이가 있음.

* 오브젝트의 수정 : 다른 오브젝트나 프리팹은 바뀌지 않는다.

* 오브젝트를 수정한 후 프리팹에 적용 : 다른 오브젝트들이 영향을 받아 바뀐다.

ex) 모든 용들의 체력을 증가시킨다. 공격력을 증가시킨다.

– 혼란을 방지하기 위해 가급적 다른 이름을 사용하거나, 폴더를 따로 생성해서 관리하는게 일반적임.

(1) 하단의 타일을 좌우로 늘린다.

(2) 몬스터를 새로 만든다. 크기는 scale 0.3 x 0.3

(3) Collider 2D 를 추가해준다. 크기를 몬스터 크기에 딱 맞게 조절한다.

(4) Assets 폴더 안에 Prefabs 폴더 생성

(5) 몬스터를 Prefabs 폴더 안으로 드래그 앤 드랍한다. (하이어라키 뷰에서 프로젝트 뷰로 드래그 앤 드랍)

이후, 화면에 놓인 몬스터를 고친다고 해도 프리팹은 영향을 받지 않는다.

우측 Inspector 에서 Prefab 항목 [Revert]를 클릭하면 현재 오프젝트 수정분이 롤백되고 프리팹과 동일하게 바뀐다.

우측 Inspector 에서 Prefab 항목 [Apply]를 클릭하면 현재 오브젝트가 프리팹에 반영된다.

———-

2-5. Variable & Data Type (1)

변수와 자료형 공부

자료형 : 어떤 종류의 값을 담을지 결정하는 통의 모양

변수 : 내가 사용하기 위해 만든 실제 통

값 : 그 실제 통에 담은 내용물

int myAge = 27;

string myName = “김철수”;

기본 자료형

int : 정수 자료형 (3, 0, -35, 289 등)

string : 문자열 자료형 (“김철수”, “산”, “아나콘다” 등)

float : 실수 자료형 (0.2, -7.8, 15.0 등)

bool : true 혹은 false (true, false)

(1) C# 스크립트를 생성한다. 파일명은 VariableTest

(2) 하단 타일에 드래그 앤 드랍한다.

public class VariableTest : MonoBehaviour {

    int test_int = 27;

    string test_string = “김철수”;

    float test_float = 10.7f;

    bool test_bool = true;

 // Use this for initialization

 void Start () {

        test_string = “나는 잘생겼다.”;

        Debug.Log(“test_int : ” + test_int);

        Debug.Log(“test_string : ” + test_string);

        Debug.Log(“test_float : ” + test_float);

        Debug.Log(“test_bool : ” + test_bool);

    }

 

 // Update is called once per frame

 void Update () {

        Debug.Log(“test_string : ” + test_string);

    }

}

———-

2-6. Variable & Data Type (2)

public class VariableTest : MonoBehaviour {

   

    int test_int = 50;

    // Use this for initialization

    void Start () {

        int test_int = 5;

        // 5가 찍힌다.

        Debug.Log(“Start : ” + test_int);

    }

    // Update is called once per frame

    void Update () {

        // 50이 찍힌다.

        Debug.Log(“Update : ” + test_int);

    }

}

[Oracle] ORA-28040: 일치하는 인증 프로토콜 없음

[Oracle] ORA-28040: 일치하는 인증 프로토콜 없음 

DB 연결 중 오류가 발생할 경우, ojdbc14.jar 대신 ojdbc6.jar 또는 ojdbc7.jar 를 추가한다.

JDK 1.6 을 사용한다면 ojdbc6.jar 파일을, JDK 1.7 을 사용한다면 ojdbc7.jar 파일을 사용하면 된다.

ex) /프로젝트경로/webapp/WEB-INF/lib/ojdbc14.jar 파일을 제거하고 같은 위치에 ojdbc6.jar 파일 추가

참고사이트 : https://cofs.tistory.com/352

[Unity] Unity 기초강의 내용 정리 (0-0강 ~ 1-5강)

[Unity] Unity 기초강의 내용 정리 (0-0강 ~ 1-5강)

다시 Unity를 공부해보기로 마음먹었음.

educast 나동빈 님의 <Mobile Defence Game 제작으로 배우는 Unity 기초> 강의를 듣고 내용 정리.

0-0강 : Unity 소개 및 개발환경 구축하기

1-1강 ~ 1-5강 : Part 1. Unity와 친해지기

———-

유니티 0-0강 : 유니티 소개 및 개발환경 구축하기

유니티 허브 : 다양한 게임 프로젝트 버전 관리

cf) 깃 허브, 도커 허브

Visual Studio 설치하라고 하면 무조건 설치할 것

유니티 2018 : 모노 디벨롭 지원을 끊고, Visual Studio 로 개발하도록 환경 채택

C# : 마이크로소프트에서 지원하는 개발언어

(1) Scripts 폴더를 만든다.

마우스 우클릭 – Create – Folder

(2) 그 안에 Example 이라는 C# 스크립트 파일을 만든다.

마우스 우클릭 – Create – C# Script

(3) void Start () {} 내용 안에

Debug.Log(“Hello World”);

라고 적는다.

(4) Example 파일을 마우스로 끌어다가 [Main Camera] 에 드래그 앤 드랍한다.

재생 버튼을 눌러 실행하면 콘솔에 Hello World 가 찍힌다.

———-

유니티 1-1강 : 오브젝트와 컴포넌트

유니티에서 아주 중요한 개념.

오브젝트 : 사물. 객체. (몬스터, 캐릭터, 건물 등) 게임 화면에서 보이는 것, 들리는 것은 전부 오브젝트라고 할 수 있음.

컴포넌트 : 오브젝트를 구성하는 기능. (공격, 이동, Object의 위치, 상태 정보 등)

오브젝트는 컴포넌트를 담는 그릇과도 같은 역할을 하기 때문에,

오브젝트를 컨테이너라고도 한다.

오브젝트는 껍데기이고, 컴포넌트는 껍데기를 채우는 내용물이다.

용 (오브젝트) – 불을 뿜는 기능 (컴포넌트)

사람 (오브젝트) – 달리는 기능 (컴포넌트)

건물 (오브젝트) – 건물이 공격을 받아 파괴당하는 기능 (컴포넌트)

씬 : 화면

화면에 보이는 몬스터 캐릭터 : 오브젝트임

하나의 오브젝트가 가지고 있는 모든 기능을 컴포넌트라고 보면 됨.

———-

유니티 1-2강 : 프로젝트 뷰와 씬 뷰

Assets[어쎗츠] : 게임을 만들기 위한 자산. 모든 재료들을 총칭. 이미지 파일, 소스 파일 등을 담는 폴더임.

Scenes[씬즈] : 로딩 화면, 엔딩 화면, 스테이지 1과 스테이지 2 등. 씬은 오브젝트와 컴포넌트

프로젝트 뷰 패널 : 어쎗츠와 씬즈를 관리하는 패널.

패키지 파일 : 게임 개발을 위한 여러 개의 파일을 하나로 묶어 저장하고 불러올 수 있는 파일임.

(패키지 파일을 프로젝트 뷰에 드래그 앤 드랍을 하면 임포트할지 선택 가능)

 

프로젝트 뷰에 게임에 사용되는 파일들을 체계적으로 관리하는 습관 중요. 대형 프로젝트의 경우 폴더 관리 중요함.

ex) Audios, Scenes, Scripts, Sprites

1. 씬 만들기

[File] – [New Scene]

Untitled 라는 씬이 생김.

프로젝트 뷰의 Sprites 폴더의 Monster 1 이미지 파일을 중앙 회색 화면(씬 뷰)로 드래그 앤 드랍해보자.

오브젝트를 생성(배치)하는 가장 간단한 방법임.

2. 씬 저장

[File] – [Save Scene As…] – 원하는 이름으로 저장 (ex : Scene0)

이러한 씬들이 여러 개 모여서 하나의 프로젝트(게임)을 완성하게 된다.

3. 이번 시간 요약

Project View : 프로젝트에서 사용될 모든 파일을 관리할 수 있는 View. 아래 쪽에 보이는 뷰임.

Scene View : 한 Scene에서 사용되는 Object들을 실제로 배치하는 View.

———-

유니티 1-3강 : 하이어라키 뷰와 인스펙터 뷰

하이어라키 뷰 : 좌측 상단에 표시되는 뷰. 하나의 씬 내부에서 사용되는 오브젝트들을 생성 및 관리하는 뷰임.

오브젝트를 하이어라키 뷰 안에서 관리할 수 있음. 우클릭해서 Delete 할 수도 있고, Rename 할 수도 있다.

하이어라키 뷰에서 오브젝트를 생성할 수도 있음. 하이어라키 뷰에서 마우스 우클릭해서 Create Empty 하면 됨.

이 때 게임을 실행하면 아무것도 표시되지 않음. 빈 오브젝트에 스프라이트 렌더러라는 컴포넌트를 추가해줘야 함.

빈 오브젝트를 클릭하고 우측의 인스펙터 뷰를 보자.

인스펙터 뷰에는 Transform 컴포넌트만 보일 것임. 어떠한 오브젝트라도 가지고 있는 기본 컴포넌트임.

Add Component 라는 버튼을 클릭하자.

영어로 Sprite Renderer 를 검색하여 더블클릭.

Sprite Renderer 상단의 Sprite 항목의 우측 O 버튼을 클릭 후 Assets 탭을 누르면 스프라이트 이미지 설정 가능.

(ex : 몬스터1 이미지)

2D 게임을 만들기 위해서는 트랜스폼 컴포넌트의 X 값과 Y 값을 조절하면 된다.

2D 게임이므로 Z 값은 0으로 주도록 한다. 가끔 오브젝트가 안보일 때가 있는 때 보통 트랜스폼 컴포넌트의 Z 값을 잘못 건드린 경우가 많다.

Scale 항목의 X, Y 값을 0.5 로 바꾸면 크기가 줄어든다.

시간날 때 Rotation 값도 바꿔보자.

1. 레이어 개념 (Sorting Layer와 Order in Layer)

두 개의 몬스터 오브젝트의 트랜스폼 컴포넌트 X와 Y값을 둘 다 0 으로 잡혔을 때

Sprite Renderer 의 Order in Layer 값을 조절하면 레이어 순서 바꾸기 가능.

Order in Layer 값이 크면 위에 있다고 보면 된다.

Sorting Layer 항목 콤보박스 클릭 – [Add Sorting Layer…] – 작은 [+] 버튼 클릭

– 원하는 레이어 이름 쓰고 엔터 (ex : Monster Layer)

Sorting Layer 를 기준으로 먼저 정렬이 이루어지고,

동일한 Sorting Layer 안에서는 Order in Layer 값을 기준으로 정렬이 이루어진다.

2. 이번 시간 요약

Hierarchy View : 한 Scene 내부에서 사용되는 Object 들을 생성 및 관리하는 View

Inspector View : 한 Object에서 사용되는 Component 들을 관리하는 View

———-

유니티 1-4강 : 씬 뷰 조작과 게임 뷰

1. 좌측상단 버튼

Q W E R T Y 단축키 => 유니티 좌측상단 버튼에 대응

Q : 핸드 툴. (손바닥 모양)

마우스나 키보드를 통해서 씬을 살펴볼 수 있음.

W : 무브 툴. (십자 화살표 모양)

오브젝트를 클릭하고 초록색 세로 선과 빨간색 가로 선이 나옴.

파란색 박스를 이용하면 자유자재로 이동 가능.

E : 로테이트 툴 (원형을 이루는 화살표 2개 모양)

동그라미 선과 십자 선 중 클릭한 선을 기준으로 회전이 되는 것을 알 수 있음.

R : 스케일 툴 (사각형 꼭지점 방향으로 화살표 4개 모양)

특정한 오브젝트를 선택해서 그 크기를 변형시킬 수 있음.

T : 렉트 툴 (사각형 안에 사각형 있는 모양)

특정한 오브젝트를 선택해서 사각형 형태로 위치, 크기, 회전을 변경할 수 있는 도구임.

특정한 오브젝트의 대략적인 트랜스폼을 설정하기에 매우 유용함.

나중에 인터페이스를 배울 때 많이 쓰이게 되는 중요 기능임.

Y : 무브/로테이트/스케일 툴

유니티 2018부터 추가된 기능임. 무브, 로테이트, 스케일 등을 모두 사용 가능.

위 툴들로는 대략적인 위치만 잡고, 상세하게는 직접 인풋박스에 입력하는게 좋음.

2. 마우스 휠

휠을 앞으로 굴려서 화면을 크게 보기, 휠을 뒤로 굴려서 화면을 작게 보기

3. 게임 뷰

씬 뷰 : 프로그래머를 위한 전용 뷰

게임 뷰 : 게이머들이 보는 사용자용 뷰

게임 뷰 바로 밑의 설정

Free Aspect를 클릭해서 변경 가능 (ex : Free Aspect => Standalone)

Play : Ctrl + P

4. 리지드바디 개요

리지드바디 2D : 2D 게임용 물리적 법칙 적용

Add Component 로 [Rigidbody 2D] 를 추가한다.

이후 게임을 실행해보면 몬스터가 아래로 떨어진다.

5. 스텝 버튼 사용법

플레이 버튼(Play) 우측의 일시정지 버튼(Pause)을 누른다.

일시정지 우측의 스텝(Step) 버튼을 누르면 시간을 잘게 쪼개서 볼 수 있다.

Step 버튼을 누르다가 다시 Scene 뷰를 가면 게임 진행 도중의 캐릭터 위치 등을 볼 수 있고

게임을 수정할 수도 있다.

6. 이번 시간 요약

Scene View : 한 Scene에서 사용되는 Object들을 실제로 배치하는 View

Game View : 실제 게임 Play 화면을 보여주는 View

———-

유니티 1-5강 : 게임 뷰와 메인 카메라

1. 레이아웃

우측 상단의 Layout : 여러 가지 뷰들을 다양한 형태로 보는 방법.

기본은 Default 임. 2 by 3, 4 Split, Wide 등 레이아웃을 바꿔 볼 수 있음.

탭의 크기를 변경하거나, 아예 새 창으로 떼어낼 수도 있음.

익숙해지면 자기 만의 레이아웃을 만들어도 됨.

2. Main Camera

게임 뷰가 비춰지는 공간 => Main Camera 가 비추는 공간임

씬 뷰에서 하얀색 사각형으로 표시되는 부분 (게임 뷰에서는 하얀색 사각형 보이지 않음)

카메라의 위치에 따라 나타나는 화면이 달라짐

2-1. 배경색 설정

Background 를 하얀색으로 설정해보자

2-2. Projection

Perspective : 보통 3D 게임에서 사용함. Z값에 따라 크기가 달라짐

Orthographic : 2D 게임에서 사용한다고 생각하면 됨.

3. 게임 뷰

3-1. 게임 뷰의 디스플레이 설정

게임 뷰 하단의 Display 1 ~ Display 8

원하는 카메라를 선택하는 것으로 이해하면 됨

2D 게임은 카메라 1개만 존재해도 충분.

3-2. 게임 뷰의 Aspect

다양한 플랫폼(PC, 모바일 등)에서 어떻게 보이는지 확인 가능

[+] 버튼을 클릭해서 임의의 해상도 설정 가능

ex) FHD 1920 x 1080 설정 가능

3-3. Scale

게임 뷰 내의 작은 요소를 자세히 볼 때 사용하면 됨

3-4. Maximize On Play

게임 플레이 시 큰 화면으로 보이게 하기

3-5. Mute Audio

게임 플레이 시 모든 소리 끄기 (소리가 안 들릴 경우 이 부분 클릭했는지 확인할 것)

3-6. Stats

게임에 관련된 상태 표시 (FPS, 해상도 등)

3-7. Gizmos

기즈모를 화면에 표시 가능

기즈모란 게임 개발에 도움이 되는 그래픽 요소임

[Android] 안드로이드 앱 종료

[Android] 안드로이드 앱 종료

액티비티를 그냥 finish()할 경우 액티비티가 백그라운드(태스크 리스트)에 남아있는 것을 볼 수 있다.

아래는 백그라운드 남지 않게 깔끔하게 안드로이드 앱 종료 하는 방법.

앱을 완전 종료하는 방법

​moveTaskToBack(true); // 태스크를 백그라운드로 이동
finishAndRemoveTask(); // 액티비티 종료 + 태스크 리스트에서 지우기
android.os.Process.killProcess(android.os.Process.myPid()); // 앱 프로세스 종료

또는

moveTaskToBack(true); // 태스크를 백그라운드로 이동
finishAndRemoveTask(); // 액티비티 종료 + 태스크 리스트에서 지우기

System.exit(0);

만약 안드로이드 빌드 버전이 낮아서 finishAndRemoveTask 에 빨간밑줄이 그어질 경우 다음 코드를 사용한다.

(finishAndRemoveTask(); 부분을 아래 5줄로 대체하면 된다)

if (Build.VERSION.SDK_INT >= 21) {
    finishAndRemoveTask();
} else {
    finish();
}

위의 두 가지 내용을 종합하면 다음과 같다.

private void exitProgram() {
    // 종료

    // 태스크를 백그라운드로 이동
    // moveTaskToBack(true);

    if (Build.VERSION.SDK_INT >= 21) {
        // 액티비티 종료 + 태스크 리스트에서 지우기
        finishAndRemoveTask();
    } else {
        // 액티비티 종료
        finish();
    }

    System.exit(0);
}

메모 : 앱 하나 종료하는 데도 정말 많은 코드들이 있네…

android.os.Process.killProcess(android.os.Process.myPid());

System.runFinalization();

System.exit(0);

finishAffinity() 등등 개발자마다 의견도 다 다르고…

정말 공부 많이 해야겠다.

참고사이트 : https://calvinjmkim.tistory.com/21

https://stackoverflow.com/questions/40802042/using-finishandremovetask-method-of-activity-class-on-api-levels-lower-than-21

[Android] 외부스킴

[Android] 외부스킴

1. 외부스킴

외부스킴은 모바일 브라우저에서 특정 주소를 호출하면 원하는 앱을 실행시킬 수 있는 방법이다.

모바일에 해당 앱이 설치되어 있어야 한다.

2. AndroidManifest.xml 에 외부스킴 정의

intent-filter 태그 안에 data 태그를 작성한다.

<data android:scheme=”스킴명” android:host=”호스트명” />

ex) <data android:scheme=”test” android:host=”launch” />

<!-- URL scheme -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="test" android:host="launch" />
</intent-filter>

3. 모바일 브라우저에서 주소 호출

모바일 브라우저에서 아래 주소를 호출한다.

intent://호스트명#Intent;scheme=스킴명;package=패키지명;end

ex) <a href=”intent://launch#Intent;scheme=test;package=com.test.android.packageName;end”>test://launch</a>

참고사이트 : https://black-jin0427.tistory.com/99

[JAVA] HttpURLConnection 예제

[JAVA] HttpURLConnection 예제


import java.io.IOException;

import java.io.InputStream;

import java.io.OutputStream;

import java.net.HttpURLConnection;

import java.net.URL;

import java.net.URLEncoder;

import java.util.Enumeration;

import java.util.Hashtable;

public class TestHttpUtil {

    public String postHttp(String urlString, Hashtable param, String encoding) throws Exception {

        StringBuffer paramBuffer = new StringBuffer();

        if (param != null) {

            Enumeration keys = param.keys();

            while (keys.hasMoreElements()) {

                Object objKey = keys.nextElement();

                if (objKey == null) {

                    continue;

                }

                String strKey = String.valueOf(objKey);

                Object objValue = param.get(strKey);

                if (objValue == null) {

                    objValue = “”;

                }

                String strValue = String.valueOf(objValue);

                strValue = URLEncoder.encode(strValue, “UTF-8”);

                

                if (paramBuffer.length() > 0) {

                    paramBuffer.append(“&”).append(strKey).append(“=”).append(strValue);

                } else {

                    paramBuffer.append(strKey).append(“=”).append(strValue);

                }

            }

        }

        return postHttp(urlString, paramBuffer.toString(), encoding);

    }

    

    

    public String postHttp(String urlString, String parameters, String encoding) throws Exception {

        if (encoding == null || encoding.length() == 0) {

            encoding = “UTF-8”;

        }

        HttpURLConnection ucon = null;

        String retVal = null;

        OutputStream os = null;

        java.io.DataOutputStream wr = null;

        InputStream is = null;

        try {

            URL url = new URL(urlString);

            ucon = (HttpURLConnection) url.openConnection();

              ucon.setConnectTimeout(1000);
              ucon.setReadTimeout(2000);

            ucon.setRequestMethod(“POST”);

            ucon.setDoOutput(true);

            ucon.setUseCaches(false);

            ucon.setRequestProperty(“Accept-Language”, encoding);

            ucon.setRequestProperty(“connection”, “Keep-Alive”);

            ucon.setRequestProperty(“cache-control”, “no-cache”);

            ucon.setRequestMethod(“POST”);

            os = ucon.getOutputStream();

            

            wr = new java.io.DataOutputStream(os);

            wr.writeBytes(parameters);

            wr.flush();

            wr.close();

            int status = ucon.getResponseCode();

            if (status >= HttpURLConnection.HTTP_OK || status < HttpURLConnection.HTTP_MULT_CHOICE) {

                is = ucon.getInputStream();

                StringBuffer buf = new StringBuffer();

                int c = 0;

                while ((c = is.read()) != -1) {

                    buf.append((char) c);

                }

                retVal = buf.toString();

                retVal = new String(retVal.getBytes(“iso-8859-1”));

            }

            ucon.disconnect();

        } catch (Exception e) {

            throw e;

        } finally {

            try {

                if (is != null) {

                    is.close();

                }

            } catch (IOException e) {

            } catch (Exception e) {

            }

            try {

                if (wr != null) {

                    wr.close();

                }

            } catch (IOException e) {

            } catch (Exception e) {

            }

            try {

                if (os != null) {

                    os.close();

                }

            } catch (IOException e) {

            } catch (Exception e) {

            }

            try {

                if (ucon != null) {

                    ucon.disconnect();

                }

            } catch (NullPointerException e) {

            } catch (Exception e) {

            }

        }

        return retVal;

    }

    

    

    public static void main(String[] args) {

        try {

            Hashtable param = new Hashtable();

            param.put(“param1”, “12345”);

            param.put(“param2”, “test”);

            param.put(“param3”, “<tag>한글값</tag>”);

            TestHttpUtil testHttpUtil = new TestHttpUtil();

            String result = testHttpUtil.postHttp(http://it-archives.com/, param, “UTF-8”);

            

            System.out.println(result);

        } catch (Exception e) {

            e.printStackTrace();

        }

    }

}

———-

위 코드는 쏘는 쪽 코드이다. 받는 쪽 jsp에는

request.setCharacterEncoding( “UTF-8” );
response.setContentType(“text/html; charset=UTF-8”);

코드를 포함하는 것이 좋다.

[Android] EditText 객체 포커스, 키보드 표시, 키보드 숨김

[Android] EditText 객체 포커스, 키보드 표시, 키보드 숨김

안드로이드에서 EditText 객체에 editText.requestFocus(); 를 했는데 포커스가 가지 않는 것처럼 보였다. 알고보니 포커스는 이동했는데 키보드가 보이지 않았던 것이었다.

사용자가 EditText 객체를 클릭하면 포커스도 잡히고 키보드도 보이는데, requestFocus 코드로 포커스를 줬을 때는 키보드를 보여주는 코드를 따로 추가해줘야 하는 것 같다… 이런 말도 안되는…

1. EditText 객체 포커스
private EditText editText;

editText = (EditText) findViewById(R.id.messageText);
editText.requestFocus();

2. 키보드 표시
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);

imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, InputMethodManager.HIDE_IMPLICIT_ONLY);

3. 키보드 숨김
InputMethodManager immhide = (InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE);

immhide.toggleSoftInput(InputMethodManager.HIDE_IMPLICIT_ONLY, 0);

참고사이트 : https://ellordnet.tistory.com/28

 

[ORACLE] ORA-28001: the password has expired

[ORACLE] ORA-28001: the password has expired

오라클 패스워드가 만료된 경우다.

system 계정으로 로그인하고, 아래 쿼리를 수행하면 된다.

— 유저명, 만료일, 계정상태 조회
SELECT USERNAME, EXPIRY_DATE, ACCOUNT_STATUS FROM DBA_USERS;

— 새 패스워드 설정
ALTER USER 유저명 IDENTIFIED BY 새패스워드;

ex) ALTER USER user_id IDENTIFIED BY new_password;

암호가 만료되지 않도록 하려면 아래 쿼리를 수행하면 된다.

— 현재 기본 프로필 조회
SELECT RESOURCE_NAME, LIMIT FROM DBA_PROFILES WHERE PROFILE=’DEFAULT’;

— 암호가 만료되지 않도록 기본 프로필 수정
ALTER PROFILE DEFAULT LIMIT PASSWORD_LIFE_TIME UNLIMITED;

참고사이트 : https://offbyone.tistory.com/118

[Xcode] The linked library ‘파일명’ is missing one more architectures required by this target: arm64.

[Xcode] The linked library ‘파일명’ is missing one more architectures required by this target: arm64.

Xcode 에서 아래 오류 메시지가 발생하는 경우

The linked library ‘파일명’ is missing one more architectures required by this target: arm64.

ex) The linked library ‘libraryName.a’ is missing one more architectures required by this target: arm64.

해결방안

(1) 해당 라이브러리가 (ex : libraryName.a) 필수적이지 않은 경우, General – Frameworks, Libraries, and Embedded Content 에서 해당 라이브러리를 제거하는 방법도 있다.

(2) 해당 라이브러리가 필수적이라면, Build Settings 에서 Architectures 에서 arm64 항목을 제거한다.

참고사이트 : https://yenos.tistory.com/entry/tipxcode-511-missing-required-architecture-arm64-error

[IOS] 애플 아이폰 이중인증 켜는 방법

[IOS] 애플 아이폰 이중인증 켜는 방법
이중인증 켜기

https://wingsnote.com/179 

[TOMCAT] 톰캣 기동 안되는 경우

[TOMCAT] 톰캣 기동 안되는 경우

대충 쓰는 트러블 슈팅. 기억나는대로.

1. 톰캣 기동 안될 경우. catalina.out 로그를 긁어서 보는게 답이다. 로그를 복사해서 구글에 붙여넣어 검색하자.

2. 톰캣 다른 포트에서는 기동되는데 80 포트에서 기동안되는 경우. 다른 사용자 말고 루트(root)로 기동하면 된다. 1024 포트까지는 루트로 기동해야 한다고 함.

3. 포트 80으로 맞추고 root 로 접속했는는데도 톰캣 기동 안되는 경우. java -version 을 확인하자. 자바 버전이 낮으면(톰캣과 맞지 않으면) JAVA_HOME 을 정의하자. 예를 들어 export JAVA_HOME=/home/java/jdk1.6 을 .bash_profile 또는 톰캣 내의 setclasspath.sh 상단에 넣자. .bash_profile 을 고쳤다면 source .bash_profile 해서 적용하는걸 잊지말자.

만약 이렇게 해도 자바 버전이 잘 잡히지 않는다면(java -version 했는데 잘못된 버전 그대로라면) PATH 앞쪽에 자바경로 와 자바경로/bin 을 넣자. 예를 들면 export PATH=/home/java/jdk1.6:/home/java/jdk1.6/bin:$PATH 이런식으로. 그리고 나서 java -version 하면 원하는 버전이 나와야하고 톰캣이 기동되어야 한다.

4. 타회사 시스템이 자사 시스템(WAS, 톰캣)과 연동해서 값을 가져가는데 어떤 URL을 요청하는지 모를 경우 톰캣의 accees.log 를 보자. tail -f 걸어놓고 테스트 해보면 어떤 URL 요청하는지 다 찍힌다.

5. 다 안된다면 항목 1번을 기억하자. 로그에 답이 있다.

[JAVA] ExceptionConverter: java.io.IOException: The document has no pages.

[JAVA] ExceptionConverter: java.io.IOException: The document has no pages. 

ExceptionConverter: java.io.IOException: The document has no pages.
 at com.itextpdf.text.pdf.PdfPages.writePageTree(PdfPages.java:113)
 at com.itextpdf.text.pdf.PdfWriter.close(PdfWriter.java:1214)
 at com.itextpdf.text.pdf.PdfDocument.close(PdfDocument.java:768)
 at com.itextpdf.text.Document.close(Document.java:398)

자바에서 itextpdf-5.3.3.jar (com.itextpdf.text.pdf.PdfWriter) 로 PDF 생성시 비어있는 도큐먼트 객체(com.itextpdf.text.Document)를 닫는 경우 (document.close()) 발생하는 오류다.

오류를 방지하려면 document.add(new Chunk(“”)); 를 사용해서 빈 페이지를 만들어주면 된다. (com.itextpdf.text.Chunk)

예를 들면 아래와 같이 코딩하면 된다.

StringReader strReader = new StringReader(html);
List<Element> objects = HTMLWorker.parseToList(strReader, styles, interfaceProps);

if (objects != null && objects.size() > 0) {
    int objectCount = objects.size();
    for (int i=0; i<objectCount; i++) {
        document.add((Element)objects.get(i));
    }
} else {

    // IOException: The document has no pages 방지
    document.add(new Chunk(“”));
}

document.close();

참고사이트 : https://stackoverflow.com/questions/6816195/exceptionconverter-java-io-ioexception-the-document-has-no-pages-am-using-ite

[Javascript] createTextRange is not a function

[Javascript] createTextRange is not a function

오타가 난게 아니라면 크롬에서는 createTextRange() 함수가 지원되지 않는다.

아래와 같이 createRange 를 사용해야 한다.

if (document.selection) { //IE
    range = document.body.createTextRange();
    range.moveToElementText(document.getElementById(containerid));
    range.select();

 
} else if (window.getSelection) { //others
    range = document.createRange();
    range.selectNode(document.getElementById(containerid));
    window.getSelection().addRange(range);

}

[Javascript] 자바스크립트 텍스트 검색

[Javascript] 자바스크립트 텍스트 검색

var findIndex = -1;
var textRange = document.body.createTextRange();
if (textRange != null) {
    for (var i=0; textRange.findText(“검색어”); i++) {
        if (textRange.offsetLeft > 0) {

            // 찾은 검색어를 노란색 음영처리
            textRange.execCommand(“BackColor”, true, “yellow”);
    
            findIndex++;
    
            // 첫번째 찾은 검색어를 블록지정
            if (findIndex == 0) {
                textRange.select();
            }

        }

​        textRange.collapse(false);
    }
}​

[ORACLE] 오라클 제약조건 셀렉트 SQL

[ORACLE] 오라클 제약조건 셀렉트 SQL

오라클에서는 아래 SQL로 모든 제약조건을 조회할 수 있다.

SELECT * FROM all_constraints;

제약조건 이름을 알면 다음과 같이 조회 가능하다.

SELECT * FROM all_constraints WHERE constraint_name = ‘SYS_C00120925’;

특정 테이블의 제약조건은 다음과 같이 조회 가능하다.

SELECT * FROM all_constraints WHERE table_name =’특정테이블명’;

윈도우 프로세스 실행시간 가져오기 (wmic process get)

윈도우 프로세스 실행시간 가져오기 (wmic process get)

일반적으로 윈도우에서 프로세스 목록을 가져오기 위해서는 cmd 에서 tasklist 라는 명령어를 사용한다.

1. tasklist

그러나 이것으로 프로세스 아이디(PID)는 얻을 수 있어도, 프로세스를 실행한 시간은 알 수 없다.

프로세스를 실행한 시간을 알기 위해서는 wmic process get 명령어를 사용한다.

2. wmic process get processid,caption,creationdate,ThreadCount | findstr exe

위 명령어를 통해 프로세스 아이디(processid)와 실행을 시작한 시간(creationdate), 쓰레드 카운트(ThreadCount) 등을 알 수 있다.

참고로 윈도우에서 process 를 kill 하기 위해서는…

taskkill /f /im 종료할_프로그램 .exe

또는

taskkill /f /im 종료할_프로그램_프로세스_아이디

를 사용하면 된다.

/f 를 안넣으면 그 프로그램에 종료 신호를 보내고 넣으면 강제 종료한다.

3. wmic 사용 시 findstr 을 사용하지 않는 방법

where name=”이름”을 사용하면 된다.

ex) wmic process where name=”notepad.exe” get processid,caption,creationdate,ThreadCount

4. wmic 사용 시 원하는 포맷으로 변경하는 방법

예를 들어 구분자를 탭이 아닌 쉼표로 바꾸고 싶은 경우, 명령어 뒤쪽에 /format:csv 를 붙이면 된다.

ex) wmic process where name=”notepad.exe” get processid,caption,creationdate,ThreadCount /format:csv

xml 형식은 명령어 뒤쪽에 /format:xml 을 붙이면 된다.

ex) wmic process where name=”notepad.exe” get processid,caption,creationdate,ThreadCount /format:xml

그 외에도 다음과 같은 포맷들이 있다. (출처 : https://www.vanstechelman.eu/windows/wmic/output_formats)

CSV
HFORM
HMOF
HTABLE
HXML
LIST
RAWXML
TABLE
VALUE
htable-sortby
htable-sortby.xsl
texttablewsys
texttablewsys.xsl
wmiclimofformat
wmiclimofformat.xsl
wmiclitableformat
wmiclitableformat.xsl
wmiclitableformatnosys
wmiclitableformatnosys.xsl
wmiclivalueformat
wmiclivalueformat.xsl

[JAVA] e.printStackTrace() 결과 아무 내용도 없는 경우 (stacktrace length 0, stacktrace is null)

[JAVA] e.printStackTrace() 결과 아무 내용도 없는 경우 (stacktrace length 0, stacktrace is null)

지난주 금요일 모 사이트 운영에서 NullPointerException 오류가 나서 jsp 단에서 stackTrace를 찍어봤더니 아무것도 찍히지가 않았다.

다시 jsp 를 수정해서 length 를 찍어봤는데 (e.getStackTrace().length) 값이 0 으로 나왔다.

stackTrace 의 길이가 0 이라니… 구글에 아무리 검색해도 그런 현상은 나오지 않았다.

(stacktrace length is zero, stacktrace length 0 등)

로컬에서는 재현이 되지 않아서 운영 클래스를 몽땅 긁어가져와서 로컬환경에 붙여넣기했다.

그리고 나서 이클립스에서 디버그를 탔더니 아래처럼 나왔다.

NullPointerException 인데 stackTrace 는 null !

아니 stackTrace 가 null?

운영에서는 length 를 찍었을 때 0이라고 찍혔는데… (null 인 객체의 length를 찍을 경우 또 다시 NullPointerException이 발생해야 정상이다)

stackTrace가 null 이든 length 0 이든 이해가지 않는 상황인건 분명했다.

(참고로 저 cause 는 찍어봤자 맹탕이다. 똑같이 stackTrace 는 null 이다)

 

문제가 된 부분은 아래 코드 (그림의 1449라인).

whereValue 벡터의 첫번째 요소가 null 이다.

다시 말해 아래 1499 라인 코드는

null.getClass().getName(); 이 된 것이다.

이 경우 NullPointerException 이 발생하는 건 이해하지만 stackTrace는 존재해야 정상이다.

아무래도 일종의 자바 버그로 보인다.

제네릭이 존재하지 않는 Vector의 요소가 null 인 경우, 그 요소의 클래스를 가져오려고 시도하면(getClass()) stackTrace가 없는 NullPointerException 이 발생하는 것 같다.

개발하다보니 별 이상한 오류를 다 본다…

stackTrace가 비어있는 Exception 이 발생했다고 얘기하면 (또 그 상황을 계속 재현할 수 있다고 하면) 아무도 안 믿을듯…


 

[JAVA] ArrayList 정렬하기 (ArrayList sort)

[JAVA] ArrayList 정렬하기 (ArrayList sort)

자바에서 ArrayList 를 오름차순으로 정렬하려면 Collections.sort 명령어를 사용하면 된다.

ArrayList<String> tempList = new ArrayList<String>();

tempList.add(“테스트3”);

tempList.add(“테스트4”);

tempList.add(“테스트2”);

tempList.add(“테스트1”);

tempList.add(“abcdefg”);

tempList.add(“0123456789”);

// 리스트를 오름차순으로 정렬

Collections.sort(tempList);

System.out.println(tempList);

결과는 아래와 같이 나온다.

[0123456789, abcdefg, 테스트1, 테스트2, 테스트3, 테스트4]

ArrayList를 오름차순이 아닌 다른 조건으로 정렬하려면 Comparator 인터페이스를 사용하면 된다.

// Comparator 인터페이스를 구현하여 리스트를 정렬

Collections.sort(tempList, new Comparator<String>() {

    @Override
    public int compare(String o1, String o2) {
        return 0;
    }

});

compare 메서드를 구현(임플리먼트)할 때, 0 을 리턴하면 순서가 바뀌지 않는다.

정확히 설명하면 두 값이 같다면 0을 반환하고, 첫 번째 값이 크다면 양수(1)를, 두 번째 인자가 크다면 음수(-1)를 반환하면 된다.

compare 메서드 안에 원하는 조건식을 넣으면 된다.

위 코드처럼 무조건 0 을 리턴하면 순서가 바뀌지 않은 상태 그대로이다.

만약 ArrayList 의 제네릭이 String이 아닌 경우라면 (ex : ArrayList<Integer>) 아래와 같이 제네릭 타입만 바꿔주면 된다.

// Comparator 인터페이스를 구현하여 리스트를 정렬

Collections.sort(tempList, new Comparator<Integer>() {

    @Override
    public int compare(Integer o1, Integer o2) {
        return 0;
    }
});

예를 들어 제네릭이 Integer 인 ArrayList의 내림차순 정렬은 아래처럼 한다.

ArrayList<Integer> tempList = new ArrayList<Integer>();

tempList.add(1);
tempList.add(5);
tempList.add(7);
tempList.add(5);
tempList.add(99);
tempList.add(-200);

// 리스트를 내림차순으로 정렬
Collections.sort(tempList, new Comparator<Integer>() {

    @Override
    public int compare(Integer o1, Integer o2) {
        // 순서를 바꾼다.
        if (o1 < o2) {
            return 1;
        } else {

            return -1;

        }
    
        return 0;
    }
});
  
System.out.println(tempList);

결과는 아래와 같다.

[99, 7, 5, 5, 1, -200]

관련글: [JAVA] 제네릭이 String 인 ArrayList 정렬하기 (ArrayList sort / String sort) (https://blog.naver.com/bb_/222033828409)

The import 패키지명.클래스명 collides with another import statement

The import 패키지명.클래스명 collides with another import statement

jsp 작성시 The import collides with another import statement 오류가 나는 경우.

예를 들어 The import com.test.MyTestUtil collides with another import statement 이런 식의 오류가 나는 경우.

“collides”는 충돌하다 라는 뜻이므로, 해당 클래스가 이미 임포트 되어있다고 볼 수 있다.

즉 jsp 상단 어딘가에 <%@page import=”com.test.MyTestUtil”%> 이 들어있거나,

인크루드(include)된 jsp 페이지 안에 <%@page import=”com.test.MyTestUtil”%> 이 들어있을 것이다.

임포트 라인을 1개만 남기고 나머지를 제거하면 오류가 해결된다.

참고페이지 : https://sabjili.tistory.com/entry/The-import-collides-with-another-import-statement-%EB%9D%BC%EB%8A%94-%EC%97%90%EB%9F%AC

[javascript] 자바스크립트 달력 요일 가져오기

[javascript] 자바스크립트 달력 요일 가져오기

// 특정 연월의 첫날(1일) 날짜 객체 가져오기 

function getFirstDateObjFromMonth(_year, _month) {
    _year = parseInt(_year, 10);
    _month = parseInt(_month, 10);
    _month = _month – 1;
    
    var firstDateObj = new Date(_year, _month, 1);
    return firstDateObj;
}

// 특정 연월의 마지막날 날짜 객체 가져오기
function getLastDateObjFromMonth(_year, _month) {
    _year = parseInt(_year, 10);
    _month = parseInt(_month, 10);
    _month = _month;
    
    var lastDateObj = new Date(_year, _month, 0);
    return lastDateObj;
}

// 날짜텍스트 가져오기 (ex : 20200101)
function getDateText(_dateObj) {
    if (_dateObj == null) {
        _dateObj = new Date();    
    }
    
    var dd = _dateObj.getDate();
    var mm = _dateObj.getMonth() + 1; // January is 0!
    var yyyy = _dateObj.getFullYear();
    
    if (dd < 10) {
        dd = “0” + dd;
    }
    
    if (mm < 10) {
        mm = “0” + mm;
    }

    return (yyyy + “” + mm + “” + dd); 

}

// 요일텍스트 가져오기. 문자열 리턴. SUN ~ SAT
function getYoilText(_dateObj) {
    if (_dateObj == null) {
        _dateObj = new Date();    
    }
    
    var yoilValue = _dateObj.getDay();
    var week = new Array(“SUN”, “MON”, “TUE”, “WED”, “THU”, “FRI”, “SAT”);
    
    var yoilText = week[yoilValue];
    return yoilText;
}

// 요일값 가져오기. 숫자 리턴. 0(SUN)~ 7(SAT)
function getYoilValue(_dateObj) {
    if (_dateObj == null) {
        _dateObj = new Date();    
    }
    
    var yoilValue = _dateObj.getDay();
    return yoilValue;
}

공인인증서 위치 / 공인인증서 폴더경로

공인인증서 위치 / 공인인증서 폴더경로

요새 정부사이트에 ActiveX가 제거되어 공인인증서 위치를 알아야할 필요성이 생겼다.

폴더 경로를 찾아들어가 직접 공인인증서를 선택해서 첨부하는 경우(연말정산)가 있고, 공인인증서를 브라우저로 드래그앤드랍 해야하는 경우(정부24)도 있다.

하드디스크 내의 공인인증서 위치는 다음과 같다.

참고로 yessign 공인인증서의 위치이다.

C:\Users\[사용자계정명]\AppData\LocalLow\NPKI\yessign\USER
ex) C:\Users\bbmon\AppData\LocalLow\NPKI\yessign\USER

[javascript] 자바스크립트 윈도우 창 가로크기, 세로크기 계산 (window.innerWidth, window.innerHeight)

[javascript] 자바스크립트 윈도우 창 가로크기, 세로크기 계산 (window.innerWidth, window.innerHeight)

자바스크립트에서 윈도우 창의 가로크기는 window.innerWidth, 세로크기는 window.innerHeight 로 가져온다.

그런데 IE 버전이 낮거나 html 의 에뮬레이트 버전이 낮은 경우 해당 변수를 사용할 수 없을 때가 있다.

그러므로 브라우저 영향을 덜 받도록 다음과 같이 계산한다.

1. 자바스크립트 윈도우 창 가로크기 계산

var winWidth = “”;
if (window.innerWidth != null) {
    winWidth = window.innerWidth + “”;
} else if (window.document != null && window.document.documentElement != null && window.document.documentElement.clientWidth != null) {
    winWidth = window.document.documentElement.clientWidth + “”;
} else if (window.document != null && window.document.body != null && window.document.body.offsetWidth != null) {
    winWidth = window.document.body.offsetWidth + “”;
}

결과값은 “10px” 처럼 문자열 형태로 리턴된다. 순수한 숫자를 얻고 싶다면 문자열 “px”를 떼고 parseInt를 적용해야 한다. (함수 getNumberFromPixel)

2. 자바스크립트 윈도우 창 세로크기 계산

var winHeight = “”;
if (window.innerHeight != null) {
    winHeight = window.innerHeight + “”;
} else if (window.document != null && window.document.documentElement != null && window.document.documentElement.clientHeight != null) {
    winHeight = winWidth = window.document.documentElement.clientHeight + “”;
} else if (window.document != null && window.document.body != null && window.document.body.offsetHeight != null) {
    winHeight = window.document.body.offsetHeight + “”;
}

결과값은 “10px” 처럼 문자열 형태로 리턴된다. 순수한 숫자를 얻고 싶다면 문자열 “px”를 떼고 parseInt를 적용해야 한다. (함수 getNumberFromPixel)

위 코드에 이어서 쓸 수 있는 함수로는 getNumberFromPixel 이 있다.

https://blog.naver.com/bb_/221781978397

[javascript] doGetElementsByClassName (getElementsByClassName 가 정의되어 있지 않을 때 사용)

[javascript] doGetElementsByClassName (getElementsByClassName 가 정의되어 있지 않을 때 사용)

IE 버전이 낮은 경우 getElementsByClassName 가 정의되어 있지 않을 때가 있다.

이 때 getElementsByClassName 대신 doGetElementsByClassName 를 직접 구현하여 사용한다.

실제 IE 버전이 높아도, htm 페이지의 에뮬레이트 버전이 낮게 설정되어 있으면 해당 함수를 쓸 수 없다.

참고로 getElementsByClassName 는 IE 9.0 이상부터 지원한다.

// getElementsByClassName 가 정의되어 있지 않을 때 사용
function doGetElementsByClassName(_tagArr, _className) {
    if (_tagArr == null || _tagArr.length == 0) {
        return null;
    }
   
    if (_className == null || _className == “”) {
        return null;
    }
   
    _className = _className + “”;
   
    var resultArr = [];
   
    var tagCnt = _tagArr.length;
    for (var k=0; k<tagCnt; k++) {
        var strTagName = _tagArr[k];
        if (strTagName == null || strTagName == “”) {
            continue;
        }
       
        var elemArr = window.document.getElementsByTagName(strTagName);
        if (elemArr != null && elemArr.length > 0) {
            var elemCnt = elemArr.length;
            for (var i=0; i<elemCnt; i++) {
                if (elemArr[i] != null && elemArr[i].className == _className) {
                    resultArr[resultArr.length] = elemArr[i];
                }
            }
        }
    }
   
    return resultArr;
}

예를 들어 아래와 같이 사용한다.

var elems = null;
if (typeof(document.getElementsByClassName) != “undefined”) {
    elems = document.getElementsByClassName(“tempClassName”);
} else {
    var tagArr = [“iframe”, “div”];
    elems = doGetElementsByClassName(tagArr, “tempClassName”);

}

[javascript] getNumberFromPixel (픽셀값에서 숫자값만 가져오기)

[javascript] getNumberFromPixel (픽셀값에서 숫자값만 가져오기)

// 픽셀값에서 숫자값만 가져온다.
// ex) “10px” => 10
function getNumberFromPixel(_px) {
    if (_px == null || _px == “”) {
        return 0;
    }
   
    _px = _px + “”;
   
    if (_px.indexOf(“px”) > -1) {
        _px = _px.replace(“px”, “”);
    }
   
    if (_px.indexOf(“PX”) > -1) {
        _px = _px.replace(“PX”, “”);
    }
   
    var result = parseInt(_px, 10);
    if ((result + “”) == “NaN”) {
        return 0;
    }
   
    return result;
}

[JAVA] ORA-01460: unimplemented or unreasonable conversion requested​

[JAVA] ORA-01460: unimplemented or unreasonable conversion requested​ 

classes12.jar 또는 ojdbc?.jar가 이전버전일 경우 발생하는 오류라고 한다.

개인적으로 classes12.jar 와 ojdbc14.jar 파일이 함께 임포트되어 있는 경우였는데,
classes12.jar 를 제거하였더니 오류가 사라졌다.

다음 포스트를 참고하여 해결하였음.

https://blog.naver.com/yysvip/220102972783

[iOS] 아이폰 개발 맥에서 CSR 파일 만들기

[iOS] 아이폰 개발 맥에서 CSR 파일 만들기

CSR은 Cert Signing Request 의 약자, 인증서 서명요청이라는 뜻이다.

CSR은 간단하게 말하면 인증서 발급을 위한 신청서다.

인증서라고 보기는 어렵고, 인증서 발급을 위해 필요한 것이다.

이 CSR 이라는게 상당히 헷갈리는 요소다.

왜 이렇게 복잡한지 모르겠지만, 인증서 발급을 할 때 [신청서 발급 신청] -> [신청서 발급됨] -> [신청서로 인증서 발급 신청] -> [인증서 발급됨] 과정을 거쳐야 한다.

CSR 파일은 키체인 접근 메뉴에서 만들 수 있다.

키체인 접근 아이콘을 더블클릭하거나, 응용프로그램 -> 기타 -> 키체인 접근을 선택한다.

이어서 상단 메뉴의 키체인 접근 -> 인증서 지원 -> 인증 기관에서 인증서 요청을 선택한다.

출처 : https://khstar.tistory.com/entry/iOS-%EC%95%B1-%EA%B0%9C%EB%B0%9C%EC%9D%84-%EC%9C%84%ED%95%9C-%EC%9D%B8%EC%A6%9D%EC%84%9C-%EC%83%9D%EC%84%B1-%EB%B0%8F-%EA%B4%80%EB%A6%AC

[Android] 안드로이드 프로젝트에 aar 파일 추가하기

[Android] 안드로이드 프로젝트 aar 파일 추가하기
aar은 라이브러리(jar)까지 포함한 안드로이드 프로젝트 묶음이다.
사실 aar은 압축 파일이므로 확장자를 zip으로 바꾸고 압축 해제할 경우 정상적으로 압축이 풀린다.
1. libs 폴더 안에 aar 파일을 붙여넣는다.
libs 폴더가 보이지 않는다면 아래 그림처럼 안드로이드 스튜디오 좌측 상단의 콤보박스 값을 [Project]로 수정후 libs 폴더를 찾아본다.
이 과정이 중요한데, 반드시 aar 파일을 libs 폴더 안에 붙여넣고 아래 과정을 진행한다.
만약 기존 라이브러리를 교체하는 상황이라면, 기존 라이브러리를 삭제하고 아래 과정을 진행하도록 한다.
2. build.gradle 파일을 수정한다. 파일명이 aar_file_name.aar 일 경우 아래와 같이 수정한다.
[AS-IS]

dependencies {
    implementation fileTree(include: [‘*.jar’], dir: ‘libs’)
    implementation ‘com.android.support:multidex:1.0.1’
    implementation ‘com.android.support:support-annotations:24.2.0’
    implementation ‘com.android.support:appcompat-v7:23.4.0’
    implementation ‘com.google.code.gson:gson:2.8.2’
}

[TO-BE]

// aar 라이브러리 사용을 위함

repositories {
    flatDir {
        dirs ‘libs’
    }
}

dependencies {
    implementation fileTree(include: [‘*.jar’], dir: ‘libs’)
    implementation ‘com.android.support:multidex:1.0.1’
    implementation ‘com.android.support:support-annotations:24.2.0’
    implementation ‘com.android.support:appcompat-v7:23.4.0’
    implementation ‘com.google.code.gson:gson:2.8.2’

    // aar 라이브러리 사용을 위함
    implementation(name: ‘aar_file_name’, ext: ‘aar’)
}

 

참고링크 : https://woochan-dev.tistory.com/7

[파워포인트 2007] PPT 창 여러 개 띄우기

[파워포인트 2007] PPT 창 여러 개 띄우기

C:\Program Files (x86)\Microsoft Office\Office12 폴더 안의 PPCORE.DLL 파일을 첨부한 압축파일 내의 PPCORE.DLL 파일로 바꾼다(덮어쓴다).

단, 오류 발생할 경우에 대비해 덮어쓰기 전에 기존 파일 백업은 필수.

[Spring] Unable to determine Dialect to use [name=Oracle, majorVersion=12]

[Spring] Unable to determine Dialect to use [name=Oracle, majorVersion=12]

스프링 프로젝트 기동시 “Unable to determine Dialect to use [name=Oracle, majorVersion=12]” 오류가 나는 경우.

정확하게는 스프링 오류가 아니라 하이버네이트 오류.

org.springframework.beans.factory.BeanCreationException: Error creating bean with name ’em’ defined in file [C:\[특정폴더경로]\context-transaction.xml]: Invocation of init method failed; nested exception is javax.persistence.PersistenceException: Unable to build EntityManagerFactory

(중략)

Caused by: javax.persistence.PersistenceException: Unable to build EntityManagerFactory

(중략)

Caused by: org.hibernate.HibernateException: Unable to determine Dialect to use [name=Oracle, majorVersion=12]; user must register resolver or explicitly set ‘hibernate.dialect’

이 때 context-transaction.xml 파일 내의 hibernate.dialect 값을 org.hibernate.dialect.Oracle10gDialect 로 변경 후 재기동해보니 잘 된다.

참고링크 : https://stackoverflow.com/questions/41323894/hibernate-cannot-determine-dialect

[Javascript] 오늘날짜 가져오기

[Javascript] 오늘날짜 가져오기

function getTodayDate() {
    var today = new Date();
    var dd = today.getDate();
    var mm = today.getMonth() + 1; // January is 0!
    var yyyy = today.getFullYear();

    if (dd < 10) {
        dd = “0” + dd;
    }

    if (mm < 10) {
        mm = “0” + mm;
    }

 

    return (yyyy + “” + mm + “” + dd);

}

[Javascript] onbeforeunload 호출되지 않는 문제

[Javascript] onbeforeunload 호출되지 않는 문제

window.onload = function(){} 은 당연히 동작, 그런데 window.onbeforeunload = function(){} 이 동작하지 않는 문제.

스크립트 오류가 발생한 것도 아니고, 함수를 잘못된 방식으로 오버라이딩(function window.onbeforeunload(){}) 한 것도 아니었다.

PC 특성인가 싶어서 로컬에 깨끗한 새 html 파일을 만들어 열고 닫았더니 onbeforeunload가 잘 호출된다. 그렇다면 무엇이 문제일까. PC가 문제가 아니라면 페이지의 문제.

PC환경은 윈도우 7 그리고 IE 9 이었다. meta 태그의 content=”IE=EmulateIE8″ 을 브라우저 버전에 맞게 content=”IE=9″로 바꿔주었더니 onbeforeunload가 잘 호출된다.

또 다른 경우. 어떤 페이지는 창이 닫힐 때 onbeforeunload가 잘 동작했는데 쇼모달을 띄웠다가 끄고 창을 닫았더니 동작하지 않았다. 해당 페이지는 content=”IE=9″이 맞았는데, 쇼모달로 띄운 페이지가 content=”IE=5″라고 되어있었다. 이것을 9으로 맞춰주니 잘 되는 것을 확인함. 단, 백 퍼센트 확실하다고는 할 수 없고 우연일 가능성 있음.

참고로 윈도우 7, IE 9 환경에서 페이지 메타태그에 content=”IE=8″이 적혀 있는 경우일지라도, 호환성 보기가 설정되어 있다면 onbeforeunload가 동작한다. 다시 말해 잘 되던 사용자가 안된다고 연락이 온다면 기존에 있던 호환성 보기 설정이 빠졌을 확률이 높다.

[JAVA] JFrame 윈도우 포커싱, 최소화되어 있는 창 복원

[JAVA] JFrame 윈도우 포커싱, 최소화되어 있는 창 복원

// 윈도우 표시
this.setVisible(true);

JFrame 창을 표시할 때 일반적으로 위 코드를 사용한다.

그런데 해당 코드는 JFrame 창을 새로 띄우는 경우 창이 나타나지만, 윈도우가 최소화 되어있는 경우 창이 나타나지 않는다.

따라서 아래와 같이 코딩한다.

// 최소화되어 있을 경우 윈도우 복원
if (this.getState() == Frame.ICONIFIED) {
    this.setState(Frame.NORMAL);
}
  
// 윈도우 표시
this.setVisible(true);
  
// 윈도우 포커싱
if (this.getFocusableWindowState()) {
    this.requestFocus();
}

이제 창이 최소화 되어있거나 포커스를 잃어버린 경우에도 창을 보여준다.

[Eclipse] eclipse validation off (이클립스 validation 끄기, validation 끄는 방법)

[Eclipse] eclipse validation off (이클립스 validation 끄기, validation 끄는 방법)

이클립스 validation 때문에 느린 경우. 그냥 끄면 된다.

소스파일 하나 고칠 때마다 이클립스 밸리데이션이 시작되는 통에 개발을 할 수가 없다.

모든 프로젝트가 그런 것은 아니고 특정 프로젝트만 그러한데 이유는 모르겠다.

다음은 validation 체크를 끄는 방법이다.

1. 이클립스 상단메뉴의 [Window] – [Preferences] 를 클릭한다.

 

2. Preferences 창이 뜨면 좌측 메뉴의 [Validation] 클릭, 우측에 보이는 [Build] 컬럼의 모든 체크박스를 해제한다.

[Manual] 컬럼은 수동으로 validation 을 체크할 수도 있으므로 그대로 둔다.

하단의 [Apply and Close] 버튼을 클릭한다.

 

 

3. [The validation settings have changed. A full rebuild is required for the changes to take effect. Do the full build now?] 메시지가 뜨면 [No] 버튼을 클릭하여 거절한다. 또 밸리데이션을 하겠다는 소리다.

 

4. 분명 Validation 을 껐는데 마지막으로 아래 그림처럼 Validation 을 진행한다면, 정지 버튼(빨간색 사각형)을 마구 눌러서 Validation 을 강제로 중지시키자.


참고사이트 : https://start.goodtime.co.kr/2013/06/%EC%83%88-%EC%9D%B4%ED%81%B4%EB%A6%BD%EC%8A%A4%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%A0-%EB%95%8C-%EB%82%98%EC%9D%98-5%EB%B6%84-%EC%84%A4%EC%A0%95/