Giter Site home page Giter Site logo

sunjay / autogamer Goto Github PK

View Code? Open in Web Editor NEW
2.0 2.0 1.0 3.98 MB

(Work in progress) An opinionated, convention over configuration game creation framework designed for use with the Tiled editor and the Python programming language

License: Mozilla Public License 2.0

Python 4.04% Rust 95.96%

autogamer's Introduction

Hi! I'm Sunjay. 👋

sunjay varma

I'm a Rust programmer, compiler developer, and systems programmer who loves making games in my spare time. I teach people programming and game development at tech conferences and love creating resources to make hard technical topics accessible to a wider audience.

Follow me on Twitter: @sunjay03 🐦
Pronouns: he/him

autogamer's People

Contributors

sunjay avatar

Stargazers

 avatar  avatar

Watchers

 avatar

Forkers

icodein

autogamer's Issues

Any plans to support other languages?

I love the idea of a Rust framework with a scripting language already plugged in! 🤩

Have you considered supporting any language implementations besides PyO3?

There’s also RustPython. It might be easier to use for cases like in-game scripting. See for instance: https://www.reddit.com/r/rust/comments/hgtuu5/announcement_wasiprocess_run_wasi_modules_as/

It’s been done before in pyckitup by the RustPython contributors @0b01 and @coolreader18

rlua has some reference implementations out there:
https://github.com/Grokmoo/sulis
https://github.com/redcodestudios/rust-scripting-example

Maker of hyperspeed @InquisitivePenguin might also have some know-how to share here?

Lastly, there’s Mun. It can’t do a whole lot yet, but that should hopefully reduce the scope of the integration work.

GUI Framework MVP

For the timebeing, all I want is the bare minimum to be able to have:

  1. A main menu - with text for the game title and buttons to start or quit
  2. A pause menu
  3. HUD - images for the player's remaining health, text that dynamically updates with the player's score or coins, a button to pause, etc.

With that in mind, we'll need support for:

  • images
  • text
  • rectangles + borders (basic box model box-sizing: border-box)
  • buttons
  • absolute positioning + anchor based alignment
  • [optional?] vertical/horizontal layout (flexbox) - https://github.com/vislyhq/stretch

I haven't had time to properly sit down and think about this or plan anything out. I'll need to do that before this work actually begins so we know we're moving in the right direction.

Querying interface over tiled files

The Python API should provide a full querying interface for tiled files via TileMap class. That includes the ability to:

  • get properties of the map like tile_width, tile_height, etc.
    • this includes custom properties
  • get layers by their name
    # Get the layer whose "name" property is "background_items"
    map.layer(name="background_items")
  • get properties of layers
  • get objects from object layers
    # Get the first object in the given layer whose "name" property is "boss_area"
    map.layer(name="game_objects").object(name="boss_area")
    # Get all the objects in the given layer whose "type" property is "boss_movement_zone"
    map.layer(name="game_objects").objects(type="boss_movement_zone")
    #TODO: Allow querying by any property - e.g. "id", "x", "y", "width", "height", etc.
    #TODO: Also support glob patterns like `.objects(name="foo*")`
  • get properties of objects
  • get tiles from tile layers
    # Get the tile at the given row and column (zero-indexed)
    map.layer(name="background_items").tile_at(row=2, col=3)
  • get properties of tiles
  • etc.

Right now, these APIs are being added on an as-needed basis, but it would be nice to complete the API with all the different kinds of properties.

Properly Implement Tile Flipping + Alignment

Our current implementation of tile flipping (5348580) is quite hacky and doesn't actually match Tiled in all cases. It works well enough if tiles are square (and symmetrical), but falls over otherwise.

tile flipping examples

In this screenshot of Tiled, you can see 4 tile objects (on the game_objects layer) on the left rotated 0°, 90°, 180°, and 270°. On the right there are 8 tiles (on the map layer) with various rotations and flips applied. Tile objects rotate about their center (determined by their alignment and defaulting to the bottom-left) whereas tiles are rotated and then aligned to the bottom-left.

tile flipping examples

In this screenshot, you can see that rotation of tile objects is currently completely broken. The other three tile objects are somewhere else (haven't debugged that yet). The tiles are misaligned because we use the unrotated version of the tile to compute alignment.

We're currently using a pivot field in the Sprite component to try and make this work. That field doesn't actually do what it advertises and should either be fixed or replaced once we figure out what the right solution is here.

The ideal computation pipeline for this is:

  1. perform horizontal and vertical flips (if any)
  2. perform rotation
  3. align the image to the right spot

This is difficult to implement for a number of reasons:

  • To properly implement diagonal flipping, you need to rotate first, but that breaks with the arbitrary rotations that are allowed for tile objects
  • SDL2 always performs flipping first and then rotates, but that makes alignment hard because you need to know the final position in advance somehow
  • To align the image, you need to compute the result of the rotation on the destination rectangle -- this duplicates work that SDL2 will do when rotating and may end up with bugs
  • You can't just cache the rotated image and figure out the position later because you need the rotation info to figure out where to render the image (i.e. you must pass an angle parameter to copy_ex, you can't get around that)
    • e.g. a 30° counterclockwise rotation is hard to align because the resulting shape isn't an axis-aligned shape (indicates that alignment occurs before rotation)

References & Notes

  • <object> - see description of rotation property
  • From Tile flipping:

    When rendering a tile, the order of operation matters. The diagonal flip (x/y axis swap) is done first, followed by the horizontal and vertical flips.

  • "Implementing Tiled Map Editor(TMX) Rotation and Flipping" - (Source Code)
    • Some subtle bugs here because the post doesn't account for tiles larger than the tile size and therefore doesn't account for alignment
  • GitHub issue comment about implementing this
  • SDL_RenderCopyEx
    • angle is clockwise, not counterclockwise as in math
    • center is relative to the top-left of the destination rectangle
    • It's possible that we may have to adjust the destination rectangle based on the rotation unless we can figure out a universal way to compute the center
  • Question: Do we need to use the rotation in determining the collision geometry? How does that work?

Next Steps

A to-do list to help me keep track of what I was planning on working on next.

This is not an exhaustive list and mostly consists of things I'm planning to work on in the near future. Far future things are included near the end of the list in less detail. I will keep adding to this over time.

  • figure out why player falls so slowly even though we setup earth gravity (changing mass and density doesn't seem to affect this?? Solution: I realized that it's because the unit is pixels so gravity was set to 9.81 pixels per second per second. The value needs to be much higher)
  • add a sensor and/or use collision events to detect when the player is touching the ground
    • Potential design:
    /// Uses collision events to determine which entities are touching this
    /// entity.
    ///
    /// For this to work, the entity must have a Position and PhysicsCollider
    /// component.
    #[derive(Component, Debug, Clone, PartialEq)]
    #[storage(HashMapStorage)]
    pub struct TouchSensor {
        /// The entities touching the top of the entity with this component
        pub touching_top: Vec<Entity>,
        /// The entities touching the bottom of the entity with this component
        pub touching_bottom: Vec<Entity>,
        /// The entities touching the left of the entity with this component
        pub touching_left: Vec<Entity>,
        /// The entities touching the right of the entity with this component
        pub touching_right: Vec<Entity>,
    }
  • Improve detection for which side an entity is on using the intersection (partial work in b858ae0)
    • Needed because with arbitrary bounding boxes it is hard to just use the center of each box to detect which side you're on. After all, the boxes are not guaranteed to be aligned along one axis
    • another idea: check if merging the two bounding boxes and using the center of that helps at all
    • if implemented incorrectly, you'll end up with a case where touching something on the side (e.g. a wall) allows you to jump again (make sure the thing you're treating as the ground is actually below you)
  • implement jumping (player can jump only when they are touching the ground)
  • Add a debug flag for rendering the collision geometry in the physics engine
  • Collision geometry positions are not being resolved properly: needs to be resolved relative to the top-left corner of the tile, regardless of alignment setting
  • choose a single convention for alignment and get rid of the concept altogether
    • e.g. if you choose that the position represents the center of the bounding box, you need to adjust all loaded tiles so they end up in the right positions
    • question: can we get rid of alignment and implement rotation properly?
  • Figure out how to implement ladders
    • Probably want to add some keys to the PlatformerControls component

      Details
        diff --git a/src/components.rs b/src/components.rs
        index a123d39..dfef5c8 100644
        --- a/src/components.rs
        +++ b/src/components.rs
        @@ -356,6 +356,10 @@ pub struct PlatformerControls {
             pub right_key: Key,
             /// The key used to make the entity initiate a jump (default: spacebar)
             pub jump_key: Key,
        +    /// The key used to make the entity climb upwards (default: up arrow key)
        +    pub climb_up_key: Key,
        +    /// The key used to make the entity climb downwards (default: down arrow key)
        +    pub climb_down_key: Key,
         
             /// The velocity applied on the x-axis when the left or right arrow keys are
             /// pressed. The value will be negated for the left arrow key to allow it to
        @@ -384,6 +388,8 @@ impl Default for PlatformerControls {
                     left_key: Key::Left,
                     right_key: Key::Right,
                     jump_key: Key::Space,
        +            climb_up_key: Key::Up,
        +            climb_down_key: Key::Down,
                     horizontal_velocity: 0.0,
                     jump_velocity: 0.0,
                     midair_horizontal_multiplier: 1.0,
        diff --git a/src/systems/keyboard.rs b/src/systems/keyboard.rs
        index e0c5ee0..d04ca19 100644
        --- a/src/systems/keyboard.rs
        +++ b/src/systems/keyboard.rs
        @@ -75,6 +75,8 @@ impl<'a> System<'a> for Keyboard {
                         left_key,
                         right_key,
                         jump_key,
        +                climb_up_key,
        +                climb_down_key,
                         horizontal_velocity,
                         jump_velocity,
                         midair_horizontal_multiplier,
    • Probably want to track a climbing state so animations can be performed

    • Probably want to disable gravity on the physics body and maybe turn the associated collider into a sensor so you can have ladders passing through platforms

  • start implementing various component templates for things like keys, obstacles, etc.
  • figure out how the MVP GUI framework is going to work and try to implement a HUD using it

Setup CI

  • setup Azure DevOps pipeline with Windows, Mac OS, and Linux build + testing
  • generate and upload a zip of the pyautogamer package for both dev and release builds
    • pyautogamer_x86_64-pc-windows-msvc_dev.zip
    • pyautogamer_x86_64-pc-windows-msvc.zip
  • make sure generated zip can be imported in Python (test in VM)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.