이번 시간에 해 볼 내용은 지난 시간에 이어서, “정말 간단한 클리커 게임”입니다.
더불어 GDscript에서 사용하는 변수에 대한 이해와 기본적 사칙연산에 대한 내용입니다.
■ 변수의 이해
지난 프로젝트에 이어서 진행합니다.
편집을 누르시면 이어서 진행하실 수 있습니다.
프로그래밍에서 변수라는 것은, 무엇이든 저장할 수 있는 “상자”를 의미합니다.
그곳에는 유저의 이름을 넣을 수도 있고, 캐릭터의 스텟을 넣을 수도 있고, 계속해서 변해가는 “변하는 수”나 “정보”를 넣을 수 있습니다.
그리고 그곳에 들어있는 내용은 언제든지 꺼낼 수 있고, 수정할 수도 있습니다.
GDscript에서 변수 만드는 방법은 간단합니다.
var 변수명 = 변수값
var coin = 0
※ 프로그래밍을 조금 아시는 분들을 위한 내용
GDscript는 동적 스크립트 언어입니다. 그러니 int, float, string 등의 정적 변수 선언을 할 필요가 없습니다.
그냥 들어 있는 내용물에 따라서 알아서 변수형이 정해지는 방식입니다. 그럼에도 변수형(format)을 정하고 싶으시다면
var 변수명 : 변수형 = 변수값
var coin : float = 1.00
이런 형태로 작성하실 수 있습니다. 그리고 일부 사용자는 동적 스크립트의 특징은 살리되 변수 선언와 변수 할당을 구분하기 위해 아래와 같이 적기도 합니다
var coin := 1.00 # 변수 선언
coin = 10.00 # 변수 할당
뭐, 어떤 걸 사용하듯 모두 결과는 같으니 간단하게 var coin = 0 로 갑시다 ㅎㅎ
지난 코드 가장 위쪽에 클리커에서 사용될 coin 이라는 변수를 추가해 봅시다.
더불어서
#뒤에 쓰는 내용은 주석으로 처리되어, 다양한 메모를 할 수 있습니다.
이렇게 # 뒤에 붙은 내용은, 프로그램에서는 어떠한 처리도 하지 않습니다. 그러니 기존에 있던 회색 문구들을 싹 지워도 전혀 문제가 없다는 말이죠 ㅎㅎ
var coin = 0 # 현재 보유한 코인
(스샷에는 1을 적어 놨네요, ㅎㅎㅎ)
□ 숫자(int) 변수와 텍스트(string) 변수
숫자 변수는 그냥 숫자만 입력하시면 됩니다.
텍스트 변수는 지난 번에 라벨에 텍스트를 넣은 것 처럼 “” 따옴표로 묶어주시면 됩니다.
뭐가 다르냐면, “숫자 변수는 사칙연산을 할 수 있다” 정도로 기억해 주시면 됩니다.
지난번에 라벨에 텍스트를 += 덧셈을 하니, 텍스트 뒤에 계속 텍스트가 연결되는 것을 보셨을 것입니다.
숫자 변수라면 1 + 1 = 2 가 나오겠지만
텍스트 변수라면 “1” + “1” = “11” 라는 결과를 볼 수 있습니다.
컴퓨터 관련 지식이 조금 있으신 분들이라면, 숫자와 텍스트 숫자가 갖게 되는 코드 값 자체가 아예 다르다는 걸 아실테지만,
거기까지 모르셔도 전혀 지장없으니, 그저 계산하려면 숫자, 붙이거나 출력하려면 텍스트! 이 정도로만 기억해 주세요.
■ 클릭 할 때 마다 코인이 +1씩 늘어나도록 해 봅시다.
지난번에 라벨 뒤에 계속해서 내용이 더해지는 것을 그대로 활용하시면 됩니다.
버튼을 클릭할 때 호출되는 함수인
func _on_button_pressed():
이 코드 바로 아래에
coin = coin +1
을 넣으면 끝입니다. 지난번에 배운 짧게 요약하는 방법을 사용하면
coin += 1
심플하군요!
어떤 방법으로 적어도 결과는 같습니다, 선호하는 방법으로 적어주세요~
■ 라벨에 현재 보유한 코인이 출력되도록 해 봅시다.
지난번에 $Label.text = “값” 을 통해서 라벨에 값이 출력되도록 하는 방법을 배웠습니다.
그럼 간단히 저기 값을 들고 있는 변수를 넣으면 끝입니다.
$Label.text = coin
만일 이 coin을 따옴표로 감싼다면 “coin” 텍스트로 인식하겠지만, 그냥 coin만 입력해 주면 변수 coin에 들어있는 값을 출력하게 될 것입니다.
만!!!!
아쉽게도 라벨은 숫자를 출력하지 못합니다. 항상 텍스트만 출력합니다.
이 숫자를 텍스트(형 숫자)로 바꿔주면 출력이 될 겁니다. 이렇게 형을 바꿔주는 방법은
str(숫자) 를 사용하시면 됩니다. 아래와 같이 되겠네요!
$Label.text = str(coin)
저장한 다음 실행해 봅시다.
혹시 여기서 += 을 = 으로수정하지 않았다면, 그건 또 재밌는 결과를 보실 수 있습니다 ㅎㅎㅎ
벌써 완성해 버린 클리커!
그런데 숫자만 적혀 있다보니 전달성이 좋지 못한 것 같군요.
조금 그럴 듯 하게 보이도록 출력되는 텍스트를 조금 더 붙여 봅시다.
$Label.text = “보유코인 : “ + str(coin)
지난번에 텍스트 더하기는 문자열이 이어진다는 것을 이미 본 적 있습니다.
■ 클릭 효율 버튼을 만들어 보자!
한번 클릭에 1씩 밖에 올라가지 않는 건, 클리커 답지 않군요.
일단 한번에 많이 올라가게 만들어 봅시다. 정말 간단합니다.
효율성 변수를 하나 추가해주고, 코인에 더해주는 값을 이 변수로 잡는 것 뿐이죠.
이제 클릭 한번마다 코인이 10개씩 증가하는 걸 볼 수 있습니다.
대소문자 실수만 없다면 막힘없이 진행하실 수 있을 겁니다.
변수명은 제 임의로 적은 단어일 뿐입니다. 여러분들이 원하시는 단어를 사용하셔도 됩니다.
다만 2개 정도만 조심해 주세요.
1. 반드시 소문자로 시작해야 합니다.
2. 한글로 적으면 프로그램이 인식하지 못하니 그것만 조심해 주세요.
고도엔진은 다국어 변수를 지원하긴 하지만, 종종 이로 인한 버그가 발생하니 처음부터 마음 놓을 수 있게 영어 변수만 이용해 주세요.
이 효율성 변수를 클릭할 때 마다 값을 추가하는 버튼을 만들어 보겠습니다.
“어? 이거 그냥 누를 때 마다 코인 추가하는 거 하고 완전히 같은 거 아니야?”
= 정확합니다. 그냥 코인 버튼이랑 똑같은데, 누를 때 마다 코인 대신 효율이 올라가는거죠.
이미 아는 부분은 최대한 스킵해서,
상단에 2D > Node2D를 누른 뒤 “+” 아이콘을 눌러 버튼 추가 > 버튼에 텍스트 입력 및 위치 조정 > 노드의 pressed() 더블클릭 > 연결
클릭하면 클릭 효율성이 1씩 추가되도록 코드를 한줄 추가해 줍시다.
그리고 테스트 용으로 크게 잡았던 coinEff = 10 도 1로 조정해 줍시다.
문제없이 작동해야 합니다!
문제가 있다면 거의 대소문자 문제일테니 한번 잘 살펴봅시다 ㅎㅎㅎ
그리고 현재의 클릭 효율을 출력하는 라벨을 추가로 만들어 보시는 것도 좋겠네요. 이미 배운 내용만으로도 충분히 만들 수 있을 겁니다.
■ 효율성 버튼에 가격을 추가해 봅시다.
그냥 마구 클릭되어선 게임답지 않겠죠.
효율성 향상 버튼을 누르면, 효율성 가격 만큼 코인이 소비되고, 가격도 오르도록 만들어 봅시다.
일단은 “업그레이드 가격”이라는 변수가 필요하겠죠?
1. 상단에 가격 변수를 추가해 줍시다.
var effPrice = 10
2. 효율성 향상 버튼을 누르면, 가격만큼 코인을 빼주는 코드를 추가해 줍시다.
덧샘에서 유추할 수 있 듯, 그냥 빼기를 추가해 주시면 되죠 ㅎㅎㅎ
coin = coin - effPrice
또는
coin -= effPrice
3. 효율성 향상 버튼을 누를 때마다 가격이, 기존 가격대비 1.5배씩 상승하도록 해주죠.
effPrice = effPrice *1.5
또는
effPrice *= 1.5
저장 후 실행을 해 보면...?
되긴 하는데, 효율성 버튼을 누를 때 코인이 갱신되지 않고, 코인이 - 값이 되는 경우도 있으며, 효율성 버튼 가격도 알 수가 없군요.
하나씩 수정해 봅시다.
■ godot 초보자의 치트키 : func _process(delta):
효율성 버튼을 눌렀을 때, 코인이 갱신되지 않는 이유는 간단합니다.
“이건 버튼이야!”를 눌렀을 때는
$Label.text = "보유코인 : " + str(coin)
이 코드가 동작하면서, 보유 코인이 계속 갱신됩니다.
즉, 효율성 버튼에도 위 코드를 그대로 붙여 넣으면, 분명 매우 잘 작동합니다.
하지만 중복되는 코드가 거슬리기도 하고, 다른 기능을 추가할 때마다 이 내용을 추가하기는 왠지 마음에 걸립니다.
여기서 godot이 초보자에게 제공하는 치트키이자, 우리가 계속 보면서도 없는 것으로 무시하던 녀석이 등장합니다.
func _process(delta):
pass
이 함수는 “매 프레임 마다 실행되는 코드” 입니다. 즉, 변수 값이 갱신 되건 변하지 않건, 항상 변수 값을 새로 받아와서 보여주는 것이죠.
여기의 pass를 지워주고 라벨을 갱신 시키는 내용을 옮겨 줍시다.
_process(_delta)에 라벨을 추가해 줬으니, 예전에 적어놨던 보유 코인은 지워버리시면 됩니다!
그리고 실행해 보면, 어떤 버튼을 누르더라도 실시간으로 갱신되는 코인 수량이 보이게 됩니다.
※ 그럼 처음부터 이 방법으로 가르쳐주지 그랬어!
이 방법은 정말로 매 프레임마다,
여러분들이 144hz 모니터와 그래픽 카드를 쓰고 있다면 1초에 144번이나 프로그램이 이 부분을 갱신하게 됩니다.
바로 최적화와 직결되어 있는 부분이죠. 물론 개인이 취미로 만드는 수준에서 여기에 뭘 넣건 컴 성능을 초과하기는 힘듭니다만,
그저, 이렇게도 할 수 있고, 저렇게도 할 수 있다. 정도의 다양한 방법 중의 하나로 생각해 주세요.
유니티의 경우도 똑같은 역할을 하는 Update()라는 함수를 지원하는데,
인디에서 만든 유니티 게임들이 무겁거나 버벅이는 대부분의 최적화 문제는,
바로 이 Update()에 모든 함수를 다 넣어버려서 발생하는게 대부분일 정도입니다.
그러니 정말 매 프레임 갱신되어야 할 UI가 아니라면 이쪽은 덜 사용하는 편이 좋다는 말이죠.
물론 위에서 말했듯, 우리들이 취미로 만드는 수준에서는 여기서 뭘 넣건 컴 성능을 웃돌 정도는 힘들긴 합니다 ㅎㅎㅎ
■ 효율성 가격을 버튼에 넣어 봅시다!
라벨의 text를 넣는 방법을 기억하시나요?완전히 100% 똑같이 할 수 있습니다. 단지 라벨 대신 버튼만 넣으면 될 뿐이죠!
그리고 이번에도 마찬가지로 실시간으로 갱신되도록 _process(delta): 함수에 집어 넣어 버립시다!
그리고 가격이 소숫점이 되는 것도 별로 좋지 않군요. 소숫점을 반올림해 버리는 함수를 추가해 줍시다.
엑셀로 업무를 보신 분에게는 익숙하실 반올림 함수 (심지어 사용법도 똑같은...)
round(숫자)를 넣어 주시면 됩니다.
※ 프로그래머의 꼼수 - 소수점 버리기로 구현하려면?
소수점을 지원하지 않는 숫자 형식 int(숫자) 를 사용하시면 됩니다^^
1. Button2를 클릭&드래그로 _process 쪽에 끌어나 놓아줍시다.
2. 그리고 버튼의 텍스트를 수정하는 것이니 .text = “텍스트”의 형태로 입력해 줍시다.
3. effPrice의 경우는 숫자이니, str(effPrice)를 사용해 텍스트 형으로 바꿔줍니다.
$Button2.text = "효율성 버튼 (" + str(effPrice) + ")"
4. effPrice 에 할당하는 값은 round(숫자) 함수를 사용해 소숫점 자리를 싹다 없애줍시다!
effPrice = round(effPrice * 1.5)
소수점도 안되고, 가격과 코인의 보유량도 실시간으로 갱신됩니다. 이제 마이너스 코인만 해결하면 되겠군요!
■ 버튼의 활성화 여부를 결정하자!
할 일은 간단합니다.
효율성 가격보다 코인이 많다 = 버튼을 누를 수 있다.
코인이 부족하다? = 버튼을 누를 수 없다.
우리가 버튼이나 라벨의 text를 수정한 것 처럼, 버튼의 인스펙터에 주목하면 해결 방법은 간단합니다.
버튼을 클릭할 수 있는 여부를 조절하는 인스펙터 값 = disabled 값을 조건에 맞춰 변하게만 만들어 주면 끝입니다.
그리고 보유 코인에 따라 실시간으로 변해야 하니, 이 조건은 process(delta)에 들어가면 되겠군요.
조건을 우리말로 적으면 아래와 같습니다.
만약 보유코인이 버튼 가격보다 적으면 (보유코인 < 버튼가격) :
버튼을 비활성화 = O
그게 아니라면 :
버튼을 비활성화 = X
if 문이 처음으로 등장하게 되는데, 게임을 만드는 사람들은 반복문 (for, while)보다도 월등히 많이, 자주 사용할 구조입니다.
그래서 별도의 시간을 들여 더욱 자세히 설명할 기회가 있으니, 지금은 간단하게 위의 내용을 그대로 if 문으로 옮기는 모습만 확인해 봅시다.
if coin < effPrice :
$Button2.disabled = true
else :
$Button2.disabled = false
위에 한국어로 적은 내용을 완전 그대로 옮긴 심플한 구조라 어려움은 없을 겁니다.
이걸 통해서 알 수 있는 것은 라벨이나 버튼의 “인스펙터에 있는 모든 설정값”은 위와 같은 방식으로 불러내서 변경할 수 있다는 것입니다.
여기서 true나 false 와 같은 값을 어떤 값을 넣어줘야 하는지는, 나중에 정말 확실하게 알 수 있는 방법을 소개해 드릴 예정입니다.
이제 소수점도 안나오고, 보유 코인과 효율성 버튼의 가격도 실시간으로 갱신되며, 코인이 부족하면 버튼이 비활성화 됩니다.
규칙을 플레이 하는 “게임”으로써의 형태가 갖춰지는 것이 슬슬 보입니다.
사칙연산으로 덧셈, 뺄셈, 곱셈까지는 다뤘지만, 나눗셈의 경우는 조금 사전 지식이 필요해 일단은
나눗셈 (몫) : /
9 / 3 =3
나머지 : %
9 % 3 = 0
정도로만 기억해 주시면 충분합니다. 나중에 조금 더 자세히 다룰 기회가 있을 테니까요.
다음 편에서는 버튼을 누를 때 마다, 코인 라벨이 뿅! 하고 나타났다 사라지는 "인스턴스"와 첫 애니메이션을 다룰 예정입니다.
이번편에서도 막히거나, 궁금하신 점은 언제든 댓글로 남겨주세요.
또는 먼저 다뤄줬으면 하는 내용이 있다면, 그것도 환영입니다!
《 고도 엔진 입문글 모음 - https://page.onstove.com/indie/global/view/10204130》
#godot #고도엔진 #입문 #튜토리얼 #게임만들기
촉촉한감자칩
🫡🫡🫡 즐겜을 위해 하루하루 살아가고 있습니다.
미소녀 게임, 건설 경영 게임을 사랑합니다!
재밌네요!!
안녕하세요! 덕분에 많이 배우고 있습니다.
예시의 if문은 process delta에 만 적용이 되더라고요
button2에 적었을 때 는 정상 작동 안 하는 이유를 혹시 알 수 있을까요?(효율성버튼 계속 비활성화)
process delta에 적힌 함수는 "매 프레임"마다 해당 함수를 실행합니다.
즉 매 프레임마다 코인이 충분한지 검토하고, 버튼을 활성화 시켜주거나 비활성화 시켜주게 되죠.
button2에 해당 함수가 들어가면, 버튼을 생성할 때, 단 한번만! 해당 함수를 실행합니다.
즉, 처음 버튼이 만들어 질 때의 상태를 계속 유지하고, 더 이상 if 문을 통해 활성화가 결정되지 않다보니, 상태가 변하지 않습니다.
게임 프로그래밍에서 delta가 정말 치트키죠. 매 프레임 변해야 한다면 싹다 delta에 넣어 버릴 수도 있습니다.
촉촉한감자칩아하! 답변 감사드립니다!
어...교수님 그러니까 챗 GPT한테 뭐라고 해야 이 클리커 게임을 만들어주는거죠?;;
이 글을 연재하는 이유 중 하나도 GPT에 있습니다. 현재 GPT-4o (유료버전)을 통해서라도 클리커 게임 하나 못 만들어 줍니다 ㅠㅠ
저도 종종 도움 받는데, 성공 확률은 대충 1/3 정도 되네요. 학습된 자료가 대부분 대 격변 이전 3.0 버전을 기준으로 답변을 해 줘서, 작동 안되는 경우가 더 많습니다 ㅠㅠ
헉... 그래서 일단 저 코인 사두면 오르는거죠?
ㅋㅋㅋㅋㅋ
오우 개발자이신가 보네요 ㄷㄷ
전공을 잘못 선택한 것 같아요 ㅋㅋㅋㅋ
개발자는 결코 아니고, 취미로 개발 공부를 하는 아마추어입니다 ㅎㅎㅎ
아마추어인 저라도 괜찮은 결과를 쉽게 얻을 수 있는 godot 엔진의 도구빨인 것 같습니다!
고수;;
과찬이십니다 ㅎㅎㅎ
설명을 일일이 적어서 길어 보일 뿐이지, 직접 해 보시면 생각보다 별거 아닐겁니다! ㅎㅎㅎ