Player navigation system

Hi All,

Lets start with some preconditions:

  • I have a level build of cells (like a chess board)
  • each cell can have some object on it (let’s say it could be coin/med kit/armor/weapon)
  • also I have a player that can walk on this level and interact with objects on cells

For processing the gameplay I want to implement set of systems and interaction between them in a generic way.

I have two thoughts how to do this:

  1. Implement a data structure that will represent a level description (matrix of cells with information about cell type/object on it/etc). This data will be stored in a separate module. Player controller can ask this module about nearest cells and possibility to step on them. One more module can monitor player’s position and other objects’ position. At the moment when player steps on cell with some object then appears a trigger and player picks this object.
    Here I tried to follow “less coupling” principle and be more abstract from UI side. But I have to write good central storage module and maintain board state after every player’s move.

  2. One more option is to be more “UI related”. I mean I can use raycast to check the nearest cells and trigger whatever logic I need in this way. But here player have additional knowledge about the environment around.

Which option is better? Or maybe both are wrong, if so then please let me know how can it be done better.

Thank you.

Option number one seems pretty plausible.

what are your doubts?

Option one sounds like regular solution applicable for any similar system (not game), but option two - more gamedev oriented. Here I just wanted to understand the best approach for particular example.

I’d go with 1 every time for a game like this. You have a very simple game world with no simulation of any kind, so make that in pure code. Use Unity to create a view of that world for you.

The cool thing here is that you can write automated tests for the game world easily. That’s something that’s really hard in a game that centers around Unity’s Update loop and physics interactions.

2 Likes

And what about second approach? When it can be useful?

The fact you have “cells” makes me want to avoid raycasting. I have a game 10k Tactics that uses hex tiles. Checking 6 neighbors is pretty easy to do with data. (I do use raycasting to figure out which tile the player is pointing at, but that’s it.)

I would use option 2 more for action games where you don’t have “cells” but instead a range of x, y, and z coordinates to deal with. You can’t possibly check every (x, y, z) around an object, so we deal with ray casts and box colliders and stuff like that to separate out just a part of the 3D world.

So if there are just a few neighbors or anything with “cells”, option 1. If things can be placed at any (x, y, z) coordinate, then I would use option 2.

1 Like

Do you mean that it is useful when we really have flexible camera that can point on any object around the player, right? Like in regular shooter where you have to take care not only about movements but enemies in 3D world.

Yep.

I think of option 2 as a variation of option 1 where every possible Vector3 is it’s own “cell”. A 3D cube has many many Vector3s in it. But we don’t list every Vector3 that is inside a cube because there are too many! (Billions? Trillions? I don’t know but it’s a lot!)

Instead of trying to track trillions of “cells”/Vector3s, we use equations instead. If a range of cells/Vector3s make our equations true, then we can group those cells/Vector3s together. If the equations are false, then those Vector3s are ones we don’t care about. We are eliminating or adding entire ranges of Vector3s. We are using equations to carve out the “cells” aka Vector3s, that we care about. Eg: A BoxCollider is really just some equations to determine if a Vector3 is inside or outside. A Raycast just determines what Vector3 is both on a line and on the near surface of a collider. Note: A “range” of cells/Vector3s could be a single cell/Vector3. You have a lot of freedom in 3D space.

Additional Note: Having access to the entire 3D space is usually bad game design. Most games will restrict where the player can go inside 3D space. Even AAA games like The Division do things like not allow jumping, generally to restrict the amount of math that the devs have to figure out. Doing lots and lots of 3D math can get hard, complicated, buggy, and time consuming quickly.

By going through Option 1, you GREATLY reduce the number of cells (Many Trillions vs Dozens) which makes things much simpler.

1 Like

btw, it’s generally a good thing to separate data out. Even when I’m using raycasting to run some game command in a shooter, the game command changes data. How to display that data is done separately.

1 Like

I have one additional question regarding 1st option: level descriptor will hold information about cells but still to interact will objects on cells (player can pick something from it) I have also to store rendered level somewhere.

I was thinking about extending level descriptor with additional information in form of references to GameObject that represents the cell. In this case I will have a single storage of all I need: cell description and rendered cell object.

The only doubt I have here is that I will mix metadata and data. What do you think?

No, I decided to do another architecture:
LevelDescriptor - with metadata
LevelRenderer - with game objects, etc
ItemManager - will handle player movements and then check LevelDescriptor is any objects available to be picked and inform LevelRenderer so suitable animation to be played
PlayerController - on move will inform: LevelDescriptor that metadata must be updated; LevelRenderer that anumation and moving must be performed; ItemManager that move was done and it must be handled