Commit | Line | Data |
---|---|---|
8012f86b | 1 | use common::{Point, Dimension, Intersection, supercover_line}; |
79914631 TW |
2 | use core::render::Renderer; |
3 | use sprites::SpriteManager; | |
1f42d724 TW |
4 | use std::rc::Rc; |
5 | use {point, dimen}; | |
79914631 TW |
6 | |
7 | mod lvlgen; | |
8 | ||
9 | pub use self::lvlgen::LevelGenerator; | |
10 | ||
11 | ////////// LEVEL /////////////////////////////////////////////////////////////// | |
12 | ||
13 | #[derive(Default)] | |
14 | pub struct Level { | |
e570927a | 15 | pub gravity: Point<f64>, |
37f3e1ed | 16 | pub grid: Grid<bool>, |
1f42d724 TW |
17 | walls: Vec<Rc<WallRegion>>, |
18 | wall_grid: Grid<Vec<Rc<WallEdge>>>, | |
79914631 TW |
19 | } |
20 | ||
21 | impl Level { | |
1f42d724 TW |
22 | pub fn new(gravity: Point<f64>, grid: Grid<bool>, mut walls: Vec<Rc<WallRegion>>) -> Self { |
23 | let size = (2560, 1440); // TODO: get actual size from walls or something | |
24 | let wall_grid = Level::build_wall_grid(&mut walls, &size.into()); | |
25 | dbg!(&wall_grid.cell_size); | |
26 | Level { | |
27 | gravity, | |
28 | grid, | |
29 | walls, | |
30 | wall_grid, | |
31 | } | |
32 | } | |
33 | ||
34 | /// Creates a grid of wall edges for fast lookup | |
d01df1fc | 35 | fn build_wall_grid(walls: &mut Vec<WallRegion>, lvlsize: &Dimension<usize>) -> Grid<Vec<Rc<WallEdge>>> { |
1f42d724 TW |
36 | let size = dimen!(lvlsize.width / 20, lvlsize.height / 20); // TODO: make sure all walls fit within the grid bounds |
37 | let cs = point!(lvlsize.width / size.width, lvlsize.height / size.height); | |
38 | //let cs = point!(cell_size.width as f64, cell_size.height as f64); | |
8012f86b TW |
39 | let mut grid = Grid { |
40 | cells: vec!(vec!(vec!(); size.height); size.width), | |
41 | size, | |
42 | cell_size: dimen!(cs.x, cs.y), | |
43 | }; | |
1f42d724 TW |
44 | |
45 | for wall in walls { | |
46 | for edge in &wall.edges { | |
8012f86b TW |
47 | for c in grid.grid_coordinates_on_line(edge.p1, edge.p2) { |
48 | grid.cells[c.x][c.y].push(Rc::clone(edge)); | |
1f42d724 TW |
49 | } |
50 | } | |
51 | } | |
52 | ||
8012f86b | 53 | grid |
1f42d724 | 54 | } |
79914631 TW |
55 | |
56 | pub fn render(&mut self, renderer: &mut Renderer, _sprites: &SpriteManager) { | |
1f42d724 | 57 | // original grid |
79914631 | 58 | renderer.canvas().set_draw_color((64, 64, 64)); |
1f42d724 TW |
59 | let size = &self.grid.cell_size; |
60 | for x in 0..self.grid.size.width { | |
61 | for y in 0..self.grid.size.height { | |
79914631 | 62 | if self.grid.cells[x][y] { |
1f42d724 TW |
63 | renderer.canvas().fill_rect(sdl2::rect::Rect::new( |
64 | x as i32 * size.width as i32, | |
65 | y as i32 * size.height as i32, | |
66 | size.width as u32, | |
67 | size.height as u32)).unwrap(); | |
68 | } | |
69 | } | |
70 | } | |
71 | ||
72 | // wall grid | |
73 | renderer.canvas().set_draw_color((0, 32, 0)); | |
74 | let size = &self.wall_grid.cell_size; | |
75 | for x in 0..self.wall_grid.size.width { | |
76 | for y in 0..self.wall_grid.size.height { | |
77 | if !self.wall_grid.cells[x][y].is_empty() { | |
8012f86b TW |
78 | let num = self.wall_grid.cells[x][y].len(); |
79 | renderer.canvas().set_draw_color((0, 32*num as u8, 0)); | |
1f42d724 TW |
80 | renderer.canvas().fill_rect(sdl2::rect::Rect::new( |
81 | x as i32 * size.width as i32, | |
82 | y as i32 * size.height as i32, | |
83 | size.width as u32, | |
84 | size.height as u32)).unwrap(); | |
79914631 TW |
85 | } |
86 | } | |
87 | } | |
88 | ||
1f42d724 | 89 | // walls |
79914631 | 90 | for wall in &self.walls { |
1f42d724 TW |
91 | for e in &wall.edges { |
92 | renderer.draw_line( | |
93 | <(i32, i32)>::from(e.p1.to_i32()), | |
94 | <(i32, i32)>::from(e.p2.to_i32()), | |
95 | (255, 255, 0)); | |
79914631 | 96 | } |
79914631 TW |
97 | } |
98 | } | |
60058b91 TW |
99 | |
100 | pub fn intersect_walls(&self, p1: Point<f64>, p2: Point<f64>) -> IntersectResult { | |
8012f86b TW |
101 | for c in self.wall_grid.grid_coordinates_on_line(p1, p2) { |
102 | if let walls = &self.wall_grid.cells[c.x][c.y] { | |
103 | for w in walls { | |
104 | if let Intersection::Point(p) = Intersection::lines(p1, p2, w.p1, w.p2) { | |
105 | let wall = Wall { | |
106 | region: &self.walls[w.region], | |
d01df1fc | 107 | edge: w, |
8012f86b TW |
108 | }; |
109 | return IntersectResult::Intersection(wall, p) | |
110 | } | |
60058b91 TW |
111 | } |
112 | } | |
113 | } | |
114 | IntersectResult::None | |
115 | } | |
116 | } | |
117 | ||
d01df1fc TW |
118 | pub enum IntersectResult<'a> { |
119 | Intersection(Wall<'a>, Point<f64>), | |
60058b91 | 120 | None |
79914631 TW |
121 | } |
122 | ||
123 | ////////// GRID //////////////////////////////////////////////////////////////// | |
124 | ||
1f42d724 | 125 | #[derive(Debug, Default)] |
37f3e1ed | 126 | pub struct Grid<T> { |
1f42d724 TW |
127 | pub size: Dimension<usize>, |
128 | pub cell_size: Dimension<usize>, | |
37f3e1ed | 129 | pub cells: Vec<Vec<T>>, |
79914631 | 130 | } |
1f42d724 | 131 | |
60058b91 TW |
132 | impl<T> Grid<T> { |
133 | pub fn at<C>(&self, c: C) -> Option<&T> | |
134 | where C: Into<(isize, isize)> | |
135 | { | |
136 | let c = c.into(); | |
137 | if c.0 >= 0 && c.0 < self.size.width as isize && c.1 >= 0 && c.1 < self.size.height as isize { | |
138 | Some(&self.cells[c.0 as usize][c.1 as usize]) | |
139 | } else { | |
140 | None | |
141 | } | |
142 | } | |
8012f86b TW |
143 | |
144 | pub fn to_grid_coordinate<C>(&self, c: C) -> Option<Point<usize>> | |
145 | where C: Into<(isize, isize)> | |
146 | { | |
147 | let c = c.into(); | |
148 | if c.0 >= 0 && c.0 < self.size.width as isize && c.1 >= 0 && c.1 < self.size.height as isize { | |
149 | Some(point!(c.0 as usize, c.1 as usize)) | |
150 | } else { | |
151 | None | |
152 | } | |
153 | } | |
154 | ||
155 | /// Returns a list of grid coordinates that a line in world coordinates passes through. | |
156 | pub fn grid_coordinates_on_line(&self, p1: Point<f64>, p2: Point<f64>) -> Vec<Point<usize>> { | |
157 | let scale = (self.cell_size.width as f64, self.cell_size.height as f64); | |
158 | supercover_line(p1 / scale, p2 / scale) | |
159 | .iter() | |
160 | .map(|c| self.to_grid_coordinate(*c)) | |
161 | .flatten() | |
162 | .collect() | |
163 | } | |
60058b91 TW |
164 | } |
165 | ||
1f42d724 TW |
166 | ////////// WALL REGION ///////////////////////////////////////////////////////// |
167 | ||
168 | #[derive(Debug)] | |
169 | pub struct WallRegion { | |
170 | edges: Vec<Rc<WallEdge>>, | |
171 | } | |
172 | ||
173 | impl WallRegion { | |
d01df1fc TW |
174 | pub fn new(points: Vec<Point<f64>>) -> Self { |
175 | let index: RegionIndex = 0; // use as param | |
60058b91 | 176 | let mut edges = Vec::with_capacity(points.len()); |
1f42d724 TW |
177 | |
178 | for i in 0..points.len() { | |
179 | let edge = Rc::new(WallEdge { | |
d01df1fc TW |
180 | region: index, |
181 | id: i, | |
1f42d724 TW |
182 | p1: points[i], |
183 | p2: points[(i + 1) % points.len()], | |
184 | }); | |
185 | edges.push(edge); | |
186 | } | |
187 | ||
d01df1fc | 188 | WallRegion { edges } |
1f42d724 TW |
189 | } |
190 | ||
d01df1fc TW |
191 | // #[allow(dead_code)] |
192 | // fn next(&self, index: EdgeIndex) -> Rc<WallEdge> { | |
193 | // let index = (index + 1) % self.edges.len(); | |
194 | // Rc::clone(&self.edges[index]) | |
195 | // } | |
196 | ||
197 | // #[allow(dead_code)] | |
198 | // fn previous(&self, index: EdgeIndex) -> Rc<WallEdge> { | |
199 | // let index = (index + self.edges.len() + 1) % self.edges.len(); | |
200 | // Rc::clone(&self.edges[index]) | |
201 | // } | |
1f42d724 TW |
202 | } |
203 | ||
204 | ////////// WALL EDGE /////////////////////////////////////////////////////////// | |
205 | ||
d01df1fc TW |
206 | type RegionIndex = usize; |
207 | type EdgeIndex = usize; | |
208 | ||
1f42d724 TW |
209 | #[derive(Debug, Default)] |
210 | struct WallEdge { | |
d01df1fc TW |
211 | region: RegionIndex, |
212 | id: EdgeIndex, | |
1f42d724 TW |
213 | pub p1: Point<f64>, |
214 | pub p2: Point<f64>, | |
215 | } | |
60058b91 TW |
216 | |
217 | ////////// WALL //////////////////////////////////////////////////////////////// | |
218 | ||
d01df1fc TW |
219 | /// kommer det här att fungera ifall nåt objekt ska spara en referens till Wall? |
220 | /// kanske istället ska lägga Vec<WallRegion> i en Rc<Walls> och skicka med en klon av den, samt id:n till regionen och väggen? | |
221 | pub struct Wall<'a> { | |
222 | region: &'a WallRegion, | |
223 | edge: &'a WallEdge, | |
224 | } | |
225 | ||
226 | impl<'a> Wall<'a> { | |
227 | pub fn next(&self) -> Wall<'a> { | |
228 | let next = (self.edge.id + 1) % self.region.edges.len(); | |
229 | let edge = &self.region.edges[next]; | |
230 | Wall { | |
231 | region: self.region, | |
232 | edge, | |
233 | } | |
234 | } | |
235 | ||
236 | pub fn previous(&self) -> Wall<'a> { | |
237 | let prev = (self.edge.id + self.region.edges.len() - 1) % self.region.edges.len(); | |
238 | let edge = &self.region.edges[prev]; | |
239 | Wall { | |
240 | region: self.region, | |
241 | edge, | |
242 | } | |
243 | } | |
60058b91 | 244 | } |