반응형

JavaScript에서 data 속성은 주로 HTML 요소에 사용자 정의 데이터를 저장할 때 사용하는 HTML5의 커스텀 데이터 속성을 의미합니다. 이 속성들은 data-로 시작하며, JavaScript를 통해 쉽게 접근하고 조작할 수 있습니다.

HTML5 커스텀 데이터 속성이란?

  • 정의: HTML 요소에 추가 정보를 저장할 수 있는 속성입니다.
  • 형식: data-키이름="값" 형식으로 사용합니다.
  • 사용 목적: 별도의 시각적 표현이 필요 없는, 추가적인 정보를 요소에 담고 싶을 때 사용합니다.

JavaScript에서의 접근 방법

HTML 요소에 설정된 커스텀 데이터 속성은 JavaScript의 dataset 프로퍼티를 통해 접근할 수 있습니다.

  • data- 뒤의 이름은 카멜 표기법으로 변환되어 접근합니다.
    예) data-user-id → element.dataset.userId

예제

다음은 HTML 요소에 커스텀 데이터 속성을 설정하고, JavaScript에서 읽고 수정하는 예제입니다.

 
<!-- HTML -->
<div id="userInfo" data-user-id="101" data-user-name="JohnDoe">
  사용자 정보
</div>
 
// JavaScript
const userInfo = document.getElementById('userInfo');

// data 속성 읽기
console.log(userInfo.dataset.userId);    // 출력: "101"
console.log(userInfo.dataset.userName);  // 출력: "JohnDoe"

// data 속성 변경
userInfo.dataset.userName = 'JaneDoe';
console.log(userInfo.dataset.userName);  // 출력: "JaneDoe"

요약

  • HTML: <div id="userInfo" data-user-id="101" data-user-name="JohnDoe"></div>
  • JavaScript: document.getElementById('userInfo').dataset를 통해 data-user-id는 userId, data-user-name은 userName으로 접근

이처럼 HTML5의 data 속성을 활용하면, 요소에 추가적인 정보를 쉽게 저장하고 JavaScript에서 이를 읽어 동적으로 활용할 수 있습니다.

 

여기서 조금더 알아봅시다.

 

id 속성 없이도, CSS 선택자를 이용하여 data-user-id="101" 속성을 가진 요소를 선택할 수 있습니다.
이를 위해 JavaScript의 document.querySelector나 document.querySelectorAll 메서드를 사용할 수 있습니다.

그리고 추가로 해당 데이터의 값을 변경하는 법을 알아보도록 하겠습니다.

 

예제를 통해 알아보겠습니다.

HTML 코드 예제

<div data-user-id="101" data-user-name="JohnDoe">
  사용자 정보
</div>

JavaScript 코드 예제

 
// data-user-id가 "101"인 요소 선택 (첫 번째 요소만 선택)
const element = document.querySelector('[data-user-id="101"]');

if (element) {
  // 기존 값 확인
  console.log(element.dataset.userId); // 출력: "101"
  
  // data-user-id 값을 수정하는 방법 1: dataset 프로퍼티 사용
  element.dataset.userId = '202';
  console.log(element.dataset.userId); // 출력: "202"
  
  // data-user-id 값을 수정하는 방법 2: setAttribute 메서드 사용
  element.setAttribute('data-user-id', '303');
  console.log(element.getAttribute('data-user-id')); // 출력: "303"
}

설명

  1. 요소 선택하기:
    • document.querySelector('[data-user-id="101"]')를 사용하여 data-user-id 속성의 값이 "101"인 요소를 선택합니다.
    • 여러 요소를 선택하려면 document.querySelectorAll('[data-user-id="101"]')를 사용하여 NodeList를 받을 수 있습니다.
  2. 값 수정하기:
    • 방법 1: dataset 프로퍼티를 사용하여 element.dataset.userId로 접근한 후 원하는 값으로 변경합니다.주의: data-user-id 속성은 dataset에서는 userId로 접근합니다.
    • 방법 2: setAttribute 메서드를 사용하여 data-user-id 속성을 직접 수정할 수 있습니다.

이처럼, id 없이도 data 속성을 가진 요소를 쉽게 선택하고, 값을 읽거나 수정할 수 있습니다.

반응형
반응형

1. 기본적인 this 동작 방식

this는 함수가 호출되는 방식에 따라 값이 달라집니다. 주요한 패턴은 다음과 같습니다.

1.1 전역 컨텍스트에서의 this

 
console.log(this); // 브라우저에서는 Window 객체, Node.js에서는 global 객체
 

전역에서 this를 출력하면 브라우저 환경에서는 window 객체를, Node.js 환경에서는 global 객체를 참조합니다.


1.2 일반 함수에서의 this (엄격 모드와 일반 모드)

function showThis() {
    console.log(this);
}
showThis(); // 브라우저에서는 window, Node.js에서는 global

"use strict";
function strictShowThis() {
    console.log(this);
}
strictShowThis(); // undefined (엄격 모드에서는 `this`가 undefined)
  • 일반 모드: this는 전역 객체(window 또는 global)를 참조합니다.
  • 엄격 모드("use strict"): this는 undefined가 됩니다.

1.3 객체의 메서드에서의 this

const obj = {
    name: "Alice",
    showThis: function () {
        console.log(this.name);
    }
};
obj.showThis(); // "Alice"
  • 메서드를 호출한 객체(obj)가 this가 됩니다.

하지만 함수 내부에서 새로운 함수가 호출되면 this가 바뀔 수 있습니다.

const obj = {
    name: "Alice",
    showThis: function () {
        function inner() {
            console.log(this);
        }
        inner(); // 일반 함수로 호출되므로 `this`는 `window` 또는 `undefined`(엄격 모드) 
    }
};
obj.showThis();
  • 해결 방법:
    1. self 또는 that 변수를 활용 (var self = this;)
    2. .bind(this) 사용
    3. 화살표 함수 사용 (아래에서 설명)

2. 생성자 함수와 this

function Person(name) {
    this.name = name;
}

const p1 = new Person("Alice");
console.log(p1.name); // "Alice"
  • new 키워드를 사용하여 생성자 함수를 호출하면 this는 새로 생성된 객체를 참조합니다.

만약 new 없이 호출하면 this가 전역 객체를 가리키거나(비엄격 모드) undefined(엄격 모드)로 설정됩니다.

const p2 = Person("Bob"); // new 없이 호출
console.log(p2); // undefined
console.log(global.name); // "Bob" (Node.js의 경우)

해결 방법:

  • new 없이 호출될 경우 this가 올바른 객체를 참조하도록 강제하는 패턴 사용
function Person(name) {
    if (!(this instanceof Person)) {
        return new Person(name);
    }
    this.name = name;
}

3. 화살표 함수에서의 this

화살표 함수는 일반 함수와 다르게 this를 바인딩하지 않고, 자신을 포함하는 외부 스코프(렉시컬 스코프)의 this를 사용합니다.

const obj = {
    name: "Alice",
    showThis: function () {
        const arrow = () => {
            console.log(this.name);
        };
        arrow();
    }
};
obj.showThis(); // "Alice"
  • arrow 함수는 obj.showThis()의 this를 유지합니다.

하지만 화살표 함수는 생성자 함수로 사용할 수 없습니다.

const Person = (name) => {
    this.name = name;
};
const p = new Person("Alice"); // TypeError: Person is not a constructor

4. bind, call, apply를 이용한 this 변경

4.1 call()과 apply()

call()과 apply()를 사용하면 특정한 this를 설정하여 함수를 실행할 수 있습니다.

 
function showName() {
    console.log(this.name);
}

const user = { name: "Alice" };
showName.call(user); // "Alice"
showName.apply(user); // "Alice"
  • call(thisArg, arg1, arg2, ...) → 개별 인자로 전달
  • apply(thisArg, [arg1, arg2, ...]) → 배열로 전달

4.2 bind()

bind()는 새로운 함수를 반환하여 이후에 this가 고정된 상태로 실행되도록 합니다.

function showName() {
    console.log(this.name);
}
const user = { name: "Alice" };

const boundFn = showName.bind(user);
boundFn(); // "Alice"
  • bind()를 사용하면 this가 영구적으로 고정됩니다.

5. 이벤트 핸들러에서의 this

5.1 일반 함수에서의 this

const button = document.querySelector("button");
button.addEventListener("click", function () {
    console.log(this); // 클릭된 button 요소를 참조
});

5.2 화살표 함수에서의 this

button.addEventListener("click", () => {
    console.log(this); // window 객체를 참조
});
  • 화살표 함수는 이벤트 핸들러로 사용될 때 this가 window가 되어 문제가 발생할 수 있습니다.

해결 방법:

  • bind(this)를 사용하거나, 일반 함수 표현식을 사용

6. 클래스에서의 this

클래스 메서드에서는 this가 자동으로 인스턴스를 가리킵니다.

class Person {
    constructor(name) {
        this.name = name;
    }
    showName() {
        console.log(this.name);
    }
}
const p = new Person("Alice");
p.showName(); // "Alice"

하지만, 클래스 내부에서 setTimeout 등을 사용할 경우 this가 바뀔 수 있습니다.

class Timer {
    start() {
        setTimeout(function () {
            console.log(this); // window 또는 undefined
        }, 1000);
    }
}
const t = new Timer();
t.start();
  • 해결 방법: bind(this) 또는 화살표 함수 사용
class Timer {
    start() {
        setTimeout(() => {
            console.log(this); // Timer 객체 유지
        }, 1000);
    }
}

7. 정리

호출 방식this 값

전역 실행 (일반 모드) window (브라우저) / global (Node.js)
전역 실행 (엄격 모드) undefined
객체의 메서드 해당 객체
화살표 함수 외부 this를 따름 (렉시컬 this)
생성자 함수 새로 생성된 객체 (new 사용 시)
call / apply 명시적으로 지정된 객체
bind 영구적으로 고정된 this
DOM 이벤트 핸들러 (일반 함수) 이벤트가 발생한 요소
DOM 이벤트 핸들러 (화살표 함수) window

this는 문맥에 따라 다르게 동작하므로, 실행 방식과 함수 선언 형태를 잘 이해해야 합니다.

 

특히 클래스 사용시에 전달값을 함수로해서 this를 사용하는 경우에 바인등을 주의깊게 살피지 않으시면 뜬금없이 에러가 발생하므로 주의깊게 사용하셔야 이상한 동작을 할 경우가 줄어듭니다.

반응형
반응형

먼저 JWT의 기본 개념에 대해 설명드리겠습니다:

JWT는 당사자간에 정보를 JSON 객체로 안전하게 전송하기 위한 간단한 방법입니다. 이 정보는 디지털 서명되어 있어 신뢰할 수 있습니다.

JWT의 구조:

  1. Header: 토큰 유형과 사용된 서명 알고리즘
  2. Payload: 전달하려는 데이터(클레임)
  3. Signature: 헤더와 페이로드를 기반으로 한 서명

주요 사용 사례:

  • 인증(Authentication)
  • 정보 교환
  • 상태 유지(Stateless) 서버 구현

 

using System;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using Microsoft.IdentityModel.Tokens;

public class JwtAuthenticationExample : System.Web.UI.Page
{
    private readonly string _secretKey = "your-256-bit-secret-key-here";
    
    // JWT 토큰 생성 메서드
    protected string GenerateJwtToken(string userId, string username, string role)
    {
        var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_secretKey));
        var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);

        var claims = new[]
        {
            new Claim(JwtRegisteredClaimNames.Sub, userId),
            new Claim(JwtRegisteredClaimNames.UniqueName, username),
            new Claim(ClaimTypes.Role, role),
            new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
            new Claim(JwtRegisteredClaimNames.Iat, DateTime.UtcNow.ToString())
        };

        var token = new JwtSecurityToken(
            issuer: "your-issuer",
            audience: "your-audience",
            claims: claims,
            expires: DateTime.UtcNow.AddHours(1),
            signingCredentials: credentials
        );

        return new JwtSecurityTokenHandler().WriteToken(token);
    }

    // JWT 토큰 검증 메서드
    protected bool ValidateToken(string token)
    {
        var tokenHandler = new JwtSecurityTokenHandler();
        var key = Encoding.ASCII.GetBytes(_secretKey);

        try
        {
            tokenHandler.ValidateToken(token, new TokenValidationParameters
            {
                ValidateIssuerSigningKey = true,
                IssuerSigningKey = new SymmetricSecurityKey(key),
                ValidateIssuer = true,
                ValidIssuer = "your-issuer",
                ValidateAudience = true,
                ValidAudience = "your-audience",
                ValidateLifetime = true,
                ClockSkew = TimeSpan.Zero
            }, out SecurityToken validatedToken);

            return true;
        }
        catch
        {
            return false;
        }
    }

    // 로그인 처리 예제
    protected void LoginButton_Click(object sender, EventArgs e)
    {
        // 실제 구현에서는 데이터베이스에서 사용자 검증
        string userId = "123";
        string username = "testuser";
        string role = "user";

        string token = GenerateJwtToken(userId, username, role);
        
        // 토큰을 클라이언트에 전달 (예: 쿠키로 저장)
        Response.Cookies.Add(new HttpCookie("jwt_token", token));
    }

    // 보호된 리소스 접근 예제
    protected void Page_Load(object sender, EventArgs e)
    {
        HttpCookie tokenCookie = Request.Cookies["jwt_token"];
        
        if (tokenCookie != null && ValidateToken(tokenCookie.Value))
        {
            // 인증된 사용자 처리
            // 보호된 리소스에 접근 허용
        }
        else
        {
            // 인증되지 않은 사용자 처리
            Response.Redirect("~/Login.aspx");
        }
    }
}

// Web.config 설정
/*
<configuration>
  <system.web>
    <authentication mode="None" />
  </system.web>
  <system.webServer>
    <modules>
      <remove name="FormsAuthentication" />
    </modules>
  </system.webServer>
</configuration>
*/

 

 

이 예제 코드의 주요 특징:

  1. 토큰 생성 (GenerateJwtToken):
    • 사용자 ID, 이름, 역할 등의 클레임 포함
    • 토큰 만료 시간 설정 (1시간)
    • HMAC SHA256 알고리즘으로 서명
  2. 토큰 검증 (ValidateToken):
    • 토큰의 서명 검증
    • 발급자(issuer)와 수신자(audience) 검증
    • 만료 시간 검증
  3. 실제 사용 예시:
    • 로그인 시 토큰 생성
    • 보호된 페이지 접근 시 토큰 검증

3번의 로그인 버튼 쪽이랑 페이지 로드 부분은 별로 신경 안 쓰셔도 됩니다. 

보통 클라이언트에서 위에 두개의 함수를 이용하여 토큰을 생성하고 검증하는 부분으로 사용되기 때문입니다.

 

구현 시 주의사항:

  1. 시크릿 키는 안전하게 보관해야 합니다
  2. HTTPS를 사용하여 통신해야 합니다
  3. 토큰 만료 시간을 적절히 설정해야 합니다
  4. 필요한 패키지를 설치해야 합니다:

 

 

 

JWT를 활용한 클라이언트 구현을 자세히 만들어보겠습니다.

<!-- Login.aspx -->
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Login.aspx.cs" Inherits="JwtExample.Login" %>

<!DOCTYPE html>
<html>
<head>
    <title>로그인</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
    <style>
        .login-container {
            max-width: 400px;
            margin: 50px auto;
            padding: 20px;
            border: 1px solid #ddd;
            border-radius: 5px;
        }
        .form-group {
            margin-bottom: 15px;
        }
        .form-group label {
            display: block;
            margin-bottom: 5px;
        }
        .form-group input {
            width: 100%;
            padding: 8px;
            border: 1px solid #ddd;
            border-radius: 4px;
        }
        .error-message {
            color: red;
            margin-top: 10px;
            display: none;
        }
    </style>
</head>
<body>
    <div class="login-container">
        <h2>로그인</h2>
        <div class="form-group">
            <label for="username">사용자명:</label>
            <input type="text" id="username" name="username" />
        </div>
        <div class="form-group">
            <label for="password">비밀번호:</label>
            <input type="password" id="password" name="password" />
        </div>
        <button onclick="login()">로그인</button>
        <div id="errorMessage" class="error-message"></div>
    </div>

    <script>
        function login() {
            const username = $('#username').val();
            const password = $('#password').val();

            // 로그인 요청
            $.ajax({
                url: 'Login.aspx/LoginUser',
                type: 'POST',
                contentType: 'application/json',
                data: JSON.stringify({
                    username: username,
                    password: password
                }),
                success: function(response) {
                    if (response.d.success) {
                        // JWT 토큰 저장
                        localStorage.setItem('jwt_token', response.d.token);
                        // 사용자 정보 저장
                        localStorage.setItem('user_info', JSON.stringify(response.d.userInfo));
                        // 메인 페이지로 리다이렉트
                        window.location.href = 'Dashboard.aspx';
                    } else {
                        $('#errorMessage').text(response.d.message).show();
                    }
                },
                error: function() {
                    $('#errorMessage').text('로그인 중 오류가 발생했습니다.').show();
                }
            });
        }
    </script>
</body>
</html>

<!-- Dashboard.aspx -->
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Dashboard.aspx.cs" Inherits="JwtExample.Dashboard" %>

<!DOCTYPE html>
<html>
<head>
   <title>대시보드</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
    <style>
        .dashboard-container {
            max-width: 800px;
            margin: 20px auto;
            padding: 20px;
        }
        .header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 20px;
        }
        .user-info {
            margin-bottom: 20px;
        }
        .protected-content {
            border: 1px solid #ddd;
            padding: 20px;
            border-radius: 5px;
        }
    </style>
</head>
<body>
    <div class="dashboard-container">
        <div class="header">
            <h2>대시보드</h2>
            <button onclick="logout()">로그아웃</button>
        </div>
        <div id="userInfo" class="user-info"></div>
        <div class="protected-content">
            <h3>보호된 컨텐츠</h3>
            <div id="protectedData"></div>
        </div>
    </div>

    <script>
        // 페이지 로드 시 인증 확인
        $(document).ready(function() {
            checkAuth();
            loadUserInfo();
            loadProtectedData();
        });

        // 인증 확인
        function checkAuth() {
            const token = localStorage.getItem('jwt_token');
            if (!token) {
                window.location.href = 'Login.aspx';
                return;
            }
        }

        // 사용자 정보 로드
        function loadUserInfo() {
            const userInfo = JSON.parse(localStorage.getItem('user_info'));
            if (userInfo) {
                $('#userInfo').html(`
                    <p>사용자명: ${userInfo.username}</p>
                    <p>역할: ${userInfo.role}</p>
                `);
            }
        }

        // 보호된 데이터 로드
        function loadProtectedData() {
            $.ajax({
                url: 'Dashboard.aspx/GetProtectedData',
                type: 'POST',
                contentType: 'application/json',
                headers: {
                    'Authorization': 'Bearer ' + localStorage.getItem('jwt_token')
                },
                success: function(response) {
                    $('#protectedData').html(response.d.data);
                },
                error: function(xhr) {
                    if (xhr.status === 401) {
                        // 인증 실패 시 로그인 페이지로 리다이렉트
                        logout();
                    } else {
                        $('#protectedData').html('데이터 로드 중 오류가 발생했습니다.');
                    }
                }
            });
        }

        // 로그아웃
        function logout() {
            localStorage.removeItem('jwt_token');
            localStorage.removeItem('user_info');
            window.location.href = 'Login.aspx';
        }

        // API 요청을 위한 공통 함수
        function apiRequest(url, method, data) {
            return $.ajax({
                url: url,
                type: method,
                contentType: 'application/json',
                headers: {
                    'Authorization': 'Bearer ' + localStorage.getItem('jwt_token')
                },
                data: JSON.stringify(data)
            });
        }
    </script>
</body>
</html>
 

이 클라이언트 구현의 주요 특징과 기능을 설명드리겠습니다:

  1. 로그인 페이지 (Login.aspx):
    • 사용자명과 비밀번호 입력 폼 제공
    • AJAX를 사용한 비동기 로그인 처리
    • 로그인 성공 시 JWT 토큰을 localStorage에 저장
    • 에러 메시지 표시 기능
  2. 대시보드 페이지 (Dashboard.aspx):
    • 인증된 사용자만 접근 가능
    • 사용자 정보 표시
    • 보호된 데이터 로드 기능
    • 로그아웃 기능
  3. 주요 보안 기능:
    • 모든 API 요청에 JWT 토큰 포함
    • 인증되지 않은 접근 시 자동 리다이렉트
    • 토큰 만료 시 자동 로그아웃

구현 시 주의사항:

  1. localStorage 대신 보안이 더 필요한 경우 httpOnly 쿠키 사용을 고려해 볼 수 있습니다.
  2. 실제 운영 환경에서는 HTTPS 사용 필수입니다.
  3. CSRF 공격 방지를 위한 대책을 추가해 주는 게 좋습니다.

이상 JWT에 대하여 간단하게 알아보았습니다.

반응형
반응형

이 버전은 Google Play 64비트 요구사항을 준수하지 않습니다.
다음 APK 또는 App Bundle은 64비트 기기를 지원하지만, 32비트 네이티브 코드만 포함합니다. [1]
앱에 64비트 및 32비트 네이티브 코드를 포함하세요. Android App Bundle 게시 형식을 사용하여 각 기기 아키텍처가 자동으로 필요한 네이티브 코드만 수신하도록 하세요. 그래야 앱의 전체 크기를 줄일 수 있습니다.

 

이런 에러가 발생하였습니다.

 

해결방법은 Project Settings > Player > Other Settings > Target Architectures > ARM64를 체크해주시면 됩니다.

 

반응형
반응형

1. Unity에서 화면을 고정하는 방법 (화면 방향 고정)

Unity에서는 화면 방향을 특정 방향으로 고정할 수 있습니다.

방법 1: Player Settings에서 설정 (정적인 방식)

  1. EditProject SettingsPlayer로 이동
  2. Resolution and Presentation 탭에서 Default Orientation 설정 변경
    • Portrait (세로 모드)
    • Portrait Upside Down (뒤집힌 세로 모드)
    • Landscape Left (가로 모드, 카메라가 왼쪽인 상태)
    • Landscape Right (가로 모드, 카메라가 오른쪽인 상태)
    • Auto Rotation (자동 회전)
  3. Auto Rotation 선택 시, 원하는 방향을 활성화/비활성화 가능

설정위치

 

#저는 이번 프로젝트가 가로모드로만 작동하는 방식이라서 카메라가 왼쪽일 경우 오른쪽일 경우의 가로모드만 체크하였습니다.

 

방법 2: 코드로 화면 방향 고정 (동적인 방식)

게임 내에서 특정 씬에서만 화면 방향을 바꾸려면 C# 코드로 설정할 수 있습니다.

using UnityEngine;

public class ScreenOrientationController : MonoBehaviour
{
    void Start()
    {
        // 세로 화면 고정
        Screen.orientation = ScreenOrientation.Portrait;

        // 또는 가로 화면 고정
        // Screen.orientation = ScreenOrientation.LandscapeLeft;
    }
}
 

위 스크립트를 특정 씬에서 사용하면 해당 씬에서는 설정된 방향으로 고정됩니다.


2. 씬마다 가로/세로 변경하는 방법 (동적 변경)

씬이 변경될 때마다 화면 방향을 변경하고 싶다면 SceneManager.sceneLoaded 이벤트를 활용할 수 있습니다.

씬 변경 시 자동으로 화면 방향 바꾸기

using UnityEngine;
using UnityEngine.SceneManagement;

public class OrientationManager : MonoBehaviour
{
    void Awake()
    {
        // 씬이 로드될 때마다 호출
        SceneManager.sceneLoaded += OnSceneLoaded;
    }

    void OnSceneLoaded(Scene scene, LoadSceneMode mode)
    {
        // 씬 이름 또는 인덱스에 따라 화면 방향 변경
        if (scene.name == "MainMenu")  
        {
            Screen.orientation = ScreenOrientation.Portrait;  // 세로 모드
        }
        else if (scene.name == "GameScene")
        {
            Screen.orientation = ScreenOrientation.LandscapeLeft;  // 가로 모드
        }
    }

    void OnDestroy()
    {
        // 이벤트 해제 (메모리 누수 방지)
        SceneManager.sceneLoaded -= OnSceneLoaded;
    }
}

설명

  • SceneManager.sceneLoaded를 사용해 씬이 로드될 때마다 자동으로 화면 방향을 변경
  • 특정 씬에서는 세로(Portrait), 다른 씬에서는 가로(LandscapeLeft)로 설정 가능

이렇게 하면 각 씬에 맞춰 자동으로 화면 방향이 변경됩니다.

 

반응형
반응형

1. PlayerPrefs란?

PlayerPrefs는 Unity에서 간단한 데이터 저장을 위해 제공하는 기능으로, 게임의 설정 값이나 간단한 데이터를 영구적으로 저장하는 데 사용됩니다. 내부적으로 Windows에서는 레지스트리, Android/iOS에서는 로컬 파일을 이용하여 데이터를 저장합니다.


2. PlayerPrefs 사용법

기본적인 데이터 저장 및 불러오기

// 데이터 저장
PlayerPrefs.SetInt("HighScore", 1000);
PlayerPrefs.SetFloat("Volume", 0.8f);
PlayerPrefs.SetString("PlayerName", "Alice");

// 데이터 불러오기 (기본값 설정 가능)
int highScore = PlayerPrefs.GetInt("HighScore", 0);
float volume = PlayerPrefs.GetFloat("Volume", 1.0f);
string playerName = PlayerPrefs.GetString("PlayerName", "Guest");

// 데이터 삭제
PlayerPrefs.DeleteKey("HighScore");

// 모든 데이터 삭제
PlayerPrefs.DeleteAll();

// 변경 사항 저장 (모바일에서 필요할 수도 있음)
PlayerPrefs.Save();

3. PlayerPrefs의 장점과 단점

장점

  1. 간단한 데이터 저장 가능
    • 별도의 파일 I/O 작업 없이 간단한 코드로 데이터를 저장할 수 있습니다.
  2. 플랫폼 독립적
    • Windows, Mac, Android, iOS 등에서 동일한 방식으로 사용할 수 있습니다.
  3. 설정 값 저장에 적합
    • 볼륨, 해상도, 컨트롤 설정 등의 데이터를 쉽게 저장하고 불러올 수 있습니다.

단점

  1. 보안이 취약함
    • 저장된 데이터가 암호화되지 않으며, Windows에서는 레지스트리를, 모바일에서는 로컬 파일을 조작하면 쉽게 변경할 수 있습니다.
  2. 대량의 데이터 저장에는 부적합
    • PlayerPrefs는 작은 설정 값을 저장하는 용도로 만들어졌으며, 큰 데이터를 저장하면 성능 저하가 발생할 수 있습니다.
  3. Binary나 구조체 저장 불가
    • int, float, string 타입만 저장 가능하며, 리스트나 복잡한 데이터 구조를 저장하려면 JSON 변환이 필요합니다.
    • 예제:
       
string json = JsonUtility.ToJson(myData);
PlayerPrefs.SetString("MyData", json);

4. PlayerPrefs를 사용해야 할 때 vs 다른 대안

기능PlayerPrefs대안

설정 값 저장 ✅ 적합 -
게임 진행 데이터 저장 ❌ 부적합 JSON 파일, SQLite, Binary Serialization, Cloud Save
보안이 중요한 데이터 (예: 유료 아이템) ❌ 매우 부적합 암호화된 파일, 클라우드 저장 (Firebase, PlayFab 등)

5. 결론

  • PlayerPrefs는 설정 값을 저장하는 데 유용하지만, 중요한 게임 데이터(점수, 진행 상황, 인벤토리 등)를 저장하는 용도로 사용하면 보안 문제가 발생할 수 있습니다.
  • 큰 데이터 저장이 필요하다면 파일 시스템, JSON, SQLite, 클라우드 저장을 고려하는 것이 좋습니다.

🔹 추천 사용 예시

✅ PlayerPrefs 사용: 볼륨, 해상도, 키 설정 저장
❌ PlayerPrefs 사용 X: 세이브 데이터, 보안이 중요한 정보

반응형

+ Recent posts