그룹으로 생성된 객체 드래그 하는 방법

저는 종종 프로젝트 중 그룹으로 생성된 객체를 드래그할 필요가 있다는 문제에 직면했습니다.
지난 며칠간 프로젝트로 인해 이것은 나를 괴롭혔습니다.
나는 현재 그리드에 엄지 손톱을 많이 표시해야하는 앱을 만들고 있습니다.
그리드는 수직으로 스크롤해야하며 축소판을 클릭해야합니다.

이제 Phaser의 그룹에서 드래그를 구현하려고 시도해 본 적이 있다면 쉬운 일이 아닌지 알 수 있습니다.
Phaser의 창시자 인 Richard Davey는 html5gamedevs 포럼에서이 게시물의 그룹을 끌 수있는 기본 방법이없는 이유를 설명합니다.

"그것은 실제로 생각보다 조금 더 복잡합니다. 그룹에는 모든 영역이 없으며 모든 방향에서 무한합니다. 따라서 클릭 한 경우 감지 할 수 없습니다. 그러나 드래그하여 다른 모든 자식, 그 자식 또는 그룹 x / y 배치 자체를 업데이트해야한다면 쉽게 자식을 클릭 할 수 있습니까? (차례 차례로 다른 아이들을, 당신이 예기 할 방법에서 어쩌면 단지) 새롭게 할 것입니다. 그리고 중첩 된 그룹은 어떻습니까?"

필자는이 기능이 마음에 든다. 표면에 나타나는 것처럼 구현하기가 쉽지 않다.

Brainstorming the solution
그래서 내가 뭘해야하니? 내가 생각해 낸 첫 번째 해결책은 그룹의 높이와 너비가 같고 드래그 할 수 있도록 스프라이트를 만드는 것입니다. 작동하지만 새로운 자체 문제는 스프라이트를 클릭하여 개별 축소판에 도달 할 수 없다는 것입니다. 이것은 프로젝트의 핵심 부분입니다. 이제는 더 나은 솔루션이 필요하다는 것을 알게되었습니다. 이것은 내가 지금까지 알고있는 것이다 :

내 요구 사항 :
- 그룹 드래그
- 자녀를 클릭 할 수있는 상태로두기

내가 지금까지 알고있는 것 :
- 클릭 할 수있는 스프라이트는 마우스 이벤트를 다른 스프라이트로 차단합니다.
- 그룹이 마우스 이벤트를 감지 할 수 없습니다.
- Phaser의 드래그를 사용하여 그룹을 끌 수 없습니다.
- game.input은 아무것도 차단되지 않습니다.

그 마지막 요점은 내가 끌기가 무엇인지 생각하고있다 :
- 마우스 다운 이벤트
- 마우스가 눈금의 범위 내에 있는지 확인하기
- 마우스의 움직임을 확인하고 필요에 따라 눈금을 업데이트하십시오.

여기서 마우스라는 용어를 사용하고 있지만 터치 이벤트 일 수도 있습니다.

여기에 내가 지금 애플 리케이션에서 사용하고있는 해결책이있다. 이 예제에서는 Javascript 클래스를 사용합니다.

드래그를 위해 DragBox라는 클래스를 사용하고 있으며이 클래스도 그룹을 확장합니다. 나는 아이들을 여기에 추가하고 있지 않지만 내장 된 업데이트 기능을 사용할 수 있도록 그룹을 확장 중입니다. 드래그 해야하는 객체는 DragBox의 인스턴스로 유일한 매개 변수로 전달됩니다.
class DragBox extends Phaser.Group {
    constructor(dragObj) {
        super(game);
        this.dragObj = dragObj;
        game.input.onDown.add(this.onDown, this);
    }
    onDown() {
        //set canDrag to false
        this.canDrag = false;
        //check if the mouse is in bounds
        //since my dragObject is the full width of the game
        //I only need to check the y position
        //The top of the drag object is the y position
        //and the bottom is the top plus the height
        //
        if (game.input.y > this.dragObj.y && game.input.y < (this.dragObj.y + this.dragObj.height)) {
            //set the canDrag to true;
            this.canDrag = true;
            //get the start position of the dragObject
            //so we may compare it to the current position
            //when dragging
            this.startY = this.dragObj.y;
            //the offset is how far down on the grid the
            //mouse is when the user started dragging
            //without this line the grid will jump when
            //the drag starts
            this.offSet = this.dragObj.y - game.input.y;
        }
    }
    update() {
        if (game.input.mousePointer.isDown) {
            if (this.canDrag == true) {
                //calculate the difference between the startY
                //and the current mouse y position
                //and add in the offSet
                var diff = game.input.y - this.startY + this.offSet;
                //update the start position
                //by adding the difference to the start position
                this.dragObj.y = this.startY + diff;
            }
        }
    }
}
대부분의 코드는 주석입니다. 노트가 없는 코드는 약 23 행뿐입니다.
class DragBox extends Phaser.Group {
    constructor(dragObj) {
        super(game);
        this.dragObj = dragObj;
        game.input.onDown.add(this.onDown, this);
    }
    onDown() {
        this.canDrag = false;
        if (game.input.y > this.dragObj.y && game.input.y < (this.dragObj.y + this.dragObj.height)) {
            this.canDrag = true;
            this.startY = this.dragObj.y;
            this.offSet = this.dragObj.y - game.input.y;
        }
    }
    update() {
        if (game.input.mousePointer.isDown) {
            if (this.canDrag == true) {
                var diff = game.input.y - this.startY + this.offSet;
                this.dragObj.y = this.startY + diff;
            }
        }
    }
}

그룹을 직접 드래그하려면 코드 클래스를 직접 복사하여 프로젝트에 포함해야합니다.

그런 다음, 이 코드를 사용하여 개체를 만든 직후에 구현합니다.
var dragBox = new DragBox(objectYouWantToDrag);

이렇게하면 객체를 세로로 드래그 할 수 있지만 코드는 수평이 좋도록 조정할 수 있습니다.
다음은 내가 하는 일의 예입니다.
먼저 Phaser 그룹을 확장하는 그리드 클래스를 만들었습니다.
이 그리드 클래스는 같은 크기의 자식 요소 용입니다.
열 수에 'cols' 매개 변수가 필요합니다.
class Grid extends Phaser.Group {
    constructor(cols) {
        super(game);
        this.cols = cols;
    }
    arrange() {
        var xx = 0;
        var yy = 0;
        this.children.forEach(function(item) {
            //place the item on a column with a 10 percent buffer
            item.x = item.width * xx * 1.1;
            //place the item on a row with a 10 percent buffer
            item.y = item.height * yy * 1.1;
            xx++;
            if (xx ==this.cols) {
                xx = 0;
                yy++;
            }
        }.bind(this));
    }
    center() {
        this.x = game.width / 2-this.width/2;
        this.y = game.height / 2-this.height/2;
    }
}

미리보기 이미지의 경우 Box라는 클래스를 사용하고 있습니다. 이것은 단순히 마우스 리스너가 연결된 이미지가 포함 된 그룹을 확장하는 클래스입니다.
class Box extends Phaser.Group
{
constructor()
{
super(game);
var thumb=this.create(0,0,"box");
thumb.anchor.set(0.5,0.5);
thumb.inputEnabled=true;
thumb.events.onInputDown.add(this.clicked);
}
clicked()
{
console.log("click");
}
}

그리고 이건 내 stateMain.js 코드입니다.
var StateMain = {
    preload: function() {
        game.load.image("box", "images/box.png");
    },
    create: function() {
        //make a grid
        //
        this.grid = new Grid(5);
        //make 30 boxes and add to the grid
        //
        for (var i = 0; i < 30; i++) {
            var box = new Box();
            this.grid.add(box);
        }
        //arrange the child objects into a grid
        //
        this.grid.arrange();
        //center on stage
        //
        this.grid.center();
        //make a dragBox and pass the grid to it
        //
        var dragBox = new DragBox(this.grid);
    }
}
그리고 드래그 그룹 코드가 실제로 작동합니다. 개발자 콘솔을 열면 사각형이 여전히 클릭 가능한지 확인할 수 있습니다. 드래그 중에 실수로 사각형이 클릭되지 않도록하려면 마우스를 아래로 내리고 마우스를 위로 올리는 시간을 확인하는 함수를 구현할 것입니다. 그것은 빠른 다음 그렇지 않으면 클릭이 될 것입니다, 나는 사용자가 드래그하고 있다고 가정합니다.


댓글 없음:

댓글 쓰기