친절한효자손 취미생활

대전에서 HTML / CSS / JS 관련 모임도 하고 있는데 회원분들 중에서는 티스토리 스킨을 취미삼아 뜯어고치시는분이 한 분 계십니다. 이분께서 만드신 스킨이 넘나 맘에 들었기에 앞으로 제작될 세번재 친효스킨에 영감을 얻어서 레이아웃을 일부 반영해 사용해도 된다는 허락을 받았죠. 그리고 최근에는 그분께서 티스토리에 물리엔진까지 적용시키는 엄청난 모습을 보여주셨습니다. 정말이지 이런 분들이 대전에 계셔서 참 다행입니다. 그렇기에 당장 모임을 열어 그분께 적용 방법을 배웠습니다. 결과물은 다음과 같습니다.

 

예시 살펴보기

보시면 클릭하는 지점에 오브젝트가 생성되고 중력에 의해 아래로 떨어집니다. 게다가 물리엔진이 적용되기에 저의 캐릭터인 효자곰이 각 모서리에 따라 서로 부딫히면서 양옆으로 자연스럽게 굴러 떨어지는 연출까지 선보이고 있습니다. 진짜 신기하죠? 이 물리엔진을 어떻게 적용시키는건지 바로 알아보겠습니다. 참고로 티스토리 뿐만 아니라 HTML 편집이 가능한 플랫폼이라면 모두 적용시킬 수 있습니다. 즉 코드펜같은 곳에서도 적용 가능합니다. 직접 가서 확인해보고 싶으시면 아래의 티스토리를 방문해 보시기 바랍니다.

 

 

친효스킨 - 아트북 개발 페이지

스킨 개발용 티스토리입니다!

gearbestkorea.tistory.com

 

준비물

다음의 준비물이 필요합니다.

 

PNG 포맷 이미지

 

네. 별거없습니다. 사용할 이미지만 있으면 되고 나머지는 코드만 세팅하면 됩니다. 물리엔진을 적용시킬것이기에 PNG 형식의 이미지가 좋습니다. JPG나 GIF는 이미지가 사각형으로 인식하겠죠? 투명한 부분을 모두 흰색으로 처리하니까요. 따라서 다이나믹한 물리엔진을 사용할 수 없습니다. 또한 엔진 오류가 발생할 수 있습니다. JPG로 테스트해봤는데 오류가 뜨더군요. 따라서 PNG로 제작해 주시기 바랍니다. 효자곰의 경우 곰돌이 부분만 인식하고 있으며 나머지는 투명한 영역이기에 저렇게 떨어지면서 다이나믹한 움직임을 보여줄 수 있는 것입니다.

 

소스 다운로드

본문 내용에서 소개되는 각종 코드를 담은 텍스트 파일을 아래에 첨부했으니 먼저 다운로드 받으시고 같이 보면서 사용하시면 되시겠습니다. 번호별로 소스를 구별했으니 찾기 쉬우실 겁니다.

 

HTML 물리엔진.txt
0.00MB

 

1. CDN 세팅하기 (물리엔진 스크립트)

아래의 스크립트 주소를 스킨의 <head> 안쪽에 넣어줍니다.

 

<script src="https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.17.1/matter.min.js"></script>

 

이 스크립트가 물리엔진 라이브러리를 로드하는 핵심 코드입니다. 반드시 필요합니다.

 

다음은 HTML의 본문인 <body>에서 작업해야 하는 내용입니다. 티스토리의 HTML에 있는 <body> 태그 안에 코드를 추가해야 합니다.

 

2. 캔버스 태그

<canvas class="canvas" id="canvas"></canvas>

 

이 요소는 클릭했을 때 물리엔진이 적용되는 영역을 설정하게 됩니다. 즉 캔버스 레이아웃이 됩니다. 다음은 본문에 추가하는 작동 스크립트입니다. <body> 바로 아래에 추가하시면 됩니다. 참고로 티스토리의 경우에는 <body> 안쪽에 id값이 들어있는 경우가 있습니다. 즉 <body id="어쩌구저쩌구..."> 이런 식일겁니다. <body 가 있다면 그곳이 곧 시작 태그이므로 해당 태그의 아래에 넣어주면 됩니다.

 

3. 본문 스크립트

<script>
    // Canvas 설정
    const canvas = document.getElementById('canvas');
    const ctx = canvas.getContext('2d');
    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;

    // Matter.js 설정
    const engine = Matter
        .Engine
        .create();
    const world = engine.world;
    const render = Matter
        .Render
        .create({
            element: document.body,
            canvas: canvas,
            engine: engine,
            options: {
                width: canvas.width,
                height: canvas.height,
                wireframes: false,
                bounds: {
                    min: {
                        x: 0,
                        y: 0
                    },
                    max: {
                        x: canvas.width,
                        y: canvas.height + 1000
                    }
                }
            }
        });

    // 이미지 로드
    const rabbit = new Image();
    rabbit.src = './images/파일명.png';

    // 이미지 떨어뜨리기
    const rabbits = [];
    canvas.addEventListener('click', (event) => {
        const x = event.clientX;
        const y = event.clientY;
        const rabbitSize = 100;
        const newRabbit = Matter
            .Bodies
            .circle(x, y, rabbitSize / 2, {
                frictionAir: 0.02, //0.05(기본값) 중력가속도 : 값이 작아질수록 중력이 강해짐
                restitution: 0.4, //0.5(기본값) 탄력도 : 값이 작아질수록 탄성이 무뎌짐 (묵직해짐)
                // 바닥에 닿으면 움직이지 않도록 설정
                isStatic: false,
                render: {
                    sprite: {
                        texture: './images/파일명.png'
                    }
                }
            });
        rabbits.push(newRabbit);
        Matter
            .World
            .add(world, newRabbit);
    });

    // 애니메이션 시작
    Matter
        .Render
        .run(render);
    Matter
        .Engine
        .run(engine);
    function animate() {
        requestAnimationFrame(animate);
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        for (let i = 0; i < rabbits.length; i++) {
            ctx.save();
            ctx.translate(rabbits[i].position.x, rabbits[i].position.y);
            ctx.rotate(rabbits[i].angle);
            ctx.drawImage(
                rabbit,
                -rabbits[i].circleRadius,
                -rabbits[i].circleRadius,
                rabbits[i].circleRadius * 2,
                rabbits[i].circleRadius * 2
            );
            ctx.restore();
            // 이미지가 바닥에 닿았는지 확인하고, 닿았으면 isStatic을 true로 설정하여 더 이상 움직이지 않도록 함
            if (rabbits[i].position.y + rabbits[i].circleRadius >= canvas.height) {
                Matter
                    .Body
                    .setStatic(rabbits[i], true);
            }
        }
    }
    animate();
</script>

보시면 주석으로 간략 설명이 되어있으니 스크립트를 어느정도 구축할 줄 아시는 분이시라면 이해가 될 것입니다. 이 스크립트는 </body> 바로 위에 넣어주시면 됩니다. 바디 태그가 끝나는 부분의 바로 위쪽 입니다. 그리고 코드 중간에 보시면 「파일명」 이라는 한글이 보이죠? 해당 텍스트는 여러분들께서 제작한 이미지 파일명으로 변경하는 영역입니다. 제 경우는 효자곰 이미지의 파일명이 ch여서 ch.png로 입력이 되어있는 상태입니다. 파일명은 한글로 하지 마시고 알파벳을 사용하시는걸 추천합니다. HTML 세계에서 한글은 오류를 일으킬 가능성이 높기 때문입니다.

 

4. CSS 세팅

이제 캔버스의 CSS 관련 코드만 세팅해주면 됩니다.

 

canvas {
	display: block;
	position: fixed;
	top: 0;
	left: 0;
	width: 100%;
	height: 100%;
	z-index: 1;
}

.canvas {
	background: transparent !important;
}

이건 당연히 스킨 편집의 CSS 탭에 넣으셔야 합니다. 아무곳이나 넣어도 되지만 처음 하시는 분들은 잘 못 넣으면 걱정이 될 것입니다. 보통은 CSS가 끝나는 부분에 새 공간을 더 확보해서 코드를 넣는 편입니다.

 

이미지 업로드

마지막으로 여러분들께서 준비하신 이미지만 티스토리에 업로드하면 끝입니다.

 

관리자 > 스킨편집 > HTML 편집 > 파일업로드로 들어가셔서 +추가 버튼을 누르면 이미지 파일을 자신의 티스토리에 업로드 할 수 있습니다. 업로드가 완료되면 오른쪽 상단의 적용 버튼을 눌러 저장합니다. 이제 여러분들의 티스토리 메인 페이지로 들어가시어 빈 영역을 클릭해 보시기 바랍니다.

 

만약 정상적으로 작동하지 않는다면?

이 경우에는 캔버스 영역이 본문 바디에 묻혔거나 바디 영역에서 빈 공간이 없어서 발생하는 문제일 가능성이 큽니다. 또한 바디에 세팅된 여러개의 레이아웃이 캔버스 영역과 중복되었을 가능성도 있습니다. 애석하게도 이 부분은 사용하는 스킨마다 레이아웃이 전부 다르기에 제가 어떻게 해드릴 수 있는 부분이 없습니다. 정말 적용하고 싶으시다면 댓글로 현재 어떤 스킨에 적용시키고 싶으신지 해당 내용을 남겨주시면 확인 후 답변드리도록 하겠습니다. 끝.

공유하기

facebook twitter kakaoTalk kakaostory naver band