Noble Engine: a li'l game engine for Playdate

, ,

Hey folks! My li'l game engine for Playdate, Noble Engine, is now ready to be poked around at.

NobleEngineOptimized

I have it in a private GitHub repo for now, so reply or DM me your GitHub username and I'll grant you access (until the Playdate SDK is public, or we get word that it's cool to post code in places). :smile: EDIT: Now public, see links below:

Features:

  • Complete scene lifecycle manager.
  • Scene transition API and animation library.
  • Settings/SaveGame API, supporting up to 1000 save slots and automatic updating of on disk files when you inevitably muck around with your data structure.
  • New input methods for onHold, and per-scene inputHandler logic.
  • Robust documented code, explaining methods and architecture (WIP).
  • Full project template, with example scenes and launcher assets, to help beginners get started with Playdate development.
  • Two new fonts! Including my super tiny Japanese font.
  • Random goodies like a unified text drawing method for normal/aligned/localized text, and one-line methods for showing/hiding the crank indicator and the FPS counter.

Gotchas:

  • I have no idea how this performs under stress. I stayed away from the Graphics API for the most part, so I'd like to think there isn't a lot of overhead, but we'll see!
  • My text system doesn't support bold/italic variants yet. On the do-to list.
  • I have a funny way of using the sprite drawBackground callback, in that I provide it as a arbitrary code block to the user rather than a function with specific arguments as the docs recommend. It works fine, but I'll need a sanity check on that in case I'm doing something silly.
  • I want to have a API for scenes to manage the items in the system menu in a consistent, expected way (like having "quit to main menu" where the user expects it), but I haven't worked out the design of that yet.

This thing has actually gotten a bit further along than I expected, so I'm eager for people to take a crack at it.

ExampleScenes

14 Likes

Hi! could I get access to the repo :slight_smile: ? afk-mario (afk) ยท GitHub

1 Like

Your got it! Be sure to comment here on what works and what doesn't after you've had some time to play around with it.

Okay, bit of an update. I split up the repo for this into two repos, one for the engine itself, and another for the project template, which includes a submodule pointing to the engine. This is very useful because you can use the project template repo as a "github template" when creating your own project's repo, and any engine code changes can still be pulled independently. You'll never be out of sync.

But... this means that if you want access to Noble Engine (again, until I can make it public), I need to make you a collaborator on both repos. This is very annoying, and since being a "collaborator" (the only way to share private repos on GitHub) also grants the ability to push, very dangerous. :grimacing:

I'm still happy to do this for anyone who wants, since it's the best way to actually use Noble Engine while the code is still in flux, but eventually there will be too many people for me to manage, or you simply won't want to wait for me to see your DM, so here is a ZIP of the current project template and engine code:

NobleEngine-ProjectTemplate_20210317.zip (450.3 KB)

Would love to check it out: @mierau

1 Like

Update: I've moved a lot of the functions outside of noble.lua and into their own files. I had to reduce the amount of local variables in the update loop, but I think it's worth it for code maintenance and documentation.

Speaking of documentation, I finally figured out how to use LDoc (the defacto standard for generating documentation pages for lua projects) and have been working on making real slick API docs for Noble Engine:

These are included in the repo, so you can view them now, but I will also host them on GitHub Pages once I'm able to make the repo public.

One thing to note is that I've introduced a breaking change to the structure of GameData objects, so you'll have to delete any existing save JSON files. These kinds of breaking changes may happen a few more times before "v1.0" whatever that is, and I'll definitely be renaming methods a bit which you can also classify as breaking if you're picky, but I'll be trying to avoid them going forward.

My own game is progressing slowly because I've been side tracked with this, so I would really appreciate any comments/feedback as a result of real-world testing. Thanks!

So, reply in this thread, send a DM, or message me on the Discord if you're interested in getting access to the GitHub repo, otherwise, here is the latest version of the project template (with the engine in "libraries/noble") as a zip: NobleEngine-ProjectTemplate_20210323.zip (491.0 KB)

I would like to try please: https://github.com/sheetsceet

1 Like

So sorry, my invitation expired :frowning:

Alright, I'll extend it... just this once! :rofl:

Your other invitation, to NobleEngine-ProjectTemplate, is still pending, so grab that one too before it expires (I can't re-up it, apparently, and don't know how long these things last).

As a reminder for anyone else who requested access back I first offered it, the current recommended use-case is to use the ProjectTemplate repo as a "GitHub template" for your own thing. That way, Noble Engine gets put in the correct library subfolder and allows you to update it as a separate repo submodule, independent of your own code. This is pretty important at the moment since I'm making frequent changes.

I'm new to git submodules myself, but if you use something like SourceTree or VSCode to wrangle git, they're pretty easy to manage and are absolutely worth the trouble to learn about.

1 Like

Update! I mentioned it in the Zoom hangout that just ended, but I just added a spritesheet/imagetable animation system, Noble.Animation, to Noble Engine:

The goal is to make you have to write less boilerplate code. Here's a basic implementation example:

MyHero = {}
class("MyHero").extends(Graphics.sprite)

function MyHero:init()
	MyHero.super.init(self)
	-- ...
	self.animation = Noble.Animation.new("assets/images/Hero")
	self.animation:addState("idle", 1, 30)
	self.animation:addState("jump", 31, 34, "float")
	self.animation:addState("float", 35, 45)
	self.animation:addState("turn", 46, 55, "idle")
	self.animation:addState("walk", 56, 65)
	-- ...
end
function MyHero:draw()
	self.animation:draw()
end
function MyHero:update()
	-- Input
	-- ...

	-- Physics/collisions
	-- ...

	-- Animation states
	if (grounded) then
		if (turning) then
			self.animation:setState(self.animation.turn)
		elseif (math.abs(self.velocity.x) > 15) then
			self.animation:setState(self.animation.walk, false, self.animation.turn)
		else
			self.animation:setState(self.animation.idle, false, self.animation.turn)
		end
	else
		self.animation:setState(self.animation.jump, false, self.animation.float)
	end

	groundedLastFrame = grounded
end

It accounts for states that transition into other states (like jump-to-airborune or landing-to-idle) and puts all the boilerplate "if not this already" logic into the library, so it's easier to implement.

It's ideal for sprite animations, characters, objects, etc, but it also works as an extension to playdate.graphics.imagetable so you can use it for things like score counters and player-controlled flipbook animations.

Give it a try and let me know what you think!

It's up on the repo (message me for access), but here's the latest zip: NobleEngine-ProjectTemplate_20210330.zip (498.0 KB)

4 Likes

It seems my invite to the engine expired :frowning: I think I only accepted the template one, If this was intended then don't mind me

I think a cool feature for the Animation lib is to be able to pass an array of frames, It happens to me a lot that for an animation I want to re-use one of the images on my image table.

local framesIdle = {1,2,3,2,1,2,3,2,1,5,3,2}
local framesRun = {1,2,3,4,5,6,7,8}
local framesFall = {5,6}
local framesJump = {2,3,4}

Also being able to specify the speed of the animation would be a nice feature

It seems my invite to the engine expired

No worries. I re-sent it.

I think a cool feature for the Animation lib is to be able to pass an array of frames

Ooo, I like that. If I'm being honest, though, I don't see a ton of use-cases for it, since Playdate is performance-bottlenecked, not bandwidth/storage-bottlenecked. You can also just include extra copies of those frames in your spritesheet without the dire impact that it used to have in the NES/GameBoy days.

But... shouldn't be too hard to implement as an option (if not nil then advance to next frame from this table instead of just the next frame count), so I'm happy to try it out. You can also submit a pull request if you are impatient for me to get to it! (NOTE: please don't push a commit directly even though you have the access to).

Also being able to specify the speed of the animation

I decided to make the animation operate on a per-update basis, rather than using any kind of timing system, since I found that dropped/skipped frames were more common for me when using playdate.graphics.animation.loop for spritesheet animations. It's the reason I built this system in the first place.

As such, I think it's somewhat out of scope for this system to do arbitrary animation speed "correctly" (especially since playdate.graphics.animation already exists and can do this).

I could add an argument to draw() or maybe addState() to allow you to advance the sequence by any number of frames. I don't know the performance implications of running Lua's math.floor / math.ceil operations repeatedly, either directly or implicitly, so it might be that allowing for fractional values (like 0.5 or 1.25) might create a performance problem even if they're not used. I'll have to look into it. Performance optimization in Lua is still very alien to me.

Playdate is performance-bottlenecked, not bandwidth/storage-bottlenecked.

Makes sense, the animation on the SDK work's like this but coming from PICO-8 I feel bad duplicating frames, not really sure if the Playdate does something to optimize duplicated images, but I see how if you have a ton of animations it could be helpful to be able to pass the frames individually. Will try to send a PR later :slight_smile:

1 Like

Looks like the animation time is out of scope and you are right the sdk animation already does that

I'd love to give it a shot :slight_smile: greysonp (Greyson Parrelli) ยท GitHub

1 Like

Hey @Mark, apologies for taking so long to finally start trying this out. It's early days yet, but I'm really impressed with the scene handling, transitions, and menu creation. You've established a structure for some of the bits that have given me trouble in my first few games and provided a layer of abstraction that, as novice game developer, I really appreciate.

I'll share more thoughts as I continue to dig in, but great work!

Aw, thanks for saying! I'm glad to see it getting use. @greysonp recently offered some helpful pull requests to the project template, too!

Current snapshot of the project template repo (engine code is in "source/libraries/noble").

NobleEngine-ProjectTemplate_20210520.zip (507.3 KB)

So, I've gone and made the repo public. I've seen enough public things posted from other devs, and with still no hard ETA on the SDK itself becoming public, I figured there was no longer a reason to wait since it makes using the engine a lot harder for people in the dev preview program and is still bascially useless to folks outside of it.

I've also created a "Github Project" with a public Kanban board so people can see which issues I'm working on, etc. --> Noble Engine ยท GitHub

For anyone who I previously added as a collaborator, I've now removed you, but since the repo is public, I don't think you'll notice a change.

3 Likes