以前咱們已經用循環讓程序持續運行, 使用宏來統一處理事件, 可是 main
函數知道的太多了, 咱們目前定一個小目標, 一步一步讓入口簡化.
照慣例 git checkout -b render-view
git
trait
目前咱們先理解成 Java 的 interface
, 就相似於一個接口, 接口定義的函數具體如何實現無論, 可是它對外開放的是一個肯定的行爲. 可是視圖除了渲染, 它的事件要如何處理. 先走一步算一步.canvas
咱們先看看以前主函數如何渲染視圖的.bash
let sdl2_context = sdl2::init().unwrap();
let video = sdl2_context.video().unwrap();
let window = video
.window("Arcade Shooter", 800, 600)
.position_centered()
.opengl()
.build()
.unwrap();
let mut canvas = window.renderer().accelerated().build().unwrap();
canvas.set_draw_color(Color::RGB(0, 0, 0));
canvas.clear();
canvas.present();
複製代碼
經過 SDL 的函數來建立一個渲染器, 這裏被命名成 canvas
的東西. 此外, 咱們還要考慮如何處理事件. 咱們把 canvas
跟事件處理包裝起來就行了.ide
use sdl2::render::Renderer;
struct Phi {
pub events: Events,
pub canvas: Renderer,
}
impl Phi {
pub fn new(events: Events, canvas: Renderer) -> Phi {
Phi {
events,
canvas,
}
}
}
複製代碼
定義一個結構體來拿到事件跟渲染器, 而後定一個渲染函數. 還要讓主函數曉得視圖的動做, 並且以前的事件觸發執行都涉及值的變化, 因此傳入的 Phi
結構體不只須要借用, 還要考慮可變.函數
pub enum ViewAction {
Quit,
None,
}
pub trait View {
fn render(&mut self, context: &mut Phi) -> ViewAction;
}
複製代碼
咱們來實現一下這個 trait
oop
pub struct DefaultView;
impl View for DefaultView {
fn render(&mut self, context: &mut Phi) -> ViewAction {
let canvas = &mut context.canvas;
let events = &mut context.events;
if events.now.quit || events.now.key_escape == Some(true) {
return ViewAction::Quit;
}
canvas.set_draw_color(Color::RGB(0, 0, 0));
canvas.clear();
ViewAction::None
}
}
複製代碼
如今仍是個半成品, 渲染器跟事件給 render
處理了, 可是入口函數仍是沒有多少精簡, 看起來更麻煩了.ui
fn main() {
let sdl2_context = sdl2::init().unwrap();
let video = sdl2_context.video().unwrap();
let window = video
.window("Arcade Shooter", 800, 600)
.position_centered()
.opengl()
.build()
.unwrap();
let canvas = window.renderer().accelerated().build().unwrap();
let events = Events::new(sdl2_context.event_pump().unwrap());
let mut context = Phi::new(events, canvas);
let mut current_view = views::DefaultView;
'running: loop {
context.events.pump();
match current_view.render(&mut context) {
ViewAction::None => context.canvas.present(),
ViewAction::Quit => break 'running
}
}
}
複製代碼
先無論那麼多, 執行一下看看效果, 這裏有個坑. 執行後發現跑不起來this
error[E0106]: missing lifetime specifier
--> src/phi/mod.rs:19:17
|
19 | pub canvas: Renderer,
| ^^^^^^^^ expected lifetime parameter
error: aborting due to previous error
For more information about this error, try `rustc --explain E0106`.
複製代碼
生命週期錯誤, canvas
好像活得不夠久誒. 咱們思考一下 canvas
從哪裏來的spa
let canvas = window.renderer().accelerated().build().unwrap();
let events = Events::new(sdl2_context.event_pump().unwrap());
let mut context = Phi::new(events, canvas);
// 注意 Window 的 renderer 函數
impl Window {
/// Initializes a new `RendererBuilder`; a convenience method that calls `RendererBuilder::new()`.
pub fn renderer(self) -> RendererBuilder {
RendererBuilder::new(self)
}
}
複製代碼
咱們能夠看到 window
調用 renderer
時把 self
給 RendererBuilder
了, 等於講咱們的 canvas
擁有 window
, 因此咱們得保證 canvas
活得夠久. 改一下 Phi
, 添加一個生命週期的標記.code
use sdl2::render::Renderer;
pub struct Phi<'window> {
pub events: Events,
pub canvas: Renderer<'window>,
}
impl<'window> Phi<'window> {
pub fn new(events: Events, canvas: Renderer<'window>) -> Phi {
Phi {
events,
canvas,
}
}
}
複製代碼
雖然如今仍是個半成品, 可是後面還有用途, 咱們當下的目的是一步一步讓 main
僅僅是做爲一個入口存在.
這一節改的東西稍微多那麼一捏捏, 有問題看看代碼. Coding