
Nannou ํ๋ ์์ํฌ์์ ์ฌ์ฉ์๊ฐ ์ง์ ์ ์ํ๋ ๊ตฌ์กฐ์ฒด๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ํ๋ฅผ ์ ์ฅํ๋ ์ญํ ์ ํ๋ฉฐ, ๊ด๋ก์ ์ผ๋ก Model์ด๋ผ๋ ์ด๋ฆ์ ์์ฃผ ์ฌ์ฉํฉ๋๋ค. ์ด๋ Nannou์ ๊ณต์ ๋ฌธ์์ ์์ ์ฝ๋์์ ํํ ๋ณด์ด๋ ํจํด์ผ๋ก, ์ฝ๋์ ๊ฐ๋ ์ฑ๊ณผ ์ผ๊ด์ฑ์ ์ํด ์ฑํ๋ ์คํ์ผ์ ๋๋ค. ํ์ง๋ง ์ด๋ ๊ฐ์ ์ ์ธ ๊ท์น์ด ์๋๋ผ ๋จ์ํ ๊ด๋ก์ผ ๋ฟ์ด๋ฏ๋ก,
AppState,State,MyModel๋ฑ ๋ค๋ฅธ ์ด๋ฆ์ ์์ ๋กญ๊ฒ ์ฌ์ฉํ ์ ์์ต๋๋ค. ์ค์ํ ๊ฒ์ ํด๋น ๊ตฌ์กฐ์ฒด๊ฐ Nannou์ ํจ์๋ค(model,update,view๋ฑ)์์ ์ผ๊ด๋๊ฒ ์ฐธ์กฐ๋๊ณ , ํ์ ์ด ๋ง์์ผ ํ๋ค๋ ์ ์ ๋๋ค.
Model ๊ตฌ์กฐ์ฒด๋ Nannou ์ ํ๋ฆฌ์ผ์ด์
์ ํต์ฌ ์ํ ๊ด๋ฆฌ์ ์ญํ ์ ํฉ๋๋ค. ์ด๋ Rust์ struct ํค์๋๋ก ์ ์๋๋ฉฐ, ์ ํ๋ฆฌ์ผ์ด์
์ ๋ชจ๋ ๋ณ์, ๋ฐ์ดํฐ, ๋๋ ์ํ(์: ์์น, ์์, ์ ๋๋ฉ์ด์
๋ณ์ ๋ฑ)๋ฅผ ์ ์ฅํฉ๋๋ค. Nannou์ ์ด๋ฒคํธ ๋ฃจํ(์: nannou::app(model).update(update).run())์์ ์ด ๊ตฌ์กฐ์ฒด๊ฐ ์ค์ฌ์ด ๋๋ฉฐ, ๋ค์๊ณผ ๊ฐ์ ๋ฐฉ์์ผ๋ก ์ฌ์ฉ๋ฉ๋๋ค:
model ํจ์):model ํจ์์์ Model ์ธ์คํด์ค๋ฅผ ์์ฑํ๊ณ ์ด๊ธฐ ์ํ๋ฅผ ์ค์ ํฉ๋๋ค. ์ด ํจ์๋ App ์ฐธ์กฐ๋ฅผ ๋งค๊ฐ๋ณ์๋ก ๋ฐ์ ์ฐฝ ์์ฑ์ด๋ ์ด๊ธฐ ์ค์ ์ ์ํํ ์ ์์ต๋๋ค.
update ํจ์):update ํจ์์์ Model์ ํ๋๋ฅผ ์์ ํฉ๋๋ค. Update ๊ตฌ์กฐ์ฒด๋ฅผ ํตํด ์๊ฐ ๊ธฐ๋ฐ ๋ก์ง(์: ์ ๋๋ฉ์ด์
)์ ๊ตฌํํ ์ ์์ต๋๋ค.
view ํจ์):view ํจ์์์ Model์ ์ํ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ๊ทธ๋ํฝ์ ๊ทธ๋ฆฝ๋๋ค. Draw ๊ตฌ์กฐ์ฒด๋ฅผ ์ฌ์ฉํด ๋ํ์ด๋ ํ
์คํธ๋ฅผ ๋ ๋๋งํฉ๋๋ค.
Model์ ์์น์ ์์์ ์ฌ์ฉํด ์์ ๊ทธ๋ฆผ.event ๋ฑ):ํ์ ์ event ํจ์์์ ์
๋ ฅ ์ด๋ฒคํธ(ํค๋ณด๋, ๋ง์ฐ์ค)๋ฅผ ์ฒ๋ฆฌํ๋ฉฐ Model์ ์
๋ฐ์ดํธํ ์ ์์ต๋๋ค.
Model์ ํ๋๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ์๊ตฌ์ฌํญ์ ๋ฐ๋ผ ์์ ๋กญ๊ฒ ์ค๊ณํ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด, ๊ฐ๋จํ 2D ์ ๋๋ฉ์ด์ ์ฑ์ด๋ผ๋ฉด ๋ฒกํฐ(Vec2), ์์(Rgb), ๋๋ ์นด์ดํฐ ๊ฐ์ ํ๋๋ฅผ ํฌํจํ ์ ์์ต๋๋ค. ์๋๋ ๊ธฐ๋ณธ์ ์ธ Model ์์ ์ ๋๋ค:
use nannou::prelude::*;
struct Model {
position: Vec2, // ์์น ์ํ
velocity: Vec2, // ์๋ ์ํ
color: Rgb, // ์์ ์ํ
}
fn model(app: &App) -> Model {
let _window = app.new_window().size(512, 512).view(view).build().unwrap();
Model {
position: vec2(0.0, 0.0),
velocity: vec2(1.0, 1.0),
color: rgb(1.0, 0.5, 0.0),
}
}
fn update(_app: &App, model: &mut Model, _update: Update) {
model.position += model.velocity; // ์ํ ์
๋ฐ์ดํธ
}
fn view(app: &App, model: &Model, frame: Frame) {
let draw = app.draw();
draw.background().color(BLACK);
draw.ellipse()
.xy(model.position)
.radius(20.0)
.color(model.color);
draw.to_frame(app, &frame).unwrap();
}
์ด ๊ตฌ์กฐ์ฒด๋ Nannou์ ๋ผ์ดํ์ฌ์ดํด๊ณผ ๋ฐ์ ํ๊ฒ ์ฐ๊ฒฐ๋์ด ์์ด, ์ํ๊ฐ ์์์ ์ผ๋ก ์ ์ง๋๋ฉด์ ์ ํ๋ฆฌ์ผ์ด์ ์ด ๋์ํฉ๋๋ค.
Nannou์ ๊ธฐ๋ณธ ํจํด์ ํ๋์ ์ฃผ์ ์ํ ๊ตฌ์กฐ์ฒด(์: Model)๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด์ง๋ง, ์ ํ๋ฆฌ์ผ์ด์
์ด ๋ณต์กํด์ง๋ฉด ์ฌ๋ฌ ๊ฐ์ ์ฌ์ฉ์ ์ ์ ๊ตฌ์กฐ์ฒด๋ฅผ ํจ๊ป ์ฌ์ฉํ ์ ์์ต๋๋ค. ์ด๋ ์ฝ๋์ ๋ชจ๋ํ, ์ฌ์ฌ์ฉ์ฑ, ๋๋ ๋ณต์กํ ์ํ ๊ด๋ฆฌ๋ฅผ ์ํด ์ ์ฉํฉ๋๋ค. Nannou ์์ฒด๊ฐ ์ด๋ฅผ ๊ฐ์ ํ์ง ์๊ธฐ ๋๋ฌธ์, Rust์ ๊ตฌ์กฐ์ฒด ๊ธฐ๋ฅ์ ํ์ฉํด ์์ ๋กญ๊ฒ ์ค๊ณํ ์ ์์ต๋๋ค. ์๋๋ ์ฃผ์ ์ฌ๋ก์
๋๋ค:
์ฃผ์ Model ์์ ์๋ธ ๊ตฌ์กฐ์ฒด๋ฅผ ํฌํจ์์ผ ์ํ๋ฅผ ๊ณ์ธต์ ์ผ๋ก ๊ด๋ฆฌํฉ๋๋ค. ์ด๋ ์ํ๊ฐ ๋ง์์ง ๋ ์ฝ๋๊ฐ ๋ณต์กํด์ง๋ ๊ฒ์ ๋ฐฉ์งํฉ๋๋ค.
Model์ด ์ ์ฒด ์ํ๋ฅผ ๊ด๋ฆฌํ๋ฉด์, ์๋ธ ๊ตฌ์กฐ์ฒด๋ก ์ธ๋ถ ๋ก์ง์ ๋ถ๋ฆฌํ ์ ์์ต๋๋ค.struct Player {
position: Vec2,
health: f32,
}
struct Enemy {
position: Vec2,
speed: f32,
}
struct Model {
player: Player, // ์๋ธ ๊ตฌ์กฐ์ฒด
enemies: Vec<Enemy>, // ์ฌ๋ฌ ์ ์ ๋ฒกํฐ๋ก ๊ด๋ฆฌ
}
fn model(app: &App) -> Model {
Model {
player: Player { position: vec2(0.0, 0.0), health: 100.0 },
enemies: vec![Enemy { position: vec2(100.0, 100.0), speed: 2.0 }],
}
}
fn update(_app: &App, model: &mut Model, _update: Update) {
model.player.position.x += 1.0; // ํ๋ ์ด์ด ์ํ ์
๋ฐ์ดํธ
for enemy in &mut model.enemies {
enemy.position.y -= enemy.speed; // ์ ์ํ ์
๋ฐ์ดํธ
}
}
Nannou์์ ์ฌ๋ฌ ์ฐฝ์ ์์ฑํ ๋, ๊ฐ ์ฐฝ๋ง๋ค ๋ณ๋์ ์ํ ๊ตฌ์กฐ์ฒด๋ฅผ ์ ์ํ ์ ์์ต๋๋ค. ๊ฐ ์ฐฝ์ model ํจ์์์ ๋
๋ฆฝ์ ์ธ ๊ตฌ์กฐ์ฒด๋ฅผ ๋ฐํํฉ๋๋ค.
WindowBuilder๋ฅผ ์ฌ์ฉํด ๊ฐ ์ฐฝ์ ๋
๋ฆฝ์ ์ธ model, update, view๋ฅผ ํ ๋นํ ์ ์์ต๋๋ค.struct MainModel {
// ๋ฉ์ธ ์ํ
counter: u32,
}
struct SettingsModel {
// ์ค์ ์ํ
theme: String,
}
fn main() {
nannou::app(main_model).update(main_update).run();
// ๋ณ๋์ ์ฐฝ ์์ฑ ์ ๋ค๋ฅธ model ํจ์ ์ฌ์ฉ ๊ฐ๋ฅ
}
fn main_model(app: &App) -> MainModel {
let _main_window = app.new_window().size(800, 600).view(main_view).build().unwrap();
MainModel { counter: 0 }
}
// ๋ค๋ฅธ ์ฐฝ์ ์ํ ๋ณ๋ ํจ์์ ๊ตฌ์กฐ์ฒด ์ ์ ๊ฐ๋ฅ
๋ณต์กํ ์ฑ์์ ์ฌ๋ฌ ๊ตฌ์กฐ์ฒด๊ฐ ๊ณตํต ๋ฉ์๋๋ฅผ ๊ณต์ ํ๋๋ก ํธ๋ ์ดํธ๋ฅผ ๊ตฌํํฉ๋๋ค. ์ด๋ ์ฌ์ฉ์ ์ ์ ๊ตฌ์กฐ์ฒด๋ฅผ ๋ ์ ์ฐํ๊ฒ ๋ง๋ญ๋๋ค. ์ด ๋ฐฉ์์ ์ฌ๋ฌ ๊ตฌ์กฐ์ฒด๋ฅผ ๋์ ์ผ๋ก ๊ด๋ฆฌํ ๋ ์ ์ฉํฉ๋๋ค.
trait Updateable {
fn update(&mut self, delta_time: f32);
}
struct Ball {
position: Vec2,
}
impl Updateable for Ball {
fn update(&mut self, delta_time: f32) {
self.position.x += 10.0 * delta_time;
}
}
struct Model {
balls: Vec<Ball>, // ์ฌ๋ฌ ๊ตฌ์กฐ์ฒด ์ธ์คํด์ค
}
fn update(_app: &App, model: &mut Model, update: Update) {
let dt = update.since_last.as_secs_f32();
for ball in &mut model.balls {
ball.update(dt); // ํธ๋ ์ดํธ ๋ฉ์๋ ํธ์ถ
}
}
์ฌ๋ฌ ๊ตฌ์กฐ์ฒด๋ฅผ ์ฌ์ฉํ ๋๋ Nannou์ ํจ์ ์๊ทธ๋์ฒ(์: fn update(_app: &App, model: &mut Model, _update: Update))๋ฅผ ์ ์งํด์ผ ํฉ๋๋ค. ์ฃผ์ ์ํ๋ ํ๋์ ๋ฃจํธ ๊ตฌ์กฐ์ฒด(์: Model)๋ก ํตํฉํ๋ ๊ฒ์ด ์ข์ต๋๋ค.
๋ณต์ก๋๊ฐ ์ฆ๊ฐํ๋ฉด ECS(Entity-Component-System) ํจํด์ด๋ ๋ณ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ(์: specs)๋ฅผ ๋์
ํ ์ ์์ง๋ง, Nannou์ ๊ธฐ๋ณธ ์ฒ ํ์ ๊ฐ๋จํ ์ํ ๊ด๋ฆฌ๋ฅผ ๊ฐ์กฐํฉ๋๋ค.
๊ด๋ก์ ์ผ๋ก Model์ ์ฃผ์ ๊ตฌ์กฐ์ฒด๋ก ์ฌ์ฉํ๋, ์๋ธ ๊ตฌ์กฐ์ฒด์๋ ์๋ฏธ ์๋ ์ด๋ฆ(์: Particle, UIState)์ ๋ถ์ฌ ์ฝ๋ ๊ฐ๋
์ฑ์ ๋์ด์ธ์.
โ โ๏ธ๐ ๏ธ๐๐๐จ๐ผ๏ธ๐งฉ๐ง ๐งฎ๐น๏ธ๐งฟโณ๐๏ธ๐ฎ๐๐ชฉ๐๏ธ๐๐งฐ๐
์๋ณด์นด๋
Sample
Important
Highlighting
๋น์
์ ํฉ์
purple
hot pink
yellow
์ด๊ตฌ์
orange
green
blue