虽然带点小效果的飞船已经搞定了,但是现在背景一片黑,完全没看头,其实加上纹理就能搞出背景,岂不美哉。
做之前先总结一下思路,在 View
的 render
函数中,渲染飞船之前先把背景渲染出来,渲染背景其实就是加载纹理图片,然后为了制造视差效果,把不同背景向左移动,速度单独设置,再加个前景在飞船之后加载渲染,同时设置移动速度,总体就是给一个飞船在太空中飞行的感觉。
现在理清思路,实现一下逻辑,就是把行为做抽象,既然要处理背景那就 Background
结构体走起,结构体除了要显示的纹理,还有自身的位置,以及平移速度,但是因为循环一直在执行,可以采用时间来计算。 先把 Background
搞定
impl Sprite {
pub fn size(&self) -> (f64, f64) {
(self.src.w, self.src.h)
}
}
#[derive(Clone)]
struct Background {
pos: f64,
vel: f64,
sprite: Sprite,
}
impl Background {
fn render(&mut self, canvas: &mut Renderer, elapsed: f64) {
let (w, h) = self.sprite.size();
self.pos += self.vel * elapsed;
if self.pos > w {
self.pos -= w;
}
let (win_w, win_h) = canvas.output_size().unwrap();
let scale = win_h as f64 / h;
let mut physical_left = -self.pos * scale;
while physical_left < win_w as f64 {
canvas.copy_sprite(&self.sprite,
Rectangle {
x: physical_left,
y: 0.0,
w: w * scale,
h: win_h as f64,
});
physical_left += w * scale;
}
}
}
复制代码
elapsed
这个形参是通过计算后传入的,所以在 spawn
函数内 loop
处算好传进去,同时 View
的 render
函数也要改一下,ShipView
也要改一下,原因很简单,ShipView
需要引入 Background
pub struct ShipView {
player: Ship,
bg_back: Background,
bg_middle: Background,
bg_front: Background,
}
impl ShipView {
pub fn new(phi: &mut Phi) -> Self {
// ...
Self {
player: Ship {
rect: Rectangle {
x: 64.0,
y: 64.0,
w: 32.0,
h: 32.0,
},
sprites,
current: ShipFrame::MidNorm,
},
bg_front: Background {
pos: 0.0,
vel: 80.0,
sprite: Sprite::load(&mut phi.canvas,
"assets/star_fg.png").unwrap(),
},
bg_middle: Background{
pos: 0.0,
vel: 40.0,
sprite: Sprite::load(&mut phi.canvas,
"assets/star_mg.png").unwrap(),
},
bg_back: Background{
pos: 0.0,
vel: 20.0,
sprite: Sprite::load(&mut phi.canvas,
"assets/star_bg.png").unwrap(),
}
}
}
}
pub trait View {
fn render(&mut self, context: &mut Phi, elapsed: f64) -> ViewAction;
}
pub fn spawn(title: &str) {
// ...
let mut timer = sdl2_context.timer().unwrap();
let interval = 1000 / 60;
let mut before = timer.ticks();
'running: loop {
let now = timer.ticks();
let dt = now - before;
let elapsed = dt as f64 / 1000.0;
if dt < interval {
timer.delay(interval - dt);
continue;
}
before = now;
context.events.pump(&mut context.canvas);
match current_view.render(&mut context, elapsed) {
ViewAction::None => context.canvas.present(),
ViewAction::Quit => break 'running,
}
}
}
impl View for ShipView {
fn render(&mut self, context: &mut Phi, elapsed: f64) -> ViewAction {
// ...
canvas.set_draw_color(Color::RGB(0, 0, 0));
canvas.clear();
self.bg_back.render(canvas, elapsed);
self.bg_middle.render(canvas, elapsed);
// ...
canvas.copy_sprite(
&self.player.sprites[self.player.current as usize],
self.player.rect);
self.bg_front.render(canvas, elapsed);
ViewAction::None
}
}
复制代码
现在就可以做到背景变化,由于视差效果,我们看起来就像飞船在不停往前移动。