Nannou: Is there a function like setup() in Processing? Can I draw during setup?

Created on 7 Feb 2020  路  9Comments  路  Source: nannou-org/nannou

Hi, I am newbie. Please tell me if this is noob question or something wrong asking.

I wanna call frame.clear(BLACK); on just first time.
But I can not find any document for that.
Of cource it may be able to be writtten with simple flag but it is not clean code, isnt it?
Is there a function like setup() in Processing ?

thanks!

Most helpful comment

There are a couple of examples (m_2_5_02, p_2_0_02, p_2_0_03, 4_01_single_particle_trail) that are using the method below for clearing the background colour on the first frame. It's using a flag, which as you say, isn't the most ideal method. But it should be a work around while we look at extending the API to initialise a frame before the first draw call.

fn view(app: &App, m: &Model, frame: &Frame) {
    let draw = app.draw();
    if app.elapsed_frames() == 1 {
        draw.background().color(WHITE);
    }
    draw.to_frame(app, &frame).unwrap();
}

All 9 comments

There are a couple of examples (m_2_5_02, p_2_0_02, p_2_0_03, 4_01_single_particle_trail) that are using the method below for clearing the background colour on the first frame. It's using a flag, which as you say, isn't the most ideal method. But it should be a work around while we look at extending the API to initialise a frame before the first draw call.

fn view(app: &App, m: &Model, frame: &Frame) {
    let draw = app.draw();
    if app.elapsed_frames() == 1 {
        draw.background().color(WHITE);
    }
    draw.to_frame(app, &frame).unwrap();
}

Hi @kawadumax, thanks for opening this!

In nannou the model function is akin to Processing's setup function. That said, unlike Processing, nannou does not currently allow for making any draw calls during this stage. There is not really a good reason for this yet, other than we haven't got around to providing an easy way to do so!

Using @JoshuaBatty's example above is probably the best approach for now. I'll leave this issue open as a reference for future users until we add something a little nicer.

Edit: a slightly safer approach than above would be to use frame.nth() == 0 rather than app.elapsed_frames() == 1 as the former better handles drawing to multiple windows. If you only have one window, this won't affect you.

@JoshuaBatty @mitchmindtree Thank you for answering! I'll write in such a style!

I started a section in the guide to address questions like this one. Can we close this issue (to keep the tracker clean)?

Hi, I'm a university student who is new to rust and nannou and am coming from p5.js background, so sorry for the potentially dump question.

I'm currently using the model as a sort of "setup" to initalize an object/struct I have created, but finding I can't mutate propertise in the object because the model is immutable.

Here's my main.rs:

mod agent;
use nannou::prelude::*;
use crate::agent::Agent;

fn main() {
    nannou::app(model)
        .event(event)
        .simple_window(view)
        .run();
}

fn model(app: &App) -> Model {
    let mut agent = Agent::new();
    agent.position[0] += 1; // Able to mutate.
    Model { agent }
}

fn view(app: &App, model: &Model, frame: Frame) {
    let draw = app.draw();
    draw.background().color(BLACK);
    model.agent.position[0] += 1; // Can't mutate.
    draw.to_frame(app, &frame).unwrap();
}

struct Model {
    agent: Agent,
}

fn event(_app: &App, _model: &mut Model, _event: Event) {
}


And here is the data I would like to manipulate.
agent.rs:

pub struct Agent {
    pub position: Vec<i32>,
}

impl Agent {
    pub fn new() -> Agent {
        Agent {
            position: vec![0, 0],
        }
    }
}

I've tried making the model mutable but this causes an error to do with pointers.

Would it be possible to make the model mutable? or some other way to bring in data for mutation?

Would be nice if we could mutate object properties or use methods to mutate properties.

Hi @wammy19, the nannou API is designed in a manner that aims to encourage separation of the update and view of your model.

  • You can use the update function to update the state of your model.
  • The view function should ideally be reserved for the presentation of your model in its current state.

The idea behind this separation of concerns is to encourage a more modular style of coding.

The update function looks like this:

fn update(app: &App, model: &mut Model, update: Update) {
}

And can be added to your app like this:

    nannou::app(model)
        .event(event)
        .update(update) // Add the update function.
        .simple_window(view)
        .run();

I'd recommend taking a look at some of the nature_of_code examples (perhaps the chp_06_agents examples in particular) as they might help to get an idea of how to separate the update and view stages.


As a side note, there are very occasionally times where you may reasonably want to update some state within your view function, normally for some sort of performance optimisation or caching. In these cases you can consider reaching for Cell, RefCell or Mutex depending on the requirements, though it's best to avoid these if possible as each have their own trade-offs.

Awesome thanks for that! Checking out the nature_of_code examples and can see there was what I'm after. Thank you! :3

Glad I found this, I think a setup method would be great to have

You could make the setup like this :

fn setup(draw: &Draw, frame: &Frame) {
    // things to do once but never clear
    if frame.nth() == 0 {
        draw.background().color(rgb(1.0, 1.0, 1.0));
    }
}

fn view(app: &App, model: &Model, frame: Frame) {
    // Begin drawing
    let draw = app.draw();
    // right after declaration
    setup(&draw, &frame);
    // other drawing stuff
}
Was this page helpful?
0 / 5 - 0 ratings

Related issues

bcbroom picture bcbroom  路  3Comments

JoshuaBatty picture JoshuaBatty  路  4Comments

MacTuitui picture MacTuitui  路  6Comments

dimitre picture dimitre  路  4Comments

jtnimoy picture jtnimoy  路  3Comments