{"id":13528677,"url":"https://github.com/babaganosch/GameMakerScaffolding","last_synced_at":"2025-04-01T14:32:46.726Z","repository":{"id":107371720,"uuid":"609350222","full_name":"babaganosch/GameMakerScaffolding","owner":"babaganosch","description":"Template for GMS 2.3","archived":false,"fork":false,"pushed_at":"2023-12-28T20:28:39.000Z","size":5749,"stargazers_count":10,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-11-02T15:35:41.160Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Yacc","has_issues":true,"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/babaganosch.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,"governance":null,"roadmap":null,"authors":null}},"created_at":"2023-03-03T23:32:59.000Z","updated_at":"2024-07-03T10:28:22.000Z","dependencies_parsed_at":"2024-01-03T04:07:36.288Z","dependency_job_id":"b843fec7-77dc-4da6-83a5-a7976fa83789","html_url":"https://github.com/babaganosch/GameMakerScaffolding","commit_stats":null,"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/babaganosch%2FGameMakerScaffolding","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/babaganosch%2FGameMakerScaffolding/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/babaganosch%2FGameMakerScaffolding/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/babaganosch%2FGameMakerScaffolding/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/babaganosch","download_url":"https://codeload.github.com/babaganosch/GameMakerScaffolding/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246655212,"owners_count":20812599,"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-08-01T07:00:22.650Z","updated_at":"2025-04-01T14:32:43.829Z","avatar_url":"https://github.com/babaganosch.png","language":"Yacc","readme":"\u003ch1 align=\"center\"\u003eGMS 2.3+ GameMaker Scaffolding | v1.2.0\u003c/h1\u003e\n\u003cp align=\"center\"\u003e\u003ca href=\"https://larsandersson.info\"\u003elarsandersson.info\u003c/a\u003e\u003c/p\u003e\n\u003cp align=\"center\"\u003eX: \u003ca href=\"https://twitter.com/Babaganosch\"\u003e@babaganosch\u003c/a\u003e\u003c/p\u003e\n\u003cp align=\"center\"\u003eDownload: \u003ca href=\"https://github.com/babaganosch/GameMakerScaffolding/releases/latest\"\u003elatest\u003c/a\u003e\u003c/p\u003e\n\n---\n\n**GameMaker Scaffolding** is a template project for GameMaker Studio 2.3, focusing on 2D low-res tile-based games. The reason for this template is to facilitate new projects for me, and possibly others, as I grew tierd of simply copy-pasting basic stuff from prior projects each time I wanted to test something new.\n\nSetup is easy. Just download the template .yyz file and create a new project by executing it.\n\n## Feature list\n* [__Rendering system__](#rendering) - double buffered rendering for post-fx, and shader programs as structs.\n* [__Notification system__](#notificationsystem) - a signal framework for easy observer pattern implementation, and a great way to decouple objects and make the game logic more event driven.\n* [__Timing module__](#timing-module) - enabling easy implementations of delta time, profiling and an alarm system based on real time instead of frames.\n* [__ParticleSystem wrapper__](#particlesystems) - for easy particle system setup and allowing particles to update based on delta time.\n* [__Lighting system__](#lighting) - lightweight 2D light engine with vivid lights based on sprites or shapes of any size.\n* [__Terminal module__](#terminal) - a lightweight debugging console for easy input/output during runtime, with easy to setup commands.\n* [__World module__](#world-module) - worlds, or levels, described as structs with tilemaps and fast collision checking.\n* [__GameObjects__ and __LiteGameObjects__](#gameobjects) - the ability to create and differentiate between real GameMaker objects and lightweight objects based on structs, all handled by a game controller.\n* [__GameController module__](#game-controller) - controls object culling, sorting and overall behaviour of the game. GameController events are split up between a couple frames, to even out the workload and improve performance.\n\n---\n# Features\n\n## Rendering\nInstead of directly rendering the application surface to the screen, the application surface is scaled down to fit the style of low-res type of games and is at the end of the draw-pass rendered to a double buffer. This double buffer can then be utilized for easy post-fx drawing by just rendering ping-pong style between the two buffers. Finally, when all post-fx is rendered, the surface will be rendered upscaled to the screen. It is also possible to render this stage through a shader as well, for high-res post-fx.\n\nA camera is included in the rendering system and easily controllable, and expandable after demand of the user.\n\nShader programs are saved as structs, containing easy utilization and access to uniforms and samplers.\n\n## NotificationSystem\nThis is a lightweight signal framework and a great way to decouple objects, and making the game logic more event driven. [Link to original repo.](https://github.com/babaganosch/NotificationSystem) This is an old project of mine, but still very relevant.\n\nFollowing is some example usage.\n```gml\n// Create event for an object which wants to listen to the notification bus.\nsubscribe();\nreceiver = new Receiver();\n\nreceiver.add(\"Monster killed\", function() {\n    increase_score();\n});\n```\n```gml\n// Destroy event for a monster\nbroadcast(\"Monster killed\");\n```\nThe messages do not have to be strings. Enums or numbers work as well, and are preferred performance wise.\n```gml\nenum MESSAGES {\n    MONSTER_KILLED,\n    GAME_OVER,\n    PLAYER_JUMP,\n    ...\n};\n\nreceiver.add(MESSAGES.MONSTER_KILLED, function(score) {\n    increase_score(score);\n});\n\nbroadcast(MESSAGES.MONSTER_KILLED, 10);\n```\n\n## Timing module\nKeeps tracks of gamespeed, delta time and timers. When working with delta time, the regular GameMaker-Alarms can be a troublesome as they are dependent on frame count and not real time. GameMaker has support for real-time timers with timesources, although I personally find them bulky and inconvenient. Especially when you need to pause some timers due to game being in a paused state.\n\nExample usage:\n```gml\n/// Create event of something\n\n// Create a local timer contained within the object.\ntimer = new AlarmSystem();\n\n// This will print \"Hello World!\" every 200 milliseconds, periodically and contained within the object. Destroyed when manually aborted or object is destroyed.\ntimer.add(milliseconds(200), function() {\n    print(\"Hello World!\");\n}, true);\n\n// This will print \"Hello World!\" every 200 milliseconds, once and even though the object disappear.\ngame_alarms.add(milliseconds(200), function() {\n    print(\"Hello World!\");\n}, false);\n\n// This will print \"Hello World!\" every 200 milliseconds, periodically even though the object disappear.\n// This timer will also tick even though the game is in a paused state and gamespeed is tuned to 0 fps (great for system controllers).\nsys_alarms.add(milliseconds(200), function() {\n    print(\"Hello World!\");\n}, true);\n```\n\n## ParticleSystems\nA simple wrapper and controller for particle systems. This makes it easy to control, enable and disable particle systems when not needed. For example when object is culled due to outside the view. These particle systems also update based on delta time instead of directly bound to the frame update speed.\n\nExample usage:\n```gml\n/// Adding a new type of particle to the system in the particle controller\nparticle_controller.add_particle(init_particle(PARTICLES.BLUE_FLAMES));\n```\n\n```gml\n/// Another object who sets up a particle system and creates some crisp blue flames\nps = new ParticleSystem();\nflames = load_particle(PARTICLES.BLUE_FLAMES);\n\n// Spawns 10 blue flames at pos 150,150\nps.spawn_particle(150, 150, flames, 10);\n\n// Create an emitter and continuously spawn 10 flames\nemitter = ps.create_emitter(0, 0, 20, 20, ps_shape_rectangle, ps_distr_linear);\nemitter.set_stream(flames, 10);\n```\n\n## Lighting\nGameMaker Scaffolding includes a lightweight 2D lighting system. [Link to original repo.](https://github.com/babaganosch/LightingSystem2D) This is an old project of mine, a remake of the lighting system \u003ca href=\"https://github.com/niksudan/prettylight\"\u003eprettylight\u003c/a\u003e made by \u003ca href=\"https://github.com/niksudan\"\u003e@niksudan\u003c/a\u003e.\n\nIf needed, one can construct a light sprite of any size runtime with `ConstructLightSprite()`. ___(If used, this should always be done once at bootup and not during gameplay)___. This is good for experimentation, but preferably, the sprites should not be created runtime. The sprites can be of any shape or size. For device compatibility however, try to keep the dimensions square and the sizes in a power of two. For example, 16x16, 32x32..\n\n```gml\nspr_light = ConstructLightSprite(128);\n```\n\n```gml\nlight = new LightSource( spr_light, {\n  color: c_orange,\n  alpha: 0.7,\n  flicker: {\n    amplitude: 0.05,\n    speed: 0.02\n  }\n});\n```\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/babaganosch/open_storage/master/lights_0.png\"\u003e\n\u003c/p\u003e\n\n## Terminal\nI've included a terminal for easy debugging. This is a great way to run commands runtime like spawning instances, changing variables or changing states of the game.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/babaganosch/open_storage/master/terminal_0.gif\"\u003e\n\u003c/p\u003e\n\n## World Module\nLevels, or Worlds, are expressed as 2D grids contained within structs. Each cell of the grid contains some data expressing the cell, for example if it's a wall or a floor tile. For simplicity sake, the information is expressed per data-bit. On top of that, a solid cell (wall or void), is an even number as opposed to an open cell (floor or whatever) which is expressed as an uneven number. This makes collision checking simple, and the data does not take up a lot of unnecessary storage. For example, a cell could look like this:\n`CELL_DATA : 100101`, where the lowest bit shows it's a floor tile, and bit 3 and 6 indicates there's something else on the tile as well. Perhaps a chest or a door?\n\nEach level contains a list of active and deactivated instances, and is stored when moving on to a new level if needed.\n\nExample usage of setting up levels:\n\n```gml\nfunction Shop(tileset, w, h) : World(tileset, w, h) constructor\n{ ... } // Stuff relevant for a shop\n\nfunction OverWorld(tileset, w, h) : World(tileset, w, h) constructor\n{ ... } // Stuff relevant for an over world\n\nenum AREA\n{\n    OVER_WORLD,\n    SHOP\n};\n\nlevel[AREA.OVER_WORLD] = new OverWorld(theme_tileset, 100, 100);\nlevel[AREA.SHOP] = new Shop(theme_tileset, 100, 100);\n\nlevel[AREA.OVER_WORLD].set_area(4, 4, 30, 30,   CELL_DATA.FLOOR);\nlevel[AREA.OVER_WORLD].set_area(8, 4, 12, 8,    CELL_DATA.WALL);\n...\nlevel[AREA.OVER_WORLD].render();\n\nlevel[AREA.SHOP].set_area(5, 5, 37, 37, CELL_DATA.FLOOR);\nlevel[AREA.SHOP].set_area(24, 24, 26, 26, CELL_DATA.WALL);\n...\nlevel[AREA.SHOP].render();\n\nCURRENT_LEVEL = AREA.OVER_WORLD;\nCURRENT_LEVEL.activate();\n\n...\n\n// Moving on to the shop area\nCURRENT_LEVEL.deactivate();\nCURRENT_LEVEL = AREA.SHOP;\nCURRENT_LEVEL.activate();\n```\n\n## GameObjects\nAll non-system game objects should inherit the parent GameObject class, or any ancestor to that. This will enable the object to update and render only when not outside view, and be controlled by the Game Controller instance. The ancestor Entity of GameObject contains some basic physics, and is will perform collision checks against the current world.\n\nAs stated above, GameObjects gets culled and deactivated when outside the camera view, and then re-activated again when back inside the view.\n\nIt is also possible to create sub-classes of the LiteGameObject struct. These objects are only structs and more lightweight for the engine to handle. This is a good choice when needing a great amount of objects of something with simple logic. For example, bullets, effects, bugs, whatever. LiteGameObjects are also culled by the Game Controller.\n\n```gml\nfunction Bullet(x, y, hspd, vspd) : LiteGameObject(x, y, spr_bullet) constructor\n{\n    static update = function(delta)\n    {\n        x += hspd * delta; y += vspd * delta;\n        if (x \u003c 0 || x \u003e room_width || y \u003c 0 || y \u003e room_height)\n        {\n            destroy();\n        }\n    }\n}\n\nfunction SmokeEffect(x, y) : AnimatedLiteGameObject(x, y, spr_smoke) constructor\n{\n    static update = function(delta)\n    {\n        var last_frame = image_index;\n        animate(delta);\n        alpha -= 0.1 * delta;\n        if (image_index \u003c last_frame)\n        {\n            destroy();\n        }\n    }\n}\n```\n\n## Game Controller\nThis system object currently controls the culling and sorting of game objects. The behaviour of the Game Controller is split up between some couple of frames, to even out the load and improve performance. All GameController events is put into UserEvents of the GameController, and expressed as an enum value. It is of course possible to run more then one event per frame, but the important task is balance. You do not want to utilize high percentage of the CPU on one frame, and then 0% on the next frame.\n\nThe following example will run GameObject culling on first frame. Sorting the draw order of the objects in the second frame. Culling of the LiteGameObjects in the third frame and finally sorting the draw order of the GameObjects and updating something important on the fourth frame. And then repeat.\n\n```gml\nenum GC_EVENT {\n    OBJECT_CULLING = 0,\n    OBJECT_SORTING = 1,\n    LITE_OBJECT_CULLING = 2,\n    UPDATE_SOMETHING_IMPORTANT = 3\n}\n\nframe_events[0] = [ GC_EVENT.OBJECT_CULLING ];\nframe_events[1] = [ GC_EVENT.OBJECT_SORTING ];\nframe_events[2] = [ GC_EVENT.LITE_OBJECT_CULLING ];\nframe_events[3] = [ GC_EVENT.OBJECT_SORTING, GC_EVENT.UPDATE_SOMETHING_IMPORTANT ];\n```\n\nAnother thing that the Game Controller does is handle the rendering of all the GameObjects. The rendering order is based on the y value of the GameObject. But instead of being drawn on different layers, as with the usual `depth = -y;`, every object is rendered in the same layer and no overhead of creating new layers per y-value is required.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/babaganosch/open_storage/master/culling_0.gif\"\u003e\n\u003c/p\u003e\n\n# Changelog\n**v1.2.0**\n* Fixed most Feather errors, warnings and suggestions\n\n**v1.1.3**\n* Object draw-sorting is now done through a shader\n\n**v1.0.2**\n* Changed modulus to bitwise operator for collision lookup\n\n**v1.0.1**\n* Utilize 16bit color channels for light engine if available\n\n# Notes\nThe project also contains some other convenient stuff, like singleton keywords, easy memory cleanup for persistent objects, stress-test macro and easy logging functionality.\n\nThere is __A LOT__ of areas of improvement in this project. Most of the modules, and code, is simply copy-pasted from my prior projects. For example, I think that the terminal module should be reworked from scratch. Game size is currently hardcoded in a very ugly way. I'm not sure but I suspect rendering objects with shaders will cause a lot of unnecessary batch breaking. The code could be commented much better as well. I would also try to implement shadow casting to the light system.\n\nWant to support me? \u003ca href=\"https://ko-fi.com/larsandersson\"\u003eBuy me a coffee or whatever\u003c/a\u003e","funding_links":["https://ko-fi.com/larsandersson"],"categories":["Utilities"],"sub_categories":["Recommendations"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbabaganosch%2FGameMakerScaffolding","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbabaganosch%2FGameMakerScaffolding","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbabaganosch%2FGameMakerScaffolding/lists"}