{"id":20669998,"url":"https://github.com/noxalus/bulletlua","last_synced_at":"2026-04-21T00:04:25.339Z","repository":{"id":36411080,"uuid":"40716022","full_name":"Noxalus/BulletLua","owner":"Noxalus","description":"Lua scripting for shmup barrage patterns","archived":false,"fork":false,"pushed_at":"2015-05-13T03:04:26.000Z","size":29556,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-01-17T13:33:13.196Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Noxalus.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-08-14T13:22:15.000Z","updated_at":"2023-11-20T08:10:14.000Z","dependencies_parsed_at":"2022-09-04T03:50:34.172Z","dependency_job_id":null,"html_url":"https://github.com/Noxalus/BulletLua","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Noxalus%2FBulletLua","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Noxalus%2FBulletLua/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Noxalus%2FBulletLua/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Noxalus%2FBulletLua/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Noxalus","download_url":"https://codeload.github.com/Noxalus/BulletLua/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":242886576,"owners_count":20201595,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-16T20:17:23.574Z","updated_at":"2026-04-21T00:04:25.310Z","avatar_url":"https://github.com/Noxalus.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"BulletLua [![Build Status](https://travis-ci.org/sanford1/BulletLua.svg?branch=master)](https://travis-ci.org/sanford1/BulletLua)\n=========\n\n### Superceded by [Barrage](https://github.com/sanford1/Barrage)\n\n\nThis C++ project aims to create a sane scriptable interface to define bullet patterns in shoot 'em up games. These patterns, while difficult to dodge in game and hard to appreciate while in the heat of the moment, can be beautiful to spectate.\n\nBullet Barrage Examples:\n\n[Example 1](http://youtu.be/yCOYrMgnNGE?t=11m39s)\n\n[Example 2](http://youtu.be/v4m08AeGFWU?t=33m22s)\n\nBulletLua is not quite mature enough at the moment to recreate the complex patterns in the videos above, but it's getting there.\n\n\n![test.lua](http://zippy.gfycat.com/PeriodicUnnaturalHartebeest.gif)\n\n![test2.lua](http://giant.gfycat.com/AmbitiousSpecificAracari.gif)\n\n![test3.lua](http://giant.gfycat.com/BelatedFakeBoilweevil.gif)\n\n\nUsage\n=========\nThis project depends on [Lua](http://www.lua.org/), so make sure your compiler can find the correct Lua files (static library, header files, etc).\n\nFor ease of use, [sol](https://github.com/Rapptz/sol.git) is used as a modern C++ binding to Lua. Remember to\n\n    git submodule update --init --recursive\n\nafter you clone this repository!\n\nBoth sol and BulletLua use C++11 features, so make sure you have a C++11-capable compiler.\n\nTo build the static library and unit tests, run\n\n    python bootstrap.py \u0026\u0026 ninja\n\nLink the library generated in the lib directory and make sure the headers in the `bulletlua` directory can be found by your project, and you're already halfway there. An alternative would be to just directly add the source code to your project, although I wouldn't recommend that.\n\nBecause there are so many use cases out there, BulletLua doesn't actually draw any sprites. It simply runs lua scripts, manages the generated bullets, and provides a simple method for collision detection. As such, you'll need to produce your own code to draw the bullets. This can be as simple as creating a class to inherit from BulletLuaManager and creating a draw method. Example:\n\n    class BulletManager : public BulletLuaManager\n    {\n        public:\n            void draw()\n            {\n                for (Bullet* b : bullets)\n                {\n                    drawPoint(b-\u003ex, b-\u003ey);\n                }\n            }\n    };\n\nThen to run a script...\n\n    // Create a bullet manager that governs a 640x480 rectangle.\n    BulletManager manager{0, 0, 640, 480};\n\n    Bullet origin(x, y, vx, vy);\n    Bullet target(x, y, vx, vy);\n\n    // Fire a bullet that runs MyFile.lua from origin at target.\n    manager.createBullet(\"MyFile.lua\", \u0026origin, \u0026target);\n\n    // Game Loop\n    while (running)\n    {\n        manager.tick();\n        manager.draw();\n    }\n\nA moderately complex example (using [SDL2](http://libsdl.org/) and OpenGL) can be found in the `example` directory. To build it easily, use the [ninja](https://martine.github.io/ninja/) script. The source code for the older example that uses [SFML](http://www.sfml-dev.org/) still exists in the `example` directory as well.\n\nLua Binding\n=========\n\nC++ Functions visible in BulletLua scripts:\n\n    -- Do nothing.\n    nullfunc()\n\n    -- Get Position (as a tuple).\n    x, y = getPosition()\n\n    -- Get Target Position\n    tx, ty = getTargetPosition()\n\n    -- Get Velocity Components (as a tuple).\n    vx, vy = getVelocity()\n\n    -- Get Bullet Speed and Direction.\n    getSpeed()\n    getDirection()\n\n    getLife()\n\n    -- Get the amount of frames since this bullet's creation.\n    getTurn()\n\n    -- Reset this bullet's frame counter\n    resetTurns()\n\n    -- Get the current barrage \"difficulty\", From [0.0, 1.0]\n    getRank()\n\n    -- Generate random floating point numbers\n    randFloat()\n    randFloatRange(float min, float max)\n\n    -- Generate random integers\n    randInt(int max)\n    randIntRange(int min, int max)\n\n    -- Set Bullet Position.\n    setPosition(float x, float y)\n\n    -- Set Bullet Velocity.\n    setVelocity(float vx, float vy)\n\n    -- Set Bullet Direction\n    setDirection(double dir)\n\n    -- Set Bullet Direction (relatively), adds to current direction.\n    setDirectionRelative(double dir)\n\n    -- Set the current bullet to aim at the \"player\"\n    aimTarget()\n\n    -- Set the current bullet to aim at a point\n    aimPoint(float x, float y)\n\n    -- Set Speed\n    setSpeed(float s)\n    setSpeedRelative(float s)\n\n    -- Set speed and direction of bullet such that it will reach (x, y) in 'n' steps.\n    linearInterpolate(float x, float y, unsigned int n)\n\n    -- Switch current running function. This also resets the bullet's frame counter.\n    setFunction(const sol::function\u0026 funcName)\n\n    -- Shoot a bullet from current bullet moving in direction (d) at\n    -- speed (s) running function (func). fire(double d, double s, const\n    sol::function\u0026 funcName)\n\n    -- Shoot a bullet and aim it at the \"player\"\n    fireAtTarget(float s, const sol::function\u0026 funcName)\n\n    -- Shoot (segments) bullets in a circle at speed (s) running function (func).\n    fireCircle(int segments, float s, const sol::function\u0026 funcName)\n\n    -- Get/Set current bullet color. Each component ranges from [0, 255]\n    setColor(int r, int g, int b)\n    r, g, b = getColor()\n\n    -- Fade out the current bullet. Kill it slowly.\n    vanish()\n\n    -- Immediately destroy the bullet.\n    kill()\n\nAn example BulletLua script can be found in `example/bin/script/test.lua`. More examples to come.\n\nExamples\n=========\n\nThis script should produce something similar to the first gif above:\n\n    -- BulletLua Test Script\n\n    dir = 0\n\n    function main()\n        local turn = getTurn()\n        local rank = getRank()\n\n        if (math.fmod(turn, 15) == 0) then\n            fire(dir, 1.5, explode)\n            dir = dir + 34\n        end\n    end\n\n    function explode()\n        local turn = getTurn()\n        if (turn == 60) then\n            fireCircle(40, 4.0, homeIn)\n\n            kill()\n        end\n    end\n\n    function homeIn()\n        local turn = getTurn()\n        if (turn == 20) then\n            setSpeed(1)\n        elseif (turn == 25) then\n            aimTarget()\n            setSpeed(10)\n        elseif (turn == 50) then\n            vanish()\n        end\n    end\n\nRight now, BulletLua associates a bullet with a function and runs that function every frame. However, since it's difficult to dynamically save arbitrary function arguments in a single container, when you set a bullet to run a function, that function cannot have parameters. A way to bypass this is by using a `bind` function. `bind` will create a wrapper function for an existing function and forward an argument to it. So effectively, you can transform any function with parameters into a (new) function with no parameters. This example (`example/bin/script/test5.lua`) should show a simple use of `bind`.\n\n![test5.lua](http://giant.gfycat.com/IncompatibleBruisedIbisbill.gif)\n\n    -- BulletLua Test Script 5\n\n    cycles = 0\n    gwait = 20\n\n    function bind(f,...)\n       local args = {...}\n       return function(...)\n          return f(unpack(args),...)\n       end\n    end\n\n    function main()\n       circle = bind(fireCircle, 40)\n       setPosition(320, 240)\n       setFunction(bind(go, 10))\n    end\n\n    function go(wait)\n       local turn = getTurn()\n       if (math.fmod(turn, wait) == 0) then\n          -- speeds = {4, 5, 6}\n          circle(21 - gwait, curve)\n\n          setFunction(bind(go, gwait))\n          gwait = gwait - 1\n          if gwait \u003c 18 then\n             gwait = 20\n          end\n\n          cycles = cycles + 1\n       end\n       if (cycles == 15) then\n          vanish()\n       end\n    end\n\n    function curve()\n       local turn = getTurn()\n       setDirectionRelative(5)\n       setSpeedRelative(0.1)\n\n       if (turn \u003e 180) then\n          vanish()\n       end\n    end\n\nA second, perhaps more useful, example of `bind` can be found in `example/bin/script/test6.lua`\n\nFuture Plans\n=========\n\n* Smooth out the C++ interface and then introduce a mechanism to convert BulletLua scripts to C++.\n* Be able to desribe collision detection area.\n* More robust collision detection.\n* Be able to agnostically define different types of bullets.\n* Design a new method to manage the initial \"bullets\" (i.e. the \"origin\" bullet and the player \"target\"))\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnoxalus%2Fbulletlua","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnoxalus%2Fbulletlua","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnoxalus%2Fbulletlua/lists"}