@@ -0,0 +1 @@ | |||
/target |
@@ -0,0 +1,12 @@ | |||
[package] | |||
name = "merchant_seas" | |||
version = "0.1.0" | |||
authors = ["Isabelle L. <me@izzabelle.dev>"] | |||
edition = "2018" | |||
[dependencies] | |||
nalgebra = "0.19.0" | |||
[dependencies.amethyst] | |||
version = "0.15.0" | |||
features = ["vulkan"] |
@@ -0,0 +1,7 @@ | |||
Copyright 2020 Isabelle L. | |||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: | |||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. | |||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
@@ -0,0 +1 @@ | |||
# OH LAWD |
@@ -0,0 +1,36 @@ | |||
List(( | |||
texture_width: 512, | |||
texture_height: 432, | |||
sprites: [ | |||
( | |||
x: 0, | |||
y: 0, | |||
width: 256, | |||
height: 144, | |||
), | |||
( | |||
x: 0, | |||
y: 144, | |||
width: 256, | |||
height: 144, | |||
), | |||
( | |||
x: 0, | |||
y: 288, | |||
width: 256, | |||
height: 144, | |||
), | |||
( | |||
x: 256, | |||
y: 0, | |||
width: 256, | |||
height: 144, | |||
), | |||
( | |||
x: 256, | |||
y: 144, | |||
width: 256, | |||
height: 144, | |||
), | |||
], | |||
)) |
@@ -0,0 +1,4 @@ | |||
( | |||
title: "Merchant Seas", | |||
dimensions: Some((1600, 900)), | |||
) |
@@ -0,0 +1,13 @@ | |||
pub mod title_screen; | |||
use amethyst::prelude::*; | |||
use title_screen::TitleScreen; | |||
/// a simple state for initializing the game | |||
pub struct InitialState; | |||
impl SimpleState for InitialState { | |||
fn on_start(&mut self, _data: StateData<'_, GameData<'_, '_>>) { | |||
Trans::Push(Box::new(TitleScreen)); | |||
} | |||
} |
@@ -0,0 +1,47 @@ | |||
use amethyst::ecs::prelude::*; | |||
// deep water component | |||
pub struct DeepWater { | |||
pub y: f32, | |||
} | |||
impl Component for DeepWater { | |||
type Storage = DenseVecStorage<Self>; | |||
} | |||
// shallow water component | |||
pub struct ShallowWater { | |||
pub y: f32, | |||
} | |||
impl Component for ShallowWater { | |||
type Storage = DenseVecStorage<Self>; | |||
} | |||
// islands component | |||
pub struct Islands; | |||
impl Component for Islands { | |||
type Storage = DenseVecStorage<Self>; | |||
} | |||
// sea component | |||
pub struct Sea; | |||
impl Component for Sea { | |||
type Storage = DenseVecStorage<Self>; | |||
} | |||
// sky component | |||
pub struct Sky; | |||
impl Component for Sky { | |||
type Storage = DenseVecStorage<Self>; | |||
} | |||
// title component | |||
pub struct Title; | |||
impl Component for Title { | |||
type Storage = DenseVecStorage<Self>; | |||
} |
@@ -0,0 +1,171 @@ | |||
mod components; | |||
// namespacing | |||
use crate::utils::{load_font, load_sprite_sheet, load_texture}; | |||
use amethyst::{ | |||
assets::Handle, | |||
core::transform::Transform, | |||
ecs::prelude::*, | |||
prelude::*, | |||
renderer::{Camera, SpriteRender, SpriteSheet}, | |||
ui::{Anchor, FontAsset, UiText, UiTransform}, | |||
window::ScreenDimensions, | |||
}; | |||
use components::*; | |||
use nalgebra::Vector3; | |||
// constants | |||
const DEFAULT_SPRITE_WIDTH: f32 = 256.0; | |||
const DEFAULT_SPRITE_HEIGHT: f32 = 144.0; | |||
/// a simple state for the title screen | |||
pub struct TitleScreen; | |||
impl SimpleState for TitleScreen { | |||
fn on_start(&mut self, data: StateData<'_, GameData<'_, '_>>) { | |||
let world = data.world; | |||
let dimensions = (*world.read_resource::<ScreenDimensions>()).clone(); | |||
let sprite_sheet = init_sprite_sheet(world); | |||
let font_asset = load_font("fnt/8x8_wide_mono_bold.ttf", world); | |||
world.register::<DeepWater>(); | |||
world.register::<ShallowWater>(); | |||
world.register::<Islands>(); | |||
world.register::<Sky>(); | |||
world.register::<Sea>(); | |||
init_scene_entities(world, sprite_sheet, font_asset, &dimensions); | |||
init_camera(world, &dimensions); | |||
} | |||
fn handle_event( | |||
&mut self, | |||
mut _data: StateData<'_, GameData<'_, '_>>, | |||
_event: StateEvent, | |||
) -> SimpleTrans { | |||
// keep going | |||
Trans::None | |||
} | |||
} | |||
fn init_sprite_sheet(world: &World) -> Handle<SpriteSheet> { | |||
let texture_handle = load_texture("img/title_screen_texture.png", world); | |||
load_sprite_sheet("img/title_screen_sprite_sheet.ron", world, texture_handle) | |||
} | |||
// initialize the camera | |||
fn init_camera(world: &mut World, dimensions: &ScreenDimensions) { | |||
let mut transform = Transform::default(); | |||
transform.set_translation_xyz(dimensions.width() * 0.5, dimensions.height() * 0.5, 1.0); | |||
world | |||
.create_entity() | |||
.with(Camera::standard_2d(dimensions.width(), dimensions.height())) | |||
.with(transform) | |||
.build(); | |||
} | |||
// initailize the entities for the scene | |||
fn init_scene_entities( | |||
world: &mut World, | |||
sprite_sheet_handle: Handle<SpriteSheet>, | |||
font_asset_handle: Handle<FontAsset>, | |||
dimensions: &ScreenDimensions, | |||
) { | |||
// create the scale vector | |||
let scale_vector3 = Vector3::new( | |||
dimensions.width() / DEFAULT_SPRITE_WIDTH, | |||
dimensions.height() / DEFAULT_SPRITE_HEIGHT, | |||
0.0, | |||
); | |||
// create the scenery transform | |||
let mut scenery_transform = Transform::default(); | |||
scenery_transform.set_translation_xyz(dimensions.width() * 0.5, dimensions.height() * 0.5, 0.0); | |||
scenery_transform.set_scale(scale_vector3); | |||
// create the shallow water entity | |||
let sprite_render = SpriteRender { | |||
sprite_sheet: sprite_sheet_handle.clone(), | |||
sprite_number: 1, | |||
}; | |||
world | |||
.create_entity() | |||
.with(ShallowWater { y: 0.0 }) | |||
.with(scenery_transform.clone()) | |||
.with(sprite_render) | |||
.build(); | |||
// create the deep water entity | |||
let sprite_render = SpriteRender { | |||
sprite_sheet: sprite_sheet_handle.clone(), | |||
sprite_number: 0, | |||
}; | |||
world | |||
.create_entity() | |||
.with(DeepWater { y: 0.0 }) | |||
.with(scenery_transform.clone()) | |||
.with(sprite_render) | |||
.build(); | |||
// create the islands entity | |||
let sprite_render = SpriteRender { | |||
sprite_sheet: sprite_sheet_handle.clone(), | |||
sprite_number: 2, | |||
}; | |||
world | |||
.create_entity() | |||
.with(Islands) | |||
.with(scenery_transform.clone()) | |||
.with(sprite_render) | |||
.build(); | |||
// create the sky entity | |||
let sprite_render = SpriteRender { | |||
sprite_sheet: sprite_sheet_handle.clone(), | |||
sprite_number: 3, | |||
}; | |||
world | |||
.create_entity() | |||
.with(Sky) | |||
.with(scenery_transform.clone()) | |||
.with(sprite_render) | |||
.build(); | |||
// create the sea entity | |||
let sprite_render = SpriteRender { | |||
sprite_sheet: sprite_sheet_handle, | |||
sprite_number: 4, | |||
}; | |||
world | |||
.create_entity() | |||
.with(Sea) | |||
.with(scenery_transform) | |||
.with(sprite_render) | |||
.build(); | |||
// create the title entity | |||
let title_transform = UiTransform::new( | |||
"title".to_owned(), | |||
Anchor::TopLeft, | |||
Anchor::TopLeft, | |||
150.0, | |||
-150.0, | |||
1.0, | |||
450.0, | |||
45.0, | |||
); | |||
world | |||
.create_entity() | |||
.with(UiText::new( | |||
font_asset_handle, | |||
"Merchant Seas".to_string(), | |||
[1.0, 1.0, 1.0, 1.0], | |||
45.0, | |||
)) | |||
.with(title_transform) | |||
.build(); | |||
} |
@@ -0,0 +1,62 @@ | |||
// namespacing | |||
use amethyst::{ | |||
core::transform::TransformBundle, | |||
input::{InputBundle, StringBindings}, | |||
prelude::*, | |||
renderer::{ | |||
plugins::{RenderFlat2D, RenderToWindow}, | |||
types::DefaultBackend, | |||
RenderingBundle, | |||
}, | |||
ui::{RenderUi, UiBundle}, | |||
utils::application_root_dir, | |||
}; | |||
mod game; | |||
// a collection of utility functions | |||
mod utils; | |||
fn main() -> amethyst::Result<()> { | |||
// enable engine logging | |||
amethyst::start_logger(Default::default()); | |||
// set up root dir | |||
let app_root = application_root_dir()?; | |||
// define assets dir | |||
let assets = app_root.join("assets"); | |||
// set up display configuration | |||
let display_config = app_root.join("config").join("display_config.ron"); | |||
let render_to_window = | |||
RenderToWindow::from_config_path(display_config)?.with_clear([1.0, 1.0, 1.0, 1.0]); | |||
// set up keybindings configuration | |||
let bindings = app_root.join("config").join("bindings.ron"); | |||
let input_bundle = InputBundle::<StringBindings>::new().with_bindings_from_file(bindings)?; | |||
// initialize the game data struct | |||
let game_data = GameDataBuilder::default() | |||
// bundle inclusion | |||
.with_bundle(TransformBundle::new())? | |||
.with_bundle(input_bundle)? | |||
.with_bundle(UiBundle::<StringBindings>::new())? | |||
.with_bundle( | |||
RenderingBundle::<DefaultBackend>::new() | |||
.with_plugin(render_to_window) | |||
.with_plugin(RenderUi::default()) | |||
.with_plugin(RenderFlat2D::default()), | |||
)? | |||
// systems inclusion | |||
.with( | |||
utils::systems::ExitGameSystem, | |||
"exit_system", | |||
&["input_system"], | |||
); | |||
// create and run the game | |||
let mut game = Application::new(assets, game::title_screen::TitleScreen, game_data)?; | |||
game.run(); | |||
Ok(()) | |||
} |
@@ -0,0 +1,53 @@ | |||
/// set of generic systems to be used through out the game | |||
pub mod systems; | |||
// namespacing | |||
use amethyst::{ | |||
assets::{AssetStorage, Handle, Loader}, | |||
prelude::*, | |||
renderer::{ImageFormat, SpriteSheet, SpriteSheetFormat, Texture}, | |||
ui::{FontAsset, TtfFormat}, | |||
}; | |||
/// wrap the image loading functions | |||
pub fn load_texture<T>(name: T, world: &World) -> Handle<Texture> | |||
where | |||
T: Into<String>, | |||
{ | |||
let loader = world.read_resource::<Loader>(); | |||
loader.load( | |||
name, | |||
ImageFormat::default(), | |||
(), | |||
&world.read_resource::<AssetStorage<Texture>>(), | |||
) | |||
} | |||
/// wrap spritesheet loading | |||
pub fn load_sprite_sheet<T>( | |||
name: T, | |||
world: &World, | |||
texture_handle: Handle<Texture>, | |||
) -> Handle<SpriteSheet> | |||
where | |||
T: Into<String>, | |||
{ | |||
let loader = world.read_resource::<Loader>(); | |||
let spritesheet_store = world.read_resource::<AssetStorage<SpriteSheet>>(); | |||
loader.load( | |||
name, | |||
SpriteSheetFormat(texture_handle), | |||
(), | |||
&spritesheet_store, | |||
) | |||
} | |||
/// wrap font loading | |||
pub fn load_font<T>(name: T, world: &World) -> Handle<FontAsset> | |||
where | |||
T: Into<String>, | |||
{ | |||
world | |||
.read_resource::<Loader>() | |||
.load(name, TtfFormat, (), &world.read_resource()) | |||
} |