Kekouan

Have I talked to you about Quake?

2024-03-17

I'm not entirely certain when I was introduced to Doom or Wolfenstein 3D. Long after their respective releases, no doubt. Quake) though, I got to experience when it was new. It was impressive as heck. Then people started making modifications for it. Grappling hooks appeared early on, there were versions that had rudimentary vehicles. What a delight. The people who created some of the initial QuakeC mods ended up being pretty prominent game developers.

At any rate, I found a Quake BSP import plugin for Blender and that unlocked some exciting new possibilities:

“Eternal Dismemberment Complex” by Kevin Shanahan aka Tyrann as seen in QuakeSpasm “Eternal Dismemberment Complex” by Kevin Shanahan aka Tyrann

Quake levels had a theme alright. Classically the palette of Quake has been described as "brown-ish". Still it beats the stuff I could create at the moment.

Quake Level in SceneKit

There's no lighting implementation at the moment so everything gets the same degree of light.

Particles

The next thing I wanted to sort out in my project was a way to have weapons. I figured why not make use of the particle system in SceneKit for this end:

A particle system can perform limited collision detection and resolution with geometries in the scene. If a moving particle intersects a geometry attached to one of the SCNNode objects in this array, SceneKit resolves the collision, either by removing the particle from the scene or allowing it to bounce off or slide along the geometry’s surface.

So I setup a simple scene to work with:

A simple particle systems test scene in SceneKit, featuring a white cone emitting red cubes towards a large green cube, passing through it

So I want those particles to stop at the green cube.

A simple particle systems test scene in SceneKit, featuring a white cone emitting red cubes towards a large green cube, stopping at it's surface

Now I need to be informed that they have collided with the cube.

![A simple particle systems test scene in SceneKit, featuring a white cone emitting red cubes towards a large green cube, which is on fire or exploding

Haha. Neat. (The cube “explodes” after getting hit by 10 particles.)

Truly we're cooking with particles here.

Next up, try it with the model I have created:

A simple particle systems test scene in SceneKit, featuring a white cone emitting red cubes towards a green Marten model A simple particle systems test scene in SceneKit, featuring a white cone emitting red cubes towards a green Marten model, which is on fire or exploding

Let's make it complicated

I had working particle collision and detection, but when you're only dealing with a single object it's very easy to know which object was collided with. In what I was imagining you'd have multiple enemies at any given time. So it was key to figure out which object was getting hit.

I am only informed of where the collision happened, so my first solution was to just iterate through all the objects that could be hit, and see if that position was within their bounds. That worked well enough:

A simple particle systems test scene in SceneKit, featuring a white cone emitting red cubes towards many green Marten models, some of which are on fire or exploding

A simple particle systems test scene in SceneKit, featuring a white cone emitting red cubes towards many green Marten models, some of which are on fire or exploding

Then I considered how it would work in reverse. I added a target for my enemies to shoot at:

A simple particle systems test scene in SceneKit, feautring many green Marten models, rotated and firing towards a white sphere

A simple particle systems test scene in SceneKit, feautring many green Marten models, rotated and firing towards where a white sphere was

Neat.

Spin, Spin, Sugar

Things were working great with just one target, but adding a second target caused some problems:

A simple particle systems test scene in SceneKit, feautring many green Marten models, and two white spheres

They should be attacking the closest target, but it's not working. I had to spend some time figuring out how to make sure that the model was correctly rotated to face the target.

A simple particle systems test scene in SceneKit, feautring many green Marten models firing at two white spheres

A simple particle systems test scene in SceneKit, feautring many green Marten models firing at where two white spheres were

Much later, after figuring out the dot product I was able to have a Marten accelerate towards a target, reach a specified range, stop immediately, and start shooting:

A Marten model that has moved towards a white sphere and is firing at it

Adding things back in, I get a scene with multiple Martens rotating, moving, and firing: Scene with multiple Martens rotating, moving, firing at white sphere targets

It's a bit chaotic, but I like it.

Scene with multiple Martens rotating, moving, firing

States

The way I was trying to organize the behaviour of my enemies was into states, specifically I had

So initially the Marten would be in the RotationState, turn to face the target. Then it would transition into the PursuitState which would cause it to accelerate towards the target, until it reached a specific distance, and then transition into the attack state.

Rotation:

A Marten rotating to face the white spehre target

Pursuit:

A Marten moving towards the white sphere target

Attacking:

A Marten firing at the white sphere target now that it is in range

Adding this back in allows the multiple version to work, and since they have a physics body they collide with each other:

Many Martens rotating and firing Many Martens rotating and firing, after some have colided together

Teams, Red, Blue, Green

One easy way of re-using assets is to give them different colour schemes. Perhaps the green versions are the standard version, and red would be for an elite or stronger version. So I wanted to see if there was an easy way to add some colours:

A Marten model in Blender, except now it's blue and gold

This allowed me to try out a version with different coloured versions:

Scne with red, blue, green martens rotating, moving, and firing

Then I organized them into teams, and had them attempt to engage each other:

A scene with teams of  3 blue, 3 red, and 3 green Martens engaged in combat with the other teams A scene with teams of  3 blue, 3 red, and 3 green Martens engaged in combat with the other teams A scene with teams of  3 blue, 3 red, and 3 green Martens engaged in combat with the other teams

I was quite pleased with how this was working. It was time to finally get back to my original project instead of my simple test case:

A blue Marten in my level scene

It worked and it didn't cause everything to immediately explode. Great. Next up a new map design.

Friends, Foes, Frenemies

2024-01-28

Having conquered "doors", I decided to move on to a new problem. Enemies.

Love them, hate them, know that they're always plotting your demise.

Turret object as seen in Blender

The lack of depth in this is a bit tricky, but the yellow portion is the fixed base. The red section can rotate freely allowing left/right directions. The green which would also be the business end of the weapon, can swivel up and down. A 2-axis pan/tilt system.

Turret object in Blender, now with shadows, shading

Turret object in my game scene

You can see the small-ish turret in the game scene. I need to fix the normals on the yellow base so they are properly pointing outwards. The blue/teal sphere was part of my initial solution. I was going to apply a constraint to the it that it was always looking at the player's ship. Then I could just take each individual rotation and apply it to either green or red, so that I didn't need do to the math myself.

That didn't work out so great, so I had to figure out the math:

blender_scene_for_math_purposes

That’s the top down perspective of my Level Zero. I need to at all points figure out what the angle is between the selected object (my turret) and the ship which is located at (1,1,0). This view is directly on top so you do not have any indication about the Z axis which is the height.

I need to figure out what angle I need to rotate so the red section is facing the ship. Trigonometry to the rescue. Then I do the same thing to figure out the relative height difference for the green section.

α = arctan((turret.y - ship.y ) / (turret.x - ship.x))

Great. Then for my green object I care about the X and Z axis as I need to know how far, and what the height is.

α = arctan((turret.z - ship.z ) / (turret.x - ship.x))

I have to take in to account things like scale and rotation, but there are things designed to do that for me. Let me give this a go.

Turret object, tracking the ship Left is the turret aimed at a space where the ship was. Right is after it has been told to point at the ship.

I can animate it as well and it looks pretty cool.

Bones

I spent a decent amount of time trying to figure out how I wanted the turret to work, maybe I'd give it legs so it could scuttle about. After spending some time looking into how you'd get animations working in SceneKit and exporting those from Blender, I decided to move on.

I returned to what Descent has for enemies:

Enemy from the game Descent

That’s a model of an enemy from one of the Descents.

It doesn’t have articulated moving animations, it just floats and shoots at you.

I thought the turret route would be easy, but adding legs was probably not the way to go.

Naming

I decided that I was going to name all my enemies after Mustelids, your weasels, badgers, otters, ferrets, minks, wolverines, and martens.

Marten model in Blender Behold the Marten, it’s just a boxy thing with guns, but sometimes the classics are best.

Marten in level

I might have to scale it up, but it shows up. There’s just two on the map right now. I think once I can get them to orient towards me, which might be really easy since I just need to turn the entire model not worry about discrete components. I did leave the “weapon pods” their own nodes so I could in theory tilt them up/down and to the left/right if I thought that would make things look better. Actually the small size will help with that, because they almost always can just fire directly forward if they’re smaller visually.

Many Martens in the void Many Martens in the void, now with tracking

I wrote at the time:

It’s very cool to see them slowly rotate to face me based on the animation duration and when it updates. I can at this point figure out how I want the firing animation to look like, and because they’re facing the ship I can have them fire “forward” and I get to go home early.

Light, as a weapon

The other thing you need to be an effective enemy, ostensibly on an asteroid mine, is a powerful laser weapon.

SceneKit has particles that I made into an effect:

SceneKit particle system that looks like "laser beams"

Which allowed me to add them to the Marten:

Many Martens floating in the void, before shooting Many Martens floating in the void, after shooting

Applied to the Marten already in the level: Marten, in level, shooting

And I made the laser more additive and added some orange tones:

Marten, in level, shooting, new orange beams

The one thing I quickly identified was that having four weapon barrels was a tremendous mistake on my part. I should've kept it at two.

Door Installation Professionals

2024-01-25

I created some new materials for both the door frame and the door segment materials.

Screenshot of Blender with multiple door frames and segments displayed

I wasn't sure of the best way to add the doors into my level. I could add them individually to the level as part of the level geometry so the level was complete, or I could add nodes that would be spawned/replaced with doors.

I opted to go with door spawning:

Door object in my level

Just need to apply some scaling to get it to fit the entire corridor.

Door object in my level, stretched

The object I was using to represent the door in my level was a 1x1x1 cube, but the door I have created is not 1x1x1 in dimensions. So I adjusted the placeholder object so it would scale properly:

Door object in my level, with new scaling

Not exactly what I was hoping for, but fixable.

Door object in my level, with new scaling, fixed

The other problem I was attempting to solve was how to store Door metadata. I am still treating Blender as a level editor, so why not make it the place where these things are defined.

Blender door properties

This allows me to configure everything in Blender, and then it will be read by my game to configure things like the door frame material, if it's locked, requires a key, or how many segments it has.

Doors with various number of segments (1-4)

A door with "3 segments" is just a 2 segment door that opens horizontally, whereas the one with 2 segment is the one that opens vertically. I worked on readjusting the segment materials and updated my game so that it would randomly select a door frame material and a segment material.

Door in level with random segment material

I also attempted to indicate that if a door requires a specific key, by adding a colour to the material:

Door that requires the Gold key

It doesn't look great, but I figured I would solve it later. The other issue I wanted to address was how you opened the door, previously you had to collide with the door for it to open. I added an additional area before/after the door that allows the door to open before you intersect with it.

Door with a purple transparent area indicating the trigger

Just entering the purple zone will open the door.

Having doors that open properly and have random material selection allowed me to create a hallway of doors:

Blender screenshot of many doors in a line

Which looks like this:

Video of the many doors opening

My own version of the Get Smart intro.

Heart in a Blender

2023-11-25

After my success with the concept of doors, I decided to embark on creating a level in which to have potentially many doors.

textured level with the Ship model

Gotta say, the darkness gives it a bit of a vibe.

textured level with two Ship models

I also added a way to create/instantiate the Ship from another scene entirely. This lets me attempt to keep things separate, any changes I make to the ship do not require me to update the level, or vice-versa. Previously the Ship object was embedded inside of the level. Unclear as to why the floor is so eye searingly red.

I also added some additional cameras on the ship, including one on the inside.

view from the inside of the ship model, looking out

view from the inside of the ship model, looking out, with a fixed texture that is not displaying on both sides

textured level with two Ship models, and a new stone floor texture

Floor textured replaced.

Looks like the carpet of a Dentist’s waiting room, but I think we can all agree: not red.

Great, now what I need is to make an elaborate door.

textured door object, seen in Blender with the Ship model

I was quite impressed with how proper textures with depth maps looked in Blender. My plan is to slice the door into 4 segments, so that I can move them independently to create different door effects.

door with a frame, in Blender

I added a door frame!

door with a frame, in Blender, opening by having the 4 segements move away from the center

door with a frame, in Blender, opening by having the 4 segements move away from the center

That's one way the door can open, but the same idea will be used for hanger and "super market entrance" doors.

Semi Permeable Membranes

2023-08-25

You know what you need to separate two areas with? Doors.

SceneKit scene with a door concept, made up of 4 rectangular boxes for the door, and a torus for the frame

I created 4 rectangular boxes to represent the door itself, and a torus to act as the frame. The reason I created 4 of them was so that I could move each independently. Early games would just move the door upwards, like a garage door. I could do that by moving all 4 boxes up. Or I could open from the middle by having the top 2 boxes go up, and the bottom 2 go down.

door in its closed state door in its opened state

I was surprised at how quickly this came together, and it works in reverse to close. I added some extra doors, and since my weapon removes things from the scene, I demolished some door segments:

3 doors, two of which have had their upper and bottom door sections destroyed

Attempting to navigate this just with keyboard controls was getting a bit tedious, so I added in mouse aiming, which doesn't really look much different from the perspective of a screenshot.

SceneKit scene after adding mouse control

Also, since I had some doors why not add some walls to the place:

level_concept_hallway

level_concept_door

level_concept_door_open

Also since I was having to deal with creating a level, why not replace the rather nice default SceneKit model with something that better suited the place:

prototype ship model, with textures applied

I had somewhat also figured out how textures worked, so I decided to spruce up everything:

prototype ship model, in the level prototype, all with textures prototype ship model, in the level prototype, all with textures, firing the weapon

Up next is refining these concepts into more sophisticated versions. I was very excited to see what I could do with the doors.

Get Smart introductory credits, the famous hallway of doors

Adventures in Particle Generation

2023-08-16

I'm actually going to skip over a chunk of time I spent trying to figure out controls and physics interactions. Skip to implementing some sort of weapon system.

It's actually pretty easy to add a Particle System in SceneKit:

SceneKit scene with a model emitting square particles

They didn't actually do anything other than stream forward, but you have to start somewhere. I figured I'd want to make them look more like "Plasma Balls" since that's what I assume you'd fire as a particle.

SceneKit scene with a model emitting a plasma ball inspired particle SceneKit scene with a model emitting a plasma ball inspired particle, but better somehow

Excellent. One issue I found is that by adding the Particle System to the model itself, meant that the particles were generated in the centre of the model and therefore had to travel through the front half of the model before becoming visible. Created an invisible node and placed it in front of the "nose" and it works like one would expect.

The next problem was how to handle interactions between the weapon and the things you'd be shooting at. My first solution was to just determine if there was any object between my weapon and a distance x in front of it.

I added some targets to my testing scene. I was attempting to keep to a colour scene. Anything blue I figured you should be able to shoot.

A SceneKit scene with multiple simple 3D objects

A SceneKit scene with Blue capusules that represent targets

And after firing the weapon a couple of times:

A SceneKit scene with Blue capusules that represent targets, after firing the weapon

One thing that caused me some issues here was that as soon as you fired it calculcated what in the path, and removed it from the scene. It worked for the time being, which was enough to move on with.

Well well well, if it isn't E1M1

2023-08-15

I spent much time trying to figure out how my controls should work, and how they'd work in my project.

Ultimately this allowed me to take the default SceneKit Jet Model and bring it to an old familiar haunt, Quake's E1M1:

SceneKit Jet Model inside of Quake's E1M1 in SceneKit

The controls were a bit disjointed, and would sometimes cause the model to spin wildly, but I could still fly around the level. Which was very neat. I've spent a lot of time inside of that level, for one reason or another, so it was exciting to go back and see it. In a fresh new globally illuminated way.

I also marvelled at the ease at which you get real-time reflections:

The SceneKit Jet Model underneath a red torus, which is being reflected off the top of the model

Out of Control

2023-06-18

The SceneKit editor showing a scene with multiple simple objects, red torus, green cubes, and blue spheres

Elsewhere, I was attempting to get working controls/movement system.

My plan, at the time:

The green cubes would be solid and you’d “bounce” off those, but you collect the blue spheres.

That seems like a reasonable and approachable goal.

I am unsure what the red torus will do, just sit there and look cool I suppose.

I'm always a big fan of setting reasonable and approachable goals.

Collision, detected

This was a great opportunity to learn more about the physics system that SceneKit gives you access to.

You can assign a “Physics Body” to a SceneKit node, and then it can be subject to various forces including gravity. There are three properties relevant to collisions/contact.

The category mask represents what type of object it is. Since we’re dealing with bitwise operations, it means that each unique value has to be a power of 2.

Entity Decimal Power of Two Binary
Level Geometry 1 2^0 0001
Player / Ship 2 2^1 0010
Enemies 4 2^2 0100
“Power Ups” 8 2^3 1000

So, for example my PlayerShip is setup this way:

Mask Value (Decimal)
Category 0x0010 (2)
Collision 0x0101 (5)
Contact 0x1000 (8)

So the physics system will have my physics body collide (resulting in the node stopping or bouncing when encountering the body it's colliding with), or generate a contact event indicating that I have run into a collectible power up.

Things like, to be inspired by Descent again: A list of powersups from the Descent manual

And so, with a couple of things in place, I was able to test things out:

The SceneKit scene with the Jet Model showing the red torus, green cubes, and blue spheres

The SceneKit scene after the physics body has collided with the blue spheres, and they have been removed from the scene

That's what the scene looks like after I have "collected" the blue spheres. The model bounces off of the green cubes.

World Building

2023-06-13

The SceneKit starter jet model, inside of a 3D object that I created

From my notes at the time:

I managed to create two adjoining spaces connected by a cylinder. Some parts are inside out because of... reasons. I’ve tried to apply a “Concrete” material to the cylinder, but it mostly just looks grey.

I think I could’ve textured these things, but that’s a complication I don’t want to deal with at the moment.

The inside out nature is due to the normals being in the wrong direction. A constant bane!

Why not just use a Quake map, I say?

In my attempts to make my life easier I found a way to import Quake 1 maps into Blender.

E1M1 from Quake, in SceneKit

The Slipgate Complex is the first level of the Dimension of the Doomed. The level serves as a relatively gentle introduction to the gameplay of Quake (even on harder skill settings). It consists of two buildings with a small River) between them. The smaller building is where the player starts and it is relatively safer. The larger building is where most of the action takes place - it features several larger rooms, a large Slime) pool, and a series of platforms above it.

https://quake.fandom.com/wiki/E1M1:_The_Slipgate_Complex

E1M1 from Quake, in SceneKit

The textures are from a project to upscale the original Quake 1 textures. The lighting is also enabled, but it was neat to see.

E1M1 from Quake, in SceneKit, with the SceneKit starter jet model

Eventually I added in the jet model that you get from the SceneKit starter project. I was able to fly through the level, which was pretty exciting.

Best laid plans, undone

2023-06-06

The first thing I wanted to sort out was going to be some way of handling interactions between my "level geometry" and the player. There's a lot of ways to solve that set of problems, but I endeavoured to make SceneKit's problem so I didn't have to deal with it.

A SceneKit scene that has the default jet model, and two simple objects

A SceneKit scene that has the default jet model, and two simple objects

The base object in SceneKit Scene is called a SCNNode

A structural element of a scene graph, representing a position and transform in a 3D coordinate space, to which you can attach geometry, lights, cameras, or other displayable content.

So I've created two new nodes, given them the geometry of a pyramid and a sphere. They also have a physics system which means that when the jet model collides with the pyramid, it causes the wing to lift up. Or when the jet model collides with the sphere, it rotates.

Great. Excellent.

Levels, Mapping

One problem though, is that a game world populated entirely with spheres and pyramids is only so compelling. I need to be able to create arbitrary structures or layouts.

A screenshot of a Blender window, showing a two cubes joined by a corridor

The last time I spent any time with a 3D Modelling application was quite some time ago, and I preferred Modo. However in the intervening span of time, Blender has become the de-facto modelling application for people who do not have some reason to use things like Maya or the other high quality and very expensive applications.

It works though, surprisingly.

A SceneKit scene that has the default jet model, and two simple objects, and the model from Blender

The jet model dutifully bounces off the walls. I now have a way of creating things in Blender and making use of them in my project.