MoveArea Part 2

MoveArea, something I introduced in the previous post, is the system wrapped in an asset that allows me to draw lines (Line2D) to make a map. But it has grown quite quickly into something a bit bigger than that. It has to consider the 3 elements of movement, line-of-sight (LOS), and bullet-blocking (cover).

These are the aspects of the MoveArea and related systems.

  • Multi-height/deck – Characters are able to move from one deck to another, changing movement area, bullet and LOS blocking configuration.
  • Movement, bullet, LOS blocking – each Line2D can be configured to independently block these aspects.
  • The blocking types can be switched independently for each Line2D.
  • Vertical LOS blocking.
  • Thickness of Line2Ds are respected.
  • Joint mode of Line2Ds are respected.

MoveArea line creation

The Line2D shapes are converted to solid polygons, which are then called BorderLines.

BorderLines may be tagged (by naming convention) to define the purpose/s they serve.

The naming convention is:

{deck-level}-{blocking-type}={name}

Examples of naming convention:

This blocks all. BorderArea created for it.

    1-MLB=DeckA


This blocks LOS only. No BorderArea created.

    1-L=Bush

This blocks Bullets only. No BorderArea created.

    1-B=Glass


This blocks movement only. BorderArea created for it.

    2=DeckB
    2-M=DeckB

Movement blockers

When a movement blocker is drawn, MoveArea does the following:

  • Creates a StaticBody2D because Player is a KinematicBody2D using move_and_slide.
  • Creates a StaticBody2D to serve as a BorderArea. BorderAreas are placed in a special channel called MOVEAREA_CHECK_COLLISION_CHANNEL and its purpose is to determine if a Character has moved from one area to another. Characters, when they are created/spawned, must acquire the current MoveArea instance and register themselves, so that a ‘checker’ can be made for them in the BorderAreas.
  • Creates an extra Area2D object and groups it under “VBulletBlockers” and “VLOSBlockers”. This is used for vertical LOS, explained later.
  • It uses the specified deck level to put it in the appropriate collision layer bit.

Bullet and LOS blockers

When a either bullet or LOS blocker is drawn or specified, MoveArea does the following:

  • Creates an Area2D object, draws the polygons.
  • Groups the object into the “BulletBlockers” or “LOSBlockers” group.
  • It uses the specified deck level to put it in the appropriate collision layer bit.

There’s an arbitrary limit of 8 deck-levels for now.

LOS

The LOS system is composed of:

  • LOSTransmitter
  • LOSReceiver

These are attached to any Character that is going to need LOS capabilities. The Player also uses LOS, but with the same purpose as the robot enemies.

In any case, the LOS components belong to LOS_COLLISION_CHANNEL (e.g. bit 28) and it’s in that channel that LOS collisions are processed.

LOS by field-of-view

Enemy robots’ have a field-of-view that is always querying whether the Player is within it. When the Player is within FOV, the LOS is activated and rays are cast.

LOS exclusions/exceptions

Because all LOS components are querying the same collision channel, I’ve opted to use exclusions via groups. When MoveArea processes LOSBLockers and VLOSBlockers, it puts them into groups suffixed with the deck-level it has detected them in. For example:

VLOSBlockers-1
VLOSBlockers-2
LOSBlockers-1
LOSBlockers-3

The nodes are cached inside the LOSTransmitter, organised by deck-level so that it immediately knows which blockers are in which deck.

When Player is within the Robot’s FOV, LOS is enabled, and those exclusions are added/updated so that only the blockers that are on the same level as the LOSTransmitter will be considered by the raycast.

Vertical LOS

Vertical LOS presented some issues, which this image can help explain.

The blue line signifies an open edge on Deck 2 from which the Player can look out and down upon.

The green line signifies a wall in Deck 1, where LOS is being blocked.

In the image below, Robot is at the higher deck, and the Player has moved closer to the virtual wall. This hides the Player from a vertical LOS point-of-view.

If the Player moved further away from the Deck 2 edge, he’ll be seen.

This was done by measuring the distance of the viewer to the edge against distance of the edge to the target (i.e. Player). By assuming a certain height of the viewer and the target (no geometrical accuracy here, folks!), the minimum distance from which to measure from the edge before everything became visible; anything under that distance was invisible.

Reverse raycasting to ensure vertical LOS

There was still a problem with this. The Robot picked its closest edge and measured from there. But this comes up wrong when you have decks at the same level, as illustrated in this image.

The Player is on Deck 1, the Robot is on Deck 2 Right, and there is a Deck 2 Left, which blocks its sight to the Player. When the ray is cast it picks up the Deck 2 Right’s edge, measuring the distance from there, which is wrong.

Instead, it should be picking the edge closest to the Player. I reversed the direction of the cast, and the 2 small white line marks indicate both results.

It is usually sufficient to compute VLOS from the nearest edge, though I noticed that checking both yields more expected results.

How to cast multiple times with Raycast2D

As an aside, there is a way to cast with Raycast2D multiple times within a frame. In the case above, I had to set a new position for the caster, and then set a new ray direction. This involved a transformation and a ray update.

Thus when moving the Raycast2D, you must use force_update_transform()

extends Raycast2D
...
set_position(new_position)
force_update_transform()

And then a new direction needs to be cast:

set_cast_to(new_ray_direction)
force_raycast_update()

Mind the original settings.

Bullets, BulletBlockers, VBulletBlockers

BulletBlockers stop Bullets as long as the Bullet is in the same deck level as the blocker.

It is the Bullets (Area2D) that use their area_entered signal to detect whether they’ve entered a BulletBlocker node.

Bullets vertical LOS using the idea as VLOS.

However, at this time, though I am getting the expected results when the Player is shooting from above, it doesn’t work so well, when the Player is below.

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.