Real Time GH Progress

Hi!

Background:

I’m trying to make a point (represented as a sphere) move along a path (represented as a maze with walls as boundaries).
I want this to happen in real-time, meaning I would supply GH initial values (such as the starting point), and the whole thing would start going according to a scripted behavior (e.g “When you reach an intersection, always turn right”, “When you reach the target point, stop”).
** As a side note - later on this will be improved to receive inputs (‘turn right’ etc.) from a peripheral device, but the logic stays the same.

After creating all the necessary geometry, I’ve reached a dead end -
How do you visualize this sort of “animation loop”? Since GH doesn’t support feedback loops, I tried implementing this in script, but (not too surprisingly) all this does is run the script to the end, and showing the final result - without visualizing the entire process and ball advancement, which is my main goal.

Thanks in advance,
Alon

**Edit:
I’m reading up about Kangaroo. It seems to offer the vast physics solutions, but I’m not sure how it tackles the problem I raised.

I wrote a bit about how I develop real-time dynamic systems using GHPython here:

With a very simple example here (of making a persistent/static mutable variable and updating the component at an interval):

EDIT:

Here’s an example of how one might implement a live Kangaroo2 solver in GHPython:

1 Like

Read all of your references - THANKS man!
I’ll go ahead and try it now and come back with conclusions.

1 Like

Hi… i’m late.
In a c# script you can use “external” values (out of main “RunScript” method) to work with iterations.
Code explain it better by itself.

Here a small example by using one point, two vectors and a value (double):
nanogame
nanogame
nanogame.gh (9.3 KB)

At every iteration (each restart of RunScript) the point is moved by the vector, values are kept between iterations.

code:

private void RunScript(bool ON, bool Reset, ref object A, ref object B)
  {
    if(Reset){ // Resetting values if user toggle Reset
      position = new Rhino.Geometry.Point3d(0, 0, 0);
      direction = new Rhino.Geometry.Vector3d(0, 1, 0);
      inertia = new Rhino.Geometry.Vector3d(0, 0, 0);
      rotation = 0;
    }
    // Detecting modifier keys
    string modifier = System.Windows.Forms.Control.ModifierKeys.ToString();
    string case1 = "Shift";
    string case2 = "Control";
    string case3 = "Alt";
    string case4 = "Shift, Control";
    string case5 = "Shift, Alt";
    string case6 = "Shift, Control, Alt";
    bool frictionActive = System.Windows.Forms.Control.IsKeyLocked(System.Windows.Forms.Keys.NumLock);

    if(modifier == case1 || modifier == case4 || modifier == case5 || modifier == case6){
      accellerate();
    }
    if(modifier == case2 || modifier == case4){
      turn("left");
    }
    if(modifier == case3 || modifier == case5){
      turn("right");
    }

    apply_forces();

    if(frictionActive){
      apply_friction();
    }

    A = position;
    B = direction;
    if(ON)this.Component.ExpireSolution(true); // This will make the "RunScript" method restart
  }

  // <Custom additional code> 
  // Objects here will not be changed when "RunScript" restart
  public Rhino.Geometry.Point3d position;
  public Rhino.Geometry.Vector3d direction;
  public Rhino.Geometry.Vector3d inertia;
  public double rotation; //This is rotating momentum

  public void accellerate(){ // Adding direction vector to the inertia vector to simulate thrust... what?
    double val = 0.01;
    inertia += (direction * val);
    Print("acc");
  }
  public void turn(string dir){
    double val = 0.003;
    if(dir == "left"){
      rotation += val;
      Print("left");
    }
    if(dir == "right"){
      rotation -= val;
      Print("right");
    }
  }
  public void apply_forces(){
    direction.Rotate(rotation, Rhino.Geometry.Vector3d.ZAxis);
    position.Transform(Rhino.Geometry.Transform.Translation(inertia));
  }
  public void apply_friction(){
    inertia *= 0.97;
    rotation *= 0.95;
  }

Hope it helps :smiley:

6 Likes

Perfect! Thank you very much!
Combining yours and Anders solution is probably the right way for us to go :slight_smile:

@AndersDeleuran @maje90

Getting pretty desperate on this one…

Any idea on how to get the ball to not collide with the walls?
Tried using Kangaroo but my laptop can’t handle it. Went for Riccardo’s way of implementing the movement.

In the C# script I tried going over all the points dividing the walls, checking for each point whether it’s less than X millimeters away from my sphere.
This was a very costly move that overpowered my computer.

Any ideas?

roller_definition.gh (20.3 KB)

Hi @alon.derfner,

Are you after a real-time physics simulation, with a blind mouse (sphere) moving through the maze by navigating like a blind animal would, probing constantly for collisions with obstacles (i.e walls)?
As mentioned above, this could either be done with a complex script (Python, C#) involving a mover or agent, maybe even using Kangaroo as a physics engine.

A second option, would be to implement a simpler logic:
If the mouse only knows, where it starts, as well as where it can exit the labyrinth (or rather how the exit is defined), and the route through the labyrinth is predefined (like your green polylines above), you can make it run like a train on its track, not having to deal with rigid body collisions (mouse-wall-collisions) and other physics stuff all the time.

At the start, the mouse has to make a decision, wether to move forward or backward on the track. This could be random or an implemented logic. In the case above, it knows that it sits on the start point of the polyline, so there is no going backwards. It can only go forward and moves for instance to the next point of the polyline. You can define the resolution of its movement by dividing each polyline.
At the next steps, it repeats the same movement, until it encounters another perpendicular polyline. Here, at the crossroads, it has to make a decision. Should it go back, left, or right (, or forward). Again this could be random.
Now, if it reaches a dead end, because previously it made the wrong decision, it has to go back.
After some time, it should reach the exit and stop there, since it knows how an exit looks somehow.

When you have achieved this. You can think about, implementing a short-term memory for the mouse. It could for instance remember an x-amount of decisions it made, to avoid repeating mistakes and thus solving the maze quicker. This could be be a great benefit for bigger mazes!
Also, by varying the memory size, you could achieve vastly different goals.

2 Likes

Do you really need a simulation for this?
If you just want to use the “right-hand rule” you can solve it with a couple of offsets and that’s it.

This reply is slightly off topic because it’s user-driven not mouse-driven, but I thought the idea of combining this with Kangaroo was interesting…
A simple C# component detects keypresses in Grasshopper (which, as a by-product, also move the window around…)

Those keypresses are converted into vectors, scaled, and a point load is applied to a point. The point collides with the maze geometry.

And hence we have a bouncy-walled maze!

File attached for reference and C# code.

Kangaroo_Driving.gh (47.9 KB)

4 Likes

Very late night (or early morning) madness here.

This is what I was referring to with offsets:
If we are talking about a maze with all the walls connected to the external perimeter, following the right/left hand rule will always lead to the exit, because somehow the 2 points (start and exit) are already “connected”.

maze2
If you make an offset of all the paths and join the regions together, we’ll get a single closed curve passing near both the 2 points.
Then we can simply shatter that curve to get the 2 full paths, being now the right and left hand rule solutions.

Even better…

By doing the offset “back” to the middle, and many, MANY “cleanings”, we can remove duplicate segments, where we are “passing 2 times on the same path”… so this means removing all the dead ends.
(this method is easy on rhino only if the maze have orthogonal, integer-long paths)
maze
maze_left-right_hand_rule.gh (56.1 KB)

This is a non-iterative, direct solution for a maze with: orthogonal and integer-long paths and with walls connected to external perimeter.

Note: An obvious thing, in a maze with some “island” wall (not connected to the perimeter), if the exit and start point are one inside and the other outside (or vice-versa) you’ll never solve the maze with right-left hand rule.

11 Likes

Wow! Thank you very much, great insights!

This was a huge contribution to my final result. I was missing the final piece in making Kangaroo work, and you had it. Thanks!!

Hi Riccardo (@maje90),

Thanks for sharing this script.

I took the liberty of creating a Python version of it, should anyone find it useful.

nanogame-python.gh (12.9 KB)

5 Likes