Kekouan

Wherein, we handle events

2024-10-30

Firing while moving Continuing to fire while moving

In my new level it quickly became apparent that there was an issue where I could not shoot and steer at the same time. I just needed to handle a mouseDragged event in addition to the mouseDown (fire), mouseUp (stop firing) and mouseMoved (aim).

Hey! I'm patrolling over here

Okay, got a new level, need some enemies. So I added my existing Marten enemy into the scene, and it immediately slams into the player at high speed. Which is fun, but only so much.

Initial enemy in new level

A note on being Goal Oriented

The way GameplayKit works is that you have agents, and you give them goals

As Apple describes it:

In many kinds of games, entities move in real time and with some degree of autonomy. For example, a game might allow the player to tap or click to move a character to a desired location, and the character will automatically walk around obstacles to reach that location. Enemy characters might move to attack, planning to intercept the player character ahead of its current position. Ally characters might fly in formation with the player character, maintaining their distance from the player character and a parallel direction of flight. In all of these cases, each entity’s movement might also be constrained to realistic limits, so that the game characters still move and change direction realistically.

https://developer.apple.com/library/archive/documentation/General/Conceptual/GameplayKit_Guide/Agent.html

Implementing Patrol Behaviour

The first thing I was able to do was to add a "wandering" behaviour.

Enemy wandering behavior Enemy continuing to wander

To actual get things to patrol, I had to combine the path following goal with a speed goal.

// Create path following goal
let pathGoal = GKGoal(toFollow: path, maxPredictionTime: 1.0, forward: true)

// Add speed maintenance goal
let speedGoal = GKGoal(toReachTargetSpeed: desiredSpeed)

// Combine goals with appropriate weights
agent.behavior = GKBehavior(goals: [
    pathGoal.withWeight(1.0),
    speedGoal.withWeight(0.5)
])

This resulted in enemies that could patrol a path:

Enemy following patrol path Enemy continuing along path Enemy completing patrol route

Path Visualization and Refinement

To help with path creation and debugging, I added visible markers along patrol routes:

Path visualization with cubes

This helped identify issues like path clipping through geometry, which could be fixed by adding additional waypoints around obstacles.

Final Results

The completed system allows enemies to smoothly patrol predefined paths while maintaining the ability to engage targets:

Blue Marten patrolling Blue Marten continuing patrol Blue Marten turning corner Blue Marten completing patrol

And if you add a camera to an endless patrolling enemy, you get a neat screensaver effect. This is after I redesigned the weapons on the marten so that instead of two "pods" with two barrels, it's two much larger single weapons. That they look like RCA connectors is merely a coincidence.

Screensaver-like patrol movement

Getting ahead by using someone else's work

2024-07-28

The large open map I had created to work on things in a "deathmatch" setting was starting to get on my nerves. It's too large, too symmetrical, and hard to orient yourself in.

Rendered version of OpenMap, which is a large circular map, with a column in the middle, and raised concentric rings for the floor. Lots of colours.

This could be address/fixed, but why do that when you can do something else. I went looking for Quake deathmatch maps, which I knew there would be an extensive collection. What I found was a bit surprising, people are still making Quake maps in this day and age?

It makes sense from the perspective of how popular Quake is/was, the continued support of its file formats by the various open source engines that implement them, and effectively how they set the tone for all things to come after.

jam2_tronyn.bsp

The map jam2_tronyn.bsp running inside of SceneKit, with no advanced lighting or shadows

jam2_tronyn by tronyn, part of the “Func Map Jam 2 - IKBlue/White Theme

The lights sorta come across, but not really. So this is not how these would look in a proper Quake engine. You can watch someone speed run it in 1 minute and 42 seconds and see that it's pretty moody.

jam2_lunaran.bsp

jam2_lunaran

jam2_lunaran, by lunaran, part of the “Func Map Jam 2 - IKBlue/White Theme

This other map, also from the same map jam, was very cool. It's a castle-y structure inside of a volcano-y cave.

It's what I would continue to use for all of my testing and prototyping.

What about a nice shade of blue?

2024-07-21

I got the notion that I should see how to handle a situation in which there would be multiple teams. So the first thing I needed was a variation on a theme.

A blue Marten model, in Blender

I opted to just change the "body colour" and the "eye colour" of the models. So I ended up with a blue/yellow, red/yellow, and the original green/red combos.

a scene showing off many coloured Martens attacking and shooting weapons at each other

I ran into an issue pretty quickly though, and which took me quite a while to figure out a solution to. I was originally removing/deleting any object that "died". A little showy explosion effect and then removed from the scene. This caused issues with the particles they had interacted with, and the targeting system. This would often also result in a crash due to attempting to perform an operation on a null object.

I tried to mark things as deleted and clean them up in a future iteration of the game processing loop. This didn't work as it typically wasn't just the current update that was at issue. Then I finally just marked them as "deleted", stopped processing them, and hide their models.

This is one of the things that is generally handled by a game engine, and I couldn't implement a great solution at the time.

a scene showing a team deathmatch between teams of Martens

a scene showing a team deathmatch between teams of Martens

a scene showing a team deathmatch between teams of Martens

Problem 2, spacing

The weapons on the Marten model are just attached to the side. They point directly forward. This wasn't an issue when they were attacking me, as the player ship was a very large rectangle. However, if they were now attacking a model that was the same shape as them, they would fire past the central body.

The solution to this was a bit easier, since I had created each "pod" as it's own object. I'd just have them rotate to face whatever it is they are firing at.

Martens firing at other Martens, and missing

Once they could rotate their weapon pods, it worked quite well.

Martens with rotatable weapon pods

Martens fighting other Martens, now successfully ignored by the scene when destroyed

Martens fighting other Martens, now successfully ignored by the scene when destroyed

the final result, Martens exploding

The large map I had created for this had 4 sections, so I added the player as an additional team.

Player ship getting attacked by the Green team, while the Red and Blue teams attack each other

I had successfully created some enemies that would seek out and attack the player (or another entity on a different team). Next up, putting this all into a single player level.

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