Monday, September 6, 2021
My only dissapointment is I didn't use a The The cover for one of the profiles.
Monday, September 6, 2021
My only dissapointment is I didn't use a The The cover for one of the profiles.
Tuesday, August 31, 2021
This past month I started doing One Game A Month. I've spent the better part of the last few months buying a new house and moving, so I'd fallen off the making stuff train for a while; doing OGAM seemed like a neat way to try to get back into the swing of making content, especially now that I've got my own office. I set a couple goals for myself for the first month:
For the first month, with the theme One-Liner, I decided to try my hand at making something I've never tried developing before: an RPG combat system. I should probably note that this was something I'd already been thinking about trying to make before OGAM, so naturally I attempted to shoehorn the theme in. Rather than casting spells, the player characters would rack up Cool PointsTM as they land attacks. Once their CP meter was full, they could execute a one-liner. Rather than casting "Ice" or something, they'd say something fitting of the character, and a major attack that thematically matched the one-liner would take place. For example, a character could say "Everybody, chill!", and the result would be a large party-wide ice attack.
As is typically the case, I didn't fully grasp just how much work and planning would be required to build out a flexible RPG combat system, and I didn't quite finish. If I had to guess, I'd say it's abouy 60% there, with logic for queueing battle actions, triggering animations, and processing some of the action types. A lot of the remaining work involves connecting all the pieces together, which is also when I tend to find that I don't like the way certain systems work so I get distracted and try to rewrite it. I'd say I rewrote the whole thing probably two and a half times over the course of August.
So did I meet my goals for the month? Kinda, honestly. Even though I didn't finish the system, I am happy with the work I did on it, and I do plan on completing it at some point so I can use it with other projects. (sidenote: I don't know how it happened, but I've only just started really enjoying playing JRPGs. Something about gaining patience in my old age, I guess.) And as for what it's like making content in my new office, it's definitely nice but there's room for improvement. A proper desk would probably go a long way, for starters. Some better storage/organization for art supplies would be good too. But a good start, for sure.
If you're interested in taking a look at the project, I've posted the source over on my Github.
Wednesday, March 31, 2021
According to the git log, I have a project I've been working on off and on since April 24th, 2020 that I haven't talked about on my blog yet. I've been working on it more and more over the last month or two, so I'd like to start writing devlogs as I go along, making this the first one I write on it.
The project is a rail shooter of sorts, heavily inspired by Starfox and Panzer Dragoon. If you're unfamiliar, the general idea is the player is control of a ship or vehicle of some kind that is always moving forward at a steady speed, firing at enemies along the way and dodging various obstacles. The key differentiator is that I'm building it as a VR game, where rather you use your hands to fly the ship and aim your weapons. It all started with a little prototype I built over the course of a week or so, just prototyping some really simple stuff like moving a little ship towards your one hand and moving a blocky environment past you, giving it a sense of flight. I thought it was cool enough to continue work on it so I kept at it for a while. Then, like with most side projects, it'd get dropped for a few weeks, I'd come back and rewrite some things, then drop it again. All very protoype-y, neat but nothing to really share.
That repeated a few times, and then finally about two months ago I started getting much more into it. I've begun creating tickets for tasks to help keep myself from feeling overwhelmed or lost. I put a good bit of time into really working out the architecture of the project, so I can more rapidly prototype concepts and put more time into content. Part of that tasking and content is writing posts about progress, so here we are.
I'd also like to take a moment here to thank the Godot team for doing some fantastic work on this engine. It's been a lot of fun learning and tinkering with it - it's nice when the tools you use to make something are nice to work with themselves. Also huge thanks to Bastiaan Olij (and all the project contributors) for the OpenVR plugin that's making my VR work with Godot possible.
Part of all the work and rework I've been doing is trying to find a way to speed up prototyping so I can make things do things faster. The less roadblocks I have to trying out a new idea, the more encouraged I'll be to try out new ideas. A big part of this is the Entity scene I've established for any element in the game I want to interact with others. I've attempted other structures like this previously, but I don't think it was until the last couple of weeks it really clicked.
In Godot, you have what are referred to as Scenes. The best way to think of a Scene is as an object in an OOP framework. You have a base class (in Godot this is a Node) that you can then extend via inheritance to create a more specific object. For a long time, my thoughts on this were to take one of the provided Node types and extend it entirely with scripting, and then inherit that new scripted Node to create other objects. While it works, I lost one major benefit of Scenes - the ability to instance and inherit from them in the editor.
Every Scene in Godot (down to the editor itself) lives inside a SceneTree. Nodes are children of parent Nodes going all the way up (down?) to the root of the tree. While each Node is a class itself in a way, you can also treat a single Node and it's children as one whole object. This parent Node and set of children can be spun off into their own scene and then instanced in other scenes over and over again, in the same way you'd write a class and create instances of it in other languages/frameworks. Now, not only can you easily instance these Scenes in Godot, you can extend them on a per-instance basis by adding new child Nodes to them. It's the same as inheriting a class and providing new functionality, except here you can do it quickly and visually with other Nodes in the engine.
If you're familiar with OOP principles this all probably sounds pretty obvious, but for whatever reason this specific approach didn't click with me until very recently. This lead to the creation of an
Entity Scene, a base Scene that I can inherit from to create all sorts of interactive entities in the game that all behave nicely with one another. It's a
Spatial Node, Godot's base 3D Node, with a
CollisionArea Node and custom
Health Node as children.
CollisionArea is an extension of the
Area Node used to define the collision layer the entity exists on and what layers it's checking for collisions on. It also includes some data that is provided to other objects when they collide with it, like how much damage a colliding object should take (if any) on impact. This is useful for ships colliding with each other or running into buildings.
Health is a GDScript extending the base Node, and it manages the health of the object. You provide a maximum health value, a length of time the entity should be invincible for following taking damage, and a checkbox for flagging an entity as invincible. There's a
take_damage() method that is used to apply damage to the entity, and two signals (Godot's built-in implementation of the observer pattern) for announcing when it's taken damage and when it's been destroyed.
The basic player projectile a good simple example of the Entity inheritance/usage. The parent node handles logic for moving the projectile, spawning a small AudioStreamPlayer3D scene that plays a brief sound effect when spawned, and the lifespan of the projectile. The Entity Scene is a child, along with a .glb placeholder model representing the projectile. The Entity is configured so it can impact anything on the Enemy, EnemyProjectile, and Obstacle layers. On impact, it takes whatever impact damage the Entity it's hitting does and applies it's own impact damage to the other Entity. For the most part, this means anything it hits "kills" the projectile while simultaneously doing 1 damage to the Entity it hit. Enemies explode, invincible obstacles don't do anything.
Here's the player's ship Scene tree. The root
Spatial Node has a script managing movement of the ship and connecting the WeaponTargeting to the player's targeting hand. The Entity Scene is stock, with the
Health signals connected to the
HealthUI Scene, driving the progress bar representing the player's current health. ShipPlayer scene is just the .glb 3D model representing the ship.
WeaponTargeting handles the aiming of the player
Weapon, which is also a child of
WeaponTargeting. Similarly to the PlayerBasic projectile, it can take and apply impact damage when colliding with anything on the Enemy, EnemyProjectile, and Obstacle layers. The nice thing about this is you can crash the player ship into an enemy with 1 HP, killing the enemy on impact while suffering 1 damage.
This post was supposed to cover other stuff like the audio effects I've been tinkering with, or how the levels are managed, but that Entity stuff got so long I don't think I could fit any of it in here. If you liked this writeup shoot me a line via email or Twitter and let me know. I wouldn't mind writing similar posts about other components as I create them, but I also can keep future posts a little bit more high-level and brief.
Thursday, September 3, 2020
At this point in the year this is all about the Presidential election. While it's definitely a big deal, registering also means you can vote in local elections which are argueably even more important. Come next year you'll be able to help decide who gets to make decisions that directly affect the community you live in. It probably doesn't get nearly enough coverage, but with a couple of web searches and some digging around on social media platforms you can learn a lot more about your local candidates than you might think. So yeah, go register and go vote!
(I meant to post this earlier in the year, but I've been neglecting my blog as per usual. More (VR) project stuff soon.)
Tuesday, August 11, 2020
Little arranged scene spotted on the side of the road while bumming around town.
Friday, July 31, 2020
My coffee was very photogenic this morning.
Tuesday, July 28, 2020
Last week I put together some visuals (e.g. looping animations) for Hang On Get Ready's live set for Hope 2020. I didn't get to catch the show when it was live as I was bumming around Keuka Lake in a canoe all weekend, but we can catch the archived version at https://www.pscp.tv/w/1mrGmEzvaXVGy. Also here, have some stills of the clips:
Wednesday, February 19, 2020
Global Game Jam wrapped a week ago last Sunday. A lot of things have happened in the last few days, hence the late conclusion post. I'll get into some of that in a later post, so for now let's talk about how things in the Godot VR world wrapped.
Sunday was a pretty short day for me. I had hit a bit of a creative wall, having implemented the basic VR interactions. I decided to spend the final day exploring other features of Godot, specifically the Constructive Solid Geometry (CSG) features. I started tinkering with generating a small level, playing with the different CSG nodes to see what worked and what didn't. Turns out they can be a bit fickle, but for the most part they worked very, very well. I was able to rapidly build not only a small stage, but a few bits of set dressing as well.
I created a little area with a big building you could run inside of first, playing with scale to see what felt good inside the HMD. Once that was hammered out I started adding some textures (quickly created in Aseprite), and then some props and lighting fixtures. By this point I had inadvertently created a nice setting for a PS1-esque horror game, and it was at this point I decided to call it a day (jam?). It was about 3pm on Sunday, so the odds of this little exploratory demo turning into a game were slim. Satisfied (relatively) with what I had learned, I wrapped the project, packed things up, and headed home.
I learned a good deal about how to work with the VR features of Godot. If you're interested in trying it out I highly recommend reading through the excellent documentation on Godot's website, as well as checking out the OpenVR assets developed by Bastiaan Olij if you're using SteamVR compatible platforms. Without that asset this wouldn't have happened at all.
I've posted builds of the project to itch.io for your perusal, and the source code is available as well to poke at and dissect. If you're interested in how any of it works or would like to chat about VR in Godot, shoot me a line; I'm more than happy to discuss it and help out where I can.
Saturday, February 1, 2020
It's about 8:30pm as I write this, and I think I'm already gonna call it a day on day 2. I got a bunch of stuff working, then tried to make it into a game, then broke a bunch of stuff, and finally reverted back to the testbed I had functional around 2pm today.
The big thing I was able to tackle today was grabbing and throwing stuff. Grabbing was pretty straightforward; I subscribed signals to the
button_release signals that ARVRController comes with, which in turn have child Area nodes subscribed and can attach grabbable objects as children to themselves if one happens to be in the, er, Area.
Following that I started working on throwing. The short version of my tinkering is I aggregate a small pool of changes in the global position of ARVRController, applying a weighted multiplier to each value, and provide that aggregate to the grabbed object as an impulse after I throw it. There's a couple other bits to it to account for the rotation of the playspace (left-stick rotates the play area), but that's pretty much it.
By this point I thought I had a pretty good set of systems in place to start making a game. I wanted to do something Myst-like, so I build out a little island terrain to start walking around it. The terrain had slopes to it, so I thought it'd be cool to move the play area up and down so it snapped to the surface where the user is "standing".
And this is where things fell apart. I started messing with some raycast stuff to position the play area, and to make a long story short I broke the player system somehow without having any commits to revert to in the repo other than the last one I made after getting throwing working. This made me grumpy, and now here we are.
I still think I might take a stab at making a little environment to walk around in, just keeping it all on a flat surface. I think it'd be fun to do a bit of lo-fi 3D modeling/texturing and walk around in it. The only thing I might try to add is some method of preventing the user from walking through walls, but we'll see where it gets.
Friday, January 31, 2020
So we're currently about four-ish hours into GGJ at BGS. I've spent the time since watching the keynote video poking at Godot and making some basic VR movement tests. I'm not doing teleporting at the moment, just free movement at speeds that most people would probably find nauseating.
It's a little snappy, but it works! Already I've learned a good bunch of little things, from how to set up the basic VR scene to manipuation of the origin transform through the use of the camera basis. Also, fun fact: trying to handle all the movement in
_process() is a bad idea, as the controllers will lag behind the view. Keeping things in
_physics_process() seems to solve this.
I've got a super simple script for grabbing that just emits a "grabbing"/"releasing" signal when you grab/release, and it scales the hand meshes down when squeezing. I'll probably hook that up to some basic grabbable objects tomorrow, then look into handling collisions between the player and the environment.
There is a loose game idea that I'll tie into this, but no talking about that until the theme is announced everywhere.