Put a rectangle

Now you’ll put a rectangle on the window and learn some other syntax of Rust. We have an unfortunate message about the recT structure in the views module. The ViewA ViewB structure is no longer used. We will use the view switch and other operations in the future.

To define the structure of a rectangle, a rectangle has the X and Y coordinates of the plane rectangular coordinate system on the window and the length and width of the rectangle itself.

If you want to write your own rectangle rendering, you can use OpenGL to draw two triangles to form a rectangle, and if you want to do the rectangle movement and other operations, but also use linear algebra matrix to do processing, fortunately, SDL provides the relevant API so that we can easily draw the rectangle

#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Rectangle {
    pub x: f64.pub y: f64.pub w: f64.pub h: f64,}impl Rectangle {
    pub fn to_sdl(&self) - >Option<SdlRect> {
        assert!(self.w >= 0.0 && self.h >= 0.0);
        Some(SdlRect::new(self.x as i32.self.y as i32.self.w as u32.self.h as u32))}}Copy the code

With #[derive(Clone, Copy, Debug, PartialEq)]], the normal structure lets bind to the variable to generate the move behavior of ownership, after adding the Clone Copy property, This structure, when bound to variables, behaves like a copy of an integer or floating-point type, for example

let a: i32 = 10;
let b = a; // copy, a can still be used

struct Test {}
impl Test {
    pub fn new() {... }}let c = Test::new();
let d = c; // move, c ownership is changed
Copy the code

The Debug property is to enable the structure to allow println! These macros are printed PartialEq to make the structure comparable.

Let’s define a RectView structure to implement the View trait

struct Rect {
    rect: Rectangle,
}

pub struct RectView {
    player: Rect,
}

impl RectView {
    pub fn new() - >Self {
        Self {
            player: Rect {
                rect: Rectangle {
                    x: 64.0,
                    y: 64.0,
                    w: 32.0,
                    h: 32.0,}}}}}impl View for RectView {
    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.50.0));
        canvas.clear();
        canvas.set_draw_color(Color::RGB(200.200.50));
        canvas.fill_rect(self.player.rect.to_sdl().unwrap())
            .expect("fill rect fail");
        ViewAction::None}}Copy the code

Once these things are defined, change the previous ViewA to RectView in the spawn function, and note the above code to clear() the background color before filling in the rect color

.let mut current_view: Box<View> = boxviews::RectView::new(); .Copy the code

Now to run it, the rectangle has been rendered.

Rectangle movement is controlled by arrow keys

Now, we can change the Rectangle’s width, height and position by changing the value of this structure. Recalcuating the values of x and y using the arrow keys on the keyboard makes the Rectangle move.

Change the call to the event macro as usual

events_macro! {
    keyboard: {
        key_escape: Escape,
        key_up: Up,
        key_down: Down,
        key_left: Left,
        key_right: Right,
        key_space: Space
    },
    else: { quit: Quit { .. }}}Copy the code

Then write the recalcation logic in the render function, now there are four arrow keys, and then we have to consider all the cases. My previous idea was to use if one by one to determine the trigger of the key, but obviously this way to write code ugly, fortunately Rust pattern matching is very good. So let’s just list what we have, up, down, left, right and bevel, and let’s define a constant as the speed of movement

const PLAYER_SPEED: f64 = 0.35;

impl View for RectView {
    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;
        }

        let diagonal: bool = (events.key_up ^ events.key_down) &&
            (events.key_left ^ events.key_right);
        let moved = if diagonal { 1.0 / 2.0 f64.sqrt() } else { 1.0 } *
            PLAYER_SPEED;
        let dx = match (events.key_left, events.key_right) {
            (true.true) | (false.false) = >0.0,
            (true.false) => -moved,
            (false.true) => moved,
        };

        let dy = match (events.key_up, events.key_down) {
            (true.true) | (false.false) = >0.0,
            (true.false) => -moved,
            (false.true) => moved,
        };

        self.player.rect.x += dx;
        self.player.rect.y += dy;

        canvas.set_draw_color(Color::RGB(0.50.0));
        canvas.clear();

        canvas.set_draw_color(Color::RGB(200.200.50));
        canvas.fill_rect(self.player.rect.to_sdl().unwrap())
            .expect("fill rect fail");

        ViewAction::None}}Copy the code

Now that you can display a rectangle in a window and control its movement based on the arrow keys on the keyboard, you’ve learned about the flexible use of Rust pattern matching and the definition of structure copy behavior, and that’s it.