add a macro for simpler first examples.
This commit is contained in:
parent
453e8e39bd
commit
cef63ca32a
@ -1,105 +0,0 @@
|
|||||||
## Project Context
|
|
||||||
- **turtle-lib**: Heavy Bevy-based turtle graphics (0.17.1) with ECS architecture
|
|
||||||
- **turtle-lib-macroquad**: Lightweight macroquad implementation with Lyon tessellation (current focus)
|
|
||||||
- **turtle-lyon-poc**: Proof of concept for Lyon (COMPLETED - integrated into main crate)
|
|
||||||
- **turtle-skia-poc**: Alternative tiny-skia rendering approach
|
|
||||||
- **Status**: Lyon migration complete, fill quality issues resolved
|
|
||||||
|
|
||||||
## Architecture
|
|
||||||
```
|
|
||||||
turtle-lib-macroquad/src/
|
|
||||||
├── lib.rs - Public API & TurtleApp
|
|
||||||
├── state.rs - TurtleState & TurtleWorld
|
|
||||||
├── commands.rs - TurtleCommand & CommandQueue
|
|
||||||
├── builders.rs - Builder traits (DirectionalMovement, Turnable, CurvedMovement)
|
|
||||||
├── execution.rs - Command execution
|
|
||||||
├── tweening.rs - Animation controller
|
|
||||||
├── drawing.rs - Macroquad rendering
|
|
||||||
├── tessellation.rs - Lyon tessellation (355 lines - polygons, circles, arcs, strokes)
|
|
||||||
├── circle_geometry.rs - Circle/arc geometry calculations
|
|
||||||
├── shapes.rs - Turtle shapes
|
|
||||||
└── general/ - Type definitions (Angle, Length, Color, etc.)
|
|
||||||
```
|
|
||||||
|
|
||||||
## Current Status
|
|
||||||
1. ✅ **Lyon integration complete**: Using Lyon 1.0 for all tessellation
|
|
||||||
2. ✅ **Fill quality fixed**: EvenOdd fill rule handles complex fills and holes automatically
|
|
||||||
3. ✅ **Simplified codebase**: Replaced manual triangulation with Lyon's GPU-optimized tessellation
|
|
||||||
4. ✅ **Full feature set**: Polygons, circles, arcs, strokes all using Lyon
|
|
||||||
|
|
||||||
## Key Features
|
|
||||||
- **Builder API**: Fluent interface for turtle commands
|
|
||||||
- **Animation system**: Tweening controller with configurable speeds (Instant/Animated)
|
|
||||||
- **Lyon tessellation**: Automatic hole detection, proper winding order, GPU-optimized
|
|
||||||
- **Fill support**: Multi-contour fills with automatic hole handling
|
|
||||||
- **Shapes**: Arrow, circle, square, triangle, classic turtle shapes
|
|
||||||
|
|
||||||
## Response Style Rules
|
|
||||||
- NO emoji/smileys
|
|
||||||
- NO extensive summaries
|
|
||||||
- Use bullet points for lists
|
|
||||||
- Be concise and direct
|
|
||||||
- Focus on code solutions
|
|
||||||
|
|
||||||
# Tools to use
|
|
||||||
- when in doubt you can always use #fetch to get additional docs and online information.
|
|
||||||
- when the userinput is incomplete generate a brief text and let the user confirm your understanding.
|
|
||||||
|
|
||||||
## Code Patterns
|
|
||||||
|
|
||||||
### Lyon Tessellation (Current)
|
|
||||||
```rust
|
|
||||||
// tessellation.rs - Lyon integration
|
|
||||||
pub fn tessellate_polygon(vertices: &[Vec2], color: Color) -> Result<MeshData, Box<dyn std::error::Error>>
|
|
||||||
pub fn tessellate_multi_contour(contours: &[Vec<Vec2>], color: Color) -> Result<MeshData, Box<dyn std::error::Error>>
|
|
||||||
pub fn tessellate_stroke(vertices: &[Vec2], color: Color, width: f32, closed: bool) -> Result<MeshData, Box<dyn std::error::Error>>
|
|
||||||
pub fn tessellate_circle(center: Vec2, radius: f32, color: Color, filled: bool, stroke_width: f32) -> Result<MeshData, Box<dyn std::error::Error>>
|
|
||||||
pub fn tessellate_arc(center: Vec2, radius: f32, start_angle: f32, arc_angle: f32, color: Color, stroke_width: f32, segments: usize) -> Result<MeshData, Box<dyn std::error::Error>>
|
|
||||||
```
|
|
||||||
|
|
||||||
### Fill with Holes
|
|
||||||
```rust
|
|
||||||
// Multi-contour fills automatically detect holes using EvenOdd fill rule
|
|
||||||
let contours = vec![outer_boundary, hole1, hole2];
|
|
||||||
let mesh = tessellate_multi_contour(&contours, color)?;
|
|
||||||
```
|
|
||||||
|
|
||||||
## Builder API
|
|
||||||
```rust
|
|
||||||
let mut t = create_turtle();
|
|
||||||
t.forward(100).right(90)
|
|
||||||
.circle_left(50.0, 180.0, 36)
|
|
||||||
.begin_fill()
|
|
||||||
.set_fill_color(BLACK)
|
|
||||||
.circle_left(90.0, 180.0, 36)
|
|
||||||
.end_fill();
|
|
||||||
let app = TurtleApp::new().with_commands(t.build());
|
|
||||||
```
|
|
||||||
|
|
||||||
## File Links
|
|
||||||
- Main crate: [turtle-lib-macroquad/src/lib.rs](turtle-lib-macroquad/src/lib.rs)
|
|
||||||
- Tessellation: [turtle-lib-macroquad/src/tessellation.rs](turtle-lib-macroquad/src/tessellation.rs)
|
|
||||||
- Rendering: [turtle-lib-macroquad/src/drawing.rs](turtle-lib-macroquad/src/drawing.rs)
|
|
||||||
- Animation: [turtle-lib-macroquad/src/tweening.rs](turtle-lib-macroquad/src/tweening.rs)
|
|
||||||
- Examples: [turtle-lib-macroquad/examples/](turtle-lib-macroquad/examples/)
|
|
||||||
|
|
||||||
## Testing
|
|
||||||
Run examples to verify Lyon integration:
|
|
||||||
```bash
|
|
||||||
cargo run --example yinyang
|
|
||||||
cargo run --example stern
|
|
||||||
cargo run --example nikolaus
|
|
||||||
```
|
|
||||||
|
|
||||||
## Code Quality
|
|
||||||
Run clippy with strict checks on turtle-lib-macroquad:
|
|
||||||
```bash
|
|
||||||
cargo clippy --package turtle-lib-macroquad -- -Wclippy::pedantic -Wclippy::cast_precision_loss -Wclippy::cast_sign_loss -Wclippy::cast_possible_truncation
|
|
||||||
```
|
|
||||||
Note: Cast warnings are intentionally allowed for graphics code where precision loss is acceptable.
|
|
||||||
|
|
||||||
## Dependencies
|
|
||||||
- macroquad 0.4 - Game framework and rendering
|
|
||||||
- lyon 1.0 - Tessellation (fills, strokes, circles, arcs)
|
|
||||||
- tween 2.1.0 - Animation easing
|
|
||||||
- tracing 0.1 - Logging (with log features)
|
|
||||||
200
.github/copilot-instructions.md
vendored
Normal file
200
.github/copilot-instructions.md
vendored
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
# Turtle Graphics Library - AI Agent Instructions
|
||||||
|
|
||||||
|
## Project Overview
|
||||||
|
|
||||||
|
Rust workspace with turtle graphics implementations. **Primary focus: `turtle-lib-macroquad`** - lightweight library using Macroquad + Lyon for GPU-accelerated rendering.
|
||||||
|
|
||||||
|
### Workspace Structure
|
||||||
|
```
|
||||||
|
turtle/
|
||||||
|
├── turtle-lib-macroquad/ # MAIN LIBRARY - Macroquad + Lyon (focus here)
|
||||||
|
├── turtle-lib-macroquad-macros/ # Proc macro for turtle_main
|
||||||
|
├── turtle-lib/ # Legacy Bevy 0.17.1 implementation (maintenance only)
|
||||||
|
├── turtle-example/ # Legacy examples
|
||||||
|
└── turtle-ui/ # UI components
|
||||||
|
```
|
||||||
|
|
||||||
|
## Architecture (`turtle-lib-macroquad`)
|
||||||
|
|
||||||
|
### Core Design Pattern: Command Queue + Tweening
|
||||||
|
- **Builder API** (`TurtlePlan`) accumulates commands
|
||||||
|
- **Command Queue** stores execution plan
|
||||||
|
- **Tween Controller** interpolates between states for animation
|
||||||
|
- **Lyon Tessellation** converts all primitives to GPU meshes
|
||||||
|
|
||||||
|
### Key Files
|
||||||
|
```
|
||||||
|
src/
|
||||||
|
├── lib.rs - Public API, TurtleApp (main loop), re-exports
|
||||||
|
├── builders.rs - Fluent API traits (forward/right/etc chain)
|
||||||
|
├── commands.rs - TurtleCommand enum (Move/Turn/Circle/etc)
|
||||||
|
├── execution.rs - Execute commands, update state
|
||||||
|
├── tweening.rs - Animation interpolation, speed control
|
||||||
|
├── drawing.rs - Render Lyon meshes with Macroquad
|
||||||
|
├── tessellation.rs - Lyon integration (polygons/strokes/fills/arcs)
|
||||||
|
├── state.rs - TurtleState, TurtleWorld, FillState
|
||||||
|
└── circle_geometry.rs - Arc/circle math
|
||||||
|
```
|
||||||
|
|
||||||
|
### Critical Concepts
|
||||||
|
|
||||||
|
**1. Consolidated Commands** (reduces duplication):
|
||||||
|
- `Move(distance)` - negative = backward
|
||||||
|
- `Turn(angle)` - positive = right, negative = left (degrees)
|
||||||
|
- `Circle{radius, angle, steps, direction}` - unified left/right
|
||||||
|
|
||||||
|
**2. Fill System** (multi-contour with holes):
|
||||||
|
- `FillState` tracks `Vec<Vec<Vec2>>` (multiple contours)
|
||||||
|
- `pen_up()` closes current contour, `pen_down()` opens new
|
||||||
|
- Lyon's EvenOdd fill rule auto-detects holes
|
||||||
|
- Example: Donut = outer circle + inner circle (2 contours)
|
||||||
|
|
||||||
|
**3. Speed Modes**:
|
||||||
|
- `< 999`: Animated with tweening
|
||||||
|
- `>= 999`: Instant execution
|
||||||
|
- Controlled via `SetSpeed` commands (dynamic switching)
|
||||||
|
|
||||||
|
**4. Lyon Tessellation Pipeline**:
|
||||||
|
All drawing → Lyon → GPU mesh → Macroquad rendering
|
||||||
|
- ~410 lines eliminated vs manual triangulation
|
||||||
|
- Functions: `tessellate_polygon/stroke/circle/arc/multi_contour`
|
||||||
|
|
||||||
|
## Developer Workflows
|
||||||
|
|
||||||
|
### Building & Testing
|
||||||
|
```bash
|
||||||
|
# Main library
|
||||||
|
cargo build --package turtle-lib-macroquad
|
||||||
|
cargo test --package turtle-lib-macroquad
|
||||||
|
cargo clippy --package turtle-lib-macroquad -- -Wclippy::pedantic \
|
||||||
|
-Aclippy::cast_precision_loss -Aclippy::cast_sign_loss -Aclippy::cast_possible_truncation
|
||||||
|
|
||||||
|
# Run examples (15+ examples available)
|
||||||
|
cargo run --package turtle-lib-macroquad --example hello_turtle
|
||||||
|
cargo run --package turtle-lib-macroquad --example yinyang
|
||||||
|
cargo run --package turtle-lib-macroquad --example cheese_macro
|
||||||
|
```
|
||||||
|
|
||||||
|
### Macro Crate
|
||||||
|
```bash
|
||||||
|
cargo build --package turtle-lib-macroquad-macros
|
||||||
|
```
|
||||||
|
|
||||||
|
### Code Quality Standards
|
||||||
|
- Clippy pedantic mode enabled
|
||||||
|
- Cast warnings allowed for graphics math
|
||||||
|
- All examples must build warning-free
|
||||||
|
- Use `#[must_use]` on builder methods
|
||||||
|
|
||||||
|
## Project-Specific Patterns
|
||||||
|
|
||||||
|
### 1. The `turtle_main` Macro (PREFERRED for examples)
|
||||||
|
Simplest way to create turtle programs:
|
||||||
|
```rust
|
||||||
|
use turtle_lib_macroquad::*;
|
||||||
|
|
||||||
|
#[turtle_main("Window Title")]
|
||||||
|
fn draw(turtle: &mut TurtlePlan) {
|
||||||
|
turtle.forward(100.0).right(90.0);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Generates: window setup + render loop + quit handling (ESC/Q)
|
||||||
|
|
||||||
|
### 2. Import Convention
|
||||||
|
Only need: `use turtle_lib_macroquad::*;`
|
||||||
|
- Re-exports: `vec2`, `RED/BLUE/GREEN/etc`, all turtle types
|
||||||
|
- No `use macroquad::prelude::*` needed (causes unused warnings)
|
||||||
|
|
||||||
|
### 3. Builder Chain Pattern
|
||||||
|
```rust
|
||||||
|
let mut t = create_turtle();
|
||||||
|
t.forward(100).right(90)
|
||||||
|
.set_pen_color(BLUE)
|
||||||
|
.circle_left(50.0, 360.0, 36)
|
||||||
|
.begin_fill()
|
||||||
|
.end_fill();
|
||||||
|
let app = TurtleApp::new().with_commands(t.build());
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Multi-Contour Fill Example
|
||||||
|
```rust
|
||||||
|
turtle.begin_fill();
|
||||||
|
turtle.circle_left(100.0, 360.0, 72); // Outer circle
|
||||||
|
turtle.pen_up(); // Closes contour
|
||||||
|
turtle.goto(vec2(0.0, -30.0));
|
||||||
|
turtle.pen_down(); // Opens new contour
|
||||||
|
turtle.circle_left(30.0, 360.0, 36); // Inner (becomes hole)
|
||||||
|
turtle.end_fill(); // EvenOdd rule creates donut
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. Manual Setup (advanced control)
|
||||||
|
```rust
|
||||||
|
#[macroquad::main("Custom")]
|
||||||
|
async fn main() {
|
||||||
|
let mut turtle = create_turtle();
|
||||||
|
// ... drawing code ...
|
||||||
|
let mut app = TurtleApp::new().with_commands(turtle.build());
|
||||||
|
|
||||||
|
loop {
|
||||||
|
clear_background(WHITE);
|
||||||
|
app.update();
|
||||||
|
app.render();
|
||||||
|
next_frame().await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Common Tasks
|
||||||
|
|
||||||
|
### Adding New Turtle Command
|
||||||
|
1. Add variant to `TurtleCommand` enum in `commands.rs`
|
||||||
|
2. Implement builder method in `builders.rs` (chain with `self`)
|
||||||
|
3. Add execution logic in `execution.rs`
|
||||||
|
4. Update tessellation/rendering if needed
|
||||||
|
|
||||||
|
### Adding Example
|
||||||
|
- Prefer `turtle_main` macro for simplicity
|
||||||
|
- Use only `use turtle_lib_macroquad::*;`
|
||||||
|
- Keep examples focused (one concept each)
|
||||||
|
- See `examples/hello_turtle.rs` for minimal template
|
||||||
|
|
||||||
|
### Debugging Lyon Issues
|
||||||
|
- Enable tracing: `RUST_LOG=turtle_lib_macroquad=debug cargo run`
|
||||||
|
- Check `tessellation.rs` for Lyon API usage
|
||||||
|
- EvenOdd fill rule: holes must have opposite winding
|
||||||
|
|
||||||
|
## Dependencies & Integration
|
||||||
|
|
||||||
|
### Main Dependencies
|
||||||
|
- `macroquad = "0.4"` - Window/rendering framework
|
||||||
|
- `lyon = "1.0"` - Tessellation (fills, strokes, circles)
|
||||||
|
- `tween = "2.1.0"` - Animation easing
|
||||||
|
- `tracing = "0.1"` - Optional logging (zero overhead when unused)
|
||||||
|
|
||||||
|
### Proc Macro Crate
|
||||||
|
- Separate crate required by Rust (proc-macro = true)
|
||||||
|
- Uses `syn`, `quote`, `proc-macro2`
|
||||||
|
- Generates full macroquad app boilerplate
|
||||||
|
|
||||||
|
## What NOT to Do
|
||||||
|
|
||||||
|
- Don't add `use macroquad::prelude::*` in examples when not required
|
||||||
|
- Don't manually triangulate - use Lyon functions
|
||||||
|
- Don't add commands for Forward/Backward separately (use Move)
|
||||||
|
- Don't modify `turtle-lib` (Bevy) unless specifically needed
|
||||||
|
- Don't create summary/comparison docs unless requested
|
||||||
|
|
||||||
|
## Key Documentation Files
|
||||||
|
|
||||||
|
- `README.md` - Main API docs
|
||||||
|
- `turtle-lib-macroquad/README.md` - Library-specific docs
|
||||||
|
- `turtle-lib-macroquad-macros/README.md` - Macro docs
|
||||||
|
|
||||||
|
## Response Style
|
||||||
|
|
||||||
|
- Be concise, no extensive summaries
|
||||||
|
- No emojis in technical responses
|
||||||
|
- Focus on code solutions over explanations
|
||||||
|
- Use bullet points for lists
|
||||||
|
- Reference specific files when helpful
|
||||||
@ -1,7 +1,12 @@
|
|||||||
[workspace]
|
[workspace]
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
|
|
||||||
members = ["turtle-lib", "turtle-example", "turtle-lib-macroquad"]
|
members = [
|
||||||
|
"turtle-lib",
|
||||||
|
"turtle-example",
|
||||||
|
"turtle-lib-macroquad",
|
||||||
|
"turtle-lib-macroquad-macros",
|
||||||
|
]
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
# Pin Bevy across the workspace
|
# Pin Bevy across the workspace
|
||||||
|
|||||||
13
turtle-lib-macroquad-macros/Cargo.toml
Normal file
13
turtle-lib-macroquad-macros/Cargo.toml
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
[package]
|
||||||
|
name = "turtle-lib-macroquad-macros"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
license = "MIT OR Apache-2.0"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
proc-macro = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
proc-macro2 = "1.0"
|
||||||
|
quote = "1.0"
|
||||||
|
syn = { version = "2.0", features = ["full"] }
|
||||||
72
turtle-lib-macroquad-macros/README.md
Normal file
72
turtle-lib-macroquad-macros/README.md
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
# turtle-lib-macroquad-macros
|
||||||
|
|
||||||
|
Procedural macros for `turtle-lib-macroquad`.
|
||||||
|
|
||||||
|
## `turtle_main` Macro
|
||||||
|
|
||||||
|
The `turtle_main` macro simplifies creating turtle graphics programs by automatically setting up:
|
||||||
|
- The Macroquad window
|
||||||
|
- Turtle initialization
|
||||||
|
- The main rendering loop
|
||||||
|
- Quit handling (ESC or Q keys)
|
||||||
|
|
||||||
|
### Usage
|
||||||
|
|
||||||
|
#### With a function parameter:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use macroquad::prelude::*;
|
||||||
|
use turtle_lib_macroquad::*;
|
||||||
|
|
||||||
|
#[turtle_main("My Drawing")]
|
||||||
|
fn my_drawing(turtle: &mut TurtlePlan) {
|
||||||
|
turtle.set_pen_color(RED);
|
||||||
|
turtle.forward(100.0);
|
||||||
|
turtle.right(90.0);
|
||||||
|
turtle.forward(100.0);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### With inline code:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use macroquad::prelude::*;
|
||||||
|
use turtle_lib_macroquad::*;
|
||||||
|
|
||||||
|
#[turtle_main("My Drawing")]
|
||||||
|
fn my_drawing() {
|
||||||
|
turtle.set_pen_color(RED);
|
||||||
|
turtle.forward(100.0);
|
||||||
|
turtle.right(90.0);
|
||||||
|
turtle.forward(100.0);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### What it does
|
||||||
|
|
||||||
|
The macro expands your code into a full Macroquad application with:
|
||||||
|
- `#[macroquad::main]` attribute for window creation
|
||||||
|
- Turtle instance creation
|
||||||
|
- TurtleApp initialization with your commands
|
||||||
|
- A main loop that:
|
||||||
|
- Clears the background to WHITE
|
||||||
|
- Updates the turtle app
|
||||||
|
- Renders the drawing
|
||||||
|
- Shows "Press ESC or Q to quit" message
|
||||||
|
- Handles quit keys
|
||||||
|
|
||||||
|
### Benefits
|
||||||
|
|
||||||
|
- **Less boilerplate**: No need to write the same loop structure in every example
|
||||||
|
- **Consistent UI**: All examples have the same quit behavior
|
||||||
|
- **Beginner-friendly**: Makes turtle graphics examples more approachable
|
||||||
|
- **Focus on drawing**: Your code focuses on the turtle commands, not the framework
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
Licensed under either of:
|
||||||
|
|
||||||
|
- Apache License, Version 2.0 ([LICENSE-APACHE](../LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
|
||||||
|
- MIT license ([LICENSE-MIT](../LICENSE-MIT) or http://opensource.org/licenses/MIT)
|
||||||
|
|
||||||
|
at your option.
|
||||||
175
turtle-lib-macroquad-macros/src/lib.rs
Normal file
175
turtle-lib-macroquad-macros/src/lib.rs
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
//! Procedural macros for turtle-lib-macroquad
|
||||||
|
//!
|
||||||
|
//! This crate provides the `turtle_main` procedural macro that simplifies
|
||||||
|
//! creating turtle graphics programs by automatically setting up the
|
||||||
|
//! macroquad window, turtle initialization, and the main rendering loop.
|
||||||
|
|
||||||
|
use proc_macro::TokenStream;
|
||||||
|
use quote::quote;
|
||||||
|
use syn::{parse_macro_input, ItemFn};
|
||||||
|
|
||||||
|
/// A convenience macro that wraps your turtle drawing code with the necessary
|
||||||
|
/// boilerplate for running a turtle graphics program.
|
||||||
|
///
|
||||||
|
/// This macro:
|
||||||
|
/// - Wraps your code with `#[macroquad::main]`
|
||||||
|
/// - Creates a turtle instance (`turtle`)
|
||||||
|
/// - Sets up the `TurtleApp` with your drawing commands
|
||||||
|
/// - Provides a main loop with rendering and quit handling (ESC or Q)
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// use turtle_lib_macroquad::*;
|
||||||
|
///
|
||||||
|
/// #[turtle_main("My Turtle Drawing")]
|
||||||
|
/// fn my_drawing(turtle: &mut TurtlePlan) {
|
||||||
|
/// // Use colors from turtle_lib_macroquad (re-exported from macroquad)
|
||||||
|
/// turtle.set_pen_color(RED);
|
||||||
|
/// turtle.forward(100.0);
|
||||||
|
/// turtle.right(90.0);
|
||||||
|
/// turtle.forward(100.0);
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// If you need macroquad types not re-exported by turtle_lib_macroquad:
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// use macroquad::prelude::SKYBLUE; // Import specific items
|
||||||
|
/// use turtle_lib_macroquad::*;
|
||||||
|
///
|
||||||
|
/// #[turtle_main("My Drawing")]
|
||||||
|
/// fn my_drawing(turtle: &mut TurtlePlan) {
|
||||||
|
/// turtle.set_pen_color(SKYBLUE);
|
||||||
|
/// turtle.forward(100.0);
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// This expands to approximately:
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// use macroquad::prelude::*;
|
||||||
|
/// use turtle_lib_macroquad::*;
|
||||||
|
///
|
||||||
|
/// #[macroquad::main("My Turtle Drawing")]
|
||||||
|
/// async fn main() {
|
||||||
|
/// let mut turtle = create_turtle();
|
||||||
|
///
|
||||||
|
/// // Your drawing code here
|
||||||
|
/// turtle.set_pen_color(RED);
|
||||||
|
/// turtle.forward(100.0);
|
||||||
|
/// turtle.right(90.0);
|
||||||
|
/// turtle.forward(100.0);
|
||||||
|
///
|
||||||
|
/// let mut app = TurtleApp::new().with_commands(turtle.build());
|
||||||
|
///
|
||||||
|
/// loop {
|
||||||
|
/// clear_background(WHITE);
|
||||||
|
/// app.update();
|
||||||
|
/// app.render();
|
||||||
|
/// draw_text("Press ESC or Q to quit", 10.0, 40.0, 16.0, DARKGRAY);
|
||||||
|
///
|
||||||
|
/// if is_key_pressed(KeyCode::Escape) || is_key_pressed(KeyCode::Q) {
|
||||||
|
/// break;
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// next_frame().await;
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[proc_macro_attribute]
|
||||||
|
pub fn turtle_main(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||||
|
let input_fn = parse_macro_input!(input as ItemFn);
|
||||||
|
|
||||||
|
// Parse the window title from args (default to "Turtle Graphics")
|
||||||
|
let window_title = if args.is_empty() {
|
||||||
|
quote! { "Turtle Graphics" }
|
||||||
|
} else {
|
||||||
|
let args_str = args.to_string();
|
||||||
|
// Remove quotes if present
|
||||||
|
let title = args_str.trim().trim_matches('"');
|
||||||
|
quote! { #title }
|
||||||
|
};
|
||||||
|
|
||||||
|
let fn_name = &input_fn.sig.ident;
|
||||||
|
let fn_block = &input_fn.block;
|
||||||
|
|
||||||
|
// Check if the function has the expected signature
|
||||||
|
let has_turtle_param = input_fn.sig.inputs.len() == 1;
|
||||||
|
|
||||||
|
let expanded = if has_turtle_param {
|
||||||
|
// Function takes a turtle parameter
|
||||||
|
quote! {
|
||||||
|
#[macroquad::main(#window_title)]
|
||||||
|
async fn main() {
|
||||||
|
let mut turtle = turtle_lib_macroquad::create_turtle();
|
||||||
|
|
||||||
|
// Call the user's function with the turtle
|
||||||
|
#fn_name(&mut turtle);
|
||||||
|
|
||||||
|
let mut app = turtle_lib_macroquad::TurtleApp::new()
|
||||||
|
.with_commands(turtle.build());
|
||||||
|
|
||||||
|
loop {
|
||||||
|
macroquad::prelude::clear_background(macroquad::prelude::WHITE);
|
||||||
|
app.update();
|
||||||
|
app.render();
|
||||||
|
macroquad::prelude::draw_text(
|
||||||
|
"Press ESC or Q to quit",
|
||||||
|
10.0,
|
||||||
|
40.0,
|
||||||
|
16.0,
|
||||||
|
macroquad::prelude::DARKGRAY
|
||||||
|
);
|
||||||
|
|
||||||
|
if macroquad::prelude::is_key_pressed(macroquad::prelude::KeyCode::Escape)
|
||||||
|
|| macroquad::prelude::is_key_pressed(macroquad::prelude::KeyCode::Q)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
macroquad::prelude::next_frame().await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn #fn_name(turtle: &mut turtle_lib_macroquad::TurtlePlan) #fn_block
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Function takes no parameters - inline the code
|
||||||
|
quote! {
|
||||||
|
#[macroquad::main(#window_title)]
|
||||||
|
async fn main() {
|
||||||
|
let mut turtle = turtle_lib_macroquad::create_turtle();
|
||||||
|
|
||||||
|
// Inline the user's code
|
||||||
|
#fn_block
|
||||||
|
|
||||||
|
let mut app = turtle_lib_macroquad::TurtleApp::new()
|
||||||
|
.with_commands(turtle.build());
|
||||||
|
|
||||||
|
loop {
|
||||||
|
macroquad::prelude::clear_background(macroquad::prelude::WHITE);
|
||||||
|
app.update();
|
||||||
|
app.render();
|
||||||
|
macroquad::prelude::draw_text(
|
||||||
|
"Press ESC or Q to quit",
|
||||||
|
10.0,
|
||||||
|
40.0,
|
||||||
|
16.0,
|
||||||
|
macroquad::prelude::DARKGRAY
|
||||||
|
);
|
||||||
|
|
||||||
|
if macroquad::prelude::is_key_pressed(macroquad::prelude::KeyCode::Escape)
|
||||||
|
|| macroquad::prelude::is_key_pressed(macroquad::prelude::KeyCode::Q)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
macroquad::prelude::next_frame().await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
TokenStream::from(expanded)
|
||||||
|
}
|
||||||
@ -9,6 +9,7 @@ macroquad = "0.4"
|
|||||||
tween = "2.1.0"
|
tween = "2.1.0"
|
||||||
lyon = "1.0"
|
lyon = "1.0"
|
||||||
tracing = { version = "0.1", features = ["log"], default-features = false }
|
tracing = { version = "0.1", features = ["log"], default-features = false }
|
||||||
|
turtle-lib-macroquad-macros = { path = "../turtle-lib-macroquad-macros" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
# For examples and testing
|
# For examples and testing
|
||||||
|
|||||||
@ -22,17 +22,74 @@ The main turtle graphics library built on Macroquad with Lyon tessellation.
|
|||||||
- Frame-rate independent animation
|
- Frame-rate independent animation
|
||||||
- Live fill preview during circle/arc drawing
|
- Live fill preview during circle/arc drawing
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
### Using the `turtle_main` Macro (Recommended for Beginners)
|
||||||
|
|
||||||
|
The easiest way to create turtle programs is with the `turtle_main` macro:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use macroquad::prelude::*;
|
||||||
|
use turtle_lib_macroquad::*;
|
||||||
|
|
||||||
|
#[turtle_main("My First Drawing")]
|
||||||
|
fn my_drawing(turtle: &mut TurtlePlan) {
|
||||||
|
turtle.set_pen_color(RED);
|
||||||
|
turtle.forward(100.0);
|
||||||
|
turtle.right(90.0);
|
||||||
|
turtle.forward(100.0);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The macro automatically handles:
|
||||||
|
- Window creation and setup
|
||||||
|
- Turtle initialization
|
||||||
|
- Rendering loop
|
||||||
|
- Quit handling (ESC or Q keys)
|
||||||
|
|
||||||
|
### Manual Setup (For Advanced Use)
|
||||||
|
|
||||||
|
For more control over the application loop:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use macroquad::prelude::*;
|
||||||
|
use turtle_lib_macroquad::*;
|
||||||
|
|
||||||
|
#[macroquad::main("Turtle")]
|
||||||
|
async fn main() {
|
||||||
|
let mut turtle = create_turtle();
|
||||||
|
turtle.forward(100.0).right(90.0);
|
||||||
|
|
||||||
|
let mut app = TurtleApp::new().with_commands(turtle.build());
|
||||||
|
|
||||||
|
loop {
|
||||||
|
clear_background(WHITE);
|
||||||
|
app.update();
|
||||||
|
app.render();
|
||||||
|
next_frame().await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Quick Examples
|
## Quick Examples
|
||||||
|
|
||||||
|
All examples now use the `turtle_main` macro for simplicity:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Run from this directory
|
# Run from this directory
|
||||||
cargo run --example square # Basic square drawing
|
cargo run --example hello_turtle # Minimal 10-line example
|
||||||
cargo run --example yinyang # Multi-contour fills with holes
|
cargo run --example macro_demo # Simple square with macro
|
||||||
cargo run --example fill_advanced # Self-intersecting fills
|
cargo run --example square # Basic square drawing
|
||||||
cargo run --example koch # Recursive fractals
|
cargo run --example shapes # Different turtle shapes
|
||||||
cargo run --example fill_demo # Multiple independent fills
|
cargo run --example yinyang # Multi-contour fills with holes
|
||||||
|
cargo run --example koch # Recursive fractals
|
||||||
|
cargo run --example fill_demo # Fill with holes (donut)
|
||||||
|
cargo run --example cheese_macro # Cheese example using macro
|
||||||
|
cargo run --example fill_advanced # Complex shapes (manual setup)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Most examples use `turtle_main` for simplicity. A few keep manual setup for custom UI or logging.
|
||||||
|
|
||||||
## Architecture Highlights
|
## Architecture Highlights
|
||||||
|
|
||||||
### Rendering Pipeline
|
### Rendering Pipeline
|
||||||
|
|||||||
66
turtle-lib-macroquad/examples/cheese_macro.rs
Normal file
66
turtle-lib-macroquad/examples/cheese_macro.rs
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
//! Cheese example using the turtle_main macro
|
||||||
|
//!
|
||||||
|
//! This is a simplified version of cheese.rs that demonstrates how the
|
||||||
|
//! turtle_main macro reduces boilerplate code.
|
||||||
|
|
||||||
|
use turtle_lib_macroquad::*;
|
||||||
|
|
||||||
|
#[turtle_main("Cheese with Holes - Using Macro")]
|
||||||
|
fn draw_cheese(turtle: &mut TurtlePlan) {
|
||||||
|
// Set fill color to yellow (cheese color!)
|
||||||
|
turtle.set_pen_color(ORANGE);
|
||||||
|
turtle.set_pen_width(3.0);
|
||||||
|
turtle.set_fill_color(YELLOW);
|
||||||
|
|
||||||
|
println!("=== Starting cheese fill ===");
|
||||||
|
turtle.begin_fill();
|
||||||
|
|
||||||
|
// Draw outer boundary (large square)
|
||||||
|
println!("Drawing outer square boundary...");
|
||||||
|
for _ in 0..4 {
|
||||||
|
turtle.forward(400.0);
|
||||||
|
turtle.right(90.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close outer contour and start drawing holes
|
||||||
|
println!("Closing outer contour with pen_up");
|
||||||
|
turtle.pen_up();
|
||||||
|
|
||||||
|
// Draw triangular hole in the middle
|
||||||
|
println!("Drawing triangular hole...");
|
||||||
|
turtle.go_to(vec2(200.0, 120.0));
|
||||||
|
turtle.pen_down(); // Start new contour for hole
|
||||||
|
|
||||||
|
for _ in 0..3 {
|
||||||
|
turtle.forward(160.0);
|
||||||
|
turtle.right(120.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("Closing triangle contour with pen_up");
|
||||||
|
turtle.pen_up(); // Close triangle hole contour
|
||||||
|
|
||||||
|
// Draw circular hole (top-left) using circle_left
|
||||||
|
println!("Drawing circular hole (top-left) with circle_left...");
|
||||||
|
turtle.go_to(vec2(100.0, 100.0));
|
||||||
|
turtle.pen_down(); // Start new contour for hole
|
||||||
|
turtle.circle_left(30.0, 360.0, 36); // radius=30, full circle, 36 steps
|
||||||
|
println!("Closing circle contour with pen_up");
|
||||||
|
turtle.pen_up(); // Close circle hole contour
|
||||||
|
|
||||||
|
// Draw circular hole (bottom-right) using circle_right
|
||||||
|
println!("Drawing circular hole (bottom-right) with circle_right...");
|
||||||
|
turtle.go_to(vec2(280.0, 280.0));
|
||||||
|
turtle.pen_down(); // Start new contour for hole
|
||||||
|
turtle.circle_right(40.0, 360.0, 36); // radius=40, full circle, 36 steps
|
||||||
|
println!("Closing circle contour with pen_up");
|
||||||
|
turtle.pen_up(); // Close circle hole contour
|
||||||
|
|
||||||
|
// End fill - Lyon will automatically create holes!
|
||||||
|
println!("Calling end_fill - Lyon should create holes now!");
|
||||||
|
turtle.end_fill();
|
||||||
|
|
||||||
|
// Set animation speed
|
||||||
|
turtle.set_speed(300);
|
||||||
|
|
||||||
|
println!("Building and executing turtle plan...");
|
||||||
|
}
|
||||||
@ -1,46 +1,29 @@
|
|||||||
//! Test circle_left and circle_right commands
|
//! Test circle_left and circle_right commands
|
||||||
|
|
||||||
use macroquad::prelude::*;
|
|
||||||
use turtle_lib_macroquad::*;
|
use turtle_lib_macroquad::*;
|
||||||
|
|
||||||
#[macroquad::main("Circle Test")]
|
#[turtle_main("Circle Test")]
|
||||||
async fn main() {
|
fn draw(turtle: &mut TurtlePlan) {
|
||||||
// Create a turtle plan
|
turtle.shape(ShapeType::Turtle);
|
||||||
let mut plan = create_turtle();
|
|
||||||
plan.shape(ShapeType::Turtle);
|
|
||||||
|
|
||||||
// Draw some circles
|
// Draw some circles
|
||||||
plan.set_pen_color(RED);
|
turtle.set_pen_color(RED);
|
||||||
plan.set_pen_width(0.5);
|
turtle.set_pen_width(0.5);
|
||||||
plan.left(90.0);
|
turtle.left(90.0);
|
||||||
plan.set_speed(999);
|
turtle.set_speed(999);
|
||||||
plan.circle_left(100.0, 540.0, 72); // partial circle to the left
|
turtle.circle_left(100.0, 540.0, 72); // partial circle to the left
|
||||||
|
|
||||||
plan.forward(150.0);
|
turtle.forward(150.0);
|
||||||
plan.set_speed(100);
|
turtle.set_speed(100);
|
||||||
plan.set_pen_color(BLUE);
|
turtle.set_pen_color(BLUE);
|
||||||
plan.circle_right(50.0, 270.0, 72); // partial circle to the right
|
turtle.circle_right(50.0, 270.0, 72); // partial circle to the right
|
||||||
// Set animation speed
|
// Set animation speed
|
||||||
plan.set_speed(20);
|
turtle.set_speed(20);
|
||||||
plan.forward(150.0);
|
turtle.forward(150.0);
|
||||||
plan.circle_left(50.0, 180.0, 12);
|
turtle.circle_left(50.0, 180.0, 12);
|
||||||
plan.circle_right(50.0, 180.0, 12);
|
turtle.circle_right(50.0, 180.0, 12);
|
||||||
|
|
||||||
plan.set_speed(700);
|
turtle.set_speed(700);
|
||||||
plan.set_pen_color(GREEN);
|
turtle.set_pen_color(GREEN);
|
||||||
plan.circle_left(50.0, 180.0, 36); // Half circle to the left
|
turtle.circle_left(50.0, 180.0, 36); // Half circle to the left
|
||||||
|
|
||||||
// Create turtle app with animation (speed = 100 pixels/sec)
|
|
||||||
let mut app = TurtleApp::new().with_commands(plan.build());
|
|
||||||
|
|
||||||
// Main loop
|
|
||||||
loop {
|
|
||||||
clear_background(WHITE);
|
|
||||||
|
|
||||||
// Update and render
|
|
||||||
app.update();
|
|
||||||
app.render();
|
|
||||||
|
|
||||||
next_frame().await
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,31 +1,13 @@
|
|||||||
//! Test circle_left and circle_right commands
|
//! Test direction and movement commands
|
||||||
|
|
||||||
use macroquad::prelude::*;
|
|
||||||
use turtle_lib_macroquad::*;
|
use turtle_lib_macroquad::*;
|
||||||
|
|
||||||
#[macroquad::main("Circle Test")]
|
#[turtle_main("Direction Test")]
|
||||||
async fn main() {
|
fn draw(turtle: &mut TurtlePlan) {
|
||||||
// Create a turtle plan
|
|
||||||
let mut plan = create_turtle();
|
|
||||||
|
|
||||||
// Set animation speed
|
// Set animation speed
|
||||||
plan.set_speed(50);
|
turtle.set_speed(50);
|
||||||
plan.right(45.0);
|
turtle.right(45.0);
|
||||||
plan.forward(100.0);
|
turtle.forward(100.0);
|
||||||
plan.right(45.0);
|
turtle.right(45.0);
|
||||||
plan.forward(100.0);
|
turtle.forward(100.0);
|
||||||
|
|
||||||
// Create turtle app with animation (speed = 100 pixels/sec)
|
|
||||||
let mut app = TurtleApp::new().with_commands(plan.build());
|
|
||||||
|
|
||||||
// Main loop
|
|
||||||
loop {
|
|
||||||
clear_background(WHITE);
|
|
||||||
|
|
||||||
// Update and render
|
|
||||||
app.update();
|
|
||||||
app.render();
|
|
||||||
|
|
||||||
next_frame().await
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,6 @@
|
|||||||
//! Advanced fill example with multiple holes and complex shapes
|
//! Advanced fill example with multiple holes and complex shapes
|
||||||
|
//!
|
||||||
|
//! This example uses manual setup to demonstrate custom window size and UI elements.
|
||||||
|
|
||||||
use macroquad::{miniquad::window::set_window_size, prelude::*};
|
use macroquad::{miniquad::window::set_window_size, prelude::*};
|
||||||
use turtle_lib_macroquad::*;
|
use turtle_lib_macroquad::*;
|
||||||
|
|||||||
@ -1,55 +1,43 @@
|
|||||||
//! Fill demonstration with holes
|
//! Fill demonstration with holes
|
||||||
|
|
||||||
use macroquad::prelude::*;
|
|
||||||
use turtle_lib_macroquad::*;
|
use turtle_lib_macroquad::*;
|
||||||
|
|
||||||
#[macroquad::main("Fill Demo")]
|
#[turtle_main("Fill Demo")]
|
||||||
async fn main() {
|
fn draw(turtle: &mut TurtlePlan) {
|
||||||
let mut t = create_turtle();
|
|
||||||
|
|
||||||
// Example from requirements: circle with hole (like a donut)
|
// Example from requirements: circle with hole (like a donut)
|
||||||
t.set_pen_color(BLUE);
|
turtle.set_pen_color(BLUE);
|
||||||
t.set_pen_width(3.0);
|
turtle.set_pen_width(3.0);
|
||||||
t.right(90.0);
|
turtle.right(90.0);
|
||||||
|
|
||||||
// Set fill color and begin fill
|
// Set fill color and begin fill
|
||||||
t.set_fill_color(RED);
|
turtle.set_fill_color(RED);
|
||||||
t.begin_fill();
|
turtle.begin_fill();
|
||||||
|
|
||||||
// Outer circle
|
// Outer circle
|
||||||
t.circle_right(150.0, 360.0, 72);
|
turtle.circle_right(150.0, 360.0, 72);
|
||||||
|
|
||||||
// Move to start of inner circle (hole)
|
// Move to start of inner circle (hole)
|
||||||
// pen_up doesn't matter for fill - vertices still recorded!
|
// pen_up doesn't matter for fill - vertices still recorded!
|
||||||
t.pen_up();
|
turtle.pen_up();
|
||||||
t.forward(50.0);
|
turtle.forward(50.0);
|
||||||
t.pen_down();
|
turtle.pen_down();
|
||||||
|
|
||||||
// Inner circle (creates a hole)
|
// Inner circle (creates a hole)
|
||||||
t.circle_right(150.0, 360.0, 72);
|
turtle.circle_right(150.0, 360.0, 72);
|
||||||
|
|
||||||
t.end_fill();
|
turtle.end_fill();
|
||||||
|
|
||||||
// Draw a square with no fill
|
// Draw a square with no fill
|
||||||
t.pen_up();
|
turtle.pen_up();
|
||||||
t.forward(100.0);
|
turtle.forward(100.0);
|
||||||
t.pen_down();
|
turtle.pen_down();
|
||||||
t.set_pen_color(GREEN);
|
turtle.set_pen_color(GREEN);
|
||||||
|
|
||||||
for _ in 0..4 {
|
for _ in 0..4 {
|
||||||
t.forward(100.0);
|
turtle.forward(100.0);
|
||||||
t.right(90.0);
|
turtle.right(90.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set animation speed
|
// Set animation speed
|
||||||
t.set_speed(100);
|
turtle.set_speed(100);
|
||||||
|
|
||||||
let mut app = TurtleApp::new().with_commands(t.build());
|
|
||||||
|
|
||||||
loop {
|
|
||||||
clear_background(WHITE);
|
|
||||||
app.update();
|
|
||||||
app.render();
|
|
||||||
next_frame().await
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,12 +1,9 @@
|
|||||||
//! Example matching the original requirements exactly
|
//! Example matching the original requirements exactly
|
||||||
|
|
||||||
use macroquad::prelude::*;
|
|
||||||
use turtle_lib_macroquad::*;
|
use turtle_lib_macroquad::*;
|
||||||
|
|
||||||
#[macroquad::main("Fill Example - Original Requirements")]
|
#[turtle_main("Fill Example - Original Requirements")]
|
||||||
async fn main() {
|
fn draw(turtle: &mut TurtlePlan) {
|
||||||
let mut turtle = create_turtle();
|
|
||||||
|
|
||||||
turtle.right(90.0);
|
turtle.right(90.0);
|
||||||
turtle.set_pen_width(3.0);
|
turtle.set_pen_width(3.0);
|
||||||
turtle.set_speed(900);
|
turtle.set_speed(900);
|
||||||
@ -37,30 +34,4 @@ async fn main() {
|
|||||||
|
|
||||||
// Set speed for animation
|
// Set speed for animation
|
||||||
turtle.set_speed(200);
|
turtle.set_speed(200);
|
||||||
|
|
||||||
let mut app = TurtleApp::new().with_commands(turtle.build());
|
|
||||||
|
|
||||||
loop {
|
|
||||||
clear_background(WHITE);
|
|
||||||
app.update();
|
|
||||||
app.render();
|
|
||||||
|
|
||||||
// Instructions
|
|
||||||
draw_text(
|
|
||||||
"Fill Example - Circle filled with red, square not filled",
|
|
||||||
10.0,
|
|
||||||
20.0,
|
|
||||||
20.0,
|
|
||||||
BLACK,
|
|
||||||
);
|
|
||||||
draw_text(
|
|
||||||
"Mouse: drag to pan, scroll to zoom",
|
|
||||||
10.0,
|
|
||||||
40.0,
|
|
||||||
16.0,
|
|
||||||
DARKGRAY,
|
|
||||||
);
|
|
||||||
|
|
||||||
next_frame().await
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
14
turtle-lib-macroquad/examples/hello_turtle.rs
Normal file
14
turtle-lib-macroquad/examples/hello_turtle.rs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
//! Minimal turtle example - just 10 lines!
|
||||||
|
//!
|
||||||
|
//! This is the simplest possible turtle program using the macro.
|
||||||
|
|
||||||
|
use turtle_lib_macroquad::*;
|
||||||
|
|
||||||
|
#[turtle_main("Hello Turtle")]
|
||||||
|
fn hello() {
|
||||||
|
turtle.set_pen_color(BLUE);
|
||||||
|
for _ in 0..4 {
|
||||||
|
turtle.forward(100.0);
|
||||||
|
turtle.right(90.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,50 +1,37 @@
|
|||||||
//! Koch snowflake fractal example
|
//! Koch snowflake fractal example
|
||||||
|
|
||||||
use macroquad::prelude::*;
|
|
||||||
use turtle_lib_macroquad::*;
|
use turtle_lib_macroquad::*;
|
||||||
|
|
||||||
fn koch(depth: u32, plan: &mut TurtlePlan, distance: f32) {
|
fn koch(depth: u32, turtle: &mut TurtlePlan, distance: f32) {
|
||||||
if depth == 0 {
|
if depth == 0 {
|
||||||
plan.forward(distance);
|
turtle.forward(distance);
|
||||||
} else {
|
} else {
|
||||||
let new_distance = distance / 3.0;
|
let new_distance = distance / 3.0;
|
||||||
koch(depth - 1, plan, new_distance);
|
koch(depth - 1, turtle, new_distance);
|
||||||
plan.left(60.0);
|
turtle.left(60.0);
|
||||||
koch(depth - 1, plan, new_distance);
|
koch(depth - 1, turtle, new_distance);
|
||||||
plan.right(120.0);
|
turtle.right(120.0);
|
||||||
koch(depth - 1, plan, new_distance);
|
koch(depth - 1, turtle, new_distance);
|
||||||
plan.left(60.0);
|
turtle.left(60.0);
|
||||||
koch(depth - 1, plan, new_distance);
|
koch(depth - 1, turtle, new_distance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[macroquad::main("Koch Snowflake")]
|
#[turtle_main("Koch Snowflake")]
|
||||||
async fn main() {
|
fn draw(turtle: &mut TurtlePlan) {
|
||||||
let mut plan = create_turtle();
|
|
||||||
|
|
||||||
// Position turtle
|
// Position turtle
|
||||||
plan.set_speed(1001);
|
turtle.set_speed(1001);
|
||||||
plan.pen_up();
|
turtle.pen_up();
|
||||||
plan.backward(150.0);
|
turtle.backward(150.0);
|
||||||
|
|
||||||
plan.pen_down();
|
turtle.pen_down();
|
||||||
|
|
||||||
// Draw Koch snowflake (triangle of Koch curves)
|
// Draw Koch snowflake (triangle of Koch curves)
|
||||||
for _ in 0..3 {
|
for _ in 0..3 {
|
||||||
koch(4, &mut plan, 300.0);
|
koch(4, turtle, 300.0);
|
||||||
plan.right(120.0);
|
turtle.right(120.0);
|
||||||
plan.set_speed(1200);
|
turtle.set_speed(1200);
|
||||||
}
|
}
|
||||||
|
|
||||||
plan.hide(); // Hide turtle when done
|
turtle.hide(); // Hide turtle when done
|
||||||
|
|
||||||
// Create app with animation
|
|
||||||
let mut app = TurtleApp::new().with_commands(plan.build());
|
|
||||||
|
|
||||||
loop {
|
|
||||||
clear_background(WHITE);
|
|
||||||
app.update();
|
|
||||||
app.render();
|
|
||||||
next_frame().await
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,6 +17,8 @@
|
|||||||
//! RUST_LOG=turtle_lib_macroquad::tessellation=debug cargo run --example logging_example
|
//! RUST_LOG=turtle_lib_macroquad::tessellation=debug cargo run --example logging_example
|
||||||
//! RUST_LOG=turtle_lib_macroquad::execution=debug cargo run --example logging_example
|
//! RUST_LOG=turtle_lib_macroquad::execution=debug cargo run --example logging_example
|
||||||
//! ```
|
//! ```
|
||||||
|
//!
|
||||||
|
//! Note: This example uses manual setup to demonstrate custom initialization logic.
|
||||||
|
|
||||||
use macroquad::prelude::*;
|
use macroquad::prelude::*;
|
||||||
use turtle_lib_macroquad::*;
|
use turtle_lib_macroquad::*;
|
||||||
@ -27,11 +29,10 @@ async fn main() {
|
|||||||
// This will respect the RUST_LOG environment variable
|
// This will respect the RUST_LOG environment variable
|
||||||
tracing_subscriber::fmt()
|
tracing_subscriber::fmt()
|
||||||
.with_env_filter(
|
.with_env_filter(
|
||||||
tracing_subscriber::EnvFilter::try_from_default_env()
|
tracing_subscriber::EnvFilter::try_from_default_env().unwrap_or_else(|_| {
|
||||||
.unwrap_or_else(|_| {
|
// Default to showing info-level logs if RUST_LOG is not set
|
||||||
// Default to showing info-level logs if RUST_LOG is not set
|
tracing_subscriber::EnvFilter::new("turtle_lib_macroquad=info")
|
||||||
tracing_subscriber::EnvFilter::new("turtle_lib_macroquad=info")
|
}),
|
||||||
}),
|
|
||||||
)
|
)
|
||||||
.with_target(true) // Show which module the log came from
|
.with_target(true) // Show which module the log came from
|
||||||
.with_thread_ids(false)
|
.with_thread_ids(false)
|
||||||
@ -40,7 +41,9 @@ async fn main() {
|
|||||||
.init();
|
.init();
|
||||||
|
|
||||||
tracing::info!("Starting turtle graphics example with logging enabled");
|
tracing::info!("Starting turtle graphics example with logging enabled");
|
||||||
tracing::info!("Try running with: RUST_LOG=turtle_lib_macroquad=debug cargo run --example logging_example");
|
tracing::info!(
|
||||||
|
"Try running with: RUST_LOG=turtle_lib_macroquad=debug cargo run --example logging_example"
|
||||||
|
);
|
||||||
|
|
||||||
// Create a turtle plan with fill operations to see detailed logging
|
// Create a turtle plan with fill operations to see detailed logging
|
||||||
let mut t = create_turtle();
|
let mut t = create_turtle();
|
||||||
|
|||||||
17
turtle-lib-macroquad/examples/macro_demo.rs
Normal file
17
turtle-lib-macroquad/examples/macro_demo.rs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
//! Simple demo of the turtle_main macro
|
||||||
|
//!
|
||||||
|
//! This example shows how the turtle_main macro simplifies turtle programs
|
||||||
|
//! by automatically handling window setup, turtle creation, and the render loop.
|
||||||
|
|
||||||
|
use turtle_lib_macroquad::*;
|
||||||
|
|
||||||
|
#[turtle_main("Macro Demo - Simple Square")]
|
||||||
|
fn draw_square(turtle: &mut TurtlePlan) {
|
||||||
|
turtle.set_pen_color(BLUE);
|
||||||
|
turtle.set_pen_width(3.0);
|
||||||
|
|
||||||
|
for _ in 0..4 {
|
||||||
|
turtle.forward(150.0);
|
||||||
|
turtle.right(90.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
17
turtle-lib-macroquad/examples/macro_demo_inline.rs
Normal file
17
turtle-lib-macroquad/examples/macro_demo_inline.rs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
//! Demo of the turtle_main macro with inline code
|
||||||
|
//!
|
||||||
|
//! This example shows that you can write your turtle code directly
|
||||||
|
//! in the function body without taking a turtle parameter.
|
||||||
|
|
||||||
|
use turtle_lib_macroquad::*;
|
||||||
|
|
||||||
|
#[turtle_main("Macro Demo - Inline Spiral")]
|
||||||
|
fn draw_spiral() {
|
||||||
|
turtle.set_pen_color(RED);
|
||||||
|
turtle.set_pen_width(2.0);
|
||||||
|
|
||||||
|
for i in 0..36 {
|
||||||
|
turtle.forward(i as f32 * 3.0);
|
||||||
|
turtle.right(25.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
57
turtle-lib-macroquad/examples/macro_full_demo.rs
Normal file
57
turtle-lib-macroquad/examples/macro_full_demo.rs
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
//! Comprehensive macro example showing various turtle features
|
||||||
|
//!
|
||||||
|
//! This example demonstrates:
|
||||||
|
//! - Colors and pen settings
|
||||||
|
//! - Fills
|
||||||
|
//! - Circles
|
||||||
|
//! - Animation speed
|
||||||
|
|
||||||
|
use turtle_lib_macroquad::*;
|
||||||
|
|
||||||
|
#[turtle_main("Turtle Macro - Full Demo")]
|
||||||
|
fn full_demo(turtle: &mut TurtlePlan) {
|
||||||
|
// Draw a colorful flower
|
||||||
|
turtle.set_speed(200);
|
||||||
|
|
||||||
|
// Center the drawing
|
||||||
|
turtle.pen_up();
|
||||||
|
turtle.go_to(vec2(200.0, 300.0));
|
||||||
|
turtle.pen_down();
|
||||||
|
|
||||||
|
// Draw petals
|
||||||
|
for i in 0..8 {
|
||||||
|
let hue = i as f32 / 8.0;
|
||||||
|
let color = Color::from_rgba(
|
||||||
|
((hue * 360.0).to_radians().sin() * 127.0 + 128.0) as u8,
|
||||||
|
((hue * 360.0 + 120.0).to_radians().sin() * 127.0 + 128.0) as u8,
|
||||||
|
((hue * 360.0 + 240.0).to_radians().sin() * 127.0 + 128.0) as u8,
|
||||||
|
255,
|
||||||
|
);
|
||||||
|
|
||||||
|
turtle.set_fill_color(color);
|
||||||
|
turtle.set_pen_color(color);
|
||||||
|
turtle.begin_fill();
|
||||||
|
|
||||||
|
// Draw a petal using circles
|
||||||
|
turtle.circle_left(50.0, 180.0, 20);
|
||||||
|
turtle.left(90.0);
|
||||||
|
turtle.circle_left(50.0, 180.0, 20);
|
||||||
|
turtle.left(90.0);
|
||||||
|
|
||||||
|
turtle.end_fill();
|
||||||
|
|
||||||
|
// Move to next petal position
|
||||||
|
turtle.right(45.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw center circle
|
||||||
|
turtle.pen_up();
|
||||||
|
turtle.go_to(vec2(200.0, 300.0));
|
||||||
|
turtle.pen_down();
|
||||||
|
turtle.set_fill_color(YELLOW);
|
||||||
|
turtle.set_pen_color(ORANGE);
|
||||||
|
turtle.set_pen_width(2.0);
|
||||||
|
turtle.begin_fill();
|
||||||
|
turtle.circle_left(20.0, 360.0, 36);
|
||||||
|
turtle.end_fill();
|
||||||
|
}
|
||||||
@ -1,74 +1,57 @@
|
|||||||
//! Nikolaus example - draws a house-like figure
|
//! Nikolaus example - draws a house-like figure
|
||||||
|
|
||||||
use macroquad::prelude::*;
|
|
||||||
use turtle_lib_macroquad::*;
|
use turtle_lib_macroquad::*;
|
||||||
|
|
||||||
fn nikolausquadrat(plan: &mut TurtlePlan, groesse: f32) {
|
fn nikolausquadrat(turtle: &mut TurtlePlan, groesse: f32) {
|
||||||
plan.forward(groesse);
|
turtle.forward(groesse);
|
||||||
plan.left(90.0);
|
turtle.left(90.0);
|
||||||
plan.forward(groesse);
|
turtle.forward(groesse);
|
||||||
plan.left(90.0);
|
turtle.left(90.0);
|
||||||
plan.forward(groesse);
|
turtle.forward(groesse);
|
||||||
plan.left(90.0);
|
turtle.left(90.0);
|
||||||
plan.forward(groesse);
|
turtle.forward(groesse);
|
||||||
plan.left(90.0);
|
turtle.left(90.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn nikolausdiag(plan: &mut TurtlePlan, groesse: f32) {
|
fn nikolausdiag(turtle: &mut TurtlePlan, groesse: f32) {
|
||||||
let quadrat = groesse * groesse;
|
let quadrat = groesse * groesse;
|
||||||
let diag = (quadrat + quadrat).sqrt();
|
let diag = (quadrat + quadrat).sqrt();
|
||||||
|
|
||||||
plan.left(45.0);
|
turtle.left(45.0);
|
||||||
plan.forward(diag);
|
turtle.forward(diag);
|
||||||
plan.left(45.0);
|
turtle.left(45.0);
|
||||||
nikolausdach2(plan, groesse);
|
nikolausdach2(turtle, groesse);
|
||||||
plan.left(45.0);
|
turtle.left(45.0);
|
||||||
plan.forward(diag);
|
turtle.forward(diag);
|
||||||
plan.left(45.0);
|
turtle.left(45.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn nikolausdach2(plan: &mut TurtlePlan, groesse: f32) {
|
fn nikolausdach2(turtle: &mut TurtlePlan, groesse: f32) {
|
||||||
let quadrat = groesse * groesse;
|
let quadrat = groesse * groesse;
|
||||||
let diag = (quadrat + quadrat).sqrt();
|
let diag = (quadrat + quadrat).sqrt();
|
||||||
plan.left(45.0);
|
turtle.left(45.0);
|
||||||
plan.forward(diag / 2.0);
|
turtle.forward(diag / 2.0);
|
||||||
plan.left(90.0);
|
turtle.left(90.0);
|
||||||
plan.forward(diag / 2.0);
|
turtle.forward(diag / 2.0);
|
||||||
plan.left(45.0);
|
turtle.left(45.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn nikolaus(plan: &mut TurtlePlan, groesse: f32) {
|
fn nikolaus(turtle: &mut TurtlePlan, groesse: f32) {
|
||||||
nikolausquadrat(plan, groesse);
|
nikolausquadrat(turtle, groesse);
|
||||||
nikolausdiag(plan, groesse);
|
nikolausdiag(turtle, groesse);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[macroquad::main("Nikolaus")]
|
#[turtle_main("Nikolaus")]
|
||||||
async fn main() {
|
fn draw(turtle: &mut TurtlePlan) {
|
||||||
// Create a turtle plan
|
turtle.shape(ShapeType::Turtle);
|
||||||
let mut plan = create_turtle();
|
|
||||||
plan.shape(ShapeType::Turtle);
|
|
||||||
|
|
||||||
// Position the turtle (pen up, move, pen down)
|
// Position the turtle (pen up, move, pen down)
|
||||||
plan.pen_up();
|
turtle.pen_up();
|
||||||
plan.backward(80.0);
|
turtle.backward(80.0);
|
||||||
plan.left(90.0);
|
turtle.left(90.0);
|
||||||
plan.forward(50.0);
|
turtle.forward(50.0);
|
||||||
plan.right(90.0);
|
turtle.right(90.0);
|
||||||
plan.pen_down();
|
turtle.pen_down();
|
||||||
|
|
||||||
nikolaus(&mut plan, 100.0);
|
nikolaus(turtle, 100.0);
|
||||||
|
|
||||||
// Create turtle app with animation
|
|
||||||
let mut app = TurtleApp::new().with_commands(plan.build());
|
|
||||||
|
|
||||||
// Main loop
|
|
||||||
loop {
|
|
||||||
clear_background(WHITE);
|
|
||||||
|
|
||||||
// Update and render
|
|
||||||
app.update();
|
|
||||||
app.render();
|
|
||||||
|
|
||||||
next_frame().await
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,50 +1,32 @@
|
|||||||
//! Example demonstrating different turtle shapes
|
//! Example demonstrating different turtle shapes
|
||||||
|
|
||||||
use macroquad::prelude::*;
|
|
||||||
use turtle_lib_macroquad::*;
|
use turtle_lib_macroquad::*;
|
||||||
|
|
||||||
#[macroquad::main("Turtle Shapes")]
|
#[turtle_main("Turtle Shapes")]
|
||||||
async fn main() {
|
fn draw(turtle: &mut TurtlePlan) {
|
||||||
// Create a turtle plan that demonstrates different shapes
|
|
||||||
let mut plan = create_turtle();
|
|
||||||
|
|
||||||
// Start with triangle (default)
|
// Start with triangle (default)
|
||||||
plan.forward(100.0);
|
turtle.forward(100.0);
|
||||||
plan.right(90.0);
|
turtle.right(90.0);
|
||||||
|
|
||||||
// Change to turtle shape
|
// Change to turtle shape
|
||||||
plan.shape(ShapeType::Turtle);
|
turtle.shape(ShapeType::Turtle);
|
||||||
plan.forward(100.0);
|
turtle.forward(100.0);
|
||||||
plan.right(90.0);
|
turtle.right(90.0);
|
||||||
|
|
||||||
// Change to circle
|
// Change to circle
|
||||||
plan.shape(ShapeType::Circle);
|
turtle.shape(ShapeType::Circle);
|
||||||
plan.forward(100.0);
|
turtle.forward(100.0);
|
||||||
plan.right(90.0);
|
turtle.right(90.0);
|
||||||
|
|
||||||
// Change to square
|
// Change to square
|
||||||
plan.shape(ShapeType::Square);
|
turtle.shape(ShapeType::Square);
|
||||||
plan.forward(100.0);
|
turtle.forward(100.0);
|
||||||
plan.right(90.0);
|
turtle.right(90.0);
|
||||||
|
|
||||||
// Change to arrow
|
// Change to arrow
|
||||||
plan.shape(ShapeType::Arrow);
|
turtle.shape(ShapeType::Arrow);
|
||||||
plan.forward(100.0);
|
turtle.forward(100.0);
|
||||||
|
|
||||||
// Set animation speed
|
// Set animation speed
|
||||||
plan.set_speed(50);
|
turtle.set_speed(50);
|
||||||
|
|
||||||
// Create turtle app with animation (speed = 100 pixels/sec for slower animation)
|
|
||||||
let mut app = TurtleApp::new().with_commands(plan.build());
|
|
||||||
|
|
||||||
// Main loop
|
|
||||||
loop {
|
|
||||||
clear_background(WHITE);
|
|
||||||
|
|
||||||
// Update and render
|
|
||||||
app.update();
|
|
||||||
app.render();
|
|
||||||
|
|
||||||
next_frame().await
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,33 +1,16 @@
|
|||||||
//! Simple square example demonstrating basic turtle graphics
|
//! Simple square example demonstrating basic turtle graphics
|
||||||
|
|
||||||
use macroquad::prelude::*;
|
|
||||||
use turtle_lib_macroquad::*;
|
use turtle_lib_macroquad::*;
|
||||||
|
|
||||||
#[macroquad::main("Turtle Square")]
|
#[turtle_main("Turtle Square")]
|
||||||
async fn main() {
|
fn draw(turtle: &mut TurtlePlan) {
|
||||||
// Create a turtle plan
|
turtle.shape(ShapeType::Turtle);
|
||||||
let mut plan = create_turtle();
|
|
||||||
plan.shape(ShapeType::Turtle);
|
|
||||||
|
|
||||||
// Draw a square
|
// Draw a square
|
||||||
for _ in 0..4 {
|
for _ in 0..4 {
|
||||||
plan.forward(100.0).right(90.0);
|
turtle.forward(100.0).right(90.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set animation speed
|
// Set animation speed
|
||||||
plan.set_speed(50);
|
turtle.set_speed(50);
|
||||||
|
|
||||||
// Create turtle app with animation
|
|
||||||
let mut app = TurtleApp::new().with_commands(plan.build());
|
|
||||||
|
|
||||||
// Main loop
|
|
||||||
loop {
|
|
||||||
clear_background(WHITE);
|
|
||||||
|
|
||||||
// Update and render
|
|
||||||
app.update();
|
|
||||||
app.render();
|
|
||||||
|
|
||||||
next_frame().await
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,38 +1,21 @@
|
|||||||
//! Simple square example demonstrating basic turtle graphics
|
//! Star pattern example demonstrating complex turtle patterns
|
||||||
|
|
||||||
use macroquad::prelude::*;
|
|
||||||
use turtle_lib_macroquad::*;
|
use turtle_lib_macroquad::*;
|
||||||
|
|
||||||
#[macroquad::main("Turtle Square")]
|
#[turtle_main("Star Pattern")]
|
||||||
async fn main() {
|
fn draw(turtle: &mut TurtlePlan) {
|
||||||
// Create a turtle plan
|
turtle.shape(ShapeType::Turtle);
|
||||||
let mut plan = create_turtle();
|
turtle.set_speed(1500);
|
||||||
plan.shape(ShapeType::Turtle);
|
turtle.set_pen_width(0.5);
|
||||||
plan.set_speed(1500);
|
|
||||||
plan.set_pen_width(0.5);
|
|
||||||
|
|
||||||
// Draw a 5-pointed star pattern repeatedly
|
// Draw a 5-pointed star pattern repeatedly
|
||||||
for _i in 0..50000 {
|
for _i in 0..50000 {
|
||||||
plan.forward(200.0);
|
turtle.forward(200.0);
|
||||||
plan.circle_left(10.0, 72.0, 1000);
|
turtle.circle_left(10.0, 72.0, 1000);
|
||||||
plan.circle_right(5.0, 360.0, 1000);
|
turtle.circle_right(5.0, 360.0, 1000);
|
||||||
plan.circle_left(10.0, 72.0, 1000);
|
turtle.circle_left(10.0, 72.0, 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set animation speed
|
// Set animation speed
|
||||||
plan.set_speed(300);
|
turtle.set_speed(300);
|
||||||
|
|
||||||
// Create turtle app with animation (speed = 100 pixels/sec)
|
|
||||||
let mut app = TurtleApp::new().with_commands(plan.build());
|
|
||||||
|
|
||||||
// Main loop
|
|
||||||
loop {
|
|
||||||
clear_background(WHITE);
|
|
||||||
|
|
||||||
// Update and render
|
|
||||||
app.update();
|
|
||||||
app.render();
|
|
||||||
|
|
||||||
next_frame().await
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,47 +1,30 @@
|
|||||||
//! Simple square example demonstrating basic turtle graphics
|
//! Yin-Yang symbol example demonstrating multi-contour fills
|
||||||
|
|
||||||
use macroquad::prelude::*;
|
|
||||||
use turtle_lib_macroquad::*;
|
use turtle_lib_macroquad::*;
|
||||||
|
|
||||||
#[macroquad::main("Turtle Square")]
|
#[turtle_main("Yin-Yang")]
|
||||||
async fn main() {
|
fn draw(turtle: &mut TurtlePlan) {
|
||||||
// Create a turtle plan
|
turtle.set_speed(900);
|
||||||
let mut t = create_turtle();
|
|
||||||
t.set_speed(900);
|
|
||||||
|
|
||||||
t.circle_left(90.0, 180.0, 36);
|
turtle.circle_left(90.0, 180.0, 36);
|
||||||
t.begin_fill();
|
turtle.begin_fill();
|
||||||
t.circle_left(90.0, 180.0, 36);
|
turtle.circle_left(90.0, 180.0, 36);
|
||||||
t.circle_left(45.0, 180.0, 26);
|
turtle.circle_left(45.0, 180.0, 26);
|
||||||
t.circle_right(45.0, 180.0, 26);
|
turtle.circle_right(45.0, 180.0, 26);
|
||||||
t.pen_up();
|
turtle.pen_up();
|
||||||
t.right(90.0);
|
turtle.right(90.0);
|
||||||
t.forward(37.0);
|
turtle.forward(37.0);
|
||||||
t.left(90.0);
|
turtle.left(90.0);
|
||||||
t.pen_down();
|
turtle.pen_down();
|
||||||
t.circle_right(8.0, 360.0, 12);
|
turtle.circle_right(8.0, 360.0, 12);
|
||||||
t.pen_up();
|
turtle.pen_up();
|
||||||
t.right(90.0);
|
turtle.right(90.0);
|
||||||
t.forward(90.0);
|
turtle.forward(90.0);
|
||||||
t.left(90.0);
|
turtle.left(90.0);
|
||||||
t.pen_down();
|
turtle.pen_down();
|
||||||
t.circle_right(8.0, 360.0, 12);
|
turtle.circle_right(8.0, 360.0, 12);
|
||||||
t.end_fill();
|
turtle.end_fill();
|
||||||
|
|
||||||
// Set animation speed
|
// Set animation speed
|
||||||
t.set_speed(1000);
|
turtle.set_speed(1000);
|
||||||
|
|
||||||
// Create turtle app with animation (speed = 100 pixels/sec)
|
|
||||||
let mut app = TurtleApp::new().with_commands(t.build());
|
|
||||||
|
|
||||||
// Main loop
|
|
||||||
loop {
|
|
||||||
clear_background(WHITE);
|
|
||||||
|
|
||||||
// Update and render
|
|
||||||
app.update();
|
|
||||||
app.render();
|
|
||||||
|
|
||||||
next_frame().await
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,7 +3,29 @@
|
|||||||
//! This library provides a turtle graphics API for creating drawings and animations
|
//! This library provides a turtle graphics API for creating drawings and animations
|
||||||
//! using the Macroquad game framework.
|
//! using the Macroquad game framework.
|
||||||
//!
|
//!
|
||||||
//! # Example
|
//! # Quick Start with `turtle_main` Macro
|
||||||
|
//!
|
||||||
|
//! The easiest way to create a turtle program is using the `turtle_main` macro:
|
||||||
|
//!
|
||||||
|
//! ```no_run
|
||||||
|
//! use macroquad::prelude::*;
|
||||||
|
//! use turtle_lib_macroquad::*;
|
||||||
|
//!
|
||||||
|
//! #[turtle_main("My Drawing")]
|
||||||
|
//! fn draw(turtle: &mut TurtlePlan) {
|
||||||
|
//! turtle.set_pen_color(RED);
|
||||||
|
//! turtle.forward(100.0);
|
||||||
|
//! turtle.right(90.0);
|
||||||
|
//! turtle.forward(100.0);
|
||||||
|
//! }
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! The macro automatically handles window setup, rendering loop, and quit handling.
|
||||||
|
//!
|
||||||
|
//! # Manual Setup Example
|
||||||
|
//!
|
||||||
|
//! For more control, you can set up the application manually:
|
||||||
|
//!
|
||||||
//! ```no_run
|
//! ```no_run
|
||||||
//! use macroquad::prelude::*;
|
//! use macroquad::prelude::*;
|
||||||
//! use turtle_lib_macroquad::*;
|
//! use turtle_lib_macroquad::*;
|
||||||
@ -43,6 +65,14 @@ pub use shapes::{ShapeType, TurtleShape};
|
|||||||
pub use state::{DrawCommand, TurtleState, TurtleWorld};
|
pub use state::{DrawCommand, TurtleState, TurtleWorld};
|
||||||
pub use tweening::TweenController;
|
pub use tweening::TweenController;
|
||||||
|
|
||||||
|
// Re-export the turtle_main macro
|
||||||
|
pub use turtle_lib_macroquad_macros::turtle_main;
|
||||||
|
|
||||||
|
// Re-export common macroquad types and colors for convenience
|
||||||
|
pub use macroquad::prelude::{
|
||||||
|
vec2, BLACK, BLUE, DARKGRAY, GOLD, GREEN, ORANGE, PURPLE, RED, WHITE, YELLOW,
|
||||||
|
};
|
||||||
|
|
||||||
use macroquad::prelude::*;
|
use macroquad::prelude::*;
|
||||||
|
|
||||||
/// Main turtle application struct
|
/// Main turtle application struct
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user