PowerPoint 프레젠테이션

Similar documents
PowerPoint 프레젠테이션

PowerPoint 프레젠테이션

chap 5: Trees

PowerPoint 프레젠테이션

adfasdfasfdasfasfadf

<4D F736F F F696E74202D20C1A63038C0E520C5ACB7A1BDBABFCD20B0B4C3BC4928B0ADC0C729205BC8A3C8AF20B8F0B5E55D>

Microsoft PowerPoint - chap04-연산자.pptx

Microsoft PowerPoint - chap02-C프로그램시작하기.pptx

Microsoft PowerPoint 자바-기본문법(Ch2).pptx

K&R2 Reference Manual 번역본

UI TASK & KEY EVENT

Microsoft PowerPoint - chap05-제어문.pptx

PowerPoint 프레젠테이션

Microsoft PowerPoint - 6-PythonGUI-sprite

쉽게 풀어쓴 C 프로그래밍

C프로-3장c03逞풚

Infinity(∞) Strategy

Microsoft PowerPoint PythonGUI-sprite

1

이장에서다룰내용 테두리를제어하는스타일시트 외부여백 (Margin) 과내부여백 (Padding) 관련속성 위치관련속성 2

Java ...

PowerPoint 프레젠테이션

Microsoft PowerPoint - Java7.pptx

슬라이드 1

PowerPoint Presentation

<4D F736F F F696E74202D B3E22032C7D0B1E220C0A9B5B5BFECB0D4C0D3C7C1B7CEB1D7B7A1B9D620C1A638B0AD202D20C7C1B7B9C0D320BCD3B5B5C0C720C1B6C0FD>

JAVA 프로그래밍실습 실습 1) 실습목표 - 메소드개념이해하기 - 매개변수이해하기 - 새메소드만들기 - Math 클래스의기존메소드이용하기 ( ) 문제 - 직사각형모양의땅이있다. 이땅의둘레, 면적과대각

(8) getpi() 함수는정적함수이므로 main() 에서호출할수있다. (9) class Circle private double radius; static final double PI= ; // PI 이름으로 로초기화된정적상수 public

Visual Basic 반복문

A Hierarchical Approach to Interactive Motion Editing for Human-like Figures

Analytics > Log & Crash Search > Unity ios SDK [Deprecated] Log & Crash Unity ios SDK. TOAST SDK. Log & Crash Unity SDK Log & Crash Search. Log & Cras

Microsoft PowerPoint - 3ÀÏ°_º¯¼ö¿Í »ó¼ö.ppt

게임 기획서 표준양식 연구보고서

PowerPoint Presentation

Lab 3. 실습문제 (Single linked list)_해답.hwp

PowerPoint Presentation

(Microsoft PowerPoint - \301\24613\260\255 - oFusion \276\300 \261\270\274\272)

PowerPoint 프레젠테이션

유니티 변수-함수.key

제8장 자바 GUI 프로그래밍 II

슬라이드 1

(Microsoft PowerPoint - \301\24608\260\255 - \261\244\277\370\260\372 \300\347\301\372)

Microsoft PowerPoint - ch09 - 연결형리스트, Stack, Queue와 응용 pm0100

설계란 무엇인가?

PowerPoint 프레젠테이션

Microsoft Word - FunctionCall

4 장클래스와객체 클래스와객체 public과 private 구조체와클래스객체의생성과생성자객체의소멸과소멸자생성자와소멸자의호출순서디폴트생성자와디폴트소멸자멤버초기화멤버함수의외부정의멤버함수의인라인함수선언 C++ 프로그래밍입문

Microsoft PowerPoint - ÀÚ¹Ù08Àå-1.ppt

[ 마이크로프로세서 1] 2 주차 3 차시. 포인터와구조체 2 주차 3 차시포인터와구조체 학습목표 1. C 언어에서가장어려운포인터와구조체를설명할수있다. 2. Call By Value 와 Call By Reference 를구분할수있다. 학습내용 1 : 함수 (Functi

슬라이드 1

설계란 무엇인가?

<4D F736F F F696E74202D20C1A63034B0AD202D20C7C1B7B9C0D3B8AEBDBAB3CABFCD20B9ABB9F6C6DBC0D4B7C2>

Chapter 4. LISTS

슬라이드 1

02 C h a p t e r Java

슬라이드 1

PowerPoint 프레젠테이션

PowerPoint Presentation

API 매뉴얼

chap01_time_complexity.key

PowerPoint 프레젠테이션

Microsoft PowerPoint - 04-UDP Programming.ppt

gnu-lee-oop-kor-lec10-1-chap10

Lab 4. 실습문제 (Circular singly linked list)_해답.hwp

Contents. 1. PMD ㆍㆍㆍㆍㆍㆍㆍㆍㆍㆍㆍㆍㆍㆍㆍㆍㆍㆍㆍㆍㆍㆍㆍㆍㆍㆍㆍㆍㆍㆍㆍ 2. Metrics ㆍㆍㆍㆍㆍㆍㆍㆍㆍㆍㆍㆍㆍㆍㆍㆍㆍㆍㆍㆍㆍㆍㆍㆍㆍㆍㆍㆍㆍㆍㆍ 3. FindBugs ㆍㆍㆍㆍㆍㆍㆍㆍㆍㆍㆍㆍㆍㆍㆍㆍㆍㆍㆍㆍㆍㆍㆍㆍㆍㆍㆍㆍㆍㆍㆍ 4. ㆍㆍㆍㆍㆍㆍㆍㆍㆍㆍㆍ

<4D F736F F F696E74202D20C1A63036C0E520BCB1C5C3B0FA20B9DDBAB928B0ADC0C729205BC8A3C8AF20B8F0B5E55D>

PowerPoint Presentation

iii. Design Tab 을 Click 하여 WindowBuilder 가자동으로생성한 GUI 프로그래밍환경을확인한다.

Microsoft PowerPoint - java1-lab5-ImageProcessorTestOOP.pptx

OCW_C언어 기초

Microsoft PowerPoint - 알고리즘_5주차_1차시.pptx

Gray level 변환 및 Arithmetic 연산을 사용한 영상 개선

Microsoft PowerPoint - Chap12-OOP.ppt

Microsoft PowerPoint - C++ 5 .pptx

슬라이드 1

DocsPin_Korean.pages

BMP 파일 처리

슬라이드 1

Chapter 4. LISTS

Microsoft PowerPoint - chap06-1Array.ppt

제이쿼리 (JQuery) 정의 자바스크립트함수를쉽게사용하기위해만든자바스크립트라이브러리. 웹페이지를즉석에서변경하는기능에특화된자바스크립트라이브러리. 사용법 $( 제이쿼리객체 ) 혹은 $( 엘리먼트 ) 참고 ) $() 이기호를제이쿼리래퍼라고한다. 즉, 제이쿼리를호출하는기호

var answer = confirm(" 확인이나취소를누르세요."); // 확인창은사용자의의사를묻는데사용합니다. if(answer == true){ document.write(" 확인을눌렀습니다."); else { document.write(" 취소를눌렀습니다.");

Microsoft PowerPoint - Lect04.pptx

4장.문장

Microsoft PowerPoint - logo_2-미해답.ppt [호환 모드]

API 매뉴얼

금오공대 컴퓨터공학전공 강의자료

Windows 8에서 BioStar 1 설치하기

Chap 6: Graphs

Chapter #01 Subject

Microsoft PowerPoint - CSharp-10-예외처리

JUNIT 실습및발표

프로그램을 학교 등지에서 조금이라도 배운 사람들을 위한 프로그래밍 노트 입니다. 저 역시 그 사람들 중 하나 입니다. 중고등학교 시절 학교 도서관, 새로 생긴 시립 도서관 등을 다니며 책을 보 고 정리하며 어느정도 독학으르 공부하긴 했지만, 자주 안하다 보면 금방 잊어

자바로

JAVA PROGRAMMING 실습 08.다형성

<443A5C4C C4B48555C B3E25C32C7D0B1E25CBCB3B0E8C7C1B7CEC1A7C6AE425CBED0C3E0C7C1B7CEB1D7B7A55C D616E2E637070>

Microsoft PowerPoint - lec2.ppt

Spring Boot/JDBC JdbcTemplate/CRUD 예제

PowerPoint 프레젠테이션

Transcription:

퍼즐게임만들기

레 벨 퍼즐게임만들기 구 현 디 자 인 하 기 블 록 연 기획하기 쇄 2

레 벨 퍼즐게임만들기 구 현 디 자 인 하 기 블 록 연 기획하기 쇄 3

* 퍼즐게임기획하기 기획단계 게임주제 아이디어정리 기획서작성 사양서작성 연달아있어도사라지지않는 3 매치퍼즐 ex) 헥사 종이에연필로마구잡이식으로써본다 규칙, 캐릭터등 게임실행화면각요소별로만들기 4

* 퍼즐게임기획 - 규칙 기획단계 다음과같은규칙을가지고게임을제작하도록한다. - 모아야할블록수는세개 - 사라질때까지시간이걸린다 ( 투명도조절을해서사라지는것을표현 ) - 점수는연쇄했을때더높은점수를얻을수있도록한다 - 블록은언제든지자유롭게교체할수있다 - 연속교체불붙이기 ( 블록이사라지기전에연속적으로엮어서사라지도록 ) - 사라진블록은위에서보충 - 게임종료규칙을만든다. ( 제한시간, 10턴이내에 1만점획득등 ) 5

* 퍼즐게임기획서 기획단계 6

* 퍼즐게임사양서 기획단계 7

* 게임에필요한데이터정리 기획단계 8

레 벨 퍼즐게임만들기 구 현 디 자 인 하 기 블 록 연 기획하기 쇄 9

* 프로그램작성순서 구현단계 1. 블록을바닥에채운다. 2. 블록을마우스로잡는다. 3. 잡은블록을상하좌우로교체한다. 4. 가로세로같은색세개가모이면블록에불을붙여사라지게한다. 5. 사라진만큼블록을위에서채운다. 6. 점수가더해지도록한다. 7. 레벨디자인 ( 난이도조정 ) 을한다. 8. 시퀀스를연결한다. 10

1. 블록을바닥에채운다. 구현단계 - 프로젝트만들기 1 [File] [New Project] 로원하는위치에 Plattach 폴더를만들고지정한다. 2 유니티에디터가재시작된다. 3 [GameObject] [Create Other] [Directional Light] 로조명을생성한다. 4 [File] [Save Scene] 를실행하고 GameScene 으로저장한다. - 필요한스크립트준비 1 [GameObject] [Create Empty] 을선택하고 GameRoot 로이름을변경한다. 2 [GameObject] [Create Other] [Cube] 를선택하고 Block 으로이름을변경한다. 3 [Assets] [Create] [C# Script] 로 SceneControl, BlockRoot. BlockControl 스크립트를만든다. 4 [GameRoot] 에 SceneControl 스크립트와 BlockRoot 스크립트를컴포넌트로등록한다. 5 Block에 BlockControl 스크립트를컴포넌트로등록한다. 6 Block을 Project 브라우저로드래그앤드롭하여프리팹으로만든다. 7 Project 브라우저의 Block을 BlockPrefab 으로이름변경한다. 8 씬에있는 BlockPrefab을삭제한다 (Hierarchy에서삭제 ). 11

1. 블록을바닥에채운다. 구현단계 * 블록나열하기 BlockControl.cs // 블록에관한정보를다룬다. public class Block { public static float COLLISION_SIZE = 1.0f; // 블록의충돌크기. public static float VANISH_TIME = 3.0f; // 불붙고사라질때까지의시 간. public struct iposition { // 그리드에서의좌표를나타내는구조체. public int x; // X 좌표. public int y; // Y 좌표. public enum COLOR { // 블록색상. NONE = -1, // 색지정없음. PINK = 0, // 분홍색. BLUE, // 파란색. YELLOW, // 노란색. GREEN, // 녹색. MAGENTA, // 마젠타. ORANGE, // 주황색. GRAY, // 그레이. NUM, // 컬러가몇종류인지나타낸다 (=7). FIRST = PINK, // 초기컬러 ( 분홍색 ). LAST = ORANGE, // 최종컬러 ( 주황색 ). NORMAL_COLOR_NUM = GRAY.; // 보통컬러 ( 회색이외의색 ) 의수. public enum DIR4 { // 상하좌우네방향. NONE = -1, // 방향지정없음. RIGHT, // 우. LEFT, // 좌. UP, // 상. DOWN, // 하. NUM, // 방향이몇종류있는지나타낸다 (=4). ; public static int BLOCK_NUM_X = 9; // 블록을배치할수있는 X 방향최대수. public static int BLOCK_NUM_Y = 9; // 블록을배치할수있는 Y 방향최대수. 12

1. 블록을바닥에채운다. 구현단계 * 블록나열하기 BlockControl.cs public class BlockControl : MonoBehaviour { public Block.COLOR color = (Block.COLOR); // 블록색. public BlockRoot block_root = null; // 블록의신. public Block.iPosition i_pos; // 블록좌표. void Start() { this.setcolor(this.color); // 색칠을한다. void Update() { // 인수 color의색으로블록을칠한다. public void setcolor(block.color color) { this.color = color; // 이번에지정된색을멤버변수에보관한다. Color color_value; // Color 클래스는색을나타낸다. switch(this.color) { // 칠할색에따라서갈라진다. default: case Block.COLOR.PINK: color_value = new Color(1.0f, 0.5f, 0.5f); break; case Block.COLOR.BLUE: color_value = Color.blue; break; case Block.COLOR.YELLOW: color_value = Color.yellow; break; case Block.COLOR.GREEN: color_value = Color.green; break; case Block.COLOR.MAGENTA: color_value = Color.magenta; break; case Block.COLOR.ORANGE: color_value = new Color(1.0f, 0.46f, 0.0f); break; // 이게임오브젝트의머티리얼색상을변경한다. this.renderer.material.color = color_value; 13

1. 블록을바닥에채운다. 구현단계 * 블록나열하기 BlockRoot.cs 블록을가로세로바둑판모양으로관리 14

1. 블록을바닥에채운다. 구현단계 * 블록나열하기 BlockRoot.cs BlockRoot.cs public class BlockRoot : MonoBehaviour { public GameObject BlockPrefab = null; // 만들어낼블록의프리팹. public BlockControl[,] blocks; // 그리드. void Start() { void Update() { // 블록을만들어내고가로 9 칸, 세로 9 칸에배치한다. public void initialsetup(){ // 그리드의크기를 9 9 로한다. this.blocks = new BlockControl [Block.BLOCK_NUM_X, Block.BLOCK_NUM_Y]; // 블록의색번호. int color_index = 0; for(int y = 0; y < Block.BLOCK_NUM_Y; y+ +) { // 처음 ~ 마지막행 for(int x = 0; x < Block.BLOCK_NUM_X; x+ +) { // 왼쪽 ~ 오른쪽 // BlockPrefab 의인스턴스를씬에만든다. GameObject game_object = Instantiate(this.BlockPrefab) as GameObject; // 위에서만든블록의 BlockControl 클래스를가져온다. BlockControl block = game_object.getcomponent<blockcontrol>(); // 블록을그리드에저장한다. this.blocks[x, y] = block; // 블록의위치정보 ( 그리드좌표 ) 를설정한다. block.i_pos.x = x; block.i_pos.y = y; // 각 BlockControl 이연계할 GameRoot 는자신이라고설정한다. block.block_root = this; // 그리드좌표를실제위치 ( 씬의좌표 ) 로변환한다. Vector3 position = BlockRoot.calcBlockPosition(block.i_pos); // 씬의블록위치를이동한다. block.transform.position = position; // 블록의색을변경한다. block.setcolor((block.color)color_index); // 블록의이름을설정 ( 후술 ) 한다. block.name = "block(" + block.i_pos.x.tostring() + "," + block.i_pos.y.tostring() + ")"; // 전체색중에서임의로하나의색을선택한다. color_index = Random.Range(0, (int)block.color.normal_color_num); 15

1. 블록을바닥에채운다. 구현단계 * 블록나열하기 BlockRoot.cs BlockRoot.cs // 지정된그리드좌표로씬에서의좌표를구한다. public static Vector3 calcblockposition(block.iposition i_pos) { // 배치할왼쪽위구석위치를초기값으로설정한다. Vector3 position = new Vector3(-(Block.BLOCK_NUM_X / 2.0f - 0.5f), -(Block.BLOCK_NUM_Y / 2.0f - 0.5f), 0.0f); // 초깃값 + 그리드좌표 블록크기. position.x += (float)i_pos.x * Block.COLLISION_SIZE; position.y += (float)i_pos.y * Block.COLLISION_SIZE; return(position); // 씬에서의좌표를반환한다. 16

1. 블록을바닥에채운다. 구현단계 * 블록나열하기 SceneControl.cs public class SceneControl : MonoBehaviour { private BlockRoot block_root = null; void Start() { // BlockRoot 스크립트를가져온다. this.block_root = this.gameobject.getcomponent<blockroot>(); // BlockRoot 스크립트의 initialsetup() 을호출한다. this.block_root.initialsetup(); void Update() { 17

2. 마우스로블록잡기 구현단계 BlockControl.cs / Block 클래스 // 블록이어던상태인지알려주는클래스 public enum STEP { NONE = -1, // 상태정보없음. IDLE = 0, // 대기중. GRABBED, // 잡혀있음. RELEASED, // 떨어진순간. SLIDE, // 슬라이드중. VACANT, // 소멸중. RESPAWN, // 재생성중. FALL, // 낙하중. LONG_SLIDE, // 크게슬라이드중. NUM, // 상태가몇종류인지표시. ; BlockControl.cs / BlockControl 클래스 public Block.STEP step = Block.STEP.NONE; // 지금상태. public Block.STEP next_step = Block.STEP.NONE; // 다음상태. private Vector3 position_offset_initial = Vector3.zero; // 교체전위치. public Vector3 position_offset = Vector3.zero; // 교체후위치. void Start() { this.setcolor(this.color); this.next_step = Block.STEP.IDLE; // 다음블록을대기중으로. 18

2. 마우스로블록잡기 구현단계 Update() : 블록이잡혔을때에블록을크게하고그렇지않을때는원래대로돌아간다. BlockControl.cs / BlockControl 클래스 void Update() { Vector3 mouse_position; // 마우스위치. this.block_root.unprojectmouseposition( // 마우스위치획득. out mouse_position, Input.mousePosition); // 획득한마우스위치를 X와 Y만으로한다. Vector2 mouse_position_xy = new Vector2(mouse_position.x, mouse_position.y); // ' 다음블록 ' 상태가 ' 정보없음 ' 이외인동안. // =' 다음블록 ' 상태가변경된경우. while(this.next_step!= Block.STEP.NONE) { this.step = this.next_step; this.next_step = Block.STEP.NONE; switch(this.step) { case Block.STEP.IDLE: // ' 대기 ' 상태. this.position_offset = Vector3.zero; // 블록표시크기를보통크기로한다. this.transform.localscale = Vector3.one * 1.0f; break; case Block.STEP.GRABBED: // ' 잡힌 ' 상태. // 블록표시크기를크게한다. this.transform.localscale = Vector3.one * 1.2f; break; case Block.STEP.RELEASED: // ' 떨어져있는 ' 상태. this.position_offset = Vector3.zero; // 블록표시크기를보통사이즈로한다. this.transform.localscale = Vector3.one * 1.0f; break; // 그리드좌표를실제좌표 ( 씬의좌표 ) 로변환하고. // position_offset을추가한다. Vector3 position = BlockRoot.calcBlockPosition(this.i_pos) + this.position_offset; // 실제위치를새로운위치로변경한다. this.transform.position = position; 19

2. 마우스로블록잡기 구현단계 BlockControl.cs / BlockControl 클래스 public void begingrab(){ // 잡혔을때호출 this.next_step = Block.STEP.GRABBED; public void endgrab() // 놓았을때호출 { This.next_step = Block.STEP.IDLE; public bool isgrabbable() // 잡을수있는상태인지판단. { bool is_grabbable = false; switch(this.step) { case Block.STEP.IDLE: // ' 대기 ' 상태일때만. is_grabbable = true; // true( 잡을수있다 ) 를반환한다. break; return(is_grabbable); public bool iscontainedposition(vector2 position){ // 지정된마우스좌표가자신과겹치는지확인 bool ret = false; Vector3 center = this.transform.position; float h = Block.COLLISION_SIZE / 2.0f; do { // X 좌표가자신과겹치지않으면 break로루프를빠져나간다. if(position.x < center.x - h center.x + h < position.x) { break; // Y 좌표가자신과겹치지않으면 break로루프를빠져나간다. if(position.y < center.y - h center.y + h < position.y) { break; // X 좌표, Y 좌표모두겹쳐있으면 true( 겹쳐있다 ) 를반환한다. ret = true; while(false); return(ret); 20

2. 마우스로블록잡기 구현단계 BlockRoot.cs // 블록을잡는데필요한멤버변수선언 private GameObject main_camera = null; // 메인카메라. private BlockControl grabbed_block = null; // 잡은블록. void Start() { this.main_camera = GameObject.FindGameObjectWithTag("MainCamera"); // 카메라로부터마우스커서를통과하는광선을쏘기위해서필요 void Update() { Vector3 mouse_position; // 마우스위치. this.unprojectmouseposition( // 마우스위치를가져온다. out mouse_position, Input.mousePosition); // 가져온마우스위치를하나의 Vector2로모은다. Vector2 mouse_position_xy = new Vector2(mouse_position.x, mouse_position.y); if(this.grabbed_block == null) { // 잡은블록이비었으면. // if(!this.is_has_falling_block()) { 나중에주석처리벗긴다. if(input.getmousebuttondown(0)) { // 마우스버튼이눌렸으면 // blocks 배열의모든요소를차례로처리한다. foreach(blockcontrol block in this.blocks) { if(! block.isgrabbable()) { // 블록을잡을수없다면. continue; // 루프의처음으로점프한다. // 마우스위치가블록영역안이아니면. if(!block.iscontainedposition(mouse_position_xy)) { continue; // 루프의처음으로점프한다. // 처리중인블록을 grabbed_block에등록한다. this.grabbed_block = block; // 잡았을때의처리를실행한다. this.grabbed_block.begingrab(); break; // else { // 블록을잡았을때. if(! Input.GetMouseButton(0)) { // 마우스버튼이눌려져있지않으면. this.grabbed_block.endgrab(); // 블록을놨을때의처리를실행. this.grabbed_block = null; // grabbed_block을비우게설정. 21

2. 마우스로블록잡기 구현단계 unprojectmouseposition( ) 22

2. 마우스로블록잡기 구현단계 BlockRoot.cs public bool unprojectmouseposition( out Vector3 world_position, Vector3 mouse_position) { bool ret; // 판을작성한다. 이판은카메라에대해서뒤로향해서 (Vector3.back). // 블록의절반크기만큼앞에둔다. Plane plane = new Plane(Vector3.back, new Vector3( 0.0f, 0.0f, -Block.COLLISION_SIZE / 2.0f)); // 카메라와마우스를통과하는빛을만든다. Ray ray = this.main_camera.getcomponent<camera>().screenpointtoray( mouse_position); float depth; // 광선 (ray) 이판 (plane) 에닿았다면. if(plane.raycast(ray, out depth)) { // 광선이닿았으면 depth에정보가기록된다 // 인수 world_position을마우스위치로덮어쓴다. world_position = ray.origin + ray.direction * depth; ret = true; // 닿지않았다면. else { // 인수 world_position을 0인벡터로덮어쓴다. world_position = Vector3.zero; ret = false; return(ret); // 카메라를통과하는광선이블록에닿았는지를반환 23

3. 블록교체 구현단계 지금까지의프로그래밍을통해블록을잡을수있게되었다. 게임을진행하기위해서는주변블록을교체할수있어야한다. 24

3. 블록교체 구현단계 * calcslidedir() : 인수로지정한마우스위치를바탕으로어느쪽으로슬라이드되었는지판단하고그방향을 Block.DIR4 형값으로반환 BlockControl.cs public float vanish_timer = -1.0f; // 블록이사라질때까지의시간. public Block.DIR4 slide_dir = Block.DIR4.NONE; // 슬라이드된방향. public float step_timer = 0.0f; // 블록이교체된때의이동시간등. public Block.DIR4 calcslidedir(vector2 mouse_position){ Block.DIR4 dir = Block.DIR4.NONE; // 지정된 mouse_position과현재위치의차를나타내는벡터. Vector2 v = mouse_position - new Vector2(this.transform.position.x, this.transform.position.y); // 벡터의크기가 0.1보다크면. // ( 그보다작으면슬라이드하지않은걸로간주한다 ). if(v.magnitude > 0.1f) { if(v.y > v.x) { if(v.y > -v.x) { dir = Block.DIR4.UP; else { dir = Block.DIR4.LEFT; else { if(v.y > -v.x) { dir = Block.DIR4.RIGHT; else { dir = Block.DIR4.DOWN; return(dir); 25

3. 블록교체 구현단계 * calcdiroffset(): 지정된위치와방향을근거로현재위치와슬라이드할곳의거리가어느정도인지반환한다. BlockControl.cs public float calcdiroffset(vector2 position, Block.DIR4 dir){ float offset = 0.0f; // 지정된위치와블록의현재위치의차를나타내는벡터. Vector2 v = position - new Vector2( this.transform.position.x, this.transform.position.y); switch(dir) { // 지정된방향에따라갈라진다. case Block.DIR4.RIGHT: offset = v.x; break; case Block.DIR4.LEFT: offset = -v.x; break; case Block.DIR4.UP: offset = v.y; break; case Block.DIR4.DOWN: offset = -v.y; break; return(offset); BlockControl.cs // 이동시작을알리는메서드 public void beginslide(vector3 offset) { this.position_offset_initial= offset; this.position_offset = this.position_offset_initial; // 상태를 SLIDE로변경. this.next_step = Block.STEP.SLIDE; 26

3. 블록교체 구현단계 * Update() 메서드수정 BlockControl.cs void Update() { Vector3 mouse_position; this.block_root.unprojectmouseposition( out mouse_position, Input.mousePosition); Vector2 mouse_position_xy = new Vector2(mouse_position.x, mouse_position.y); this.step_timer += Time.deltaTime; float slide_time = 0.2f; if(this.next_step == Block.STEP.NONE) { // ' 상태정보없음 ' 의경우. switch(this.step) { case Block.STEP.SLIDE: if(this.step_timer >= slide_time) { // 슬라이드중인블록이소멸되면 VACANT( 사라진 ) 상태로이행. if(this.vanish_timer == 0.0f) { this.next_step = Block.STEP.VACANT; // vanish_timer가 0이아니면 IDLE( 대기 ) 상태로이행. else { this.next_step = Block.STEP.IDLE; break; // 변했을때만시행할부분-----------------. while(this.next_step!= Block.STEP.NONE) { this.step = this.next_step; this.next_step = Block.STEP.NONE; switch(this.step) { case Block.STEP.IDLE: this.position_offset = Vector3.zero; this.transform.localscale = Vector3.one * 1.0f; break; case Block.STEP.GRABBED: this.transform.localscale = Vector3.one * 1.2f; break; case Block.STEP.RELEASED: this.position_offset = Vector3.zero; this.transform.localscale = Vector3.one * 1.0f; break; 27

3. 블록교체 구현단계 * Update() 메서드수정 BlockControl.cs case Block.STEP.VACANT: this.position_offset = Vector3.zero; break; this.step_timer = 0.0f; switch(this.step) { case Block.STEP.GRABBED: // 잡힌상태. // 잡힌상태일때는항상슬라이드방향을체크. this.slide_dir = this.calcslidedir(mouse_position_xy); break; case Block.STEP.SLIDE: // 슬라이드 ( 교체 ) 중. // 블록을서서히이동하는처리. // ( 어려운부분이니지금은몰라도괜찮다 ). float rate = this.step_timer / slide_time; rate = Mathf.Min(rate, 1.0f); rate = Mathf.Sin(rate*Mathf.PI / 2.0f); this.position_offset = Vector3.Lerp( this.position_offset_initial, Vector3.zero, rate); break; Vector3 position = BlockRoot.calcBlockPosition(this.i_pos) + this.position_offset; this.transform.position = position; 28

3. 블록교체 구현단계 * BlockRoot 스크립트에새메서드추가 getnextblock( ): 블록이슬라이드할곳에어느블록이있는지반환한다. 인수 - 현재잡고있는블록. 슬라이드방향 getdirvector( ): 인수로지정된방향을바탕으로이동량의벡터를반환한다. 현재블록에서지정방향으로이동하는양반환 getopposite( ): 인수로지정된방향의반대방향을반환한다. 블록을서로교체할때, 이동할곳에있는블록은역방향이동 swapblock( ): 실제로블록을교체한다. 29

3. 블록교체 구현단계 * getnextblock( ) : 블록이슬라이드할곳에어느블록이있는지반환 BlockRoot.cs public BlockControl getnextblock( BlockControl block, Block.DIR4 dir){ BlockControl next_block = null; // 슬라이드할곳의블록을여기에저장. switch(dir) { case Block.DIR4.RIGHT: if(block.i_pos.x < Block.BLOCK_NUM_X - 1) { // 그리드안이라면. next_block = this.blocks[block.i_pos.x + 1, block.i_pos.y]; break; case Block.DIR4.LEFT: if(block.i_pos.x > 0) { // 그리드안이라면. next_block = this.blocks[block.i_pos.x - 1, block.i_pos.y]; break; case Block.DIR4.UP: if(block.i_pos.y < Block.BLOCK_NUM_Y - 1) { // 그리드안이라면. next_block = this.blocks[block.i_pos.x, block.i_pos.y + 1]; break; case Block.DIR4.DOWN: if(block.i_pos.y > 0) { // 그리드안이라면. next_block = this.blocks[block.i_pos.x, block.i_pos.y - 1]; break; return(next_block); 30

3. 블록교체 구현단계 * getdirvector( ) : 인수로지정된방향을바탕으로이동량의벡터를반환 * getopposite( ) : 인수로지정된방향의반대방향을반환 BlockRoot.cs public static Vector3 getdirvector(block.dir4 dir) { Vector3 v = Vector3.zero; switch(dir) { case Block.DIR4.RIGHT: v = Vector3.right; break; // 오른쪽으로 1단위이동. case Block.DIR4.LEFT: v = Vector3.left; break; // 왼쪽으로 1단위이동. case Block.DIR4.UP: v = Vector3.up; break; // 위로 1단위이동. case Block.DIR4.DOWN: v = Vector3.down; break; // 아래로 1단위이동. v *= Block.COLLISION_SIZE; // 블록의크기를곱한다. return(v); BlockRoot.cs public static Block.DIR4 getoppositdir(block.dir4 dir) { Block.DIR4 opposit = dir; switch(dir) { case Block.DIR4.RIGHT: opposit = Block.DIR4.LEFT; break; case Block.DIR4.LEFT: opposit = Block.DIR4.RIGHT; break; case Block.DIR4.UP: opposit = Block.DIR4.DOWN; break; case Block.DIR4.DOWN: opposit = Block.DIR4.UP; break; return(opposit); 31

3. 블록교체 구현단계 * swapblock( ) : 실제로블록을교체한다. BlockRoot.cs public void swapblock( BlockControl block0, Block.DIR4 dir, BlockControl block1) { // 각각의블록색을기억해둔다. Block.COLOR color0 = block0.color; Block.COLOR color1 = block1.color; // 각각의블록의확대율을기억해둔다. Vector3 scale0 = block0.transform.localscale; Vector3 scale1 = block1.transform.localscale; // 각각의블록의 ' 사라지는시간 ' 을기억해둔다. float vanish_timer0 = block0.vanish_timer; float vanish_timer1 = block1.vanish_timer; // 색을교체한다. block0.setcolor(color1); block1.setcolor(color0); // 확대율을교체한다. block0.transform.localscale = scale1; block1.transform.localscale = scale0; // ' 사라지는시간 ' 을교체한다. block0.vanish_timer = vanish_timer1; block1.vanish_timer = vanish_timer0; block0.beginslide(offset0); // 원래블록이동을시작한다. block1.beginslide(offset1); // 이동할위치의블록이동을시작한다. // 각각의블록의이동할곳을구한다. Vector3 offset0 = BlockRoot.getDirVector(dir); Vector3 offset1 = BlockRoot.getDirVector(BlockRoot.getOppositDir(dir)); 32

3. 블록교체 구현단계 * update() 메서드에교체파트추가 33

3. 블록교체 구현단계 * update() 메서드에교체파트추가 BlockRoot.cs do { // 슬라이드할곳의블록을가져온다. BlockControl swap_target = this.getnextblock(grabbed_block, grabbed_block.slide_dir); // 슬라이드할곳블록이비어있으면. if(swap_target == null) { break; // 루프탈출. // 슬라이드할곳의블록이잡을수있는상태가아니라면. if(! swap_target.isgrabbable()) { break; // 루프탈출. // 현재위치에서슬라이드위치까지의거리를얻는다. float offset = this.grabbed_block.calcdiroffset( mouse_position_xy, this.grabbed_block.slide_dir); // 수리거리가블록크기의절반보다작다면. if(offset < Block.COLLISION_SIZE / 2.0f) { break; // 루프탈출. // 블록을교체한다. this.swapblock( grabbed_block, grabbed_block.slide_dir, swap_target); this.grabbed_block = null; // 지금은블록을잡고있지않다. while(false); 34

레 벨 퍼즐게임만들기 구 현 디 자 인 하 기 블 록 연 기획하기 쇄 3 5

1. 3 매치로블록지우기 블록연쇄구현 BlockControl.cs public Material opague_material; // 불투명머티리얼. public Material transparent_material; // 반투명머티리얼. void Update() { // 굵은부분추가 Vector2 mouse_position_xy = new Vector2(mouse_position.x, mouse_position.y); if(this.vanish_timer >= 0.0f) { // 타이머가 0 이상이면. this.vanish_timer -= Time.deltaTime; // 타이머의값을줄인다. if(this.vanish_timer < 0.0f) { // 타이머가 0 미만이면. if(this.step!= Block.STEP.SLIDE) { // 슬라이드중이아니라면. this.vanish_timer = -1.0f; this.next_step = Block.STEP.VACANT; // 상태를 소멸중 으로. else { this.vanish_timer = 0.0f; 36

1. 3 매치로블록지우기 블록연쇄구현 BlockControl.cs void Update() { // 굵은부분추가 while(this.next_step!= Block.STEP.NONE) {... switch(this.step) { case Block.STEP.RELEASED: this.position_offset = Vector3.zero; this.transform.localscale = Vector3.one * 1.0f; break; case Block.STEP.VACANT: this.position_offset = Vector3.zero; this.setvisible(false); // 블록을표시하지않게한다. break; this.step_timer = 0.0f;... Vector3 position = BlockRoot.calcBlockPosition(this.i_pos) + this.position_offset; this.transform.position = position; this.setcolor(this.color); if(this.vanish_timer >= 0.0f) { Color color0 = // 현재색과흰색의중간색. Color.Lerp(this.renderer.material.color, Color.white, 0.5f); Color color1 = // 현재색과검은색의중간색. Color.Lerp(this.renderer.material.color, Color.black, 0.5f); // 불붙는연출시간이절반을지났다면. if(this.vanish_timer < Block.VANISH_TIME / 2.0f) { // 투명도 (a) 를설정. color0.a = this.vanish_timer / (Block.VANISH_TIME / 2.0f); color1.a = color0.a; // 반투명머티리얼을적용. this.renderer.material = this.transparent_material; // vanish_timer가줄어들수록 1에가까워진다. float rate = 1.0f - this.vanish_timer / Block.VANISH_TIME; // 서서히색을바꾼다. this.renderer.material.color = Color.Lerp(color0, color1, rate); 37

1. 3 매치로블록지우기 블록연쇄구현 BlockControl.cs public void tovanishing(){ // ' 사라질때까지걸리는시간 ' 을규정값으로리셋. this.vanish_timer = Block.VANISH_TIME; public void setvisible(bool is_visible){ // 그리기가능설정에인수를대입. this.renderer.enabled = is_visible; public bool isvanishing(){ // vanish_timer가 0보다크면 true. bool is_vanishing = (this.vanish_timer > 0.0f); return(is_vanishing); public void rewindvanishtimer(){ // ' 사라질때까지걸리는시간 ' 을규정값으로리셋. this.vanish_timer = Block.VANISH_TIME; public bool isvisible(){ // 그리기가능 (renderer.enabled가 true) 상태라면. // 표시되고있다. bool is_visible = this.renderer.enabled; return(is_visible); public bool isidle(){ bool is_idle = false; // 현재블록상태가 ' 대기중 ' 이고. // 다음블록상태가 ' 없음 ' 이면. if(this.step = = Block.STEP.IDLE && this.next_step = = Block.STEP.NONE) { is_idle = true; return(is_idle); 38

1. 3 매치로블록지우기 블록연쇄구현 BlockRoot.cs void Update() {... if(! Input.GetMouseButton(0)) {. // 낙하중또는슬라이드중이면. if(this.is_has_falling_block() this.is_has_sliding_block()) { // 아무것도하지않는다. // 낙하중도슬라이드중도아니면. else { int ignite_count = 0; // 불붙은개수. // 그리드안의모든블록에대해서처리. foreach(blockcontrol block in this.blocks) { if(! block.isidle()) { // 대기중이면루프의처음으로점프하고. continue; // 다음블록을처리한다. // 세로또는가로에같은색블록이세개이상나열했다면. if(this.checkconnection(block)) { ignite_count++; // 불붙은개수를증가. if(ignite_count > 0) { // 불붙은개수가 0보다크면. // =한군데라도맞춰진곳이있으면. int block_count = 0; // 불붙는중인블록수 ( 다음장에서사용한다 ). // 그리드내의모든블록에대해서처리. foreach(blockcontrol block in this.blocks) { if(block.isvanishing()) { // 타는중이면. block.rewindvanishtimer(); // 다시점화!. 39

1. 3 매치로블록지우기 블록연쇄구현 BlockRoot.cs // 인수로받은블록이세개의블록안에들어가는지파악하는메서드 public bool checkconnection(blockcontrol start) { bool ret = false; int normal_block_num = 0; // 인수인블록이불붙은다음이아니면. if(! start.isvanishing()) { normal_block_num = 1; // 그리드좌표를기억해둔다. int rx = start.i_pos.x; int lx = start.i_pos.x; // 블록의왼쪽을검사. for(int x = lx - 1; x > 0; x--) { BlockControl next_block = this.blocks[x, start.i_pos.y]; if(next_block.color!= start.color) { // 색이다르면. break; // 루프를빠져나간다. if(next_block.step = = Block.STEP.FALL // 낙하중이면. next_block.next_step = = Block.STEP.FALL) { break; if(next_block.step = = Block.STEP.SLIDE // 슬라이드중이면. next_block.next_step = = Block.STEP.SLIDE) { break; if(! next_block.isvanishing()) { // 불붙은상태가아니면. normal_block_num++; // 검사용카운터를증가. lx = x; 40

1. 3 매치로블록지우기 블록연쇄구현 BlockRoot.cs // 블록의오른쪽을검사. for(int x = rx + 1; x < Block.BLOCK_NUM_X; x+ +) { BlockControl next_block = this.blocks[x, start.i_pos.y]; if(next_block.color!= start.color) { break; do { // 오른쪽블록의그리드번호 - 왼쪽블록의그리드번호 +. // 중앙블록 (1) 을더한수가 3 미만이면. if(rx - lx + 1 < 3) { break; // 루프탈출. if(next_block.step = = Block.STEP.FALL next_block.next_step = = Block.STEP.FALL) { break; if(next_block.step = = Block.STEP.SLIDE next_block.next_step = = Block.STEP.SLIDE) { break; if(! next_block.isvanishing()) { normal_block_num++; if(normal_block_num = = 0) { // 불붙지않은블록이하나도없으면. break; for(int x = lx; x < rx + 1; x+ +) { // 나열된같은색블록을불붙은상태로. this.blocks[x, start.i_pos.y].tovanishing(); ret = true; while(false); rx = x; 41

1. 3 매치로블록지우기 블록연쇄구현 BlockRoot.cs normal_block_num = 0; if(! start.isvanishing()) { normal_block_num = 1; int uy = start.i_pos.y; int dy = start.i_pos.y; // 블록의위쪽을검사. for(int y = dy - 1; y > 0; y--) { BlockControl next_block = this.blocks[start.i_pos.x, y]; if(next_block.color!= start.color) { break; if(next_block.step = = Block.STEP.FALL next_block.next_step = = Block.STEP.FALL) { break; if(next_block.step = = Block.STEP.SLIDE next_block.next_step = = Block.STEP.SLIDE) { break; if(! next_block.isvanishing()) { normal_block_num++; dy = y; 42

1. 3 매치로블록지우기 블록연쇄구현 BlockRoot.cs // 블록의아래쪽을검사. for(int y = uy + 1; y < Block.BLOCK_NUM_Y; y + +) { BlockControl next_block = this.blocks[start.i_pos.x, y]; if(next_block.color!= start.color) { break; if(next_block.step = = Block.STEP.FALL next_block.next_step = = Block.STEP.FALL) { break; if(next_block.step = = Block.STEP.SLIDE next_block.next_step = = Block.STEP.SLIDE) { break; if(! next_block.isvanishing()) { normal_block_num++; uy = y; do { if(uy - dy + 1 < 3) { break; If(normal_block_num == 0) { break; for(int y = dy; y < uy + 1; y++) { this.blocks[start.i_pos.x, y].tovanishing(); ret = true; while(false); return(ret); 43

2. 블록보충하기 블록연쇄구현 44

2. 블록보충하기 블록연쇄구현 BlockControl.cs 45 private struct StepFall { while(this.next_step!= Block.STEP.NONE) { public float velocity; // 낙하속도. switch(this.step) { private StepFall fall;... void Update() { case Block.STEP.VACANT:... if(this.next_step = = Block.STEP.NONE) { case Block.STEP.RESPAWN: // 색을랜덤하게선택하여블록을그색으로설정. case Block.STEP.IDLE: int color_index = Random.Range( this.renderer.enabled = true; 0, (int)block.color.normal_color_num); break; this.setcolor((block.color)color_index); case Block.STEP.FALL: this.next_step = Block.STEP.IDLE; if(this.position_offset.y <= 0.0f) { break; this.next_step = Block.STEP.IDLE; case Block.STEP.FALL: this.position_offset.y = 0.0f; this.setvisible(true); // 블록을표시. this.fall.velocity = 0.0f; // 낙하속도리셋. break; break;... this.step_timer = 0.0f;...

2. 블록보충하기 블록연쇄구현 BlockControl.cs void Update() {... switch(this.step) {... case Block.STEP.SLIDE: float rate = this.step_timer / slide_time;... case Block.STEP.FALL: // 속도에중력의영향을부여한다. this.fall.velocity += Physics.gravity.y * Time.deltaTime * 0.3f; // 세로방향위치를계산. this.position_offset.y += this.fall.velocity * Time.deltaTime; if(this.position_offset.y < 0.0f) { // 다내려왔다면. this.position_offset.y = 0.0f; // 그자리에머무른다. break; 46

2. 블록보충하기 블록연쇄구현 BlockRoot.cs 47

2. 블록보충하기 블록연쇄구현 BlockRoot.cs // 하나라도연소중인블록이있는가?. bool is_vanishing = this.is_has_vanishing_block(); // 조건이만족되면블록을떨어뜨리고싶다. do { if(is_vanishing) { // 연소중인블록이있다면. break; // 낙하처리를실행하지않는다. if(this.is_has_sliding_block()) { // 교체중인블록이있다면. break; // 낙하처리를실행하지않는다. for(int x = 0; x < Block.BLOCK_NUM_X; x++) { // 열에교체중인블록이있다면그열은처리하지않고 // 다음열로진행한다. 주석처리를벗겨낸다 if(this.is_has_sliding_block_in_column(x)) { continue; // 그열에있는블록을위에서부터검사한다. for(int y = 0; y < Block.BLOCK_NUM_Y - 1; y++) { // 지정블록이비표시라면다음블록으로. if(! this.blocks[x, y].isvacant()) { continue; // 지정블록아래에있는블록을검사. for(int y1 = y + 1; y1 < Block.BLOCK_NUM_Y; y1++) { // 아래에있는블록이비표시라면다음블록으로. if(this.blocks[x, y1].isvacant()) { continue; // 블록을교체한다. this.fallblock(this.blocks[x, y], Block.DIR4.UP, this.blocks[x, y1]); break; 48

2. 블록보충하기 블록연쇄구현 BlockRoot.cs // 보충처리. for(int x = 0; x < Block.BLOCK_NUM_X; x++) { int fall_start_y = Block.BLOCK_NUM_Y; for(int y = 0; y < Block.BLOCK_NUM_Y; y++) { // 비표시블록이아니라면다음블록으로. if(! this.blocks[x, y].isvacant()) { continue; this.blocks[x, y].beginrespawn(fall_start_y); // 블록부활. fall_start_y++; while(false); 49

레 벨 퍼즐게임만들기 구 현 디 자 인 하 기 블 록 연 기획하기 쇄 5 0

1. 점수와시간삽입 레벨디자인 ScoreCounter.cs // 멤버변수초기화 51

1. 점수와시간삽입 레벨디자인 ScoreCounter.cs public void print_value(int x, int y, string label, int value) { // 지정된데이터를두개의행에나눠표시 // label 을표시. GUI.Label(new Rect(x, y, 100, 20), label, guistyle); y += 15; // 다음행에 value 를표시. GUI.Label(new Rect(x + 20, y, 100, 20), value.tostring(), guistyle); y += 15; public void addignitecount(int count){ this.last.ignite += count; // 연쇄수에 count 를합산. this.update_score(); // 점수계산. public void print_value(int x, int y, string label, int value) public void updatetotalscore() { this.last.total_socre += this.last.score; // 합계점수갱신. public bool isgameclear() { bool is_clear = false; // 현재합계점수가클리어기준보다크면. if(this.last.total_socre > QUOTA_SCORE) { is_clear = true; return(is_clear); public void clearignitecount(){ this.last.ignite = 0; // 연쇄횟수리셋. private void update_score(){ this.last.score = this.last.ignite * 10; // 점수갱신. 52

1. 점수와시간삽입 레벨디자인 SceneControl.cs 53

1. 점수와시간삽입 레벨디자인 SceneControl.cs // 화면에클리어한시간과메시지를표시 54

1. 점수와시간삽입 레벨디자인 BlackRoot.cs 점수에관련된부분을변경 연쇄된블록수만큼점수계산 불타는중엔리셋되지않는다 = 연쇄수가된다 55

1. 점수와시간삽입 레벨디자인 * 완성화면 * 56

2. 텍스트읽어오기 레벨디자인 LevelControl.cs // List 를사용하기위함 57

2. 텍스트읽어오기 레벨디자인 * LevelControl 클래스에필요한메서드 level_datas: 각레벨의레벨데이터를저장하는 List 값 select_level: 선택된레벨을저장하는 int 값 initialize( ): 초기화처리를한다 (level_datas를초기화할뿐 ). loadleveldata( ): 텍스트데이터를읽어와서그내용을해석하고데이터를보관한다. selectlevel( ): 몇개의레벨패턴에서지금사용할패턴을선택한다. getcurrentleveldata( ): 선택되어있는레벨패턴의레벨데이터를반환한다. getvanishingtime( ): 선택되어있는레벨패턴의연소시간을반환한다. 58

2. 텍스트읽어오기 레벨디자인 LevelControl.cs // 각레벨에데이터를저장 59

2. 텍스트읽어오기 레벨디자인 LevelControl.cs 60

2. 텍스트읽어오기 레벨디자인 * BlackRoot 클래스에필요한메서드 leveldata: 레벨데이터의텍스트를저장한다. level_control: LevelControl을저장한다. create( ): 레벨데이터의초기화, 로드, 패턴설정까지시행한다. selectblockcolor( ): 현재패턴의출현확률을바탕으로색을산출해서반환한다. 61

2. 텍스트읽어오기 레벨디자인 BlackRoot.cs 62

2. 텍스트읽어오기 레벨디자인 LevelControl.cs 나열할초기배치블록도선택된레벨의출현패턴을따르게하는수정 63

2. 텍스트읽어오기 SceneControl.cs BlockControl.cs 레벨디자인 // 레벨데이터의연소시간이반영되도록함 씬이시작될때텍스트데이터를읽고레벨선택을할수있게함 64

2. 텍스트읽어오기 레벨디자인 BlockControl.cs 65

3. 레벨디자인 레벨디자인 정책결정 난이도를비슷하게한다 패턴별로색상수와연소시간을바꾼다 패턴종류 패턴 A: 평균적인색상수 출현확률 연소시간 패턴 B: 색상수는조금적지만연소시간이조금짧다. 패턴 C: 색상수가적지만연소시간이짧다. 패턴 D: 색상수는조금많지만연소시간이조금길다. 패턴 E: 색상수는많지만연소시간이길다. 패턴 F: 특정색이나올확률이조금높지만연소시간이다소짧다. 패턴 G: 특정색이나올확률이높지만연소시간이짧다. 66

4. 게임시퀀스연결 레벨디자인 TitleScript.cs SceneControl.cs 67

* 완성! 레벨디자인 68

이번에도수고하셨습니다. 다음페이지에서보아요!