본문 바로가기
코딩과 알고리즘

코드이그나이터 뷰를 나눠볼까요?

1. 오토셋 APM 인스톨러 ( apache + php7.2 + mariadb ) 설치 | https://itadventure.tistory.com/93

2. 코드이그나이터 4 ( codeigniter 4 ) 설치 | https://itadventure.tistory.com/95

3. 비주얼 스튜디오 코드 에디터 설치 & 한글 설정 | https://itadventure.tistory.com/96

4. 폴더열기 / 웹페이지 편집(1) | https://itadventure.tistory.com/97

5. 웹페이지 편집(2) | https://itadventure.tistory.com/101

6. 코드이그나이터4의 URL 규칙 | https://itadventure.tistory.com/105

7. php, 네임스페이스 [ namespace ] ?! | https://itadventure.tistory.com/118

8. 코드이그나이터의 네임스페이스, 그리고 모델 | https://itadventure.tistory.com/122

9. 코드이그나이터 뷰의 파라미터 전달 | https://itadventure.tistory.com/147

♣ 10. 코드이그나이터 뷰를 나눠 볼까요? ♣


이번 시간에는 코드이그나이터에서 뷰를 나누는 부분을 살펴보겠습니다.

지난 시간에 뷰(View)웹페이지 조각이라고 설명드린 바가 있는데요
이번 시간에는 뷰를 3개로 나눠서 컨트롤러에서 사용하는 방법을 살펴보도록 하겠습니다.

소스를 구성하는 방법은 지난 강좌를 참조해주시기를 바라며,
여기서는 간단히 소스에 들어갈 내용만 개제하고 설명들어가겠습니다.

다음과 같이 각각의 폴더에 소스를 구성해 주세요.

<Controllers/Sample.php>

<?php 
namespace App\Controllers;
use CodeIgniter\Controller;
class Sample extends Controller
{
  public function index()
  {
    echo view('header');
    echo view('sample1');
    echo view('tail');
  }
}

<Views/header.php>

<!DOCTYPE html>
<html lang="ko">
<head>
	<meta charset="UTF-8">
	<title>캔바스. 테트리스</title>
</head>
<body>

<Views/sample1.php>

https://itadventure.tistory.com / 크레이의 IT탐구 티스토리 블로그<br/>
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
<script>
// 기본 초기화
var init=false;
var myCanvas;
var Context;

var Mode=1; // 1=게임중, 2=게임오버
const MODE_GAME=1;
const MODE_GAMEOVER=2;

var tetrix_blockbox_boxsize=25;
var tetrix_blockbox_top=50;
var tetrix_blockbox_left=280;

var tetrix_blockbox;

var score;

var RunEvent;
var RunEventTime = 500;
var level=1;
var exp=0;

// 테트리스 블럭박스 초기화
function tetrix_blockbox_init()
{
	// 20행 10열의 박스 생성
	tetrix_blockbox=new Array();
	for(i=0;i<20;++i)
	{
		tetrix_blockbox.push(new Array(10));
		// 모두 0으로 채운다
		for(j=0;j<10;++j)tetrix_blockbox[i][j]=0;
	}
}

// 5가지 타입 블록
var tetrix_block;

// 현재 사용중인 블록
var tetrix_block_this;

// 5가지 블럭 초기화
function tetrix_block_init()
{
	tetrix_block=new Array();

	// 첫번째 블럭
	// □□□□
	tmp=new Array();
	tmp.push(0,0); tmp.push(0,1); tmp.push(0,2); tmp.push(0,3);
	tetrix_block.push(tmp);

	// 두번째 블럭
	// □□□
	//  □
	tmp=new Array();
	tmp.push(0,0); tmp.push(0,1); tmp.push(0,2); tmp.push(1,1);
	tetrix_block.push(tmp);

	// 세번째 블럭
	// □□
	//  □□
	tmp=new Array();
	tmp.push(0,0); tmp.push(0,1); tmp.push(1,1); tmp.push(1,2);
	tetrix_block.push(tmp);

	// 네번째 블럭
	//  □□
	// □□
	tmp=new Array();
	tmp.push(0,1); tmp.push(0,2); tmp.push(1,0); tmp.push(1,1);
	tetrix_block.push(tmp);

	// 다섯번째 블럭
	// □□
	// □□
	tmp=new Array();
	tmp.push(0,0); tmp.push(0,1); tmp.push(1,0); tmp.push(1,1);
	tetrix_block.push(tmp);

	// 여섯번째 블럭
	// □□□
	// □
	tmp=new Array();
	tmp.push(0,0); tmp.push(0,1); tmp.push(0,2); tmp.push(1,0);
	tetrix_block.push(tmp);

	// 일곱째 블럭
	// □□□
	//   □
	tmp=new Array();
	tmp.push(0,0); tmp.push(0,1); tmp.push(0,2); tmp.push(1,2);
	tetrix_block.push(tmp);
}

// 현재 떨어지는 블록번호와 좌표
var tetrix_block_number=1;
var tetrix_block_x=3;
var tetrix_block_y=0;


var bgImage = new Image();
var blockImage = Array();

var bgSound = new Audio();
var blockSound = new Audio();
var block10Sound = new Audio();

// 초기화
function Init()
{
	if(init==false)
	{
		myCanvas=document.getElementById("MyCanvas");
		Context=myCanvas.getContext("2d");

		// 이미지 로딩
		bgImage.src="https://i.imgur.com/PTrYSqH.png";
		for(i=0;i<7;++i)blockImage.push(new Image());
		blockImage[0].src="https://i.imgur.com/zdluTLl.png";
		blockImage[1].src="https://i.imgur.com/BCpg8vG.png";
		blockImage[2].src="https://i.imgur.com/X4MIbXi.png";
		blockImage[3].src="https://i.imgur.com/80Xv589.png";
		blockImage[4].src="https://i.imgur.com/ZaQNHG6.png";
		blockImage[5].src="https://i.imgur.com/9RXm6Tp.png";
		blockImage[6].src="https://i.imgur.com/TnoZ1LF.png";

		// 사운드 로딩
		bgSound.src="http://dreamplan7.cafe24.com/canvas/sound/bensound-summer.mp3";
		bgSound.volume=0.2;
		bgSound.playbackRate=1.0;
		blockSound.src="http://dreamplan7.cafe24.com/canvas/sound/sound55.mp3";
		block10Sound.src="http://dreamplan7.cafe24.com/canvas/sound/sound39.mp3";

		tetrix_block_init();	// 5가지 블럭 모양 초기화
		tetrix_blockbox_init();	// 블럭상자 초기화
		tetrix_block_number=Math.floor(Math.random()*6.9);
		tetrix_block_this = tetrix_block[tetrix_block_number].slice();
		score=0;		
		init=true;
	}
}

function CheckConflict()
{
	var size=tetrix_block_this.length;
	for(k=0;k<size;k+=2)
	{
		check_y = tetrix_block_y + tetrix_block_this[k];
		check_x = tetrix_block_x + tetrix_block_this[k+1];
		if(check_y < 0 )continue;	// y좌표가 0보다 적은 사각형은 중돌 검사를 안함
		// 겹치는 경우
		if(check_x < 0 || check_x >=10 || check_y >= 20 || tetrix_blockbox[check_y][check_x]!=0)return true;
	}
	return false;
}
function Run()
{
	// 블럭을 떨어뜨리지도 않았는데 충돌해 있으면
	// 게임오버
	if(CheckConflict()) 
		Mode=MODE_GAMEOVER;

	if(Mode==MODE_GAME)
	{	
		bgSound.play();

		// 블럭을 한칸 떨어뜨리고
		tetrix_block_y++;

		// 겹침검사	
		if(CheckConflict())
		{
			// 다시 위로 이동시킨 다음
			tetrix_block_y--;
			var size=tetrix_block_this.length;
			// 블럭을 블럭판에 박는다
			for(k=0;k<size;k+=2)
			{
				check_y = tetrix_block_y + tetrix_block_this[k];
				check_x = tetrix_block_x + tetrix_block_this[k+1];
				tetrix_blockbox[check_y][check_x]=tetrix_block_number + 1;
			}
			blockSound.play();
			score++;

			// 꽉참 줄 검사
			for(i=0;i<20;++i)
			{
				// 한줄 단위로 0이 아닌 블럭을 세서 
				sum=0;
				for(j=0;j<10;++j)
					if(tetrix_blockbox[i][j]!=0)
						sum++;

				// 합계가 10이면 꽉찬 것
				if(sum==10)
				{
					// 위의 내용을 아래로 복사해준다.
					for(k=i;k>0;--k)
						for(j=0;j<10;++j)
							tetrix_blockbox[k][j]=tetrix_blockbox[k-1][j];
					score+=10;

					// 난이도 레벨을 증가시키기 위해 경험치 증가
					exp++;
					if(exp>=10){
						level++; exp=0;
						RunEventTime-=50;
						clearInterval(RunEvent);
						RunEvent = setInterval(Run, RunEventTime);
						bgSound.playbackRate=1.0 + (level-1) * 0.05;
					}
					block10Sound.play();
				}
			}

			// 블럭을 다시 제일 위로 생성시키고
			tetrix_block_y=0;
			tetrix_block_x=3;
			// 블럭번호도 바꿔 주자
			tetrix_block_number=Math.floor(Math.random()*6.9);
			tetrix_block_this=tetrix_block[tetrix_block_number].slice();

		}
	}
	else if(Mode==MODE_GAMEOVER)
	{
		bgSound.pause();
	}

	// 그리기 이벤트
	onDraw();
}

function RotateBlock()
{
	switch(tetrix_block_number)
	{
		case 0: case 1: case 2: case 3: case 5: case 6:
			// 첫번째 블럭
			// □□□□
			// 두번째 블럭
			// □□□
			//  □
			// 세번째 블럭
			// □□
			//  □□
			// 네번째 블럭
			//  □□
			// □□
			centerY=0; centerX=1;	// ( 0, 1 ) 지점을 중심
			break;
		case 4:
			// 다섯번째 블럭
			// □□
			// □□
			return;
	}

	// 회전
	// x ← -y
	// y ← x
	// 이전 형태를 미리 기억
	tetrix_block_save = tetrix_block_this.slice();
	for(i=0;i<tetrix_block_this.length;i+=2)
	{
		y=tetrix_block_this[i+1] - centerX;
		x=-(tetrix_block_this[i] - centerY);
		tetrix_block_this[i]=y + centerY;
		tetrix_block_this[i+1]=x + centerX;
	}

	// 충돌인 경우 원상복귀
	if(CheckConflict())
		tetrix_block_this=tetrix_block_save.slice();
}

// 키입력
function onKeyDown(event)
{
	// 게임중일 때만 이동 회전키가 작동
	if(Mode==MODE_GAME)
	{

		if(event.which==37)	// 왼쪽키
		{
			tetrix_block_x--;
			if(CheckConflict())tetrix_block_x++;
			else onDraw();
		}
		if(event.which==39)	// 오른쪽키
		{
			tetrix_block_x++;
			if(CheckConflict())tetrix_block_x--;
			else onDraw();
		}
		if(event.which==40 || event.which==32)	// 아래쪽키, 스페이스키 
		{
			tetrix_block_y++;
			if(CheckConflict())tetrix_block_y--;
			else onDraw();
		}
		if(event.which==38)	// 위쪽키(회전)
		{
			RotateBlock();
			onDraw();
		}
	}
	// 게임오버일 때 재시작 단축키는 Enter 키
	else if(Mode==MODE_GAMEOVER)
	{
		if(event.which==13)	// Enter 키를 누르면
		{
			// 재시작
			tetrix_blockbox_init();	// 블럭상자 초기화
			tetrix_block_number=Math.floor(Math.random()*6.9);
			tetrix_block_this = tetrix_block[tetrix_block_number].slice();
			score=0;
			bgSound.playbackRate=1.0;
			level=1; exp=0;
			RunEventTime=500;
			clearInterval(RunEvent);
			RunEvent = setInterval(Run, RunEventTime);
			Mode=MODE_GAME;
		}
	}
}

// draw 이벤트
function onDraw()
{
	if(init==false)return;
	// 전체 테두리
	Context.strokeStyle="#000";
	Context.lineWidth=1;
	Context.strokeRect(0, 0, myCanvas.width-1, myCanvas.height-1);
	Context.fillStyle="#fcfcfc";
	Context.fillRect(1, 1, myCanvas.width-2, myCanvas.height-2);
	Context.drawImage(bgImage, 0, 0);
	// 블럭 표시
	for(i=0;i<20;++i)
		for(j=0;j<10;++j)
		{
			if(tetrix_blockbox[i][j]==0)
			{
				Context.fillStyle="#999";
				isblock=-1;
			}
			else {
				isblock=tetrix_blockbox[i][j]-1;
			}
			
			// 떨어지는 블럭표시
			var size=tetrix_block_this.length;
			for(k=0;k<size;k+=2)
			{
				if(tetrix_block_y+tetrix_block_this[k]==i
				   && tetrix_block_x+tetrix_block_this[k+1]==j)
				{
					isblock=tetrix_block_number;
					break;
				}
			}

			x=tetrix_blockbox_left + j*tetrix_blockbox_boxsize;
			y=tetrix_blockbox_top + i*tetrix_blockbox_boxsize;

			if(isblock==-1)
				Context.fillRect(x, y, tetrix_blockbox_boxsize-1, tetrix_blockbox_boxsize-1);
			else Context.drawImage(blockImage[isblock], x, y);
		}
	// 점수표시
	Context.font = "bold 30px 나눔고딕";
	Context.fillStyle="#eee";
	Context.strokeStyle="#fff";
	Context.fillStyle="blue";

	Context.fillText("Score " + score, 50, 90);
	Context.strokeText("Score " + score, 50, 90);

	Context.fillText("Level " + level, 50, 130);
	Context.strokeText("Level " + level, 50, 130);

	if(Mode==MODE_GAMEOVER)
	{
		Context.fillStyle="red";
		Context.fillText("GAME OVER", tetrix_blockbox_left + 40, tetrix_blockbox_top + 250);
	}
}

$(document).ready(function(){
	Init();
	RunEvent = setInterval(Run, RunEventTime);
});

$(document).keydown(function( event ){
	onKeyDown(event);		
});

</script>

<canvas id="MyCanvas" width=800 height=600>
Canvas is not supported.
</canvas>
<br/>
배경음악 추가<br/>
블럭 쌓을때, 10줄 찼을 때 효과음 추가<br/>

<span id=debug></span>

<Views/tail.php>

</body>
</html>

소스가 좀 길지요?
사실 이 소스 내용은 자바스크립트 강좌에서 다루었던 테트리스 게임의 완성본 소스인데,
코드 이그나이터용으로 살짝 바꿔본 겁니다.

앞선 강좌를 쭉 따라하셨던 분들이라면 APM 이 PC에 설치되어 있을테니, 아래 주소로 접속하셔서 플레이해보시면 될 겁니다.

http://localhost/sample


혹시 자바스크립트쪽에도 관심이 있으시다면 아래 게시글도 한번 참조해 보세요 :)
https://itadventure.tistory.com/159

 

자바스크립트와 캔버스 11, 테트리스를 만들어봐-7

1. HTML 표준 CANVAS 기술 소개 / https://itadventure.tistory.com/130 2. 자바스크립트와 CANVAS 두번째시간. 캔바스에 눈을 내리자 / https://itadventure.tistory.com/131 3. 자바스크립트와 캔버스 3번째 시..

itadventure.tistory.com

사실 오늘 내용은 소스의 양이 중요한게 아니라 소스를 어떻게 구성하는 게 중요한지가 키포인트입니다.

우선 컨트롤러 소스는 1개가 준비되었습니다.

Controllers/Sample.php

그리고 뷰는 3개의 소스가 준비되어 있지요.

Views/header.php
Views/sample1.php
Views/tail.php

컨트롤러에서는 이 3개의 뷰를 순서대로 하나씩 보여주도록 되어 있는데요.
첫번째는 header.php, 두번째는 sample1.php, 마지막으로는 tail.php 를 보여줍니다.

header.php
sample1.php
tail.php

그 부분이 컨트롤러에서 바로 이 소스에 해당합니다. 아주 간단하지요?
아마도 프로그래밍 감각이 있으신 분은 직관적으로 이해하셨을 겁니다.

echo view('header');
echo view('sample1');
echo view('tail');

Views/header.php 는 일종의 머리글입니다.
보통 홈페이지를 꾸밀 때 여러 페이지의 앞 부분에 나오는 부분을 머리말이라고 하는데요.
만일 홈페이지가 50개 정도의 페이지로 구성되고
50개 페이지에 동일한 머리글이 각각 들어 있는 상태에서 제목을 바꿀 일이 생겼다고 생각해보세요.

50개 소스를 일일히 찾아가며 수정해줘야 할겁니다.
그리고 다음날 전화번호가 바뀌었다고 또 뭔가 고쳐달라고 하면?
어휴!! 완전 노가다(?)이지요.

그래서 앞부분중 머리글만 따로 떼어놓아 공통부분은 하나 또는 몇개의 웹페이지로 넣어 놓은 후
여러개의 웹페이지에서 동일한 웹페이지를 불러다가 쓸 수가 있지요.

그러한 이유 때문에 웹페이지 조각이라고 크레이는 부르짖는(?) 것입니다.
아무도 이러한 용어를 쓰지는 않지만요 ㅎㅎ

Views/tail.php 또한 꼬리글입니다. 웹페이지에서 문서의 끝 마무리 부분 또한 여러 문서가 겹치는 경우가 많은데요.
중복되는 부분을 tail.php 에 넣어놓은 것이고,

실제 본문에 해당하는 부분은 머리글과 꼬리글을 뺀 Views/sample1.php 인 것이지요.
본 예제에서는 뷰를 3개의 파일로 나눴지만, 3개가 정석은 아닙니다.

다양한 웹페이지 구성에 따라 5개로 나눌수도 있고 10개로 나눌수도 있는 것이지요.
로그인 영역만 따로 떼어놓아 로그인 했을때와 로그인하지 않았을 때의 뷰를 각각 나눠서 보여줄 수도 있는 겁니다.

오늘은 여기까지입니다 :)

오늘도 읽어주셔서 감사드리구요,
테트리스 게임에 관심 있는 분들은 크레이의 기록에 도전해 보시겠어요?
크레이는 그리 잘하는 편은 아니라서, 레벨9에 1059 점 정도가 한계입니다 :)

코드이그나이터가 없이 그냥 읽기만 하시는 분이라도 아래 URL로 접속하시면 플레이하실 수 있습니다.
http://dreamplan7.cafe24.com/canvas/cray13.php

레벨9 인증샷!