Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 16 additions & 5 deletions docs/api/cpp/game_state.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,8 @@ Description of the object in the labels buffer.

**objectName / object_name** - ingame object name, many different objects can have the same name (e.g. Medikit, Clip, Zombie).

**objectCategory / object_category** - category of the object (e.g. "Monster", "Weapon", "Player"). Category "Self" is assigned to current player.
**objectCategory / object_category** - category of the object (e.g. "Monster", "Weapon", "Player"). Category "Self" is assigned to current player.
The category assigment may not be accurate, especcialy for custom objects and WADs other than Freedoom/Doom. Note: added in 1.3.0.

**value** - value that represents this particular object in **labelsBuffer**.

Expand All @@ -89,7 +90,9 @@ See also:
(`C++ type / Python type` **name**)

- `unsigned int / int` **id**
- `int / int` **sectorId / sector_id**
- `std::string / str` **name**
- `std::string / str` **category**
- `double / float` **positionX / position_x**
- `double / float` **positionY / position_y**
- `double / float` **positionZ / position_z**
Expand All @@ -102,12 +105,17 @@ See also:

Description of the object present in the game world.

**id** - unique object ID.
**id** - unique object ID. This is the value referenced by **Label.objectId / object_id**.

**name** - ingame object name, many different objects can have the same name (e.g. Medikit, Clip, Zombie).

**category** - category of the object (e.g. "Monster", "Weapon", "Player"). Category "Self" is assigned to current player.
The category assigment may not be accurate, especcialy for custom objects and WADs other than Freedoom/Doom. Note: added in 1.3.1.

**sectorId / sector_id** - ID of the sector the object currently belongs to (same as corresponding **Sector.id**). Note: added in 1.3.1.

See also:
- [`DoomGame::setObjectsInfoEnabled`](./doom_game.md#setsectorsinfoenabled),
- [`DoomGame::setObjectsInfoEnabled`](./doom_game.md#setobjectsinfoenabled),
- [examples/python/objects_and_sectors.py](https://github.com/Farama-Foundation/ViZDoom/tree/master/examples/python/objects_and_sectors.py).

Note: added in 1.1.8.
Expand Down Expand Up @@ -141,12 +149,15 @@ Note: added in 1.1.8.
### `Sector`
(`C++ type / Python type` **name**)

- `double / float` **floorHeight / floor_height**
- `unsigned int / int` **id**
- `double / float` **floorHeight / floor_height** - Note: before 1.3.1 the value of floorHeight was inverted (negative). The bug was fixed in 1.3.1.
- `double / float` **ceilingHeight / ceiling_height**
- `std::vector<Label> / list` **lines**
- `std::vector<Line> / list` **lines**

Description of the sector, part of the map with the same floor and ceiling height.

**id** - unique sector ID. This is the value referenced by **Object.sectorId / sector_id**. Note: added in 1.3.1.

**floorHeight / floor_height** - height of the sector's floor.

**ceilingHeight / ceiling_height** - height of the sector's ceiling.
Expand Down
12 changes: 9 additions & 3 deletions docs/api/python/game_state.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,16 @@ See also:
:undoc-members:
```

**id** - unique object ID.
**id** - unique object ID. This is the value referenced by **Label.objectId / object_id**.

**name** - ingame object name, many different objects can have the same name (e.g. Medikit, Clip, Zombie).

**category** - category of the object (e.g. "Monster", "Weapon", "Player"). Category "Self" is assigned to current player. Note: added in 1.3.1.

**sector_id** - ID of the sector the object currently belongs to (same as corresponding **Sector.id**). Note: added in 1.3.1.

See also:
- [`DoomGame.set_objects_info_enabled`](./doom_game.md#vizdoom.DoomGame.set_sectors_info_enabled),
- [`DoomGame.set_objects_info_enabled`](./doom_game.md#vizdoom.DoomGame.set_objects_info_enabled),
- [examples/python/objects_and_sectors.py](https://github.com/Farama-Foundation/ViZDoom/tree/master/examples/python/objects_and_sectors.py).

Note: added in 1.1.8.
Expand Down Expand Up @@ -83,7 +87,9 @@ Note: added in 1.1.8.
:undoc-members:
```

**floor_height** - height of the sector's floor.
**id** - unique sector ID. This is the value referenced by **Object.sector_id**. Note: added in 1.3.1.

**floor_height** - height of the sector's floor. Note: before 1.3.1 the value of floorHeight was inverted (negative). The bug was fixed in 1.3.1.

**ceiling_height** - height of the sector's ceiling.

Expand Down
3 changes: 3 additions & 0 deletions examples/python/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ Presents different scenarios that come with ViZDoom environment.
- [seed.py](https://github.com/mwydmuch/ViZDoom/blob/master/examples/python/seed.py)
Shows how to run deterministic episodes by setting the seed. After setting the seed every episode will look the same (if the agent behaves deterministically).

- [sectors_visualization.py](https://github.com/mwydmuch/ViZDoom/blob/master/examples/python/sectors_visualization.py)
Renders a one-shot 3D map of sectors (floor/ceiling/walls) and objects, then saves the plot.

- [shaping.py](https://github.com/mwydmuch/ViZDoom/blob/master/examples/python/shaping.py)
Demonstrates how to make use of the game variables to implement [shaping](https://en.wikipedia.org/wiki/Shaping_(psychology)) using health_guided.wad scenario.

Expand Down
209 changes: 209 additions & 0 deletions examples/python/sectors_visualization.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
#!/usr/bin/env python3

#####################################################################
# This script captures map sectors information once and renders a 3D
# sector map (floor/ceiling edges and blocking walls), then exits.
#####################################################################

import os
from argparse import ArgumentParser

import matplotlib.colors as mcolors
import matplotlib.pyplot as plt
from matplotlib.lines import Line2D
from mpl_toolkits.mplot3d.art3d import Poly3DCollection

import vizdoom as vzd


DEFAULT_CONFIG = os.path.join(vzd.scenarios_path, "basic.cfg")

DEFAULT_OUTPUT = "sectors_3d.png"
FLOOR_COLOR = "#2ca25f"
CEILING_COLOR = "#ef6548"
OBJECT_COLOR = "#3288bd"
PLAYER_COLOR = "#ffd92f"


def draw_sectors_3d(ax, sectors, objects):
"""Draw floor/ceiling edges, blocking walls, and map objects."""
floor_heights = [s.floor_height for s in sectors]
min_floor = min(floor_heights)
max_floor = max(floor_heights)
norm = mcolors.Normalize(
vmin=min_floor, vmax=max_floor if max_floor > min_floor else min_floor + 1.0
)
colormap = plt.get_cmap("viridis")
xs, ys, zs = [], [], []

for sector in sectors:
color = colormap(norm(sector.floor_height))
fz = sector.floor_height
cz = sector.ceiling_height
assert cz >= fz, "Ceiling height must be greater than or equal to floor height."
zs.extend([fz, cz])

for line in sector.lines:
x = [line.x1, line.x2]
y = [line.y1, line.y2]
xs.extend(x)
ys.extend(y)

# Floor and ceiling are marked with fixed colors.
ax.plot(x, y, [fz, fz], color=FLOOR_COLOR, linewidth=1.4, alpha=0.95)
ax.plot(
x,
y,
[cz, cz],
color=CEILING_COLOR,
linewidth=1.2,
alpha=0.95,
)

# Draw vertical walls only for blocking edges.
if line.is_blocking:
wall = [
(line.x1, line.y1, fz),
(line.x2, line.y2, fz),
(line.x2, line.y2, cz),
(line.x1, line.y1, cz),
]
ax.add_collection3d(
Poly3DCollection(
[wall],
facecolors=[color],
edgecolors=[color],
linewidths=0.3,
alpha=0.22,
)
)

for obj in objects:
is_player = obj.name == "DoomPlayer"
marker_color = PLAYER_COLOR if is_player else OBJECT_COLOR
marker_size = 45 if is_player else 20
x, y, z = obj.position_x, obj.position_y, obj.position_z
xs.append(x)
ys.append(y)
zs.append(z)
ax.scatter(
[x],
[y],
[z],
color=marker_color,
s=marker_size,
edgecolors="black",
linewidths=0.3,
alpha=0.95,
)

ax.set_title("ViZDoom sectors 3D map")
ax.set_xlabel("X")
ax.set_ylabel("Y")
ax.set_zlabel("Z")
ax.grid(alpha=0.2)
ax.view_init(elev=35, azim=-60)
if xs and ys and zs:
x_min, x_max = min(xs), max(xs)
y_min, y_max = min(ys), max(ys)
z_min, z_max = min(zs), max(zs)
max_range = max(x_max - x_min, y_max - y_min, z_max - z_min, 1.0)
half = max_range / 2.0
x_center = (x_min + x_max) / 2.0
y_center = (y_min + y_max) / 2.0
z_center = (z_min + z_max) / 2.0
ax.set_xlim(x_center - half, x_center + half)
ax.set_ylim(y_center - half, y_center + half)
ax.set_zlim(z_center - half, z_center + half)
ax.set_box_aspect((1.0, 1.0, 1.0))
ax.legend(
handles=[
Line2D([0], [0], color=FLOOR_COLOR, lw=2, label="Floor"),
Line2D([0], [0], color=CEILING_COLOR, lw=2, label="Ceiling"),
Line2D(
[0],
[0],
marker="o",
color="w",
markerfacecolor=OBJECT_COLOR,
markeredgecolor="black",
markersize=7,
label="Object",
),
Line2D(
[0],
[0],
marker="o",
color="w",
markerfacecolor=PLAYER_COLOR,
markeredgecolor="black",
markersize=8,
label="Player",
),
],
loc="upper right",
)


if __name__ == "__main__":
parser = ArgumentParser(
"ViZDoom example showing how to render sectors information as a 3D map."
)
parser.add_argument(
dest="config",
default=DEFAULT_CONFIG,
nargs="?",
help="Path to the configuration file of the scenario."
" Please see "
"../../scenarios/*cfg for more scenarios.",
)
parser.add_argument(
"--output",
default=DEFAULT_OUTPUT,
help="Output image path.",
)
args = parser.parse_args()

game = vzd.DoomGame()
game.load_config(args.config)
game.set_window_visible(False)
game.set_render_hud(False)
game.set_sectors_info_enabled(True)
game.set_objects_info_enabled(True)

game.clear_available_game_variables()
game.add_available_game_variable(vzd.GameVariable.POSITION_X)
game.add_available_game_variable(vzd.GameVariable.POSITION_Y)

game.init()
game.new_episode()
state = game.get_state()
if state is None or state.sectors is None or len(state.sectors) == 0:
game.close()
raise RuntimeError(
"Sectors info is unavailable. Ensure '+viz_nocheat' is not enabled and "
"the scenario map defines sectors."
)
if state.objects is None:
game.close()
raise RuntimeError(
"Objects info is unavailable. Ensure '+viz_nocheat' is not enabled."
)

print("Sectors:", len(state.sectors))
print("Objects:", len(state.objects))

output_dir = os.path.dirname(args.output)
if output_dir:
os.makedirs(output_dir, exist_ok=True)

fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(111, projection="3d")
draw_sectors_3d(ax, state.sectors, state.objects)
fig.tight_layout()
fig.savefig(args.output, dpi=180)
print("Saved plot:", args.output)

plt.close(fig)

game.close()
3 changes: 3 additions & 0 deletions include/ViZDoomTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ namespace vizdoom{
struct Object {
// Actor properties
unsigned int id;
int sectorId;

double positionX;
double positionY;
Expand All @@ -87,6 +88,7 @@ namespace vizdoom{
double velocityZ;

std::string name;
std::string category;
};

struct Line{
Expand All @@ -98,6 +100,7 @@ namespace vizdoom{
};

struct Sector{
unsigned int id;
double floorHeight;
double ceilingHeight;
std::vector<Line> lines;
Expand Down
2 changes: 2 additions & 0 deletions src/lib/ViZDoomGame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,7 @@ namespace vizdoom {
this->state->objects.emplace_back();
std::memcpy(&this->state->objects.back().id, &smState->OBJECT[i].id, objectPartSize);
this->state->objects.back().name = std::string(smState->OBJECT[i].name);
this->state->objects.back().category = std::string(smState->OBJECT[i].category);
}
}

Expand All @@ -391,6 +392,7 @@ namespace vizdoom {
if(this->doomController->isSectorsEnabled()){
for (unsigned int i = 0; i < smState->SECTOR_COUNT; ++i) {
this->state->sectors.emplace_back();
this->state->sectors.back().id = smState->SECTOR[i].id;
this->state->sectors.back().ceilingHeight = smState->SECTOR[i].ceilingHeight;
this->state->sectors.back().floorHeight = smState->SECTOR[i].floorHeight;
for (unsigned int j = 0; j < smState->SECTOR[i].lineCount; ++j) {
Expand Down
3 changes: 3 additions & 0 deletions src/lib/ViZDoomSharedMemory.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,14 @@ namespace vizdoom {

struct SMObject {
unsigned int id;
int sectorId;
double position[9];
char category[MAX_NAME_LENGTH];
char name[MAX_NAME_LENGTH];
};

struct SMSector{
unsigned int id;
double floorHeight;
double ceilingHeight;
unsigned int lineCount;
Expand Down
1 change: 1 addition & 0 deletions src/lib_python/ViZDoomGamePython.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ namespace vizdoom {
pyb::list pySectors;
for (auto& sector : this->state->sectors){
SectorPython pySector;
pySector.id = sector.id;
pySector.floorHeight = sector.floorHeight;
pySector.ceilingHeight = sector.ceilingHeight;
pySector.lines = DoomGamePython::vectorToPyList<Line>(sector.lines);
Expand Down
1 change: 1 addition & 0 deletions src/lib_python/ViZDoomGamePython.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ namespace vizdoom {
};

struct SectorPython {
unsigned int id;
double floorHeight;
double ceilingHeight;
pyb::list lines;
Expand Down
2 changes: 1 addition & 1 deletion src/lib_python/ViZDoomObjectsDocstrings.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ namespace docstrings {
const char *Sector = R"DOCSTRING(Represents sectors (floor/ceiling areas) in the game world geometry.)DOCSTRING";
const char *Object = R"DOCSTRING(Represents objects in the game world with position and other properties.)DOCSTRING";
const char *ServerState = R"DOCSTRING(Contains the state of the multiplayer server.)DOCSTRING";
const char *GameState = R"DOCSTRING(Contains the state of the game including screen buffer, game variables, and world geometry, available information depand on the configuration of the game instance.)DOCSTRING";
const char *GameState = R"DOCSTRING(Contains the state of the game including screen buffer, game variables, and world geometry, available information depends on the configuration of the game instance.)DOCSTRING";
const char *DoomGame = R"DOCSTRING(DoomGame is the main object of the ViZDoom library, representing a single instance of the Doom game and providing the interface for a single agent/player to interact with the game. The object allows sending actions to the game, getting the game state, etc.)DOCSTRING";

} // namespace docstrings
Expand Down
Loading
Loading