├── .gitignore
├── cover.png
├── assets
├── heart.png
├── icon.png
├── log.png
├── tile.png
├── goblin.png
├── card_base.png
├── tile_base.glb
├── tile_slot.png
├── tile_woods.png
└── villager.png
├── tile_base.blend
├── tile_base.blend1
├── README.md
├── wasm
└── index.html
├── LICENSE
├── Cargo.toml
├── src
├── main.rs
└── game
│ ├── mod.rs
│ ├── animate.rs
│ ├── camera.rs
│ ├── progress_bar.rs
│ ├── tile.rs
│ └── card.rs
├── .cargo
└── config.toml
├── .github
└── workflows
│ ├── ci.yaml
│ └── release.yaml
├── source.svg
└── Cargo.lock
/.gitignore:
--------------------------------------------------------------------------------
1 | /target
2 |
--------------------------------------------------------------------------------
/cover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cart/card_combinator/HEAD/cover.png
--------------------------------------------------------------------------------
/assets/heart.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cart/card_combinator/HEAD/assets/heart.png
--------------------------------------------------------------------------------
/assets/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cart/card_combinator/HEAD/assets/icon.png
--------------------------------------------------------------------------------
/assets/log.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cart/card_combinator/HEAD/assets/log.png
--------------------------------------------------------------------------------
/assets/tile.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cart/card_combinator/HEAD/assets/tile.png
--------------------------------------------------------------------------------
/tile_base.blend:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cart/card_combinator/HEAD/tile_base.blend
--------------------------------------------------------------------------------
/tile_base.blend1:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cart/card_combinator/HEAD/tile_base.blend1
--------------------------------------------------------------------------------
/assets/goblin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cart/card_combinator/HEAD/assets/goblin.png
--------------------------------------------------------------------------------
/assets/card_base.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cart/card_combinator/HEAD/assets/card_base.png
--------------------------------------------------------------------------------
/assets/tile_base.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cart/card_combinator/HEAD/assets/tile_base.glb
--------------------------------------------------------------------------------
/assets/tile_slot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cart/card_combinator/HEAD/assets/tile_slot.png
--------------------------------------------------------------------------------
/assets/tile_woods.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cart/card_combinator/HEAD/assets/tile_woods.png
--------------------------------------------------------------------------------
/assets/villager.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cart/card_combinator/HEAD/assets/villager.png
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Card Combinator
2 |
3 | 
4 |
5 | A game about stacking cards on top of each other to make new cards. Built for [Bevy Jam #2](https://itch.io/jam/bevy-jam-2).
--------------------------------------------------------------------------------
/wasm/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | This is dual-licensed under either
2 |
3 | * MIT License (docs/LICENSE-MIT or http://opensource.org/licenses/MIT)
4 | * Apache License, Version 2.0 (docs/LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
5 |
6 | at your option.
--------------------------------------------------------------------------------
/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "card_combinator"
3 | version = "0.1.0"
4 | edition = "2021"
5 | license = "MIT OR Apache-2.0"
6 |
7 | [profile.dev.package."*"]
8 | opt-level = 3
9 |
10 | [profile.dev]
11 | opt-level = 1
12 |
13 | [dependencies]
14 | bevy = "0.8"
15 | bevy-inspector-egui = "0.12"
16 | bevy_rapier3d = {version = "0.16", features = ["debug-render"]}
--------------------------------------------------------------------------------
/src/main.rs:
--------------------------------------------------------------------------------
1 | #[allow(dead_code, unused_variables, unused_mut, unused_imports)]
2 | mod game;
3 |
4 | use bevy::{asset::AssetServerSettings, prelude::*};
5 | use bevy_rapier3d::prelude::*;
6 |
7 | use crate::game::GamePlugin;
8 |
9 | fn main() {
10 | App::new()
11 | .insert_resource(AmbientLight {
12 | color: Color::WHITE,
13 | brightness: 0.4,
14 | })
15 | .insert_resource(AssetServerSettings {
16 | watch_for_changes: true,
17 | ..default()
18 | })
19 | .insert_resource(ClearColor(Color::rgb(0.2, 0.2, 0.2)))
20 | .add_plugins(DefaultPlugins)
21 | .add_plugin(RapierPhysicsPlugin::::default())
22 | // .add_plugin(bevy_inspector_egui::WorldInspectorPlugin::new())
23 | // .add_plugin(RapierDebugRenderPlugin::default())
24 | .add_plugin(GamePlugin)
25 | .run();
26 | }
27 |
--------------------------------------------------------------------------------
/.cargo/config.toml:
--------------------------------------------------------------------------------
1 | # Add the contents of this file to `config.toml` to enable "fast build" configuration. Please read the notes below.
2 |
3 | # NOTE: For maximum performance, build using a nightly compiler
4 | # If you are using rust stable, remove the "-Zshare-generics=y" below (as well as "-Csplit-debuginfo=unpacked" when building on macOS).
5 |
6 | [target.x86_64-unknown-linux-gnu]
7 | linker = "/usr/bin/clang"
8 | rustflags = ["-Clink-arg=-fuse-ld=lld"]
9 |
10 | # NOTE: you must manually install https://github.com/michaeleisel/zld on mac. you can easily do this with the "brew" package manager:
11 | # `brew install michaeleisel/zld/zld`
12 | # [target.x86_64-apple-darwin]
13 | # rustflags = ["-C", "link-arg=-fuse-ld=/usr/local/bin/zld", "-Zshare-generics=y", "-Csplit-debuginfo=unpacked"]
14 |
15 | # [target.x86_64-pc-windows-msvc]
16 | # linker = "rust-lld.exe"
17 | # rustflags = ["-Zshare-generics=y"]
18 |
19 | # Optional: Uncommenting the following improves compile times, but reduces the amount of debug info to 'line number tables only'
20 | # In most cases the gains are negligible, but if you are on macos and have slow compile times you should see significant gains.
21 | #[profile.dev]
22 | #debug = 1
23 |
--------------------------------------------------------------------------------
/src/game/mod.rs:
--------------------------------------------------------------------------------
1 | pub mod animate;
2 | pub mod camera;
3 | pub mod card;
4 | pub mod progress_bar;
5 | pub mod tile;
6 |
7 | use std::f32::consts::PI;
8 |
9 | use self::camera::PlayerCameraPlugin;
10 | use crate::game::{
11 | card::{Card, CardBundle, CardPlugin, CardType},
12 | progress_bar::{ProgressBar, ProgressBarBundle, ProgressBarPlugin},
13 | tile::TilePlugin,
14 | };
15 | use bevy::prelude::*;
16 |
17 | pub struct GamePlugin;
18 |
19 | impl Plugin for GamePlugin {
20 | fn build(&self, app: &mut App) {
21 | app.add_plugin(CardPlugin)
22 | .add_plugin(PlayerCameraPlugin)
23 | .add_plugin(ProgressBarPlugin)
24 | .add_plugin(TilePlugin)
25 | .add_startup_system(setup);
26 | }
27 | }
28 |
29 | fn setup(
30 | mut commands: Commands,
31 | asset_server: Res,
32 | mut materials: ResMut>,
33 | mut meshes: ResMut>,
34 | ) {
35 | commands.spawn_bundle(CardBundle {
36 | transform: Transform::from_xyz(-0.5, 0.0, 0.0),
37 | card: Card::from(CardType::Villager),
38 | ..default()
39 | });
40 | commands.spawn_bundle(CardBundle {
41 | transform: Transform::from_xyz(0.5, 0.0, 0.0),
42 | card: Card::from(CardType::Villager),
43 | ..default()
44 | });
45 |
46 | // commands.spawn_bundle(CardBundle {
47 | // transform: Transform::from_xyz(0.0, 3.0, 0.0),
48 | // card: Card::from(CardType::Goblin),
49 | // ..default()
50 | // });
51 |
52 | // commands.spawn_bundle(CardBundle {
53 | // transform: Transform::from_xyz(1.0, 0.0, 0.0),
54 | // card: Card {
55 | // card_type: CardType::Log,
56 | // ..default()
57 | // },
58 | // ..default()
59 | // });
60 | }
61 |
--------------------------------------------------------------------------------
/src/game/animate.rs:
--------------------------------------------------------------------------------
1 | use std::{ops::Range, time::Duration};
2 |
3 | use bevy::prelude::Timer;
4 |
5 | pub struct AnimateRange {
6 | timer: Timer,
7 | ease: Ease,
8 | range: Range,
9 | }
10 |
11 | impl AnimateRange {
12 | pub fn new(duration: Duration, ease: Ease, range: Range, repeat: bool) -> Self {
13 | Self {
14 | timer: Timer::new(duration, repeat),
15 | ease,
16 | range,
17 | }
18 | }
19 |
20 | pub fn set_percent(&mut self, percent: f32) {
21 | self.timer.set_elapsed(Duration::from_secs_f32(
22 | self.timer.duration().as_secs_f32() * percent,
23 | ));
24 | }
25 |
26 | pub fn percent(&mut self) -> f32 {
27 | self.timer.percent()
28 | }
29 |
30 | pub fn reset(&mut self) {
31 | self.timer.reset();
32 | }
33 |
34 | pub fn just_finished(&mut self) -> bool {
35 | self.timer.just_finished()
36 | }
37 |
38 | pub fn finished(&mut self) -> bool {
39 | self.timer.finished()
40 | }
41 |
42 | pub fn tick(&mut self, delta: Duration) -> f32 {
43 | self.timer.tick(delta);
44 | let amount = self.ease.ease(self.timer.percent());
45 | self.range.start + ((self.range.end - self.range.start) * amount)
46 | }
47 | }
48 |
49 | #[derive(Copy, Clone)]
50 | #[allow(dead_code)]
51 | pub enum Ease {
52 | Linear,
53 | // Sin,
54 | InOutCirc,
55 | OutBack,
56 | // Custom(fn(f32) -> f32),
57 | }
58 |
59 | impl Ease {
60 | pub fn ease(&self, x: f32) -> f32 {
61 | match self {
62 | Ease::Linear => x,
63 | // Ease::Sin => x.sin(),
64 | Ease::InOutCirc => {
65 | if x < 0.5 {
66 | (1. - (1. - (2. * x).powf(2.)).sqrt()) / 2.
67 | } else {
68 | ((1. - (-2. * x + 2.).powf(2.)).sqrt() + 1.) / 2.
69 | }
70 | }
71 | Ease::OutBack => {
72 | const C1: f32 = 1.70158;
73 | const C3: f32 = C1 + 1.0;
74 |
75 | 1. + C3 * (x - 1.).powf(3.) + C1 * (x - 1.).powf(2.)
76 | }
77 | }
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yaml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on:
4 | push:
5 | branches: [main]
6 | pull_request:
7 | branches: [main]
8 |
9 | env:
10 | CARGO_TERM_COLOR: always
11 |
12 | jobs:
13 |
14 | # Run cargo test
15 | test:
16 | name: Test Suite
17 | runs-on: ubuntu-latest
18 | steps:
19 | - name: Checkout sources
20 | uses: actions/checkout@v2
21 | - name: Cache
22 | uses: actions/cache@v2
23 | with:
24 | path: |
25 | ~/.cargo/bin/
26 | ~/.cargo/registry/index/
27 | ~/.cargo/registry/cache/
28 | ~/.cargo/git/db/
29 | target/
30 | key: ${{ runner.os }}-cargo-test-${{ hashFiles('**/Cargo.toml') }}
31 | - name: Install stable toolchain
32 | uses: actions-rs/toolchain@v1
33 | with:
34 | profile: minimal
35 | toolchain: stable
36 | override: true
37 | - name: Install Dependencies
38 | run: sudo apt-get update; sudo apt-get install pkg-config libx11-dev libasound2-dev libudev-dev libxcb-render0-dev libxcb-shape0-dev libxcb-xfixes0-dev
39 | - name: Run cargo test
40 | uses: actions-rs/cargo@v1
41 | with:
42 | command: test
43 |
44 | # Run cargo clippy -- -D warnings
45 | clippy_check:
46 | name: Clippy
47 | runs-on: ubuntu-latest
48 | steps:
49 | - name: Checkout sources
50 | uses: actions/checkout@v2
51 | - name: Cache
52 | uses: actions/cache@v2
53 | with:
54 | path: |
55 | ~/.cargo/bin/
56 | ~/.cargo/registry/index/
57 | ~/.cargo/registry/cache/
58 | ~/.cargo/git/db/
59 | target/
60 | key: ${{ runner.os }}-cargo-clippy-${{ hashFiles('**/Cargo.toml') }}
61 | - name: Install stable toolchain
62 | uses: actions-rs/toolchain@v1
63 | with:
64 | toolchain: stable
65 | profile: minimal
66 | components: clippy
67 | override: true
68 | - name: Install Dependencies
69 | run: sudo apt-get update; sudo apt-get install pkg-config libx11-dev libasound2-dev libudev-dev
70 | - name: Run clippy
71 | uses: actions-rs/clippy-check@v1
72 | with:
73 | token: ${{ secrets.GITHUB_TOKEN }}
74 | args: -- -D warnings
75 |
76 | # Run cargo fmt --all -- --check
77 | format:
78 | name: Format
79 | runs-on: ubuntu-latest
80 | steps:
81 | - name: Checkout sources
82 | uses: actions/checkout@v2
83 | - name: Install stable toolchain
84 | uses: actions-rs/toolchain@v1
85 | with:
86 | toolchain: stable
87 | profile: minimal
88 | components: rustfmt
89 | override: true
90 | - name: Run cargo fmt
91 | uses: actions-rs/cargo@v1
92 | with:
93 | command: fmt
94 | args: --all -- --check
95 |
--------------------------------------------------------------------------------
/src/game/camera.rs:
--------------------------------------------------------------------------------
1 | use std::time::Duration;
2 |
3 | use bevy::{input::mouse::MouseWheel, prelude::*};
4 |
5 | use crate::game::animate::{AnimateRange, Ease};
6 |
7 | #[derive(Component)]
8 | pub struct PlayerCamera {
9 | base_speed: f32,
10 | }
11 |
12 | impl Default for PlayerCamera {
13 | fn default() -> Self {
14 | Self { base_speed: 4.0 }
15 | }
16 | }
17 | pub struct PlayerCameraPlugin;
18 |
19 | impl Plugin for PlayerCameraPlugin {
20 | fn build(&self, app: &mut App) {
21 | app.add_startup_system(setup_camera).add_system(move_camera);
22 | }
23 | }
24 |
25 | fn setup_camera(mut commands: Commands) {
26 | // camera
27 | commands
28 | .spawn_bundle(Camera3dBundle {
29 | transform: Transform {
30 | translation: Vec3::new(0.0, -1.5, 8.0),
31 | rotation: Quat::from_rotation_x(0.2),
32 | ..default()
33 | },
34 | ..default()
35 | })
36 | .insert(PlayerCamera::default());
37 | }
38 |
39 | pub fn move_camera(
40 | mut view_height: Local,
41 | mut scroll_accumulation: Local,
42 | time: Res