Tile based movement

Dec 6, 2013 at 11:00 AM
So I have a little demo that moves my 2D sprite around an isometric map. Great stuff.

But I need to do something a bit more complex. I need to
  1. Calculate the allowed movement score of my sprite
  2. Highlight the adjacent tiles relative to this movement score
  3. Move the sprite to the correct tiles once clicking on them
Now all the movement data etc., is stored within an object. My original idea was to set this object to as a property of the base sheet which the sprite is located on. From that point I guess it would be easy to calculate the positioning of tiles in 8 directions from that particular base tile. To create the highlights, I would create sheets and colour and position them according to calculations.

The problem I'm having is, I guess I need a function to calculate the closest base sheet to a particular object...or anything really, as I'd like to be able to click anywhere on the canvas and be able to highlight the closest tile if possible.

Seems like crossyards is doing this when mousing over the yards. Not really sure how to do it right now. Any help would be really appreciated!
Coordinator
Dec 6, 2013 at 1:48 PM
First of all, take a look at the 'Selecting locations and objects' example (equations in the documentation is a bit more up-to-date because they also take page scrolling into account). Basically you can use inverseTransformPoint and getPointuv functions to transform coordinates for what you want.

Also, to get the corners of a particular sheet you can use
var cornersInXYZ = sheet1.corners; // array of objects with x,y,z properties
var cornersInUV = sheet1.data.cornersuv; // array of objects with u,v,z properties
And there is a function to check if a 2D point is inside a 2D polygon:
var x = 5;
var y = 5;
var corners = sheet1.data.cornersuv;
var isPointInside = sheetengine.calc.checkInboundsPolygon(corners,x,y).inbounds;
So basically what you can do is transform your mouse click coordinates to uv coordinates and then call the checkInboundsPolygon function to check if the click occurred inside a given sheet.
If you want something similar for an object in the scene, then why not just compare the x,y,z coordinates of that object with the corners of sheets?

Let me know if you are stuck!
Dec 6, 2013 at 8:19 PM
Edited Dec 6, 2013 at 9:04 PM
Hey thanks for the reply!

I think my main problem in understanding those functions is that I don't know what the puv or pxy objects actually relate to.

edit: can you also let me know what the relu and relv properties on sheet objects are?

edit: okay I'm reading the Creating Objects tutorial. So, pretty much all my interactive objects will be 64px x 64px sheets. Sprites will be rotated at a gammaD of 45. When creating a sprite I need to map it to a SheetObject to interact with it right? Should that new object have the same dimensions as the sheet? What do the width, height, relu and relv properties of that SheetObject relate to?

Also, by the way, in the Selecting locations and objects tutorial, if I scroll the window low and click inside the canvas, the character moves very far in the completely opposite direction. This is happening in both Chrome and FF.
Coordinator
Dec 6, 2013 at 9:03 PM
xyz always refer to world coordinates and uv refer to screen coordinates.
In the 'Selecting locations and objects' example the puv is your click coordinates relative to the top left corner of the visible main canvas in screen coordinates and pxy is the point with x-y-z coordinates that corresponds to that puv point in world coordinates. So if your world is positioned at the exact center and you click the center of the main canvas, your click (puv) coordinates will be something like (u: canvaswidth/2, v:canvasheight/2) and the corresponding pxy point will be (x:0,y:0,z:0).

To determine if your click point falls inside a sheet you don't actually have to calculate pxy from puv, because you have puv, the point in screen coordinates where your mouse is pointing at and you have the sheet's corners in the same screen coordinate system (sheet.data.cornersuv), and you can call the checkInboundsPolygon with these data simply to check if your mouse location is "over" a specific sheet or not.

relu, relv: an object is a group of sheets whose view/visuals can be updated on the main canvas. To make this redraw procedure fast, you have to define the smallest possible bounding box that will be redrawn every time the object changes/moves/rotates. When objects move they disappear from one location and appear on another location, so if you don't want to end up redrawing two separate regions you have to define the bounding box big enough so that it surely will overlap with the object's previous drawn state. It could be a good first guess to simply use a bounding box that has equal distance from the object from all sides, however in practice it would not necessarily lead to the best performance, because the shadows cast by the object are drawn in one specific direction - that also needs to be covered by the bounding box. So usually you would set up a bounding box that contains the object not necessarily in its exact center, and that is controlled by the relu/relv parameters in the canvasSize constructor parameter. These parameters define where the object is positioned relative to the top left corner of the bounding box. Take a look at this also: https://www.crossyards.com/developers/defining-and-displaying-a-character#canvassize
Dec 6, 2013 at 9:39 PM
Edited Dec 6, 2013 at 10:48 PM
Hmm so in reference to your first paragraph. I have created an object and placed it at x:0,y:0 in the world.

When I do this:
canvasElement.onclick = function(event)
          {
            var puv =
            {
              u:event.clientX - sheetengine.canvas.offsetLeft,
              v:event.clientY - sheetengine.canvas.offsetTop
            };
            var pxy = sheetengine.transforms.inverseTransformPoint(
            {
              u:puv.u + sheetengine.scene.center.u,
              v:puv.v + sheetengine.scene.center.v
            });

            console.log('puv u: ' + puv.u + " puv v: " + puv.v);
            console.log('pxy x: ' + pxy.x + " pxy y: " + pxy.y);
          }
And click on the object, my pxy.x output is like 510...not really sure why!

edit: I get the PUV stuff from clicking now, that seems to be resolving correctly, if I click in the center of the canvas my puv.u is 960 and my screen is 1920px wide. So that makes sense. What seems to be off is my pxy, this doesn't seem to be calculating correctly.

Also &#43 is meant to be plus, not sure why the markdown is not working with that.
Coordinator
Dec 6, 2013 at 10:23 PM
Hm, what is the value of sheetengine.scene.center?
Dec 6, 2013 at 10:41 PM
Object {x: 0, y: 0, u: 0, v: 0} 
Coordinator
Dec 6, 2013 at 11:01 PM
I don't really get it then. What is the value of sheetengine.canvasCenter? If you call sheetengine.transforms.inverseTransformPoint(sheetengine.canvasCenter) you should get (x:0,y:0,z:null) result.
Dec 6, 2013 at 11:07 PM
sheetengine.canvasCenter = Object {u: 450, v: 250}
and
sheetengine.transforms.inverseTransformPoint(sheetengine.canvasCenter) = {x:0,y:0,z:null}
just as you said. Is there something wrong with the way I am calculating pxy?
Coordinator
Dec 6, 2013 at 11:19 PM
No. But something is wrong. Take a look at the following:
sheetengine.canvasCenter = {u:sheetengine.canvas.width/2,v:sheetengine.canvas.height/2}; // main canvas center
This is how canvasCenter is defined. So if you get 450 by 250 then it means that your canvas size is 900 by 500, just like in the examples. However if you get 960 for your puv.u instead of 450, then there is something wrong in how you get puv. If you click the center of the canvas, u should be half the width of the canvas. If you click the top-left corner of the canvas u should be 0. Take a look at this:
var puv = {
    u:event.clientX - sheetengine.canvas.offsetLeft + pageXOffset,
    v:event.clientY - sheetengine.canvas.offsetTop + pageYOffset
  };
Here pageXOffset and pageYOffset make sure that the calculation is correct even if the page is scrolled to somewhere. Maybe it's the same issue for you?
Dec 6, 2013 at 11:29 PM
Edited Dec 7, 2013 at 12:14 AM
Something is definitely off.

Yes I just decided to do all my experiments inside of the "Adjusting the light source" tutorial.

But isn't puv calculated as the real world coordinates? In that sense, I thought puv will be wherever you click on the browser window. That makes sense then that the center of the screen is 960 if my window width is 1920.

Using the new puv object you posted seems to make no difference for me...well it makes a difference but I'm still not getting x:0,y:0 when I click on the object at x:0,y:0
Dec 7, 2013 at 12:18 AM
OMG hahahaha

placing the canvas inside a div that has position:relative was the problem!

All sorted now!

Man choosing the light source tutorial to do my experiments on was the wrong decision!!!
Dec 7, 2013 at 10:10 AM
Edited Dec 7, 2013 at 10:18 AM
Okay, got things working how I want finally. I did things a little different to how you suggested

Here is my code (I'm using jQuery as well btw)
canvasElement.onclick = function(event)
{
var puv = {
                u:event.clientX - sheetengine.canvas.offsetLeft + pageXOffset,
                v:event.clientY - sheetengine.canvas.offsetTop + pageYOffset
              };
var pxy = sheetengine.transforms.inverseTransformPoint(
            {
              u:puv.u + sheetengine.scene.center.u,
              v:puv.v + sheetengine.scene.center.v
            });
var mapSize = (tiles*2 +1)*64/2;

            if(pxy.x > mapSize || pxy.x < -mapSize || pxy.y > mapSize || pxy.y < -mapSize)
            {
              console.log('out of bounds');
            }
var basesheetCenters = [];
          $.each(sheetengine.basesheets , function(index , item)
          {
            item.centerp.max_x = item.centerp.x + 32;
            item.centerp.min_x = item.centerp.x - 32;
            item.centerp.max_y = item.centerp.y + 32;
            item.centerp.min_y = item.centerp.y - 32;

            basesheetCenters[index] = item.centerp;
          });
function getBasesheet(clicked_x , clicked_y)
            {
              var clicked_sheet = 0;
              $.each(basesheetCenters , function(index , item)
              {
                if  (
                        clicked_x >= item.min_x
                        &&
                        clicked_x <= item.max_x
                        &&
                        clicked_y >= item.min_y
                        &&
                        clicked_y <= item.max_y
                      )
                  {
                    clicked_sheet = sheetengine.basesheets[index]
                  }
              });

              return clicked_sheet;
            }
            var clicked = getBasesheet(pxy.x , pxy.y);

            cursor_obj.move({x:clicked.centerp.x,y:clicked.centerp.y,z:0} , true);
            cursor.canvasChanged();
            sheetengine.calc.calculateAllSheets();
            sheetengine.drawing.drawScene();
}
Apr 14, 2014 at 1:39 AM
This code is absolutly brilliant Rohan!!! Million thanks!!!
Apr 17, 2014 at 9:10 AM
Hi Keten, glad you found it helpful.

I've gotten pretty far with my code that uses SheetEngine, while I've had to put my game on hold because of work commitments, I'm still actively developing it. What kind of game are you making?