DIYPlay
블로그

Blockly, pixi.js 사용해서 블록코딩 그림판 만들기 - 1

DIYPlayer

·

1달 전

blockly
pixi.js
그림판
블록코딩

 이전 포스팅에서 Blockly의 샘플 프로젝트를 간단히 살펴보았습니다. 이번 포스팅에서는 Blockly 를 활용해서 직접 블록코딩 켄텐츠를 만들어 보도록 하겠습니다. 

이전 포스팅

 블록코딩 콘텐츠 제작을 위한 Blockly 개발 시작하기

 

완성된 프로젝트 바로가기

 블록코딩 그림판 결과물 프로젝트

 

컨텐츠 소개

 만들어 볼 컨텐츠는 그림판입니다. 

 선 그리기, 원 그리기, 사각형 그리기 등의 명령을 통해 그림판에 선이나 도형을 그려볼 수 있도록 하겠습니다.

개발 순서

1. 기본 프로그램 제작( 블록 코딩을 사용해서 제어할 프로그램)

2. 블록 코딩에서 제어할 수 있도록 기능을 API 제공

3. API를 사용할 수 있도록 커스텀 블록 정의

4. 블록코딩으로 작성된 코드를 프로그램에 주입

저번 포스팅에서 이런 흐름으로 블록코딩 콘텐츠 개발을 진행할 수 있다고 언급했었는데요. 비슷한 형태로 진행해보도록 하겠습니다.

  1. 먼저 그림판 프로그램을 만들어 보겠습니다. 그림판 제작에는 pixi.js 라는 2D 렌더링 라이브러리를 사용 할겁니다. 단순한 그림판 제작에는 Canvas의 2d context 사용만으로 충분하겠지만 업데이트 루프를 만들거나 도형을 개별적으로 제어하기 편한 pixi.js 를 사용해 보겠습니다. pixi.js 에 익숙해지면 추후에 제작해볼 코딩게임 컨텐츠 제작에도 도움이 될 겁니다.
     
  2. 그림판은 마우스로 그림을 그리는 대신 각각의 그리기 명령을 수행하는 API(함수)들을 만들어 놓고 API 호출을 통해 그릴 수 있게 만들겠습니다.
     
  3. 그림판 그리기 명령을 블록코딩을 통해 수행 할 수 있도록 각각의 API 와 매칭되는 커스텀 블록들을 정의 하겠습니다.
     
  4. 블록코딩으로 작성된 로직이 그림판 프로그램을 제어할 수 있도록 javascript 의 Function 기능을 활용해서 런타임 중에 스크립트를 추가하는 방법에 대해서 구현해보겠습니다.

그림판 만들기

프로젝트 초기화

 이전에 만들어 놓았던 DIY에디터의 Blockly 시작 프로젝트를 기반으로 새로운 프로젝트를 만들어서 진행하겠습니다. 기본에 있던 파일들은 모두 그대로 두고 추가로 paint 라는 이름으로 폴더를 새로 만들고 paint폴더 안에 paintApp.js 파일을 만듭니다. 아래 코드를 추가해 줍니다. pixi.js 의 사용법에 대해서는 따로 설명하지 않겠습니다. 대신에 코드에 달려있는 주석을 참조해 주세요.

// paint/paintApp.js

class PaintApp {
    constructor(parentEl) {
		//pixi의 주요 기능들을 사용하기 위한 Application 인스턴스 생성
        this.app = new PIXI.Application({
            width: 400,
            height: 300,
            backgroundColor: 0x1099bb,        
        });
        
        //Application 생성시 동시에 생성되는 Canvas(view) 를 부모 엘리먼트에 추가
        parentEl.appendChild(this.app.view);
    }
}

 만들어진 그림판 프로그램을 테스트 해볼 수 있게 paint폴더안에 paintTest.js 파일도 만듭니다.

 기존에 사용하던 텍스트 출력 영역을 그림판 영역으로 사용하도록 하겠습니다.

const paintParent = document.getElementById('output');
const paintApp = new PaintApp(paintParent);

 

index.html 파일에 pixi.js를 cdn 으로 설치하고 위에 만든 파일들을 스크립트로 추가해 줍니다.


<script src="https://pixijs.download/v7.4.0/pixi.min.js"></script>

<script src="paint/paintApp.js"></script>
<script src="paint/paintTest.js"></script>

 

DIY 에디터에서 코드를 수정하거나 추가한 후 코드 영역이 활성화 되어 있는 상태에서 Ctrl + s 단축키를 입력하면 변경된 사항이 저장됩니다. 

코드가 저장되면 HTML 실행 미리 보기 화면이 자동으로 새로 고침 되지만 미리보기 화면을 강제로 새로고침하고 싶으면 미리보기 화면 좌상단에 위치한 새로고침 아이콘을 클릭해 주세요.

 

아래 스크린샷 처럼 왼쪽 하단영역에 파란색 배경의 그림판 영역이 추가된다면 성공입니다. 

나머지 영역들은 나중에 사용할 수 있게 그대로 두고 그림판에 집중하면서 계속 진행하겠습니다.

그리기 기능 만들기

본격적인 그리기 기능 추가에 앞서서 PaintApp 클레스의 생성자에 아래 코드를 추가해 줍니다.

constructor(parentEl) {

	...

	//PIXI.Container
	// - 아무 렌더링 요소도 가지고 있지 않지만, 자식을 가질 수 있음.
	// - 자식들을 한번에 제어하기에 용이함.               
	this.container = new PIXI.Container();
	//PIXI는 html처럼 트리 형태로 각각의 렌더링 객체를 관리함.
	//PIXI.Application에서 트리의 루트 역할을 하는 stage에 컨테이너를 자식으로 추가함.
	this.app.stage.addChild(this.container);
}

 

선 그리기 기능을 추가 해줍니다.

drawLine(x1, y1, x2, y2, color = 0x000000, weight = 2) {
    //PIXI.Graphics
    //그리기 기능을 하는 클레스. 대부분의 그림판기능을 포함하고 있음.
    //Canvas 2d Context 와 유사한 사용법을 가지고 있음.
    const graphics = new PIXI.Graphics();
    this.container.addChild(graphics);
    
    graphics.lineStyle(weight, color, 1);
    graphics.moveTo(x1, y1);
    graphics.lineTo(x2, y2);
}

 

paintTest.js 파일에 drwaLine 함수를 호출해서 잘 동작하는지 확인합니다.

paintApp.drawLine(100, 100, 200, 200);
paintApp.drawLine(200, 100, 100, 200, 0xff0000, 3);

 

다른 그리기 기능들도 추가해 줍니다.

drawRect(left, top, width, height, color = 0x000000, weight = 2) {
    const graphics = new PIXI.Graphics();
    this.container.addChild(graphics);
    graphics.lineStyle(weight, color, 1);
    graphics.drawRect(left, top, width, height);
}

drawCircle(x, y, radius, color = 0x000000, weight = 2) {
    const graphics = new PIXI.Graphics();
    this.container.addChild(graphics);
    graphics.lineStyle(weight, color, 1);
    graphics.drawCircle(x, y, radius);
}

drawPolygon(points, color = 0x000000, weight = 2) {
    if(!points || points.length <= 2) return;
    const graphics = new PIXI.Graphics();
    this.container.addChild(graphics);
    graphics.lineStyle(weight, color, 1);
    const startPoint = points[0];
    graphics.moveTo(startPoint.x, startPoint.y);
    for(let i = 1; i <= points.length; i++) {
        const idx = i % points.length;
        const point = points[idx];
        graphics.lineTo(point.x, point.y);
    }
}

drawRectFill(left, top, width, height, color = 0x000000) {
    const graphics = new PIXI.Graphics();
    this.container.addChild(graphics);
    graphics.beginFill(color);
    graphics.drawRect(left, top, width, height);        
}

drawCircleFill(x, y, radius, color = 0x000000) {
    const graphics = new PIXI.Graphics();
    this.container.addChild(graphics);
    graphics.beginFill(color);
    graphics.drawCircle(x, y, radius);
}

drawPolygonFill(points, color = 0x000000) {
    if(!points || points.length <= 2) return;
    const graphics = new PIXI.Graphics();
    this.container.addChild(graphics);
    
    graphics.beginFill(color);
    const startPoint = points[0];
    graphics.moveTo(startPoint.x, startPoint.y);
    for(let i = 1; i <= points.length; i++) {
        const idx = i % points.length;
        const point = points[idx];
        graphics.lineTo(point.x, point.y);
    }
}
...

paintApp.drawLine(100, 100, 200, 200);
paintApp.drawLine(200, 100, 100, 200, 0xff0000, 3);

paintApp.drawRect(200, 100, 100, 100, 0x00ff00, 1);

paintApp.drawCircle(200, 200, 50, 0x0000ff, 2);


paintApp.drawRectFill(120, 30, 50, 50, 0x00ffff);
paintApp.drawCircleFill(220, 50, 25, 0xffff00);

paintApp.drawPolygon([
    {x: 300, y: 25},
    {x: 330, y: 75},
    {x: 270, y: 75},
], 0x880088, 3);

paintApp.drawPolygonFill([
    {x: 300, y: 225},
    {x: 330, y: 275},
    {x: 270, y: 275},
], 0xff8800);

프로젝트 바로가기

https://diyplay.co.kr/editor/edit/11

 

 

이번 포스팅은 여기까지 하고 다음 포스팅에서 이어서 하겠습니다.

감사합니다.

이전 글

Blockly, pixi.js 사용해서 블록코딩 그림판 만들기 - 2

다음 글

블록코딩 콘텐츠 제작을 위한 Blockly 개발 시작하기

댓글 0
    서비스 이용약관|개인정보 보호정책

    Copyright © DIYPlay All rights reserved.