Browse Source

Init Commit

Simon Watson 1 year ago
parent
commit
905ea33390

+ 3 - 0
.gitignore

@@ -0,0 +1,3 @@
+target/
+target/*
+Cargo.lock

+ 11 - 0
Cargo.toml

@@ -0,0 +1,11 @@
+[package]
+name = "rs-rl"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+rltk = { version = "0.8.0" }
+specs = "0.16.1"
+specs-derive = "0.4.1"

+ 12 - 0
resources/backing.fs

@@ -0,0 +1,12 @@
+#version 330 core
+out vec4 FragColor;
+
+in vec2 TexCoords;
+
+uniform sampler2D screenTexture;
+
+void main()
+{
+    vec3 col = texture(screenTexture, TexCoords).rgb;
+    FragColor = vec4(col, 1.0);
+}

+ 11 - 0
resources/backing.vs

@@ -0,0 +1,11 @@
+#version 330 core
+layout (location = 0) in vec2 aPos;
+layout (location = 1) in vec2 aTexCoords;
+
+out vec2 TexCoords;
+
+void main()
+{
+    TexCoords = aTexCoords;
+    gl_Position = vec4(aPos.x, aPos.y, 0.0, 1.0);
+}

+ 17 - 0
resources/console_no_bg.fs

@@ -0,0 +1,17 @@
+#version 330 core
+out vec4 FragColor;
+
+in vec3 ourColor;
+in vec2 TexCoord;
+in vec3 ourBackground;
+
+// texture sampler
+uniform sampler2D texture1;
+
+void main()
+{
+    vec4 original = texture(texture1, TexCoord);
+    if (original.r < 0.1f || original.g < 0.1f || original.b < 0.1f) discard;
+    vec4 fg = original * vec4(ourColor, 1.f);
+	FragColor = fg;
+}

+ 17 - 0
resources/console_no_bg.vs

@@ -0,0 +1,17 @@
+#version 330 core
+layout (location = 0) in vec3 aPos;
+layout (location = 1) in vec3 aColor;
+layout (location = 2) in vec3 bColor;
+layout (location = 3) in vec2 aTexCoord;
+
+out vec3 ourColor;
+out vec3 ourBackground;
+out vec2 TexCoord;
+
+void main()
+{
+	gl_Position = vec4(aPos, 1.0);
+	ourColor = aColor;
+	ourBackground = bColor;
+	TexCoord = vec2(aTexCoord.x, aTexCoord.y);
+}

+ 16 - 0
resources/console_with_bg.fs

@@ -0,0 +1,16 @@
+#version 330 core
+out vec4 FragColor;
+
+in vec3 ourColor;
+in vec2 TexCoord;
+in vec3 ourBackground;
+
+// texture sampler
+uniform sampler2D texture1;
+
+void main()
+{
+    vec4 original = texture(texture1, TexCoord);
+    vec4 fg = original.r > 0.1f || original.g > 0.1f || original.b > 0.1f ? original * vec4(ourColor, 1.f) : vec4(ourBackground, 1.f);
+	FragColor = fg;
+}

+ 17 - 0
resources/console_with_bg.vs

@@ -0,0 +1,17 @@
+#version 330 core
+layout (location = 0) in vec3 aPos;
+layout (location = 1) in vec3 aColor;
+layout (location = 2) in vec3 bColor;
+layout (location = 3) in vec2 aTexCoord;
+
+out vec3 ourColor;
+out vec3 ourBackground;
+out vec2 TexCoord;
+
+void main()
+{
+	gl_Position = vec4(aPos, 1.0);
+	ourColor = aColor;
+	ourBackground = bColor;
+	TexCoord = vec2(aTexCoord.x, aTexCoord.y);
+}

BIN
resources/example_tiles.jpg


BIN
resources/example_tiles.xcf


BIN
resources/mltest.xp


BIN
resources/nyan.xp


BIN
resources/resources.zip


+ 26 - 0
resources/scanlines.fs

@@ -0,0 +1,26 @@
+#version 330 core
+out vec4 FragColor;
+
+in vec2 TexCoords;
+
+uniform sampler2D screenTexture;
+uniform vec3 screenSize;
+uniform bool screenBurn;
+
+void main()
+{
+    vec3 col = texture(screenTexture, TexCoords).rgb;
+    float scanLine = mod(gl_FragCoord.y, 2.0) * 0.25;
+    vec3 scanColor = col.rgb - scanLine;
+
+    if (col.r < 0.1f && col.g < 0.1f && col.b < 0.1f) {
+        if (screenBurn) {
+            float dist = (1.0 - distance(vec2(gl_FragCoord.x / screenSize.x, gl_FragCoord.y / screenSize.y), vec2(0.5,0.5))) * 0.2;
+            FragColor = vec4(0.0, dist, dist, 1.0);
+        } else {
+            FragColor = vec4(0.0, 0.0, 0.0, 1.0);
+        }
+    } else {
+        FragColor = vec4(scanColor, 1.0);
+    }
+}

+ 11 - 0
resources/scanlines.vs

@@ -0,0 +1,11 @@
+#version 330 core
+layout (location = 0) in vec2 aPos;
+layout (location = 1) in vec2 aTexCoords;
+
+out vec2 TexCoords;
+
+void main()
+{
+    TexCoords = aTexCoords;
+    gl_Position = vec4(aPos.x, aPos.y, 0.0, 1.0);
+}

BIN
resources/terminal8x8.jpg


BIN
resources/vga8x16.jpg


+ 23 - 0
src/components.rs

@@ -0,0 +1,23 @@
+use specs::prelude::*;
+use specs_derive::*;
+use rltk::{RGB};
+
+// COMPONENTS
+
+
+
+#[derive(Component)]
+pub struct Position {
+    pub x: i32,
+    pub y: i32,
+}
+
+#[derive(Component)]
+pub struct Renderable {
+    pub glyph: rltk::FontCharType,
+    pub fg: RGB,
+    pub bg: RGB,
+}
+
+#[derive(Component, Debug)]
+pub struct Player {}

+ 65 - 0
src/main.rs

@@ -0,0 +1,65 @@
+use rltk::{GameState, Rltk, RGB};
+use specs::prelude::*;
+
+mod components;
+pub use components::*;
+mod map;
+pub use map::*;
+mod player;
+use player::*;
+mod rect;
+pub use rect::Rect;
+
+// ***** //
+// STATE //
+pub struct State {
+    pub ecs: World
+}
+
+impl GameState for State {
+    fn tick(&mut self, ctx : &mut Rltk) {
+        ctx.cls();
+        
+        player_input(self, ctx);
+
+        let map = self.ecs.fetch::<Vec<map::TileType>>();
+        draw_map(&map, ctx);
+
+        let positions = self.ecs.read_storage::<Position>();
+        let renderables = self.ecs.read_storage::<Renderable>();
+
+        for (pos, render) in (&positions, &renderables).join() {
+            ctx.set(pos.x, pos.y, render.fg, render.bg, render.glyph);
+        }
+        
+    }
+}
+
+// ********
+// MAIN
+
+fn main() -> rltk::BError {
+    use rltk::RltkBuilder;
+    let context = RltkBuilder::simple80x50()
+        .with_title("Roguelike Tutorial")
+        .build()?;
+    let mut gs = State{ 
+        ecs: World::new()
+    };
+    gs.ecs.register::<Position>();
+    gs.ecs.register::<Renderable>();
+    gs.ecs.register::<Player>();
+    gs.ecs
+        .create_entity()
+        .with(Position { x: 40, y: 25 })
+        .with(Renderable {
+            glyph: rltk::to_cp437('@'),
+            fg: RGB::named(rltk::YELLOW),
+            bg: RGB::named(rltk::BLACK),
+    })
+    .with(Player{})
+    .build();
+    gs.ecs.insert(new_map_rooms_and_corridors());
+
+    rltk::main_loop(context, gs)
+}

+ 89 - 0
src/map.rs

@@ -0,0 +1,89 @@
+use rltk::{ RGB, Rltk};
+use super::{Rect};
+use std::cmp::{max, min};
+
+#[derive(PartialEq, Copy, Clone)]
+pub enum TileType {
+    Wall, 
+    Floor
+}
+
+pub fn xy_idx(x: i32, y: i32) -> usize {
+    (y as usize * 80) + x as usize
+}
+
+/// Makes a map with solid boundaries and 400 randomly placed walls. No guarantees that it won't
+/// look awful.
+pub fn new_map_test() -> Vec<TileType> {
+    let mut map = vec![TileType::Floor; 80*50];
+
+    // Make the boundaries walls
+    for x in 0..80 {
+        map[xy_idx(x, 0)] = TileType::Wall;
+        map[xy_idx(x, 49)] = TileType::Wall;
+    }
+    for y in 0..50 {
+        map[xy_idx(0, y)] = TileType::Wall;
+        map[xy_idx(79, y)] = TileType::Wall;
+    }
+
+    // Now we'll randomly splat a bunch of walls. It won't be pretty, but it's a decent illustration.
+    // First, obtain the thread-local RNG:
+    let mut rng = rltk::RandomNumberGenerator::new();
+
+    for _i in 0..400 {
+        let x = rng.roll_dice(1, 79);
+        let y = rng.roll_dice(1, 49);
+        let idx = xy_idx(x, y);
+        if idx != xy_idx(40, 25) {
+            map[idx] = TileType::Wall;
+        }
+    }
+
+    return map
+}
+
+pub fn new_map_rooms_and_corridors() -> Vec<TileType> {
+    let mut map = vec![TileType::Wall; 80*50];
+
+    let room1 = Rect::new(20, 15, 10, 15);
+    let room2 = Rect::new(35, 15, 10, 15);
+
+    apply_room_to_map(&room1, &mut map);
+    apply_room_to_map(&room2, &mut map);
+
+    map
+}
+
+fn apply_room_to_map(room : &Rect, map: &mut [TileType]) {
+    for y in room.y1 +1 ..= room.y2 {
+        for x in room.x1 + 1 ..= room.x2 {
+            map[xy_idx(x, y)] = TileType::Floor;
+        }
+    }
+}
+
+pub fn draw_map(map: &[TileType], ctx : &mut Rltk) {
+    let mut y = 0;
+    let mut x = 0;
+    for tile in map.iter() {
+        // Render a tile depending upon the tile type
+        match tile {
+            TileType::Floor => {
+                ctx.set(x, y, RGB::from_f32(0.5, 0.5, 0.5), RGB::from_f32(0., 0., 0.), rltk::to_cp437('.'));
+            }
+            TileType::Wall => {
+                ctx.set(x, y, RGB::from_f32(0.0, 1.0, 0.0), RGB::from_f32(0., 0., 0.), rltk::to_cp437('#'));
+            }
+        }
+
+        // Move the coordinates
+        x += 1;
+        if x > 79 {
+            x = 0;
+            y += 1;
+        }
+    }
+}
+
+

+ 32 - 0
src/player.rs

@@ -0,0 +1,32 @@
+use rltk::{VirtualKeyCode, Rltk};
+use specs::prelude::*;
+use super::{Position, Player, TileType, xy_idx, State};
+use std::cmp::{min, max};
+
+pub fn try_move_player(delta_x: i32, delta_y: i32, ecs: &mut World) {
+    let mut positions = ecs.write_storage::<Position>();
+    let mut players = ecs.write_storage::<Player>();
+    let map = ecs.fetch::<Vec<TileType>>();
+
+    for (_player, pos) in (&mut players, &mut positions).join() {
+        let destination_idx = xy_idx(pos.x + delta_x, pos.y + delta_y);
+        if map[destination_idx] != TileType::Wall {
+            pos.x = min(79 , max(0, pos.x + delta_x));
+            pos.y = min(49, max(0, pos.y + delta_y));
+        }
+    }
+}
+
+pub fn player_input(gs: &mut State, ctx: &mut Rltk) {
+    // Player movement
+    match ctx.key {
+        None => {} // Nothing happened
+        Some(key) => match key {
+            VirtualKeyCode::A => try_move_player(-1, 0, &mut gs.ecs),
+            VirtualKeyCode::D => try_move_player(1, 0, &mut gs.ecs),
+            VirtualKeyCode::W => try_move_player(0, -1, &mut gs.ecs),
+            VirtualKeyCode::S => try_move_player(0, 1, &mut gs.ecs),
+            _ => {}
+        },
+    }
+}

+ 21 - 0
src/rect.rs

@@ -0,0 +1,21 @@
+pub struct Rect {
+    pub x1 : i32,
+    pub x2 : i32,
+    pub y1 : i32,
+    pub y2 : i32
+}
+
+impl Rect {
+    pub fn new(x:i32, y: i32, w:i32, h:i32) -> Rect {
+        Rect{x1:x, y1:y, x2:x+w, y2:y+h}
+    }
+
+    // Returns true if this overlaps with other
+    pub fn intersect(&self, other:&Rect) -> bool {
+        self.x1 <= other.x2 && self.x2 >= other.x1 && self.y1 <= other.y2 && self.y2 >= other.y1
+    }
+
+    pub fn center(&self) -> (i32, i32) {
+        ((self.x1 + self.x2)/2, (self.y1 + self.y2)/2)
+    }
+}