├── .gitignore ├── Cargo.toml ├── README.md ├── assets ├── fonts │ ├── FiraCodeNerdFontMono-Light.ttf │ ├── FiraMono-Medium.ttf │ ├── FiraSans-Bold.ttf │ └── SourceHanSansCN-Normal.otf ├── items │ ├── AK47.png │ ├── knife.png │ └── paper.png ├── space_battle │ ├── audio │ │ ├── disintegrator_fire_01.ogg │ │ ├── light_assault_gun_fire_01.ogg │ │ ├── ui_button_pressed.ogg │ │ └── ui_type.ogg │ ├── background4.jpg │ ├── engineflame32-orig.png │ ├── engineflame32-orig.pxd │ ├── engineflame32-orig2.png │ ├── engineflame32.png │ ├── lasher_ff.png │ ├── lasher_ff.pxd │ ├── lasher_ff_shape.png │ ├── lasher_ff_shape.svg │ ├── projbody.png │ ├── shader │ │ └── engine_flame.wgsl │ └── tempest.png ├── storage │ └── fow.json └── textures │ ├── HexTilesetv3.png │ ├── Idle.png │ └── Walk.png ├── examples ├── 2d │ ├── 2d_shapes.rs │ ├── 2d_viewport_to_world.rs │ ├── bloom_2d.rs │ ├── bounding_2d.rs │ ├── mesh2d.rs │ ├── mesh2d_arcs.rs │ ├── mesh2d_manual.rs │ ├── mesh2d_vertex_color_texture.rs │ ├── rotation.rs │ ├── sprite_animation.rs │ ├── sprite_flipping.rs │ ├── sprite_sheet.rs │ ├── sprite_slice.rs │ ├── sprite_tile.rs │ ├── text2d.rs │ ├── texture_atlas.rs │ ├── time.rs │ ├── timers.rs │ ├── transparency_2d.rs │ └── virtual_time.rs ├── README.md ├── async_tasks │ └── async_compute.rs ├── byronzr │ ├── camera_renderlayer │ │ └── main.rs │ ├── hexagon_tile │ │ ├── env.rs │ │ ├── main.rs │ │ └── utils.rs │ ├── inventory │ │ └── main.rs │ └── space_battle │ │ ├── README.md │ │ ├── components │ │ ├── audio.rs │ │ ├── effects.rs │ │ ├── mod.rs │ │ ├── ship.rs │ │ └── weapon.rs │ │ ├── effects │ │ └── mod.rs │ │ ├── events │ │ └── mod.rs │ │ ├── main.rs │ │ ├── resources │ │ ├── enemy.rs │ │ ├── menu.rs │ │ ├── mod.rs │ │ ├── player.rs │ │ └── turret.rs │ │ ├── shader │ │ └── mod.rs │ │ ├── strategies │ │ ├── enemy │ │ │ ├── collision.rs │ │ │ ├── mod.rs │ │ │ ├── movement.rs │ │ │ └── random.rs │ │ ├── mod.rs │ │ ├── player │ │ │ ├── drift.rs │ │ │ ├── generate.rs │ │ │ ├── mod.rs │ │ │ └── player_detection.rs │ │ ├── projectile.rs │ │ ├── turret.rs │ │ └── weapon.rs │ │ ├── ui │ │ ├── detect.rs │ │ ├── game │ │ │ ├── interaction.rs │ │ │ ├── mod.rs │ │ │ └── setup.rs │ │ ├── hud │ │ │ ├── init.rs │ │ │ ├── mod.rs │ │ │ └── sync.rs │ │ ├── mod.rs │ │ ├── panel │ │ │ ├── interaction.rs │ │ │ ├── mod.rs │ │ │ └── setup.rs │ │ └── statistic.rs │ │ └── utility │ │ ├── mod.rs │ │ ├── png.rs │ │ └── track.rs ├── ecs │ ├── change_detection.rs │ ├── component_hooks.rs │ ├── custom_query_param.rs │ ├── custom_schedule.rs │ ├── dynamic.rs │ ├── ecs_guide.rs │ ├── event.rs │ ├── fallible_params.rs │ ├── fixed_timestep.rs │ ├── generic_system.rs │ ├── hierarchy.rs │ ├── iter_combinations.rs │ ├── nondeterministic_system_order.rs │ ├── observer_propagation.rs │ ├── observers.rs │ ├── one_shot_systems.rs │ ├── parallel_query.rs │ ├── query.rs │ ├── removal_detection.rs │ ├── run_conditions.rs │ ├── send_and_receive_events.rs │ ├── system_closure.rs │ ├── system_param.rs │ ├── system_piping.rs │ └── system_stepping.rs ├── hello_bevy.rs ├── input │ ├── char_input_events.rs │ ├── keyboard_modifiers.rs │ ├── mouse_grab.rs │ └── text_input.rs ├── movement │ └── physics_in_fixed_timestep.rs ├── picking │ └── sprite_picking.rs ├── rapier2d │ ├── advanced_detection.rs │ ├── collider_event.rs │ ├── collider_related.rs │ ├── collider_type.rs │ ├── joints.rs │ ├── joints_motor.rs │ ├── rigid_kinematic.rs │ ├── rigid_related.rs │ ├── rigid_type.rs │ ├── scene_queries_cast.rs │ ├── scene_queries_intersections.rs │ └── scene_queries_projection.rs ├── scene │ └── scene.rs ├── state │ ├── computed_states.rs │ ├── states.rs │ └── sub_states.rs └── ui │ ├── flex_layout.rs │ ├── grid.rs │ ├── overflow.rs │ ├── relative_curosr_position.rs │ ├── render_ui_to_texture.rs │ └── ui_scaling.rs ├── keynote ├── Bevy_016.key └── Bevy_Plugins(Physics).key ├── space_battle └── src └── main.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | .DS_Store 3 | Cargo.lock 4 | *.plist 5 | .gitignore 6 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "learn_bevy" 3 | version = "0.1.0" 4 | edition = "2024" 5 | 6 | [package.metadata.cargo-run] 7 | env = { "RUST_BACKTRACE" = "1" } 8 | 9 | 10 | [dependencies] 11 | bevy = { version = "0.16.0", features = ["track_location", "jpeg"] } 12 | bevy_ecs = "0.16.0" 13 | bevy_image = "0.16.0" 14 | # bevy_rapier2d = { version = "0.29.0", features = [ 15 | # "simd-stable", 16 | # "debug-render-2d", 17 | # #"serde-serialize", 18 | # ] } 19 | bevy_rapier2d = { git = "https://github.com/dimforge/bevy_rapier", branch = "master", features = [ 20 | "simd-stable", 21 | "debug-render-2d", 22 | #"serde-serialize", 23 | ] } 24 | bitflags = "2.9.1" 25 | contour = { version = "0.13.1", features = ["f32", "geojson"] } 26 | image = "0.25.6" 27 | log = "0.4.27" 28 | lyon = "1.0.1" 29 | rand = "0.9.1" 30 | rand_chacha = "*" 31 | serde = "1.0.219" 32 | serde_json = "1.0.140" 33 | thiserror = "2.0.12" 34 | 35 | 36 | [profile.dev.package.bevy_rapier2d] 37 | opt-level = 3 38 | 39 | [profile.release] 40 | opt-level = 3 41 | lto = true 42 | 43 | 44 | # Integrated Experiments # 45 | [[example]] 46 | name = "camera_renderlayer" 47 | path = "examples/byronzr/camera_renderlayer/main.rs" 48 | 49 | 50 | [[example]] 51 | name = "inventory" 52 | path = "examples/byronzr/inventory/main.rs" 53 | 54 | 55 | [[example]] 56 | name = "hexagon_tile" 57 | path = "examples/byronzr/hexagon_tile/main.rs" 58 | 59 | [[example]] 60 | name = "space_battle" 61 | path = "examples/byronzr/space_battle/main.rs" 62 | 63 | 64 | # Rapier2d Experiments 65 | [[example]] 66 | name = "rapier_rigid_type" 67 | path = "examples/rapier2d/rigid_type.rs" 68 | 69 | [[example]] 70 | name = "rapier_rigid_related" 71 | path = "examples/rapier2d/rigid_related.rs" 72 | 73 | [[example]] 74 | name = "rapier_rigid_kinematic" 75 | path = "examples/rapier2d/rigid_kinematic.rs" 76 | 77 | [[example]] 78 | name = "rapier_collider_type" 79 | path = "examples/rapier2d/collider_type.rs" 80 | 81 | [[example]] 82 | name = "rapier_collider_related" 83 | path = "examples/rapier2d/collider_related.rs" 84 | 85 | [[example]] 86 | name = "rapier_collider_event" 87 | path = "examples/rapier2d/collider_event.rs" 88 | 89 | [[example]] 90 | name = "rapier_joints" 91 | path = "examples/rapier2d/joints.rs" 92 | 93 | [[example]] 94 | name = "rapier_joints_motor" 95 | path = "examples/rapier2d/joints_motor.rs" 96 | 97 | [[example]] 98 | name = "rapier_scene_queries_cast" 99 | path = "examples/rapier2d/scene_queries_cast.rs" 100 | 101 | [[example]] 102 | name = "rapier_scene_queries_projection" 103 | path = "examples/rapier2d/scene_queries_projection.rs" 104 | 105 | [[example]] 106 | name = "rapier_scene_queries_intersections" 107 | path = "examples/rapier2d/scene_queries_intersections.rs" 108 | 109 | [[example]] 110 | name = "rapier_advanced_detection" 111 | path = "examples/rapier2d/advanced_detection.rs" 112 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 个人笔记 2 | 3 | 一步步,迈向游戏国度.集成个人零游戏开发经验的探索过程,在没有完整策案前,会不断累游戏场景,应用(桌面)场景,随着版本迭代,可能会出现"造轮子"的案例. 4 | 5 | # 官方用例 6 | 请查看官方用例 [bevy](https://bevyengine.org/),中文注释的代码 [高级伴读](https://github.com/byronzr/learn_bevy/tree/main/examples),(从 0.15 开始的注释,如果没有出现 panic 将不会主动优化代码,仅作来理解使用) 7 | 8 | # 实践型案例 9 | * **[camera_renderlayer](https://github.com/byronzr/learn_bevy/tree/main/examples/byronzr/camera_renderlayer/main.rs):** 关于 camera 中的 RenderLayers / TaregetCamera 的相关实践 10 | * [0.16] 变更了部分函数名称 11 | * **[inventory](https://github.com/byronzr/learn_bevy/tree/main/examples/byronzr/inventory/main.rs):** 利用 `Trigger>` 实现物品栏堆叠 12 | * [0.16] 支持了透明区域无法选择的直觉操作 13 | * **[hexagon_tile](https://github.com/byronzr/learn_bevy/tree/main/examples/byronzr/hexagon_tile):** 六边形走地图与迷雾(三种区域测试方式) 14 | * 以纯数学函数实现 15 | * MeshPickingPlugin 加入后,支持 Mesh2d 的 picking 事件 16 | * Rapier2d 实现 Collider Interscetion Test 17 | * **[space_battle](https://github.com/byronzr/learn_bevy/tree/main/examples/byronzr/space_battle)** Doing: 类 starsector 的太空战 18 | * 弹道,寻敌,护盾,伤害,炮塔转向,规避,幅能冷却 19 | 20 | 21 | # Rapier (bevy_rapier2d) 22 | 23 | 以下是一些用于观察 rapier 物理特性的实践用例,更多资料请查阅官网 [rapier](https://rapier.rs/) 24 | 25 | * **[rapier_rigid_type](https://github.com/byronzr/learn_bevy/tree/main/examples/rapier2d/rigid_type.rs):** Rapier2d 的 rigid 类型介绍 26 | * **[rapier_rigid_related](https://github.com/byronzr/learn_bevy/tree/main/examples/rapier2d/rigid_related.rs):** Rapier2d 的 rigid 与之相关的一些 Component 用例说明 27 | * **[rapier_rigid_kinematic](https://github.com/byronzr/learn_bevy/tree/main/examples/rapier2d/rigid_kinematic.rs):** 对于 Rigidbody::Kinematic* 用例说明 28 | * **[rapier_collider_type](https://github.com/byronzr/learn_bevy/tree/main/examples/rapier2d/collider_type.rs):** Rapier2d 的 collider 类型介绍(实体与传感器) 29 | * **[rapier_collider_related](https://github.com/byronzr/learn_bevy/tree/main/examples/rapier2d/collider_related.rs):** Rapier2d 的 collider 相关的 Component 用例 30 | * **[rapier_collider_event](https://github.com/byronzr/learn_bevy/tree/main/examples/rapier2d/collider_event.rs):** 关于 Event 用例 31 | * **[rapier_scene_queries_cast](https://github.com/byronzr/learn_bevy/tree/main/examples/rapier2d/scene_queries_cast.rs):** 关于 场景查询 (Scene Queries) cast(ray/shape) 用例 32 | * **[rapier_scene_queries_projection](https://github.com/byronzr/learn_bevy/tree/main/examples/rapier2d/scene_queries_projection.rs):** 关于 场景查询 (point projection) 用例 33 | * **[rapier_scene_queries_intersections](https://github.com/byronzr/learn_bevy/tree/main/examples/rapier2d/scene_queries_intersections.rs):** 关于 场景查询 (intersection) 用例 34 | * **[rapier_joints](https://github.com/byronzr/learn_bevy/tree/main/examples/rapier2d/joints.rs):** 关于 (joints) 用例 35 | * **[rapier_joints_motor](https://github.com/byronzr/learn_bevy/tree/main/examples/rapier2d/joints_motor.rs):** 关于 (joint_motor) 关节(马达)电机用例 36 | * **[rapier_advanced_detection](https://github.com/byronzr/learn_bevy/tree/main/examples/rapier2d/advanced_detection.rs):** 进阶测试用例 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /assets/fonts/FiraCodeNerdFontMono-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/byronzr/learn_bevy/95a9e8adc79e5ed60b3f047a1587ddb7fe488851/assets/fonts/FiraCodeNerdFontMono-Light.ttf -------------------------------------------------------------------------------- /assets/fonts/FiraMono-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/byronzr/learn_bevy/95a9e8adc79e5ed60b3f047a1587ddb7fe488851/assets/fonts/FiraMono-Medium.ttf -------------------------------------------------------------------------------- /assets/fonts/FiraSans-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/byronzr/learn_bevy/95a9e8adc79e5ed60b3f047a1587ddb7fe488851/assets/fonts/FiraSans-Bold.ttf -------------------------------------------------------------------------------- /assets/fonts/SourceHanSansCN-Normal.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/byronzr/learn_bevy/95a9e8adc79e5ed60b3f047a1587ddb7fe488851/assets/fonts/SourceHanSansCN-Normal.otf -------------------------------------------------------------------------------- /assets/items/AK47.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/byronzr/learn_bevy/95a9e8adc79e5ed60b3f047a1587ddb7fe488851/assets/items/AK47.png -------------------------------------------------------------------------------- /assets/items/knife.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/byronzr/learn_bevy/95a9e8adc79e5ed60b3f047a1587ddb7fe488851/assets/items/knife.png -------------------------------------------------------------------------------- /assets/items/paper.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/byronzr/learn_bevy/95a9e8adc79e5ed60b3f047a1587ddb7fe488851/assets/items/paper.png -------------------------------------------------------------------------------- /assets/space_battle/audio/disintegrator_fire_01.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/byronzr/learn_bevy/95a9e8adc79e5ed60b3f047a1587ddb7fe488851/assets/space_battle/audio/disintegrator_fire_01.ogg -------------------------------------------------------------------------------- /assets/space_battle/audio/light_assault_gun_fire_01.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/byronzr/learn_bevy/95a9e8adc79e5ed60b3f047a1587ddb7fe488851/assets/space_battle/audio/light_assault_gun_fire_01.ogg -------------------------------------------------------------------------------- /assets/space_battle/audio/ui_button_pressed.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/byronzr/learn_bevy/95a9e8adc79e5ed60b3f047a1587ddb7fe488851/assets/space_battle/audio/ui_button_pressed.ogg -------------------------------------------------------------------------------- /assets/space_battle/audio/ui_type.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/byronzr/learn_bevy/95a9e8adc79e5ed60b3f047a1587ddb7fe488851/assets/space_battle/audio/ui_type.ogg -------------------------------------------------------------------------------- /assets/space_battle/background4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/byronzr/learn_bevy/95a9e8adc79e5ed60b3f047a1587ddb7fe488851/assets/space_battle/background4.jpg -------------------------------------------------------------------------------- /assets/space_battle/engineflame32-orig.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/byronzr/learn_bevy/95a9e8adc79e5ed60b3f047a1587ddb7fe488851/assets/space_battle/engineflame32-orig.png -------------------------------------------------------------------------------- /assets/space_battle/engineflame32-orig.pxd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/byronzr/learn_bevy/95a9e8adc79e5ed60b3f047a1587ddb7fe488851/assets/space_battle/engineflame32-orig.pxd -------------------------------------------------------------------------------- /assets/space_battle/engineflame32-orig2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/byronzr/learn_bevy/95a9e8adc79e5ed60b3f047a1587ddb7fe488851/assets/space_battle/engineflame32-orig2.png -------------------------------------------------------------------------------- /assets/space_battle/engineflame32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/byronzr/learn_bevy/95a9e8adc79e5ed60b3f047a1587ddb7fe488851/assets/space_battle/engineflame32.png -------------------------------------------------------------------------------- /assets/space_battle/lasher_ff.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/byronzr/learn_bevy/95a9e8adc79e5ed60b3f047a1587ddb7fe488851/assets/space_battle/lasher_ff.png -------------------------------------------------------------------------------- /assets/space_battle/lasher_ff.pxd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/byronzr/learn_bevy/95a9e8adc79e5ed60b3f047a1587ddb7fe488851/assets/space_battle/lasher_ff.pxd -------------------------------------------------------------------------------- /assets/space_battle/lasher_ff_shape.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/byronzr/learn_bevy/95a9e8adc79e5ed60b3f047a1587ddb7fe488851/assets/space_battle/lasher_ff_shape.png -------------------------------------------------------------------------------- /assets/space_battle/projbody.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/byronzr/learn_bevy/95a9e8adc79e5ed60b3f047a1587ddb7fe488851/assets/space_battle/projbody.png -------------------------------------------------------------------------------- /assets/space_battle/shader/engine_flame.wgsl: -------------------------------------------------------------------------------- 1 | #import bevy_sprite::{ 2 | mesh2d_view_bindings::globals, 3 | mesh2d_vertex_output::VertexOutput, 4 | } 5 | // #import bevy_pbr::mesh_view_bindings::globals 6 | 7 | // #import bevy_pbr::{ 8 | // mesh_view_bindings::globals, 9 | // forward_io::VertexOutput, 10 | // } 11 | 12 | @group(2) @binding(0) var my_texture: texture_2d; 13 | @group(2) @binding(1) var my_sampler: sampler; 14 | @group(2) @binding(2) var lumina: vec4; 15 | @group(2) @binding(3) var time: f32; 16 | 17 | @fragment 18 | fn fragment(in: VertexOutput) -> @location(0) vec4 { 19 | let v = sin(globals.time)*0.2; 20 | let uv = in.uv; 21 | let center = 0.5; 22 | let amplitude = 0.2; // 最大收缩幅度(0~0.5之间,越大收缩越明显) 23 | //let scale = 1.0 - amplitude * sin(globals.time); // scale 在 [1-amplitude, 1+amplitude] 之间变化 24 | let scale = 1.0 - amplitude * sin(time)-v; // scale 在 [1-amplitude, 1+amplitude] 之间变化 25 | let new_x = (uv.x - center) * scale + center; 26 | let new_uv = vec2(new_x, uv.y); 27 | 28 | // 标准亮度加权值 29 | var raw_color = textureSample(my_texture, my_sampler, new_uv); 30 | let luminance = dot(raw_color.rgb, vec3(0.2126, 0.7152, 0.0722)); 31 | 32 | // 伪随机 33 | let rnd = fract(sin(dot(vec2(uv.x, uv.y) + globals.time, vec2(12.9898, 78.233))) * 43758.5453); 34 | let rnd2 = fract(sin(dot(vec2(uv.x, uv.y) + globals.time, vec2(12.9898, 78.233))) * 10000.5453); 35 | 36 | if raw_color.a > 0.5 { 37 | raw_color = lumina * textureSample(my_texture, my_sampler, new_uv); 38 | } 39 | 40 | if time == -1 { 41 | raw_color = vec4(0.0, 0.0, 0.0, 1.0); 42 | } 43 | 44 | return rnd * rnd * raw_color; 45 | } -------------------------------------------------------------------------------- /assets/space_battle/tempest.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/byronzr/learn_bevy/95a9e8adc79e5ed60b3f047a1587ddb7fe488851/assets/space_battle/tempest.png -------------------------------------------------------------------------------- /assets/storage/fow.json: -------------------------------------------------------------------------------- 1 | { 2 | "range": 3 | [ 4 | [ 5 | [[0,0]], 6 | [[0,-2],[0,-1],[0,1],[0,2],[-1,1],[-1,-1]], 7 | [[0,-4],[0,-3],[1,-2],[1,0],[1,2],[0,3],[0,4],[-1,3],[-1,2],[-1,0],[-1,-2],[-1,-3]], 8 | [[0,-6],[0,-5],[1,-4],[1,-3],[1,-1],[1,1],[1,3],[1,4],[0,5],[0,6],[-1,5],[-1,4],[-2,3],[-2,1],[-2,-1],[-2,-3],[-1,-4],[-1,-5]], 9 | [[0,-8],[1,-6],[1,-6],[1,-5],[2,-2],[2,-2],[2,0],[2,2],[1,5],[1,6],[0,7],[0,7],[0,8],[-1,7],[-1,6],[-2,5],[-2,4],[-2,2],[-2,0],[-2,-2],[-2,-4],[-2,-5],[-1,-6],[0,-7],[2,-4],[2,4],[-1,-7]], 10 | [[-3,-5],[-2,-6],[-2,-7],[-1,-8],[-1,-9],[0,-10],[0,-9],[1,-8],[1,-7],[2,-6],[2,-5],[2,-3],[2,-1],[2,1],[2,3],[2,5],[2,6],[1,7],[1,8],[0,9],[0,10],[-1,9],[-1,8],[-2,7],[-2,6],[-3,5],[-3,3],[-3,1],[-3,-1],[-3,-3],[-3,-5],[-2,-6],[-2,-7],[-1,-8],[-1,-9]] 11 | ], 12 | [ 13 | [[0,0]], 14 | [[0,-2],[0,-1],[0,1],[0,2],[1,1],[1,-1]], 15 | [[0,-4],[0,-3],[1,-2],[1,0],[1,2],[0,3],[0,4],[1,3],[-1,2],[-1,0],[-1,-2],[1,-3]], 16 | [[0,-6],[0,-5],[1,-4],[1,-3],[1,-1],[1,1],[1,3],[1,4],[0,5],[0,6],[1,5],[-1,4],[2,3],[2,1],[2,-1],[2,-3],[-1,-4],[1,-5],[-1,-3],[-1,-1],[-1,1],[-1,3]], 17 | [[0,-8],[1,-7],[1,-6],[2,-5],[2,-4],[2,-2],[2,0],[2,4],[2,5],[1,6],[1,6],[1,7],[0,8],[0,7],[-1,6],[-1,5],[-2,2],[-2,0],[-2,0],[-2,-2],[-2,-4],[-1,-6],[-1,-6],[-1,-5],[2,2],[-2,4],[0,-7]], 18 | [[0,-10],[1,-9],[2,-7],[2,-7],[2,-6],[3,-5],[3,-3],[3,1],[3,1],[3,3],[3,5],[2,6],[2,7],[1,8],[1,9],[0,10],[0,9],[-1,8],[-1,7],[-2,6],[-2,5],[-2,3],[-2,1],[-2,-1],[-2,-3],[-2,-5],[-1,-7],[-1,-7],[-2,-6],[1,-8],[3,-1],[-1,-8],[0,-9]] 19 | ] 20 | ] 21 | } -------------------------------------------------------------------------------- /assets/textures/HexTilesetv3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/byronzr/learn_bevy/95a9e8adc79e5ed60b3f047a1587ddb7fe488851/assets/textures/HexTilesetv3.png -------------------------------------------------------------------------------- /assets/textures/Idle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/byronzr/learn_bevy/95a9e8adc79e5ed60b3f047a1587ddb7fe488851/assets/textures/Idle.png -------------------------------------------------------------------------------- /assets/textures/Walk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/byronzr/learn_bevy/95a9e8adc79e5ed60b3f047a1587ddb7fe488851/assets/textures/Walk.png -------------------------------------------------------------------------------- /examples/2d/2d_shapes.rs: -------------------------------------------------------------------------------- 1 | //! Shows how to render simple primitive shapes with a single color. 2 | //! 3 | //! You can toggle wireframes with the space bar except on wasm. Wasm does not support 4 | //! `POLYGON_MODE_LINE` on the gpu. 5 | 6 | use bevy::prelude::*; 7 | #[cfg(not(target_arch = "wasm32"))] 8 | use bevy::sprite::{Wireframe2dConfig, Wireframe2dPlugin}; 9 | 10 | fn main() { 11 | let mut app = App::new(); 12 | app.add_plugins(( 13 | DefaultPlugins, 14 | #[cfg(not(target_arch = "wasm32"))] 15 | Wireframe2dPlugin, 16 | )) 17 | .insert_resource(ClearColor(Color::BLACK)) 18 | //.insert_resource(ClearColor(Color::WHITE)) 19 | .add_systems(Startup, setup); 20 | #[cfg(not(target_arch = "wasm32"))] 21 | app.add_systems(Update, toggle_wireframe); 22 | app.run(); 23 | } 24 | 25 | const X_EXTENT: f32 = 900.; 26 | 27 | fn setup( 28 | mut commands: Commands, 29 | mut meshes: ResMut>, 30 | mut materials: ResMut>, 31 | ) { 32 | commands.spawn(Camera2d); 33 | 34 | // 创建图形网络 (mesh) 并添加到场景中 35 | let shapes = [ 36 | meshes.add(Circle::new(50.0)), // 圆形 37 | meshes.add(CircularSector::new(50.0, 1.0)), // 扇形 (max angle(弧度值) = 2pi) 38 | meshes.add(CircularSegment::new(50.0, 1.25)), // 圆弧 39 | meshes.add(Ellipse::new(25.0, 50.0)), // 椭圆 40 | meshes.add(Annulus::new(25.0, 50.0)), // 圆环 (inner radius = 25.0, outer radius = 50.0) 41 | meshes.add(Capsule2d::new(25.0, 50.0)), // 胶囊 42 | meshes.add(Rhombus::new(75.0, 100.0)), // 棱形 43 | meshes.add(Rectangle::new(50.0, 100.0)), // 矩形 44 | meshes.add(RegularPolygon::new(50.0, 6)), // 多边形 45 | meshes.add(Triangle2d::new( 46 | Vec2::Y * 50.0, 47 | Vec2::new(-50.0, -50.0), 48 | Vec2::new(50.0, -50.0), 49 | )), // 三角形 50 | ]; 51 | let num_shapes = shapes.len(); 52 | 53 | for (i, shape) in shapes.into_iter().enumerate() { 54 | // Distribute colors evenly across the rainbow. 55 | // hue 为色相, saturation 为饱和度, lightness 为亮度 56 | // hue 是色轮,最大取值为 360 度, 0 和 360 是红色, 120 是绿色, 240 是蓝色 57 | let color = Color::hsl(360. * i as f32 / num_shapes as f32, 0.95, 0.7); 58 | 59 | commands.spawn(( 60 | Mesh2d(shape), // 将网格组件化 61 | //MeshMaterial2d(materials.add(color)), 62 | Transform::from_xyz( 63 | // Distribute shapes from -X_EXTENT/2 to +X_EXTENT/2. 64 | -X_EXTENT / 2. + i as f32 / (num_shapes - 1) as f32 * X_EXTENT, 65 | 0.0, 66 | 0.0, 67 | ), 68 | )); 69 | } 70 | 71 | #[cfg(not(target_arch = "wasm32"))] 72 | commands.spawn(( 73 | Text::new("Press to toggle wireframes\nPress to toggle material colors"), 74 | Node { 75 | position_type: PositionType::Absolute, 76 | top: Val::Px(12.0), 77 | left: Val::Px(12.0), 78 | ..default() 79 | }, 80 | )); 81 | } 82 | 83 | #[cfg(not(target_arch = "wasm32"))] 84 | fn toggle_wireframe( 85 | mut wireframe_config: ResMut, 86 | keyboard: Res>, 87 | query: Query>, 88 | mut commands: Commands, 89 | mut materials: ResMut>, 90 | ) { 91 | // 展示线框图(meshes.add) 92 | if keyboard.just_pressed(KeyCode::Space) { 93 | wireframe_config.global = !wireframe_config.global; 94 | } 95 | // 切换材质(颜色) 96 | if keyboard.just_pressed(KeyCode::KeyC) { 97 | let num_shapes = query.iter().len(); 98 | for (i, entity_ref) in query.iter().enumerate() { 99 | let mut entity = commands.entity(entity_ref.id()); 100 | if entity_ref.get::>().is_some() { 101 | entity.remove::>(); 102 | } else { 103 | let color = Color::hsl(360. * i as f32 / num_shapes as f32, 0.95, 0.7); 104 | entity.insert(MeshMaterial2d(materials.add(color))); 105 | } 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /examples/2d/2d_viewport_to_world.rs: -------------------------------------------------------------------------------- 1 | //! This example demonstrates how to use the `Camera::viewport_to_world_2d` method. 2 | 3 | use bevy::{color::palettes::basic::WHITE, log::warn_once, prelude::*}; 4 | 5 | fn main() { 6 | App::new() 7 | .add_plugins(DefaultPlugins) 8 | .add_systems(Startup, setup) 9 | .add_systems(Update, draw_cursor.param_warn_once()) 10 | .run(); 11 | } 12 | 13 | // Transform 相对坐标系(Entity嵌套) 14 | // GlobalTransform 绝对坐标系(世界坐标系),脱离父子关系 15 | fn draw_cursor( 16 | camera_query: Single<(&Camera, &GlobalTransform, &Transform)>, 17 | windows: Query<&Window>, 18 | mut gizmos: Gizmos, 19 | ) { 20 | let (camera, camera_transform, local_transform) = *camera_query; 21 | warn_once!("global_transform: {camera_transform:?}"); 22 | warn_once!("local_transform: {local_transform:?}"); 23 | 24 | // 获得 App 的 window 25 | let Ok(window) = windows.get_single() else { 26 | println!("window not found"); 27 | return; 28 | }; 29 | 30 | // 获得鼠标的位置(不包括 title bar mac中),所以鼠标位置是基于 Canvas 的 31 | let Some(cursor_position) = window.cursor_position() else { 32 | //warn!("cursor_position not found"); 33 | warn_once!("cursor_position not found"); 34 | return; 35 | }; 36 | 37 | // Calculate a world position based on the cursor's position. 38 | // 将视窗坐标系转换成世界坐标系 39 | // 如果有 viewport_to_world_2d 方法,当然就会有 world_to_viewport 方法 40 | // 注意: 没有 world_to_viewport_2d 方法,因为 2d 是不需要转换的,因为没有深度(z) 41 | // 在 2d 场景中,如果鼠标(或其它)超出屏幕,则不需要转换,而未超出屏幕的部分,其本身就是世界坐标系 42 | let Ok(point) = camera.viewport_to_world_2d(camera_transform, cursor_position) else { 43 | warn!("viewport_to_world_2d failed"); 44 | return; 45 | }; 46 | 47 | // 画个小圆圈跟随鼠标 48 | gizmos.circle_2d(point, 10., WHITE); 49 | } 50 | 51 | fn setup(mut commands: Commands) { 52 | commands.spawn(Camera2d); 53 | } 54 | -------------------------------------------------------------------------------- /examples/2d/mesh2d.rs: -------------------------------------------------------------------------------- 1 | //! Shows how to render a polygonal [`Mesh`], generated from a [`Rectangle`] primitive, in a 2D scene. 2 | 3 | use bevy::{color::palettes::basic::PURPLE, prelude::*}; 4 | 5 | fn main() { 6 | App::new() 7 | .add_plugins(DefaultPlugins) 8 | .add_systems(Startup, setup) 9 | .run(); 10 | } 11 | 12 | fn setup( 13 | mut commands: Commands, 14 | mut meshes: ResMut>, 15 | mut materials: ResMut>, 16 | ) { 17 | commands.spawn(Camera2d); 18 | commands.spawn(( 19 | Mesh2d(meshes.add(Rectangle::default())), 20 | MeshMaterial2d(materials.add(Color::from(PURPLE))), 21 | Transform::default().with_scale(Vec3::splat(128.)), 22 | )); 23 | } 24 | -------------------------------------------------------------------------------- /examples/2d/mesh2d_arcs.rs: -------------------------------------------------------------------------------- 1 | //! Demonstrates UV mappings of the [`CircularSector`] and [`CircularSegment`] primitives. 2 | //! 3 | //! Also draws the bounding boxes and circles of the primitives. 4 | 5 | use std::f32::consts::FRAC_PI_2; 6 | 7 | use bevy::{ 8 | color::palettes::css::{BLUE, DARK_SLATE_GREY, RED}, 9 | math::{ 10 | bounding::{Bounded2d, BoundingVolume}, 11 | Isometry2d, 12 | }, 13 | prelude::*, 14 | render::mesh::{CircularMeshUvMode, CircularSectorMeshBuilder, CircularSegmentMeshBuilder}, 15 | }; 16 | 17 | fn main() { 18 | App::new() 19 | .add_plugins(DefaultPlugins) 20 | .add_systems(Startup, setup) 21 | .add_systems( 22 | Update, 23 | ( 24 | draw_bounds::, 25 | draw_bounds::, 26 | ), 27 | ) 28 | .run(); 29 | } 30 | 31 | #[derive(Component, Debug)] 32 | struct DrawBounds(Shape); 33 | 34 | fn setup( 35 | mut commands: Commands, 36 | asset_server: Res, 37 | mut meshes: ResMut>, 38 | mut materials: ResMut>, 39 | ) { 40 | let material = materials.add(asset_server.load("branding/icon.png")); 41 | 42 | commands.spawn(( 43 | Camera2d, 44 | Camera { 45 | clear_color: ClearColorConfig::Custom(DARK_SLATE_GREY.into()), 46 | ..default() 47 | }, 48 | )); 49 | 50 | const UPPER_Y: f32 = 50.0; 51 | const LOWER_Y: f32 = -50.0; 52 | const FIRST_X: f32 = -450.0; 53 | const OFFSET: f32 = 100.0; 54 | const NUM_SLICES: i32 = 8; 55 | 56 | // This draws NUM_SLICES copies of the Bevy logo as circular sectors and segments, 57 | // with successively larger angles up to a complete circle. 58 | for i in 0..NUM_SLICES { 59 | let fraction = (i + 1) as f32 / NUM_SLICES as f32; 60 | 61 | let sector = CircularSector::from_turns(40.0, fraction); 62 | // We want to rotate the circular sector so that the sectors appear clockwise from north. 63 | // We must rotate it both in the Transform and in the mesh's UV mappings. 64 | let sector_angle = -sector.half_angle(); 65 | let sector_mesh = 66 | CircularSectorMeshBuilder::new(sector).uv_mode(CircularMeshUvMode::Mask { 67 | angle: sector_angle, 68 | }); 69 | commands.spawn(( 70 | Mesh2d(meshes.add(sector_mesh)), 71 | MeshMaterial2d(material.clone()), 72 | Transform { 73 | translation: Vec3::new(FIRST_X + OFFSET * i as f32, 2.0 * UPPER_Y, 0.0), 74 | rotation: Quat::from_rotation_z(sector_angle), 75 | ..default() 76 | }, 77 | DrawBounds(sector), 78 | )); 79 | 80 | let segment = CircularSegment::from_turns(40.0, fraction); 81 | // For the circular segment, we will draw Bevy charging forward, which requires rotating the 82 | // shape and texture by 90 degrees. 83 | // 84 | // Note that this may be unintuitive; it may feel like we should rotate the texture by the 85 | // opposite angle to preserve the orientation of Bevy. But the angle is not the angle of the 86 | // texture itself, rather it is the angle at which the vertices are mapped onto the texture. 87 | // so it is the negative of what you might otherwise expect. 88 | let segment_angle = -FRAC_PI_2; 89 | let segment_mesh = 90 | CircularSegmentMeshBuilder::new(segment).uv_mode(CircularMeshUvMode::Mask { 91 | angle: -segment_angle, 92 | }); 93 | commands.spawn(( 94 | Mesh2d(meshes.add(segment_mesh)), 95 | MeshMaterial2d(material.clone()), 96 | Transform { 97 | translation: Vec3::new(FIRST_X + OFFSET * i as f32, LOWER_Y, 0.0), 98 | rotation: Quat::from_rotation_z(segment_angle), 99 | ..default() 100 | }, 101 | DrawBounds(segment), 102 | )); 103 | } 104 | } 105 | 106 | fn draw_bounds( 107 | q: Query<(&DrawBounds, &GlobalTransform)>, 108 | mut gizmos: Gizmos, 109 | ) { 110 | for (shape, transform) in &q { 111 | let (_, rotation, translation) = transform.to_scale_rotation_translation(); 112 | let translation = translation.truncate(); 113 | let rotation = rotation.to_euler(EulerRot::XYZ).2; 114 | let isometry = Isometry2d::new(translation, Rot2::radians(rotation)); 115 | 116 | let aabb = shape.0.aabb_2d(isometry); 117 | gizmos.rect_2d(aabb.center(), aabb.half_size() * 2.0, RED); 118 | 119 | let bounding_circle = shape.0.bounding_circle(isometry); 120 | gizmos.circle_2d(bounding_circle.center, bounding_circle.radius(), BLUE); 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /examples/2d/mesh2d_vertex_color_texture.rs: -------------------------------------------------------------------------------- 1 | //! Shows how to render a polygonal [`Mesh`], generated from a [`Rectangle`] primitive, in a 2D scene. 2 | //! Adds a texture and colored vertices, giving per-vertex tinting. 3 | 4 | use bevy::prelude::*; 5 | 6 | fn main() { 7 | App::new() 8 | .add_plugins(DefaultPlugins) 9 | .add_systems(Startup, setup) 10 | .run(); 11 | } 12 | 13 | fn setup( 14 | mut commands: Commands, 15 | mut meshes: ResMut>, 16 | mut materials: ResMut>, 17 | asset_server: Res, 18 | ) { 19 | // Load the Bevy logo as a texture 20 | let texture_handle = asset_server.load("branding/banner.png"); 21 | // Build a default quad mesh 22 | let mut mesh = Mesh::from(Rectangle::default()); 23 | // Build vertex colors for the quad. One entry per vertex (the corners of the quad) 24 | let vertex_colors: Vec<[f32; 4]> = vec![ 25 | LinearRgba::RED.to_f32_array(), 26 | LinearRgba::GREEN.to_f32_array(), 27 | LinearRgba::BLUE.to_f32_array(), 28 | LinearRgba::WHITE.to_f32_array(), 29 | ]; 30 | // Insert the vertex colors as an attribute 31 | mesh.insert_attribute(Mesh::ATTRIBUTE_COLOR, vertex_colors); 32 | 33 | let mesh_handle = meshes.add(mesh); 34 | 35 | // Spawn camera 36 | commands.spawn(Camera2d); 37 | 38 | // Spawn the quad with vertex colors 39 | commands.spawn(( 40 | Mesh2d(mesh_handle.clone()), 41 | MeshMaterial2d(materials.add(ColorMaterial::default())), 42 | Transform::from_translation(Vec3::new(-96., 0., 0.)).with_scale(Vec3::splat(128.)), 43 | )); 44 | 45 | // Spawning the quad with vertex colors and a texture results in tinting 46 | commands.spawn(( 47 | Mesh2d(mesh_handle), 48 | MeshMaterial2d(materials.add(texture_handle)), 49 | Transform::from_translation(Vec3::new(96., 0., 0.)).with_scale(Vec3::splat(128.)), 50 | )); 51 | } 52 | -------------------------------------------------------------------------------- /examples/2d/sprite_flipping.rs: -------------------------------------------------------------------------------- 1 | //! Displays a single [`Sprite`], created from an image, but flipped on one axis. 2 | 3 | use bevy::prelude::*; 4 | 5 | fn main() { 6 | App::new() 7 | .add_plugins(DefaultPlugins) 8 | .add_systems(Startup, setup) 9 | .run(); 10 | } 11 | 12 | fn setup(mut commands: Commands, asset_server: Res) { 13 | commands.spawn(Camera2d); 14 | commands.spawn(Sprite { 15 | image: asset_server.load("branding/bevy_bird_dark.png"), 16 | // Flip the logo to the left 17 | // ** 以 X 轴为中心翻转 18 | flip_x: true, 19 | // And don't flip it upside-down ( the default ) 20 | // ** Y 轴 21 | flip_y: false, 22 | ..Default::default() 23 | }); 24 | } 25 | -------------------------------------------------------------------------------- /examples/2d/sprite_sheet.rs: -------------------------------------------------------------------------------- 1 | //! Renders an animated sprite by loading all animation frames from a single image (a sprite sheet) 2 | //! into a texture atlas, and changing the displayed image periodically. 3 | 4 | use bevy::prelude::*; 5 | 6 | fn main() { 7 | App::new() 8 | .add_plugins(DefaultPlugins.set(ImagePlugin::default_nearest())) // prevents blurry sprites 9 | .add_systems(Startup, setup) 10 | .add_systems(Update, animate_sprite) 11 | .run(); 12 | } 13 | 14 | #[derive(Component)] 15 | struct AnimationIndices { 16 | first: usize, 17 | last: usize, 18 | } 19 | 20 | #[derive(Component, Deref, DerefMut)] 21 | struct AnimationTimer(Timer); 22 | 23 | // 精灵动画循环系统 24 | fn animate_sprite( 25 | time: Res