제작하는 게임에 오프라인 보상 제공 시스템이 필요해서 만들게 됐다.
구현 완료영상
1.요구 조건
- 초 : 각종 오프라인 보상에 필요(10초간 자리 비웠을 시 보상 제공 등..)
- 일(Day) : 하루가 지났는지 확인 필요 (일일 보상및 던전 입장 제한이 끝났는지)
- 달(Month) : 달 보상 필요
- 년 : 아직은 쓸 때 없지만 필요하긴 함.
- 기기 시간 조작으로 오프라인 보상을 무한정 받는것을 막기 위해서 검증 시스템 제작
2.간단한 나의 알고리즘
1. 3초 이상 비어있으면 서버 시간 검증 메서드를 호출한다.
2. 비동기 프로그래밍을 통해 서버에서 시간을 요청하고, 콜백 함수를 만들어서시간을 검증한다.
3. 검증된 시간을 받아와서 비교 후, 보상을 제공한다.
3.알고리즘 세부화
1-1. Update 함수에서 마지막 시간을 지속적으로 저장한다
(Update 함수가 성능에 매우 안좋은 것은 맞지만 마지막 시간을 저장하기 위해서는 불가피한 선택이라고 판단) 단순한 게임 종료가 아닌 백그라운드로 나갔다 오는 것도 포함이다.
1-2. n초마다 현재 시각 - 저장된 시간을 한다. 이 값이 m 이상일 시 서버 시간 검증 메서드를 호출한다.
n초마다 하는 이유는 굳이 매 프레임마다 시간 값을 비교하는 것은 의미가 없기 때문. 또한 m초 이상이란 조건을 넣어준 것은 한 1초 자리비웠는데 오프라인 보상 창이 뜨는 것도 짜증만 유발하지 실질적인 효용이 없기 때문 나는 여기서 n =1 m = 5 정도로 설정했다.
2-1. Task를 이용해서 검증된 시간이 맞는지 찾아오는 메서드를 비동기로 호출한다. Task<bool> 값을 이용해서 비동기 작업이 완료됐을 경우 true, false로 값을 받아올 수 있다.
true일 경우 => 기기 시간이 정상적인 값임으로 보상받는 절차 호출
false일 경우 => 기기 시간이 비정상적인 값이거나 오프라인이기 때문에 보상을 줄 수 없다는 메시지와 재시도 기회 줌.
2-2. 서버 시간 검증 메서드를 만든다. (이 부분은 보안 문제상 생략)
3-1. 현재 시간 - 마지막 시간을 이용해 보상을 지급한다. 너무 길어서 이 부분은 메서드에서 설명
1번 부분 구현(n초 이상 자리 비울시 오프라인 보상 메서드 호출)
public void CheckTimeGap()//Update마다
{
if (progressCheckConnect) //boolean 값으로 현재 오프라인 보상 절차가 진행중이면 더이상 해당 메서드를 호출하지 않는다.
return;
DateTime LastTime = SafetyLoader.Load("LastTime", DateTime.Now);
TimeSpan timeSpan = DateTime.Now - LastTime;
if (timeSpan.TotalSeconds > 5) //5초이상 오프라인일 때
{
CheckConnectRevenue();
progressCheckConect = true;
return; //아래의 마지막 시간 저장을 막는다. return이 없으면 시간이
}
SafetyLoader.Save("LastTime", DateTime.Now);
}
2번 부분 구현(검증된 시간인지 아닌지 비교)
public async void CheckConnectRevenue()
{
FailObjectController(false);
WaitObjectController(true);
bool internetTime = await TimeCheck.CheckInternetTime();
//true면 검증된 시간!, false면 검증되지 않음.
WaitObjectController(false);
if (internetTime)
{
GetRevenue(DateTime.Now); //보상 오브젝트 On
}
else
{
FailObjectController(true); //실패 오브젝트 On
}
}
3.GetRevenue함수
public void GetRevenue(DateTime nowtime)
{
DateTime lastTime = SafetyLoader.Load("LastTime", DateTime.Now);
TimeSpan timeSpan = nowtime - lastTime;
if (DateTime.Now.Year - lastTime.Year > 0) //년이 다를경우
{
PassYear(DateTime.Now.Year - lastTime.Year, (int)timeSpan.TotalSeconds / MonthTime, (int)timeSpan.TotalSeconds / DayTime, (int)timeSpan.TotalSeconds);
}
else if (DateTime.Now.Month - lastTime.Month > 0)
{
PassMonth(DateTime.Now.Month - lastTime.Month, (int)timeSpan.TotalSeconds / DayTime, (int)timeSpan.TotalSeconds);
}
else if (DateTime.Now.Day - lastTime.Day > 0)
{
PassDay(DateTime.Now.Day - lastTime.Day, (int)timeSpan.TotalSeconds);
}
else
{
PassSec((int)timeSpan.TotalSeconds);
}
progressCheckConnect = false;
SafetyLoader.Save("LastTime", DateTime.Now);
Debug.Log("시간 보정 작동됨. " + timeSpan.TotalSeconds + "초");
}
년, 달, 일, 초등등 을 나누어서 처리했다. 이렇게 하면 가시성도 좋고 디버깅 할 때도 편하다.
'개발일지 > 기능구현' 카테고리의 다른 글
[Unity] 투사체의 방향 전환 구현 CalculateAngle (0) | 2023.10.26 |
---|---|
[Unity] 가중치 확률 메소드 구현 WeightedRandomIndex (1) | 2023.10.26 |
[Unity] 확률 함수 구현 Random Function (1) | 2023.10.26 |
[Unity] Json 암호화 파일 Save, Load 구현 (0) | 2023.10.26 |
[Unity] Android, IOS 푸시알림 구현 (1) | 2023.05.03 |