以前咱们已经用循环让程序持续运行, 使用宏来统一处理事件, 可是 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