# Merging tiles into paths

**URL:** <https://discourse.processing.org/t/merging-tiles-into-paths/44670>\
**Category:** Project Guidance\
**Created:** [July 1, 2024, 11:07am UTC](https://discourse.processing.org/t/merging-tiles-into-paths/44670 "2024-07-01T11:07:25Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![eightohnine](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/eightohnine/32/19793_2.png) [@eightohnine](https://discourse.processing.org/u/eightohnine)\
**Post date:** [July 1, 2024, 11:07am UTC](https://discourse.processing.org/t/merging-tiles-into-paths/44670/1 "2024-07-01T11:07:25Z")

</div>

Hi all, I’d like to pick your brains for a sketch I’m tackling.

I’m building off of this:

![tiles](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/5/4/54f0b89ce0b24660a376e90a0a89a35f0c59a75c.png)

It’s a basic tile placement generator that for this example uses two tile types – straight and 90° curve – to fill the canvas so everything fits neatly together. (For transparency: I’m using a vector program to quickly illustrate these visuals.)

Mind you, creating this “carpet of tiles” is not the issue. There’s some neat Wave Function Collapse tutorials I’m following to achieve this. But I want to take this further now.

After filling the canvas with the tiles, I’d like to identify continuous paths through the tiles, e.g. like in the following image highlighted in magenta. Ultimately I’m trying to have agents move along the paths.

![path](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/d/e/dead21b269b00785b8adb7ba83642cc332d2038f.png)

Here is where my questions arise and where I’d like to see if my initial thinking is sound enough:

How do I go from building a carpet using individual tiles to creating continuous paths independent of these tiles?

My best idea for now is having the tiles include points that contain “movement instructions” for any agent that’s following the path.

![movementInstr](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/4/0/40985cdb36def359852c6f8b2a537ffcb6ddf506.png)

So every time an agent enters a tile and hits such a point (shown in orange), they receive some instruction, e.g. “move straight to the right” or “curve down 90°” or “curve right 90°”. I’m guessing this could be achieved by passing velocity and direction PVectors into the agent.

Another approach would be to somehow attach the agent onto the lines and curves in the tiles and have them move using some kind of path-following algorithm. (Though I wouldn’t even know where to start with this…)

Yet another foundational hurdle is that all Wave Function Collapse tutorials I’ve seen operate using pngs, which are great for generating static visuals, but useless for what I’m trying to build. So I’m also wondering if I need to tackle the whole tile generation part from a different angle as well?

For now I’m interested in a sanity-check on these considerations, before I start investing too much time into potential dead ends.

Thanks!

---

<div class="post-metadata">

**Author:** ![glv](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/glv/32/18785_2.png) [@glv](https://discourse.processing.org/u/glv)\
**Post date:** [July 1, 2024, 9:21pm UTC](https://discourse.processing.org/t/merging-tiles-into-paths/44670/2 "2024-07-01T21:21:58Z")

</div>

Hello @eightohnine,

This inspired me to write some related code to generating a path.

This may be something in here of interest in your research:

> [@Shape generator help (Armin Hofmann's 'rubber band' shape generator)](https://discourse.processing.org/t/shape-generator-help-armin-hofmanns-rubber-band-shape-generator/33190/1):
>
> Hi I’m trying to create a Hofmann’esque shape generator based on a grid of circles: I have the basic structure of the grid done, but I’m totally stuck on where to go from here? How do I make this into a combined shape? Here’s my code so far: color bg = #FFFFFF; color fc = #000000; void setup() { size(800, 800); frameRate(2); } void draw() { background(bg); noStroke(); float tilesX = 4; float tilesY = tilesX; float gap = 16; float tileW = …

> [@10 print chr$(205.5+rnd(1)); : goto 10](https://discourse.processing.org/t/10-print-chr-205-5-rnd-1-goto-10/15483):
>
> 10 PRINT CHR$(205.5+RND(1)); : GOTO 10 Can this be done in Processing? grin@jeremydouglass

The last one is generating mazes and inspired me to solve a maze by looking ahead to see what was in the way and making a decision based on that. A lot of interesting and related stuff may come up in a maze related search.

In one example of code I simply looked ahead to see if there was a pixel color change. In others I kept track of nodes on a grid (where I have been) in an array and checked array to see if something was ahead.

> [@eightohnine](#):
>
> I’m guessing this could be achieved by passing velocity and direction PVectors into the agent.

Thinking about it already I am, green eggs and ham!

Pick a random direction from your current direction and look ahead and draw your \*curves! It should be simple enough to check nodes in the path; the nodes being stored in an array. Since these are tiles the nodes can represent each tile.

\*According to one source _a line is a curve without any curvature_. `:)`

I do not have any algorithms or approaches to suggest for this as I generally code from scratch to engage my brain and then may look at other approaches.

Have fun!

`:)`

---

<div class="post-metadata">

**Author:** ![eightohnine](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/eightohnine/32/19793_2.png) [@eightohnine](https://discourse.processing.org/u/eightohnine)\
**Post date:** [July 1, 2024, 10:06pm UTC](https://discourse.processing.org/t/merging-tiles-into-paths/44670/3 "2024-07-01T22:06:14Z")

</div>

Oh wow, those are some jam-packed threads! I’ll have a sit down and sift through all this new inspiraiton. Thanks!

---

<div class="post-metadata">

**Author:** ![glv](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/glv/32/18785_2.png) [@glv](https://discourse.processing.org/u/glv)\
**Post date:** [July 1, 2024, 11:10pm UTC](https://discourse.processing.org/t/merging-tiles-into-paths/44670/4 "2024-07-01T23:10:25Z")

</div>

Hello again!

> [@eightohnine](#):
>
> So every time an agent enters a tile and hits such a point (shown in orange), they receive some instruction, e.g. “move straight to the right” or “curve down 90°” or “curve right 90°”. I’m guessing this could be achieved by passing velocity and direction PVectors into the agent.

This certainly did inspire me!

I wrote some minimal code using PVectors to do this with small lines progressing.  
It it only goes left, right or forward but does not look ahead yet for obstacles.

I can share if you are receptive to it.

`:)`

---

<div class="post-metadata">

**Author:** ![eightohnine](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/eightohnine/32/19793_2.png) [@eightohnine](https://discourse.processing.org/u/eightohnine)\
**Post date:** [July 2, 2024, 8:31am UTC](https://discourse.processing.org/t/merging-tiles-into-paths/44670/5 "2024-07-02T08:31:04Z")

</div>

Sure, I’m always open to new approaches and directions.

---

<div class="post-metadata">

**Author:** ![glv](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/glv/32/18785_2.png) [@glv](https://discourse.processing.org/u/glv)\
**Post date:** [July 2, 2024, 10:59am UTC](https://discourse.processing.org/t/merging-tiles-into-paths/44670/6 "2024-07-02T10:59:37Z")

</div>

Hello again!

A quick and minimal example I cooked up:

```auto
/*
 Project: Random path with Vectors
 Author: GLV
 Date: 2024-07-01
 Version: 1.0.0
*/

//println((int)random(4));
//println(choice(4)); //Similar to above in source code

PVector v, v0, v1, v2;

void setup()
  {
  size(400, 400);
  v0 = new PVector(20, 0);
  v1 = new PVector(0, 0);
  v2 = new PVector(20, 0);
  
  frameRate(10);
  }
  
void draw()
  {
  translate(width/2, height/2);  
  
  strokeWeight(2);
  line (v1.x, v1.y, v2.x, v2.y); 
  
  int ch = choice(3)-1; // 0 to 2 becomes -1, 0, 1
  println(ch);
  
  v1 = v2.copy();
  // Look ahead not implemented. Not yet...
  v0.rotate(ch*TAU/4);
  v2 = v1.copy().add(v0);
  v2.set(round(v2.x), round(v2.y)); // get rid of rounding errors!
  println (v2);
  }

```

![image](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/8/b/8b670d1241049468dfd97e468c6cf15aac3e752c.png)

They are still overlapping in this version.

I leave the fun part with you!

References:

- [PVector / Processing.org](https://processing.org/tutorials/pvector)
- [PVector / Reference / Processing.org](https://processing.org/reference/PVector.html)

`:)`

---

<div class="post-metadata">

**Author:** ![Chrisir](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/chrisir/32/45_2.png) [@Chrisir](https://discourse.processing.org/u/Chrisir)\
**Post date:** [July 3, 2024, 11:07am UTC](https://discourse.processing.org/t/merging-tiles-into-paths/44670/7 "2024-07-03T11:07:13Z")

</div>

The player has a position p.

Once he enters a tile the tile manages the change of p.

To do this it has an ArrayList of the points of its path (a line or different types of circles)

When leaving the tile the next tile takes over.

You need

- a Tile class containing the image and the  
Arraylist and
- an animation manager within the tile and
- a next tile manager in the main sketch

---

<div class="post-metadata">

**Author:** ![eightohnine](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/eightohnine/32/19793_2.png) [@eightohnine](https://discourse.processing.org/u/eightohnine)\
**Post date:** [July 4, 2024, 8:41am UTC](https://discourse.processing.org/t/merging-tiles-into-paths/44670/8 "2024-07-04T08:41:22Z")

</div>

Fun part, indeed!

I’m currently trying to inject different steering forces into the agent, so that it can not only go straight, but also describe nice 90° curve segments. Might sent an update when I sort things out.

---

<div class="post-metadata">

**Author:** ![eightohnine](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/eightohnine/32/19793_2.png) [@eightohnine](https://discourse.processing.org/u/eightohnine)\
**Post date:** [July 4, 2024, 8:53am UTC](https://discourse.processing.org/t/merging-tiles-into-paths/44670/9 "2024-07-04T08:53:05Z")

</div>

That’s about the gist of what I was able to come up with until now.

I believe I’ve got the basics down when it comes to creating classes and objects that stand for themselves. But as soon as it is multiple classes, some managing the behaviour of others, I tend to get my brain all knotted up. Will just have to approach this step by step…

---

<div class="post-metadata">

**Author:** ![glv](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/glv/32/18785_2.png) [@glv](https://discourse.processing.org/u/glv)\
**Post date:** [July 4, 2024, 11:07am UTC](https://discourse.processing.org/t/merging-tiles-into-paths/44670/10 "2024-07-04T11:07:10Z")

</div>

> [@eightohnine](#):
>
> Will just have to approach this step by step…

That is the best way!

What is your approach to steering and adding steps (without obstacle avoidance)?

The PVector approach I shared was just an initial inspiration. It was in my head in the moment and I had to release it.

I don’t need to see code.  
Just a description to understand it.

`:)`

---

<div class="post-metadata">

**Author:** ![Chrisir](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/chrisir/32/45_2.png) [@Chrisir](https://discourse.processing.org/u/Chrisir)\
**Post date:** [July 4, 2024, 6:33pm UTC](https://discourse.processing.org/t/merging-tiles-into-paths/44670/11 "2024-07-04T18:33:53Z")

</div>

> [@eightohnine](#):
>
> managing the behaviour of others

here is a quick demo for animate a player going through tiles

```auto

// We have a grid of tiles with different types / paths, e.g. - | or \ or / path.
// The goal is to animate a player through the grid.

// https://discourse.processing.org/t/merging-tiles-into-paths/44670

// Some player data :
// player gets animated by the tile class.
PVector playerPos = new PVector(0, 0);

// the current % of the animation of the player within a tile
float playerAmt; // animation

// the current Tile of the player (= index for grid)
int playerFieldIndexX=0;
int playerFieldIndexY=0;

// grid
Tile [][] grid = new Tile[10][10];

// ----------------------------------------------------------------------------------------

void setup() {
  size( 1300, 900 );

  // the grid
  for (int x=0; x<10; x++) {
    for (int y=0; y<10; y++) {
      // rect( x * 20, y * 20, 10,10);
      grid[x][y] = new Tile (x*50+55, y*50+55);
    }
  }

  // !!!!!!!!!!!!!!!!!!!!!!!!
  // type 0 is the default for every Tile which is ------->>>>

  grid[3][0].typeTile = 1; // going \

  grid[3][1].typeTile = 2; // going |
  grid[3][2].typeTile = 2;

  grid[3][3].typeTile = 2; // going |
  grid[3][4].typeTile = 2;
  grid[3][5].typeTile = 2;

  grid[3][5].typeTile = 3; // going \

  // set start and end PVector from type for all Tiles
  for (int x=0; x<10; x++) {
    for (int y=0; y<10; y++) {
      grid[x][y].setPVectorFromType();
    }
  }

  // set player position within grid (the Tile the player starts on)
  playerFieldIndexX = 0;
  playerFieldIndexY = 0;

  // get PVector from Tile start and set player
  playerPos = grid[playerFieldIndexX][playerFieldIndexY].getPosOfTile();
  //
} // setup

void draw() {
  background(0);

  // show grid
  for (int x=0; x<10; x++) {
    for (int y=0; y<10; y++) {
      grid[x][y].display();
    }
  }

  // show player
  fill(255, 0, 0);
  circle(playerPos.x, playerPos.y, 9);

  // when the current field of the player is ok
  if (playerFieldIndexX<10&&playerFieldIndexY<10) {
    // animate player
    grid[playerFieldIndexX][playerFieldIndexY].animatePlayer();
  } else {
    // game over - when we left the grid
    fill(255, 0, 0);
    text("game over", 600, 200);
  }
} // draw

// -------------------------------------------------------------------------------------------------------------

void keyPressed() {
  // Eval key

  if (key==' ') {
    // Space bar: reset player

    // reset
    playerAmt=0;

    // set player position within grid (the Tile the player starts on)
    playerFieldIndexX = 0;
    playerFieldIndexY = 0;

    // get PVector from Tile start and set player
    playerPos = grid[playerFieldIndexX][playerFieldIndexY].getPosOfTile();
  }//if
  //
}//func

//===========================================================================================================

class Tile {

  // position of Tile = upper left corner
  PVector posTile;

  // type = for example path going on right ----- or | or / or \
  int typeTile = 0;

  // the start and end of the path the player moves on within the Tile
  PVector start, end;

  // this value is 0, 1 or -1 and tells us where the next Tile is relative to the current Tile.
  // Do we have to move the player right or down, or left or top?
  // The number gets added to the index of the grid (playerFieldIndexX,playerFieldIndexY) to reach the next neigbouring Tile.
  // This depends on the path: when the path is horizontal, the next Tile is right, when the path is vertical, the next Tile is down etc.
  int modifyIndexX, modifyIndexY;

  // ----------------------

  // constr
  Tile (float x, float y) {
    posTile=new PVector(x, y);
    // setPVectorFromType();
  }//constr

  // ----------------------

  void setPVectorFromType() {
    // set start and end PVector from type

    // Also set modifyIndexX and modifyIndexY because depending on the path the next Tile is either right or down or .....

    //if (random(1)<0.2) type=1;

    switch(typeTile) {
    case 0:
      start = new PVector( posTile.x, posTile.y + (50/2) );
      end = new PVector( posTile.x+50, posTile.y + (50/2) );
      modifyIndexX=1; // RIGHT
      modifyIndexY=0;
      break;
    case 1:
      start = new PVector( posTile.x, posTile.y + (50/2));
      end = new PVector( posTile.x+50/2, posTile.y + (50) );
      modifyIndexX=0;
      modifyIndexY=1; // DOWN
      break;
    case 2:
      start = new PVector( posTile.x + (50/2), posTile.y);
      end = new PVector( posTile.x+50/2, posTile.y + (50) );
      modifyIndexX=0;
      modifyIndexY=1; // DOWN
      break;
    case 3:
      start = new PVector( posTile.x + (50/2), posTile.y);
      end = new PVector( posTile.x+50, posTile.y + (50/2) );
      modifyIndexX=1; // RIGHT
      modifyIndexY=0;
      break;
    }
  }

  void display() {
    // display the Tile

    // show Tile as rect
    // noFill();
    fill(50);
    stroke(111);
    rect( posTile.x, posTile.y,
      50, 50);

    // show type of Tile / optional
    fill(255);
    text(typeTile, posTile.x+22-8-8, posTile.y+14);

    // show the path
    stroke(0, 111, 0);
    strokeWeight(4);
    line(start.x, start.y,
      end.x, end.y);
    strokeWeight(1);
  }//method

  void animatePlayer() {
    // 1. animate player on path
    playerPos.x = lerp (start.x, end.x, playerAmt); // see lerp() in the reference
    playerPos.y = lerp (start.y, end.y, playerAmt);
    // a) show playerAmt
    fill(255);
    text(playerAmt, 600, 200);

    // 2. increase % of animation
    playerAmt+=0.01; // this is the speed of the player

    // 3. when animation is over
    if (playerAmt >= 1 ) {
      // start all over
      // reset %
      playerAmt=0;

      // move to next Tile by adding modifyIndexX and modifyIndexY
      playerFieldIndexX+=modifyIndexX;
      playerFieldIndexY+=modifyIndexY;
    }// if
  }// method

  PVector getPosOfTile() {
    // return start PVector
    return
      new PVector(start.x, start.y );
  }//method
  //
}//class
//

```

---

<div class="post-metadata">

**Author:** ![eightohnine](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/eightohnine/32/19793_2.png) [@eightohnine](https://discourse.processing.org/u/eightohnine)\
**Post date:** [July 4, 2024, 10:38pm UTC](https://discourse.processing.org/t/merging-tiles-into-paths/44670/12 "2024-07-04T22:38:13Z")

</div>

So, this is just about on little manoeuvre… a 90° turn.

Step 1 – an object (orange) moves with a certain velocity (black arrow).  
 ![01](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/6/3/635c5f9374ab3474f04e1f21763b7845872156b4.png)

Step 2 – at a specific trigger (e.g. the object enters a new tile) the object picks up new movement instructions. In this case, a steering force (red arrow) pointing towards a center point. The velocity and steering force put the object on a circular orbit around this center point.  
 ![02](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/f/9/f93ada401d4f1c9ee7a9dea803495c655ffd6c8b.png)

Step 3 – the object moves for a quarter of the orbit. (No idea yet how I’ll check this. I kinda want to do this without angles and angular velocities. Not entirely sure why, as I know this is more complex. But I believe it will keep the movement more flexible and powerful for some ideas down the line…)  
 ![03](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/f/b/fb432b1ec0b58644192570d31235c1488698beb6.png)

Step 4 – after the completed turn, scrap the steering force and continue on a straight line with the velocity only (or pick up the next turning instructions).  
 ![04](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/b/9/b96ae24b04fa04337e4c64e7974c7617c54f919a.png)

This is all theory for now. I kinda didn’t get my brain into coding mode the past day. But I like to sketch these things out beforehand. Obs for me it’s all quick and dirty scribbles, for here I cleaned them up a little.

---

<div class="post-metadata">

**Author:** ![Chrisir](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/chrisir/32/45_2.png) [@Chrisir](https://discourse.processing.org/u/Chrisir)\
**Post date:** [July 4, 2024, 11:07pm UTC](https://discourse.processing.org/t/merging-tiles-into-paths/44670/13 "2024-07-04T23:07:48Z")

</div>

> [@eightohnine](#):
>
> This is all theory for now. I kinda didn’t get my brain into coding mode the p

So how do you like my sketch

---

<div class="post-metadata">

**Author:** ![glv](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/glv/32/18785_2.png) [@glv](https://discourse.processing.org/u/glv)\
**Post date:** [July 5, 2024, 1:02am UTC](https://discourse.processing.org/t/merging-tiles-into-paths/44670/14 "2024-07-05T01:02:46Z")

</div>

Hello @eightohnine ,

A minimal example:

```auto
/*
 Project: Path with 90° corners
 Author: GLV
 Date: 2024-07-04
 Version: 1.0.0
*/

PVector v, v0, v1, v2;

void setup()
  {
  size(400, 400);
  v0 = new PVector(1, 0);  
  v1 = new PVector(0, 0); // Center of sketch
  v2 = new PVector(1, 0);
  background(255);
  }
  
boolean rot;
int rotStart;
int dir = 1;
  
void draw()
  {
  translate(width/2, height/2);  
  
  strokeWeight(2);
  
  v2 = v1.copy().add(v0);
  line (v1.x, v1.y, v2.x, v2.y); 
 
  int step = 30; //rotates for 30 steps
  if (rot)
    {  
    v0.rotate((TAU/4)/step); //rotates 90° (TAU/4) over 30 steps
    
    rotStart++;
    if (rotStart>=step)
      {
      rot=false;
      rotStart=0;
      }
    println(v2.x, v2.y);
    
    //v1 = v2.copy(); //Interesting error!
    }
  v1 = v2.copy();  
  }  
  
void mousePressed()
  {
  rot=true;
  }

```

My version (not posted) had more control:

![image](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/7/e/7e41b36d06502895f9fda88289b8710e3c7f5328.png)

Have fun!

Resource:  
[The Nature of Code](https://noc-processing-archive.netlify.app/)

`:)`

---

<div class="post-metadata">

**Author:** ![eightohnine](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/eightohnine/32/19793_2.png) [@eightohnine](https://discourse.processing.org/u/eightohnine)\
**Post date:** [July 5, 2024, 9:07am UTC](https://discourse.processing.org/t/merging-tiles-into-paths/44670/15 "2024-07-05T09:07:21Z")

</div>

Totally appreciate your effort. Though I honestly ran the sketch just once and then realized that I wasn’t in the mindset to dissect and understand the code any further. As soon as that happens I’ll get back to you. Thanks!

---

<div class="post-metadata">

**Author:** ![glv](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/glv/32/18785_2.png) [@glv](https://discourse.processing.org/u/glv)\
**Post date:** [July 5, 2024, 1:53pm UTC](https://discourse.processing.org/t/merging-tiles-into-paths/44670/16 "2024-07-05T13:53:23Z")

</div>

> [@eightohnine](#):
>
> I kinda want to do this without angles and angular velocities. Not entirely sure why, as I know this is more complex.

I did have angles in the last example.  
It was easier for me for a first pass at this.

If you have fixed curves for the bends you could store the values in an array and step through them.

For many of my projects the final version may look nothing like initial attempts.  
I am just sharing ideas with you and it is up to you to scrutinize.

Keep at it! Once step at a time…

`:)`

---

<div class="post-metadata">

**Author:** ![quark](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/quark/32/26_2.png) [@quark](https://discourse.processing.org/u/quark)\
**Post date:** [July 6, 2024, 1:04pm UTC](https://discourse.processing.org/t/merging-tiles-into-paths/44670/17 "2024-07-06T13:04:33Z")

</div>

I have read this discussion with interest and it sounds and challenging project to implement. The ideas I present here are just that ultimately you must follow your own programming path but I hope you find my ideas interesting if not useful.

I have decided to implement something very similar but using Javascript. I created the sketch below to try some ideas out and share them with you. The each cell contains a path and that path is described by a pair of parametric equations x=f(t) and y=g(t). The variable t can have any value in the range \ge0 and \le1 but 0 defines the path start and 1 the path end, values between represent some point on the path.

Having a single `Cell` class that can be used for any path is not efficient because you are forever having to check the path type and direction and the code becomes messy and unmanageable . The solution I used is a simple class hierarchy which can easily be extended to include other paths.

Anyway this video shows the output from the sketch. If you have questions about the code then just ask away 😄

[![](https://img.youtube.com/vi/3NNvYxuXADo/hqdefault.jpg "Cell Paths") ](https://www.youtube.com/watch?v=3NNvYxuXADo&t=20s)

```auto

ArrayList<Cell> cells = new ArrayList<Cell>();
ArrayList<String> types = new ArrayList<String>();

float t = 0f, dt = 0.005f;

public void settings() {
  size(500, 320);
}

public void setup() {
  float s = 80, x = 20, y = 100, dx = 120, dy = 120;
  textAlign(CENTER, CENTER);
  textSize(20);
  cells.add(getCell("NS", x, y, s));
  cells.add(getCell("EW", x + dx, y, s));
  cells.add(getCell("NE", x, y + dy, s));
  cells.add(getCell("ES", x + dx, y + dy, s));
  cells.add(getCell("SW", x + 2 * dx, y + dy, s));
  cells.add(getCell("WN", x + 3 * dx, y + dy, s));
}

public void draw() {
  background(192);
  t += dt;
  if (t < 0) {
    t=0;
    dt *= -1;
  } else if (t > 1) {
    t = 1;
    dt *= -1;
  }
  if (t > 1) t = 0;
  noStroke();
  fill(255, 255, 0);
  for (Cell c : cells) {
    c.draw();
    float[] p = c.getPos(t);
    ellipse(c.x + p[0], c.y + p[1], 10, 10);
  }
  // Travel direction and parametric details
  rect(240, 30, t*200, 30);
  noFill();
  stroke(0);
  strokeWeight(2);
  rect(240, 30, 200, 30);
  fill(0);
  text(nf(t, 0, 3), 240, 30, 200, 24);
  text("Direction:", 20, 0, 200, 24);
  text(dt >= 0 ? "Forward" : "Reverse", 220, 0, 200, 24);
  text("Parametric value (t):", 20, 30, 200, 24);

  // Display NS, EW , NE etc
  fill(0);
  for (int i = 0; i < types.size(); i++) {
    Cell c = cells.get(i);
    text(types.get(i), c.x, c.y - 32, 36, 30);
  }
}

public void exit() {
  super.exit();
}

/**
 * This is the key method for creating the tiles with the correct path.
 *
 * @param type two letter code indicating positive travel direction
 * @param x x coordinate for top-left corner for the tile
 * @param y y coordinate for top-left corner for the tile
 * @param size cell size
 * @return the tile or null if the type cannot be found
 */
public Cell getCell(String type, float x, float y, float size) {
  switch(type.toUpperCase()) {
  case "NS":
    types.add("NS");
    return new CellLine(x, y, size, new float[] {0.5f, 0, 0.5f, 1});
  case "EW":
    types.add("EW");
    return new CellLine(x, y, size, new float[] {1, 0.5f, 0, 0.5f});
  case "NE":
    types.add("NE");
    return new CellArc(x, y, size, new float[] {1, 0, PI, 0.5f * PI});
  case "ES":
    types.add("ES");
    return new CellArc(x, y, size, new float[] {1, 1, 1.5f * PI, PI});
  case "SW":
    types.add("SW");
    return new CellArc(x, y, size, new float[] {0, 1, 2 * PI, 1.5f * PI});
  case "WN":
    types.add("WN");
    return new CellArc(x, y, size, new float[] {0, 0, 0.5f * PI, 0});
  }
  return null;
}

/**
 * The base class for all cells. All useful cells are created
 * from sub-classes.
 *
 */
public class Cell {
  public float x, y, size, t;
  public float pathLength;

  public Cell(float x, float y, float size) {
    this.x = x;
    this.y = y;
    this.size = size;
  }

  public void drawCellBorder() {
    rectMode(CORNER);
    noFill();
    strokeWeight(1);
    stroke(255, 255, 0);
    rect(0, 0, size, size);
  }

  public void draw() {
  }
  public float[] getPos(float t) {
    return new float[] {0, 0};
  }
  public float getPathLength() {
    return pathLength;
  }
}

/** Straight path cell */
public class CellLine extends Cell {
  public float tx0, tx1, ty0, ty1;

  public CellLine(float x, float y, float size, float[] path_0_1) {
    super(x, y, size);
    this.tx0 = path_0_1[0];
    this.ty0 = path_0_1[1];
    this.tx1 = path_0_1[2];
    this.ty1 = path_0_1[3];
    this.pathLength = this.size;
  }

  public float[] getPos(float t) {
    t = constrain(t, 0, 1);
    float x = map(t, 0, 1, tx0, tx1) * size;
    float y = map(t, 0, 1, ty0, ty1) * size;
    return new float[] {x, y};
  }

  public void draw() {
    push();
    translate(x, y);
    drawCellBorder();
    stroke(0);
    line(tx0 * size, ty0 * size, tx1 * size, ty1 * size);
    pop();
  }
}

/** Arc path cell */
public class CellArc extends Cell {
  public float ta0, ta1;
  public float orgX, orgY;

  public CellArc(float x, float y, float size, float[] path_0_1) {
    super(x, y, size);
    this.orgX = path_0_1[0];
    this.orgY = path_0_1[1];
    this.ta0 = path_0_1[2];
    this.ta1 = path_0_1[3];
    this.pathLength = this.size * PI /4;
  }

  public float[] getPos(float t) {
    t = constrain(t, 0.0f, 1.0f);
    float ang = map(t, 0.0f, 1f, ta0, ta1);
    float x = (orgX + 0.5f * cos(ang)) * size;
    float y = (orgY + 0.5f * sin(ang)) * size;
    return new float[] {x, y};
  }

  public void draw() {
    push();
    translate(x, y);
    drawCellBorder();
    ellipseMode(CENTER);
    stroke(0);
    arc(orgX * size, orgY * size, size, size,
      min(ta0, ta1), max(ta0, ta1));
    pop();
  }
}

```

---

<div class="post-metadata">

**Author:** ![eightohnine](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/eightohnine/32/19793_2.png) [@eightohnine](https://discourse.processing.org/u/eightohnine)\
**Post date:** [July 10, 2024, 10:56am UTC](https://discourse.processing.org/t/merging-tiles-into-paths/44670/18 "2024-07-10T10:56:10Z")

</div>

Back at it…

I appreciate the effort you put in with commenting all relevant parts of your sketch, makes it super easy to make sense of it all. Overall a clean solution and great foundation to expand step by step with more capabilities.

One observation…

The sketch decouples Player position management (via the 2D matrix) and the Player animation. It makes for a clean structure, a neat sequential execution. I feel though, that I would want more flexibility to the movement of the Player and thus need to bring position and animation back together again.

Especially the fact that it’s the animation – `if (playerAmt >= 1 )` – that defines when the Player moves at a new tile, makes it somewhat rigid.  
I’d like to have the Player move along and be able to at any point in time pick up a new movement instruction.

Thanks for your for thought!

---

<div class="post-metadata">

**Author:** ![eightohnine](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/eightohnine/32/19793_2.png) [@eightohnine](https://discourse.processing.org/u/eightohnine)\
**Post date:** [July 10, 2024, 12:45pm UTC](https://discourse.processing.org/t/merging-tiles-into-paths/44670/19 "2024-07-10T12:45:53Z")

</div>

@glv

> [@glv](#):
>
> For many of my projects the final version may look nothing like initial attempts.  
> I am just sharing ideas with you and it is up to you to scrutinize.

Very true. The sketches I end up with rarely are exactly what I envisioned at the start. If an unexpected but interesting outcome happens, I’m all for going with the flow.

Though I DO need to watch out that I don’t suddenly get interested by a totally new thing halfway through a sketch and then abandon it.

---

<div class="post-metadata">

**Author:** ![eightohnine](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/eightohnine/32/19793_2.png) [@eightohnine](https://discourse.processing.org/u/eightohnine)\
**Post date:** [July 10, 2024, 12:55pm UTC](https://discourse.processing.org/t/merging-tiles-into-paths/44670/20 "2024-07-10T12:55:04Z")

</div>

@quark

Oh, this looks neat! And very robust.

Although I will say that extending classes is not yet a concept that I’ve understood well.

I’ll have to dissect this one for sure.  
Correct me if I’m wrong, but for now I understand this as follos.

There’s ONE parent class – Cell – that handles basic parameters like loc and size.  
From this you create SIX sub-classes.  
TWO handle the straight line movement,  
FOUR handle the curved movement.

Fun!

[Next page](https://discourse.processing.org/t/merging-tiles-into-paths/44670.md?page=2)
