commit
955274e68f
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -1,4 +1,6 @@
|
|||
/target
|
||||
/demo/target
|
||||
Cargo.lock
|
||||
.vscode/
|
||||
.vscode/
|
||||
pkg/
|
||||
package-lock.json
|
14
README.md
14
README.md
|
@ -6,16 +6,9 @@
|
|||
|
||||
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
|
||||
|
||||
If you want to check how the maps look like, then:
|
||||
* Clone this rep
|
||||
* Go to the demo folder
|
||||
* Run demo app (`cargo run`)
|
||||
Check [demo app](https://klangner.github.io/mapgen.rs/)
|
||||
|
||||
|
||||
## 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)
|
||||
|
||||
|
||||
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
|
||||
|
||||
Licensed under either of
|
||||
|
|
|
@ -2,15 +2,26 @@
|
|||
name = "mapgen-demo"
|
||||
version = "0.1.1"
|
||||
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"
|
||||
|
||||
[dependencies]
|
||||
rand = "0.7"
|
||||
amethyst = {version = "0.15", features = ["tiles", "no-slow-safety-checks"]}
|
||||
log = { version = "0.4.8", features = ["serde"] }
|
||||
mapgen = {path=".."}
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[features]
|
||||
default = ["metal"]
|
||||
metal = ["amethyst/metal"]
|
||||
vulkan = ["amethyst/vulkan"]
|
||||
[dependencies]
|
||||
rand = { version = "0.7", features = ["wasm-bindgen"] }
|
||||
mapgen = {path=".."}
|
||||
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
|
||||
|
||||
## Build the project:
|
||||
|
||||
```
|
||||
wasm-pack build
|
||||
cd www
|
||||
npm run build
|
||||
```
|
||||
|
||||
This app uses:
|
||||
* [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>
|
||||
<meta charset="utf-8">
|
||||
<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>
|
||||
<body>
|
||||
<h1>Map generator demo</h1>
|
||||
<button id="play-pause"></button>
|
||||
<div id="fps"></div>
|
||||
<canvas id="demo-canvas"></canvas>
|
||||
<script src='./index.js'></script>
|
||||
<h1>Mapgen demo</h1>
|
||||
<canvas id="mapgen-canvas"></canvas>
|
||||
<noscript>This page contains webassembly and javascript content, please enable javascript in your browser.</noscript>
|
||||
<script src="./bootstrap.js"></script>
|
||||
</body>
|
||||
</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 {
|
||||
generator: Box<dyn MapGenerator>,
|
||||
modifiers: Vec<Box<dyn MapModifier>>,
|
||||
rng: StdRng,
|
||||
}
|
||||
|
||||
impl MapBuilder {
|
||||
/// Create Map Builder with initial map generator
|
||||
pub fn new(generator : Box<dyn MapGenerator>) -> MapBuilder {
|
||||
let system_time = SystemTime::now().duration_since(UNIX_EPOCH).expect("Can't access system time");
|
||||
MapBuilder {
|
||||
generator,
|
||||
modifiers: Vec::new(),
|
||||
rng: StdRng::seed_from_u64(system_time.as_secs())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -72,16 +69,25 @@ impl MapBuilder {
|
|||
self
|
||||
}
|
||||
|
||||
/// Build map using random number seeded with system time
|
||||
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
|
||||
for modifier in self.modifiers.iter() {
|
||||
map = modifier.modify_map(&mut self.rng, &map);
|
||||
map = modifier.modify_map(rng, &map);
|
||||
}
|
||||
|
||||
map
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// ------------------------------------------------------------------------------------------------
|
||||
|
|
Loading…
Reference in New Issue
Block a user