Skip to content

Commit 4e32de9

Browse files
committed
feat(canon): add bullet canon
1 parent bbcad93 commit 4e32de9

20 files changed

+285
-31
lines changed

.github/workflows/clippy_workflow.yml

+2-1
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,9 @@ jobs:
1616
run: sudo apt install libasound2-dev
1717
- run: rustup component add clippy
1818
- run: cargo clippy --fix -Z unstable-options --features vulkan
19+
- run: git diff
1920
- name: Create Pull Request
20-
uses: peter-evans/create-pull-request@v3
21+
uses: peter-evans/create-pull-request@v3.5.0
2122
with:
2223
token: ${{ secrets.GITHUB_TOKEN }}
2324
branch-suffix: timestamp

assets/levels/level_1.json

+14-6
Large diffs are not rendered by default.

assets/levels/level_1.png

637 Bytes
Loading

assets/sprites/bullets.png

93 Bytes
Loading

assets/sprites/bullets.ron

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
List((
2+
texture_width: 12,
3+
texture_height: 4,
4+
sprites: [
5+
(
6+
x: 0,
7+
y: 0,
8+
width: 4,
9+
height: 4,
10+
),
11+
(
12+
x: 4,
13+
y: 0,
14+
width: 8,
15+
height: 4,
16+
),
17+
]
18+
))

assets/sprites/main.png

6 Bytes
Loading

src/entities/canons.rs

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
use amethyst::core::ecs::{DenseVecStorage, Component};
2+
use crate::utils::Direction;
3+
#[derive(Debug)]
4+
pub enum CanonKind {
5+
Bullet, Plasma, Air
6+
}
7+
#[derive(Debug)]
8+
pub struct Canon {
9+
pub direction: Direction,
10+
pub kind: CanonKind,
11+
pub bullet_x_start: f32,
12+
pub bullet_y_start: f32
13+
}
14+
15+
impl Component for Canon {
16+
type Storage = DenseVecStorage<Self>;
17+
}
18+
#[derive(Debug)]
19+
pub struct Bullet {
20+
pub direction: Direction,
21+
}
22+
23+
impl Component for Bullet {
24+
type Storage = DenseVecStorage<Self>;
25+
}

src/entities/collision.rs

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ impl Component for Transparent {
1515
type Storage = DenseVecStorage<Self>;
1616
}
1717

18+
#[derive(Debug)]
1819
pub struct Colliders {
1920
colliders: Vec<Collider>,
2021
polygons: Vec<Polygon<f32>>

src/entities/mod.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
pub mod ship;
22
pub mod collision;
3-
pub mod explosion;
3+
pub mod explosion;
4+
pub mod canons;

src/main.rs

+12-1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ use crate::systems::explosion_systems::ExplosionSystem;
2727
use crate::utils::starlight_tile::StartLightTile;
2828
use amethyst_tiles::MortonEncoder;
2929
use amethyst_tiles::RenderTiles2D;
30+
use crate::systems::canon_system::CanonSystem;
31+
use crate::systems::bullet_system::BulletSystem;
3032

3133
fn main() -> amethyst::Result<()> {
3234
amethyst::start_logger(Default::default());
@@ -55,7 +57,6 @@ fn main() -> amethyst::Result<()> {
5557
)
5658
.with_plugin(RenderUi::default())
5759
.with_plugin(RenderFlat2D::default())
58-
.with_plugin(RenderTiles2D::<StartLightTile, MortonEncoder>::default()),
5960
)?
6061
.with(
6162
ShipSystem,
@@ -82,6 +83,16 @@ fn main() -> amethyst::Result<()> {
8283
"explosion_system",
8384
&[],
8485
)
86+
.with(
87+
CanonSystem::default(),
88+
"canon_system",
89+
&[],
90+
)
91+
.with(
92+
BulletSystem,
93+
"bullet_system",
94+
&[],
95+
)
8596
;
8697

8798
let mut game = Application::new(resources, LevelState, game_data)?;

src/resources/main_resource.rs

+8-4
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,14 @@ pub struct MainResource {
1818
pub should_be_reset: bool,
1919
_gravity: f32,
2020
current_level_config: Option<LevelConfig>,
21-
pub sprites: Option<ShipSprites>
21+
pub sprites: Option<MainSprites>,
2222

23+
pub ship_life: usize,
2324
}
2425

25-
pub struct ShipSprites {
26-
pub explosion_sprite_render: Handle<SpriteSheet>
26+
pub struct MainSprites {
27+
pub explosion_sprite_render: Handle<SpriteSheet>,
28+
pub bullet_sprite_render: Handle<SpriteSheet>
2729
}
2830

2931
impl MainResource {
@@ -38,7 +40,8 @@ impl MainResource {
3840
is_exploding: false,
3941
should_be_reset: false,
4042
current_level_config,
41-
sprites: None
43+
sprites: None,
44+
ship_life: 3
4245
}
4346
}
4447

@@ -58,6 +61,7 @@ impl MainResource {
5861
self.current_rotation_angle = 0.;
5962
self.is_exploding = false;
6063
self.should_be_reset = false;
64+
self.ship_life = 3;
6165
}
6266

6367
pub fn power(&mut self, delta_time: f32, rotation: &UnitQuaternion<f32>) {

src/states/level.rs

+16-7
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ use serde_json::from_reader;
1010
use serde::Deserialize;
1111
use std::collections::HashMap;
1212
use crate::entities::ship::{Ship, ShipParent, Thrusters};
13-
use crate::resources::main_resource::{MainResource, ShipSprites};
14-
use crate::utils::sprite_to_colliders::{sprite_to_colliders, is_landing_platform_start};
13+
use crate::resources::main_resource::{MainResource, MainSprites};
14+
use crate::utils::sprite_to_entities::{sprite_to_colliders, is_landing_platform_start, sprite_to_canon};
1515
use crate::entities::collision::{Transparent, LandingPlatform};
1616
use amethyst::utils::application_root_dir;
1717
use amethyst::core::math::{Point3, Vector3};
@@ -31,6 +31,9 @@ const CONFIG_MISC: &str = "sprites/main.ron";
3131
const IMAGE_SHIP: &str = "sprites/space_ship.png";
3232
const CONFIG_SHIP: &str = "sprites/space_ship.ron";
3333

34+
const IMAGE_BULLETS: &str = "sprites/bullets.png";
35+
const CONFIG_BULLETS: &str = "sprites/bullets.ron";
36+
3437
const IMAGE_EXPLOSION: &str = "sprites/explosion.png";
3538
const CONFIG_EXPLOSION: &str = "sprites/explosion.ron";
3639

@@ -43,14 +46,15 @@ impl SimpleState for LevelState {
4346
//let misc_spritesheet_handle = load_misc_spritesheet(world);
4447
let level_spritesheet_handle = load_level_spritesheet(world, 1);
4548
let ship_spritesheet_handle = load_ship_spritesheet(world);
49+
let bullet_spritesheet_handle = load_bullets_spritesheet(world);
4650
let ship_explosion_handle = load_explosion_spritesheet(world);
4751

4852
initialize_level_tileset(world, level_spritesheet_handle, &level);
49-
initialize_colliders(world, &level);
53+
initialize_colliders_with_entitites(world, &level);
5054
let ship = initialize_ship(world, &level, ship_spritesheet_handle);
5155
initialize_camera(world, &level, ship);
5256
let mut ship_resource = MainResource::new_from_level(Some(level));
53-
ship_resource.sprites = Some(ShipSprites { explosion_sprite_render: ship_explosion_handle });
57+
ship_resource.sprites = Some(MainSprites { explosion_sprite_render: ship_explosion_handle, bullet_sprite_render: bullet_spritesheet_handle });
5458
world.insert(ship_resource);
5559
}
5660
}
@@ -63,6 +67,10 @@ pub fn load_ship_spritesheet(world: &mut World) -> Handle<SpriteSheet> {
6367
load_texture(world, IMAGE_SHIP, CONFIG_SHIP)
6468
}
6569

70+
pub fn load_bullets_spritesheet(world: &mut World) -> Handle<SpriteSheet> {
71+
load_texture(world, IMAGE_BULLETS, CONFIG_BULLETS)
72+
}
73+
6674
pub fn load_explosion_spritesheet(world: &mut World) -> Handle<SpriteSheet> {
6775
load_texture(world, IMAGE_EXPLOSION, CONFIG_EXPLOSION)
6876
}
@@ -98,7 +106,7 @@ fn load_texture(world: &mut World, image: &str, config: &str) -> Handle<SpriteSh
98106
)
99107
}
100108

101-
fn initialize_colliders(world: &mut World, level: &LevelConfig) {
109+
fn initialize_colliders_with_entitites(world: &mut World, level: &LevelConfig) {
102110
for (point, sprite) in level.tiles.borrow() {
103111
let collider = sprite_to_colliders(*sprite, point.x as f32 * TILE_SIZE, point.y as f32 * TILE_SIZE);
104112
if collider.is_some() {
@@ -107,6 +115,7 @@ fn initialize_colliders(world: &mut World, level: &LevelConfig) {
107115
.with(collider.unwrap());
108116

109117
if is_landing_platform_start(*sprite) { builder = builder.with(LandingPlatform); }
118+
if let Some(canon) = sprite_to_canon(*sprite, point.x as usize, point.y as usize) {builder = builder.with(canon); }
110119
builder.build();
111120
}
112121
}
@@ -122,7 +131,7 @@ fn initialize_level_tileset(
122131
sprite_number: 0,
123132
};
124133
let mut t = Transform::default();
125-
t.set_translation_xyz(32. * level.width as f32 / 2. - 16.0, 32. * level.height as f32 / 2. - 16., 0.);
134+
t.set_translation_xyz( (TILE_SIZE * level.width as f32) / 2. - TILE_SIZE / 2., (TILE_SIZE * level.height as f32) / 2. - TILE_SIZE / 2., 0.);
126135
world
127136
.create_entity()
128137
.with(sprite_render)
@@ -148,7 +157,7 @@ fn initialize_ship(
148157
let mut transform = Transform::default();
149158
transform.set_translation_xyz(
150159
level.start_x as f32 * TILE_SIZE - 16.,
151-
((level.height - level.start_y) as f32 * TILE_SIZE) -32.,
160+
((level.height - level.start_y) as f32 * TILE_SIZE),
152161
0.04,
153162
);
154163

src/systems/bullet_system.rs

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
use amethyst::core::ecs::{System, ReadStorage, WriteStorage, Join, Read, Entities, Write};
2+
use crate::entities::canons::{Bullet, Canon, CanonKind};
3+
use amethyst::core::{Transform, Time};
4+
use crate::utils::Direction;
5+
use crate::entities::collision::{Colliders, are_colliding};
6+
use geo::Polygon;
7+
use crate::utils::sprite_to_entities::init_bullet_collider;
8+
use std::ops::Deref;
9+
use crate::resources::main_resource::MainResource;
10+
use crate::entities::ship::ShipParent;
11+
12+
pub struct BulletSystem;
13+
14+
impl<'s> System<'s> for BulletSystem {
15+
type SystemData = (
16+
ReadStorage<'s, Bullet>,
17+
ReadStorage<'s, Canon>,
18+
WriteStorage<'s, Transform>,
19+
ReadStorage<'s, Colliders>,
20+
ReadStorage<'s, ShipParent>,
21+
Write<'s, MainResource>,
22+
Read<'s, Time>,
23+
Entities<'s>,);
24+
25+
fn run(&mut self, (bullets, canons, mut transforms, colliders, ships,mut main_resource, time, entities): Self::SystemData) {
26+
let mut ship_polygon = Vec::new();
27+
for (_ship, transform) in (&ships, &transforms).join() {
28+
ship_polygon = main_resource.get_colliders_polygons(transform.translation().x, transform.translation().y);
29+
}
30+
let mut bullet_vec: Vec<(u32, Vec<Polygon<f32>>)> = Vec::new();
31+
for (bullet, transform, entity) in (&bullets, &mut transforms, &entities).join() {
32+
let colliders = init_bullet_collider(CanonKind::Bullet, transform.translation().x, transform.translation().y);
33+
if are_colliding(colliders.polygons(), &ship_polygon) {
34+
main_resource.ship_life -= 1;
35+
entities.delete(entity);
36+
}else{
37+
bullet_vec.push((entity.id(), colliders.polygons().clone()));
38+
}
39+
match bullet.direction {
40+
Direction::Left => transform.append_translation_xyz(-200.0 * time.delta_seconds(), 0., 0.),
41+
Direction::Right => transform.append_translation_xyz(200.0 * time.delta_seconds(), 0., 0.),
42+
_ => {transform.append_translation_xyz(0.,0.,0.)}
43+
};
44+
}
45+
for (platform_collider, _, _) in (&colliders, !&bullets, !&canons).join() {
46+
for (id, polygons) in bullet_vec.iter(){
47+
if are_colliding(&polygons, platform_collider.polygons()) {
48+
let e = entities.entity(*id);
49+
entities.delete(e);
50+
}
51+
}
52+
}
53+
}
54+
}

src/systems/canon_system.rs

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
use amethyst::core::ecs::{System, WriteStorage, ReadStorage, Entities, Join, Read};
2+
use crate::entities::collision::Colliders;
3+
use amethyst::core::{Transform, Time};
4+
use crate::entities::canons::{Canon, Bullet, CanonKind};
5+
use amethyst::renderer::SpriteRender;
6+
use std::collections::HashMap;
7+
use amethyst::core::ecs::world::Index;
8+
use rand::{random, Rng};
9+
use crate::utils::Direction;
10+
use crate::resources::main_resource::MainResource;
11+
use crate::utils::sprite_to_entities::init_bullet_collider;
12+
13+
pub struct CanonSystem {
14+
shooting_timers: HashMap<u32, f32>
15+
}
16+
17+
impl Default for CanonSystem {
18+
fn default() -> Self {
19+
CanonSystem {
20+
shooting_timers: HashMap::new()
21+
}
22+
}
23+
}
24+
25+
impl<'s> System<'s> for CanonSystem {
26+
type SystemData = (
27+
ReadStorage<'s, Canon>,
28+
WriteStorage<'s, Bullet>,
29+
WriteStorage<'s, Transform>,
30+
WriteStorage<'s, SpriteRender>,
31+
Read<'s, Time>,
32+
Read<'s, MainResource>,
33+
Entities<'s>,
34+
);
35+
36+
fn run(&mut self, (canons, mut bullets, mut transforms, mut sprite_renders, time,resource, entities): Self::SystemData) {
37+
for (canon, entity) in (&canons, &entities).join() {
38+
*self.shooting_timers.entry(entity.id())
39+
.or_insert(rand::thread_rng().gen_range(0.1, 2.5)) -= time.delta_seconds();
40+
let mut val = self.shooting_timers.get(&entity.id()).unwrap();
41+
if val <= &0. {
42+
let mut bullet_transform = Transform::default();
43+
bullet_transform.set_translation_xyz(canon.bullet_x_start, canon.bullet_y_start, 0.9);
44+
entities
45+
.build_entity()
46+
.with(Bullet{ direction: canon.direction.clone() }, &mut bullets)
47+
.with(SpriteRender {
48+
sprite_sheet: resource.sprites.as_ref().unwrap().bullet_sprite_render.clone(),
49+
sprite_number: 0,
50+
}, &mut sprite_renders)
51+
.with(bullet_transform, &mut transforms)
52+
.build();
53+
54+
self.shooting_timers.remove(&entity.id());
55+
self.shooting_timers.insert(entity.id(), 1.5);
56+
}
57+
}
58+
}
59+
}

src/systems/collision_system.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use amethyst::assets::Handle;
1111
use amethyst::core::ecs::storage::MaskedStorage;
1212
use amethyst_tiles::{TileMap, MortonEncoder2D};
1313
use crate::utils::starlight_tile::StartLightTile;
14+
use crate::entities::canons::Bullet;
1415

1516
pub struct CollisionSystem;
1617

@@ -23,15 +24,15 @@ impl<'s> System<'s> for CollisionSystem {
2324
Write<'s, MainResource>,
2425
WriteStorage<'s, Explosion>,
2526
WriteStorage<'s, SpriteRender>,
26-
Entities<'s>,
27-
ReadStorage<'s, TileMap<StartLightTile, MortonEncoder2D>>
27+
ReadStorage<'s, Bullet>,
28+
Entities<'s>
2829
);
2930

30-
fn run(&mut self, (colliders, landing_plateforms, ships, mut transforms, mut ship_resource, mut explosions, mut sprite_renders, entities, tilemap): Self::SystemData) {
31+
fn run(&mut self, (colliders, landing_plateforms, ships, mut transforms, mut ship_resource, mut explosions, mut sprite_renders, bullets, entities): Self::SystemData) {
3132
let mut explosion_information = (false, 0., 0.);
3233
for (_ship, transform) in (&ships, &transforms).join() {
3334
let ship_polygon = ship_resource.get_colliders_polygons(transform.translation().x, transform.translation().y);
34-
for (collider, _) in (&colliders, !&landing_plateforms).join() {
35+
for (collider, _, _) in (&colliders, !&landing_plateforms, !&bullets).join() {
3536
let struct_polygons = collider.polygons();
3637
if !ship_resource.is_exploding && are_colliding(&ship_polygon, struct_polygons) {
3738
ship_resource.is_exploding = true;

src/systems/mod.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,6 @@ pub mod ship_systems;
22
pub mod collision_system;
33
pub mod thruster_system;
44
pub mod explosion_systems;
5-
pub mod landing_system;
5+
pub mod landing_system;
6+
pub mod canon_system;
7+
pub mod bullet_system;

0 commit comments

Comments
 (0)