• assets/reaper.png
  • assets/bardo.png
  • src/main.rs
+29 -2src/main.rs
1 1
use sdl2::pixels::Color;
2 2
use sdl2::event::Event;
3 3
use sdl2::keyboard::Keycode;
4 4
use sdl2::render::{WindowCanvas, Texture};
5 5
use sdl2::rect::{Point, Rect};
6 6
// "self" imports the "image" module itself as well as everything else we listed
7 7
use sdl2::image::{self, LoadTexture, InitFlag};
8 8
use std::time::Duration;
9 9

10 10
const PLAYER_MOVEMENT_SPEED: i32 = 20;
11 11

12 12
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13 13
enum Direction {
14 14
    Up,
15 15
    Down,
16 16
    Left,
17 17
    Right,
18 18
}
19 19

20 20
#[derive(Debug)]
21 21
struct Player {
22 22
    position: Point,
23 23
    sprite: Rect,
24 24
    speed: i32,
25 25
    direction: Direction,
  26
    current_frame: i32,
  27
}
  28

  29
/// Returns the row of the spritesheet corresponding to the given direction
  30
fn direction_spritesheet_row(direction: Direction) -> i32 {
  31
    use self::Direction::*;
  32
    match direction {
  33
        Up => 3,
  34
        Down => 0,
  35
        Left => 1,
  36
        Right => 2,
  37
    }
26 38
}
27 39

28 40
fn render(
29 41
    canvas: &mut WindowCanvas,
30 42
    color: Color,
31 43
    texture: &Texture,
32 44
    player: &Player,
33 45
) -> Result<(), String> {
34 46
    canvas.set_draw_color(color);
35 47
    canvas.clear();
36 48

37 49
    let (width, height) = canvas.output_size()?;
38 50

  51
    let (frame_width, frame_height) = player.sprite.size();
  52
    let current_frame = Rect::new(
  53
        player.sprite.x() + frame_width as i32 * player.current_frame,
  54
        player.sprite.y() + frame_height as  i32 * direction_spritesheet_row(player.direction),
  55
        frame_width,
  56
        frame_height,
  57
    );
  58

39 59
    // Treat the center of the screen as the (0, 0) coordinate
40 60
    let screen_position = player.position + Point::new(width as i32 / 2, height as i32 / 2);
41  
    let screen_rect = Rect::from_center(screen_position, player.sprite.width(), player.sprite.height());
42  
    canvas.copy(texture, player.sprite, screen_rect)?;
  61
    let screen_rect = Rect::from_center(screen_position, frame_width, frame_height);
  62
    canvas.copy(texture, current_frame, screen_rect)?;
43 63

44 64
    canvas.present();
45 65

46 66
    Ok(())
47 67
}
48 68

49 69
// Update player a fixed amount based on their speed.
50 70
// WARNING: Calling this function too often or at a variable speed will cause the player's speed
51 71
// to be unpredictable!
52 72
fn update_player(player: &mut Player) {
53 73
    use self::Direction::*;
54 74
    match player.direction {
55 75
        Left => {
56 76
            player.position = player.position.offset(-player.speed, 0);
57 77
        },
58 78
        Right => {
59 79
            player.position = player.position.offset(player.speed, 0);
60 80
        },
61 81
        Up => {
62 82
            player.position = player.position.offset(0, -player.speed);
63 83
        },
64 84
        Down => {
65 85
            player.position = player.position.offset(0, player.speed);
66 86
        },
67 87
    }
  88

  89
    // Only continue to animate if the player is moving
  90
    if player.speed != 0 {
  91
        // Cheat: using the fact that all animations are 3 frames (NOT extensible)
  92
        player.current_frame = (player.current_frame + 1) % 3;
  93
    }
68 94
}
69 95

70 96
fn main() -> Result<(), String> {
71 97
    let sdl_context = sdl2::init()?;
72 98
    let video_subsystem = sdl_context.video()?;
73 99
    // Leading "_" tells Rust that this is an unused variable that we don't care about. It has to
74 100
    // stay unused because if we don't have any variable at all then Rust will treat it as a
75 101
    // temporary value and drop it right away!
76 102
    let _image_context = image::init(InitFlag::PNG | InitFlag::JPG)?;
77 103

78 104
    let window = video_subsystem.window("game tutorial", 800, 600)
79 105
        .position_centered()
80 106
        .build()
81 107
        .expect("could not initialize video subsystem");
82 108

83 109
    let mut canvas = window.into_canvas().build()
84 110
        .expect("could not make a canvas");
85 111

86 112
    let texture_creator = canvas.texture_creator();
87 113
    let texture = texture_creator.load_texture("assets/bardo.png")?;
88 114

89 115
    let mut player = Player {
90 116
        position: Point::new(0, 0),
91 117
        sprite: Rect::new(0, 0, 26, 36),
92 118
        speed: 0,
93 119
        direction: Direction::Right,
  120
        current_frame: 0,
94 121
    };
95 122

96 123
    let mut event_pump = sdl_context.event_pump()?;
97 124
    let mut i = 0;
98 125
    'running: loop {
99 126
        // Handle events
100 127
        for event in event_pump.poll_iter() {
101 128
            match event {
102 129
                Event::Quit {..} |
103 130
                Event::KeyDown { keycode: Some(Keycode::Escape), .. } => {
104 131
                    break 'running;
105 132
                },
106 133
                Event::KeyDown { keycode: Some(Keycode::Left), repeat: false, .. } => {
107 134
                    player.speed = PLAYER_MOVEMENT_SPEED;
108 135
                    player.direction = Direction::Left;
109 136
                },
110 137
                Event::KeyDown { keycode: Some(Keycode::Right), repeat: false, .. } => {
111 138
                    player.speed = PLAYER_MOVEMENT_SPEED;
112 139
                    player.direction = Direction::Right;
113 140
                },
114 141
                Event::KeyDown { keycode: Some(Keycode::Up), repeat: false, .. } => {
115 142
                    player.speed = PLAYER_MOVEMENT_SPEED;
116 143
                    player.direction = Direction::Up;
117 144
                },
118 145
                Event::KeyDown { keycode: Some(Keycode::Down), repeat: false, .. } => {
119 146
                    player.speed = PLAYER_MOVEMENT_SPEED;
120 147
                    player.direction = Direction::Down;
121 148
                },
122 149
                Event::KeyUp { keycode: Some(Keycode::Left), repeat: false, .. } |
123 150
                Event::KeyUp { keycode: Some(Keycode::Right), repeat: false, .. } |
124 151
                Event::KeyUp { keycode: Some(Keycode::Up), repeat: false, .. } |
125 152
                Event::KeyUp { keycode: Some(Keycode::Down), repeat: false, .. } => {
126 153
                    player.speed = 0;
127 154
                },
128 155
                _ => {}
129 156
            }
130 157
        }
131 158

132 159
        // Update
133 160
        i = (i + 1) % 255;
134 161
        update_player(&mut player);
135 162

136 163
        // Render
137 164
        render(&mut canvas, Color::RGB(i, 64, 255 - i), &texture, &player)?;
138 165

139 166
        // Time management!
140 167
        ::std::thread::sleep(Duration::new(0, 1_000_000_000u32 / 20));
141 168
    }
142 169

143 170
    Ok(())
144 171
}
+29 -2src/main.rs
1
use sdl2::pixels::Color;
1
use sdl2::pixels::Color;
2
use sdl2::event::Event;
2
use sdl2::event::Event;
3
use sdl2::keyboard::Keycode;
3
use sdl2::keyboard::Keycode;
4
use sdl2::render::{WindowCanvas, Texture};
4
use sdl2::render::{WindowCanvas, Texture};
5
use sdl2::rect::{Point, Rect};
5
use sdl2::rect::{Point, Rect};
6
// "self" imports the "image" module itself as well as everything else we listed
6
// "self" imports the "image" module itself as well as everything else we listed
7
use sdl2::image::{self, LoadTexture, InitFlag};
7
use sdl2::image::{self, LoadTexture, InitFlag};
8
use std::time::Duration;
8
use std::time::Duration;
9

9

10
const PLAYER_MOVEMENT_SPEED: i32 = 20;
10
const PLAYER_MOVEMENT_SPEED: i32 = 20;
11

11

12
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13
enum Direction {
13
enum Direction {
14
    Up,
14
    Up,
15
    Down,
15
    Down,
16
    Left,
16
    Left,
17
    Right,
17
    Right,
18
}
18
}
19

19

20
#[derive(Debug)]
20
#[derive(Debug)]
21
struct Player {
21
struct Player {
22
    position: Point,
22
    position: Point,
23
    sprite: Rect,
23
    sprite: Rect,
24
    speed: i32,
24
    speed: i32,
25
    direction: Direction,
25
    direction: Direction,
    26
    current_frame: i32,
    27
}
    28

    29
/// Returns the row of the spritesheet corresponding to the given direction
    30
fn direction_spritesheet_row(direction: Direction) -> i32 {
    31
    use self::Direction::*;
    32
    match direction {
    33
        Up => 3,
    34
        Down => 0,
    35
        Left => 1,
    36
        Right => 2,
    37
    }
26
}
38
}
27

39

28
fn render(
40
fn render(
29
    canvas: &mut WindowCanvas,
41
    canvas: &mut WindowCanvas,
30
    color: Color,
42
    color: Color,
31
    texture: &Texture,
43
    texture: &Texture,
32
    player: &Player,
44
    player: &Player,
33
) -> Result<(), String> {
45
) -> Result<(), String> {
34
    canvas.set_draw_color(color);
46
    canvas.set_draw_color(color);
35
    canvas.clear();
47
    canvas.clear();
36

48

37
    let (width, height) = canvas.output_size()?;
49
    let (width, height) = canvas.output_size()?;
38

50

    51
    let (frame_width, frame_height) = player.sprite.size();
    52
    let current_frame = Rect::new(
    53
        player.sprite.x() + frame_width as i32 * player.current_frame,
    54
        player.sprite.y() + frame_height as  i32 * direction_spritesheet_row(player.direction),
    55
        frame_width,
    56
        frame_height,
    57
    );
    58

39
    // Treat the center of the screen as the (0, 0) coordinate
59
    // Treat the center of the screen as the (0, 0) coordinate
40
    let screen_position = player.position + Point::new(width as i32 / 2, height as i32 / 2);
60
    let screen_position = player.position + Point::new(width as i32 / 2, height as i32 / 2);
41
    let screen_rect = Rect::from_center(screen_position, player.sprite.width(), player.sprite.height());
61
    let screen_rect = Rect::from_center(screen_position, frame_width, frame_height);
42
    canvas.copy(texture, player.sprite, screen_rect)?;
62
    canvas.copy(texture, current_frame, screen_rect)?;
43

63

44
    canvas.present();
64
    canvas.present();
45

65

46
    Ok(())
66
    Ok(())
47
}
67
}
48

68

49
// Update player a fixed amount based on their speed.
69
// Update player a fixed amount based on their speed.
50
// WARNING: Calling this function too often or at a variable speed will cause the player's speed
70
// WARNING: Calling this function too often or at a variable speed will cause the player's speed
51
// to be unpredictable!
71
// to be unpredictable!
52
fn update_player(player: &mut Player) {
72
fn update_player(player: &mut Player) {
53
    use self::Direction::*;
73
    use self::Direction::*;
54
    match player.direction {
74
    match player.direction {
55
        Left => {
75
        Left => {
56
            player.position = player.position.offset(-player.speed, 0);
76
            player.position = player.position.offset(-player.speed, 0);
57
        },
77
        },
58
        Right => {
78
        Right => {
59
            player.position = player.position.offset(player.speed, 0);
79
            player.position = player.position.offset(player.speed, 0);
60
        },
80
        },
61
        Up => {
81
        Up => {
62
            player.position = player.position.offset(0, -player.speed);
82
            player.position = player.position.offset(0, -player.speed);
63
        },
83
        },
64
        Down => {
84
        Down => {
65
            player.position = player.position.offset(0, player.speed);
85
            player.position = player.position.offset(0, player.speed);
66
        },
86
        },
67
    }
87
    }
    88

    89
    // Only continue to animate if the player is moving
    90
    if player.speed != 0 {
    91
        // Cheat: using the fact that all animations are 3 frames (NOT extensible)
    92
        player.current_frame = (player.current_frame + 1) % 3;
    93
    }
68
}
94
}
69

95

70
fn main() -> Result<(), String> {
96
fn main() -> Result<(), String> {
71
    let sdl_context = sdl2::init()?;
97
    let sdl_context = sdl2::init()?;
72
    let video_subsystem = sdl_context.video()?;
98
    let video_subsystem = sdl_context.video()?;
73
    // Leading "_" tells Rust that this is an unused variable that we don't care about. It has to
99
    // Leading "_" tells Rust that this is an unused variable that we don't care about. It has to
74
    // stay unused because if we don't have any variable at all then Rust will treat it as a
100
    // stay unused because if we don't have any variable at all then Rust will treat it as a
75
    // temporary value and drop it right away!
101
    // temporary value and drop it right away!
76
    let _image_context = image::init(InitFlag::PNG | InitFlag::JPG)?;
102
    let _image_context = image::init(InitFlag::PNG | InitFlag::JPG)?;
77

103

78
    let window = video_subsystem.window("game tutorial", 800, 600)
104
    let window = video_subsystem.window("game tutorial", 800, 600)
79
        .position_centered()
105
        .position_centered()
80
        .build()
106
        .build()
81
        .expect("could not initialize video subsystem");
107
        .expect("could not initialize video subsystem");
82

108

83
    let mut canvas = window.into_canvas().build()
109
    let mut canvas = window.into_canvas().build()
84
        .expect("could not make a canvas");
110
        .expect("could not make a canvas");
85

111

86
    let texture_creator = canvas.texture_creator();
112
    let texture_creator = canvas.texture_creator();
87
    let texture = texture_creator.load_texture("assets/bardo.png")?;
113
    let texture = texture_creator.load_texture("assets/bardo.png")?;
88

114

89
    let mut player = Player {
115
    let mut player = Player {
90
        position: Point::new(0, 0),
116
        position: Point::new(0, 0),
91
        sprite: Rect::new(0, 0, 26, 36),
117
        sprite: Rect::new(0, 0, 26, 36),
92
        speed: 0,
118
        speed: 0,
93
        direction: Direction::Right,
119
        direction: Direction::Right,
    120
        current_frame: 0,
94
    };
121
    };
95

122

96
    let mut event_pump = sdl_context.event_pump()?;
123
    let mut event_pump = sdl_context.event_pump()?;
97
    let mut i = 0;
124
    let mut i = 0;
98
    'running: loop {
125
    'running: loop {
99
        // Handle events
126
        // Handle events
100
        for event in event_pump.poll_iter() {
127
        for event in event_pump.poll_iter() {
101
            match event {
128
            match event {
102
                Event::Quit {..} |
129
                Event::Quit {..} |
103
                Event::KeyDown { keycode: Some(Keycode::Escape), .. } => {
130
                Event::KeyDown { keycode: Some(Keycode::Escape), .. } => {
104
                    break 'running;
131
                    break 'running;
105
                },
132
                },
106
                Event::KeyDown { keycode: Some(Keycode::Left), repeat: false, .. } => {
133
                Event::KeyDown { keycode: Some(Keycode::Left), repeat: false, .. } => {
107
                    player.speed = PLAYER_MOVEMENT_SPEED;
134
                    player.speed = PLAYER_MOVEMENT_SPEED;
108
                    player.direction = Direction::Left;
135
                    player.direction = Direction::Left;
109
                },
136
                },
110
                Event::KeyDown { keycode: Some(Keycode::Right), repeat: false, .. } => {
137
                Event::KeyDown { keycode: Some(Keycode::Right), repeat: false, .. } => {
111
                    player.speed = PLAYER_MOVEMENT_SPEED;
138
                    player.speed = PLAYER_MOVEMENT_SPEED;
112
                    player.direction = Direction::Right;
139
                    player.direction = Direction::Right;
113
                },
140
                },
114
                Event::KeyDown { keycode: Some(Keycode::Up), repeat: false, .. } => {
141
                Event::KeyDown { keycode: Some(Keycode::Up), repeat: false, .. } => {
115
                    player.speed = PLAYER_MOVEMENT_SPEED;
142
                    player.speed = PLAYER_MOVEMENT_SPEED;
116
                    player.direction = Direction::Up;
143
                    player.direction = Direction::Up;
117
                },
144
                },
118
                Event::KeyDown { keycode: Some(Keycode::Down), repeat: false, .. } => {
145
                Event::KeyDown { keycode: Some(Keycode::Down), repeat: false, .. } => {
119
                    player.speed = PLAYER_MOVEMENT_SPEED;
146
                    player.speed = PLAYER_MOVEMENT_SPEED;
120
                    player.direction = Direction::Down;
147
                    player.direction = Direction::Down;
121
                },
148
                },
122
                Event::KeyUp { keycode: Some(Keycode::Left), repeat: false, .. } |
149
                Event::KeyUp { keycode: Some(Keycode::Left), repeat: false, .. } |
123
                Event::KeyUp { keycode: Some(Keycode::Right), repeat: false, .. } |
150
                Event::KeyUp { keycode: Some(Keycode::Right), repeat: false, .. } |
124
                Event::KeyUp { keycode: Some(Keycode::Up), repeat: false, .. } |
151
                Event::KeyUp { keycode: Some(Keycode::Up), repeat: false, .. } |
125
                Event::KeyUp { keycode: Some(Keycode::Down), repeat: false, .. } => {
152
                Event::KeyUp { keycode: Some(Keycode::Down), repeat: false, .. } => {
126
                    player.speed = 0;
153
                    player.speed = 0;
127
                },
154
                },
128
                _ => {}
155
                _ => {}
129
            }
156
            }
130
        }
157
        }
131

158

132
        // Update
159
        // Update
133
        i = (i + 1) % 255;
160
        i = (i + 1) % 255;
134
        update_player(&mut player);
161
        update_player(&mut player);
135

162

136
        // Render
163
        // Render
137
        render(&mut canvas, Color::RGB(i, 64, 255 - i), &texture, &player)?;
164
        render(&mut canvas, Color::RGB(i, 64, 255 - i), &texture, &player)?;
138

165

139
        // Time management!
166
        // Time management!
140
        ::std::thread::sleep(Duration::new(0, 1_000_000_000u32 / 20));
167
        ::std::thread::sleep(Duration::new(0, 1_000_000_000u32 / 20));
141
    }
168
    }
142

169

143
    Ok(())
170
    Ok(())
144
}
171
}
/target
**/*.rs.bk
[package]
name = "game-tutorial"
version = "0.1.0"
authors = ["Sunjay Varma <[email protected]>"]
edition = "2018"

[dependencies]

[dependencies.sdl2]
version = "0.32.1"
default-features = false
features = ["image"]
use sdl2::pixels::Color;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use sdl2::render::{WindowCanvas, Texture};
use sdl2::rect::{Point, Rect};
// "self" imports the "image" module itself as well as everything else we listed
use sdl2::image::{self, LoadTexture, InitFlag};
use std::time::Duration;

const PLAYER_MOVEMENT_SPEED: i32 = 20;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum Direction {
    Up,
    Down,
    Left,
    Right,
}

#[derive(Debug)]
struct Player {
    position: Point,
    sprite: Rect,
    speed: i32,
    direction: Direction,
    current_frame: i32,
}

/// Returns the row of the spritesheet corresponding to the given direction
fn direction_spritesheet_row(direction: Direction) -> i32 {
    use self::Direction::*;
    match direction {
        Up => 3,
        Down => 0,
        Left => 1,
        Right => 2,
    }
}

fn render(
    canvas: &mut WindowCanvas,
    color: Color,
    texture: &Texture,
    player: &Player,
) -> Result<(), String> {
    canvas.set_draw_color(color);
    canvas.clear();

    let (width, height) = canvas.output_size()?;

    let (frame_width, frame_height) = player.sprite.size();
    let current_frame = Rect::new(
        player.sprite.x() + frame_width as i32 * player.current_frame,
        player.sprite.y() + frame_height as  i32 * direction_spritesheet_row(player.direction),
        frame_width,
        frame_height,
    );

    // Treat the center of the screen as the (0, 0) coordinate
    let screen_position = player.position + Point::new(width as i32 / 2, height as i32 / 2);
    let screen_rect = Rect::from_center(screen_position, frame_width, frame_height);
    canvas.copy(texture, current_frame, screen_rect)?;

    canvas.present();

    Ok(())
}

// Update player a fixed amount based on their speed.
// WARNING: Calling this function too often or at a variable speed will cause the player's speed
// to be unpredictable!
fn update_player(player: &mut Player) {
    use self::Direction::*;
    match player.direction {
        Left => {
            player.position = player.position.offset(-player.speed, 0);
        },
        Right => {
            player.position = player.position.offset(player.speed, 0);
        },
        Up => {
            player.position = player.position.offset(0, -player.speed);
        },
        Down => {
            player.position = player.position.offset(0, player.speed);
        },
    }

    // Only continue to animate if the player is moving
    if player.speed != 0 {
        // Cheat: using the fact that all animations are 3 frames (NOT extensible)
        player.current_frame = (player.current_frame + 1) % 3;
    }
}

fn main() -> Result<(), String> {
    let sdl_context = sdl2::init()?;
    let video_subsystem = sdl_context.video()?;
    // Leading "_" tells Rust that this is an unused variable that we don't care about. It has to
    // stay unused because if we don't have any variable at all then Rust will treat it as a
    // temporary value and drop it right away!
    let _image_context = image::init(InitFlag::PNG | InitFlag::JPG)?;

    let window = video_subsystem.window("game tutorial", 800, 600)
        .position_centered()
        .build()
        .expect("could not initialize video subsystem");

    let mut canvas = window.into_canvas().build()
        .expect("could not make a canvas");

    let texture_creator = canvas.texture_creator();
    let texture = texture_creator.load_texture("assets/bardo.png")?;

    let mut player = Player {
        position: Point::new(0, 0),
        sprite: Rect::new(0, 0, 26, 36),
        speed: 0,
        direction: Direction::Right,
        current_frame: 0,
    };

    let mut event_pump = sdl_context.event_pump()?;
    let mut i = 0;
    'running: loop {
        // Handle events
        for event in event_pump.poll_iter() {
            match event {
                Event::Quit {..} |
                Event::KeyDown { keycode: Some(Keycode::Escape), .. } => {
                    break 'running;
                },
                Event::KeyDown { keycode: Some(Keycode::Left), repeat: false, .. } => {
                    player.speed = PLAYER_MOVEMENT_SPEED;
                    player.direction = Direction::Left;
                },
                Event::KeyDown { keycode: Some(Keycode::Right), repeat: false, .. } => {
                    player.speed = PLAYER_MOVEMENT_SPEED;
                    player.direction = Direction::Right;
                },
                Event::KeyDown { keycode: Some(Keycode::Up), repeat: false, .. } => {
                    player.speed = PLAYER_MOVEMENT_SPEED;
                    player.direction = Direction::Up;
                },
                Event::KeyDown { keycode: Some(Keycode::Down), repeat: false, .. } => {
                    player.speed = PLAYER_MOVEMENT_SPEED;
                    player.direction = Direction::Down;
                },
                Event::KeyUp { keycode: Some(Keycode::Left), repeat: false, .. } |
                Event::KeyUp { keycode: Some(Keycode::Right), repeat: false, .. } |
                Event::KeyUp { keycode: Some(Keycode::Up), repeat: false, .. } |
                Event::KeyUp { keycode: Some(Keycode::Down), repeat: false, .. } => {
                    player.speed = 0;
                },
                _ => {}
            }
        }

        // Update
        i = (i + 1) % 255;
        update_player(&mut player);

        // Render
        render(&mut canvas, Color::RGB(i, 64, 255 - i), &texture, &player)?;

        // Time management!
        ::std::thread::sleep(Duration::new(0, 1_000_000_000u32 / 20));
    }

    Ok(())
}