├── assets ├── coin.animation.yml ├── coin.png └── README.md ├── .gitignore ├── .github └── workflows │ ├── create-release.yml │ └── check.yml ├── .cargo └── fast_compiles_config ├── release.toml ├── renovate.json ├── Cargo.toml ├── LICENSE-MIT ├── UNLICENSE ├── CHANGELOG.md ├── justfile ├── src ├── lib.rs ├── animation │ ├── mod.rs │ └── dto.rs └── state.rs ├── examples └── bevy.rs ├── README.md └── CONTRIBUTING.md /assets/coin.animation.yml: -------------------------------------------------------------------------------- 1 | mode: Repeat 2 | fps: 12 3 | frames: [0, 1, 2, 3, 4] 4 | -------------------------------------------------------------------------------- /assets/coin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jcornaz/benimator/HEAD/assets/coin.png -------------------------------------------------------------------------------- /assets/README.md: -------------------------------------------------------------------------------- 1 | # Credits 2 | 3 | Coin by [La Red Games](https://laredgames.itch.io/gems-coins-free) (CC0) 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Rust 2 | /target 3 | /Cargo.lock 4 | /.cargo/*.toml 5 | 6 | # IDE 7 | /.idea 8 | /.vscode 9 | *.iml 10 | 11 | # Operating systems 12 | .DS_Store 13 | .trashes 14 | *.db 15 | 16 | # Nodes tools 17 | /node_modules 18 | -------------------------------------------------------------------------------- /.github/workflows/create-release.yml: -------------------------------------------------------------------------------- 1 | name: Create github release 2 | 3 | permissions: 4 | contents: write 5 | 6 | on: 7 | push: 8 | tags: 9 | - v[0-9]+.* 10 | 11 | jobs: 12 | create-release: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v4 16 | - uses: taiki-e/create-gh-release-action@v1 17 | with: 18 | changelog: CHANGELOG.md 19 | token: ${{ github.token }} 20 | -------------------------------------------------------------------------------- /.cargo/fast_compiles_config: -------------------------------------------------------------------------------- 1 | # Copy the content of this file to `.cargo/config.toml` 2 | 3 | [target.x86_64-unknown-linux-gnu] 4 | linker = "clang" 5 | rustflags = ["-Clink-arg=-fuse-ld=lld"] 6 | 7 | [target.x86_64-apple-darwin] 8 | rustflags = ["-C", "link-arg=-fuse-ld=/usr/local/bin/zld"] 9 | 10 | [target.aarch64-apple-darwin] 11 | rustflags = ["-C", "link-arg=-fuse-ld=/opt/homebrew/bin/zld"] 12 | 13 | [target.x86_64-pc-windows-msvc] 14 | linker = "rust-lld.exe" 15 | 16 | [target.wasm32-unknown-unknown] 17 | runner = "wasm-server-runner" 18 | -------------------------------------------------------------------------------- /.github/workflows/check.yml: -------------------------------------------------------------------------------- 1 | name: check 2 | 3 | on: 4 | push: 5 | branches: ["[0-9]+.x", main, rc, beta, alpha] 6 | pull_request: 7 | workflow_dispatch: 8 | 9 | jobs: 10 | verify: 11 | runs-on: ubuntu-24.04 12 | timeout-minutes: 10 13 | steps: 14 | - uses: actions/checkout@v4 15 | - uses: dtolnay/rust-toolchain@stable 16 | with: 17 | components: clippy, rustfmt 18 | - uses: Swatinem/rust-cache@v2 19 | - uses: taiki-e/install-action@v2 20 | with: 21 | tool: cargo-hack@0.5,just@1,cargo-msrv@0.16 22 | - run: just verify 23 | -------------------------------------------------------------------------------- /release.toml: -------------------------------------------------------------------------------- 1 | allow-branch = ["main"] 2 | pre-release-commit-message = "release {{version}}" 3 | 4 | [[pre-release-replacements]] 5 | file = "CHANGELOG.md" 6 | search = "## \\[Unreleased\\]" 7 | replace = "## [Unreleased]\n\n\n## [{{version}}] - {{date}}" 8 | prerelease = true 9 | exactly = 1 10 | 11 | [[pre-release-replacements]] 12 | file = "CHANGELOG.md" 13 | search = "\\.\\.\\.HEAD" 14 | replace = "...v{{version}}" 15 | prerelease = true 16 | exactly = 1 17 | 18 | [[pre-release-replacements]] 19 | file = "CHANGELOG.md" 20 | search = "\\[Unreleased\\]:" 21 | replace = "[Unreleased]: https://github.com/jcornaz/beancount-parser/compare/v{{version}}...HEAD\n[{{version}}]:" 22 | prerelease = true 23 | exactly = 1 24 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": ["config:recommended"], 4 | "timezone": "Europe/Zurich", 5 | "schedule": ["after 10pm", "before 5:00am"], 6 | "packageRules": [ 7 | { 8 | "matchPackageNames": "bevy", 9 | "enabled": false 10 | }, 11 | { 12 | "matchCurrentVersion": ">=1.0.0", 13 | "matchUpdateTypes": [ 14 | "minor", 15 | "patch" 16 | ], 17 | "automerge": true 18 | }, 19 | { 20 | "matchCurrentVersion": ">=0.1.0 <1.0.0", 21 | "matchUpdateTypes": [ 22 | "patch" 23 | ], 24 | "automerge": true 25 | }, 26 | { 27 | "matchDepTypes": [ 28 | "dev-dependencies" 29 | ], 30 | "automerge": true 31 | } 32 | ] 33 | } 34 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "benimator" 3 | version = "4.1.3" 4 | edition = "2021" 5 | rust-version = "1.70" 6 | authors = ["Jonathan Cornaz"] 7 | license = "Unlicense OR MIT" 8 | description = "A sprite animation library for rust game development" 9 | repository = "https://github.com/jcornaz/benimator" 10 | keywords = ["game", "gamedev", "anmiation"] 11 | categories = ["game-development"] 12 | 13 | [package.metadata.docs.rs] 14 | all-features = true 15 | 16 | [features] 17 | default = [] 18 | 19 | [dependencies] 20 | # Public dependencies (Present in the public API) 21 | serde = { version = "1.0.200", features = ["derive"], optional = true } 22 | 23 | [dev-dependencies] 24 | serde_yaml = { version = "0.9.34", default-features = false } 25 | rstest = { version = "0.21.0", default-features = false } 26 | bevy = { version = "0.12.1", default-features = false, features = ["bevy_asset", "bevy_winit", "bevy_render", "bevy_sprite", "bevy_core_pipeline", "png", "x11", "dynamic_linking"] } 27 | anyhow = "1.0.82" 28 | toml = "0.8.12" 29 | 30 | [build-dependencies] 31 | rustc_version = "0.4.0" 32 | 33 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Jonathan Cornaz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /UNLICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). 6 | 7 | 8 | ## [Unreleased] 9 | 10 | ### Dependencies 11 | 12 | * Minimum supported rust version raised to `1.70` 13 | 14 | 15 | ## [4.1.3] - 2023-07-01 16 | 17 | ### Bug fixes 18 | 19 | * Fixed deserialization error of a "short form" frame list when using the toml crate. 20 | 21 | 22 | ### Thank you 23 | 24 | * @tguichaoua 25 | 26 | 27 | ## [4.1.2](https://github.com/jcornaz/benimator/compare/v4.1.1...v4.1.2) (2023-01-09) 28 | 29 | 30 | ### Documentation 31 | 32 | * **readme:** lower minimum support rust version to 1.60 ([909eaea](https://github.com/jcornaz/benimator/commit/909eaea4b8974872126961c2be0650aa5e3e5b85)) 33 | 34 | ## [4.1.1](https://github.com/jcornaz/benimator/compare/v4.1.0...v4.1.1) (2023-01-08) 35 | 36 | 37 | ### Documentation 38 | 39 | * **readme:** fix build badge ([6ee96e7](https://github.com/jcornaz/benimator/commit/6ee96e719de6cef82eb04d4ca86e11cef3e011a1)) 40 | * **readme:** remove build status badge ([dd9adc9](https://github.com/jcornaz/benimator/commit/dd9adc9aa0b4d47c7eabcfcbf954f9bc9e2e4ca7)) 41 | 42 | 43 | [Unreleased]: https://github.com/jcornaz/beancount-parser/compare/v4.1.3...HEAD 44 | [4.1.3]: https://github.com/jcornaz/benimator/compare/v4.1.2...v4.1.3 45 | 46 | -------------------------------------------------------------------------------- /justfile: -------------------------------------------------------------------------------- 1 | set dotenv-load 2 | 3 | @_choose: 4 | just --choose --unsorted 5 | 6 | # Perform all verifications (compile, test, lint, etc.) 7 | verify: test lint doc check-msrv 8 | 9 | # Watch the source files and run `just verify` when source changes 10 | watch: 11 | cargo watch --delay 0.1 --clear --why -- just verify 12 | 13 | # Run the tests 14 | test: 15 | cargo hack test --feature-powerset --optional-deps 16 | 17 | # Run the static code analysis 18 | lint: 19 | cargo fmt -- --check 20 | cargo hack clippy --feature-powerset --all-targets --optional-deps 21 | 22 | # Build the documentation 23 | doc *args: 24 | cargo doc --all-features --no-deps {{args}} 25 | 26 | # Open the documentation page 27 | doc-open: (doc "--open") 28 | 29 | # Run the given example 30 | run example: 31 | cargo run --all-features --example {{example}} 32 | 33 | # Make sure the MSRV is satisfiable 34 | check-msrv: 35 | cargo msrv verify 36 | 37 | # Clean up compilation output 38 | clean: 39 | rm -rf target 40 | rm -f Cargo.lock 41 | rm -rf node_modules 42 | 43 | # Install cargo dev-tools used by the `verify` recipe (requires rustup to be already installed) 44 | install-dev-tools: 45 | rustup install stable 46 | rustup override set stable 47 | cargo install cargo-hack cargo-watch cargo-msrv 48 | 49 | # Install a git hook to run tests before every commits 50 | install-git-hooks: 51 | echo '#!/usr/bin/env sh' > .git/hooks/pre-commit 52 | echo 'just verify' >> .git/hooks/pre-commit 53 | chmod +x .git/hooks/pre-commit 54 | 55 | release *args: verify 56 | cargo release {{args}} 57 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![warn( 2 | future_incompatible, 3 | nonstandard_style, 4 | rust_2018_idioms, 5 | missing_docs, 6 | clippy::pedantic 7 | )] 8 | #![cfg_attr(test, allow(clippy::needless_pass_by_value))] 9 | #![cfg_attr(nightly, feature(doc_auto_cfg))] 10 | 11 | //! A sprite animation library for rust game development 12 | //! 13 | //! Initially designed for [bevy], it is now engine agnostic. 14 | //! 15 | //! # Get started 16 | //! 17 | //! benimator assumes usage of texture atlas (or equivalent). 18 | //! 19 | //! An [`Animation`] contains the list of animation frames, 20 | //! each frame defined by an index. 21 | //! 22 | //! ``` 23 | //! # use std::time::Duration; 24 | //! use benimator::*; 25 | //! 26 | //! // Create an animation 27 | //! let animation = Animation::from_indices(0..=3, FrameRate::from_fps(10.0)); 28 | //! 29 | //! // Create a new animation state 30 | //! let mut state = State::new(); 31 | //! 32 | //! // In the game loop, for each update, tell the state how much time has elapsed 33 | //! let delta_time = Duration::from_millis(250); 34 | //! state.update(&animation, delta_time); 35 | //! 36 | //! // Then get the current frame index. 37 | //! // (so that we can tell our engine to render the sprite at that index) 38 | //! assert_eq!(state.frame_index(), 2); 39 | //! ``` 40 | //! 41 | //! Have a look at the [examples](https://github.com/jcornaz/benimator/tree/main/examples) for complete examples using the [bevy] game engine. 42 | //! 43 | //! [bevy]: https://bevyengine.org 44 | 45 | #[cfg(test)] 46 | #[macro_use] 47 | extern crate rstest; 48 | 49 | pub use animation::{Animation, Frame, FrameRate}; 50 | pub use state::State; 51 | 52 | mod animation; 53 | mod state; 54 | -------------------------------------------------------------------------------- /examples/bevy.rs: -------------------------------------------------------------------------------- 1 | use bevy::prelude::*; 2 | 3 | use benimator::FrameRate; 4 | 5 | // Create the animation component 6 | // Note: you may make the animation an asset instead of a component 7 | #[derive(Component, Deref)] 8 | struct Animation(benimator::Animation); 9 | 10 | // Create the player component 11 | #[derive(Default, Component, Deref, DerefMut)] 12 | struct AnimationState(benimator::State); 13 | 14 | fn main() { 15 | App::new() 16 | .add_plugins(DefaultPlugins.set(ImagePlugin::default_nearest())) 17 | .add_systems(Startup, spawn) 18 | .add_systems(Update, animate) 19 | .run(); 20 | } 21 | 22 | fn spawn( 23 | mut commands: Commands, 24 | asset_server: Res, 25 | mut textures: ResMut>, 26 | ) { 27 | // Don't forget the camera ;-) 28 | commands.spawn(Camera2dBundle::default()); 29 | 30 | // Create an animation 31 | let animation = Animation(benimator::Animation::from_indices( 32 | 0..=4, 33 | FrameRate::from_fps(12.0), 34 | )); 35 | 36 | commands 37 | // Spawn a bevy sprite-sheet 38 | .spawn(SpriteSheetBundle { 39 | texture_atlas: textures.add(TextureAtlas::from_grid( 40 | asset_server.load("coin.png"), 41 | Vec2::new(16.0, 16.0), 42 | 5, 43 | 1, 44 | None, 45 | None, 46 | )), 47 | transform: Transform::from_scale(Vec3::splat(10.0)), 48 | ..Default::default() 49 | }) 50 | // Insert the animation 51 | .insert(animation) 52 | // Insert the state 53 | .insert(AnimationState::default()); 54 | } 55 | 56 | fn animate( 57 | time: Res