Let's now add some movement to our circle to give it a bit of life.
To do this, we will make use of the ever wonderful sinewave.
These can be generated in nannou by taking the progressed time of the application and feeding it to a sine function.
#![allow(unreachable_code, unused_variables)]use nannou::prelude::*;
fnmain() {
let app: App = unimplemented!();
let sine = app.time.sin();
}
Let's make another one but at half the speed by dividing the time value by two
#![allow(unreachable_code, unused_variables)]use nannou::prelude::*;
fnmain() {
let app: App = unimplemented!();
let slowersine = (app.time / 2.0).sin();
}
Now that we have two functions generating nice, smooth wave movements, let's use them to control our little circle.
If we put these values directly in the ellipse's .x_y()-method we would not see much movement. That's because the sine waves generate values between -1.0 and 1.0 and the coordinates expect a pixel position.
But how wide is our window ? To get a precise idea of this, we can use a handy method called window_rect which is available in the app variable.
#![allow(unreachable_code, unused_variables)]use nannou::prelude::*;
fnmain() {
let app: App = unimplemented!();
let boundary = app.window_rect();
}
This will give us the boundary of the window as a handy Rect. This is a struct that responds to tons of useful methods that we can use to define the minimum and maximum values of our x and y coordinates respectively to constrain the movements of our circle.
Using these values, we can map our sine and slowersine values to ranges of values that are within the boundary of our window. To do this, we will use the map_range function available in nannou.
The map_range function takes 5 arguments: val, in_min, in_max, out_min, out_max. The val here is our sinewaves which has a minimum value of -1.0 and a maximum value of 1.0. For the x-coordinate, we then map it to a range of values between the leftmost point and the rightmost point.
#![allow(unreachable_code, unused_variables)]use nannou::prelude::*;
fnmain() {
let app: App = unimplemented!();
let sine = app.time.sin();
let boundary = app.window_rect();
let x = map_range(sine, -1.0, 1.0, boundary.left(), boundary.right());
}
And then the same for the y value but using the slowersine variable.
#![allow(unreachable_code, unused_variables)]use nannou::prelude::*;
fnmain() {
let app: App = unimplemented!();
let sine = app.time.sin();
let slowersine = (app.time / 2.0).sin();
let boundary = app.window_rect();
let y = map_range(slowersine, -1.0, 1.0, boundary.bottom(), boundary.top());
}
The only thing left to do now is to put this into the arguments of our circle-drawing function.
#![allow(unreachable_code, unused_variables)]use nannou::prelude::*;
fnmain() {
let app: App = unimplemented!();
let draw = app.draw();
let sine = app.time.sin();
let slowersine = (app.time / 2.0).sin();
let boundary = app.window_rect();
let x = map_range(sine, -1.0, 1.0, boundary.left(), boundary.right());
let y = map_range(slowersine, -1.0, 1.0, boundary.bottom(), boundary.top());
draw.ellipse().color(STEELBLUE).x_y(x, y);
}
Your updated view function should now look something like this:
#![allow(dead_code, unreachable_code, unused_variables)]use nannou::prelude::*;
structModel{}
fnmain() {}
fnview(app: &App, _model: &Model, frame: Frame) {
// Prepare to draw.let draw = app.draw();
// Generate sine wave data based on the time of the applet sine = app.time.sin();
let slowersine = (app.time / 2.0).sin();
// Get boundary of the window (to constrain the movements of our circle)let boundary = app.window_rect();
// Map the sine wave functions to ranges between the boundaries of the windowlet x = map_range(sine, -1.0, 1.0, boundary.left(), boundary.right());
let y = map_range(slowersine, -1.0, 1.0, boundary.bottom(), boundary.top());
// Clear the background to purple.
draw.background().color(PLUM);
// Draw a blue ellipse at the x/y coordinates 0.0, 0.0
draw.ellipse().color(STEELBLUE).x_y(x, y);
draw.to_frame(app, &frame).unwrap();
}