

fn main() {
nannou::app(model)
.update(update)
.simple_window(view)
.size(800, 800)
.run();
}
simple_window๊ฐ ๋ด๋ถ์ ์ผ๋กApp::new_window()๋ฅผ ํธ์ถํ๊ณ , ๊ทธWindowBuilder์.size()๋ฅผ ์ด์ด ๋ถ์ด๋ ๋ฐฉ์
fn model(app: &App) -> Model {
app.new_window()
.size(800, 800)
.view(view)
.build()
.unwrap();
Model {}
}
fn model()์App๊ฐ์ฒด๋ฅผ ์ ๋ฌ๋ฐ์ผ๋ฏ๋ก ์ด ์์์ ์ ์ฐฝ์ ๋ง๋๋ ๋ฐฉ์
์ด ๊ฒฝ์ฐmain()์๋nannou::app(model).update(update).run();๋ง ์์ฑ.
model()์์ ์ํ๋ ๋งํผ new_window() ํธ์ถ.view()ํจ์, ๋ค๋ฅธ ํฌ๊ธฐ, ๋ค๋ฅธ ์ด๋ฆ์ ์ง์ ๊ฐ๋ฅ.Model๊ณผ ํจ๊ป ์ฐฝ ID๋ฅผ ์ ์ฅํด๋๊ณ ์ดํ์ ํน์ ์ฐฝ์ ์ฐพ์์ update()๋ view()์์ ํ์ฉ.model()์์ ์ฌ์ฉํ ์ ์๋ ์ฐฝ ์ค์ ๋ฉ์๋ (WindowBuilder)
app.new_window()๊ฐ ๋ฐํํ๋ ๊ฑดnannou::app::window::Builderํ์ ์ธ๋ฐ, ์ฌ๊ธฐ์ ์ฌ๋ฌ ๋ฉ์๋๋ฅผ ๋ถ์ผ ์ ์์.
https://docs.rs/nannou/latest/nannou/window/struct.Builder.html
| ์ฃผ์ ๋ฉ์๋ | ์ค๋ช |
|---|---|
.size(w, h) | ์ฐฝ์ ํฌ๊ธฐ๋ฅผ ์ง์ (ํฝ์ ๋จ์) |
.title("string") | ์ฐฝ ์ ๋ชฉ ์ค์ |
.resizable(bool) | ์ฐฝ ํฌ๊ธฐ ์กฐ์ ๊ฐ๋ฅ ์ฌ๋ถ |
.fullscreen() | ์ ์ฒด ํ๋ฉด ๋ชจ๋ |
.decorations(bool) | ์ฐฝ์ ํ์ดํ๋ฐ, ๋ซ๊ธฐ ๋ฒํผ ๋ฑ ํ์ ์ฌ๋ถ |
.always_on_top(bool) | ์ฐฝ์ ํญ์ ์์ ๋๊ธฐ |
.position(x, y) | ์ฐฝ์ ์ด๊ธฐ ์์น ์ง์ (ํ๋ฉด ์ขํ) |
.view(view_fn) | ๋ ๋๋งํ view ํจ์ ๋ฑ๋ก |
.event(event_fn) | ํค๋ณด๋, ๋ง์ฐ์ค ์ด๋ฒคํธ ํธ๋ค๋ฌ ๋ฑ๋ก |
.key_pressed(key_fn) | ํน์ ํค ์ ๋ ฅ ์ฒ๋ฆฌ |
.mouse_pressed(mouse_fn) | ๋ง์ฐ์ค ์ ๋ ฅ ์ฒ๋ฆฌ |
.raw_event(raw_event_fn) | ๋ ์ ์์ค ์ด๋ฒคํธ ์ฒ๋ฆฌ |
.update(update_fn) | ์ด ์ฐฝ ์ ์ฉ update ํจ์ ์ง์ (์ ์ญ update์ ๋ณ๋๋ก) |
.vsync(bool) | V-Sync ํ์ฑ/๋นํ์ฑ |
.samples(n) | MSAA ์ํ ์ (์ํฐ์จ๋ฆฌ์ด์ฑ ํ์ง) |
.srgb(bool) | sRGB ์๊ณต๊ฐ ํ์ฑํ |
.transparent(bool) | ์ฐฝ ๋ฐฐ๊ฒฝ์ ํฌ๋ช ํ๊ฒ ๋ง๋ค๊ธฐ |
use nannou::prelude::*;
use nannou::rand::prelude::*;
fn main() {
nannou::app(model).update(update).event(event).run();
}
struct Model {
win_sub: WindowId,
current_color: Rgb8,
current_color_name: String,
}
// nannou color ๋ชจ๋์ ๋ชจ๋ ์์ ์์๋ค (์ด 147๊ฐ ์ค ์ผ๋ถ)
const COLORS: &[(Rgb8, &str)] = &[
(ALICEBLUE, "ALICEBLUE"),
(ANTIQUEWHITE, "ANTIQUEWHITE"),
(AQUA, "AQUA"),
(AQUAMARINE, "AQUAMARINE"),
(AZURE, "AZURE"),
(BEIGE, "BEIGE"),
(BISQUE, "BISQUE"),
(WHITESMOKE, "WHITESMOKE"),
(YELLOW, "YELLOW"),
(YELLOWGREEN, "YELLOWGREEN"),
];
fn model(app: &App) -> Model {
// ์ฒซ ๋ฒ์งธ ์ฐฝ (๋ฉ์ธ)
let _win_main = app
.new_window()
.size(600, 400)
.title("Main Window")
.view(view_main)
.build()
.unwrap();
// ๋ ๋ฒ์งธ ์ฐฝ (์๋ธ)
let win_sub = app
.new_window()
.size(400, 400)
.title("Sub Window")
.view(view_sub)
.build()
.unwrap();
Model {
win_sub,
current_color: WHITE,
current_color_name: "WHITE".to_string(),
}
}
fn update(_app: &App, _model: &mut Model, _update: Update) {}
fn event(_app: &App, model: &mut Model, event: Event) {
match event {
Event::WindowEvent { id, simple: Some(MousePressed(_button)), .. } => {
// sub ์ฐฝ์ ํด๋ฆญํ์ ๋๋ง ์์ ๋ณ๊ฒฝ
if id == model.win_sub {
let mut rng = thread_rng();
let (color, color_name) = COLORS.choose(&mut rng).unwrap();
model.current_color = *color;
model.current_color_name = color_name.to_string();
}
}
_ => {}
}
}
fn view_main(app: &App, model: &Model, frame: Frame) {
let draw = app.draw();
draw.background().color(model.current_color);
draw.text(&model.current_color_name).color(BLACK).font_size(24).x_y(0.0, 0.0);
draw.to_frame(app, &frame).unwrap();
}
fn view_sub(app: &App, _model: &Model, frame: Frame) {
let draw = app.draw();
draw.background().color(GRAY);
draw.text("CLICK TO CHANGE THE COLOR").color(BLACK).font_size(18).x_y(0.0, 0.0);
draw.to_frame(app, &frame).unwrap();
}
event() ํจ์์ ๋์ ๊ณผ์ fn event(_app: &App, model: &mut Model, event: Event)
_app: ์ฑ ์ฐธ์กฐ (์ธ๋์ค์ฝ์ด๋ก ์ฌ์ฉํ์ง ์์์ ํ์)model: ๋ชจ๋ธ์ ๊ฐ๋ณ ์ฐธ์กฐ (๊ฐ์ ๋ณ๊ฒฝํ ์ ์์)event: ๋ฐ์ํ ์ด๋ฒคํธ ์ ๋ณดmatch ๋ฌธ๋ฒmatch event {
// ํจํด๋ค...
}
match๋ Rust์ ํจํด ๋งค์นญ ๋ฌธ๋ฒ์
๋๋ค. event์ ๊ฐ์ ๋ฐ๋ผ ๋ค๋ฅธ ์ฝ๋๋ฅผ ์คํํฉ๋๋ค. switch๋ฌธ๊ณผ ๋น์ทํ์ง๋ง ๋ ๊ฐ๋ ฅํฉ๋๋ค.WindowEventEvent::WindowEvent { id, simple: Some(MousePressed(_button)), .. } => {
// ์คํ๋ ์ฝ๋
}
์ด ํจํด์ ๋ถํดํด๋ณด๊ฒ ์ต๋๋ค:
Event::WindowEvent
Event๋ ์ด๊ฑฐํ(enum)์ด๊ณ , WindowEvent๋ ๊ทธ ์ค ํ๋์ ๋ณํ์
๋๋ค{ id, simple: Some(MousePressed(_button)), .. }
์ด๋ ๊ตฌ์กฐ์ฒด ํจํด ๋งค์นญ์
๋๋ค:
id: ์ด๋ฒคํธ๊ฐ ๋ฐ์ํ ์ฐฝ์ ID๋ฅผ id ๋ณ์์ ์ถ์ถํฉ๋๋ค
simple: Some(MousePressed(_button)):
simple์ ๊ฐ๋จํ ์ด๋ฒคํธ ์ ๋ณด๋ฅผ ๋ด๋ ํ๋์
๋๋คSome(...)์ Option ํ์
์ ๊ฐ์ด ์์์ ์๋ฏธํฉ๋๋คMousePressed(_button)์ ๋ง์ฐ์ค๊ฐ ๋๋ ธ์์ ์๋ฏธํฉ๋๋ค_button์ ์ด๋ค ๋ง์ฐ์ค ๋ฒํผ์ธ์ง๋ ๋ฌด์ํฉ๋๋ค (์ธ๋์ค์ฝ์ด)..: ๋๋จธ์ง ํ๋๋ค์ ๋ฌด์ํฉ๋๋คif id == model.win_sub {
let mut rng = thread_rng();
let (color, color_name) = COLORS.choose(&mut rng).unwrap();
model.current_color = *color;
model.current_color_name = color_name.to_string();
}
if id == model.win_sub: ํด๋ฆญ๋ ์ฐฝ์ด ์๋ธ ์ฐฝ์ธ์ง ํ์ธํฉ๋๋คlet mut rng = thread_rng(): ๋์ ์์ฑ๊ธฐ๋ฅผ ๋ง๋ญ๋๋คCOLORS.choose(&mut rng).unwrap(): ์์ ๋ฐฐ์ด์์ ๋๋คํ๊ฒ ํ๋๋ฅผ ์ ํํฉ๋๋คlet (color, color_name) = ...: ํํ ๊ตฌ์กฐ๋ถํด๋ก ์์๊ณผ ์ด๋ฆ์ ๊ฐ๊ฐ ๋ณ์์ ํ ๋นํฉ๋๋ค*color: ์์ ๊ฐ์ ์ญ์ฐธ์กฐํด์ ๋ณต์ฌํฉ๋๋คcolor_name.to_string(): ๋ฌธ์์ด ์ฌ๋ผ์ด์ค๋ฅผ String์ผ๋ก ๋ณํํฉ๋๋ค_ => {}
_๋ ์์ผ๋์นด๋ ํจํด์ผ๋ก "๋๋จธ์ง ๋ชจ๋ ๊ฒฝ์ฐ"๋ฅผ ์๋ฏธํฉ๋๋ค{}๋ ๋น ๋ธ๋ก์ผ๋ก ์๋ฌด๊ฒ๋ ํ์ง ์์ต๋๋คWindowEvent์ ๋ง์ฐ์ค ํด๋ฆญ์ด ์๋ ๋ค๋ฅธ ๋ชจ๋ ์ด๋ฒคํธ๋ ๋ฌด์ํฉ๋๋คevent ํจ์๊ฐ ํธ์ถ๋ฉ๋๋คmatch๋ฌธ์ผ๋ก ์ด๋ฒคํธ ํ์
์ ํ์ธํฉ๋๋ค์ด๋ ๊ฒ ํด์ ์๋ธ ์ฐฝ์ ํด๋ฆญํ ๋๋ง ๋ฉ์ธ ์ฐฝ์ ์์์ด ๋ณ๊ฒฝ๋ฉ๋๋ค.
use nannou::prelude::*;
struct Model {
main_window: WindowId,
control_window: WindowId,
target_sides: usize, // ํ์ฌ ๋ค๊ฐํ ๋ณ ๊ฐ์
}
// ๋ฒํผ ์ ์
struct Button {
rect: Rect,
label: &'static str,
}
impl Button {
fn draw(&self, draw: &Draw) {
draw.rect()
.xy(self.rect.xy())
.wh(self.rect.wh())
.color(STEELBLUE);
draw.text(self.label)
.xy(self.rect.xy())
.color(WHITE)
.font_size(18);
}
fn contains(&self, point: Point2) -> bool {
self.rect.contains(point)
}
}
fn main() {
nannou::app(model).update(update).run();
}
fn model(app: &App) -> Model {
let main_window = app
.new_window()
.title("Main Window")
.size(600, 600)
.view(view_main)
.build()
.unwrap();
let control_window = app
.new_window()
.title("Control Window")
.size(300, 200)
.view(view_control)
.event(event_control)
.build()
.unwrap();
Model {
main_window,
control_window,
target_sides: 6,
}
}
fn update(_app: &App, _model: &mut Model, _update: Update) {
// ์ง๊ธ์ ์ ๋๋ฉ์ด์
์์ โ ์๋ฌด๊ฒ๋ ์ ํจ
}
// === ๋ฉ์ธ ์๋์ฐ ===
fn view_main(app: &App, model: &Model, frame: Frame) {
if frame.window_id() == model.main_window {
let draw = app.draw();
draw.background().color(rgba(0.2, 0.2, 0.2, 1.0));
// ๋ฉ์ธ ๋ํ ๊ทธ๋ฆฌ๊ธฐ
let polygon = (0..model.target_sides).map(|i| {
let angle = i as f32 / model.target_sides as f32 * TAU;
pt2(angle.cos() * 200.0, angle.sin() * 200.0)
});
draw.polygon().points(polygon).color(DARKTURQUOISE);
// ๋ค๊ฐํ ๋ณ ๊ฐ์๋ฅผ ์ค์์ ํ์
draw.text(&model.target_sides.to_string())
.x_y(0.0, 0.0)
.color(WHITE)
.font_size(64);
draw.to_frame(app, &frame).unwrap();
}
}
// === ์ปจํธ๋กค ์๋์ฐ ===
fn view_control(app: &App, _model: &Model, frame: Frame) {
let draw = app.draw();
draw.background().color(BLACK);
// ๋ฒํผ ๋ ๊ฐ
let inc_button = Button {
rect: Rect::from_xy_wh(pt2(-80.0, 0.0), vec2(100.0, 50.0)),
label: "+",
};
let dec_button = Button {
rect: Rect::from_xy_wh(pt2(80.0, 0.0), vec2(100.0, 50.0)),
label: "-",
};
inc_button.draw(&draw);
dec_button.draw(&draw);
draw.to_frame(app, &frame).unwrap();
}
fn event_control(app: &App, model: &mut Model, event: WindowEvent) {
// ํ์ฌ ์ด๋ฒคํธ๊ฐ ์ด๋ ์๋์ฐ์์ ๋ฐ์ํ๋์ง ํ์ธ
if app.window_id() == model.control_window {
match event {
WindowEvent::MousePressed(_button) => {
let pos = app.mouse.position();
let inc_button = Button {
rect: Rect::from_xy_wh(pt2(-80.0, 0.0), vec2(100.0, 50.0)),
label: "+",
};
let dec_button = Button {
rect: Rect::from_xy_wh(pt2(80.0, 0.0), vec2(100.0, 50.0)),
label: "-",
};
if inc_button.contains(pos) {
model.target_sides += 1;
} else if dec_button.contains(pos) {
if model.target_sides > 3 {
model.target_sides -= 1;
}
}
}
_ => {}
}
}
}
์๋ณด์นด๋
Sample
Important
Highlighting
๋น์
์ ํฉ์
purple
hot pink
yellow
์ด๊ตฌ์
orange
green
blue