This documentation overviews creating new environments and relevant useful wrappers, utilities and tests included in Gymnasium designed for the creation of new environments.
You can clone gym-examples to play with the code that are presented here. We recommend that you use a virtual environment:
There, you should specify the render-modes that are supported by your environment (e.g. `"human"`, `"rgb_array"`, `"ansi"`)
and the framerate at which your environment should be rendered. Every environment should support`None` as render-mode; you don't need to add it in the metadata.
In `GridWorldEnv`, we will support the modes "rgb_array" and "human" and render at 4 FPS.
The `__init__` method of our environment will accept the integer `size`, that determines the size of the square grid.
We will set up some variables for rendering and define `self.observation_space` and `self.action_space`.
In our case, observations should provide information about the location of the agent and target on the 2-dimensional grid.
We will choose to represent observations in the form of a dictionaries with keys `"agent"` and `"target"`. An observation
may look like ` {"agent": array([1, 0]), "target": array([0, 3])}`.
Since we have 4 actions in our environment ("right", "up", "left", "down"), we will use `Discrete(4)` as an action space.
Here is the declaration of `GridWorldEnv` and the implementation of `__init__`:
The `close` method should close any open resources that were used by the environment. In many cases,
you don't actually have to bother to implement this method. However, in our example `render_mode` may
be `"human"` and we might need to close the window that has been opened:
```python
def close(self):
if self.window is not None:
pygame.display.quit()
pygame.quit()
```
In other environments `close` might also close files that were opened
or release other resources. You shouldn't interact with the environment after having called `close`.
## Registering Envs
In order for the custom environments to be detected by Gymnasium, they must be registered as follows. We will choose to put this code in `gym-examples/gym_examples/__init__.py`.
```python
from gymnasium.envs.registration import register
register(
id='gym_examples/GridWorld-v0',
entry_point='gym_examples.envs:GridWorldEnv',
max_episode_steps=300,
)
```
The environment ID consists of three components, two of which are optional: an optional namespace (here: `gym_examples`), a mandatory name (here: `GridWorld`) and an optional but recommended version (here: v0). It might have also been registered as `GridWorld-v0` (the recommended approach), `GridWorld` or `gym_examples/GridWorld`, and the appropriate ID should then be used during environment creation.
The keyword argument `max_episode_steps=300` will ensure that GridWorld environments that are instantiated via `gymnasium.make`
| `reward_threshold` | `float` | `None` | The reward threshold before the task is considered solved |
| `nondeterministic` | `bool` | `False` | Whether this environment is non-deterministic even after seeding |
| `max_episode_steps` | `int` | `None` | The maximum number of steps that an episode can consist of. If not `None`, a `TimeLimit` wrapper is added |
| `order_enforce` | `bool` | `True` | Whether to wrap the environment in an `OrderEnforcing` wrapper |
| `autoreset` | `bool` | `False` | Whether to wrap the environment in an `AutoResetWrapper` |
| `kwargs` | `dict` | `{}` | The default kwargs to pass to the environment class |
Most of these keywords (except for `max_episode_steps`, `order_enforce` and `kwargs`) do not alter the behavior
of environment instances but merely provide some extra information about your environment.
After registration, our custom `GridWorldEnv` environment can be created with `env = gymnasium.make('gym_examples/GridWorld-v0')`.
`gym-examples/gym_examples/envs/__init__.py` should have:
```python
from gym_examples.envs.grid_world import GridWorldEnv
```
If your environment is not registered, you may optionally pass a module to import, that would register your environment before creating it like this -
`env = gymnasium.make('module:Env-v0')`, where `module` contains the registration code. For the GridWorld env, the registration code is run by importing `gym_examples` so if it were not possible to import gym_examples explicitly, you could register while making by `env = gymnasium.make('gym_examples:gym_examples/GridWorld-v0)`. This is especially useful when you're allowed to pass only the environment ID into a third-party codebase (eg. learning library). This lets you register your environment without needing to edit the library's source code.
## Creating a Package
The last step is to structure our code as a Python package. This involves configuring `gym-examples/setup.py`. A minimal example of how to do so is as follows: