LandonSchropp

Click location relative to sprite

Recommended Posts

I'm building a simple tic-tac-toe game in Phaser. I've added a sprite for the board, and I'd like to detect where inside the board the user has clicked so I can add a.

Here's what I have so far:

let game = new Phaser.Game(380, 720, Phaser.AUTO, '', { preload, create });

function preload() {
  game.load.image('board', `/images/board.png`);
}

function create() {

  // Add the board
  let board = game.add.sprite(0, 0, 'board');
  board.anchor.setTo(0.5, 0.5);
  board.position = game.world.bounds.size().multiply(0.5, 0.5);

  // Scale the board so it properly fits in the canvas
  let scale = game.world.bounds.width / board.width * 0.9;
  board.scale.setTo(scale, scale);

  // Listen to clicks on the sprite
  board.inputEnabled = true;
  board.events.onInputDown.add(onBoardClick, this);
}

I'd really love to be able to do something like this:

function onBoardClick(sprite, pointer) {

  // Get the coordinates of the click relative to the bounds inside the board
  let point = sprite.relativeClickCoordinates;
  let { x, y } = point.divide(sprite.width, sprite.height).multiply(3, 3);
    
  let row = Math.floor(x);
  let column = Math.floor(y);
}

Ideally, this would spit out values for row and column between 0 and 2. Obviously relativeClickCoordinates doesn't exist, but I haven't been able to find an equivalent property or function while digging through the Phaser docs. Ideally, the relative coordinates of the click would take into account:

  • The anchor point of the sprite
  • The scale of the sprite
  • The position of the sprite relative to the mouse

Is there a simple way to accomplish this? Is there a better way? Thanks in advance!

Share this post


Link to post
Share on other sites

One way might be to dissect the area of the game manually via switch statements, and check if the mouse pointer lies within a certain range (x,y) and assign the appropriate column/row directly but thats inconvenient if you want a bigger board size.

Another possiblity might be to create two groups that contain sprites (X and O).You correctly position each sprite(two nested for loops), enable input to listen to mouseclicks, but set their alpha to zero to hide them. You can add a custom property to each sprite within the most inner for loop: ROWNUMBER and COLUMNNUMBER . Then, if the corresponding player clicks, set either X or O sprite alpha to 1, get corresponding COLUMNNUMBER and ROWNUMBER and continue with your algorithm. 

Another, maybe more convenient way (maybe not) : Here is an example of a tic-tac-toe game concept purely based upon collision checking (without physics). You can quickly alter the size of the board using this method. Here is the codepen:

Basically, you make a group of sprites and a group of hidden (green debug rendered) lines that you use for intersection calculation. Then after each player clicks on his board, it will "notify" any line that intersects with the sprite in that board and mark it. So you are keeping track of the intersect counts that each player has with each line, and if its a winning combination(for example: LINE_ROW2.intersection_list.filter_To("player2").count==3), then you have a winner. Also, since the number of possible "win lines" are 2*boardsize+2*diagonal lines., you can adjust the board size to any dimension.

It does not directly answer your problem, but it might give you more ideas on how to approach it within Phaser. Its probably not  the standard, quickest/most efficient algorithm, but its an interesting way of demonstrating the usefulness of collision detection. Also using this approach will allow you to retrieve any property you mentioned, such as mouse position (in the collisionCheck function). You can use the pointer object to retrieve the x and y position of your mouse when you click a certain area:

http://phaser.io/docs/2.6.2/Phaser.Pointer.html

 

Share this post


Link to post
Share on other sites

Thanks for the reply! I like all of the ideas, and the collision detection was really interesting! In this case, I think I'd like to keep it simple and do the math, but I'll definitely be keeping a couple of those techniques in my toolbox.

I was able to get things working by taking advantage of getBounds. Here's what I did:

function onBoardClick(sprite, pointer) {
  let { x, y, width, height } = sprite.getBounds();

  let row = Math.floor((pointer.y - y) * 3 / height);
  let column = Math.floor((pointer.x - x) * 3 / width);
}

Thanks again for the help!

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now


  • Recently Browsing   0 members

    No registered users viewing this page.