Browse Source

initial commit

physics
trashbyte 1 year ago
commit
80a875cc3a
14 changed files with 2611 additions and 0 deletions
  1. 2
    0
      .gitignore
  2. 2271
    0
      Cargo.lock
  3. 11
    0
      Cargo.toml
  4. 5
    0
      LICENSE
  5. BIN
      resources/DejaVuSansMono.ttf
  6. BIN
      resources/DejaVuSerif.ttf
  7. BIN
      resources/tileset.png
  8. 46
    0
      src/assetmanager.rs
  9. 126
    0
      src/engine.rs
  10. 16
    0
      src/input.rs
  11. 41
    0
      src/main.rs
  12. 45
    0
      src/tilemap.rs
  13. 45
    0
      src/tileset.rs
  14. 3
    0
      src/types.rs

+ 2
- 0
.gitignore View File

@@ -0,0 +1,2 @@
1
+/target
2
+**/*.rs.bk

+ 2271
- 0
Cargo.lock
File diff suppressed because it is too large
View File


+ 11
- 0
Cargo.toml View File

@@ -0,0 +1,11 @@
1
+[package]
2
+name = "platformaker"
3
+version = "0.0.1"
4
+authors = ["trashbyte <github@trashbyte.io>"]
5
+edition = "2018"
6
+
7
+[dependencies]
8
+ggez = "0.5.0-rc.2"
9
+nalgebra = {version = "0.18", features = ["mint"] }
10
+mint = "0.5"
11
+rand = "0.6"

+ 5
- 0
LICENSE View File

@@ -0,0 +1,5 @@
1
+Copyright 2019 trashbyte
2
+
3
+Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
4
+
5
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

BIN
resources/DejaVuSansMono.ttf View File


BIN
resources/DejaVuSerif.ttf View File


BIN
resources/tileset.png View File


+ 46
- 0
src/assetmanager.rs View File

@@ -0,0 +1,46 @@
1
+use std::collections::HashMap;
2
+
3
+use ggez::graphics;
4
+use ggez::{Context, GameResult};
5
+
6
+
7
+pub struct AssetManager {
8
+    images: HashMap<String, graphics::Image>,
9
+    fonts: HashMap<String, graphics::Font>,
10
+}
11
+
12
+
13
+impl AssetManager {
14
+    pub fn new(ctx: &mut Context) -> GameResult<AssetManager> {
15
+        let mut images = HashMap::new();
16
+        {
17
+            let mut tileset_image = graphics::Image::new(ctx, "/tileset.png")?;
18
+            tileset_image.set_filter(graphics::FilterMode::Nearest);
19
+            images.insert(String::from("tileset"), tileset_image);
20
+        }
21
+        
22
+        let mut fonts = HashMap::new();
23
+        fonts.insert(String::from("DejaVuSerif"), graphics::Font::new(ctx, "/DejaVuSerif.ttf")?);
24
+
25
+        Ok(AssetManager {
26
+            images,
27
+            fonts,
28
+        })
29
+    }
30
+
31
+
32
+    pub fn image(&self, key: &str) -> Option<graphics::Image> {
33
+        match self.images.get(&String::from(key)) {
34
+            Some(i) => Some(i.clone()),
35
+            None => None
36
+        }
37
+    }
38
+
39
+    
40
+    pub fn font(&self, key: &str) -> Option<graphics::Font> {
41
+        match self.fonts.get(&String::from(key)) {
42
+            Some(f) => Some(f.clone()),
43
+            None => None
44
+        }
45
+    }
46
+}

+ 126
- 0
src/engine.rs View File

@@ -0,0 +1,126 @@
1
+use ggez::event::{EventHandler, KeyCode, KeyMods};
2
+use ggez::graphics;
3
+use ggez::timer;
4
+use ggez::{Context, GameResult};
5
+
6
+use crate::assetmanager::AssetManager;
7
+use crate::tilemap::TilemapLayer;
8
+use crate::tileset::Tileset;
9
+use crate::input::InputState;
10
+use crate::types::Point2;
11
+
12
+
13
+pub struct Engine {
14
+    pub assets: AssetManager,
15
+    pub input: InputState,
16
+    pub camera_pos: Point2,
17
+    pub tileset: Tileset,
18
+    pub tilemap: TilemapLayer,
19
+}
20
+
21
+
22
+const WINDOW_WIDTH: f32 = 1600.0;
23
+const WINDOW_HEIGHT: f32 = 900.0;
24
+
25
+
26
+impl Engine {
27
+    pub fn new(ctx: &mut Context) -> GameResult<Self> {
28
+        //println!("Game resource path: {:?}", ctx.filesystem);
29
+
30
+        let assets = AssetManager::new(ctx)?;
31
+        let tileset_image = assets.image("tileset").unwrap();
32
+
33
+        let mut tile_ids: Vec<u32> = (0..25).collect();
34
+        tile_ids.reverse();
35
+
36
+        let s = Engine {
37
+            assets,
38
+            input: InputState::default(),
39
+            camera_pos: Point2::new(0f32, 0f32),
40
+            tilemap: TilemapLayer::from(tile_ids, 5, 5),
41
+            tileset: Tileset::new(tileset_image, 5, 5),
42
+        };
43
+
44
+        Ok(s)
45
+    }
46
+}
47
+
48
+
49
+fn world_to_screen_coords(point: Point2, camera_pos: Point2) -> Point2 {
50
+    let x = point.x * 32.0 - camera_pos.x * 32.0;
51
+    let y = WINDOW_HEIGHT - point.y * 32.0 - camera_pos.y * 32.0;
52
+    Point2::new(x, y)
53
+}
54
+
55
+
56
+impl EventHandler for Engine {
57
+    fn update(&mut self, ctx: &mut Context) -> GameResult {
58
+        const DESIRED_FPS: u32 = 60;
59
+
60
+        while timer::check_update_time(ctx, DESIRED_FPS) {
61
+            let seconds = 1.0 / (DESIRED_FPS as f32);
62
+            self.camera_pos.x += seconds / 5.0;
63
+        }
64
+
65
+        Ok(())
66
+    }
67
+
68
+
69
+    fn draw(&mut self, ctx: &mut Context) -> GameResult {
70
+        graphics::clear(ctx, graphics::BLACK);
71
+
72
+        self.tilemap.draw(world_to_screen_coords(Point2::new(10.0, 10.0), self.camera_pos), &self.tileset, ctx)?;
73
+
74
+        let test_text = graphics::Text::new((String::from("Test text"), self.assets.font("DejaVuSerif").unwrap(), 32.0));
75
+        graphics::draw(ctx, &test_text, (Point2::new(800.0, 10.0), 0.0, graphics::WHITE))?;
76
+
77
+        graphics::present(ctx)?;
78
+
79
+        timer::yield_now();
80
+        Ok(())
81
+    }
82
+
83
+
84
+    fn key_down_event(
85
+        &mut self,
86
+        ctx: &mut Context,
87
+        keycode: KeyCode,
88
+        _keymod: KeyMods,
89
+        _repeat: bool,
90
+    ) {
91
+        match keycode {
92
+            KeyCode::S => {
93
+                self.input.yaxis = -1.0;
94
+            }
95
+            KeyCode::W => {
96
+                self.input.yaxis = 1.0;
97
+            }
98
+            KeyCode::A => {
99
+                self.input.xaxis = -1.0;
100
+            }
101
+            KeyCode::D => {
102
+                self.input.xaxis = 1.0;
103
+            }
104
+            KeyCode::P => {
105
+                let img = graphics::screenshot(ctx).expect("Could not take screenshot");
106
+                img.encode(ctx, graphics::ImageFormat::Png, "/screenshot.png")
107
+                    .expect("Could not save screenshot");
108
+            }
109
+            KeyCode::Escape => ggez::quit(ctx),
110
+            _ => (), // Do nothing
111
+        }
112
+    }
113
+
114
+
115
+    fn key_up_event(&mut self, _ctx: &mut Context, keycode: KeyCode, _keymod: KeyMods) {
116
+        match keycode {
117
+            KeyCode::W | KeyCode::S => {
118
+                self.input.yaxis = 0.0;
119
+            }
120
+            KeyCode::A | KeyCode::D => {
121
+                self.input.xaxis = 0.0;
122
+            }
123
+            _ => (), // Do nothing
124
+        }
125
+    }
126
+}

+ 16
- 0
src/input.rs View File

@@ -0,0 +1,16 @@
1
+#[derive(Debug)]
2
+pub struct InputState {
3
+    pub xaxis: f32,
4
+    pub yaxis: f32,
5
+    pub fire: bool,
6
+}
7
+
8
+impl Default for InputState {
9
+    fn default() -> Self {
10
+        InputState {
11
+            xaxis: 0.0,
12
+            yaxis: 0.0,
13
+            fire: false,
14
+        }
15
+    }
16
+}

+ 41
- 0
src/main.rs View File

@@ -0,0 +1,41 @@
1
+extern crate ggez;
2
+extern crate nalgebra;
3
+extern crate mint;
4
+extern crate rand;
5
+
6
+use ggez::conf;
7
+use ggez::event;
8
+use ggez::{ContextBuilder, GameResult};
9
+
10
+use std::env;
11
+use std::path;
12
+
13
+pub mod types;
14
+pub mod input;
15
+pub mod engine;
16
+pub mod assetmanager;
17
+pub mod tilemap;
18
+pub mod tileset;
19
+
20
+use crate::engine::Engine;
21
+
22
+
23
+pub fn main() -> GameResult {
24
+    let resource_dir = if let Ok(manifest_dir) = env::var("CARGO_MANIFEST_DIR") {
25
+        let mut path = path::PathBuf::from(manifest_dir);
26
+        path.push("resources");
27
+        path
28
+    } else {
29
+        path::PathBuf::from("./resources")
30
+    };
31
+
32
+    let cb = ContextBuilder::new("platformaker", "ggez")
33
+        .window_setup(conf::WindowSetup::default().title("platformaker"))
34
+        .window_mode(conf::WindowMode::default().dimensions(1600.0, 900.0))
35
+        .add_resource_path(resource_dir);
36
+
37
+    let (ctx, events_loop) = &mut cb.build()?;
38
+
39
+    let engine = &mut Engine::new(ctx)?;
40
+    event::run(ctx, events_loop, engine)
41
+}

+ 45
- 0
src/tilemap.rs View File

@@ -0,0 +1,45 @@
1
+use ggez::{Context, GameResult};
2
+
3
+use crate::types::{IntPoint2, Point2};
4
+use crate::tileset::Tileset;
5
+
6
+
7
+pub struct TilemapLayer {
8
+    tile_ids: Vec<u32>,
9
+    width: u32,
10
+    height: u32,
11
+}
12
+
13
+
14
+impl TilemapLayer {
15
+    pub fn from(tile_ids: Vec<u32>, width: u32, height: u32) -> Self {
16
+        assert!(tile_ids.len() == (width*height) as usize);
17
+        TilemapLayer {
18
+            tile_ids,
19
+            width,
20
+            height,
21
+        }
22
+    }
23
+
24
+
25
+    pub fn at(&self, pos: IntPoint2) -> u32 {
26
+        assert!(pos.x >= 0 && pos.y >= 0);
27
+        let x = pos.x as u32;
28
+        let y = pos.y as u32;
29
+        let index = (y * self.width + x) as usize;
30
+        assert!(index < self.tile_ids.len());
31
+        self.tile_ids[index]
32
+    }
33
+
34
+
35
+    pub fn draw(&self, base_pos: Point2, tileset: &Tileset, ctx: &mut Context) -> GameResult {
36
+        for x in 0..self.width {
37
+            for y in 0..self.height {
38
+                tileset.draw_tile(self.at(IntPoint2::new(x as i32, y as i32)),
39
+                                  Point2::new(base_pos.x + (x as f32 * 32.0), base_pos.y + (y as f32 * 32.0)),
40
+                                  ctx)?;
41
+            }
42
+        }
43
+        Ok(())
44
+    }
45
+}

+ 45
- 0
src/tileset.rs View File

@@ -0,0 +1,45 @@
1
+use ggez::graphics;
2
+use ggez::{Context, GameResult};
3
+
4
+use crate::types::{Point2, Vector2};
5
+
6
+
7
+pub struct Tileset {
8
+    pub image: graphics::Image,
9
+    pub width: u32,
10
+    pub height: u32,
11
+}
12
+
13
+
14
+impl Tileset {
15
+    pub fn new(image: graphics::Image, width: u32, height: u32) -> Self {
16
+        Tileset {
17
+            image,
18
+            width,
19
+            height,
20
+        }
21
+    }
22
+
23
+
24
+    pub fn is_valid(&self) -> bool {
25
+        self.width > 0 && self.height > 0
26
+    }
27
+
28
+
29
+    pub fn draw_tile(&self, tile_index: u32, pixel_coords: Point2, ctx: &mut Context) -> GameResult {
30
+        assert!(self.is_valid());
31
+
32
+        let x = tile_index % self.width;
33
+        let y = tile_index / self.width;
34
+        assert!(x < self.width && y < self.height);
35
+
36
+        let tile_width = 1.0 / (self.width as f32);
37
+        let tile_height = 1.0 / (self.height as f32);
38
+        let drawparams = graphics::DrawParam::new()
39
+            .src(graphics::Rect::new(tile_width*(x as f32), tile_height*(y as f32), tile_width, tile_height))
40
+            .dest(pixel_coords)
41
+            .scale(Vector2::new(2.0, 2.0))
42
+            .offset(Point2::new(0.0, 1.0));
43
+        graphics::draw(ctx, &self.image, drawparams)
44
+    }
45
+}

+ 3
- 0
src/types.rs View File

@@ -0,0 +1,3 @@
1
+pub type IntPoint2 = nalgebra::Point2<i32>;
2
+pub type Point2 = nalgebra::Point2<f32>;
3
+pub type Vector2 = nalgebra::Vector2<f32>;

Loading…
Cancel
Save