Making a game isn’t easy. Focusing on a game until it is finished and released, is very hard. It looks like I have been successful at doing it for the last 8 years or so, releasing at least one new game every year –sometimes two!–. And, honestly, I don’t know for how long I will be able to keep it up.
I tweeted this two days ago, and it seems to have resonated with people:
What if the real happiness was starting projects, work on them as much as you feel like, and then never finish them?
There are those times in my life that I feel very productive, like I would like to work on so many projects, including a few that I know are not going anywhere. Early signs of that is when I started to work in a CRPG –this time for the CPC, and I’ve got further than ever before!–, or my latest work with Go and Ebiten.
And a lot of other projects I shouldn’t start because it is likely I won’t finish them ever –a compiler for a toy language? sure!–, and it all makes me lose energy, momentum, and focus on the projects that I could finish.
Hyperdrive started back in November 2021. It is a difficult one, that needed a few rewrites of the engine before I got it where I wanted, but we are almost in April 2022 and there is still a lot of work to do.
I guess it really sucks feeling productive, because I get easily distracted; even if that may be the real happiness.
I’m still refreshing my Go, and my friend Oscar is meeting Go for first time. Having a chat, I proposed him a possible project that could be interesting to have something to work on as he learns. Because learning to program a new language requires programming on that language, and for that, you most likely need a project.
I guess it could have been a blog as well –and I know it because I wrote my own blog engine in PHP, Perl and Python–, but I contributed a spec and Oscar is working on wikingo now based on that.
Looking at Oscar’s code, last weekend I thought: why not give it a go using Scala and some of the tools I work with at my day job but I never have time to do other things with?
So I wrote a toy wiki with Scala, http4s, doobie, ScalaTags and CommonMark (to render the Markdown), and using Tagless Final pattern –some context in the Expression Problem, and I haven’t found a “good” resource to link–.
Tagless Final is a pattern in functional programming, and is just an abstraction to build software, in which you define a Domain Specific Language (DSL) using Algebraic Data Types (or ADT, for example: a generic trait with abstract methods), and then provide an implementation (also called interpreter).
// my DSL
traitWiki[F[_]]{typeR=TypedTag[String]def init:F[Unit]def getPage(id:String):F[Option[R]]def editPage(id:String):F[Option[R]]def savePage(id:String, body:String):F[Int]def searchPage(query:String):F[R]}
And this is relevant because http4s is built on top of Cats, which is a library for functional programming in Scala borrowing ideas from the Haskell programming language, and supports Tagless Final nicely.
Anyway, if what I have written so far doesn’t transmit the idea that is complicated, let me tell you: it is!
My expectations was to put together something quick and easy, but I got myself stuck in the same problems I have often encountered in my day job.
Some notes:
Missing documentation and examples –if you are trying to do something not in the docs, it isn’t easy to discover things yourself–. This was specially painful when trying to decode the form data: I was missing an implicit, and even looking at the examples, I didn’t see that my type F was asking for Sync but I really needed Async –facepalm–.
Because I decided to use H2 as database, I got stuck a couple of times with doobie –always my fault, if you use H2 as an in memory database, remember to set DB_CLOSE_DELAY=-1 in your connection properties, or your DB will be wiped mysteriously–.
I got stuck finding a mapping for Java’s LocalDateTime in doobie, even if I knew there has an implicit somewhere. The answer is deep down in the FAQ, instead of being included in the part of the docs that deals with mappings.
Turns out there aren’t many current Markdown to HTML libraries, CommonMark works fine –although it is a Java one–.
The end result looks very nice. Is not that different from a Model View Controller pattern: Wiki provides a description of the controller, with implementation in impl. It calls the models –implemented with SQL in WikiSql–, and maps to the views in WikiTemplates. WikiServer has the router that calls the controller. Concise yet very readable.
So I didn’t dislike the result, but oh it was hard to get there!
As I mentioned in you learn by doing it wrong, I was thinking that perhaps it would be a good idea to work on a CRPG targeting a modern platform, because it would be easier to fail faster than with my current approach with the Amstrad CPC.
I had started all the infrastructure to start writing code in C using SDL2, with the latest version compiled from source, and I was almost convinced that I wanted to use C. I even had researched some libraries that I would need to work comfortably. Being a modern platform, there’s no point on suffering the same struggles of making software for an 8-bit.
But then I remembered that, no so long ago, I was looking for a language that was higher level than C, compiled to native code, and ideally supported cross-compilation –at least let me build Windows binaries on Linux–.
I started looking at Haskell –because it would be also useful in the context of my day job, where I write functional code in Scala using ideas borrowed from Haskell–, but I got bored pretty quickly by the book I was reading. Then there’s that Rust language that the new kids are always talking about, but I have the feeling that it would be unlikely that I could use it professionally.
Then I remembered that I wrote a good amount of Go before moving to Scala –professionally–. Back then I thought Go was alright, with a few things I didn’t like, but it was mostly down to some tooling or the way the Go community handled releases that I found it wasn’t my cup of tea. At the end I was writing C at home, with a lot of Python for my tools, so I kind of left Go behind.
I’m sure I learned about Ebiten at some point. “A dead simple 2D game library for Go”, and after looking at it I thought it was neat. But I wasn’t doing Go any more, so I didn’t dig too much.
The language has changed since then, and it looks like some of the things I didn’t like are better now. So I have decided to revisit Go, and give Ebiten a go –the Go jokes never end–.
I have a plan and I’ve been streaming on my twitch what I have been doing so far. With the new shiny toys for vim –for example: LSP–, the experience is quite nice and I have enjoyed it so far –mostly, the interface bingo is still tricky if you don’t know the packages–. We will see how far I will get, because I didn’t do anything after refreshing my Javascript.
I’ve been asked if the code will be open source, to follow along as I stream my sessions. That has been a bit distracting, to be honest, because doing things in the open as open source requires some effort. I’m not sure how to do it, if making the engine open and then make a game with it –very ambitious–, or just keep things simple and make a game –which may be a feat on itself!–.
As I say: distracting. In reality I don’t think I will write anything too exciting.
Meanwhile, my progress on Hyperdrive is steady. The engine is solid, I have one stage –complete with final boss!–, and I’m working on graphics and enemy designs for the second stage. I will stream more sessions working on it, but only when the graphics are ready.
I love the graphics –hand-drawn by Capcom–, the character design, how the story is told –e.g. you play a character that is not part of the party to know about his story–, the combat, how you can learn new skills from enemies –it is amusing learning the “command” special from the duck commander and use it to ask its minions to kill him–; there are a lot of things to love in this game.
So, why I am bouncing from this game after roughly 10 hours? Because I wanted to play a JRPG, and this one has a lot of mini-games that ask me to navigate screens to do uninteresting things.
And that is the main problem. The game looks fantastic, but the way they implemented the isometric graphics requires you to constantly rotate the camera to see where are you and where are you going. So having to do that chasing some sort of wild boar to find the mayor of a weird town so you get permissions to cross some tunnels is not only uninteresting but annoying.
The combat is alright, I found it to have the right amount of options and strategy, so I didn’t mind when I had to fight cute mice and roaches –big, strong ones– when I was already used to fight undead and zombies.
But when I start missing the combat because I spent one hour finding orphans playing hide and seek so I could continue my main quest, having to kill a few mice and roaches is too little when the game asks me again to play one of those mini-games.
It is a shame, but considering how little time I have to put on a game like this, I don’t think Breath of Fire IV is for me!
So shortly after I posted here my notes about my Python with LSP setup, I decided to give the neovim native LSP support a go. Mainly because I found that vim-lsc didn’t understand some of the messages Python LSP Server was sending and, although it looks like that didn’t have any effect, the error reporting was a bit distracting –even when I tried to disable it–. So I thought, how difficult would be using neovim’s built-in support?
Very easy, actually. I guess I’m not the only one not willing to burn all bridges in case I have to go back to use vim –that has been around long enough to make me think it will be there for ever–. There is no reason to think that neovim will disappear, or go in a direction I don’t fancy. My vim-lsc setup did work with vim, and in some cases I don’t have neovim available (or at least not at the minimal version required to enjoy all this).
But the fact is that I’m already enjoying some neovim-only features, like Telescope, so let’s go with full in with neovim for my LSP needs –at the end of the day, it is what I use for development–.
The changes to my previous configuration are actually very simple. First, I removed the vim-lsc plugin and added nvim-lspconfig, wrapped on a condition, so it doesn’t load if I use vim or the neovim version is not high enough:
That should make vim –and older neovim– load fine.
Then, in my init.vim for neovim, I added an include to the file that will have the LSP specific configuration –and now I realise it should be wrapped on a version check, as well–. This doesn’t include my metals setup because nvim-metals doesn’t use the nvim-lspconfig framework –I need to investigate this, actually–.
I decided to include the configuration in lua instead of vimscript, because it is readable, and because the minimal example is using that language.
For full reference –for my future self–, this is the configuration:
-- for nvim lsp support-- Mappings.-- See `:help vim.diagnostic.*` for documentation on any of the below functionslocal opts = { noremap=true, silent=true }
vim.api.nvim_set_keymap('n', '<leader>d', '<cmd>lua vim.diagnostic.open_float()<CR>', opts)
vim.api.nvim_set_keymap('n', '[d', '<cmd>lua vim.diagnostic.goto_prev()<CR>', opts)
vim.api.nvim_set_keymap('n', ']d', '<cmd>lua vim.diagnostic.goto_next()<CR>', opts)
vim.api.nvim_set_keymap('n', 'da', '<cmd>lua vim.diagnostic.setloclist()<CR>', opts)
-- Use an on_attach function to only map the following keys-- after the language server attaches to the current bufferlocal on_attach =function(client, bufnr)
-- Enable completion triggered by <c-x><c-o> vim.api.nvim_buf_set_option(bufnr, 'omnifunc', 'v:lua.vim.lsp.omnifunc')
-- Mappings.-- See `:help vim.lsp.*` for documentation on any of the below functions vim.api.nvim_buf_set_keymap(bufnr, 'n', '<C-]>', '<cmd>lua vim.lsp.buf.definition()<CR>', opts)
vim.api.nvim_buf_set_keymap(bufnr, 'n', 'K', '<cmd>lua vim.lsp.buf.hover()<CR>', opts)
vim.api.nvim_buf_set_keymap(bufnr, 'n', 'gi', '<cmd>lua vim.lsp.buf.implementation()<CR>', opts)
vim.api.nvim_buf_set_keymap(bufnr, 'n', 'gsh', '<cmd>lua vim.lsp.buf.signature_help()<CR>', opts)
vim.api.nvim_buf_set_keymap(bufnr, 'n', '<leader>rn', '<cmd>lua vim.lsp.buf.rename()<CR>', opts)
vim.api.nvim_buf_set_keymap(bufnr, 'n', '<leader>ca', '<cmd>lua vim.lsp.buf.code_action()<CR>', opts)
vim.api.nvim_buf_set_keymap(bufnr, 'n', 'gr', '<cmd>lua vim.lsp.buf.references()<CR>', opts)
vim.api.nvim_buf_set_keymap(bufnr, 'n', '<leader>F', '<cmd>lua vim.lsp.buf.formatting()<CR>', opts)
endlocal signs = { Error ="🔥", Warn ="⚠️ ", Hint ="✨", Info ="ℹ️ " }
for type, icon in pairs(signs) dolocal hl ="DiagnosticSign".. type
vim.fn.sign_define(hl, { text = icon, texthl = hl, numhl = hl })
end-- Use a loop to conveniently call 'setup' on multiple servers and-- map buffer local keybindings when the language server attacheslocal servers = { 'pylsp' }
for _, lsp in pairs(servers) do require('lspconfig')[lsp].setup {
on_attach = on_attach,
flags = {
-- This will be the default in neovim 0.7+ debounce_text_changes =150,
},
-- FIXME: shouldn't this be only for pylsp? settings = {
pylsp = {
plugins = {
pylsp_mypy = {
enabled =true,
live_move =false }
}
}
}
}
end
Which is the suggested minimal configuration, plus the keybindings I use in metals –and I’m used to them–, plus a couple of small things, that affect my metals setup as well –e.g. the icons in the gutter to signal errors, warnings, etc; also something I need to investigate further–.
And that’s all, really. Seems to work fine, and all the noise from vim-lsc seems to be gone. I don’t know if the native neovim LSP support is doing anything differently, but at least is not reporting errors, so I guess… if I don’t know about it, it is perfectly fine.
This is still a bit work in progress and there are things I still don’t fully understand, but I will get there!
I wrote a similar post back in April 2021 –on Gemini, that’s obscure!–, but I updated my main Debian box and something broke. Then I revisited it all after I dropped the few projects I still had with Python 2, and it all stopped working –did it ever work Python 3? Not sure–. So there you go, I did it again and I’m documenting it for “the future”.
I use vim-lsc –for now–, because it does a lot out of the box, and with almost zero configuration. Even now that I use nvim-metals for Scala –in neovim–, I have configured most bindings to behave like vim-lsc because I like it. I guess I could investigate the native neovim support for LSP, but I’ve been lazy. vim-lsc is good, but it doesn’t look like it is actively maintained, so take that into account if you want to try this.
The way I’m enjoying Python lately is with:
Python LSP Server –this is a community fork of the unmaintained Python Language Server–. This does a lot of things already, even if you only use this, it is a good experience.
Mypy –an optional static type checker for Python–, via pylsp-mypy. The code is checked on save.
Black –a code formatter; “Any color you like”–, via python-lsp-black. The code is formatted on save.
You can install all this in your local user using pip with:
This is best with Python 3.8 or later. You may also want to ensure neither yapf nor autopep8 are installed, or black won’t kick in. But you can skip black all together and use yapf –it is also nice, just not as nice–.
I’m not always annotating my code with types –and I should–, specially in old scripts, but in general this is my setup. And all controlled via vim-lsc and this piece of configuration:
vim-lsc will start the LSP server only when we edit a Python file. I recommend reading its help to know what are the keyboard bindings to navigate the code, autocomplete, etc.
I hope this doesn’t break again any time soon, specially now that I’m not using the outdated and unmaintained Python LSP server!
You have al the info at @reidrac is CODING, but basically I tried streaming a couple of my coding sessions on Twitch, and I liked it!
The way I’m looking at it is different than what I used to do in YouTube (and these are the videos so far): my “off-line” sessions are videos to keep in the channel, while in Twitch is more about sharing my programming session as they happen –currently I’m not keeping the videos, although I may keep some that are specially good to get a bit more attention–.
What I would like to get from these sessions? Good question!
First and foremost, finishig my current game –or whatever is the project I’m coding on, it won’t always be 8-bit gamedev–. If Twitch helps me with motivation and, in a way, to gamify the development process –like sharing progress on Twitter–, that’s great. One of the hardest things of gamedev is being persistent, because making a game is a long road, and until you get to the end… there’s no game!
Secondly, 8-bit gamedev is kind of lonely activity as in it is very unlikely I chat about it with anyone in “real life”, so I’m curious to see how will it work the community part of a streaming channel –which initially will be none, because nobody will watch my sessions–.
I was joking on the title of this post –see the Buggles song–, and I plan this to be non-stress and it will last as long as I feel like doing it. I won’t have the webcam and/or the microphone on if I’m not alone or it isn’t quiet enough around me –I don’t have dedicated office space at home–, and it is unlikely I will be able to schedule the streams in advance: I will code as I usually do, with the difference that I will be streaming it.
My Twitch channel is MrReidrac –because my reglar nickname was taken!–.
So I’m at the end of Crystal World and my next fight is Deathguise –I don’t know this one–, followed by Kuja, and then Necron –I don’t know this one either–. Looks like I’m under-equipped, and I can only go back to the previous area (Memoria), and that’s it.
According to the save game, that was almost 42 hours –in reality a bit more, as I used save-states as I thought it was useful–. I didn’t read any guide, so I would say the game is not hard.
I guess I could go back to Memoria and grind for a couple of hours until the end bosses are easier, although Deathguise uses attacks that can wipe half of my party in one hit, and that suggests I’m not using the right protections.
If I had used a guide, that would have helped to prepare my party for these boss fights. Some things can be found by trial and error –for example: the Soft potion will remove paralysis effects–, and I’m very proud of killing the undead type of boss at Lifa Tree by using Life spell, but I don’t think the equipment names give enough information on what they do.
Other than not being able to beat the game, I think I got most of what the game had to offer –and I can always watch the end on YouTube–. I enjoyed Final Fantasy IX, although I spent most of my play-through wishing it was better at some things.
The story is all over the place –which to be fair, could be considered your usual anime thing–, but the game is almost completely lineal –I know a side quest I didn’t do–, with a lot of “press X to read” parts with sprinkles of combat kind of to justify the RPG elements. I don’t know if it was because I was playing with the boys and they can’t read, but some of those pieces of exposition felt too long –for example, during the battle of Alexandria–.
But on the other hand the characters are well developed, the story is OK –including who’s the baddie now parts–, and there’s also a good amount of world building. With the combat not being too complicated, what I ended missing was a bit more RPG.
The 3D graphics are dated –it is a PlayStation game after all–, but I found them to be good enough to my eyes –and the boys really liked the big monsters: cute but a bit scary–. The pre-rendered background look great, but this was my biggest problem with the exploration: I got stuck at least 3 times just because I missed that there was an exit on a screen. That was half the scenes being very busy and half the camera angle, but it is a shame that it was the only times where I felt I didn’t know what to do or where to go.
I’m looking for my next game, continuing to research JRPGs. I tried a bit of Final Fantasy VI on the SNES –a patched ROM that improves the translation and adds a few bug-fixes–, but going back to those 16-bit graphics and the UI being a bit less refined felt too hard. So I’m going to try something different: Breath of Fire IV on the PlayStation. Those Capcom hand-drawn sprites look beautiful!
I’m a bit stuck with my CRPG project –that really, really needs a name!–. I think I got the gist of implementing the Whitebox rules, and a nice keyboard (or joystick) controlled menu system to manage inventory, but I have never made a full CRPG before –the closest was many years ago in GWBASIC–, so I don’t know if what I’m doing is correct.
It is true that it doesn’t matter too much as long as it works, but I have reasons to think that I’m not doing a great job. For example: I’m using a lot of code, and the cartridge format I’m using makes it easy to have lots of data, but code is tricky (specially coding in C).
So I have that feeling that I’m going to continue putting hours on the project to realise too late that I have lost my motivation, or I got to a dead end.
It has happened to me before, even recently working on Hyperdrive: I have implemented the same engine three times already–. A CRPG is a larger project and I don’t feel like starting everything again –there was a failed project before this one, and if you count moving from disc to cartridge as an iteration; this could be my third go already!–.
That’s why I have been focusing in more direct projects, like Hyperdrive –despite being unclear how things are going to be implemented, I have finished a couple of shoot’em ups already–, letting the CRPG project rest and keep thinking about it in background.
I watched a talk by Josh Ge on How to Make a Roguelike, and besides of being very inspiring –I don’t think I’m going to make a roguelike any time soon; although you never know!–, it made me realise how little of a plan I have to build my CRPG. And then a talk by Bob Nystrom (from Game Programming Patterns fame, among others) Is There More to Game Architecture than ECS made pretty clear that I have no idea if my approach will work –and the fact that the bits I have feel too big for an 8-bit could be a good indicator–. I may need a way of learning before I can succeed in an actual CRPG.
So now I’m thinking that perhaps I should try a smaller project, probably on a modern system so I can prototype and iterate faster, and manage to finish something –even if is small–. I know how to finish games, but not a CRPG.
Recently I’ve been playing with some C with SDL2 code that looks very simple –and not that different from what I do in 8-bit systems!–, and I also have a clean new codebase to do 2D games using Javascript and Canvas 2D. I’m considering one of these two options to implement something small on the side, so I can validate some of my current assumptions on the actual 8-bit CRPG. Sounds like a better way to do things wrong, and I may even finish a game!
Today is the first anniversary of ubox MSX lib –1.0 was released today one year ago–, and yesterday I tagged version 1.1.9, and it is likely that wraps 2021.
I believe the code is stable, and in the 14 releases on 2021 I mostly focused on:
Improving Windows compatibility. Although I didn’t want this to be a priority –I don’t use Windows at all, I can’t support it–, once I had one user trying to compile on Windows, it was a great opportunity to make things more portable –portability is good–.
Added compression (with aPLib and apultra). Arguably this should have been in the first release, but it was not essential.
Added missing documentation. This is mostly regarding the tools used by the example game. In my original idea, the important thing were the libraries, so that was well documented. Turns out users want to use the Python tools in their own projects.
Then I had a few contributions from one user (Pedro), and that resulted in a few unexpected improvements:
Some usability improvements in the Python tools.
A better build pipeline, including basic CI in GitLab.
And on top of all this, some bugs where fixed. These are mostly issues that I introduced accidentally when I ported the original code from Night Knight / Uchusen Gamma to something more general and usable.
What is next?
It is complicated because I’m currently not actively working on an MSX project, and adding functionality that you are not using, is hard. But I have a TODO list:
Add some CAS support.
Add perhaps another compression tool; probably ZX0 with salvador.
Support 48K ROMs.
Add some MSX 2 features.
Pedro is interested in the MSX 2 support, but that is something I’m still planning and I want to create an experimental branch to see how we can support some sort of configuration to target MSX or MSX 2, dealing with the limitations of SDCC (specially sdasz80). Besides it would be ideal if I could align that with a game project, so things are well tested and I can justify adding code to the project that I will have to maintain.
Open Source projects can take a lot of your time, and I very much prefer making games than libraries/tools, but with some patience I think we can do some interesting things in 2022.