Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Question] Need to better understand several ways to setup/animate in Twojs #648

Open
geohuz opened this issue Jul 22, 2022 · 5 comments
Open
Labels

Comments

@geohuz
Copy link

geohuz commented Jul 22, 2022

Several questions to understand the process of initializing/animating objects in twojs

First of all thank you for creating this awesome library! I'm studying the examples to make twojs work in my project, specifically the webgl rendering mode. Here are some of the questions list below, although I can run the examples and make several tweaks here and there, but I believe a better understanding will make my life easier:

  1. The difference between new Two.XXXX and two.makeXXXX, when to choose which.

  2. When to use method two.render()? In home page animation example we dont have to call two.render(), instead we have the following code:

two.bind('update', update);
two.play();

It looks like there are two ways of initialize and control the animation, also in one of the way we don't need to call requestAnimationFrame, it is quite confusing because there is no documentation explains the reason behind the scene. Sorry I'm quite new to the twojs and animation library. But if there are narrative chapters explain the logic then it will become much easier to grasp.

  1. The velocity, It seems that I have to call position.add(velocity) to make the object moving. Still, I don't understand why in other way (two.bind('update', update)) we dont need to use velocity (Just calling two.play())
@jonobr1
Copy link
Owner

jonobr1 commented Jul 23, 2022

I'll get into all of these answers as separate posts. This post will be about

The difference between new Two.XXX and two.makeXXX

two.makeXXX calls new Two.XXX internally. new Two.XXX is the foundational way to create objects that can be rendered in two.js. two.makeXXX also adds the object to the instance's scene. In the case of two.makePath and two.makeCurve it also constructs Two.Anchors for you.

e.g:

// This is...
const a = new Two.Star(x, y, innerRadius, outerRadius, sides);
two.add(a);
// ...equivalent to:
const b = two.makeStar(x, y, innerRadius, outerRadius, sides);

And for Two.Paths and curves:

const x1 = - 10;
const x2 = 0;
const x3 = 10;
const y = 0;

// This is...
const a = new Two.Path([new Two.Anchor(x1, y), new Two.Anchor(x2, y), new Two.Anchor(x3, y)]);
two.add(a);
// ...equivalent to:
const b = two.makePath(x1, y, x2, y, x3, y);

// And for curves
// This is...
const c = new Two.Path([new Two.Anchor(x1, y), new Two.Anchor(x2, y), new Two.Anchor(x3, y)]);
c.curved = true;
two.add(c);
// ...equivalent to
const d = two.makeCurve(x1, y, x2, y, x3, y);

So, essentially the make functions are shorthand methods to construct objects bound to the current instance of Two.js.

@geohuz
Copy link
Author

geohuz commented Jul 23, 2022

@jonobr1 thank you!, can't wait for the new post! BTW, would you mind to put usage of clone into the post? I guess the clone will be memory efficiency?

@jonobr1
Copy link
Owner

jonobr1 commented Jul 25, 2022

When to use method two.render()? In home page animation example we don't have to call two.render(), instead we have the following code:

Kind of like two.makeXXX and new Two.XXX, two.update calls two.render. two.update also calculates time deltas, frame counts, and resizes the canvas (if you've set fullscreen: true on construction). The time deltas and frame counts are passed through as arguments to the update handler like so:

two.bind('update', onUpdate);
let elapsed = 0;
function onUpdate(frameCount, timeDelta) {
  elapsed += timeDelta;
}

If you're not using the out of the box animation, like a physics library or just drawing one frame, then you should use two.render:

const two = new Two({
  width: 300,
  height: 200
}).appendTo(document.body);
const rect = new Two.Rectangle(two.width / 2, two.height / 2, 50, 50);
two.add(rect);
// Nothing will show up on canvas until...
two.render();

@jonobr1
Copy link
Owner

jonobr1 commented Jul 25, 2022

The velocity, It seems that I have to call position.add(velocity) to make the object moving. Still, I don't understand why in other way (two.bind('update', update)) we don't need to use velocity (Just calling two.play())

Velocity isn't a Two.js construct, I just use Two.Vectors to store x and y steps. Regardless of the example, it's necessary to tell Two.js where everything should be at whatever time. So, if you want to make a rectangle move across the screen you can do it several ways:

const two = new Two({
  fullscreen: true,
  autostart: true
}).appendTo(document.body);

const rect = new Two.Rectangle(0, 50, 50, 50);
// First way with two.js functions
two.bind('update', onUpdate);
function onUpdate(frameCount, timeDelta) {
  rect.position.x += 1;
}
// Second way: using your own requestAnimationFrame
loop();
function loop() {
  rect.position.x += 1;
  requestAnimationFrame(loop);
}

No need to use a velocity object to move things across the screen. We just say move 1 pixel every frame. The benefit of using Two.Vector, which is what the position attribute of any two.js shape is, is that you can use its methods to make the code shorter. E.g:

const velocity = new Two.Vector(1, 0);
two.bind('update', onUpdate);

function onUpdate(frameCount, timeDelta) {
  rect.position.add(velocity);
  // Or subtract to move it to the left instead of the right
}

There's not really a "right" or "wrong" way, but many ways to achieve the same thing.

@jonobr1
Copy link
Owner

jonobr1 commented Jul 25, 2022

would you mind to put usage of clone into the post?

Clone is a method to create an object and copy all of its current properties at the time of invocation. Again, it's shorthand. E.g:

const circle = new Two.Circle(two.width / 2, two.height / 2, 50);
const anotherCircle = circle.clone();
const yetAnotherCircle = new Two.Circle();
yetAnotherCircle.position.copy(circle.position);
yetAnotherCircle.radius = circle.radius;

Each of these instances have the same position and radius. It was just one line of code for anotherCircle because of the clone method.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants