Seed automation works
This commit is contained in:
Generated
+4018
-1287
File diff suppressed because it is too large
Load Diff
+3
-3
@@ -4,6 +4,6 @@ version = "0.1.0"
|
|||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
bevy = { version = "0.18.1", features = ["keyboard"] }
|
||||||
ggez = "0.9.3"
|
rand = "0.10.1"
|
||||||
rand = "0.9.1"
|
rand_chacha = "0.10.0"
|
||||||
+19
-14
@@ -1,5 +1,5 @@
|
|||||||
|
use bevy::prelude::Color;
|
||||||
use std::ops::{Index, IndexMut};
|
use std::ops::{Index, IndexMut};
|
||||||
use ggez::graphics::Color;
|
|
||||||
|
|
||||||
pub struct Table<T: Clone> {
|
pub struct Table<T: Clone> {
|
||||||
default: T,
|
default: T,
|
||||||
@@ -7,12 +7,12 @@ pub struct Table<T: Clone> {
|
|||||||
pub(crate) side: usize,
|
pub(crate) side: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T : Clone> Clone for Table<T>{
|
impl<T: Clone> Clone for Table<T> {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
Table{
|
Table {
|
||||||
default: self.default.clone(),
|
default: self.default.clone(),
|
||||||
data: self.data.clone(),
|
data: self.data.clone(),
|
||||||
side: self.side
|
side: self.side,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -60,7 +60,7 @@ impl<T: Clone> Table<T> {
|
|||||||
self.side = new_side;
|
self.side = new_side;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn iter(&self) -> impl Iterator<Item=&T> {
|
pub fn iter(&self) -> impl Iterator<Item = &T> {
|
||||||
self.data.iter()
|
self.data.iter()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,25 +77,30 @@ impl<T: Clone> Into<Vec<T>> for Table<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Into<Vec<u8>> for Table<Color> {
|
pub trait IntoImage {
|
||||||
fn into(self) -> Vec<u8> {
|
fn get_image_data(&self) -> Vec<u8>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntoImage for Table<bool> {
|
||||||
|
fn get_image_data(&self) -> Vec<u8> {
|
||||||
let mut data: Vec<u8> = vec![0; self.side * self.side * 4];
|
let mut data: Vec<u8> = vec![0; self.side * self.side * 4];
|
||||||
self.data
|
self.data
|
||||||
.iter()
|
.iter()
|
||||||
.zip((0..self.data.len()).collect::<Vec<_>>())
|
.zip((0..self.data.len()).collect::<Vec<_>>())
|
||||||
.for_each(|(color, idx)| {
|
.for_each(|(color, idx)| {
|
||||||
let (r, g, b, a) = color.to_rgba();
|
|
||||||
let idx = idx * 4;
|
let idx = idx * 4;
|
||||||
data[idx] = r;
|
let value = if *color { 255 } else { 0 };
|
||||||
data[idx + 1] = g;
|
|
||||||
data[idx + 2] = b;
|
data[idx] = value;
|
||||||
data[idx + 3] = a;
|
data[idx + 1] = value;
|
||||||
|
data[idx + 2] = value;
|
||||||
|
data[idx + 3] = 255;
|
||||||
});
|
});
|
||||||
data
|
data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T : Clone> Index<usize> for Table<T>{
|
impl<T: Clone> Index<usize> for Table<T> {
|
||||||
type Output = T;
|
type Output = T;
|
||||||
|
|
||||||
fn index(&self, index: usize) -> &Self::Output {
|
fn index(&self, index: usize) -> &Self::Output {
|
||||||
@@ -103,7 +108,7 @@ impl<T : Clone> Index<usize> for Table<T>{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T : Clone> IndexMut<usize> for Table<T>{
|
impl<T: Clone> IndexMut<usize> for Table<T> {
|
||||||
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
||||||
self.data.index_mut(index)
|
self.data.index_mut(index)
|
||||||
}
|
}
|
||||||
|
|||||||
+37
-154
@@ -1,165 +1,48 @@
|
|||||||
mod basic;
|
mod basic;
|
||||||
|
mod seed_automation;
|
||||||
|
mod plate_automation;
|
||||||
|
|
||||||
use crate::basic::Table;
|
use crate::basic::{IntoImage, Table};
|
||||||
use ggez::conf::{WindowMode, WindowSetup};
|
use bevy::asset::io::embedded::GetAssetServer;
|
||||||
use ggez::event::{self, EventHandler};
|
use bevy::input::keyboard::keyboard_input_system;
|
||||||
use ggez::glam::Vec2;
|
use bevy::prelude::*;
|
||||||
use ggez::graphics::{self, Color, DrawParam, Image, ImageFormat};
|
use rand::{Rng, RngExt};
|
||||||
use ggez::{Context, ContextBuilder, GameResult};
|
use rand_chacha::ChaCha8Rng;
|
||||||
use rand::Rng;
|
use rand_chacha::rand_core::SeedableRng;
|
||||||
use rand::rngs::ThreadRng;
|
use seed_automation::SeedAutomation;
|
||||||
|
|
||||||
const WIN_SIZE_F: f32 = 1000.0;
|
const RECTANGLE_SIDE: f32 = 500.0;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// Make a Context.
|
App::new()
|
||||||
let (mut ctx, event_loop) = ContextBuilder::new("tectonic_generator", "YaslePoy")
|
.add_plugins(DefaultPlugins)
|
||||||
.window_setup(WindowSetup::default().title("Tectonic generator"))
|
.add_systems(Startup, setup)
|
||||||
.window_mode(
|
.insert_resource(Time::<Fixed>::from_hz(1024.0))
|
||||||
WindowMode::default()
|
.add_systems(Update, keyboard_input_system)
|
||||||
.resizable(false)
|
.add_systems(Update, seed_automation::update_automation_seed)
|
||||||
.dimensions(WIN_SIZE_F, WIN_SIZE_F),
|
.add_systems(Update, seed_automation::update_automation_view_seed)
|
||||||
)
|
.add_systems(Update, plate_automation::update_automation_plate)
|
||||||
.build()
|
.add_systems(Update, plate_automation::update_automation_view_plate)
|
||||||
.expect("aieee, could not create ggez context!");
|
.run();
|
||||||
|
|
||||||
// Create an instance of your event handler.
|
|
||||||
// Usually, you should provide it with the Context object to
|
|
||||||
// use when setting your game up.
|
|
||||||
let my_game = MyGame::new(&mut ctx);
|
|
||||||
|
|
||||||
// Run!
|
|
||||||
event::run(ctx, event_loop, my_game);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct MyGame {
|
fn setup(mut commands: Commands, mut images: ResMut<Assets<Image>>) {
|
||||||
display: Image,
|
commands.spawn(Camera2d);
|
||||||
pub raw_view: Table<Color>,
|
|
||||||
require_draw: bool,
|
|
||||||
state: Box<dyn LandscapeState>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MyGame {
|
let handle = images.add(Image::default());
|
||||||
pub fn new(_ctx: &mut Context) -> MyGame {
|
|
||||||
// Load/create resources such as images here.
|
let mut shape = Sprite::from_image(handle);
|
||||||
let initial_size = 32_u32;
|
shape.custom_size = Some(Vec2::new(RECTANGLE_SIDE, RECTANGLE_SIDE));
|
||||||
let raw = Table::new(Color::BLACK, initial_size as usize);
|
|
||||||
let game = MyGame {
|
let automation = SeedAutomation {
|
||||||
display: Image::from_pixels(
|
world: Table::new(false, 16),
|
||||||
_ctx,
|
|
||||||
&vec![0_u8; (initial_size * initial_size * 4) as usize],
|
|
||||||
ImageFormat::Rgba8UnormSrgb,
|
|
||||||
initial_size,
|
|
||||||
initial_size,
|
|
||||||
),
|
|
||||||
raw_view: raw,
|
|
||||||
require_draw: false,
|
|
||||||
state: Box::new(SeedLandscape::new(initial_size)),
|
|
||||||
};
|
};
|
||||||
game
|
|
||||||
}
|
commands.spawn((shape, automation));
|
||||||
|
|
||||||
|
let seeded_rng = ChaCha8Rng::seed_from_u64(rand::random());
|
||||||
|
commands.insert_resource(SeededRng(seeded_rng));
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EventHandler for MyGame {
|
#[derive(Resource)]
|
||||||
fn update(&mut self, _ctx: &mut Context) -> GameResult {
|
struct SeededRng(ChaCha8Rng);
|
||||||
if _ctx
|
|
||||||
.keyboard
|
|
||||||
.is_key_just_pressed(ggez::input::keyboard::KeyCode::T)
|
|
||||||
{
|
|
||||||
self.state.propagate(LandscapeTick::Tick);
|
|
||||||
self.require_draw = true;
|
|
||||||
}
|
|
||||||
if _ctx
|
|
||||||
.keyboard
|
|
||||||
.is_key_just_pressed(ggez::input::keyboard::KeyCode::N)
|
|
||||||
{
|
|
||||||
self.state.propagate(LandscapeTick::Next);
|
|
||||||
self.require_draw = true;
|
|
||||||
}
|
|
||||||
if _ctx
|
|
||||||
.keyboard
|
|
||||||
.is_key_just_pressed(ggez::input::keyboard::KeyCode::S)
|
|
||||||
{
|
|
||||||
self.raw_view.grow();
|
|
||||||
self.state.propagate(LandscapeTick::Scale);
|
|
||||||
self.require_draw = true;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn draw(&mut self, ctx: &mut Context) -> GameResult {
|
|
||||||
let mut canvas = graphics::Canvas::from_frame(ctx, Color::BLACK);
|
|
||||||
|
|
||||||
if self.require_draw {
|
|
||||||
self.state.render(&mut self.raw_view);
|
|
||||||
let pixels: Vec<u8> = self.raw_view.clone().try_into().unwrap();
|
|
||||||
self.display = Image::from_pixels(
|
|
||||||
ctx,
|
|
||||||
&pixels,
|
|
||||||
ImageFormat::Rgba8UnormSrgb,
|
|
||||||
self.raw_view.side as u32,
|
|
||||||
self.raw_view.side as u32,
|
|
||||||
);
|
|
||||||
self.require_draw = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
let scale = WIN_SIZE_F / self.raw_view.side as f32;
|
|
||||||
canvas.draw(
|
|
||||||
&self.display,
|
|
||||||
DrawParam::default().scale(Vec2::new(scale, scale)),
|
|
||||||
);
|
|
||||||
|
|
||||||
canvas.finish(ctx)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum LandscapeTick {
|
|
||||||
Scale,
|
|
||||||
Tick,
|
|
||||||
Next,
|
|
||||||
}
|
|
||||||
|
|
||||||
trait LandscapeState {
|
|
||||||
fn propagate(&mut self, action: LandscapeTick);
|
|
||||||
fn render(&mut self, display: &mut Table<Color>);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct SeedLandscape {
|
|
||||||
field: Table<bool>,
|
|
||||||
random: ThreadRng,
|
|
||||||
color: Color,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SeedLandscape {
|
|
||||||
pub fn new(size: u32) -> SeedLandscape {
|
|
||||||
Self {
|
|
||||||
field: Table::new(false, size as usize),
|
|
||||||
random: rand::rng(),
|
|
||||||
color: Color::WHITE,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl LandscapeState for SeedLandscape {
|
|
||||||
fn propagate(&mut self, action: LandscapeTick) {
|
|
||||||
match action {
|
|
||||||
LandscapeTick::Scale => self.field.grow(),
|
|
||||||
LandscapeTick::Tick => loop {
|
|
||||||
let index = self.random.random_range(0..self.field.data.len());
|
|
||||||
if !self.field[index] {
|
|
||||||
self.field[index] = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
LandscapeTick::Next => {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn render(&mut self, display: &mut Table<Color>) {
|
|
||||||
self.field.convert_copy(display, |x| {
|
|
||||||
if x { self.color } else { Color::BLACK }
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -0,0 +1,68 @@
|
|||||||
|
use crate::SeededRng;
|
||||||
|
use crate::basic::{IntoImage, Table};
|
||||||
|
use bevy::asset::{Assets, RenderAssetUsages};
|
||||||
|
use bevy::image::{BevyDefault, Image};
|
||||||
|
use bevy::input::ButtonInput;
|
||||||
|
use bevy::prelude::{Component, KeyCode, Query, ResMut, Sprite};
|
||||||
|
use bevy::render::render_resource::{Extent3d, TextureDimension, TextureFormat};
|
||||||
|
use rand::RngExt;
|
||||||
|
use rand_chacha::ChaCha8Rng;
|
||||||
|
|
||||||
|
pub fn update_automation_view_plate(
|
||||||
|
query: Query<(&Sprite, &PlateAutomation)>,
|
||||||
|
mut images: ResMut<Assets<Image>>,
|
||||||
|
) {
|
||||||
|
let (sprite, automation) = query.iter().next().unwrap();
|
||||||
|
let size = automation.world.side as u32;
|
||||||
|
let data = automation.world.get_image_data();
|
||||||
|
let image = Image::new(
|
||||||
|
Extent3d {
|
||||||
|
width: size,
|
||||||
|
height: size,
|
||||||
|
depth_or_array_layers: 1,
|
||||||
|
},
|
||||||
|
TextureDimension::D2,
|
||||||
|
data,
|
||||||
|
TextureFormat::bevy_default(),
|
||||||
|
RenderAssetUsages::default(),
|
||||||
|
);
|
||||||
|
|
||||||
|
images.remove(sprite.image.id());
|
||||||
|
images.insert(sprite.image.id(), image).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_automation_plate(
|
||||||
|
mut query: Query<&mut PlateAutomation>,
|
||||||
|
mut seeded_rng: ResMut<SeededRng>,
|
||||||
|
keys: ResMut<ButtonInput<KeyCode>>,
|
||||||
|
) {
|
||||||
|
let mut automation = query.iter_mut().next().unwrap();
|
||||||
|
if keys.just_pressed(KeyCode::Space) {
|
||||||
|
let random = &mut seeded_rng.0;
|
||||||
|
|
||||||
|
automation.next(random)
|
||||||
|
}
|
||||||
|
|
||||||
|
if keys.just_pressed(KeyCode::AltLeft) {
|
||||||
|
automation.world.grow()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Component)]
|
||||||
|
pub struct PlateAutomation {
|
||||||
|
pub(crate) world: Table<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PlateAutomation {
|
||||||
|
fn next(&mut self, rng: &mut ChaCha8Rng) {
|
||||||
|
let len = (self.world.side * self.world.side) as f32;
|
||||||
|
loop {
|
||||||
|
let index = (rng.random::<f32>() * len) as usize;
|
||||||
|
if *self.world.get(index) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
self.world.set(index, true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
use crate::SeededRng;
|
||||||
|
use crate::basic::{IntoImage, Table};
|
||||||
|
use bevy::asset::{Assets, RenderAssetUsages};
|
||||||
|
use bevy::image::{BevyDefault, Image};
|
||||||
|
use bevy::input::ButtonInput;
|
||||||
|
use bevy::prelude::{Commands, Component, Entity, KeyCode, Query, ResMut, Sprite};
|
||||||
|
use bevy::render::render_resource::{Extent3d, TextureDimension, TextureFormat};
|
||||||
|
use rand::RngExt;
|
||||||
|
use rand_chacha::ChaCha8Rng;
|
||||||
|
|
||||||
|
pub fn update_automation_view_seed(
|
||||||
|
query: Query<(&Sprite, &SeedAutomation)>,
|
||||||
|
mut images: ResMut<Assets<Image>>,
|
||||||
|
) {
|
||||||
|
let (sprite, automation) = query.iter().next().unwrap();
|
||||||
|
let size = automation.world.side as u32;
|
||||||
|
let data = automation.world.get_image_data();
|
||||||
|
let image = Image::new(
|
||||||
|
Extent3d {
|
||||||
|
width: size,
|
||||||
|
height: size,
|
||||||
|
depth_or_array_layers: 1,
|
||||||
|
},
|
||||||
|
TextureDimension::D2,
|
||||||
|
data,
|
||||||
|
TextureFormat::bevy_default(),
|
||||||
|
RenderAssetUsages::default(),
|
||||||
|
);
|
||||||
|
|
||||||
|
images.remove(sprite.image.id());
|
||||||
|
images.insert(sprite.image.id(), image).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_automation_seed(
|
||||||
|
mut query: Query<(&mut SeedAutomation, Entity)>,
|
||||||
|
mut seeded_rng: ResMut<SeededRng>,
|
||||||
|
keys: ResMut<ButtonInput<KeyCode>>,
|
||||||
|
mut commands: Commands) {
|
||||||
|
let (mut automation, entity) = query.iter_mut().next().unwrap();
|
||||||
|
if keys.just_pressed(KeyCode::Space){
|
||||||
|
let random = &mut seeded_rng.0;
|
||||||
|
automation.next(random)
|
||||||
|
}
|
||||||
|
if keys.just_pressed(KeyCode::Tab){
|
||||||
|
commands.entity(entity).;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Component)]
|
||||||
|
pub struct SeedAutomation {
|
||||||
|
pub(crate) world: Table<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SeedAutomation {
|
||||||
|
fn next(&mut self, rng: &mut ChaCha8Rng) {
|
||||||
|
let len = (self.world.side * self.world.side) as f32;
|
||||||
|
loop {
|
||||||
|
let index = (rng.random::<f32>() * len) as usize;
|
||||||
|
if *self.world.get(index) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
self.world.set(index, true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user