commit
955274e68f
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -1,4 +1,6 @@
|
||||||
/target
|
/target
|
||||||
/demo/target
|
/demo/target
|
||||||
Cargo.lock
|
Cargo.lock
|
||||||
.vscode/
|
.vscode/
|
||||||
|
pkg/
|
||||||
|
package-lock.json
|
14
README.md
14
README.md
|
@ -6,16 +6,9 @@
|
||||||
|
|
||||||
Generate procedural maps for games.
|
Generate procedural maps for games.
|
||||||
|
|
||||||
This library is based on the code from the [Roguelike tutorial](https://github.com/thebracket/rustrogueliketutorial).
|
|
||||||
I highly recommend it for learning how to write Roguelike in Rust.
|
|
||||||
|
|
||||||
|
|
||||||
## Demo app
|
## Demo app
|
||||||
|
|
||||||
If you want to check how the maps look like, then:
|
Check [demo app](https://klangner.github.io/mapgen.rs/)
|
||||||
* Clone this rep
|
|
||||||
* Go to the demo folder
|
|
||||||
* Run demo app (`cargo run`)
|
|
||||||
|
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
@ -80,6 +73,11 @@ let map = MapBuilder::new(Box::new(CellularAutomataGen::new(80, 50)))
|
||||||
|
|
||||||
For more information check the [doc](https://docs.rs/mapgen)
|
For more information check the [doc](https://docs.rs/mapgen)
|
||||||
|
|
||||||
|
|
||||||
|
This library is based on the code from the [Roguelike tutorial](https://github.com/thebracket/rustrogueliketutorial).
|
||||||
|
I highly recommend it for learning how to write Roguelike in Rust.
|
||||||
|
|
||||||
|
|
||||||
# License
|
# License
|
||||||
|
|
||||||
Licensed under either of
|
Licensed under either of
|
||||||
|
|
|
@ -2,15 +2,26 @@
|
||||||
name = "mapgen-demo"
|
name = "mapgen-demo"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
authors = ["Krzysztof Langner <klangner@gmail.com>"]
|
authors = ["Krzysztof Langner <klangner@gmail.com>"]
|
||||||
|
description = "Map generator demo"
|
||||||
|
license = "MIT OR Apache-2.0"
|
||||||
|
repository = "https://github.com/klangner/mapgen.rs"
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[lib]
|
||||||
rand = "0.7"
|
crate-type = ["cdylib"]
|
||||||
amethyst = {version = "0.15", features = ["tiles", "no-slow-safety-checks"]}
|
|
||||||
log = { version = "0.4.8", features = ["serde"] }
|
|
||||||
mapgen = {path=".."}
|
|
||||||
|
|
||||||
[features]
|
[dependencies]
|
||||||
default = ["metal"]
|
rand = { version = "0.7", features = ["wasm-bindgen"] }
|
||||||
metal = ["amethyst/metal"]
|
mapgen = {path=".."}
|
||||||
vulkan = ["amethyst/vulkan"]
|
wasm-bindgen = "0.2"
|
||||||
|
js-sys = "0.3"
|
||||||
|
|
||||||
|
[dependencies.web-sys]
|
||||||
|
version = "0.3.4"
|
||||||
|
features = [
|
||||||
|
'Document',
|
||||||
|
'Element',
|
||||||
|
'HtmlElement',
|
||||||
|
'Node',
|
||||||
|
'Window',
|
||||||
|
]
|
201
demo/LICENSE-APACHE
Normal file
201
demo/LICENSE-APACHE
Normal file
|
@ -0,0 +1,201 @@
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright 2017 Krzysztof Langner
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
|
@ -1,6 +1,12 @@
|
||||||
# Demo application for mapgen
|
# Demo application for mapgen
|
||||||
|
|
||||||
|
## Build the project:
|
||||||
|
|
||||||
|
```
|
||||||
|
wasm-pack build
|
||||||
|
cd www
|
||||||
|
npm run build
|
||||||
|
```
|
||||||
|
|
||||||
This app uses:
|
This app uses:
|
||||||
* [Urizen OneBit Tilesets](https://vurmux.itch.io/urizen-onebit-tilesets)
|
* [Urizen OneBit Tilesets](https://vurmux.itch.io/urizen-onebit-tilesets)
|
|
@ -1,4 +0,0 @@
|
||||||
(
|
|
||||||
title: "mapgen demo",
|
|
||||||
dimensions: Some((840, 520)),
|
|
||||||
)
|
|
|
@ -1,27 +0,0 @@
|
||||||
|
|
||||||
(
|
|
||||||
axes: {
|
|
||||||
"camera_x": Emulated(
|
|
||||||
pos: Key(D),
|
|
||||||
neg: Key(A),
|
|
||||||
),
|
|
||||||
"camera_y": Emulated(
|
|
||||||
pos: Key(W),
|
|
||||||
neg: Key(S),
|
|
||||||
),
|
|
||||||
"camera_scale": Emulated(
|
|
||||||
pos: Key(E),
|
|
||||||
neg: Key(Q),
|
|
||||||
),
|
|
||||||
"camera_z": Emulated(
|
|
||||||
pos: Key(R),
|
|
||||||
neg: Key(F),
|
|
||||||
),
|
|
||||||
},
|
|
||||||
actions: {
|
|
||||||
"camera_switch": [[Key(Space)]],
|
|
||||||
"select": [[Mouse(Left)]],
|
|
||||||
"toggle_rotation": [[Key(Y)]],
|
|
||||||
"toggle_translation": [[Key(T)]],
|
|
||||||
},
|
|
||||||
)
|
|
59
demo/index.html
Normal file
59
demo/index.html
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta content="text/html;charset=utf-8" http-equiv="Content-Type" />
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<!-- Note the usage of `type=module` here as this is an ES6 module -->
|
||||||
|
<script type="module">
|
||||||
|
// Use ES module import syntax to import functionality from the module
|
||||||
|
// that we have compiled.
|
||||||
|
//
|
||||||
|
// Note that the `default` import is an initialization function which
|
||||||
|
// will "boot" the module and make it ready to use. Currently browsers
|
||||||
|
// don't support natively imported WebAssembly as an ES module, but
|
||||||
|
// eventually the manual initialization won't be required!
|
||||||
|
import init, { add } from './pkg/mapgen_demo.js';
|
||||||
|
|
||||||
|
async function run() {
|
||||||
|
// First up we need to actually load the wasm file, so we use the
|
||||||
|
// default export to inform it where the wasm file is located on the
|
||||||
|
// server, and then we wait on the returned promise to wait for the
|
||||||
|
// wasm to be loaded.
|
||||||
|
//
|
||||||
|
// It may look like this: `await init('./pkg/without_a_bundler_bg.wasm');`,
|
||||||
|
// but there is also a handy default inside `init` function, which uses
|
||||||
|
// `import.meta` to locate the wasm file relatively to js file.
|
||||||
|
//
|
||||||
|
// Note that instead of a string you can also pass in any of the
|
||||||
|
// following things:
|
||||||
|
//
|
||||||
|
// * `WebAssembly.Module`
|
||||||
|
//
|
||||||
|
// * `ArrayBuffer`
|
||||||
|
//
|
||||||
|
// * `Response`
|
||||||
|
//
|
||||||
|
// * `Promise` which returns any of the above, e.g. `fetch("./path/to/wasm")`
|
||||||
|
//
|
||||||
|
// This gives you complete control over how the module is loaded
|
||||||
|
// and compiled.
|
||||||
|
//
|
||||||
|
// Also note that the promise, when resolved, yields the wasm module's
|
||||||
|
// exports which is the same as importing the `*_bg` module in other
|
||||||
|
// modes
|
||||||
|
await init();
|
||||||
|
|
||||||
|
// And afterwards we can use all the functionality defined in wasm.
|
||||||
|
const result = add(1, 2);
|
||||||
|
console.log(`1 + 2 = ${result}`);
|
||||||
|
if (result !== 3)
|
||||||
|
throw new Error("wasm addition doesn't work!");
|
||||||
|
}
|
||||||
|
|
||||||
|
run();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
56
demo/src/lib.rs
Normal file
56
demo/src/lib.rs
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
use wasm_bindgen::prelude::*;
|
||||||
|
use rand::prelude::*;
|
||||||
|
use js_sys::Date;
|
||||||
|
use mapgen::dungeon::{
|
||||||
|
MapBuilder,
|
||||||
|
map::TileType,
|
||||||
|
cellular_automata::CellularAutomataGen,
|
||||||
|
starting_point::{AreaStartingPosition, XStart, YStart},
|
||||||
|
cull_unreachable::CullUnreachable,
|
||||||
|
distant_exit::DistantExit,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub struct World {
|
||||||
|
width: u32,
|
||||||
|
height: u32,
|
||||||
|
tiles: Vec<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
impl World {
|
||||||
|
pub fn new(width: u32, height: u32) -> World {
|
||||||
|
let seed = Date::new_0().get_time() as u64;
|
||||||
|
let mut rng = StdRng::seed_from_u64(seed);
|
||||||
|
let map = MapBuilder::new(Box::new(CellularAutomataGen::new(width as usize, height as usize)))
|
||||||
|
.with(AreaStartingPosition::new(XStart::CENTER, YStart::CENTER))
|
||||||
|
.with(CullUnreachable::new())
|
||||||
|
.with(DistantExit::new())
|
||||||
|
.build_map_with_rng(&mut rng);
|
||||||
|
let tiles = (0..map.tiles.len()).map(|i| map.tiles[i] == TileType::Floor).collect();
|
||||||
|
World {
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
tiles }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn width(&self) -> u32 {
|
||||||
|
self.width
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn height(&self) -> u32 {
|
||||||
|
self.height
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tiles(&self) -> *const bool {
|
||||||
|
self.tiles.as_ptr()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Called when the wasm module is instantiated
|
||||||
|
// #[wasm_bindgen(start)]
|
||||||
|
// pub fn main() -> Result<(), JsValue> {
|
||||||
|
// Ok(())
|
||||||
|
// }
|
179
demo/src/main.rs
179
demo/src/main.rs
|
@ -1,179 +0,0 @@
|
||||||
use amethyst::{
|
|
||||||
assets::{AssetStorage, Loader},
|
|
||||||
core::{
|
|
||||||
math::{Point3, Vector3},
|
|
||||||
Transform, TransformBundle,
|
|
||||||
},
|
|
||||||
ecs::Entity,
|
|
||||||
input::{is_close_requested, is_key_down, InputBundle, StringBindings},
|
|
||||||
prelude::*,
|
|
||||||
renderer::{
|
|
||||||
camera::Camera,
|
|
||||||
formats::texture::ImageFormat,
|
|
||||||
sprite::{SpriteSheet, SpriteSheetFormat, SpriteSheetHandle},
|
|
||||||
types::DefaultBackend,
|
|
||||||
RenderFlat2D, RenderToWindow, RenderingBundle, Texture,
|
|
||||||
palette::Srgba,
|
|
||||||
},
|
|
||||||
tiles::{MortonEncoder, RenderTiles2D, Tile, TileMap},
|
|
||||||
utils::application_root_dir,
|
|
||||||
window::ScreenDimensions,
|
|
||||||
winit,
|
|
||||||
};
|
|
||||||
use mapgen::dungeon::{
|
|
||||||
MapBuilder,
|
|
||||||
map::{Map, Point, TileType},
|
|
||||||
cellular_automata::CellularAutomataGen,
|
|
||||||
starting_point::{AreaStartingPosition, XStart, YStart},
|
|
||||||
cull_unreachable::CullUnreachable,
|
|
||||||
distant_exit::DistantExit,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Default, Clone)]
|
|
||||||
struct MapTiles ;
|
|
||||||
|
|
||||||
impl Tile for MapTiles {
|
|
||||||
fn sprite(&self, p: Point3<u32>, world: &World) -> Option<usize> {
|
|
||||||
let map = world.read_resource::<Map>();
|
|
||||||
let pos = Point::new(p.x as usize, p.y as usize);
|
|
||||||
if map.starting_point == Some(pos) {
|
|
||||||
Some(160)
|
|
||||||
} else if map.exit_point == Some(pos) {
|
|
||||||
Some(12)
|
|
||||||
} else if map.at(p.x as usize, p.y as usize) == TileType::Wall {
|
|
||||||
Some(140)
|
|
||||||
} else {
|
|
||||||
Some(19)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn tint(&self, p: Point3<u32>, world: &World) -> Srgba {
|
|
||||||
let map = world.read_resource::<Map>();
|
|
||||||
let pos = Some(Point::new(p.x as usize, p.y as usize));
|
|
||||||
if map.starting_point == pos || map.exit_point == pos {
|
|
||||||
Srgba::new(1.0, 1.0, 0.0, 1.0)
|
|
||||||
} else {
|
|
||||||
Srgba::new(1.0, 1.0, 1.0, 1.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn load_tiles_sprite_sheet(world: &mut World, png_path: &str, ron_path: &str) -> SpriteSheetHandle {
|
|
||||||
let texture_handle = {
|
|
||||||
let loader = world.read_resource::<Loader>();
|
|
||||||
let texture_storage = world.read_resource::<AssetStorage<Texture>>();
|
|
||||||
loader.load(png_path, ImageFormat::default(), (), &texture_storage)
|
|
||||||
};
|
|
||||||
let loader = world.read_resource::<Loader>();
|
|
||||||
let sprite_sheet_store = world.read_resource::<AssetStorage<SpriteSheet>>();
|
|
||||||
loader.load(
|
|
||||||
ron_path,
|
|
||||||
SpriteSheetFormat(texture_handle),
|
|
||||||
(),
|
|
||||||
&sprite_sheet_store,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn init_camera(world: &mut World, transform: Transform, camera: Camera) -> Entity {
|
|
||||||
world
|
|
||||||
.create_entity()
|
|
||||||
.with(transform)
|
|
||||||
.with(camera)
|
|
||||||
.named("camera")
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn init_map(world: &mut World) {
|
|
||||||
let map = MapBuilder::new(Box::new(CellularAutomataGen::new(80, 50)))
|
|
||||||
.with(AreaStartingPosition::new(XStart::CENTER, YStart::CENTER))
|
|
||||||
.with(CullUnreachable::new())
|
|
||||||
.with(DistantExit::new())
|
|
||||||
.build_map();
|
|
||||||
world.insert(map);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
struct PlayState;
|
|
||||||
impl SimpleState for PlayState {
|
|
||||||
fn on_start(&mut self, data: StateData<'_, GameData<'_, '_>>) {
|
|
||||||
|
|
||||||
let mut world = data.world;
|
|
||||||
|
|
||||||
// Create map
|
|
||||||
init_map(&mut world);
|
|
||||||
|
|
||||||
let map_sprite_sheet_handle =
|
|
||||||
load_tiles_sprite_sheet(world, "texture/basic.png", "texture/basic.ron");
|
|
||||||
|
|
||||||
let (width, height) = {
|
|
||||||
let dim = world.read_resource::<ScreenDimensions>();
|
|
||||||
(dim.width(), dim.height())
|
|
||||||
};
|
|
||||||
|
|
||||||
let _camera = init_camera(
|
|
||||||
world,
|
|
||||||
Transform::from(Vector3::new(-10.0, 10.0, 1.1)),
|
|
||||||
Camera::standard_2d(width, height),
|
|
||||||
);
|
|
||||||
|
|
||||||
let tile_map = TileMap::<MapTiles, MortonEncoder>::new(
|
|
||||||
Vector3::new(80, 50, 1),
|
|
||||||
Vector3::new(20, 20, 1),
|
|
||||||
Some(map_sprite_sheet_handle),
|
|
||||||
);
|
|
||||||
|
|
||||||
let _map_entity = world
|
|
||||||
.create_entity()
|
|
||||||
.with(tile_map)
|
|
||||||
.with(Transform::default())
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_event(
|
|
||||||
&mut self,
|
|
||||||
data: StateData<'_, GameData<'_, '_>>,
|
|
||||||
event: StateEvent,
|
|
||||||
) -> SimpleTrans {
|
|
||||||
let StateData { .. } = data;
|
|
||||||
if let StateEvent::Window(event) = &event {
|
|
||||||
if is_close_requested(&event) || is_key_down(&event, winit::VirtualKeyCode::Escape) {
|
|
||||||
Trans::Quit
|
|
||||||
} else {
|
|
||||||
Trans::None
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Trans::None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() -> amethyst::Result<()> {
|
|
||||||
amethyst::Logger::from_config(Default::default())
|
|
||||||
.level_for("demo", log::LevelFilter::Warn)
|
|
||||||
.start();
|
|
||||||
|
|
||||||
let app_root = application_root_dir()?;
|
|
||||||
let assets_directory = app_root.join("assets");
|
|
||||||
let display_config_path = app_root.join("config/display.ron");
|
|
||||||
|
|
||||||
let game_data = GameDataBuilder::default()
|
|
||||||
.with_bundle(TransformBundle::new())?
|
|
||||||
.with_bundle(
|
|
||||||
InputBundle::<StringBindings>::new()
|
|
||||||
.with_bindings_from_file("config/input.ron")?,
|
|
||||||
)?
|
|
||||||
.with_bundle(
|
|
||||||
RenderingBundle::<DefaultBackend>::new()
|
|
||||||
.with_plugin(
|
|
||||||
RenderToWindow::from_config_path(display_config_path)?
|
|
||||||
.with_clear([0.0, 0.0, 0.0, 1.0]),
|
|
||||||
)
|
|
||||||
.with_plugin(RenderFlat2D::default())
|
|
||||||
.with_plugin(RenderTiles2D::<MapTiles, MortonEncoder>::default()),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let mut game = Application::build(assets_directory, PlayState)?.build(game_data)?;
|
|
||||||
game.run();
|
|
||||||
Ok(())
|
|
||||||
}
|
|
12
demo/src/utils.rs
Normal file
12
demo/src/utils.rs
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
|
||||||
|
pub fn set_panic_hook() {
|
||||||
|
// When the `console_error_panic_hook` feature is enabled, we can call the
|
||||||
|
// `set_panic_hook` function at least once during initialization, and then
|
||||||
|
// we will get better error messages if our code ever panics.
|
||||||
|
//
|
||||||
|
// For more details see
|
||||||
|
// https://github.com/rustwasm/console_error_panic_hook#readme
|
||||||
|
#[cfg(feature = "console_error_panic_hook")]
|
||||||
|
console_error_panic_hook::set_once();
|
||||||
|
}
|
||||||
|
|
1
demo/www
Submodule
1
demo/www
Submodule
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 9ac3dff9ebea4675e5c478bcdcbc0fd547d1529f
|
61
docs/0.bootstrap.js
Normal file
61
docs/0.bootstrap.js
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
(window["webpackJsonp"] = window["webpackJsonp"] || []).push([[0],{
|
||||||
|
|
||||||
|
/***/ "../pkg/mapgen_demo.js":
|
||||||
|
/*!*****************************!*\
|
||||||
|
!*** ../pkg/mapgen_demo.js ***!
|
||||||
|
\*****************************/
|
||||||
|
/*! exports provided: World, __wbindgen_object_drop_ref, __wbg_getTime_29addd71c7089c47, __wbg_new0_a3af66503e735141, __wbindgen_throw */
|
||||||
|
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _mapgen_demo_bg_wasm__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./mapgen_demo_bg.wasm */ \"../pkg/mapgen_demo_bg.wasm\");\n/* harmony import */ var _mapgen_demo_bg_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./mapgen_demo_bg.js */ \"../pkg/mapgen_demo_bg.js\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"World\", function() { return _mapgen_demo_bg_js__WEBPACK_IMPORTED_MODULE_1__[\"World\"]; });\n\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"__wbindgen_object_drop_ref\", function() { return _mapgen_demo_bg_js__WEBPACK_IMPORTED_MODULE_1__[\"__wbindgen_object_drop_ref\"]; });\n\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"__wbg_getTime_29addd71c7089c47\", function() { return _mapgen_demo_bg_js__WEBPACK_IMPORTED_MODULE_1__[\"__wbg_getTime_29addd71c7089c47\"]; });\n\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"__wbg_new0_a3af66503e735141\", function() { return _mapgen_demo_bg_js__WEBPACK_IMPORTED_MODULE_1__[\"__wbg_new0_a3af66503e735141\"]; });\n\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"__wbindgen_throw\", function() { return _mapgen_demo_bg_js__WEBPACK_IMPORTED_MODULE_1__[\"__wbindgen_throw\"]; });\n\n\n\n\n//# sourceURL=webpack:///../pkg/mapgen_demo.js?");
|
||||||
|
|
||||||
|
/***/ }),
|
||||||
|
|
||||||
|
/***/ "../pkg/mapgen_demo_bg.js":
|
||||||
|
/*!********************************!*\
|
||||||
|
!*** ../pkg/mapgen_demo_bg.js ***!
|
||||||
|
\********************************/
|
||||||
|
/*! exports provided: World, __wbindgen_object_drop_ref, __wbg_getTime_29addd71c7089c47, __wbg_new0_a3af66503e735141, __wbindgen_throw */
|
||||||
|
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
eval("__webpack_require__.r(__webpack_exports__);\n/* WEBPACK VAR INJECTION */(function(module) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"World\", function() { return World; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"__wbindgen_object_drop_ref\", function() { return __wbindgen_object_drop_ref; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"__wbg_getTime_29addd71c7089c47\", function() { return __wbg_getTime_29addd71c7089c47; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"__wbg_new0_a3af66503e735141\", function() { return __wbg_new0_a3af66503e735141; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"__wbindgen_throw\", function() { return __wbindgen_throw; });\n/* harmony import */ var _mapgen_demo_bg_wasm__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./mapgen_demo_bg.wasm */ \"../pkg/mapgen_demo_bg.wasm\");\n\n\nconst heap = new Array(32).fill(undefined);\n\nheap.push(undefined, null, true, false);\n\nfunction getObject(idx) { return heap[idx]; }\n\nlet heap_next = heap.length;\n\nfunction dropObject(idx) {\n if (idx < 36) return;\n heap[idx] = heap_next;\n heap_next = idx;\n}\n\nfunction takeObject(idx) {\n const ret = getObject(idx);\n dropObject(idx);\n return ret;\n}\n\nconst lTextDecoder = typeof TextDecoder === 'undefined' ? (0, module.require)('util').TextDecoder : TextDecoder;\n\nlet cachedTextDecoder = new lTextDecoder('utf-8', { ignoreBOM: true, fatal: true });\n\ncachedTextDecoder.decode();\n\nlet cachegetUint8Memory0 = null;\nfunction getUint8Memory0() {\n if (cachegetUint8Memory0 === null || cachegetUint8Memory0.buffer !== _mapgen_demo_bg_wasm__WEBPACK_IMPORTED_MODULE_0__[\"memory\"].buffer) {\n cachegetUint8Memory0 = new Uint8Array(_mapgen_demo_bg_wasm__WEBPACK_IMPORTED_MODULE_0__[\"memory\"].buffer);\n }\n return cachegetUint8Memory0;\n}\n\nfunction getStringFromWasm0(ptr, len) {\n return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len));\n}\n\nfunction addHeapObject(obj) {\n if (heap_next === heap.length) heap.push(heap.length + 1);\n const idx = heap_next;\n heap_next = heap[idx];\n\n heap[idx] = obj;\n return idx;\n}\n/**\n*/\nclass World {\n\n static __wrap(ptr) {\n const obj = Object.create(World.prototype);\n obj.ptr = ptr;\n\n return obj;\n }\n\n free() {\n const ptr = this.ptr;\n this.ptr = 0;\n\n _mapgen_demo_bg_wasm__WEBPACK_IMPORTED_MODULE_0__[\"__wbg_world_free\"](ptr);\n }\n /**\n * @param {number} width\n * @param {number} height\n * @returns {World}\n */\n static new(width, height) {\n var ret = _mapgen_demo_bg_wasm__WEBPACK_IMPORTED_MODULE_0__[\"world_new\"](width, height);\n return World.__wrap(ret);\n }\n /**\n * @returns {number}\n */\n width() {\n var ret = _mapgen_demo_bg_wasm__WEBPACK_IMPORTED_MODULE_0__[\"world_width\"](this.ptr);\n return ret >>> 0;\n }\n /**\n * @returns {number}\n */\n height() {\n var ret = _mapgen_demo_bg_wasm__WEBPACK_IMPORTED_MODULE_0__[\"world_height\"](this.ptr);\n return ret >>> 0;\n }\n /**\n * @returns {number}\n */\n tiles() {\n var ret = _mapgen_demo_bg_wasm__WEBPACK_IMPORTED_MODULE_0__[\"world_tiles\"](this.ptr);\n return ret;\n }\n}\n\nconst __wbindgen_object_drop_ref = function(arg0) {\n takeObject(arg0);\n};\n\nconst __wbg_getTime_29addd71c7089c47 = function(arg0) {\n var ret = getObject(arg0).getTime();\n return ret;\n};\n\nconst __wbg_new0_a3af66503e735141 = function() {\n var ret = new Date();\n return addHeapObject(ret);\n};\n\nconst __wbindgen_throw = function(arg0, arg1) {\n throw new Error(getStringFromWasm0(arg0, arg1));\n};\n\n\n/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! ./../www/node_modules/webpack/buildin/harmony-module.js */ \"./node_modules/webpack/buildin/harmony-module.js\")(module)))\n\n//# sourceURL=webpack:///../pkg/mapgen_demo_bg.js?");
|
||||||
|
|
||||||
|
/***/ }),
|
||||||
|
|
||||||
|
/***/ "../pkg/mapgen_demo_bg.wasm":
|
||||||
|
/*!**********************************!*\
|
||||||
|
!*** ../pkg/mapgen_demo_bg.wasm ***!
|
||||||
|
\**********************************/
|
||||||
|
/*! exports provided: memory, __wbg_world_free, world_new, world_width, world_height, world_tiles */
|
||||||
|
/***/ (function(module, exports, __webpack_require__) {
|
||||||
|
|
||||||
|
eval("\"use strict\";\n// Instantiate WebAssembly module\nvar wasmExports = __webpack_require__.w[module.i];\n__webpack_require__.r(exports);\n// export exports from WebAssembly module\nfor(var name in wasmExports) if(name != \"__webpack_init__\") exports[name] = wasmExports[name];\n// exec imports from WebAssembly module (for esm order)\n/* harmony import */ var m0 = __webpack_require__(/*! ./mapgen_demo_bg.js */ \"../pkg/mapgen_demo_bg.js\");\n\n\n// exec wasm module\nwasmExports[\"__webpack_init__\"]()\n\n//# sourceURL=webpack:///../pkg/mapgen_demo_bg.wasm?");
|
||||||
|
|
||||||
|
/***/ }),
|
||||||
|
|
||||||
|
/***/ "./index.js":
|
||||||
|
/*!******************!*\
|
||||||
|
!*** ./index.js ***!
|
||||||
|
\******************/
|
||||||
|
/*! no exports provided */
|
||||||
|
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var mapgen_demo__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! mapgen-demo */ \"../pkg/mapgen_demo.js\");\n/* harmony import */ var mapgen_demo_mapgen_demo_bg__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! mapgen-demo/mapgen_demo_bg */ \"../pkg/mapgen_demo_bg.wasm\");\n\n\n\nconst CELL_SIZE = 12;\nconst GRID_COLOR = \"#CCCCCC\";\nconst DEAD_COLOR = \"#FFFFFF\";\nconst ALIVE_COLOR = \"#000000\";\n\nconst world = mapgen_demo__WEBPACK_IMPORTED_MODULE_0__[\"World\"].new(80, 50);\nconst width = world.width();\nconst height = world.height();\n\n// Give the canvas room for all of our cells and a 1px border\n// around each of them.\nconst canvas = document.getElementById(\"mapgen-canvas\");\ncanvas.height = (CELL_SIZE + 1) * height + 1;\ncanvas.width = (CELL_SIZE + 1) * width + 1;\n\nconst ctx = canvas.getContext('2d');\n\nconst renderLoop = () => {\n // universe.tick();\n\n drawGrid();\n drawCells();\n\n requestAnimationFrame(renderLoop);\n};\n\nconst drawGrid = () => {\n ctx.beginPath();\n ctx.strokeStyle = GRID_COLOR;\n\n // Vertical lines.\n for (let i = 0; i <= width; i++) {\n ctx.moveTo(i * (CELL_SIZE + 1) + 1, 0);\n ctx.lineTo(i * (CELL_SIZE + 1) + 1, (CELL_SIZE + 1) * height + 1);\n }\n\n // Horizontal lines.\n for (let j = 0; j <= height; j++) {\n ctx.moveTo(0, j * (CELL_SIZE + 1) + 1);\n ctx.lineTo((CELL_SIZE + 1) * width + 1, j * (CELL_SIZE + 1) + 1);\n }\n\n ctx.stroke();\n};\n\nconst getIndex = (row, column) => {\n return row * width + column;\n};\n\nconst drawCells = () => {\n const tilesPtr = world.tiles();\n const tiles = new Uint8Array(mapgen_demo_mapgen_demo_bg__WEBPACK_IMPORTED_MODULE_1__[\"memory\"].buffer, tilesPtr, width * height);\n\n ctx.beginPath();\n\n for (let row = 0; row < height; row++) {\n for (let col = 0; col < width; col++) {\n const idx = getIndex(row, col);\n\n ctx.fillStyle = tiles[idx]\n ? DEAD_COLOR\n : ALIVE_COLOR;\n\n ctx.fillRect(\n col * (CELL_SIZE + 1) + 1,\n row * (CELL_SIZE + 1) + 1,\n CELL_SIZE,\n CELL_SIZE\n );\n }\n }\n\n ctx.stroke();\n};\n\ndrawGrid();\ndrawCells();\nrequestAnimationFrame(renderLoop);\n\n//# sourceURL=webpack:///./index.js?");
|
||||||
|
|
||||||
|
/***/ }),
|
||||||
|
|
||||||
|
/***/ "./node_modules/webpack/buildin/harmony-module.js":
|
||||||
|
/*!*******************************************!*\
|
||||||
|
!*** (webpack)/buildin/harmony-module.js ***!
|
||||||
|
\*******************************************/
|
||||||
|
/*! no static exports found */
|
||||||
|
/***/ (function(module, exports) {
|
||||||
|
|
||||||
|
eval("module.exports = function(originalModule) {\n\tif (!originalModule.webpackPolyfill) {\n\t\tvar module = Object.create(originalModule);\n\t\t// module.parent = undefined by default\n\t\tif (!module.children) module.children = [];\n\t\tObject.defineProperty(module, \"loaded\", {\n\t\t\tenumerable: true,\n\t\t\tget: function() {\n\t\t\t\treturn module.l;\n\t\t\t}\n\t\t});\n\t\tObject.defineProperty(module, \"id\", {\n\t\t\tenumerable: true,\n\t\t\tget: function() {\n\t\t\t\treturn module.i;\n\t\t\t}\n\t\t});\n\t\tObject.defineProperty(module, \"exports\", {\n\t\t\tenumerable: true\n\t\t});\n\t\tmodule.webpackPolyfill = 1;\n\t}\n\treturn module;\n};\n\n\n//# sourceURL=webpack:///(webpack)/buildin/harmony-module.js?");
|
||||||
|
|
||||||
|
/***/ })
|
||||||
|
|
||||||
|
}]);
|
BIN
docs/bf853f7fb17b7aed38db.module.wasm
Normal file
BIN
docs/bf853f7fb17b7aed38db.module.wasm
Normal file
Binary file not shown.
276
docs/bootstrap.js
vendored
Normal file
276
docs/bootstrap.js
vendored
Normal file
|
@ -0,0 +1,276 @@
|
||||||
|
/******/ (function(modules) { // webpackBootstrap
|
||||||
|
/******/ // install a JSONP callback for chunk loading
|
||||||
|
/******/ function webpackJsonpCallback(data) {
|
||||||
|
/******/ var chunkIds = data[0];
|
||||||
|
/******/ var moreModules = data[1];
|
||||||
|
/******/
|
||||||
|
/******/
|
||||||
|
/******/ // add "moreModules" to the modules object,
|
||||||
|
/******/ // then flag all "chunkIds" as loaded and fire callback
|
||||||
|
/******/ var moduleId, chunkId, i = 0, resolves = [];
|
||||||
|
/******/ for(;i < chunkIds.length; i++) {
|
||||||
|
/******/ chunkId = chunkIds[i];
|
||||||
|
/******/ if(Object.prototype.hasOwnProperty.call(installedChunks, chunkId) && installedChunks[chunkId]) {
|
||||||
|
/******/ resolves.push(installedChunks[chunkId][0]);
|
||||||
|
/******/ }
|
||||||
|
/******/ installedChunks[chunkId] = 0;
|
||||||
|
/******/ }
|
||||||
|
/******/ for(moduleId in moreModules) {
|
||||||
|
/******/ if(Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {
|
||||||
|
/******/ modules[moduleId] = moreModules[moduleId];
|
||||||
|
/******/ }
|
||||||
|
/******/ }
|
||||||
|
/******/ if(parentJsonpFunction) parentJsonpFunction(data);
|
||||||
|
/******/
|
||||||
|
/******/ while(resolves.length) {
|
||||||
|
/******/ resolves.shift()();
|
||||||
|
/******/ }
|
||||||
|
/******/
|
||||||
|
/******/ };
|
||||||
|
/******/
|
||||||
|
/******/
|
||||||
|
/******/ // The module cache
|
||||||
|
/******/ var installedModules = {};
|
||||||
|
/******/
|
||||||
|
/******/ // object to store loaded and loading chunks
|
||||||
|
/******/ // undefined = chunk not loaded, null = chunk preloaded/prefetched
|
||||||
|
/******/ // Promise = chunk loading, 0 = chunk loaded
|
||||||
|
/******/ var installedChunks = {
|
||||||
|
/******/ "main": 0
|
||||||
|
/******/ };
|
||||||
|
/******/
|
||||||
|
/******/
|
||||||
|
/******/
|
||||||
|
/******/ // script path function
|
||||||
|
/******/ function jsonpScriptSrc(chunkId) {
|
||||||
|
/******/ return __webpack_require__.p + "" + chunkId + ".bootstrap.js"
|
||||||
|
/******/ }
|
||||||
|
/******/
|
||||||
|
/******/ // object to store loaded and loading wasm modules
|
||||||
|
/******/ var installedWasmModules = {};
|
||||||
|
/******/
|
||||||
|
/******/ function promiseResolve() { return Promise.resolve(); }
|
||||||
|
/******/
|
||||||
|
/******/ var wasmImportObjects = {
|
||||||
|
/******/ "../pkg/mapgen_demo_bg.wasm": function() {
|
||||||
|
/******/ return {
|
||||||
|
/******/ "./mapgen_demo_bg.js": {
|
||||||
|
/******/ "__wbindgen_object_drop_ref": function(p0i32) {
|
||||||
|
/******/ return installedModules["../pkg/mapgen_demo_bg.js"].exports["__wbindgen_object_drop_ref"](p0i32);
|
||||||
|
/******/ },
|
||||||
|
/******/ "__wbg_getTime_29addd71c7089c47": function(p0i32) {
|
||||||
|
/******/ return installedModules["../pkg/mapgen_demo_bg.js"].exports["__wbg_getTime_29addd71c7089c47"](p0i32);
|
||||||
|
/******/ },
|
||||||
|
/******/ "__wbg_new0_a3af66503e735141": function() {
|
||||||
|
/******/ return installedModules["../pkg/mapgen_demo_bg.js"].exports["__wbg_new0_a3af66503e735141"]();
|
||||||
|
/******/ },
|
||||||
|
/******/ "__wbindgen_throw": function(p0i32,p1i32) {
|
||||||
|
/******/ return installedModules["../pkg/mapgen_demo_bg.js"].exports["__wbindgen_throw"](p0i32,p1i32);
|
||||||
|
/******/ }
|
||||||
|
/******/ }
|
||||||
|
/******/ };
|
||||||
|
/******/ },
|
||||||
|
/******/ };
|
||||||
|
/******/
|
||||||
|
/******/ // The require function
|
||||||
|
/******/ function __webpack_require__(moduleId) {
|
||||||
|
/******/
|
||||||
|
/******/ // Check if module is in cache
|
||||||
|
/******/ if(installedModules[moduleId]) {
|
||||||
|
/******/ return installedModules[moduleId].exports;
|
||||||
|
/******/ }
|
||||||
|
/******/ // Create a new module (and put it into the cache)
|
||||||
|
/******/ var module = installedModules[moduleId] = {
|
||||||
|
/******/ i: moduleId,
|
||||||
|
/******/ l: false,
|
||||||
|
/******/ exports: {}
|
||||||
|
/******/ };
|
||||||
|
/******/
|
||||||
|
/******/ // Execute the module function
|
||||||
|
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
|
||||||
|
/******/
|
||||||
|
/******/ // Flag the module as loaded
|
||||||
|
/******/ module.l = true;
|
||||||
|
/******/
|
||||||
|
/******/ // Return the exports of the module
|
||||||
|
/******/ return module.exports;
|
||||||
|
/******/ }
|
||||||
|
/******/
|
||||||
|
/******/ // This file contains only the entry chunk.
|
||||||
|
/******/ // The chunk loading function for additional chunks
|
||||||
|
/******/ __webpack_require__.e = function requireEnsure(chunkId) {
|
||||||
|
/******/ var promises = [];
|
||||||
|
/******/
|
||||||
|
/******/
|
||||||
|
/******/ // JSONP chunk loading for javascript
|
||||||
|
/******/
|
||||||
|
/******/ var installedChunkData = installedChunks[chunkId];
|
||||||
|
/******/ if(installedChunkData !== 0) { // 0 means "already installed".
|
||||||
|
/******/
|
||||||
|
/******/ // a Promise means "currently loading".
|
||||||
|
/******/ if(installedChunkData) {
|
||||||
|
/******/ promises.push(installedChunkData[2]);
|
||||||
|
/******/ } else {
|
||||||
|
/******/ // setup Promise in chunk cache
|
||||||
|
/******/ var promise = new Promise(function(resolve, reject) {
|
||||||
|
/******/ installedChunkData = installedChunks[chunkId] = [resolve, reject];
|
||||||
|
/******/ });
|
||||||
|
/******/ promises.push(installedChunkData[2] = promise);
|
||||||
|
/******/
|
||||||
|
/******/ // start chunk loading
|
||||||
|
/******/ var script = document.createElement('script');
|
||||||
|
/******/ var onScriptComplete;
|
||||||
|
/******/
|
||||||
|
/******/ script.charset = 'utf-8';
|
||||||
|
/******/ script.timeout = 120;
|
||||||
|
/******/ if (__webpack_require__.nc) {
|
||||||
|
/******/ script.setAttribute("nonce", __webpack_require__.nc);
|
||||||
|
/******/ }
|
||||||
|
/******/ script.src = jsonpScriptSrc(chunkId);
|
||||||
|
/******/
|
||||||
|
/******/ // create error before stack unwound to get useful stacktrace later
|
||||||
|
/******/ var error = new Error();
|
||||||
|
/******/ onScriptComplete = function (event) {
|
||||||
|
/******/ // avoid mem leaks in IE.
|
||||||
|
/******/ script.onerror = script.onload = null;
|
||||||
|
/******/ clearTimeout(timeout);
|
||||||
|
/******/ var chunk = installedChunks[chunkId];
|
||||||
|
/******/ if(chunk !== 0) {
|
||||||
|
/******/ if(chunk) {
|
||||||
|
/******/ var errorType = event && (event.type === 'load' ? 'missing' : event.type);
|
||||||
|
/******/ var realSrc = event && event.target && event.target.src;
|
||||||
|
/******/ error.message = 'Loading chunk ' + chunkId + ' failed.\n(' + errorType + ': ' + realSrc + ')';
|
||||||
|
/******/ error.name = 'ChunkLoadError';
|
||||||
|
/******/ error.type = errorType;
|
||||||
|
/******/ error.request = realSrc;
|
||||||
|
/******/ chunk[1](error);
|
||||||
|
/******/ }
|
||||||
|
/******/ installedChunks[chunkId] = undefined;
|
||||||
|
/******/ }
|
||||||
|
/******/ };
|
||||||
|
/******/ var timeout = setTimeout(function(){
|
||||||
|
/******/ onScriptComplete({ type: 'timeout', target: script });
|
||||||
|
/******/ }, 120000);
|
||||||
|
/******/ script.onerror = script.onload = onScriptComplete;
|
||||||
|
/******/ document.head.appendChild(script);
|
||||||
|
/******/ }
|
||||||
|
/******/ }
|
||||||
|
/******/
|
||||||
|
/******/ // Fetch + compile chunk loading for webassembly
|
||||||
|
/******/
|
||||||
|
/******/ var wasmModules = {"0":["../pkg/mapgen_demo_bg.wasm"]}[chunkId] || [];
|
||||||
|
/******/
|
||||||
|
/******/ wasmModules.forEach(function(wasmModuleId) {
|
||||||
|
/******/ var installedWasmModuleData = installedWasmModules[wasmModuleId];
|
||||||
|
/******/
|
||||||
|
/******/ // a Promise means "currently loading" or "already loaded".
|
||||||
|
/******/ if(installedWasmModuleData)
|
||||||
|
/******/ promises.push(installedWasmModuleData);
|
||||||
|
/******/ else {
|
||||||
|
/******/ var importObject = wasmImportObjects[wasmModuleId]();
|
||||||
|
/******/ var req = fetch(__webpack_require__.p + "" + {"../pkg/mapgen_demo_bg.wasm":"bf853f7fb17b7aed38db"}[wasmModuleId] + ".module.wasm");
|
||||||
|
/******/ var promise;
|
||||||
|
/******/ if(importObject instanceof Promise && typeof WebAssembly.compileStreaming === 'function') {
|
||||||
|
/******/ promise = Promise.all([WebAssembly.compileStreaming(req), importObject]).then(function(items) {
|
||||||
|
/******/ return WebAssembly.instantiate(items[0], items[1]);
|
||||||
|
/******/ });
|
||||||
|
/******/ } else if(typeof WebAssembly.instantiateStreaming === 'function') {
|
||||||
|
/******/ promise = WebAssembly.instantiateStreaming(req, importObject);
|
||||||
|
/******/ } else {
|
||||||
|
/******/ var bytesPromise = req.then(function(x) { return x.arrayBuffer(); });
|
||||||
|
/******/ promise = bytesPromise.then(function(bytes) {
|
||||||
|
/******/ return WebAssembly.instantiate(bytes, importObject);
|
||||||
|
/******/ });
|
||||||
|
/******/ }
|
||||||
|
/******/ promises.push(installedWasmModules[wasmModuleId] = promise.then(function(res) {
|
||||||
|
/******/ return __webpack_require__.w[wasmModuleId] = (res.instance || res).exports;
|
||||||
|
/******/ }));
|
||||||
|
/******/ }
|
||||||
|
/******/ });
|
||||||
|
/******/ return Promise.all(promises);
|
||||||
|
/******/ };
|
||||||
|
/******/
|
||||||
|
/******/ // expose the modules object (__webpack_modules__)
|
||||||
|
/******/ __webpack_require__.m = modules;
|
||||||
|
/******/
|
||||||
|
/******/ // expose the module cache
|
||||||
|
/******/ __webpack_require__.c = installedModules;
|
||||||
|
/******/
|
||||||
|
/******/ // define getter function for harmony exports
|
||||||
|
/******/ __webpack_require__.d = function(exports, name, getter) {
|
||||||
|
/******/ if(!__webpack_require__.o(exports, name)) {
|
||||||
|
/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter });
|
||||||
|
/******/ }
|
||||||
|
/******/ };
|
||||||
|
/******/
|
||||||
|
/******/ // define __esModule on exports
|
||||||
|
/******/ __webpack_require__.r = function(exports) {
|
||||||
|
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
|
||||||
|
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
||||||
|
/******/ }
|
||||||
|
/******/ Object.defineProperty(exports, '__esModule', { value: true });
|
||||||
|
/******/ };
|
||||||
|
/******/
|
||||||
|
/******/ // create a fake namespace object
|
||||||
|
/******/ // mode & 1: value is a module id, require it
|
||||||
|
/******/ // mode & 2: merge all properties of value into the ns
|
||||||
|
/******/ // mode & 4: return value when already ns object
|
||||||
|
/******/ // mode & 8|1: behave like require
|
||||||
|
/******/ __webpack_require__.t = function(value, mode) {
|
||||||
|
/******/ if(mode & 1) value = __webpack_require__(value);
|
||||||
|
/******/ if(mode & 8) return value;
|
||||||
|
/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
|
||||||
|
/******/ var ns = Object.create(null);
|
||||||
|
/******/ __webpack_require__.r(ns);
|
||||||
|
/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value });
|
||||||
|
/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
|
||||||
|
/******/ return ns;
|
||||||
|
/******/ };
|
||||||
|
/******/
|
||||||
|
/******/ // getDefaultExport function for compatibility with non-harmony modules
|
||||||
|
/******/ __webpack_require__.n = function(module) {
|
||||||
|
/******/ var getter = module && module.__esModule ?
|
||||||
|
/******/ function getDefault() { return module['default']; } :
|
||||||
|
/******/ function getModuleExports() { return module; };
|
||||||
|
/******/ __webpack_require__.d(getter, 'a', getter);
|
||||||
|
/******/ return getter;
|
||||||
|
/******/ };
|
||||||
|
/******/
|
||||||
|
/******/ // Object.prototype.hasOwnProperty.call
|
||||||
|
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
|
||||||
|
/******/
|
||||||
|
/******/ // __webpack_public_path__
|
||||||
|
/******/ __webpack_require__.p = "";
|
||||||
|
/******/
|
||||||
|
/******/ // on error function for async loading
|
||||||
|
/******/ __webpack_require__.oe = function(err) { console.error(err); throw err; };
|
||||||
|
/******/
|
||||||
|
/******/ // object with all WebAssembly.instance exports
|
||||||
|
/******/ __webpack_require__.w = {};
|
||||||
|
/******/
|
||||||
|
/******/ var jsonpArray = window["webpackJsonp"] = window["webpackJsonp"] || [];
|
||||||
|
/******/ var oldJsonpFunction = jsonpArray.push.bind(jsonpArray);
|
||||||
|
/******/ jsonpArray.push = webpackJsonpCallback;
|
||||||
|
/******/ jsonpArray = jsonpArray.slice();
|
||||||
|
/******/ for(var i = 0; i < jsonpArray.length; i++) webpackJsonpCallback(jsonpArray[i]);
|
||||||
|
/******/ var parentJsonpFunction = oldJsonpFunction;
|
||||||
|
/******/
|
||||||
|
/******/
|
||||||
|
/******/ // Load entry module and return exports
|
||||||
|
/******/ return __webpack_require__(__webpack_require__.s = "./bootstrap.js");
|
||||||
|
/******/ })
|
||||||
|
/************************************************************************/
|
||||||
|
/******/ ({
|
||||||
|
|
||||||
|
/***/ "./bootstrap.js":
|
||||||
|
/*!**********************!*\
|
||||||
|
!*** ./bootstrap.js ***!
|
||||||
|
\**********************/
|
||||||
|
/*! no static exports found */
|
||||||
|
/***/ (function(module, exports, __webpack_require__) {
|
||||||
|
|
||||||
|
eval("// A dependency graph that contains any wasm must all be imported\n// asynchronously. This `bootstrap.js` file does the single async import, so\n// that no one else needs to worry about it again.\n__webpack_require__.e(/*! import() */ 0).then(__webpack_require__.bind(null, /*! ./index.js */ \"./index.js\"))\n .catch(e => console.error(\"Error importing `index.js`:\", e));\n\n\n//# sourceURL=webpack:///./bootstrap.js?");
|
||||||
|
|
||||||
|
/***/ })
|
||||||
|
|
||||||
|
/******/ });
|
BIN
docs/favicon.ico
Normal file
BIN
docs/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 31 KiB |
|
@ -3,29 +3,11 @@
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>Mapgen demo</title>
|
<title>Mapgen demo</title>
|
||||||
<style>
|
|
||||||
body {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
#fps {
|
|
||||||
white-space: pre;
|
|
||||||
font-family: monospace;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>Map generator demo</h1>
|
<h1>Mapgen demo</h1>
|
||||||
<button id="play-pause"></button>
|
<canvas id="mapgen-canvas"></canvas>
|
||||||
<div id="fps"></div>
|
<noscript>This page contains webassembly and javascript content, please enable javascript in your browser.</noscript>
|
||||||
<canvas id="demo-canvas"></canvas>
|
<script src="./bootstrap.js"></script>
|
||||||
<script src='./index.js'></script>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
199
docs/index.js
199
docs/index.js
|
@ -1,199 +0,0 @@
|
||||||
import { Universe, Cell } from "wasm-game-of-life";
|
|
||||||
import { memory } from "wasm-game-of-life/wasm_game_of_life_bg";
|
|
||||||
|
|
||||||
const CELL_SIZE = 8; // px
|
|
||||||
const GRID_COLOR = "#CCCCCC";
|
|
||||||
const DEAD_COLOR = "#FFFFFF";
|
|
||||||
const ALIVE_COLOR = "#000000";
|
|
||||||
|
|
||||||
// Construct the universe, and get its width and height.
|
|
||||||
// const universe = Universe.new_spaceship();
|
|
||||||
const universe = Universe.new();
|
|
||||||
const width = universe.width();
|
|
||||||
const height = universe.height();
|
|
||||||
|
|
||||||
// Give the canvas room for all of our cells and a 1px border
|
|
||||||
// around each of them.
|
|
||||||
const canvas = document.getElementById("game-of-life-canvas");
|
|
||||||
canvas.height = (CELL_SIZE + 1) * height + 1;
|
|
||||||
canvas.width = (CELL_SIZE + 1) * width + 1;
|
|
||||||
|
|
||||||
const ctx = canvas.getContext('2d');
|
|
||||||
|
|
||||||
let animationId = null;
|
|
||||||
|
|
||||||
const renderLoop = () => {
|
|
||||||
fps.render();
|
|
||||||
for (let i = 0; i < 9; i++) {
|
|
||||||
universe.tick();
|
|
||||||
}
|
|
||||||
|
|
||||||
drawGrid();
|
|
||||||
drawCells();
|
|
||||||
|
|
||||||
animationId = requestAnimationFrame(renderLoop);
|
|
||||||
};
|
|
||||||
|
|
||||||
const drawGrid = () => {
|
|
||||||
ctx.beginPath();
|
|
||||||
ctx.strokeStyle = GRID_COLOR;
|
|
||||||
|
|
||||||
// Vertical lines.
|
|
||||||
for (let i = 0; i <= width; i++) {
|
|
||||||
ctx.moveTo(i * (CELL_SIZE + 1) + 1, 0);
|
|
||||||
ctx.lineTo(i * (CELL_SIZE + 1) + 1, (CELL_SIZE + 1) * height + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Horizontal lines.
|
|
||||||
for (let j = 0; j <= height; j++) {
|
|
||||||
ctx.moveTo(0, j * (CELL_SIZE + 1) + 1);
|
|
||||||
ctx.lineTo((CELL_SIZE + 1) * width + 1, j * (CELL_SIZE + 1) + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.stroke();
|
|
||||||
};
|
|
||||||
|
|
||||||
const getIndex = (row, column) => {
|
|
||||||
return row * width + column;
|
|
||||||
};
|
|
||||||
|
|
||||||
const drawCells = () => {
|
|
||||||
const cellsPtr = universe.cells();
|
|
||||||
|
|
||||||
// This is updated!
|
|
||||||
const cells = new Uint8Array(memory.buffer, cellsPtr, width * height / 8);
|
|
||||||
|
|
||||||
ctx.beginPath();
|
|
||||||
|
|
||||||
// Alive cells.
|
|
||||||
ctx.fillStyle = ALIVE_COLOR;
|
|
||||||
for (let row = 0; row < height; row++) {
|
|
||||||
for (let col = 0; col < width; col++) {
|
|
||||||
const idx = getIndex(row, col);
|
|
||||||
if (!bitIsSet(idx, cells)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.fillRect(
|
|
||||||
col * (CELL_SIZE + 1) + 1,
|
|
||||||
row * (CELL_SIZE + 1) + 1,
|
|
||||||
CELL_SIZE,
|
|
||||||
CELL_SIZE
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dead cells.
|
|
||||||
ctx.fillStyle = DEAD_COLOR;
|
|
||||||
for (let row = 0; row < height; row++) {
|
|
||||||
for (let col = 0; col < width; col++) {
|
|
||||||
const idx = getIndex(row, col);
|
|
||||||
if (bitIsSet(idx, cells)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.fillRect(
|
|
||||||
col * (CELL_SIZE + 1) + 1,
|
|
||||||
row * (CELL_SIZE + 1) + 1,
|
|
||||||
CELL_SIZE,
|
|
||||||
CELL_SIZE
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.stroke();
|
|
||||||
};
|
|
||||||
|
|
||||||
const bitIsSet = (n, arr) => {
|
|
||||||
const byte = Math.floor(n / 8);
|
|
||||||
const mask = 1 << (n % 8);
|
|
||||||
return (arr[byte] & mask) === mask;
|
|
||||||
};
|
|
||||||
|
|
||||||
const isPaused = () => {
|
|
||||||
return animationId === null;
|
|
||||||
};
|
|
||||||
|
|
||||||
const playPauseButton = document.getElementById("play-pause");
|
|
||||||
|
|
||||||
const play = () => {
|
|
||||||
playPauseButton.textContent = "⏸";
|
|
||||||
renderLoop();
|
|
||||||
};
|
|
||||||
|
|
||||||
const pause = () => {
|
|
||||||
playPauseButton.textContent = "▶";
|
|
||||||
cancelAnimationFrame(animationId);
|
|
||||||
animationId = null;
|
|
||||||
};
|
|
||||||
|
|
||||||
playPauseButton.addEventListener("click", event => {
|
|
||||||
if (isPaused()) {
|
|
||||||
play();
|
|
||||||
} else {
|
|
||||||
pause();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
canvas.addEventListener("click", event => {
|
|
||||||
const boundingRect = canvas.getBoundingClientRect();
|
|
||||||
|
|
||||||
const scaleX = canvas.width / boundingRect.width;
|
|
||||||
const scaleY = canvas.height / boundingRect.height;
|
|
||||||
|
|
||||||
const canvasLeft = (event.clientX - boundingRect.left) * scaleX;
|
|
||||||
const canvasTop = (event.clientY - boundingRect.top) * scaleY;
|
|
||||||
|
|
||||||
const row = Math.min(Math.floor(canvasTop / (CELL_SIZE + 1)), height - 1);
|
|
||||||
const col = Math.min(Math.floor(canvasLeft / (CELL_SIZE + 1)), width - 1);
|
|
||||||
|
|
||||||
universe.toggle_cell(row, col);
|
|
||||||
|
|
||||||
drawGrid();
|
|
||||||
drawCells();
|
|
||||||
});
|
|
||||||
|
|
||||||
const fps = new class {
|
|
||||||
constructor() {
|
|
||||||
this.fps = document.getElementById("fps");
|
|
||||||
this.frames = [];
|
|
||||||
this.lastFrameTimeStamp = performance.now();
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
// Convert the delta time since the last frame render into a measure
|
|
||||||
// of frames per second.
|
|
||||||
const now = performance.now();
|
|
||||||
const delta = now - this.lastFrameTimeStamp;
|
|
||||||
this.lastFrameTimeStamp = now;
|
|
||||||
const fps = 1 / delta * 1000;
|
|
||||||
|
|
||||||
// Save only the latest 100 timings.
|
|
||||||
this.frames.push(fps);
|
|
||||||
if (this.frames.length > 100) {
|
|
||||||
this.frames.shift();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find the max, min, and mean of our 100 latest timings.
|
|
||||||
let min = Infinity;
|
|
||||||
let max = -Infinity;
|
|
||||||
let sum = 0;
|
|
||||||
for (let i = 0; i < this.frames.length; i++) {
|
|
||||||
sum += this.frames[i];
|
|
||||||
min = Math.min(this.frames[i], min);
|
|
||||||
max = Math.max(this.frames[i], max);
|
|
||||||
}
|
|
||||||
let mean = sum / this.frames.length;
|
|
||||||
|
|
||||||
// Render the statistics.
|
|
||||||
this.fps.textContent = `
|
|
||||||
Frames per Second:
|
|
||||||
latest = ${Math.round(fps)}
|
|
||||||
avg of last 100 = ${Math.round(mean)}
|
|
||||||
min of last 100 = ${Math.round(min)}
|
|
||||||
max of last 100 = ${Math.round(max)}
|
|
||||||
`.trim();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
play();
|
|
|
@ -53,17 +53,14 @@ pub trait MapModifier {
|
||||||
pub struct MapBuilder {
|
pub struct MapBuilder {
|
||||||
generator: Box<dyn MapGenerator>,
|
generator: Box<dyn MapGenerator>,
|
||||||
modifiers: Vec<Box<dyn MapModifier>>,
|
modifiers: Vec<Box<dyn MapModifier>>,
|
||||||
rng: StdRng,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MapBuilder {
|
impl MapBuilder {
|
||||||
/// Create Map Builder with initial map generator
|
/// Create Map Builder with initial map generator
|
||||||
pub fn new(generator : Box<dyn MapGenerator>) -> MapBuilder {
|
pub fn new(generator : Box<dyn MapGenerator>) -> MapBuilder {
|
||||||
let system_time = SystemTime::now().duration_since(UNIX_EPOCH).expect("Can't access system time");
|
|
||||||
MapBuilder {
|
MapBuilder {
|
||||||
generator,
|
generator,
|
||||||
modifiers: Vec::new(),
|
modifiers: Vec::new(),
|
||||||
rng: StdRng::seed_from_u64(system_time.as_secs())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,16 +69,25 @@ impl MapBuilder {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Build map using random number seeded with system time
|
||||||
pub fn build_map(&mut self) -> Map {
|
pub fn build_map(&mut self) -> Map {
|
||||||
let mut map = self.generator.generate_map(&mut self.rng);
|
let system_time = SystemTime::now().duration_since(UNIX_EPOCH).expect("Can't access system time");
|
||||||
|
let mut rng = StdRng::seed_from_u64(system_time.as_millis() as u64);
|
||||||
|
self.build_map_with_rng(&mut rng)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Build map using provided random number generator
|
||||||
|
pub fn build_map_with_rng(&mut self, rng: &mut StdRng) -> Map {
|
||||||
|
let mut map = self.generator.generate_map(rng);
|
||||||
|
|
||||||
// Build additional layers in turn
|
// Build additional layers in turn
|
||||||
for modifier in self.modifiers.iter() {
|
for modifier in self.modifiers.iter() {
|
||||||
map = modifier.modify_map(&mut self.rng, &map);
|
map = modifier.modify_map(rng, &map);
|
||||||
}
|
}
|
||||||
|
|
||||||
map
|
map
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ------------------------------------------------------------------------------------------------
|
/// ------------------------------------------------------------------------------------------------
|
||||||
|
|
Loading…
Reference in New Issue
Block a user