My first code

edited February 2014 in Questions about Code

Hello :)

I made some simple shapes (only quadrilaterals and ellipses)

I aligned them using the input of the mouse, in order to have them follow the mouse

Now I would like to have certain shapes delayed, so that they are following the movements of the mouse from a couple of seconds ago.

How can I code this kind of delay?

Thanks in advance!

Aidan :)

Answers

  • This is what I've done so far:

    void setup() {
      size(1000, 1000);
      noSmooth();
      background(255, 255, 255);
      time = 0;
    }
    
    void draw() {
    
    
        fill(0, 0, 0);
      quad(mouseX-2000, mouseY-2000, mouseX+2000, mouseY-2000, mouseX+2000, mouseY+2000, mouseX-2000, mouseY+2000);
    
    
          fill(255, 255, 255);
       ellipse(mouseX, mouseY, 2002, 2002);
    
    
     fill(0, 0, 0);
      quad(mouseX-708, mouseY-708, mouseX+708, mouseY-708, mouseX+708, mouseY+708, mouseX-708, mouseY+708);
    
       fill(255, 255, 255);
       ellipse(mouseX, mouseY, 1416, 1416);
    
     fill(0, 0, 0);
      quad(mouseX-500, mouseY-500, mouseX+500, mouseY-500, mouseX+500, mouseY+500, mouseX-500, mouseY+500);
    
      fill(255, 255, 255);
      ellipse(mouseX, mouseY, 1000, 1000);
    
    fill(0, 0, 0);
      quad(mouseX-353, mouseY-353, mouseX+353, mouseY-353, mouseX+353, mouseY+353, mouseX-353, mouseY+353);
    
      fill(255, 255, 255);
      ellipse(mouseX, mouseY, 707, 707);
    
      fill(0, 0, 0);
      quad(mouseX-250, mouseY-250, mouseX+250, mouseY-250, mouseX+250, mouseY+250, mouseX-250, mouseY+250);
    
      fill(255, 255, 255);
      ellipse(mouseX, mouseY, 500, 500);
    
    fill(0, 0, 0);
      quad(mouseX-177, mouseY-177, mouseX+177, mouseY-177, mouseX+177, mouseY+177, mouseX-177, mouseY+177);
    
      fill(255, 255, 255);
      ellipse(mouseX, mouseY, 352, 352);
    
    fill(0, 0, 0);
      quad(mouseX-125, mouseY-125, mouseX+125, mouseY-125, mouseX+125, mouseY+125, mouseX-125, mouseY+125);
    
      fill(255, 255, 255);
      ellipse(mouseX, mouseY, 250, 250);
    
    fill(0, 0, 0);
      quad(mouseX-88, mouseY-88, mouseX+88, mouseY-88, mouseX+88, mouseY+88, mouseX-88, mouseY+88);
    
       fill(255, 255, 255);
      ellipse(mouseX, mouseY, 175, 175);
    
    fill(0, 0, 0);
      quad(mouseX-62, mouseY-62, mouseX+62, mouseY-62, mouseX+62, mouseY+62, mouseX-62, mouseY+62);
    
      fill(255, 255, 255);
      ellipse(mouseX, mouseY, 124, 124);
    
    fill(0, 0, 0);
      quad(mouseX-44, mouseY-44, mouseX+44, mouseY-44, mouseX+44, mouseY+44, mouseX-44, mouseY+44);
    
      fill(255, 255, 255);
      ellipse(mouseX, mouseY, 86, 86);
    
    fill(0, 0, 0);
      quad(mouseX-30, mouseY-30, mouseX+30, mouseY-30, mouseX+30, mouseY+30, mouseX-30, mouseY+30);
    
      fill(255, 255, 255);
      ellipse(mouseX, mouseY, 58, 58);
    
    fill(0, 0, 0);
      quad(mouseX-20, mouseY-20, mouseX+20, mouseY-20, mouseX+20, mouseY+20, mouseX-20, mouseY+20);
    
       fill(255, 255, 255);
      ellipse(mouseX, mouseY, 38, 38);
    
     fill(0, 0, 0);
      quad(mouseX-13, mouseY-13, mouseX+13, mouseY-13, mouseX+13, mouseY+13, mouseX-13, mouseY+13);
    
      fill(255, 255, 255);
      ellipse(mouseX, mouseY, 24, 24);
    
    fill(0, 0, 0);
      quad(mouseX-8, mouseY-8, mouseX+8, mouseY-8, mouseX+8, mouseY+8, mouseX-8, mouseY+8);
    
        fill(255, 255, 255);
      ellipse(mouseX, mouseY, 16, 16);
    
    fill(0, 0, 0);
      quad(mouseX-5, mouseY-5, mouseX+5, mouseY-5, mouseX+5, mouseY+5, mouseX-5, mouseY+5);
    
      fill(255, 255, 255);
      ellipse(mouseX, mouseY, 9, 9);
    
    fill(0, 0, 0);
      quad(mouseX-3, mouseY-3, mouseX+3, mouseY-3, mouseX+3, mouseY+3, mouseX-3, mouseY+3);
    
        fill(255, 255, 255);
      ellipse(mouseX, mouseY, 4, 4);
    
    fill(0, 0, 0);
      quad(mouseX-1, mouseY-1, mouseX+1, mouseY-1, mouseX+1, mouseY+1, mouseX-1, mouseY+1);
    
    
        }
    
  • very cool! How did you figure out all the numbers in your calls to quad and ellipse? You could probably make this a lot easier to read and write with a for loop.

  • In case you have no experience in using Arrays, Classes, loops or linear interpolation this could be tough. The following code is an example how it could be achieved, "play" with it to see how it works:

    SomeShape[] shapes;
    
    void setup() {
    
        size(1000, 1000);
        noStroke();
        noSmooth();
    
        int[] radii = new int[] { 3, 5, 8, 13, 20, 30, 44, 62, 88, 125, 177, 250, 353, 500, 708, 2000 };
        shapes = new SomeShape[radii.length];
        for(int n = 0; n < shapes.length; n++)
            shapes[n] = new SomeShape(width / 2, height / 2, radii[n]);
    
    }
    
    void draw() {
    
        background(255);
    
        shapes[0].posX = mouseX;
        shapes[0].posY = mouseY;
        for(int n = shapes.length - 1; n > 0; n--) {
            shapes[n].posX = lerp(shapes[n].posX, shapes[n - 1].posX, 0.5);
            shapes[n].posY = lerp(shapes[n].posY, shapes[n - 1].posY, 0.5);
        }
    
        for(int n = shapes.length - 1; n > -1; n--)
            shapes[n].render();
    
    }
    
    class SomeShape {
    
        float posX;
        float posY;
        float radius;
    
        SomeShape(float posX, float posY, float radius) {
            this.posX = posX;
            this.posY = posY;
            this.radius = radius;
        }
    
        void render() {
            fill(0);
            rect(posX - radius, posY - radius, radius * 2, radius * 2);
            fill(255);
            ellipse(posX, posY, radius * 2, radius * 2);
        }
    
    }
    
  • you can use rect instead of quad if you're making a rectangle, it's a bit easier. If you use rectMode(RADIUS) and ellipseMode(RADIUS), then the size of the rect and the circle can have the same radius. Makes it way easier!

    You can draw the same thing like this:

    void setup() {
      size(500, 500);
    }
    
    void draw() {
      background(255);
      noStroke();
      ellipseMode(RADIUS);
      rectMode(RADIUS);
      for (float r = 2.0*max(width,height); r >= 1.0; r /= sqrt(2.0)) {
        fill(255);
        rect(mouseX, mouseY, r, r);
        fill(0);    
        ellipse(mouseX, mouseY, r, r);
      }
    }
    

    having something trailing the mouse is a little harder, depending on how you want to do it.

  • edited February 2014

    ah. Here's a pretty simple way to do a trailing draw. Basically what you have to remember is that you need to store the coordinates of where the mouse is right now, and you need to hold onto that information until you're ready to use it. So, in this example, we have a red dot and then a blue dot that is drawn some 10 frames later, based on where the mouse was. So we need to have 10 frames of history at any time.

    ArrayList<PVector> history; // this will store the history of where the mouse was
    
    void setup() {
      size(500, 500);
      history = new ArrayList<PVector>();
      noStroke();
      ellipseMode(RADIUS);
    }
    
    void draw() {
      background(255);
    
      // record where the mouse is now.  This always gets added onto the
      // end of the list.
      history.add(new PVector(mouseX, mouseY));
    
      if (history.size() > 9) {
        // if we have enough history...
    
        // take the item from the beginning of the list; the oldest item.
        PVector old = history.get(0);
    
        // draw a blue circle there
        fill(#1874CD);
        ellipse(old.x, old.y, 20, 20);
    
        // remove this item off the list, since we're done with it now.
        history.remove(0);
      }
    
      // draw a red circle where the mouse is now
      fill(#B22222);
      ellipse(mouseX, mouseY, 20, 20);
    }
    
  • edited February 2014

    @jordanorelli: The new operator is slow (peformance wise), using an array with a given amount of entries (like in my example above) is fast. Using remove(0) on an ArrayList (or any other data structure with an underlying Array) is always a bad idea. All entries above 0 have to be shiftet one index down, which means ~18 array accesses. Use a LinkedList instead, it has no underlying Array and it's get(index) is therefore really slow (use getFirst() instead), but random insertion/removal is super fast, as it will only update one link/reference per insertion/removal.

  • yeah, it makes sense to use a LinkedList instead because the backing store for an ArrayList is ... an array.

    umm, the descriptions of "this is fast" and "this is slow" are kinda... misleading, though. get(0) and getFirst() will be very similar on a linked list, since you never have to traverse beyond the first element of the list, which you have a reference to to begin with. "Random insertion is fast" isn't strictly true; any operation you do using an index on a linked list will still require traversing the list up to that index, so inserting to the middle of a large linked list isn't going to be fast if all you have is an index. Random insertion to a linked list is only fast if the elements of the list are exposed, but in Java's LinkedList, only the contents of the list elements are exposed, so I don't see how you would ever be in a situation where you could perform a list insertion in the way you've stated.

    Same thing with LinkedList:

    import java.util.LinkedList;
    
    LinkedList<PVector> history; // this will store the history of where the mouse was
    
    void setup() {
      size(500, 500);
      history = new LinkedList<PVector>();
      noStroke();
      ellipseMode(RADIUS);
    }
    
    void draw() {
      background(255);
    
      // record where the mouse is now.  This always gets added onto the
      // end of the list.
      history.add(new PVector(mouseX, mouseY));
    
      if (history.size() > 9) {
        // if we have enough history...
    
        // take the item from the beginning of the list; the oldest item.
        PVector old = history.getFirst();
    
        // draw a blue circle there
        fill(#1874CD);
        ellipse(old.x, old.y, 20, 20);
    
        // remove this item off the list, since we're done with it now.
        history.remove(0);
      }
    
      // draw a red circle where the mouse is now
      fill(#B22222);
      ellipse(mouseX, mouseY, 20, 20);
    }
    
  • edited February 2014

    get(0) will attempt to loop the list's entries to find the specified index, therefore it will create an Iterator and object creation is still costly. getFirst() will simply return the first element (it's reference is already saved in the list).

    You can simply insert/remove elements while iterating a list with an Iterator. In case of entity/particle/object/item/etc. lists this is the most common case.

    This code is better.

  • edited February 2014

    What about a version using just a regular array? And no extra PVector re-instantiations along the way?! :P

    Well, I've got an old online trailing example which I've tweaked from @9egenwind back then:

    http://studio.processingtogether.com/sp/pad/export/ro.9GTDpA6dp4tH1/latest
    http://forum.processing.org/one/topic/newbie-question-understandig-problems-with-arrays

    So I've taken the same approach and tweak yours as well! :D
    I guess performance is above par! ;;)

    http://studio.processingtogether.com/sp/pad/export/ro.90vdKMfkiO$zf/latest

    /** 
     * Follow My Lead Closely! (v3.02)
     * by  jordanorelli (2014/Feb)
     * mod GoToLoop
     *
     * forum.processing.org/two/discussion/2846/my-first-code
     *
     * studio.processingtogether.com/sp/pad/export/ro.90vdKMfkiO$zf/latest
     */
    
    static final int DIM = 050, GAP = 10;
    final PVector[] hist = new PVector[GAP];
    
    static final color LEADER_C = #B22222, CHASER_C = #1874CD;
    
    int idx;
    
    void setup() {
      size(600, 600);
      frameRate(60);
      smooth(4);
      noStroke();
      noCursor();
      ellipseMode(CENTER);
    
      mouseX = mouseY = width<<1;
    
      for (int i = GAP; i-- != 0; hist[i] = new PVector(mouseX, mouseY));
    }
    
    void draw() {
      background(-1);
    
      hist[idx].set(mouseX, mouseY);
    
      final PVector old = hist[idx = (idx + 1) % GAP];
    
      fill(CHASER_C);
      ellipse(old.x, old.y, DIM, DIM);
    
      fill(LEADER_C);
      ellipse(mouseX, mouseY, DIM, DIM);
    }
    
  • edited February 2014

    @GoToLoop: You were faster again! :))

    I know the lerp()'s are a bit slow, but the following code also utilizes arrays and avoids new calls in the draw loop:

    PVector[] snake;
    
    void setup() {
        size(500, 500);
        noStroke();
        ellipseMode(RADIUS);
        snake = new PVector[10];
        for(int n = 0; n < snake.length; n++)
            snake[n] = new PVector(width / 2, height / 2);
    }
    
    void draw() {
        background(255);
        snake[0].set(mouseX, mouseY);
        for(int n = snake.length - 1; n > 0; n--) {
            snake[n].lerp(snake[n - 1], 0.15);
            //snake[n].set(snake[n - 1]); // Alternately
            fill(lerpColor(#1874cd, #b22222, 1 - (float)n / snake.length));
            ellipse(snake[n].x, snake[n].y, 20, 20);
        }
        fill(#b22222);
        ellipse(snake[0].x, snake[0].y, 20, 20);
    }
    
  • edited February 2014

    Wow! It's a different twist! And very similar to the old Chase-Shadow Circles I had:

    http://studio.processingtogether.com/sp/pad/export/ro.9GTDpA6dp4tH1/latest

    Prominent differences is that yours right-shifts the array, while mine left-shifts it.
    And yours use lerp() for color effects, while mine use alpha + different sizes.

  • edited February 2014

    It's advisable to place every fixed configuration in setup(), so the big draw() "loop" has less things to worry about and be faster:

    /** 
     * Circles Inside Rectangles (v3.01)
     * by  agfd (2014/Feb)
     * mod jordanorelli & GoToLoop
     *
     * forum.processing.org/two/discussion/2846/my-first-code
     */
    
    float dim, step;
    
    void setup() {
      size(800, 800);
      smooth(4);
      noStroke();
      noCursor();
    
      ellipseMode(RADIUS);
      rectMode(RADIUS);
    
      dim = max(width, height) * 2.0;
      step = sqrt(2.0);
    }
    
    void draw() {
      background(-1);
    
      for (float r = dim; r > 1.0; r /= step) {
        fill(-1);
        rect(mouseX, mouseY, r, r);
    
        fill(0);    
        ellipse(mouseX, mouseY, r, r);
      }
    }
    
  • @Poersch get(0) won't create any iterator, it just creates one reference and does a bunch of pointer following: http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/LinkedList.java#LinkedList.entry(int)

    it just goes through a few checks but eventually returns a reference to the same thing that getFirst does, so the difference is effectively nothing.

    anyway, I kinda feel like this sort of premature optimization only serves to make the material less approachable for a beginner.

  • edited February 2014

    Sorry, I'm currently not at home. In any case, using getFirst() instead of get(0) has nothing to do with optimization. It's simply more readable/elegant maybe even easier to understand.

  • edited February 2014

    @jordanorelli , nice source code resource on Java API! \m/

    However, I've got to concur w/ @Poersch :
    1 of the 1st things I've learned about Java is that LinkedList is the slowest class to access elements thru' direct index!!! b-(
    Just compare an ArrayList vs LinkedList loop using get() to check what I mean! ;))

    While getFirst() or element() are merely -> return header.next.element;, get() is a loop as deep long as the index requested!
    Although it seems a lower index like get(0) the looping search ends up shorter after all! :-$

    Anyway, I kinda feel like this sort of premature optimization only serves to make the material less approachable for a beginner.

    Somewhat that's true. But it's also important to spread adequate knowledge. 8-X

    using getFirst() instead of get(0) has nothing to do with optimization.

    Well, IMO, if some1 intends to use index to access data within a structure, LinkedList shouldn't be his 1st choice by far!!! (~~)

  • edited February 2014

    @jordanorelli: Sorry, I was wrong get(0) will only take ~4 times as long as getFirst() but it's still an overhead and not as clean as getFirst(), imo.

    @jordanorelli, @GoToLoop: Optimization can be premature, but that highly depends on how frequent your code is running. One reason the most AAA games are not written in Java isn't it bad performance, it's the habit of most Java coders to write highly unoptimized code. Have a look at Minecraft's source code for example, you'll find instructions like this.getBlockIcon(block).getIconName().equals("grass_top") (in the render loop, that will be executed for every block) instead of block == Block.grass. Minecraft is full of those bad code examples. Many of it's players need mods like Optifine, which replaces parts of Minecraft's rendering code, in order to be able to play it on the low graphics settings. With a little bit of optimization you could at least double the framerate. I don't say, you should optimize everything, but if there's a way to double or triple the speed of your code with almost the same amount or even fewer instructions, then do it. (%)

  • @Poersch 4 times as long? how are you measuring that? My yardstick is reading the code ;)

  • edited February 2014

    @jordanorelli: Just count the opcodes and multiply them by how many CPU cycles they need in average. ;)

    Anyhow, maybe we should stop spamming this thread with our tech talk, agfd hasn't even responded to one of our answers and for a beginning programmer this could easily be too much information. At the end of the day, I hope we gave him a nice repertoire of possible solutions to his problem.

Sign In or Register to comment.