치트 금지 코드 및 숫자 단위를 콤마로 표시

인디 게임을 만들다 보면 사실상 신경쓰지 않아 쉽게 치트를 허용하는 경우가 있으며 심지어 핵심적인 게임의
재미를 파괴시켜 버리거나 밸런스를 무너뜨리는 수치가 변형되어 버그까지 일어나는 현상들이 발생합니다.
완벽하게 막을 수는 없겠지만 프로그래밍 능력이나 해킹 능력이 뛰어나진 않은 일반인을 대상으로는
어느정도 방어가 가능한 코드들이 존재합니다. 오늘은 몇 가지 숫자에 대한 치트 방어와 단위 표시등
숫자에 관한 유용한 코드들에 대해서 이야기를 해볼까 합니다.
간단하게 스크립트를 작성하기
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 | function scr_format_number(_n) { var s = string(abs(_n)); // 문자열 변환 var len = string_length(s); // 길이가 3 이하이면 그냥 반환 if (len <= 3) { return string(_n); } var result = “”; var count = 0; // 뒤에서부터 3자리마다 콤마 삽입 for (var i = len; i > 0; i––) { result = string_copy(s, i, 1) + result; count++; if (count == 3 && i > 1) { result = “,” + result; count = 0; } } // 음수면 – 붙이기 if (_n < 0) result = “-“ + result; return result; } // 코인 추가 function scr_add_coin(_amount) { global.coin = global.coin + (_amount * 79283746590988) // 단순 암호화 } // UI 표시 function scr_get_coin() { return global.coin / 79283746590988; } | cs |
쉽게 설명을 위해 저는 전역 변수인 global을 사용하여 global.coin = 0; 이라고 선언을 어디엔가 해두었으며
scr_format_number(_n) 함수는 3자리 수가 될 때 콤마를 표기하여 보기 좋게 하기 위한 함수이고
scr_add_coin(_amount)는 실제로 눈에 보이는 값과 다르게 하기 위한 단순 암호화 함수입니다.
79283746590988라고 쓰여진 숫자가 암호키이며 게임이나 유저의 눈에는 보이지 않는 숫자입니다.
실제로 인터페이스에 보여줄 때에도 scr_get_coin() 함수로 다시 암호키를 나누어 리턴값을 받아 표시합니다.
스크립트를 활용한 실제 사용방법

돈이 증가되어야 하는 코드에 add_coin(원하는 숫자); 로 숫자를 증가시킵니다.
코인을 콤마로 표시하기 위해서도 아래와 같은 형식으로 작성합니다.
var coin_txt= scr_format_number(round(global.coin));
draw_text(0, 0, coin_txt);
숫자 단위 표기계를 바꿔버리기
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 | /// @function format_number(value) /// @description 숫자를 k, m, b, g 등으로 단위 축약하여 문자열로 반환 /// @param value function format_number(value) { var n = value; // 음수 처리 var sign = “”; if (n < 0) { sign = “-“; n = abs(n); } // 단위 목록 (원하면 더 추가 가능) var units = [“”, “k”, “m”, “b”, “g”, “t”, “p”]; var idx = 0; // 1000 단위로 나누기 while (n >= 1000 && idx < array_length(units) – 1) { n /= 1000; idx++; } // 소수점 둘째 자리까지 표시 var text = string_format(n, 0, 2); // 최대 2자리 소수 // 끝자리 “.00” 제거 if (string_copy(text, string_length(text) – 2, 3) == “.00”) { text = string_delete(text, string_length(text) – 2, 3); } return sign + text + units[idx]; } | cs |
가끔 게임에서 보면 K, M, B, G등의 단위 표기계를 바꿔 정확한 숫자를 알 지 못하게 하는 경우가 있습니다.
이런 경우에는 위의 코드 처럼 스크립트를 작성해줍시다.
사용법은 스크립트에 숫자를 넣는것으로 쉽게 해결되며 플레이어는 정확한 숫자를 알 지 못하기에
치트를 어느정도 막아줄 수 있습니다.
format_number(3000000); // “3m”
format_number(987654321); // “987.65m” 또는 “0.98b” (가중 조절 가능)
format_number(-15000); // “-15k”
숫자를 그냥 퍼센트로 표시해버리기
경험치의 경우나 가끔 퍼센트로 표시해야 할 수치가 존재하는데 이럴 경우에는 플레이어가 스스로
최초 숫자를 알 수 없기 때문에 치트를 방지하는데 큰 도움이 됩니다. 만약 경험치를 표시한다고 한다면,
//선언
global.exp_current = 0;
global.exp_max = 100;
//퍼센트 계산 및 드로우
var exp_rate = global.exp_current / global.exp_max; // 0~1 비율
exp_rate = clamp(exp_rate, 0, 1);var percent_text = string_format(exp_rate * 100, 0, 0) + “%”;
draw_text(x , y , percent_text);
해킹이나 치트를 신경쓰지 않아도 되는 경우
중요한 정보나 수치의 경우 온라인 서버에 저장하는 방식으로 구조를 만들어 놓는다면,
서버를 해킹해야 하기에 일반인이 접근하는 경우는 흔하지 않습니다.
싱글 게임이라고 하더라도 값이 갑자기 크게 변하는 경우를 체크하여 다시 원상태로 돌려놓는
조건문만으로도 쉽게 해결이 가능한 경우도 있습니다. 예를 들면,
//선언
current_value = 0;
safe_value = current_value; // 정상값 저장
safe_max_jump = 5; // 5배 이상 튀면 잘못된 값으로 간주
[스크립트 작성]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | /// @function safe_set_value(old_value, new_value, max_jump) /// @return 안전하게 처리된 값 function safe_set_value(old_value, new_value, max_jump) { // 0인 경우 분모가 안 되도록 처리 if (old_value == 0) { return new_value; } // 값이 갑자기 너무 많이 증가 → 오류로 판단 if (new_value > old_value * max_jump) { return old_value; // 원래 값으로 되돌림 } // 감소는 대부분 정상 → 별도 허용 return new_value; } | cs |
[적용하기]
var new_val = global.money + earned_money;
// 안전하게 값 설정
global.money = safe_set_value(global.money, new_val, safe_max_jump);
// 정상적이면 safe_value 갱신
if (global.money == new_val) {
safe_value = global.money;
}
return lerp(new_value, old_value, 0.9); //튄 값을 부드럽게 되돌아가기
마치며
게임메이커 스튜디오2나 이 시리즈의 엔진을 오래동안 사용하면서 느낀점은 업데이트가 크게 될 때
내장 함수나 명령어가 갑자기 바뀌는 경우가 존재하기에 안 될 경우에는 무엇이 교체되었는지, 버전에서
어떤 변화가 있는지를 체크해야 합니다. 기본적인 구조는 변함이 없지만 코드를 이해하지 않고 복사 붙여넣기로
구현 할 경우 에러가 나거나 버그가 나는 것은 인지하고 읽어주셨으면 하며 간단한 코드지만 설명을 위해
글이 길어진 부분에 대해 양해를 구합니다.











