dr.ugi

Input and/or drag on a group

Recommended Posts

This is afaik not possible with phasers drag implementation. However should be able to do this yourself. Use sprite.events.onInputDown to register when and where the user clicked on one of your sprites. With game.input.onUp you know when he has released the button. While he has not released the button you can update the group coordinates yourself in the update function in relation to the current coordinates of the input and the position you got when he clicked on your sprite.

Share this post


Link to post
Share on other sites

It's actually a bit more complex than you'd think. A Group doesn't have any area itself, it's infinite in all directions - so there's no detecting if you've clicked on it. But you can click on a child easily, however should the drag update all other children, just that child OR the group x/y placement itself? (which in turn would update the other children to, only maybe not in the way you'd expect). And then what about nested groups? :)

 

I like the feature, it's just not as straight forward to implement as it appears on the surface :)

Share this post


Link to post
Share on other sites

Hi

 

I'm really new to phaser

 

I am trying to make something like a factory, where you have to drag and drop "products" that come out of a machine. I created these products as a group but now when I try to drag them, it keeps pointing to the last element created, not to the product i'm clicking on.

 

I'm not sure how to implement this, I saw somewhere on the examples that they used as a parameter _ball and _brick and that somehow works with the current brick. But I don't see how to do this with clicking.

 

I also need to "unite" somehow different elements of a group to create something bigger.

 

Should I do this with diferent functions like the tank examples or is it doable with groups?

 

Thank you so much in advance

 

Here's the code on pastebin http://www.pastebin.ca/2690180

Share this post


Link to post
Share on other sites
It may not be the most efficient, but for simplicity, I just create an invisible sprite the same size as the group and make that a child of the group, then add the input controls to that.

 

i.e.

 



var group = game.add.group();
//add stuff to group etc...
var fakeHitZone = game.add.sprite(0, 0, 'spritesheet', 'invisible-box', group);
fakeHitZone.width = group.width;
fakeHitZone.height = group.height;
fakeHitZone.inputEnabled = true;
fakeHitZone.events.onInputDown.add(functionToRun); //add more events if required..


 

Here 'invisible-box' is a 1*1 transparent pixel.

 

Just be aware that changes to the size of the group have to be manually applied to the hit zone too.

Share this post


Link to post
Share on other sites

I got tired of waiting for group dragging so I added it. I'll figure out how to get a pull request with the GitHub stuff later, but for now you can do what I used to do...

 

After you have your group set up, drop a transparent "sprite" on top of it with game.add.sprite(yourGroup.x, yourGroup.y, "somePng"); Set its width and height to equal the group's width and height. Now make the sprite draggable. Every game update, just set the group's x and y equal to the sprite's x and y.

 

That's essentially what my mod does anyway, just more automatic.

Share this post


Link to post
Share on other sites

I got tired of waiting for group dragging so I added it. I'll figure out how to get a pull request with the GitHub stuff later, but for now you can do what I used to do...

 

After you have your group set up, drop a transparent "sprite" on top of it with game.add.sprite(yourGroup.x, yourGroup.y, "somePng"); Set its width and height to equal the group's width and height. Now make the sprite draggable. Every game update, just set the group's x and y equal to the sprite's x and y.

 

That's essentially what my mod does anyway, just more automatic.

 

 

Do you have an example of this? And are you updated each child's x/y individually? 

Share this post


Link to post
Share on other sites

I'm just reviving this old thread. I had the same issue and wanted to make an entire group draggable. I came up with this approach which doesn't require to add a hit area:

const group = game.add.group()
const item1 = game.add.image( 0, 0, 'item1', null, group )
const item2 = game.add.image( 0, 0, 'item2', null, group )

makeDraggableGroup( group )

function makeDraggableGroup ( g ) {
  g.forEach( makeDraggable )
}

function makeDraggable ( obj ) {
  if ( obj.inputEnabled === undefined ) return

  obj.inputEnabled = true
  obj.input.enableDrag()

  obj.events.onDragUpdate.add( handleDragUpdate )

  // optional:
  // obj.events.onDragStart.add( handleDragStart )
  // obj.events.onDragStop.add( handleDragStop )
}

function handleDragUpdate ( obj, pointer, x, y, snapPoint, isFirstUpdate ) {
  if ( isFirstUpdate ) {
    obj.origin = new Phaser.Point( obj.x, obj.y )
    obj.parent.origin = new Phaser.Point( obj.parent.x, obj.parent.y )
  }

  obj.parent.x = obj.parent.origin.x + x
  obj.parent.y = obj.parent.origin.y + y
  obj.x = obj.origin.x
  obj.y = obj.origin.y
}

// optional:

// function handleDragStart ( obj ) {
//  console.log( 'start drag', obj )
// }

// function handleDragStop ( obj ) {
//  console.log( 'stop drag', obj )
// }

Just note that the above code only considers direct children. If you have nested groups you'd need to drill into each sub group. Something like replacing the

if ( obj.inputEnabled === undefined ) return

with

if ( obj.children ) obj.forEach( makeDraggable )

But it'd need some more work than just this for nested groups.

Share this post


Link to post
Share on other sites

Here's an improved version that seems to work better to make Phaser groups draggable. Actually it doesn't matter if you pass it a group or other item, it works for anything you want to make draggable. It also includes nested groups and you can pass your (optional) callbacks. Also the previous code had an issue when children had positions other than (0,0) as the dragged group would jump by that offset. So here is a more general approach:

function makeDraggable ( { item, startCallback, stopCallback, updateCallback } ) {
  if ( item.forEach ) {
    item.forEach( makeDraggableObject )
  } else {
    makeDraggableObject( item )
  }

  function makeDraggableObject ( obj ) {
    if ( obj.forEach ) {
      obj.forEach( makeDraggableObject )
      return
    }

    obj.inputEnabled = true
    obj.input.enableDrag()
    obj.origin = new Phaser.Point( obj.x, obj.y )

    const callback = item.forEach ? handleDragUpdate : updateCallback

    if ( callback ) obj.events.onDragUpdate.add( callback )
    if ( startCallback ) obj.events.onDragStart.add( startCallback )
    if ( stopCallback ) obj.events.onDragStop.add( stopCallback )
  }

  function handleDragUpdate ( obj, pointer, x, y, snapPoint, isFirstUpdate ) {
    if ( isFirstUpdate ) {
      obj.startDragPos = new Phaser.Point( obj.x, obj.y )
      item.startDragPos = new Phaser.Point( item.x, item.y )
    }

    item.x = item.startDragPos.x - obj.origin.x + x
    item.y = item.startDragPos.y - obj.origin.y + y
    obj.x = obj.startDragPos.x
    obj.y = obj.startDragPos.y

    if ( updateCallback ) updateCallback( obj, pointer, x, y, snapPoint, isFirstUpdate )
  }
}

Usage, e.g.:

const group = game.add.group()
const item1 = game.add.image( 100, -50, 'item1', null, group )
const item2 = game.add.image( -100, 50, 'item2', null, group )

makeDraggable( {
  item: group,
  startCallback: handleDragStart,
  stopCallback: handleDragStop,
  updateCallback: handleDragUpdate,
} )

function handleDragStart ( obj ) {
  console.log( 'START DRAG', obj )
}

function handleDragStop ( obj ) {
  console.log( 'STOP DRAG', obj )
  // makeDraggable adds the original position to the object as obj.origin
  // we can use this e.g. to tween rebound the item to it's origin
  TweenMax.to( obj, 1, { x: obj.origin.x, y: obj.origin.y, ease: Elastic.easeOut } )
}

function handleDragUpdate ( obj, pointer, x, y, snapPoint, isFirstUpdate ) {
  console.log( 'UPDATE DRAG', obj )
}

 

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...

  • Recently Browsing   0 members

    No registered users viewing this page.