-
[게임엔진활용] 4강 미니(사과)게임 제작[DSU] 게임엔진활용 2026. 4. 7. 00:07728x90
지난 시간까지 구현한 함수들을 활용해서, 작은 프로젝트로 사과 게임을 제작.
RenderView.cs에서 Start와 파괴자에서 loadGame, freeGame 각각 호출
123456789101112131415public class RenderView : MonoBehaviour{// ...void Start(){// ...loadGame();}~RenderView(){freeGame();}cs 그리고 OnGUI에서 drawGame을 호출
123456789101112131415161718192021222324252627282930313233343536373839void OnGUI(){if (Event.current.type != EventType.Repaint)return;GL.Clear(true, true, Color.black);#if falseGUI.color = Color.white;GUI.DrawTexture(new Rect(0, 0, Screen.width, Screen.height),mc.rt, ScaleMode.ScaleToFit);//StretchToFill#elseMaterial m = material[materialIndex];m.SetColor("_BaseColor", Color.white);m.SetTexture("_BaseMap", mc.rt);m.SetFloat("size", mozicSize);m.SetFloat("iTime", playbackTime);playbackTime += Time.deltaTime;m.SetVector("iMouse", new Vector4(0, 0, 0, 0));Graphics.DrawTexture(mc.viewport, mc.rt, m);#endifRenderTexture texBack = RenderTexture.active;RenderTexture.active = texGame;// mc.rt;Matrix4x4 matBack = GUI.matrix;GUI.matrix = Matrix4x4.TRS(Vector3.zero, Quaternion.identity, Vector3.one);GL.Clear(true, true, Color.clear);drawGame(Time.deltaTime);// do something ...RenderTexture.active = texBack;GUI.matrix = matBack;GUI.matrix = Matrix4x4.TRS(new Vector3(mc.viewport.x, mc.viewport.y, 0),Quaternion.identity,new Vector3((float)(Screen.width - mc.viewport.x * 2) / mc.devWidth,(float)(Screen.height - mc.viewport.y * 2) / mc.devHeight, 1.0f));drawImage(texGame, 0, 0, TOP | LEFT);//mc.rt}cs MainCamera.cs에서 mouseGame 호출
12345678910111213141516171819202122232425262728293031323334void Update(){// ...if (Mouse.current.leftButton.wasPressedThisFrame){Vector2 p = convertPosition(Mouse.current.position.value);rv.mouseGame(0, p.x, p.y);//drag = true;}else if (Mouse.current.leftButton.wasReleasedThisFrame){Vector2 p = convertPosition(Mouse.current.position.value);rv.mouseGame(2, p.x, p.y);//drag = false;}else// if( drag ){Vector2 p = convertPosition(Mouse.current.position.value);rv.mouseGame(1, p.x, p.y);}}//bool drag = false;Vector2 convertPosition(Vector2 p){p.x = devWidth * (p.x - viewport.x) / viewport.width;p.y = devHeight * (1f - (p.y - viewport.y) / viewport.height);//Debug.LogFormat($"({p.x}, {p.y})");return p;}cs 사과 게임 메인 로직은 title과 inGame으로 구분.
1. title
- 배경이미지와 Play버튼 구성
2. inGame
- 랜덤(1~9) 값을 가진 사과가 총 15 x 10개가 있으며, 드래그시 선택된 사과의 숫자 합이 10이면 포함된 사과는 모두 제거함.
- 제한된 시간 2분 동안 최대한 많은 사과를 제거하는 것이 목표이며, 사과 하나 제거시 점수 1점 획득.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367int gameState;// 0:title, 1:inGamevoid loadGame(){gameState = 0;loadTitle();}void freeGame(){switch (gameState){case 0: freeTitle(); break;case 1: freeIngame(); break;}}void drawGame(float dt){switch (gameState){case 0: drawTitle(dt); break;case 1: drawIngame(dt); break;}}public void mouseGame(int state, float x, float y){switch (gameState){case 0: mouseTitle(state, x, y); break;case 1: mouseIngame(state, x, y); break;}}// backgroud, button(play)Texture texLogo;struct Button{public Rect rt;public string s;public bool pressed;public Color cb;public Color ch;public Color cf;public float size;}Button btnPlay;void loadTitle(){texLogo = createImage("logo");Button b = new Button();b.rt = new Rect(10, 10, 400, 300);b.s = "Play";b.pressed = false;b.cb = Color.red;// 기본b.ch = Color.blue;// 커서b.cf = Color.white;b.size = 300;btnPlay = b;}void freeTitle(){}void drawButton(Button b){Rect rt = b.rt;Color c = b.pressed ? b.ch : b.cb;setRGBA(c.r, c.g, c.b, c.a);fillRect(rt.x, rt.y, rt.width, rt.height);setRGBA(1, 1, 1, 1);setStringName("굴림");float stringSize = b.size;setStringSize(stringSize);Vector2 size = sizeOfString(b.s);if (size.x > rt.width)setStringSize(stringSize * rt.width / size.x);setStringRGBA(b.cf.r, b.cf.g, b.cf.b, b.cf.a);drawString(b.s, rt.x + rt.width / 2,rt.y + rt.height / 2, VCENTER | HCENTER);}void drawTitle(float dt){float rx = (float)mc.devWidth / texLogo.width;float ry = (float)mc.devHeight / texLogo.height;drawImage(texLogo, 0, 0, 0, 0, texLogo.width, texLogo.height,TOP | LEFT, rx, ry);drawButton(btnPlay);}bool containPoint(float x, float y, Rect rt){if (x < rt.x ||x > rt.x + rt.width ||y < rt.y ||y > rt.y + rt.height)return false;return true;}bool containRect(Rect rt0, Rect rt1){if (rt0.x + rt0.width < rt1.x ||rt0.x > rt1.x + rt1.width ||rt0.y + rt0.height < rt1.y ||rt0.y > rt1.y + rt1.height)return false;return true;}public void mouseTitle(int state, float x, float y){switch (state){case 0:if (btnPlay.pressed){gameState = 1;freeTitle();loadIngame();}break;case 1:btnPlay.pressed = containPoint(x, y, btnPlay.rt);break;}}Button[] apple;int score;float playTime, _playTime;bool gameOver;Button[] btnResult;public static Color cGreen = new Color(0.1f, 0.5f, 0.0f, 1.0f);void loadIngame(){// 60 * 15float x = (mc.devWidth - 60 * 15) / 2;float y = (mc.devHeight - 60 * 10) / 2;apple = new Button[15 * 10];for (int i = 0; i < apple.Length; i++){Button b = new Button();b.s = "" + UnityEngine.Random.Range(1, 10);b.rt = new Rect(x + 60 * (i % 15), y + 60 * (i / 15), 50, 50);b.cb = cGreen;//Color.green;b.ch = Color.yellow;b.cf = Color.white;b.pressed = false;b.size = 30;apple[i] = b;}score = 0;_playTime = 120f;playTime = 120f;gameOver = false;btnResult = new Button[2];string[] s = new string[2] { "다시시작", "나가기" };for (int i = 0; i < btnResult.Length; i++){Button b = new Button();b.s = s[i];b.rt = new Rect(500 + 120 * i, 350, 100, 50);b.cb = Color.blue;b.ch = Color.black;b.cf = Color.white;b.pressed = false;b.size = 30;btnResult[i] = b;}}void freeIngame(){}void drawIngame(float dt){for (int i = 0; i < apple.Length; i++){if (apple[i].s == "0")continue;drawButton(apple[i]);}if (drag){setRGBA(0, 0, 1, 0.5f);Rect rt = dragRect();fillRect(rt.x, rt.y, rt.width, rt.height);setRGBA(1, 1, 1, 1);//setLineWidth(1);//drawRect(rt.x, rt.y, rt.width, rt.height);}setStringName("고딕체");setStringSize(30);setStringRGBA(1, 0, 0, 1);drawString("Score : " + score, mc.devWidth - 10, 10, TOP | RIGHT);setRGBA(0, 1, 0, 1);float h = mc.devHeight - 100;float dh = h * playTime / _playTime;fillRect(mc.devWidth - 20, 50 + h - dh, 5, dh);drawRect(mc.devWidth - 20, 50, 5, h);setRGBA(1, 1, 1, 1);playTime -= dt;if (playTime <= 0f){gameOver = true;}if (gameOver){setStringName("고딕체");setStringSize(100);setStringRGBA(1, 0, 0, 1);drawString("Score : " + score, 400, 200, TOP | LEFT);for (int i = 0; i < btnResult.Length; i++)drawButton(btnResult[i]);}}bool drag = false;float sx, sy, ex, ey;Rect dragRect(){float x0, x1, y0, y1;if (sx < ex) { x0 = sx; x1 = ex; }else { x0 = ex; x1 = sx; }if (sy < ey) { y0 = sy; y1 = ey; }else { y0 = ey; y1 = sy; }return new Rect(x0, y0, x1 - x0 - 1, y1 - y0 - 1);}public void mouseIngame(int state, float x, float y){if (mouseGameOver(state, x, y))return;if (state == 0){sx = ex = x;sy = ey = y;drag = true;}else if (state == 2){drag = false;int sum = 0;for (int i = 0; i < apple.Length; i++){if (apple[i].pressed){int n = Int32.Parse(apple[i].s);sum += n;}}if (sum == 10){Debug.Log("제거하자");for (int i = 0; i < apple.Length; i++){if (apple[i].pressed){apple[i].s = "0";score++;}}}else{for (int i = 0; i < apple.Length; i++){if (apple[i].pressed)apple[i].pressed = false;}}}else if (drag){ex = x;ey = y;Rect rt = dragRect();for (int i = 0; i < apple.Length; i++)apple[i].pressed = false;for (int i = 0; i < apple.Length; i++){if (containRect(rt, apple[i].rt)){if(apple[i].s != "0")apple[i].pressed = true;}}}}bool mouseGameOver(int state, float x, float y){if (gameOver == false)return false;switch (state){case 0:for (int i = 0; i < btnResult.Length; i++){if (btnResult[i].pressed){if (i == 0){// 다시시작for (int j = 0; j < apple.Length; j++){apple[j].s = "" + UnityEngine.Random.Range(1, 10);apple[j].pressed = false;}score = 0;playTime = _playTime;gameOver = false;}else{// 나가기gameState = 0;freeIngame();loadTitle();}break;}}break;case 1:for (int i = 0; i < btnResult.Length; i++)btnResult[i].pressed = containPoint(x, y, btnResult[i].rt);break;}return true;}cs 애플게임 (https://www.gamesaien.com/game/fruit_box_a)
1) drawLine, fill(draw)Rect, drawImage, drawString 등 소수의 함수로 게임 제작함.
2) 엔진에서 제공하는 기능(컴포넌트 등)이 만들어지는 과정을 설명하기 위한 용도.
3) 최종적으로 라이브러리를 만들어 가는 과정을 통해, 게임 엔진에 대한 이해 향상하는것이 최종 목표.키보드 조작으로 Hierachy에 포함된 오브젝트를 보는 카메라 조정 가능하며, RenderView MaterialIndex값을 변경하여 각종 Shader효과를 확인 가능.

'[DSU] 게임엔진활용' 카테고리의 다른 글
[게임엔진활용] 6-1강 operator (0) 2026.04.20 [게임엔진활용] 5강 AutoNumber, ProgressBar (0) 2026.04.13 [게임엔진활용] 3강 Geometry, Texture, String (0) 2026.03.30 [게임엔진활용] 2강 게임 개발 해상도(더블버퍼링, 뷰포트) (0) 2026.03.25 [게임엔진활용] 1-5강 쉐이더토이 적용 (0) 2026.03.16

