some tileset changes and some preliminary collision code
Getty Ritter
5 years ago
1 | 1 | <?xml version="1.0" encoding="UTF-8"?> |
2 | <tileset name="animaltransiro" tilewidth="24" tileheight="24" tilecount="1024" columns="32"> | |
3 | <image source="../tiles/spritesheet.png" width="768" height="768"/> | |
2 | <tileset version="1.2" tiledversion="1.2.3" name="animaltransiro" tilewidth="24" tileheight="24" tilecount="1024" columns="32"> | |
3 | <image source="spritesheet.png" width="768" height="768"/> | |
4 | 4 | <terraintypes> |
5 | 5 | <terrain name="Grass" tile="0"/> |
6 | 6 | <terrain name="Dirt" tile="70"/> |
1 | 1 | <?xml version="1.0" encoding="UTF-8"?> |
2 |
<map version="1. |
|
2 | <map version="1.2" tiledversion="1.2.3" orientation="orthogonal" renderorder="right-down" width="16" height="12" tilewidth="24" tileheight="24" infinite="0" nextlayerid="5" nextobjectid="10"> | |
3 | 3 | <properties> |
4 | 4 | <property name="south" value="south"/> |
5 | 5 | <property name="west" value="west"/> |
6 | 6 | </properties> |
7 | 7 | <tileset firstgid="1" source="animaltransiro.tsx"/> |
8 |
<layer |
|
8 | <layer id="1" name="tiles" width="16" height="12"> | |
9 | 9 | <data encoding="csv"> |
10 | 10 | 1,1,1,1,1,1,33,1,1,1,1,1,33,1,1,1, |
11 | 11 | 1,1,1,1,1,43,45,1,1,1,1,1,1,43,44,45, |
15 | 15 | 44,79,77,1,1,1,75,76,77,1,70,73,40,75,77,1, |
16 | 16 | 76,76,78,45,1,33,107,108,109,1,70,71,72,107,109,1, |
17 | 17 | 76,76,46,109,1,1,38,39,39,39,74,71,72,33,1,1, |
18 | 108,108,109,1,1,38,74,41,103,42,71,41,104,1,1,1, | |
19 | 1,1,1,1,38,74,71,72,38,74,41,104,1,1,33,1, | |
20 |
1 |
|
18 | 108,108,109,1,1,38,74,103,42,71,71,41,104,1,1,1, | |
19 | 1,1,1,1,38,74,72,1,70,71,41,104,1,1,33,1, | |
20 | 1,1,33,1,102,103,73,39,74,41,104,1,1,1,1,1, | |
21 | 21 | 1,1,1,1,1,1,70,71,71,72,1,1,1,1,1,1 |
22 | 22 | </data> |
23 | 23 | </layer> |
24 |
<layer |
|
24 | <layer id="2" name="entities" width="16" height="12"> | |
25 | 25 | <data encoding="csv"> |
26 | 26 | 0,26,27,28,29,0,0,0,30,31,32,0,0,0,0,0, |
27 | 27 | 0,58,59,60,61,0,0,37,62,63,64,0,0,0,0,0, |
37 | 37 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 |
38 | 38 | </data> |
39 | 39 | </layer> |
40 |
<layer |
|
40 | <layer id="3" name="decoration" width="16" height="12"> | |
41 | 41 | <data encoding="csv"> |
42 | 42 | 0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0, |
43 | 43 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, |
53 | 53 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 |
54 | 54 | </data> |
55 | 55 | </layer> |
56 |
<objectgroup |
|
56 | <objectgroup id="4" name="meta"> | |
57 | 57 | <object id="2" x="96" y="72" width="24" height="24"> |
58 | 58 | <properties> |
59 | 59 | <property name="signText" value="Bonvenon al la kafejo!"/> |
Binary diff not shown
1 | use specs::{Component, VecStorage, NullStorage}; | |
2 | ||
3 | /// Register all the components with the world. | |
4 | pub fn register(world: &mut specs::World) { | |
5 | world.register::<Position>(); | |
6 | world.register::<Velocity>(); | |
7 | world.register::<Sprite>(); | |
8 | world.register::<Background>(); | |
9 | world.register::<Foreground>(); | |
10 | world.register::<Decoration>(); | |
11 | world.register::<Controlled>(); | |
12 | world.register::<Collision>(); | |
13 | world.register::<Blocking>(); | |
14 | } | |
15 | ||
16 | /// The `Position` component represents (in world coordinates) a thing | |
17 | /// that has a position in the world, measured from the top-left of | |
18 | /// the thing. | |
19 | #[derive(Component, Debug)] | |
20 | #[storage(VecStorage)] | |
21 | pub struct Position { | |
22 | pub x: f32, | |
23 | pub y: f32, | |
24 | } | |
25 | ||
26 | impl Position { | |
27 | /// Convert a `Position` to a screen point | |
28 | pub fn to_point(&self) -> ggez::nalgebra::Point2<f32> { | |
29 | ggez::nalgebra::Point2::new(self.x * 3.0, self.y * 3.0) | |
30 | } | |
31 | ||
32 | pub fn to_grid(&self) -> (i32, i32) { | |
33 | ((self.x / 24.0) as i32, | |
34 | (self.y / 24.0) as i32, | |
35 | ) | |
36 | } | |
37 | ||
38 | pub fn moved(&self, vel: &Velocity) -> Position { | |
39 | Position { | |
40 | x: self.x + vel.dx, | |
41 | y: self.x + vel.dy, | |
42 | } | |
43 | } | |
44 | } | |
45 | ||
46 | /// The `Velocity` componenent is present on any entity that moves | |
47 | /// through the world, and represents its rate of change per | |
48 | /// time-unit. | |
49 | #[derive(Component, Debug)] | |
50 | #[storage(VecStorage)] | |
51 | pub struct Velocity { | |
52 | pub dx: f32, | |
53 | pub dy: f32, | |
54 | } | |
55 | ||
56 | ||
57 | /// The `Sprite` components represents the current display location of | |
58 | /// a sprite in the spritesheet. | |
59 | #[derive(Component, Debug)] | |
60 | #[storage(VecStorage)] | |
61 | pub struct Sprite { | |
62 | pub u: u8, | |
63 | pub v: u8, | |
64 | } | |
65 | ||
66 | impl Sprite { | |
67 | /// Convert a `Sprite` into the rectangle that specifies the | |
68 | /// sprite location on the spritesheet | |
69 | pub fn to_rect(&self) -> ggez::graphics::Rect { | |
70 | ggez::graphics::Rect { | |
71 | x: (1.0 / 32.0) * self.u as f32, | |
72 | y: (1.0 / 32.0) * self.v as f32, | |
73 | w: 1.0 / 32.0, | |
74 | h: 1.0 / 32.0, | |
75 | } | |
76 | } | |
77 | } | |
78 | ||
79 | /// A drawing-phase component: represents tiles that appear in the | |
80 | /// background of everything. | |
81 | #[derive(Component, Default, Debug)] | |
82 | #[storage(NullStorage)] | |
83 | pub struct Background; | |
84 | ||
85 | /// A drawing-phase component: represents tiles which appear in the | |
86 | /// foreground, possibly entities. | |
87 | #[derive(Component, Default, Debug)] | |
88 | #[storage(NullStorage)] | |
89 | pub struct Foreground; | |
90 | ||
91 | /// A drawing-phase component: represents tiles which appear on top of | |
92 | /// everything else, such as the tops of trees or roofs of houses. | |
93 | #[derive(Component, Default, Debug)] | |
94 | #[storage(NullStorage)] | |
95 | pub struct Decoration; | |
96 | ||
97 | /// A component that represents entities which are controlled by the | |
98 | /// keyboard. | |
99 | #[derive(Component, Default, Debug)] | |
100 | #[storage(NullStorage)] | |
101 | pub struct Controlled; | |
102 | ||
103 | /// A component that represents entities which can collide with other | |
104 | /// things. | |
105 | #[derive(Component, Debug)] | |
106 | #[storage(VecStorage)] | |
107 | pub struct Collision { | |
108 | pub has_collision: bool | |
109 | } | |
110 | ||
111 | #[derive(Component, Default, Debug)] | |
112 | #[storage(NullStorage)] | |
113 | pub struct Blocking; |
1 | use specs::{Component, VecStorage, NullStorage}; | |
2 | ||
3 | /// Register all the components with the world. | |
4 | pub fn register(world: &mut specs::World) { | |
5 | world.register::<Position>(); | |
6 | world.register::<Velocity>(); | |
7 | world.register::<Sprite>(); | |
8 | world.register::<Background>(); | |
9 | world.register::<Foreground>(); | |
10 | world.register::<Decoration>(); | |
11 | world.register::<Controlled>(); | |
12 | } | |
13 | ||
14 | /// The `Position` component represents (in world coordinates) a thing | |
15 | /// that has a position in the world, measured from the top-left of | |
16 | /// the thing. | |
17 | #[derive(Component, Debug)] | |
18 | #[storage(VecStorage)] | |
19 | pub struct Position { | |
20 | pub x: f32, | |
21 | pub y: f32, | |
22 | } | |
23 | ||
24 | impl Position { | |
25 | /// Convert a `Position` to a screen point | |
26 | pub fn to_point(&self) -> ggez::nalgebra::Point2<f32> { | |
27 | ggez::nalgebra::Point2::new(self.x * 3.0, self.y * 3.0) | |
28 | } | |
29 | } | |
30 | ||
31 | /// The `Velocity` componenent is present on any entity that moves | |
32 | /// through the world, and represents its rate of change per | |
33 | /// time-unit. | |
34 | #[derive(Component, Debug)] | |
35 | #[storage(VecStorage)] | |
36 | pub struct Velocity { | |
37 | pub dx: f32, | |
38 | pub dy: f32, | |
39 | } | |
40 | ||
41 | ||
42 | /// The `Sprite` components represents the current display location of | |
43 | /// a sprite in the spritesheet. | |
44 | #[derive(Component, Debug)] | |
45 | #[storage(VecStorage)] | |
46 | pub struct Sprite { | |
47 | pub u: u8, | |
48 | pub v: u8, | |
49 | } | |
50 | ||
51 | impl Sprite { | |
52 | /// Convert a `Sprite` into the rectangle that specifies the | |
53 | /// sprite location on the spritesheet | |
54 | pub fn to_rect(&self) -> ggez::graphics::Rect { | |
55 | ggez::graphics::Rect { | |
56 | x: (1.0 / 32.0) * self.u as f32, | |
57 | y: (1.0 / 32.0) * self.v as f32, | |
58 | w: 1.0 / 32.0, | |
59 | h: 1.0 / 32.0, | |
60 | } | |
61 | } | |
62 | } | |
63 | ||
64 | /// A drawing-phase component: represents tiles that appear in the | |
65 | /// background of everything. | |
66 | #[derive(Component, Default, Debug)] | |
67 | #[storage(NullStorage)] | |
68 | pub struct Background; | |
69 | ||
70 | /// A drawing-phase component: represents tiles which appear in the | |
71 | /// foreground, possibly entities. | |
72 | #[derive(Component, Default, Debug)] | |
73 | #[storage(NullStorage)] | |
74 | pub struct Foreground; | |
75 | ||
76 | /// A drawing-phase component: represents tiles which appear on top of | |
77 | /// everything else, such as the tops of trees or roofs of houses. | |
78 | #[derive(Component, Default, Debug)] | |
79 | #[storage(NullStorage)] | |
80 | pub struct Decoration; | |
81 | ||
82 | /// A component that represents entities which are controlled by the | |
83 | /// keyboard. | |
84 | #[derive(Component, Default, Debug)] | |
85 | #[storage(NullStorage)] | |
86 | pub struct Controlled; | |
87 | ||
88 | /// A component that represents entities which can collide with other | |
89 | /// things. | |
90 | #[derive(Component, Debug)] | |
91 | #[storage(VecStorage)] | |
92 | pub struct Collision { | |
93 | pub has_collision: bool | |
94 | } |
10 | 10 | use sdl2::keyboard as sdl; |
11 | 11 | |
12 | 12 | pub mod consts; |
13 |
pub mod com |
|
13 | pub mod com; | |
14 | 14 | pub mod game; |
15 | 15 | pub mod res; |
16 | 16 | pub mod sys; |
18 | 18 | use game::MyGame; |
19 | 19 | |
20 | 20 | impl EventHandler for MyGame { |
21 | ||
22 | 21 | fn update(&mut self, _ctx: &mut Context) -> GameResult<()> { |
23 | 22 | sys::input::systems(self); |
24 | 23 | sys::physics::systems(self); |
55 | 54 | |
56 | 55 | fn main() -> Result<(), ggez::error::GameError> { |
57 | 56 | let mut world = specs::World::new(); |
58 |
com |
|
57 | com::register(&mut world); | |
59 | 58 | |
60 | 59 | res::world_from_file(&mut world, "assets/main.tmx"); |
61 | 60 |
1 | 1 | use crate::consts; |
2 |
use crate::com |
|
2 | use crate::com::*; | |
3 | 3 | |
4 | 4 | use specs::world::Builder; |
5 | 5 | use std::path::Path; |
47 | 47 | pub fn world_from_file<P: AsRef<Path>>(w: &mut specs::World, path: P) { |
48 | 48 | let tiled::Map { |
49 | 49 | layers, |
50 | tilesets, | |
50 | 51 | .. |
51 | 52 | } = tiled::parse_file(path.as_ref()).unwrap(); |
52 | 53 | |
66 | 67 | DrawLayer::Foreground => e.with(Foreground), |
67 | 68 | DrawLayer::Decoration => e.with(Decoration), |
68 | 69 | }; |
70 | ||
71 | let e = if tilesets[0].tiles[n as usize].properties["pass"] == | |
72 | tiled::PropertyValue::BoolValue(false) { | |
73 | e.with(Blocking) | |
74 | } else { | |
75 | e | |
76 | }; | |
69 | 77 | e.build(); |
70 | 78 | } |
71 | 79 | } |
82 | 90 | .with(Velocity { dx: 0.0, dy: 0.0 }) |
83 | 91 | .with(Foreground) |
84 | 92 | .with(Controlled) |
93 | .with(Collision { has_collision: false }) | |
85 | 94 | .build(); |
86 | 95 | } |
1 | 1 | use crate::consts; |
2 |
use crate::com |
|
2 | use crate::com::{self,Position,Sprite}; | |
3 | 3 | use crate::game::MyGame; |
4 | 4 | |
5 | 5 | use ggez::{ |
53 | 53 | |
54 | 54 | Draw { |
55 | 55 | ctx, |
56 |
_phase: com |
|
56 | _phase: com::Background, | |
57 | 57 | }.run_now(&game.world.res); |
58 | 58 | Draw { |
59 | 59 | ctx, |
60 |
_phase: com |
|
60 | _phase: com::Foreground, | |
61 | 61 | }.run_now(&game.world.res); |
62 | 62 | Draw { |
63 | 63 | ctx, |
64 |
_phase: com |
|
64 | _phase: com::Decoration, | |
65 | 65 | }.run_now(&game.world.res); |
66 | 66 | |
67 | 67 | graphics::present(ctx); |
1 |
use crate::com |
|
1 | use crate::com::{Controlled, Velocity}; | |
2 | 2 | use crate::game::MyGame; |
3 | 3 | use crate::res::KeySet; |
4 | 4 |
1 |
use crate::com |
|
1 | use crate::com::{Blocking, Collision, Velocity, Position}; | |
2 | 2 | use crate::game::MyGame; |
3 | 3 | |
4 |
use specs:: |
|
4 | use specs::{Join,RunNow}; | |
5 | ||
6 | struct Intersection; | |
7 | ||
8 | impl<'a> specs::System<'a> for Intersection { | |
9 | type SystemData = ( | |
10 | specs::Entities<'a>, | |
11 | specs::ReadStorage<'a, Position>, | |
12 | specs::ReadStorage<'a, Velocity>, | |
13 | specs::ReadStorage<'a, Blocking>, | |
14 | specs::WriteStorage<'a, Collision>, | |
15 | ); | |
16 | ||
17 | fn run(&mut self, (entity, position, velocity, blocking, mut collision): Self::SystemData) { | |
18 | let mut spacemap = std::collections::HashMap::new(); | |
19 | for (e, pos, _) in (&entity, &position, &blocking).join() { | |
20 | spacemap.insert(pos.to_grid(), e); | |
21 | } | |
22 | ||
23 | for (pos, vel, col) in (&position, &velocity, &mut collision).join() { | |
24 | if let Some(_) = spacemap.get(&pos.moved(vel).to_grid()) { | |
25 | col.has_collision = true; | |
26 | } | |
27 | } | |
28 | } | |
29 | } | |
5 | 30 | |
6 | 31 | struct Physics; |
7 | 32 | |
8 | 33 | impl <'a> specs::System<'a> for Physics { |
9 | 34 | type SystemData = ( |
10 | 35 | specs::ReadStorage<'a, Velocity>, |
36 | specs::ReadStorage<'a, Collision>, | |
11 | 37 | specs::WriteStorage<'a, Position>, |
12 | 38 | ); |
13 | 39 | |
14 | fn run(&mut self, (velocity, mut position): Self::SystemData) { | |
15 | use specs::Join; | |
16 | ||
17 | for (vel, pos) in (&velocity, &mut position).join() { | |
18 | pos.x += vel.dx; | |
19 | pos.y += vel.dy; | |
40 | fn run(&mut self, (velocity, collision, mut position): Self::SystemData) { | |
41 | for (vel, col, pos) in (&velocity, &collision, &mut position).join() { | |
42 | if !col.has_collision { | |
43 | pos.x += vel.dx; | |
44 | pos.y += vel.dy; | |
45 | } | |
20 | 46 | } |
21 | 47 | } |
22 | 48 | } |
23 | 49 | |
50 | struct ResetCollision; | |
51 | ||
52 | impl<'a> specs::System<'a> for ResetCollision { | |
53 | type SystemData = | |
54 | specs::WriteStorage<'a, Collision>; | |
55 | ||
56 | fn run(&mut self, mut collision: Self::SystemData) { | |
57 | for mut e in (&mut collision).join() { | |
58 | e.has_collision = false; | |
59 | } | |
60 | } | |
61 | } | |
24 | 62 | |
25 | 63 | pub fn systems(game: &mut MyGame) { |
64 | Intersection.run_now(&game.world.res); | |
26 | 65 | Physics.run_now(&game.world.res); |
66 | ResetCollision.run_now(&game.world.res); | |
27 | 67 | } |