0x05. 視圖操做

簡化主函數

咱們已經肯定要讓主函數知道的更少, 在 phi 模塊內定義一個 spawn 函數, 入口只要調用這個函數, 就完成視圖的處理, 咱們要讓入口不須要了解到具體生成窗口之類的細節.canvas

pub fn spawn(title: &str) {
    let sdl2_context = sdl2::init().unwrap();
    let video = sdl2_context.video().unwrap();
    let window = video
        .window(title, 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: Box<View> = box views::DefaultView;

    'running: loop {
        context.events.pump();
        match current_view.render(&mut context) {
            ViewAction::None => context.canvas.present(),
            ViewAction::Quit => break 'running
        }
    }
}
複製代碼

如今主函數直接調用 spawn 就能夠了ide

fn main() {
    phi::spawn("Arcade Shooter");
}
複製代碼

若是以前的代碼寫過的話, 可能發現其實 spawn 相較以前多了一個 box 的關鍵字, 若是使用的是 nightly 版本的 Rust, 能夠在 main.rs 處添加這個特性來啓用這個關鍵字函數

#![feature(box_syntax)]
複製代碼

要是不想用不穩定的特性, 就把使用 box 的地方改爲oop

Box::new(views::DefaultView)
複製代碼

爲何忽然用起了 Box<T>, 引經據典一下, 根據官方的 Rust Book 的說法, 使用 Box<T> 的場景一般分ui

  • When you have a type whose size can’t be known at compile time and you want to use a value of that type in a context that requires an exact size
  • When you have a large amount of data and you want to transfer ownership but ensure the data won’t be copied when you do so
  • When you want to own a value and you care only that it’s a type that implements a particular trait rather than being of a specific type

很明顯知足第三個使用場景, 咱們只須要關心一個值的特徵, 不須要關心它具體的類型, 就跟鴨子類型同樣, 走起來是鴨子, 叫起來是鴨子, 它本質上是否是鴨子並不重要, 咱們只要口感上是鴨子就行了.
如今只考慮一個值是否 impl View 就夠了, 因此這裏直接使用 Box<T>.spa

如今執行一下能夠看到跟以前的效果沒什麼區別, 目前已經作到讓主函數變成甩手掌櫃了.code

視圖之間的切換

咱們開發一個 iOS App, 一般都會涉及到多個控制器以前的切換, 如今這個應用, 也來實現一下視圖切換的事. 把處理事件的宏添加一下空格鍵的定義, 以後只要按了空格鍵就會觸發切換視圖的事件.事件

events_macro! {
    keyboard: {
        key_escape: Escape,
        key_up: Up,
        key_down: Down,
        key_space: Space
    },
    else: {
        quit: Quit { .. }
    }
}
複製代碼

這時候不得再也不次感慨一下實現了宏的感受真贊.ip

而後在 views 的模塊內, 以前已經爲 DefaultView 實現了 View 這個 trait, 如今再來實現一個 ViewB, DefaultView 也能夠更名成 ViewA 爲了好區分. 並且這裏能夠先寫上空格鍵觸發後的控制語句.ci

impl View for ViewB {
    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;
        }
        if let Some(true) = events.now.key_space {}
        canvas.set_draw_color(Color::RGB(0, 0, 0));
        canvas.clear();
        ViewAction::None
    }
}
複製代碼

咱們在 loop 這塊有使用模式匹配的代碼, 使用到了 ViewAction 這個枚舉類型, 那就改一下 phi 模塊內的 ViewAction 的定義, 添加一個切換視圖的類型

pub enum ViewAction {
    None,
    Quit,
    ChangeView(Box<View>),
}
複製代碼

活用各類數據類型能夠簡化解決不少問題, 如今再改一下兩個視圖結構體對於 View 的實現, 主要是剛纔的空格鍵事件判斷這塊

pub struct ViewA;
pub struct ViewB;

impl View for ViewA {
    fn render(&mut self, context: &mut Phi) -> ViewAction {
        ......
        if let Some(true) = events.now.key_space {
            return ViewAction::ChangeView(box ViewB);
        }
        ......
    }
}

impl View for ViewB {
    fn render(&mut self, context: &mut Phi) -> ViewAction {
        ......
        if let Some(true) = events.now.key_space {
            return ViewAction::ChangeView(box ViewA);
        }
        ......
    }
}
複製代碼

而後天然是修改 loop 內的代碼

'running: loop {
    context.events.pump();
    match current_view.render(&mut context) {
        ViewAction::None => context.canvas.present(),
        ViewAction::Quit => break 'running,
        ViewAction::ChangeView(view) => current_view = view,
    }
}
複製代碼

如今的效果就是點擊空格就會發生視圖改變, 爲了讓本身看得出來, 能夠把每一個視圖的背景色設置成不同的.


如今已經完成了簡化主函數的工做, 還搞定了視圖的切換. 以後再處理其餘方面的工做.

相關文章
相關標籤/搜索