(September 2024) Monthly WIP Screenshot Thread

Calculated the walk direction vector for the character control and made the player the target. So the enemy now follows the character for attack.

2 Likes

I finally implemented the Save/Load game feature in my FPS framework.
It took some effort but thankfully at the end it wasnā€™t as troublesome as I expected.
I chose to use javaā€™s serialization for simplicity, I know it has some issues (mainly security vulnerabilities) but I donā€™t expect or recommend people to share or download save files from unreliable sources.

In my framework entities have three parts:

  • Spatial: I serialize a factory object for each spatial (usually loads a model from a file).
  • Physic Object: I take advantage jMEā€™s Savable implemented by Minieā€™s PhysicsCollisionObject and serialize them (most are simple capsules or box collision shapes).
  • Behavior: The entities behavior is scripted in groovy by implementing my EntityBehavior interface, I extended Serializable and forced all scripts to be serializable (had to make some fixes, but most scripts have simple logic anyway).

For the level map (itā€™s an entity) I omitted it in the save file and instead save which level(s) are loaded.
Then in the load process I load the level without spawning its entities, then spawn entities as I continue reading records from the file.

With all that I didnā€™t have to dump any mesh buffer, so the file is acceptably compact (around 200kb for 100 entities).

I implemented all the strictly functional parts but I still miss some things, like active particles, decals and playing sound effects. These are not as important but are nice to haves, depending on how hard or slow to load they are.

I split the video in two parts, first showing the normal save and load and then showing a multi-level setup, the two rooms are two different ā€œlevelsā€ in my game, so I can support Hexen like multimap hub levels and keep the whole state, not just the active level.

8 Likes

Be careful with java serialisation. I used to do my save game formats that way but i found them very difficult to retain compatibility of the save file between game versions (changing the java classes would make the binary file incompatible with limited options for migration). (I think the jme capsule system might be nore resistant to that problem)

2 Likes

Yeah, thanks for the heads up! I considered it but I decided to ignore backward compat for the time being.
I know how much work it is to maintain data models from my work and since this is my hobby I want to keep the complexity low and focus on making games.
I donā€™t expect to have that many players at the same time I deliver updates, and if that happens Iā€™ll make it easy to skip levels to recover progress.

1 Like

There are many options if you plan aheadā€¦ but yes, Java serialization is not great for code that is still influx.

I think all of the ways you can fix something in JMEā€™s capsule system, you can fix them in Java serialization. They will both ā€œbreak completelyā€ under certain types of changes.

Java serialization is a lot more flexible than many realize.

Edit: and I would never in a million years replace Java serialization with JMEā€™s binary capsule. There are perhaps better ways to do save games than Java serializationā€¦ but JMEā€™s approach is definitely not one of them. Itā€™s effectively a ā€œnot invented hereā€ version of Javaā€™s serialization thatā€™s only original ā€œhigh claim for existenceā€ was being able to target XML as well as pure binary.

Otherwise, it has all of the same limitations as Java serialization (and perhaps a few more).

1 Like

Interesting, ive never used the capsule system so was hedging my bets.

I typically serialise to json and use a library (jackson) to map to java DTOs. Which is relatively easy to begin with and gives me options to hand write deserialisation code if anything weird happens (and can transparently handle things like new fields). Obviously might have issues if the save file was huge

Yeah, I use JSON (google gson) if I need to read it or editā€¦ but use Java serialization for a lot of stuff. (For close to 20 years now.)

I have some custom binary formats, too, but for cases where I wanted to tightly control the size of the results. Java serialization is pretty compact and you can control the whole serialization of the data yourself, if you wantā€¦ but itā€™s always going to serialize class info and stuff.

I use Derby to save game states, high scores, key config, etc.

ā€¦yeah, a relational database is one way, too. Tends to be a little opaque for playerā€™s local save games.

I prefer hsqldb, personally.

In the gif the camera is moving up and down in the Y axis. The triangle moves clock or counter clock wise to match the camera position on the x and y coordinates. In other words the triangle looks at the player.

Iā€™m adding the ability for the enemy to rotate to look at the player.

Iā€™m currently using: Vectors, Trigonometry and Quaternions to achieve this. Iā€™m almost done.

Problems to solve:
undefined tangent at 90, -90, 270 degrees.
angles donā€™t go higher than 90 degrees.

Summary of things Iā€™ve completed in the last 7 days:

  • The CharacterControlled enemy follows the player.
  • The geometry looks at the player.
  • Used Breadth First Search navigate the enemy from point a to point b.

So in short, Iā€™m almost finished adding intermediate Ai to my game. :blush:

Didnā€™t use a third party Ai library, so I learned A LOOOT.

2 Likes

Frequently trig is unnecessary with steering algorithms.

Are you setting the object to look at the player instantly or will there be some physical limitations involved like rotation speed?

If you havenā€™t read about steering algorithms yet then I highly recommend. Tons of fun.

ā€¦and usually the inputs to a steering system can be done with only dot products.

2 Likes

Thank you for the suggestion.

But Iā€™m not currently looking for steering algorithms.

Time Stamp: 16m 37s. This shows the exact problem Iā€™m trying to solve. Though Iā€™m solving it even before I look at the video.

ā€œFrequently trig is unnecessary with steering algorithms.ā€ Even if that was the case I would still go the Trig route. Iā€™d prefer build my Math foundation with practice. Iā€™m very careful not to jump from internet article to internet article when looking for an answer. Iā€™d prefer to spot the solutions inside college textbooks, then as a laaaast resot I look at google and youtube.

ā€œAre you setting the object to look at the player instantlyā€ Yes, instantly. Maybe in the future I add turrets that take some time to look at the player. But right now Iā€™m exercising my brain muscles with: Vectors, Trigonometry and Quaternions. :slightly_smiling_face:

Trig is only nice because we get to see angles. Itā€™s just frequently an extra unnecessary math stepā€¦ trig to find the angle, some potentially dodgy angle math, then trig to turn the angle back into sin/cos again. So while itā€™s nice to ā€œseeā€ those angles, the math usually doesnā€™t need it.

The dot product will already magically provide the cosine between two vectors and it doesnā€™t worry about angle math, quadrants, or any of that stuff. Much less to go wrong. Thatā€™s why itā€™s good for steering algorithms because dot product = 0 means donā€™t turn. 0ā€¦1 means turn left, 0ā€¦-1 means turn rightā€¦ already nicely scaled by how fast to turn.

Even for ā€œinstant lookā€, trig is unnecessary as Quaternion().lookAt() will already do that. In the days before quaterions, weā€™d just construct the three vector axes and turn that into a rotation matrix. (A rotation matrix is just the three orthogonal axis vectors.) And so a ā€œlookā€ matrix is a vector and two cross products away.

So to me, itā€™s not really about ā€œmath foundationsā€ but using math not really suited to the task.

4 Likes

Yes. Thatā€™s a lot of math. It may be simple for you, but for a mere mortal like me Iā€™m not there yet. Iā€™ll get there eventually. But for now thatā€™s why I mention what I said.

Iā€™ve been meaning to create torch fire for some time, so here it is using the emitter.

Some gameplay itā€™s happening underground, so it makes sense to have torches light the way.

2 Likes

Are you trying to avoid using JMEā€™s Quaternion class? Like, to learn the basics or something?

You got me. Yes.

I try to understand things like Quaternion.lookAt() I donā€™t use it right now because Iā€™ll learn how to do it at some time.

But functions like the ones below I already know to how code so I use them in development.
Vector3f.normalize()
Quaternion.mult()

In short, if a class or a function is fundamental and I donā€™t understand it. I try to solve it myself. This doesnā€™t add to development time because I do it in off-hours. But itā€™s the only way I learn how to create games and 3D tools.

Itā€™s true.

From experience, invest a lot of time in vectors, dot product, and cross product. 90% of all 3D math can be done with just simple vector math, the dot product, the cross product, and the pathagorean theorem. (length()).

I spent a good deal of my life poorly grasping a ā€œwhole lot of mathā€ that I was able to dismiss by knowing the vector ā€œtricksā€. And it turns out that ā€œwhole lot of mathā€ was not helpful in the end.

Coming up, I spent a lot of time reading Michael Abrashā€™s books on graphics, 3D, whatever he wrote. (For you youngunā€™s, he was ā€˜the manā€™ when it came to performance optimization back in the early daysā€¦ and even worked for ā€˜idā€™ for a while to help John Carmack with the original Quakeā€¦ and wrote some nice books/articles out of that.) Between that and Foley and Vandam (still on my shelf), my head was swimming with stuff.

By then, I well knew about dot products because they were the magic that made Doom possible at all. Dot product and cross product are really simple functions to understand ā€œthe mathā€ but have so many magic uses that I feel like I still find new ones.

The day I got to throw ā€œthe restā€ away was when reading one of Abrashā€™s later books where he mentioned in passing ā€œIt just occurred to me that multiplying a vector by a rotation matrix can be thought of as 3 dot products with the axis vectors.ā€ That blew my mind. A matrix went from a magic thing to something I could read with my own eyes.

In modern times, it can be useful to get a sense of a Quaternion, tooā€¦ by turning it into a 3x3 rotation matrix and just reading it. Which is literally identical to:

System.out.println(q.mult(Vector3f.UNIT_X));
System.out.println(q.mult(Vector3f.UNIT_Y));
System.out.println(q.mult(Vector3f.UNIT_Z));

ā€¦the axes of rotation and a 3x3 rotation matrix.

If youā€™ve read this far, the math of the dot product is easy to understand (few multiplies and adds). What it means is:
v1.dot(v2) = v1.length() * v2.length() * cos(angle between v1 and v2 in 3 space)

You can spend a lot of very complicated math figuring out the ā€œangle between v1 and v2 in 3 spaceā€ā€¦ but itā€™s already right there.

When v1.length() == 1 and/or v2.length() == 1 (unit vectors) is where things get really interesting.

Maybe I should write an article.

8 Likes

Behold! My dear jmonkeys!

What I solved:
The enemy follows the player.
The enemy looks at the player.

To do:
Provide the position of the player when the enemy is far away via Breadth First Search.

Math used:

Vectors addition and subtraction.
Math.atan2(z,x). I think of this function as atan(rad) but it takes care of the edge cases.
Quaternion.

In case it helps others learn.

6 Likes

I personally find that learning calculus and applied linear algebra solves a major part of this problem and links the low-level mathematics with the algorithms you trying to use. Trigonometry is a very fundamental in itself, useful, but cannot be translated directly to data structures unlike vectors and matrices.