{"payload":{"feedbackUrl":"https://github.com/orgs/community/discussions/53140","repo":{"id":479737260,"defaultBranch":"main","name":"bevy-snake","ownerLogin":"rust-adventure","currentUserCanPush":false,"isFork":false,"isEmpty":false,"createdAt":"2022-04-09T13:39:42.000Z","ownerAvatar":"https://avatars.githubusercontent.com/u/75100245?v=4","public":true,"private":false,"isOrgOwned":true},"refInfo":{"name":"","listCacheKey":"v0:1720676236.0","currentOid":""},"activityList":{"items":[{"before":"373a01973731c6895f77d15e69520e9acf81fac8","after":"dcdcc8966ce1f8ca59623c809628ecd0c9bbcf22","ref":"refs/heads/bevy-0.14-tilemap","pushedAt":"2024-07-13T04:06:00.000Z","pushType":"push","commitsCount":1,"pusher":{"login":"ChristopherBiscardi","name":"Chris Biscardi","path":"/ChristopherBiscardi","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/551247?s=80&v=4"},"commit":{"message":"add lints","shortMessageHtmlLink":"add lints"}},{"before":"27f1d74ae902a3f9445720681dd54678c6508b41","after":"373a01973731c6895f77d15e69520e9acf81fac8","ref":"refs/heads/bevy-0.14-tilemap","pushedAt":"2024-07-13T03:54:10.000Z","pushType":"push","commitsCount":1,"pusher":{"login":"ChristopherBiscardi","name":"Chris Biscardi","path":"/ChristopherBiscardi","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/551247?s=80&v=4"},"commit":{"message":"tile_storage","shortMessageHtmlLink":"tile_storage"}},{"before":"b372d5e81c3ce5c8b9d1b4e0f63f73db28a6b0dc","after":"27f1d74ae902a3f9445720681dd54678c6508b41","ref":"refs/heads/bevy-0.14-tilemap","pushedAt":"2024-07-11T06:00:31.000Z","pushType":"push","commitsCount":2,"pusher":{"login":"ChristopherBiscardi","name":"Chris Biscardi","path":"/ChristopherBiscardi","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/551247?s=80&v=4"},"commit":{"message":"some clippy","shortMessageHtmlLink":"some clippy"}},{"before":null,"after":"b372d5e81c3ce5c8b9d1b4e0f63f73db28a6b0dc","ref":"refs/heads/bevy-0.14-tilemap","pushedAt":"2024-07-11T05:37:16.000Z","pushType":"branch_creation","commitsCount":0,"pusher":{"login":"ChristopherBiscardi","name":"Chris Biscardi","path":"/ChristopherBiscardi","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/551247?s=80&v=4"},"commit":{"message":"tilemap version","shortMessageHtmlLink":"tilemap version"}},{"before":"8925e695ed8d146b3b6c7d4ed964de144c512fdd","after":"a9e41a63851575768ff9e58ad9e3808835851ff4","ref":"refs/heads/bevy-0.14","pushedAt":"2024-07-09T23:33:13.000Z","pushType":"push","commitsCount":1,"pusher":{"login":"ChristopherBiscardi","name":"Chris Biscardi","path":"/ChristopherBiscardi","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/551247?s=80&v=4"},"commit":{"message":"snake segment observers","shortMessageHtmlLink":"snake segment observers"}},{"before":null,"after":"8925e695ed8d146b3b6c7d4ed964de144c512fdd","ref":"refs/heads/bevy-0.14","pushedAt":"2024-07-09T20:18:18.000Z","pushType":"branch_creation","commitsCount":0,"pusher":{"login":"ChristopherBiscardi","name":"Chris Biscardi","path":"/ChristopherBiscardi","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/551247?s=80&v=4"},"commit":{"message":"food is observers","shortMessageHtmlLink":"food is observers"}},{"before":null,"after":"224c785b9929f8370a68bb5971001be4032eb870","ref":"refs/heads/bevy-0.13","pushedAt":"2024-05-25T20:05:43.000Z","pushType":"branch_creation","commitsCount":0,"pusher":{"login":"ChristopherBiscardi","name":"Chris Biscardi","path":"/ChristopherBiscardi","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/551247?s=80&v=4"},"commit":{"message":"bevy 0.13","shortMessageHtmlLink":"bevy 0.13"}},{"before":"34703d5e48dfead67a183f041aaba041e3c5e011","after":"909fba27ec78c1158c4fb4d04da0a9c0f42917a1","ref":"refs/heads/bevy-0.12-steps","pushedAt":"2024-01-24T21:21:47.000Z","pushType":"push","commitsCount":1,"pusher":{"login":"ChristopherBiscardi","name":"Chris Biscardi","path":"/ChristopherBiscardi","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/551247?s=80&v=4"},"commit":{"message":"pausing-with-game-states\n\nThe Snake game is fairly playable now. It's recognizable as Snake in any case.\n\nWe still don't have any way to end the game or restart the game once it ends.\n\nTo do that we're going to introduce game states.\n\nIn `lib.rs` we can create a new enum to represent the states we could be in. We'll have one for the main menu and one for playing the game. Our `GameState` enum with derive [`States`](https://docs.rs/bevy/0.12.0/bevy/ecs/schedule/trait.States.html) as well as a number of other trait implementations.\n\n```rust\n\\#[derive(\n Debug, Clone, Copy, Default, Eq, PartialEq, Hash, States,\n)]\npub enum GameState {\n #[default]\n Menu,\n Playing,\n}\n```\n\nWe also need to add the state machine to our App in `src/main.rs`.\n\n```rust\n.add_state::()\n```\n\nThis game state creates a state machine that we can control via our Bevy systems. We can also use the state of the machine to control which systems are running at any given time.\n\nIn the `add_systems` call where we add the `tick` system we can use [`run_if`](https://docs.rs/bevy/0.12.0/bevy/ecs/prelude/trait.IntoSystemConfigs.html#method.run_if) to run systems conditionally if a [`Condition`](https://docs.rs/bevy/0.12.0/bevy/ecs/schedule/trait.Condition.html) is true.\n\nIn this case the `Condition` we're using is [`in_state`](https://docs.rs/bevy/0.12.0/bevy/ecs/prelude/fn.in_state.html) which will cause our system to run if the state machine is currently in the state we pass in. We've passed in `GameState::Playing`.\n\n```rust\n.add_systems(\n FixedUpdate,\n tick.run_if(in_state(GameState::Playing)),\n)\n```\n\nNow depending on which `GameState` variant is the `#[default]`, our game will either run as normal or will appear \"paused\" because our `tick` system is no longer running.","shortMessageHtmlLink":"pausing-with-game-states"}},{"before":"554f6d21232be414fdd77f4a1a07d191d229ea62","after":"34703d5e48dfead67a183f041aaba041e3c5e011","ref":"refs/heads/bevy-0.12-steps","pushedAt":"2023-11-26T20:09:32.000Z","pushType":"force_push","commitsCount":0,"pusher":{"login":"ChristopherBiscardi","name":"Chris Biscardi","path":"/ChristopherBiscardi","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/551247?s=80&v=4"},"commit":{"message":"many-apples-with-the-rand-crate\n\nOne apple is nice, but to play a full game of snake we need to spawn an apple every time one gets eaten.\n\nFirst let's address a common piece of code that we're going to re-use.\n\nIn `spawn_board`, we established that we can get all of the possible board positions using `cartesian_product`. This is fine, but we are going to access all of the tiles for the second time in this lesson, so let's encapsulate this logic in our `impl Board`.\n\nWe'll create a new function called `tiles` that returns an `Iterator`. Specifically an `Iterator` where the type of the `Item`s is a `Position`.\n\n```rust\nimpl Board {\n ...\n pub fn tiles(&self) -> impl Iterator {\n (0..self.size).cartesian_product(0..self.size).map(\n |(x, y)| {\n Position::new(i32::from(x), i32::from(y))\n },\n )\n }\n}\n```\n\nWe can do this by copying our `cartesian_product` logic that uses the `board.size`, then using `.map` to turn the `(x,y)` values that are `u16`s into `Position`s, which use `i32`s. A `u16` always fits neatly into an `i32`, so this translation will never fail.\n\nWe'll use this new function in `spawn_board` instead of the old `cartesian_product`. We're in the same file as the definition of `Position`, so we can destructure using the inner `IVec2` to reach the `x` and `y` values.\n\n```rust\nfor Position(IVec2 { x, y }) in board.tiles() {\n```\n\nThen we can update the `cell_position_to_physical` calls now that the numbers don't need to be converted here.\n\n```rust\nboard.cell_position_to_physical(x),\nboard.cell_position_to_physical(y),\n```\n\n\\## Randomness\n\nWe're going to use the `rand` crate to randomly pick a place to spawn apples, so add that now.\n\n```rust\ncargo add rand\n```\n\nWhen I installed I got `0.8.5` but `rand` tends to be pretty stable.\n\n```toml\n[dependencies]\nbevy = \"0.12.0\"\nitertools = \"0.11.0\"\nrand = \"0.8.5\"\n```\n\nOur apple spawning system is going to be driven by events. When the snake eats an apple, we'll fire off a `NewFoodEvent` and there will be a system listening to those events that will handle spawning a new apple on the board.\n\nUpdate the code in `food.rs` to have a new `FoodPlugin`, a `NewFoodEvent`, and our `food_event_listener`.\n\n```rust\npub struct FoodPlugin;\n\nimpl Plugin for FoodPlugin {\n fn build(&self, app: &mut App) {\n app.add_event::()\n .add_systems(Update, food_event_listener);\n }\n}\n\n\\#[derive(Event)]\npub struct NewFoodEvent;\n\n\\#[derive(Component)]\npub struct Food;\n\npub fn food_event_listener(\n mut commands: Commands,\n board: Res,\n mut events: EventReader,\n positions: Query<&Position>,\n) {\n let num_food = events.read().count();\n\n let mut rng = rand::thread_rng();\n for pos in board\n .tiles()\n .filter(|tile| {\n !positions.iter().any(|pos| pos == tile)\n })\n .choose_multiple(&mut rng, num_food)\n {\n commands.add(SpawnApple { position: pos });\n }\n}\n```\n\nWe also need to bring the `IteratorRandom` trait into scope from the `rand` crate.\n\n```rust\nuse rand::seq::IteratorRandom;\n```\n\nSimilar to how we must derive `Resource` or `Component`, we must derive `Event` for any Bevy events. Our `NewFoodEvent` is otherwise unremarkable. An empty struct with no fields.\n\n```rust\n\\#[derive(Event)]\npub struct NewFoodEvent;\n```\n\nEvents must be added to the `App` before we can send or receive them. We can use [`add_event`](https://docs.rs/bevy/0.12.0/bevy/app/struct.App.html#method.add_event) in our new plugin for this.\n\n```rust\n.add_event::()\n```\n\n\\## Listening for Events\n\nWhen an event is sent, its stored by Bevy and made available to read in our systems. We can use [`EventReader`](https://docs.rs/bevy/0.12.0/bevy/prelude/struct.EventReader.html) to read events that have been sent and track whether or not we've consumed them\n\n```rust\npub fn food_event_listener(\n mut commands: Commands,\n board: Res,\n mut events: EventReader,\n positions: Query<&Position>,\n) {\n let num_food = events.read().count();\n\n let mut rng = rand::thread_rng();\n for pos in board\n .tiles()\n .filter(|tile| {\n !positions.iter().any(|pos| pos == tile)\n })\n .choose_multiple(&mut rng, num_food)\n {\n commands.add(SpawnApple { position: pos });\n }\n}\n```\n\nWe can use the [`read`](https://docs.rs/bevy/0.12.0/bevy/prelude/struct.EventReader.html#method.read) function on the `EventReader` to read the incoming events as an Iterator. This will iterate over each event we haven't consumed yet and consume it. Rust's `Iterator` trait includes a function that consumes every item and returns the total count. It is appropriately named [`count`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.count).\n\nThis gives us the total number of new food events that we need to process. The number for us will always be 1 event (or 0) but we don't have any control over the number of events from the reading side. We can only control how many we're sending and when we're sending them.\n\n`rand` is a random number generator utility crate. It includes helpful traits and functions for dealing with randomness.\n\nIn our case, we start up a new random number generator and then take advantage of the [`IteratorRandom`](https://docs.rs/rand/0.8.5/rand/seq/trait.IteratorRandom.html) trait from the `rand` crate to pick a number of the tiles based on how many events came in. The [`choose_multiple`](https://docs.rs/rand/0.8.5/rand/seq/trait.IteratorRandom.html#method.choose_multiple) function on the `IteratorRandom` trait allows us to choose multiple random items from our iterator.\n\nWe take the `board.tiles()` and filter out any tile that already has something on it, then choose a subset of the remaining tiles randomly.\n\nFor each position we chose randomly, we spawn a new apple at that `Position`.\n\nBring our new plugin into scope in `src/main.rs`.\n\n```rust\nuse snake::{\n board::{spawn_board, Board},\n controls::ControlsPlugin,\n food::{spawn_apple, FoodPlugin},\n snake::{spawn_snake, Snake},\n tick,\n};\n```\n\nand add the plugin to our `App` alongside the others.\n\n```rust\n.add_plugins((\n DefaultPlugins.set(WindowPlugin {\n primary_window: Some(Window {\n title: \"Snake!\".into(),\n ..default()\n }),\n ..default()\n }),\n ControlsPlugin,\n FoodPlugin,\n))\n```\n\n\\## Sending Events\n\nWith the plugin added, which means the listener is set up, we'll add an argument to our `tick` function in `src/lib.rs` to write new events.\n\n```rust\npub fn tick(\n\t...\n mut food_events: EventWriter,\n) {\n```\n\nand where we despawn the food, we'll send an event to spawn a new apple.\n\n```rust\nSome((food_entity, _)) => {\n commands\n .entity(food_entity)\n .despawn_recursive();\n food_events.send(NewFoodEvent);\n}\n```\n\nand now our snake can eat apples and have new ones spawn!\n\n```\ncargo run\n```","shortMessageHtmlLink":"many-apples-with-the-rand-crate"}},{"before":null,"after":"554f6d21232be414fdd77f4a1a07d191d229ea62","ref":"refs/heads/bevy-0.12-steps","pushedAt":"2023-11-26T03:54:47.000Z","pushType":"branch_creation","commitsCount":0,"pusher":{"login":"ChristopherBiscardi","name":"Chris Biscardi","path":"/ChristopherBiscardi","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/551247?s=80&v=4"},"commit":{"message":"creating-custom-bevy-commands\n\nOur `Snake` is moving but that's not showing on the screen just yet. This is because while we're spawning the `Entity` with the right `Position` in our `tick` function we don't have a `Sprite` component on that `Entity`.\n\nThe logic we need for spawning a `Snake` segment in `tick` is the same logic we used in `snake::spawn_snake`, so we have roughly two choices.\n\n1. We could write a function that is not a system that we call from our systems\n2. We could write a custom Bevy [`Command`](https://docs.rs/bevy/0.12.0/bevy/ecs/system/trait.Command.html)\n\nFor option 1, writing a function is fine but it requires that the arguments we pass to that function are queried in every system we use it in. We then have to pass all of those arguments into the function which is a bit of a headache for logic that uses a variety of arguments.\n\nUsing option 2, a custom `Command`, we'll be able to encapsulate all of the queries for `Resource`s and `Component`s where we're using them. The downside of using a custom `Command` is that we'll be dealing with the [`World`](https://docs.rs/bevy/0.12.0/bevy/ecs/prelude/struct.World.html) directly instead of getting system arguments injected for us.\n\nOur `Command` will look like this when we use it to spawn a new segment, using [`commands.add`](https://docs.rs/bevy/latest/bevy/ecs/system/struct.Commands.html#method.add).\n\n```rust\ncommands.add(SpawnSnakeSegment {\n\tposition: Position::new(..)\n});\n```\n\\## Implementing a Command\n\nIn `src/snake.rs` we'll need to bring `Command` into scope.\n\n```rust\nuse bevy::{ecs::system::Command, prelude::*};\n```\n\nand we can start implementing our new `Command`.\n\n```rust\npub struct SpawnSnakeSegment {\n pub position: Position,\n}\n\nimpl Command for SpawnSnakeSegment {\n fn apply(self, world: &mut World) {\n\t todo!();\n }\n}\n```\n\n`Command` is a trait, so that means we need a type to implement the trait for.\n\nIn `src/snake.rs`, we'll create a new struct called `SpawnSnakeSegment`. Any fields in this struct will be accessible when we apply this `Command`, so we'll store a `Position` that represents the location we want to spawn a new snake segment at.\n\nTo implement `Command` for `SpawnSnakeSegment`, we need to implement the `apply` function. `apply` takes `self`, which is a shorthand version of writing `self: Self`. `Self` is a way to refer to the type that's implementing the trait, which is a `SpawnSnakeSegment` in our case.\n\n`apply` also gets an exclusive reference to `World`, which allows us to insert `Enitity`s, `Resource`, and more. The `World` type allows us to access pretty much anything in our Bevy app.\n\nWe've already implemented the logic for spawning in a new snake segment in `spawn_snake`, so we'll mostly copy that with two adjustments:\n\nInstead of asking for `Board` from our system arguments, we'll use [`world.get_resource`](https://docs.rs/bevy/0.12.0/bevy/prelude/struct.World.html#method.get_resource) with a type argument.\n\n```rust\nlet board = world.get_resource::().unwrap();\n```\n\nInstead of asking for `Snake` from our system arguments, we'll use [`world.get_resource_mut`](https://docs.rs/bevy/0.12.0/bevy/prelude/struct.World.html#method.get_resource_mut) with a type argument.\n\n```rust\nworld.get_resource_mut::().unwrap();\n```\n\nIn the end we can remove almost all of the logic from our `spawn_snake` function and replace it with calls to our new `Command`. Our `src/snake.rs` file now looks like this.\n\n```rust\nuse bevy::{ecs::system::Command, prelude::*};\nuse std::collections::VecDeque;\n\nuse crate::{\n board::{Board, Position, TILE_SIZE},\n colors,\n};\n\n\\#[derive(Debug, Default, Resource)]\npub struct Snake {\n pub segments: VecDeque,\n}\n\npub fn spawn_snake(mut commands: Commands) {\n for position in\n [Position::new(3, 4), Position::new(4, 4)]\n {\n commands.add(SpawnSnakeSegment { position });\n }\n}\n\npub struct SpawnSnakeSegment {\n pub position: Position,\n}\n\nimpl Command for SpawnSnakeSegment {\n fn apply(self, world: &mut World) {\n let board = world.get_resource::().unwrap();\n let x = board\n .cell_position_to_physical(self.position.x);\n let y = board\n .cell_position_to_physical(self.position.y);\n\n let entity = world\n .spawn((\n SpriteBundle {\n sprite: Sprite {\n color: colors::SNAKE,\n custom_size: Some(Vec2::splat(\n TILE_SIZE,\n )),\n ..default()\n },\n transform: Transform::from_xyz(\n x, y, 2.0,\n ),\n ..default()\n },\n self.position,\n ))\n .id();\n\n let mut snake =\n world.get_resource_mut::().unwrap();\n\n snake.segments.push_front(entity);\n }\n}\n```\n\nand in `src/lib.rs` in the `tick` system, we can replace our previous `commands.spawn(next_position)` with our new `Command`.\n\nBring `SpawnSnakeSegment` into scope.\n\n```rust\nuse crate::snake::SpawnSnakeSegment;\n```\n\nand then use `commands.add` to apply our new `Command`.\n\n```rust\npub fn tick(\n mut commands: Commands,\n mut snake: ResMut,\n positions: Query<&Position>,\n) {\n let snake_head_entity = snake\n .segments\n .front()\n .expect(\"snake should have a head entity\");\n\n let next_position = positions.get(*snake_head_entity)\n .map(|head| {\n Position::new(head.x + 1, head.y)\n })\n .expect(\"stored entities in a snake should have a Position component associated with them\");\n\n commands.add(SpawnSnakeSegment {\n position: next_position,\n });\n\n let old_tail = snake\n .segments\n .pop_back()\n .expect(\"snake should have a tail entity\");\n commands.entity(old_tail).despawn_recursive();\n\n info!(?snake);\n}\n```\n\nWhen we `cargo run` now, we see a snake moving to the right and off of the screen.\n\n![snake running off screen](https://res.cloudinary.com/dilgcuzda/image/upload/v1700970112/workshops/snake-with-bevy-ecs/bevy-0.12/snake-off-screen.avif)\n\nLet's finish up this lesson by removing the `info!(?snake);` log in `src/lib.rs`.","shortMessageHtmlLink":"creating-custom-bevy-commands"}},{"before":null,"after":"33c7a7f490faba26b20e5b7f74ea854efe167389","ref":"refs/heads/bevy-0.12-single-row-visualization","pushedAt":"2023-11-12T01:24:51.000Z","pushType":"branch_creation","commitsCount":0,"pusher":{"login":"ChristopherBiscardi","name":"Chris Biscardi","path":"/ChristopherBiscardi","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/551247?s=80&v=4"},"commit":{"message":"single-row system-stepping visualization","shortMessageHtmlLink":"single-row system-stepping visualization"}},{"before":"d4d73de8f8885ed30ce1a7805b8e7d8dc9e7b8bb","after":"518fe183842495edf225b712dc8ab91ce6b88b81","ref":"refs/heads/bevy-0.12","pushedAt":"2023-11-11T19:23:07.000Z","pushType":"push","commitsCount":1,"pusher":{"login":"ChristopherBiscardi","name":"Chris Biscardi","path":"/ChristopherBiscardi","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/551247?s=80&v=4"},"commit":{"message":"make board a resource","shortMessageHtmlLink":"make board a resource"}},{"before":"4241d4f50b1c772cc62aae387f9fc75f803fd48c","after":"d4d73de8f8885ed30ce1a7805b8e7d8dc9e7b8bb","ref":"refs/heads/bevy-0.12","pushedAt":"2023-11-11T17:49:42.000Z","pushType":"push","commitsCount":1,"pusher":{"login":"ChristopherBiscardi","name":"Chris Biscardi","path":"/ChristopherBiscardi","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/551247?s=80&v=4"},"commit":{"message":"make colors const","shortMessageHtmlLink":"make colors const"}},{"before":"3fe6919a513a82dbd09433fd5fdb82415a4a1008","after":"4241d4f50b1c772cc62aae387f9fc75f803fd48c","ref":"refs/heads/bevy-0.12","pushedAt":"2023-11-10T03:05:25.000Z","pushType":"push","commitsCount":1,"pusher":{"login":"ChristopherBiscardi","name":"Chris Biscardi","path":"/ChristopherBiscardi","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/551247?s=80&v=4"},"commit":{"message":"all real releases","shortMessageHtmlLink":"all real releases"}},{"before":"cc3d168324f79e07cd08ec2b09ba830cc6da9f48","after":"3fe6919a513a82dbd09433fd5fdb82415a4a1008","ref":"refs/heads/bevy-0.12","pushedAt":"2023-11-07T16:44:24.000Z","pushType":"push","commitsCount":1,"pusher":{"login":"ChristopherBiscardi","name":"Chris Biscardi","path":"/ChristopherBiscardi","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/551247?s=80&v=4"},"commit":{"message":"upgrade to 0.12 actual release; bevy_asset_loader still waiting for official release, but it doesnt matter much to us as we're using well-supported features","shortMessageHtmlLink":"upgrade to 0.12 actual release; bevy_asset_loader still waiting for o…"}},{"before":"7b2e33409ec9e52620fe1ee0034a4c40614c42be","after":"cc3d168324f79e07cd08ec2b09ba830cc6da9f48","ref":"refs/heads/bevy-0.12","pushedAt":"2023-10-27T06:16:06.000Z","pushType":"push","commitsCount":1,"pusher":{"login":"ChristopherBiscardi","name":"Chris Biscardi","path":"/ChristopherBiscardi","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/551247?s=80&v=4"},"commit":{"message":"re-introduce window title","shortMessageHtmlLink":"re-introduce window title"}},{"before":"46d41fc3ca517fed9e312428255cc4fb5f266451","after":"7b2e33409ec9e52620fe1ee0034a4c40614c42be","ref":"refs/heads/bevy-0.12","pushedAt":"2023-10-27T04:51:39.000Z","pushType":"push","commitsCount":1,"pusher":{"login":"ChristopherBiscardi","name":"Chris Biscardi","path":"/ChristopherBiscardi","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/551247?s=80&v=4"},"commit":{"message":"position and ivec2","shortMessageHtmlLink":"position and ivec2"}},{"before":"58ea8ec4ba233ac1877d44df84d50ad725e52c3d","after":"46d41fc3ca517fed9e312428255cc4fb5f266451","ref":"refs/heads/bevy-0.12","pushedAt":"2023-10-26T23:28:04.000Z","pushType":"push","commitsCount":1,"pusher":{"login":"ChristopherBiscardi","name":"Chris Biscardi","path":"/ChristopherBiscardi","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/551247?s=80&v=4"},"commit":{"message":"some fixups","shortMessageHtmlLink":"some fixups"}},{"before":"cbb8d902a1a74a1d516b533e3de1eedd284a9413","after":"58ea8ec4ba233ac1877d44df84d50ad725e52c3d","ref":"refs/heads/bevy-0.12","pushedAt":"2023-10-25T22:07:44.000Z","pushType":"push","commitsCount":1,"pusher":{"login":"ChristopherBiscardi","name":"Chris Biscardi","path":"/ChristopherBiscardi","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/551247?s=80&v=4"},"commit":{"message":"board.tiles()","shortMessageHtmlLink":"board.tiles()"}},{"before":null,"after":"cbb8d902a1a74a1d516b533e3de1eedd284a9413","ref":"refs/heads/bevy-0.12","pushedAt":"2023-10-25T21:49:11.000Z","pushType":"branch_creation","commitsCount":0,"pusher":{"login":"ChristopherBiscardi","name":"Chris Biscardi","path":"/ChristopherBiscardi","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/551247?s=80&v=4"},"commit":{"message":"remove an extra comment","shortMessageHtmlLink":"remove an extra comment"}}],"hasNextPage":false,"hasPreviousPage":false,"activityType":"all","actor":null,"timePeriod":"all","sort":"DESC","perPage":30,"startCursor":"Y3Vyc29yOnYyOpK7MjAyNC0wNy0xM1QwNDowNjowMC4wMDAwMDBazwAAAAR-YJCm","endCursor":"Y3Vyc29yOnYyOpK7MjAyMy0xMC0yNVQyMTo0OToxMS4wMDAwMDBazwAAAAOf5CX9"}},"title":"Activity · rust-adventure/bevy-snake"}