반응형

안녕하세요. 

이전시간에 안드로이드와 Firebase와 연결을 해보았습니다.

이번에는 안드로이드 스튜디오에서 Firebase의 Database를 연동해서 DB 데이터 저장 및 로드를 해보도록 하겠습니다.

일단 Database 추가를 위해서 Firebase colsole으로 들어갑니다.

 

 

 

로그인 - Google 계정

하나의 계정으로 모든 Google 서비스를 Google 계정으로 로그인

accounts.google.com

 

추가한 프로젝트를 클릭합니다.

왼쪽에 Firestore Database와 Realtime Database가 있는데, 저는 Realtime Database로 셋팅해보겠습니다.

"Realtime Database"를 클릭합니다.

Firestore Database와 Realtime Database의 차이가 궁금하시다면, 다음 페이지를 참조하시면 될 것 같습니다.

https://firebase.google.com/docs/database/rtdb-vs-firestore?authuser=0 

 

데이터베이스 선택: Cloud Firestore 또는 실시간 데이터베이스  |  Firebase

Firebase는 실시간 데이터 동기화를 지원하며 클라이언트에서 액세스할 수 있는 2가지 클라우드 기반 데이터베이스 솔루션을 제공합니다. Cloud Firestore는 모바일 앱 개발을 위한 Firebase의 최신 데이

firebase.google.com

 

데이터베이스 만들기를 클릭합니다.

 

대한민국은 없기때문에 Default인 미국으로 설정하고 다음을 클릭합니다.

 

테스트를 하기위해서 테스트 모드에서 시작으로 변경해주고 사용설정을 클릭해줍니다.

잠시 기다리면 데이터베이스를 추가할 수 있는 창이 생성되었습니다.

 

이제 안드로이드 스튜디오에서 관련 코드를 넣습니다.

다음 코드로 데이터베이스를 얻어옵니다.

DatabaseReference m_Database;

m_Database = FirebaseDatabase.getInstance().getReference();

 

저장은 다음과 같은 코드로 넣습니다.

                        m_Database.child("child1").child("child2").child("child3").setValue("child3 저장할데이터")
                        .addOnSuccessListener(new OnSuccessListener<Void>() {
                            @Override
                            public void onSuccess(Void aVoid) {
                                // 저장 성공 시 처리
                            }
                        })
                        .addOnFailureListener(new OnFailureListener() {
                            @Override
                            public void onFailure(@NonNull Exception e) {
                                // 저장 실패 시 처리
                            }
                        });

                       

로드는 다음과 같은 코드로 할 수 있습니다.

ValueEventListener postListener = new ValueEventListener() {
            @Override
            public void onDataChange(DataSnapshot dataSnapshot) {
                // 데이터를 불러올 때 처리
                int nCount = (int)dataSnapshot.getChildrenCount();
                String name;
                for (DataSnapshot postSnapshot: dataSnapshot.getChildren()) {
                  // 저장된 데이터를 하나씩 얻어옵니다.
                    if(postSnapshot.child("child3").getValue(String.class) != null) {

                        name = postSnapshot.child("child3").getValue(String.class);
                    }

                }
            }

            @Override
            public void onCancelled(DatabaseError databaseError) {
                // 데이터 불러오기 실패 시 처리
            }
        };
       // child3으로 정렬합니다.
        Query sortbyAge = m_Database.child("child1").orderByChild("child3");
        sortbyAge.addListenerForSingleValueEvent(postListener);

 

실제적으로 안드로이드 스튜디오에서 적용은 다음과 같이합니다.

MainActivity.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
package com.Testcompany.test;
 
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
 
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Toast;
 
import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.Query;
import com.google.firebase.database.ValueEventListener;
 
import java.util.ArrayList;
 
public class MainActivity extends AppCompatActivity {
    private DatabaseReference m_Database;
    EditText m_edittext1;
    Button m_button1;
    ListView m_listview;
    int m_nCount = 0;
    ArrayList<String> m_arritems;
    ArrayAdapter m_adapter;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        m_Database = FirebaseDatabase.getInstance().getReference();
        m_edittext1 = findViewById(R.id.edit1);
        m_button1 = findViewById(R.id.button1);
        m_listview =findViewById(R.id.listview1);
 
        m_arritems = new ArrayList<String>() ;
        m_adapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, m_arritems);
 
 
        m_listview.setAdapter(m_adapter);
 
        readUser();
 
        m_button1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                String data1 = m_edittext1.getText().toString();
 
                m_Database.child("users").child("Data"+m_nCount).child("username").setValue(data1)
                        .addOnSuccessListener(new OnSuccessListener<Void>() {
                            @Override
                            public void onSuccess(Void aVoid) {
                                Toast.makeText(MainActivity.this"저장 성공.", Toast.LENGTH_SHORT).show();
                                readUser();
                                m_edittext1.setText("");
                            }
                        })
                        .addOnFailureListener(new OnFailureListener() {
                            @Override
                            public void onFailure(@NonNull Exception e) {
                                Toast.makeText(MainActivity.this"저장 실패.", Toast.LENGTH_SHORT).show();
                            }
                        });
 
            }
 
        });
 
 
    }
 
 
    private void readUser(){
        ValueEventListener postListener = new ValueEventListener() {
            @Override
            public void onDataChange(DataSnapshot dataSnapshot) {
                m_arritems.clear();
                m_nCount = (int)dataSnapshot.getChildrenCount();
                String name;
                for (DataSnapshot postSnapshot: dataSnapshot.getChildren()) {
                    if(postSnapshot.child("username").getValue(String.class!= null) {
                        name = postSnapshot.child("username").getValue(String.class);
                        m_arritems.add(name);
                    }
                }
                m_adapter.notifyDataSetChanged();
            }
 
            @Override
            public void onCancelled(DatabaseError databaseError) {
                Log.w("FirebaseDatabase","onCancelled", databaseError.toException());
            }
        };
        Query sortbyAge = m_Database.child("users").orderByChild("users");
        sortbyAge.addListenerForSingleValueEvent(postListener);
 
    }
}
cs

activity_main.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
 
    <EditText
        android:id="@+id/edit1"
        android:layout_width="189dp"
        android:layout_height="70dp"
        android:layout_marginEnd="36dp"
        android:layout_marginRight="36dp"
        android:layout_marginTop="28dp"
        android:ems="10"
        android:inputType="textPersonName"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.236"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
 
    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="44dp"
        android:text="Button"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.861"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
 
    <ListView
        android:id="@+id/listview1"
        android:layout_width="409dp"
        android:layout_height="300dp"
        android:layout_marginTop="104dp"
        app:layout_constraintTop_toTopOf="parent"
        tools:layout_editor_absoluteX="1dp" />
</androidx.constraintlayout.widget.ConstraintLayout>
cs

 

 

반응형
반응형

오늘은 안드로이드 스튜디오와 Firebase를 연동하는 방법에 대해 알려드리도록 하겠습니다.

과정은 다음과 같습니다.

1. Firebase Colsole에서 Firebase 프로젝트 만들기

firebase 콘솔에 접속한 후 구글아이디로 로그인합니다.

 

로그인 - Google 계정

하나의 계정으로 모든 Google 서비스를 Google 계정으로 로그인

accounts.google.com

이 페이지에서 일단 프로젝트를 추가해줘야합니다. 

프로젝트 추가를 클릭합니다.

프로젝트 이름을 지정한 후 "계속" 버튼을 클릭합니다.

Google 애널리틱스 를 사용할지를 정한 후 계속 버튼을 클릭합니다.

애널리틱스 계정을 선택합니다. 

계정이 따로 없다면, Default Account for Firebase로 설정한 후 "프로젝트 만들기" 버튼을 클릭합니다.

프로젝트 생성 중 화면이 나오면 완료될 때 까지 기다립니다.

기다리면, 새 프로젝트가 준비되었다고 나옵니다.

"계속" 버튼을 클릭합니다.

 

프로젝트 창으로 이동하게 되는데, 여기서는 어떤 플랫폼에서 사용할지 지정할 수 있습니다.

안드로이드 모양 버튼을 클릭합니다.

Android 패키지 이름, 앱 닉네임(선택), 디버그 서명 인증서 SHA-1(선택)을 입력해야합니다.

Android 패키지 이름은 처음에 안드로이드 스튜디오에서 프로젝트 만들때 지정된 패키지 이름을 넣습니다.

MainActivity.java파일에서 바로 확인가능합니다.

앱 닉네임, 디버그 서명 인증서 SHA-1은 넣습니다.

"앱등록" 버튼을 누릅니다.

"google-services.json 다운로드" 버튼을 누릅니다.

설명과 같이 다운로드 받은 google-services.json을 프로젝트의 app에 넣어줍니다.

이제 안드로이드 스튜디오와 Firebase를 연결을 해야합니다.

build.gradle파일을 수정해야합니다.

앱수준의 build.gradle, 프로젝트 수준의 build.gradle을 수정해야합니다.

밑에 이미지에서는 1번이 앱수준의 build.gradle, 2번이 프로젝트 수준의 build.gradle입니다.

1번 앱 수준의 build.gradle은 다음과 같이 추가가 되어야합니다.

2번 프로젝트 수준의 build.gradle은 다음과 같이 추가가 되어야합니다.

 

이 후 동기화를 합니다.

 

이제 Firebase 콘솔에서 설정은 끝났습니다.

 

이제 연결을 확인합니다.

안드로이드 스튜디오 메뉴에서 Tool-Firebase를 클릭합니다.

Firebase 메뉴가 나옵니다.

저는 실시간 디비를 통해 연결을 확인해보도록 하겠습니다.

3번째 Realtime Database를 클릭해봅니다.

Save and retrieve data가 생깁니다. 클릭합니다.

 

다음과 같은 화면이 나옵니다.

1, 2번이 모두 체크가 되어야 합니다.

2번은 아직 체크가 안되었기 때문에 Add to Realtime Database to your app을 클릭합니다.

클릭하면 메세지 박스가 하나 뜹니다. app/build.gradle파일에 database 관련 라이브러리 관련 구문을 추가하겠냐고 물어봅니다.

Accept Changes를 클릭합니다.

잠시 기다리면 "Dependencies set up correctly"로 변경된 것을 볼 수 있습니다.

안드로이드 스튜디오에서 Firebase와 연결되었습니다.

반응형
반응형

안녕하세요.

코딩을 하다 보면 시간에 관련된 함수를 많이 사용하게 됩니다.

항상 구글링으로 찾아보았었는데, 이번 기회에 한번 정리해봅니다.

공통으로 헤더 파일은 time.h를 포함시켜줘야 합니다.

 

time

현재시간을 time_t로 리턴합니다.

함수 원형

time_t time(time_t*  _Time);

반환형도 있고, 리턴 값도 있습니다. 리턴 값으로 받아도 되고, 파라미터에 time_t변수의 포인트를 넘겨서 받을 수도 있습니다.

time_t는 32비트 플랫폼에서는 long으로 64비트 플랫폼에서는 __int64로 typedef 되어 있습니다.

예제

1
2
3
4
5
6
7
8
9
10
11
12
13
#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS
#endif
 
#include <stdio.h>
#include <time.h>
 
void main()
{
    time_t t = 0;
    t = time(NULL);        // time(&t);로 해도 같습니다.
    printf("%lld\n", t);
}
cs

 

localtime

time_t타입을 이용해서 tm구조체로 만듭니다.

tm구조체는 멤버 변수로 년, 월, 날, 시간, 분, 초가 있어서 현재시간을 명확하게 알 수 있게 해 줍니다.

 

함수 원형

struct tm * localtime(const time_t * _Time)

예제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS
#endif
 
#include <stdio.h>
#include <time.h>
 
void main()
{
    struct tm* pTimeInfo;
    time_t t = time(NULL);
    pTimeInfo = localtime(&t);
 
    int year = pTimeInfo->tm_year + 1900;    //연도에는 1900 더해줌
    int month = pTimeInfo->tm_mon + 1;    // 월에는 1 더해줌
    int day = pTimeInfo->tm_mday;
    int hour = pTimeInfo->tm_hour;
    int min = pTimeInfo->tm_min;
    int sec = pTimeInfo->tm_sec;
 
    printf("%d-%.2d-%.2d %.2d:%.2d:%.2d\n", year, month, day, hour, min, sec);
}
cs

asctime

tm 구조체를 읽어 들여서 Www Mmm dd hh:mm:ss yyyy 형식으로 스트링 리턴합니다.

함수 원형

char * asctime(_In_ const struct tm * _Tm);

예제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS
#endif
 
#include <stdio.h>
#include <time.h>
void main()
{
    struct tm* pTimeInfo;
    time_t t = time(NULL);
    pTimeInfo = localtime(&t);
 
    printf("%s", asctime(pTimeInfo));
}
cs

 

gmtime

time_t를 파라미터로 받아 UTC 시간을 리턴합니다.

함수 원형

struct tm * gmtime(const time_t * _Time)

예제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS
#endif
 
#include <stdio.h>
#include <time.h>
 
void main()
{
    struct tm* pTimeInfo;
    time_t t = time(NULL);
    pTimeInfo = gmtime(&t);
 
    int year = pTimeInfo->tm_year + 1900;    //연도에는 1900 더해줌
    int month = pTimeInfo->tm_mon + 1;    // 월에는 1 더해줌
    int day = pTimeInfo->tm_mday;
    int hour = pTimeInfo->tm_hour;
    int min = pTimeInfo->tm_min;
    int sec = pTimeInfo->tm_sec;
 
    printf("UTC %d-%.2d-%.2d %.2d:%.2d:%.2d\n", year, month, day, hour, min, sec);
    hour = hour + 9;
    if (hour >= 24)
    {
        day++;
        hour -= 24;
    }
        
    printf("KST %d-%.2d-%.2d %.2d:%.2d:%.2d\n", year, month, day, hour, min, sec);
}
cs

 

mktime

tm구조체를 이용해서 time_t타입으로 만듭니다.

함수 원형

time_t mktime(struct tm * _Tm)

예제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS
#endif
 
#include <stdio.h>
#include <time.h>
 
void main()
{
    struct tm* pTimeInfo;
    time_t t1 = time(NULL);
    pTimeInfo = localtime(&t1);
 
    pTimeInfo->tm_mday = pTimeInfo->tm_mday + 7;
 
    time_t t2 = mktime(pTimeInfo);
 
    printf("time : %d\n", t1);
    printf("7 days later %d\n", t2);
    printf("t2-t1 : %d\n", t2 - t1);
}
cs

현재 시간과 7일 후 시간의 차를 계산해보는 예제입니다.

1분을 초로 변환하면 60 

시간을 초로 변환하면 60 X 60 = 3,600

하루를 초로 변환하면 60 X 60 X 24= 86,400

7일을 초로 계산하면 60 X 60 X 24 X 7= 604,800

 

기타로 mktime함수를 실제로 구현해보았습니다.

특정 시간 time_t로 지정한 후 tm구조체에 넣은 후 다시 time_t로 변경해보았습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS
#endif
 
#include <stdio.h>
#include <time.h>
 
 
int GetMinToSec(int nMin);
int GetHourToSec(int nHour);
int GetDayToSec(int nDay);
int GetMonthToSec(int nMonth);
int GetYearToSec(int nYear);
void main()
{
    time_t t;
    struct tm* pTimeInfo;
    //t = time(NULL);
    t = 1620716583;
    pTimeInfo = localtime(&t);
 
    int year = pTimeInfo->tm_year + 1900;    //연도에는 1900 더해줌
    int month = pTimeInfo->tm_mon + 1;    // 월에는 1 더해줌
    int day = pTimeInfo->tm_mday;
    int hour = pTimeInfo->tm_hour;
    int min = pTimeInfo->tm_min;
    int sec = pTimeInfo->tm_sec;
 
    time_t nTime = sec + GetMinToSec(min) + GetHourToSec(hour - 9+ GetDayToSec(day) + GetMonthToSec(month - 1+ GetYearToSec(year - 1970);
 
    printf("%d-%.2d-%.2d %.2d:%.2d:%.2d\n", year, month, day, hour, min, sec);
    printf("%lld", nTime);
}
 
int GetMinToSec(int nMin)
{
    return nMin * 60;
}
int GetHourToSec(int nHour)
{
    return nHour * 3600;    // nHour * 60 * 60
}
int GetDayToSec(int nDay)
{
    return nDay * 86400;        // nDay * 60 * 60 * 24
}
int GetMonthToSec(int nMonth)
{
    int nMonthDay[12= { 312831303130313130313031 };    // Number of days per month
 
    int nMonthDayCount = 0;
 
    for (int i = 0; i < nMonth; i++)
        nMonthDayCount += nMonthDay[i];
 
    return nMonthDayCount * 86400;    // nMonthDayCount * 60 * 60 * 24
}
 
int GetYearToSec(int nYear)
{
    int nAddDay = nYear / 4;
 
    return  GetMonthToSec(12* nYear + nAddDay * 86400;    // GetMonthToSec(12) * nYear + nAddDay * 60 * 60 * 24
}
cs

지정한 1620716583과 같은 값이 출력되는 것을 확인할 수 있습니다.

반응형
반응형

안녕하세요.

오늘은 하이라이키(Hierarchy)에서 순위 변경하는 방법에 대해 알아보도록 하겠습니다.

UI 등 같은 위치에 겹치게 되면 하이라이키(Hierarchy)의 나중에 있는 게 더 위로 나옵니다.

물론 순서를 바꾸면, 순위를 바꿀 수 있습니다.

하지만, 실행 중에 변경하려면 스크립트를 이용해야 합니다.

스크립트에서 다음 함수를 사용할 수 있습니다.

Transform.SetAsLastSibling
해당 오브젝트의 순위를 마지막으로 변경(가장 나중에 출력되므로 겹쳐졋을 경우 앞으로 나옵니다.)

Transform.SetAsFirstSibling
해당 오브젝트의 순위를 처음으로 변경(가장 처음 출력되므로 겹쳐졋을 경우 가려집니다.)

Transform.SetSiblingIndex(int nIndex)
nIndex를 매개변수를 넣어서 순위를 지정합니다.(0이 처음입니다.)

Transform.GetSiblingIndex()
해당 오브젝트의 순위를 얻어옵니다.

 

예제

일단 이미지 오브젝트를 생성하고, blue, red로 지정하겠습니다.

그리고 스크립트가 들어갈 오브젝트를 하나 만듭니다.(ScriptObject)

스크립트에 다음과 같이 입력하면 현재 오브젝트의 순위값을 알 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class GameManger : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        GameObject goRed = GameObject.Find("Canvas/red");
        GameObject goBlue = GameObject.Find("Canvas/blue");
 
        Debug.Log("goRed : " + goRed.transform.GetSiblingIndex());
        Debug.Log("goBlue : " + goBlue.transform.GetSiblingIndex());
    }
}
 
cs

출력값은 다음과 같습니다.

빨간 사각형이 나중에 나오기 때문에 1로 표기 되었습니다.

순위를 변경할 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class GameManger : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        GameObject goRed = GameObject.Find("Canvas/red");
        GameObject goBlue = GameObject.Find("Canvas/blue");
 
        Debug.Log("before goRed : " + goRed.transform.GetSiblingIndex());
        Debug.Log("before goBlue : " + goBlue.transform.GetSiblingIndex());
 
        goRed.transform.SetSiblingIndex(0);
        Debug.Log("after goRed : " + goRed.transform.GetSiblingIndex());
        Debug.Log("after goBlue : " + goBlue.transform.GetSiblingIndex());
    }
}
cs

출력값

16번째 줄 "goRed.transform.SetSiblingIndex(0);" 대신에 "goRed.transform.SetAsFirstSibling();", "goBlue.transform.SetAsLastSibling();"를 넣으면 같은 결과를 얻을 수 있습니다. 

 

반응형
반응형

안녕하세요.

오늘은 메세지박스에 WCHAR스트링으로 메세지 넣는것에 대해 알아보도록 하겠습니다.

일본어로 메세지박스의 메세지를 넣고 싶었는데, 프로젝트 자체가 이미 "멀티바이트 문자 집합 사용"으로 되어있어서,

일본어가 깨지는 문제가 발생했습니다.(물론 유니코드 문자 집합 사용을 하면 깨지지 않았습니다.)

하지만 이미 많이 진행된 프로젝트이기 때문에 유니코드 문자 집합으로 변경이 어려운 상황이였습니다.

그래서 WCHAR형으로 메세지를 넣으면 되지 않을까해서 찾아보던중,

MessageBoxW로 하면 된다는 걸 알게되었습니다.

WINAPI
MessageBoxW(
    __in_opt HWND hWnd,
    __in_opt LPCWSTR lpText,
    __in_opt LPCWSTR lpCaption,
    __in UINT uType);

lpText, lpCaption를 모두 WCHAR형으로 넣어주면 됩니다.

기본적으로 WINAPI함수입니다. 하지만 MFC에서도 hWnd을 0으로 사용하면 동일하게 사용할 수 있습니다.

예제
MessageBoxW(0, L"再試行してください。", L"Error", MB_OK );

반응형
반응형

안녕하세요.

오늘은 하나의 이미지를 자르는 방법에 대해 알아보도록 하겠습니다.

기본적인 ui image에서는 자르는게 안 되는 것 같습니다.(못 찾았습니다.)

Raw Image를 사용하면 자를 수 있습니다.

Hierarchy에서 UI - Raw Image로 오브젝트를 추가합니다.

Inspector에서 Raw Image 항목의 UV Rect 값을 변경하여 자를 수 있습니다.

X, Y에는 0~1 값이 들어가며, X, Y 자르는 시작 점을 지정할 수 있습니다.

W, H에는 0~1값이 들어가며, 너비와 높이를 지정할 수 있습니다.

좌표계는 다음과 같이 됩니다.

만약에 4등분으로 오른쪽 위를 반으로 자르고 싶다면 다음과 같이 설정하면 됩니다.

 

같은 방식으로 4등분에 X, Y값은 다음과 같이 설정할 수 있습니다.

1.  X : 0, Y : 0.5 (왼쪽 위)

2. X : 0.5, Y : 0.5 (오른쪽 위)

3. X : 0, Y : 0 (왼쪽 아래)

4 X : 0.5 Y 0 (오른쪽 아래)

 

반응형
반응형

안녕하세요.

유니티에서 개발을 하다보면, 투명도를 설정하려면 어떻게 해야할까요?

Inspector에 color에서 설정할 수 있습니다.

color설정창을 열어서 알파값을 변경하면 됩니다.

수치를 낮추면, 더 투명하게 할 수 있습니다.

 

코드로 추가할 수도 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;   // Image class를 사용하기 위해 추가합니다.
 
 
public class CGameManager : MonoBehaviour
{
    void Start()
    {
        GameObject goImage = GameObject.Find("Canvas/Image");
        Color color = goImage.GetComponent<Image>().color;
        color.a = 0.5f;
        goImage.GetComponent<Image>().color = color;
    }
}
cs

0.5f는 255를 기준으로 255 * 0.5 = 127.5 소수점 반올림해서 128을 의미합니다.

반응형
반응형

안녕하세요.

오늘은 문자가 숫자인지를 확인하는 함수에 대해 알아보도록 하겠습니다.

문자가 숫자('0'~'9')인지를 확인하는 함수입니다.

함수 원형
int isdigit(int _C);
_C가 숫자인지를 판별합니다.

헤더파일
ctype.h

리턴값
숫자이면 0이 아닌값을 리턴합니다.( 4를 리턴 합니다)
숫자가 아니면 0을 리턴합니다.

예제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>
#include <ctype.h>
 
void main()
{
    char chString[] = "a1-2+&ZY8b";
    
    for (int i = 0; chString[i] != '\0'; i++)
    {
        if (isdigit(chString[i]))
            printf("digit : %c\n", chString[i]);
        else
            printf("not digit : %c\n", chString[i]);
    }
}
cs

결과

isdigit함수를 사용하지 않고 구현하려면 다음과 같이 구현합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>
#include <ctype.h>
 
void main()
{
    char chString[] = "a1-2+&ZY8b";
        
    for (int i = 0; chString[i] != '\0'; i++)
    {
        if ((chString[i] >= '0' && chString[i] <= '9'))
            printf("digit : %c\n", chString[i]);
        else
            printf("not digit : %c\n", chString[i]);
    }
}
cs
반응형
반응형

안녕하세요.

오늘은 C언어에서 문자가 알파벳이거나 숫자인지 확인하는 함수에 대해 알아보로독 하겠습니다.

문자가 특수문자가 아닌 알파벳('a'~'z', 'A'~'Z')과 숫자('0'~'9')인지를 확인할 때 사용할 수 있습니다.

함수 원형
int isalnum( int _C );
_C가 알파벳이거나 숫자인지를 판별하게 됩니다.


헤더파일
ctype.h


리턴값
알파벳이거나 숫자이면 0이 아닌 값을 리턴합니다.(알파벳 대문자 : 1, 알파벳 소문자 : 2, 숫자 : 4를 리턴합니다.)
알파벳이거나 숫자가 아니면 0을 리턴합니다.

예제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>
#include <ctype.h>
 
void main()
{
    char chString[] = "a1-2+&ZY8b";
    
    for (int i = 0; chString[i] != '\0'; i++)
    {
        if (isalnum(chString[i]))
            printf("alphanumeric : %c\n", chString[i]);
        else
            printf("not alphanumeric : %c\n", chString[i]);
    }
}
cs

 

isalnum함수를 사용하지 않고 직접 구현하려면 다음과 같이 구현하면 됩니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <stdio.h>
#include <ctype.h>
 
void main()
{
    char chString[] = "a1-2+&ZY8b";
        
    for (int i = 0; chString[i] != '\0'; i++)
    {
        if ( (chString[i] >= 'a' && chString[i] <= 'z'
            || (chString[i] >= 'A' && chString[i] <= 'Z'
            || (chString[i] >= '0' && chString[i] <= '9'))
            printf("alphanumeric : %c\n", chString[i]);
        else
            printf("not alphanumeric : %c\n", chString[i]);
    }
}
cs
반응형
반응형

안녕하세요.

C언어에서 문자가 알파벳인지 아닌지 확인해주는 함수에 대해 알아보도록 하겠습니다.

캐릭터명이 알파벳으로만 만들어졌는지 확인할 때 유용합니다.

함수 원형
int isalpha( int _C );
_C가 문자 알파벳인지 판별하게 됩니다.

헤더 파일
ctype.h

리턴값
알파벳이면 0이 아닌 값(true), 대문자는 2, 소문자는 1
알파벳이 아니면 0(false)

예제

간단하게 문자를 하나씩 isalpha함수 파라메터에 넣어서 알파벳인지 판별합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>
#include <ctype.h>
 
void main()
{
    char chString[] = "a-+&b";
    
    for (int i = 0; chString[i] != '\0'; i++)
    {
        if (isalpha(chString[i]))
            printf("alpha : %c\n", chString[i]);
        else
            printf("not alpha : %c\n", chString[i]);
    }
}
cs

 

isalpha함수를 이용하지 않고 직접 구현해볼 수 도 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>
#include <ctype.h>
 
void main()
{
    char chString[] = "a-+&b";
 
    for (int i = 0; chString[i] != '\0'; i++)
    {
        if ((chString[i] >= 'a' && chString[i] <= 'z'|| (chString[i] >= 'A' && chString[i] <= 'Z'))
            printf("alpha : %c\n", chString[i]);
        else
            printf("not alpha : %c\n", chString[i]);
    }
}
cs
반응형
반응형

안녕하세요.

해외 서버를 셋팅하면서 영문(영어) 윈도우가 아닌 다른 언어로 변경해야하는 경우가 종종 있어서 정리해봅니다.

대만 윈도우 서버를 만들기 위해 영문(영어) 윈도우를 중문(중국어)윈도우로 변경해보도록 하겠습니다.

차례는 키입력 추가 한 후 전체적인 윈도우 언어를 변경하는 순서로 하겠습니다.

1. 키입력 추가

변경하려면 시작을 눌러서, "language"를 입력한 후 Language항목을 선택합니다.

 

그 후 나오는 창에서 "Add a language"를 선택합니다.

 

필요한 언어를 찾습니다.

저는 중문(중국어)로 설정하기 위해서 Chinese를 찾아서 선택했습니다.

선택 후 Add 버튼을 누릅니다.

 

키입력이 추가된 것을 확인할 수 있습니다.

 

2. 윈도우 언어변경

 

위에 이어서 Language창에서 왼쪽 아래에있는 Location을 클릭합니다.

클릭하면 Region창이 열립니다.

Home location 리스트 박스에서 Taiwan을 선택합니다.

다음으로 Administrative탭을 선택 후, Change system locale…을 클릭합니다.

Current System locale에서 리스트박스중에 "Chinese (Traditional, Taiwan)" 변경 후 OK버튼을 누릅니다.

재시작하겠냐고 메세지박스가 나오면 "Apply"버튼을 누르고 윈도우를 재시작합니다.

반응형
반응형

안녕하세요

만약 게임에서 몬스터가 랜덤한 위치에 나오게 하거나,
상자를 열었을 경우 랜덤하게 아이템이 나오게 하려면 어떻게 구현을 해야할까요??
오늘은 이러한 경우에 난수(Random)값을 추출하는 함수에 대해 이야기하려고 합니다.

 

rand

함수 원형
int rand();

헤더 파일
stdlib.h

리턴값
0에서 32,767까지 값이 리턴됩니다.
0~RAND_MAX(0~32767) 
RAND_MAX값이 32767(16진수로 0x7fff)로 정의되어있습니다.

예제

1
2
3
4
5
6
7
8
#include <stdio.h>
#include <stdlib.h>
 
void main()
{
    for ( int i = 0; i < 10; i++ )
        printf("%d\n", rand());
}
cs

문제점
예제를 여러번 실행해보면 항상 값이 같다는 것을 확인할 수 있습니다.
프로그램이 실행될 때마다 rand함수 호출 시 다른 값을 호출하기 위해서는 srand함수를 이용해야합니다.

srand

함수 원형
void srand(unsigned int _Seed);

헤더 파일
stdlib.h

리턴값
없습니다.

설명
Seed를 다른 값을 넣어주면 rand호출 시 마다 다른 값을 리턴해줄 수 있습니다.
시드에 상수를 넣어버리면 의미가 없기 떄문에 time함수를 넣어서 시간마다 다른 시드가 들어가도록 합니다.
time함수를 사용하기 위해서는 time.h 헤더파일을 추가해줘야합니다.

예제

1
2
3
4
5
6
7
8
9
10
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void main()
{
    srand((unsigned)time(NULL));
    for ( int i = 0; i < 10; i++ )
        printf("%d\n", rand());
}
 
cs

 

응용하기

1~3 랜덤값 추출하기
rand값에 3으로 나눈 나머지를 구하면 0~2까지 값이 나오고 여기서 1을 더해줍니다.

1
2
3
4
5
6
7
8
9
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void main()
{
    srand((unsigned)time(NULL));
    for ( int i = 0; i < 10; i++ )
        printf("%d\n", rand()%3+1);
}
cs

 

중복값이 없도록 난수 생성

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void main()
{
    srand((unsigned)time(NULL));
    int nResult[10= { 0, };
    int nCount = 0;
    int nNum = 0;
    bool bExist = false;
    while(nCount < 10 )
    {
        bExist = false;
        nNum = rand() % 10 + 1;
        for (int i = 0; i < 10; i++)
        {
            if (nNum == nResult[i])
                bExist = true;
        }
 
        if (!bExist)
        {
            nResult[nCount++= nNum;
        }
            
    }
    for ( int i = 0; i < 10; i++ )
        printf("%d\n", nResult[i]);
}
cs

 

반응형
반응형

안녕하세요.

vecter에서 특정 데이터를 삭제할 때는 erase를 사용합니다.

간단하게 다음과 같이 삭제하면 될거같은데, 에러가 발생합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <stdio.h>
#include <vector>
using namespace std;
 
void main()
{
    vector<int> v;
 
    v.push_back(1);
    v.push_back(2);
    v.push_back(3);
    v.push_back(4);
 
    for (vector<int>::iterator iter = v.begin(); iter != v.end(); ++iter)
    {
        if ( *iter == 3 )
        {
            v.erase(iter);
        }
    }
 
    for (vector<int>::iterator iter = v.begin(); iter != v.end(); ++iter)
    {
        printf("%d\n"*iter);
    }
    printf("size : %d\n", v.size());
}
cs

 

vector 이터레이터(iterator)가 더이상증가할 수 없다고 나옵니다.

 

해결 코드

earse후에 반환되는 이터레이터(iterator)가 있습니다.
erase후 반환 이터레이터(iterator)를 넣어줍니다.

v.erase(iter);

이렇게 변경합니다. iter = v.erase(iter); 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <stdio.h>
#include <vector>
using namespace std;
 
void main()
{
    vector<int> v;
 
    v.push_back(1);
    v.push_back(2);
    v.push_back(3);
    v.push_back(4);
 
    for (vector<int>::iterator iter = v.begin(); iter != v.end(); ++iter)
    {
        if ( *iter == 3 )
        {
            iter = v.erase(iter);
        }
    }
 
    for (vector<int>::iterator iter = v.begin(); iter != v.end(); ++iter)
    {
        printf("%d\n"*iter);
    }
    printf("size : %d\n", v.size());
}
cs

 

이터레이터(iterator)를 사용하지 않는 경우는 다음과 같이 구현합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <stdio.h>
#include <vector>
using namespace std;
 
void main()
{
    vector<int> v;
 
    v.push_back(1);
    v.push_back(2);
    v.push_back(3);
    v.push_back(4);
 
    for (int i = 0; i < v.size(); i++)
    {
        if ( v[i] == 3 )
        {
            v.erase(v.begin()+i);
        }
    }
 
    for (vector<int>::iterator iter = v.begin(); iter != v.end(); ++iter)
    {
        printf("%d\n"*iter);
    }
    printf("size : %d\n", v.size());
}
cs

 

감사합니다.

반응형
반응형

안녕하세요.

오늘은 삽입 정렬 알고리즘에 대해 알아보도록 하겠습니다.

 

삽입 정렬 알고리즘

데이터를 정렬 위치에 맞게 삽입하면서 정렬하는 알고리즘

 

구현 방법

오름차순 기준으로 설명하겠습니다.
두 번째 데이터부터 첫 번째 데이터랑 비교 후 두 번째 데이터가 작다면, 두 값을 스왑 하고,
세 번째 데이터를 첫 번째, 두 번째와 비교 후 세 번째 데이터보다 큰 값이 있다면 값이 하나씩 뒤로 밀리게 됩니다.
이것을 반복합니다.

 

예제

배열 arrData에 100, 20, 10, 12, 5 값이 있다면, 다음과 같이 정렬이 되게 됩니다.


첫 번째 회전
두번째 데이터 arrData[1](20)를 임시 변수에 저장합니다.
임시 변수와 첫 번째 데이터와 비교하면, 임시 변수 데이터인 20이 첫 번째 데이터인 arrData[0](100)보다 작기 때문에 arrData[0]을 arrData[1]로 이동합니다.
그리고 임시 변수에 저장한 값을 arrData[0]에 저장합니다. (20, 100, 10, 12, 5)


두 번째 회전
세 번째 데이터 arrData[2](10)를 임시 변수에 저장합니다.
임시 변수와 두 번째 데이터와 비교하면, 임시변수 데이터인 10이 두 번째 데이터인 arrData[1](100)보다 작기 때문에 arrData[1]을 arrData[2]로 이동합니다.
임시 변수와 첫 번째 데이터와 비교하면, 임시 변수 데이터인 10이 두 번째 데이터인 arrData[0](20)보다 작기 때문에 arrData[0]을 arrData[1]로 이동합니다.
그리고 임시 변수에 저장한 값을 arrData[0]에 저장합니다. (10, 20, 100, 12, 5)


세 번째 회전
네 번째 데이터 arrData[3](12)를 임시 변수에 저장합니다.
임시 변수와 세 번째 데이터와 비교하면, 임시 변수 데이터인 12가 세 번째 데이터인 arrData[2](100)보다 작기 때문에 arrData[2]을 arrData[3]로 이동합니다.
임시 변수와 두 번째 데이터와 비교하면, 임시 변수 데이터인 12가 두 번째 데이터인 arrData[1](20)보다 작기 때문에 arrData[1]을 arrData[2]로 이동합니다.
임시 변수와 첫 번째 데이터와 비교하면, 임시 변수 데이터인 12가 첫 번째 데이터인 arrData[0](10)보다 크기 때문에 이동을 멈춥니다.
임시 변수에 저장한 값을 arrData[1]에 저장합니다. (10, 12, 20, 100, 5)


네 번째 회전
다섯 번째 데이터 arrData[4](5)를 임시 변수에 저장합니다.
임시 변수와 네 번째 데이터와 비교하면, 임시 변수 데이터인 5가 네 번째 데이터인 arrData[3](100)보다 작기 때문에 arrData[3]을 arrData[4]로 이동합니다.
임시 변수와 세 번째 데이터와 비교하면, 임시 변수 데이터인 5가 세 번째 데이터인 arrData[2](20)보다 작기 때문에 arrData[2]을 arrData[3]로 이동합니다.
임시 변수와 두 번째 데이터와 비교하면, 임시 변수 데이터인 5가 두 번째 데이터인 arrData[1](12)보다 작기 때문에 arrData[1]을 arrData[2]로 이동합니다.
임시 변수와 첫 번째 데이터와 비교하면, 임시 변수 데이터인 5가 첫 번째 데이터인 arrData[0](10)보다 작기 때문에 arrData[0]을 arrData[1]로 이동합니다.
임시 변수에 저장한 값을 arrData[0]에 저장합니다. (5, 10, 12, 20, 100)

 

C++ 코드로 구현

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <iostream>
using namespace std;
 
void main()
{
    int arrData[5= { 1002010125 };
    int nTemp;
    int nIndex;
    int nSize = sizeof(arrData) / sizeof(int);
    int j;
    cout << "before : ";
    forint i = 0; i < 5; i++ )
        cout << arrData[i] << " ";
    cout << endl;
 
    forint i = 1; i < nSize ; i++ )
    {
        nTemp = arrData[i];
        for( j = i; j > 0; j-- )
        {
            if( nTemp < arrData[j-1] )
            {
                arrData[j] = arrData[j-1];
                if( j == 1 )
                {
                    arrData[j-1= nTemp;
                    break;
                }
            }
            else
            {
                arrData[j] = nTemp;
                break;
            }
            
        }
        
    }
    cout << "after : ";
    forint i = 0; i < 5; i++ )
        cout << arrData[i] << " ";
    cout << endl;
}
cs
반응형
반응형

안녕하세요.

오늘은 선택 정렬 알고리즘에 대해 알아보도록 하겠습니다.

 

선택 정렬 알고리즘

배열등 리스트에서 배열 위치에 맞게 오름/내림 정렬하는 알고리즘

 

구현 방법


오름차순 기준(제일 작은 값이 앞으로, 제일 큰 값이 뒤로 정렬)으로 설명하면,
첫 번째 데이터를 전체 데이터와 비교하여, 첫 번째 데이터와 제일 작은 값을 스왑 합니다.
다음 두 번째 데이터와 첫 번째를 제외한 전체 데이터와 비교하여 두 번째 데이터와 2번째로 작은 값을 스왑 합니다.
이것을 반복합니다.

예제


배열 arrData에 100, 20, 10, 12, 5 값이 있고, 최소값이 저장된 인덱스를 저장하기 위한 변수가 nIndex라면 다음과 같이 정렬됩니다.
nIndex의 초기값은 첫 번째 인덱스인 0입니다.

arrData[nIndex]의 값 100을 두 번째 값 20과 비교했을 때, 20이 더 작기 때문에 1을 nIndex에 저장합니다.
arrData[nIndex]의 값 20을 세 번째 값 10과 비교했을 때, 10이 더 작기 때문에 2를 nIndex에 저장합니다.
arrData[nIndex]의 값 10을 네 번째 값 12과 비교했을 때, 12이 더 크기 때문에 넘깁니다.
arrData[nIndex]의 값 10을 다섯 번째 값 5과 비교했을 때, 5가 더 작기 때문에 4를 nIndex에 저장합니다.
그 후 arrData[0]과 arrData[nIndex(=4)]를 스왑 합니다.(5, 20, 10, 12, 100)

다음으로 nIndex에 1을 넣고 비교를 합니다.
arrData[nIndex]의 값 20을 세 번째 값 10과 비교했을 때, 10이 더 작기 때문에 2를 nIndex에 저장합니다.
arrData[nIndex]의 값 10을 네 번째 값 12과 비교했을 때, 12이 더 크기 때문에 넘깁니다.
arrData[nIndex]의 값 10을 다섯 번째 값 100과 비교했을 때, 100이 더 크기 때문에 넘깁니다.
그 후 arrData[1]과 arrData[nIndex(=2)]를 스왑 합니다.(5, 10, 20, 12, 100)

다음으로 nIndex에 2를 넣고 비교를 합니다.
arrData[nIndex]의 값 20을 네 번째 값 12과 비교했을 때, 12이 더 작기 때문에 3을 nIndex에 저장합니다.
arrData[nIndex]의 값 12를 다섯 번째 값 100과 비교했을 때, 100이 더 크기 때문에 넘깁니다.
그 후 arrData[2]과 arrData[nIndex(=3)]를 스왑 합니다.(5, 10, 12, 20, 100)

다음으로 nIndex에 3을 넣고 비교를 합니다.
arrData[nIndex]의 값 20을 다섯 번째 값 100과 비교했을 때, 100이 더 크기 때문에 넘깁니다.
그 후 arrData[3]과 arrData[nIndex(=3)]를 스왑 하는 건 의미가 없으므로 최종 정렬이 됩니다.

 

코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <iostream>
using namespace std;
 
void main()
{
    int arrData[5= { 1002010125 };
    int nTemp;
    int nIndex;
    int nSize = sizeof(arrData) / sizeof(int);
 
    cout << "before : ";
    forint i = 0; i < 5; i++ )
        cout << arrData[i] << " ";
    cout << endl;
 
    forint i = 0; i < nSize; i++ )
    {
        nIndex = i;
        forint j = i; j < nSize; j++ )
        {
            if( arrData[nIndex] > arrData[j] )
            {
                nIndex = j;
            }
        }
 
        nTemp = arrData[i];
        arrData[i] = arrData[nIndex];
        arrData[nIndex] = nTemp;
        forint k = 0; k < 5; k++ )
            cout << arrData[k] << " ";
        cout << endl;
    }
    cout << "after : ";
    forint i = 0; i < 5; i++ )
        cout << arrData[i] << " ";
    cout << endl;
}
 
cs
반응형

+ Recent posts