본문 바로가기
블로그 이미지

방문해 주셔서 감사합니다! 항상 행복하세요!

  
   - 문의사항은 메일 또는 댓글로 언제든 연락주세요.
   - "해줘","답 내놔" 같은 질문은 답변드리지 않습니다.
   - 메일주소 : lts06069@naver.com


Html 캔버스/Html 캔버스 에니메이션

HTML Canvas 사다리 타기(ladder, ghost leg, Amidakuji)

야근없는 행복한 삶을 위해 ~
by 마샤와 곰 2022. 2. 22.

 

* 게시글 하단의 제 깃허브 주소를 통해 실제 구현된 모습을 볼 수 있습니다

 

이번에 구현한 기능은 사다리타기 기능 입니다.

사다리 타기는 주어진 세로형태의 선에 본인이 원하는 선을 붙여서 만드는 기능입니다.

와..여긴 증말 많네요..

 

사다리 기능을 구현하기 위해서는 먼저 세로형태의 선을 그려줄 필요가 있습니다.

캔버스의 넓이를 가져온 다음에 그릴 갯수만큼 나누어준 뒤, 최소 넓이의 절반을 더해서 여백을 주도록 합니다.

높이는 전부 길게 할 경우에 여백이 생기지 않으므로 적절한 비율을 선택해 곱해 줍니다.

캔버스에서의 save와 restore는 필수 입니다.

 

이렇게 하고난 뒤에 시작과 끝 정보를 배열에 담아줍니다.

1차로 완성된 모습입니다.

 

다음으로 고민한 것이 이제 선을 그려준 뒤에 어떻게 찾아가게 할 지였습니다.

사다리에서의 규칙은 위에서 아래로 내려가는 것 이므로,

각각의 선의 구간별로 배열을 만들어 준 다음에 y축을 중심으로 순차정렬을 해 주게 하였습니다.

위 그림을 보면 선이 총 5개가 존재하는데, 5개의 구간별로 배열을 만들어 줍니다.

위의 예시로는 let data = [] 에서의 배열은 총 5개가 나오며,

배열 안에서의 데이터는 사용자가 그린 횟수만큼의 시작, 종료지점이 됩니다.

 

마우스가 다운(mousedown)되었으면서 움직이는(mousemove)경우에는 시작점을 지정하고,

마우스가 업(mouseup)되면 종료지점을 넣어줍니다.

    //마우스 다운 이벤트
    canvas.addEventListener('mousedown', (event) =>{
        if(!ctx) return
        isClicked = true
        let x1 = event.clientX - canvas.parentElement.offsetLeft || canvas.offsetLeft
        let y1 = event.clientY - canvas.parentElement.offsetTop || canvas.offsetTop
        if(isClicked){
            let startTarget = _isInSide(x1,y1)  //시작점을 기록 합니다
            startBridge = {...startTarget, x: startTarget.object.x, y: y1, originX:x1, originY : y1}  //x축은 그려진 선 기준값을 대입 합니다
        }        
    })    


    //마우스 업 이벤트
    canvas.addEventListener('mouseup', (event) =>{
        if(!ctx) return
        hoverPosition = {}
        if(isClicked){  //마우스가 다운된 상태의 조건이 충족하면,
            let x1 = event.clientX - canvas.parentElement.offsetLeft || canvas.offsetLeft
            let y1 = event.clientY - canvas.parentElement.offsetTop || canvas.offsetTop            
            let endBridge =  _isInSide(x1,y1)  //가장 마지막의 선 지점값을 가져 옵니다
            endBridge = {...endBridge, x: endBridge.object.x, y: y1}  //x축은 그려진 선 기준값을 대입 합니다

            //같은 선분 또는 옆 영역을 뛰어넘어가는 경우 등록하지 않습니다
            if(startBridge.dataIndex == endBridge.dataIndex || Math.abs(startBridge.dataIndex - endBridge.dataIndex) > 1) {
                isClicked = false
                hoverPosition = {}
                startBridge = null
                _init()
                _drawDataLine()
                return
            }

            //첫 마우스 다운 지점에서 마지막 마우스 업 지점까지의 거리를 lineData 배열에 담아둡니다
            let bridgeIdx = _makeid(50)
            startBridge.linkIdx = bridgeIdx
            endBridge.linkIdx = bridgeIdx
            data[startBridge.dataIndex].push(startBridge)  //데이터 배열에도 넣습니다
            data[endBridge.dataIndex].push(endBridge)
            lineData.push({startBridge, endBridge})
            _init()
            _drawDataLine()
        }
        isClicked = false
    })

 

각각의 x축 값은 고정이 되어야 합니다.

그래야만 세로선을 기준으로 그려지는 모양을 구현 할 수 있기 때문 입니다.

또한 서로의 연결 지점을 위해서 링크를 위한 인덱스 값을 서로 갖게 하였습니다(linkIndex)

 

이제 남은 것은 길찾기 입니다!

LinkedList에서 사용되는 기법처럼 서로의 연결값(linkIndex)을 바탕으로 찾아가게 하였습니다.

또한 사용자가 축을 교차로 하여 무한 재귀현상을 방지하기 위해서 이미 지나간 값은 히스토리를 관리하는 배열에 담아서 두번다시 가지않게 하였습니다.

이러한 경우에서도 궁극적인 목적은 맨 마지막의 y축 값까지 깊이탐색을 하는 것 입니다.

이를 바탕으로 구현한 모습 입니다.

기초기능만 붙여보았습니다!

 

넘어가는 선에 대한 제약조건까지 주면 조금 더 구현하기가 쉬워집니다.

선과 선에서의 거리는 삼각함수를 활용하여 거리를 구한 다음에 최근접 거리를 구해서 해당 지점을 넣어주면 됩니다.

 

간단하게 핵심위주의 기능만 구현 해 보았습니다.

제 깃허브(gitHub)에서 실제 동작하는 모습을 확인 할 수 있습니다.

* 위 사진처럼, 마우스 다운 + 무브(드래그) 를 하시면 됩니다! (근접 선까지만 가야 합니다!)

 

https://taeseungryu.github.io/sample/sampleView/ghostLeg/index.html

 

ladder

 

taeseungryu.github.io

 

위 기능에 사용된 전체 소스코드는 마찬가지로 제 깃허브에 올려놓았습니다.

주석에 설명을 붙여놓았습니다.

어렵지 않는 내용이라 쉽게 이해 할 수 있습니다. ^^

https://github.com/TaeSeungRyu/sample/tree/main/사다리 그리기

 

 

위 모든 내용이 웹(web)에서 동작하는 캔버스(canvas)로 이루어진 내용 입니다.

 * 플래쉬, 액션스크립트, 유니티 같은 응용 프로그램이 아닙니다~

이상으로 HTML Canvas 사다리 타기(ladder, ghost leg, Amidakuji)에 대해서 살펴보았습니다.

문의사항이나 궁금한 점은 언제든 댓글 또는 메일로 연락주세요~ 👻

 

 

반응형
* 위 에니메이션은 Html의 캔버스(canvas)기반으로 동작하는 기능 입니다. Html 캔버스 튜토리얼 도 한번 살펴보세요~ :)
* 직접 만든 Html 캔버스 애니메이션 도 한번 살펴보세요~ :)

댓글