Observation Spaces¶
EldenGym provides flexible observation spaces for different use cases.
RGB Mode (Default)¶
Type: gymnasium.spaces.Box(0, 255, (H, W, 3), uint8)
Returns only the game frame as RGB image.
env = gym.make("EldenGym-v0", observation_mode="rgb")
obs, info = env.reset()
print(obs.shape) # (1080, 1920, 3) - depends on game resolution
Usage¶
Best For¶
- Vision-based agents
- CNN policies
- Pixel-to-action learning
Dictionary Mode¶
Type: gymnasium.spaces.Dict({...})
Returns frame plus game state information.
env = gym.make("EldenGym-v0", observation_mode="dict")
obs, info = env.reset()
print(obs.keys()) # ['frame', 'player_hp', 'target_hp', ...]
Structure¶
{
'frame': Box(0, 255, (H, W, 3), uint8),
'player_hp': Box(0, inf, (1,), float32),
'player_max_hp': Box(0, inf, (1,), float32),
'target_hp': Box(0, inf, (1,), float32),
'target_max_hp': Box(0, inf, (1,), float32),
'distance': Box(0, inf, (1,), float32),
'player_animation_id': Box(0, inf, (1,), float32),
'target_animation_id': Box(0, inf, (1,), float32),
}
Usage¶
obs, info = env.reset()
frame = obs['frame']
player_hp = obs['player_hp'][0]
boss_hp = obs['target_hp'][0]
distance = obs['distance'][0]
print(f"HP: {player_hp}/{obs['player_max_hp'][0]}")
print(f"Boss HP: {boss_hp}/{obs['target_max_hp'][0]}")
print(f"Distance: {distance:.2f}")
Best For¶
- Multi-modal agents
- State-based policies
- Hybrid vision + state approaches
Custom Observations¶
Wrapper for Grayscale¶
from gymnasium.wrappers import GrayScaleObservation
env = gym.make("EldenGym-v0")
env = GrayScaleObservation(env)
obs, info = env.reset()
print(obs.shape) # (H, W) - grayscale
Wrapper for Resize¶
from gymnasium.wrappers import ResizeObservation
env = gym.make("EldenGym-v0")
env = ResizeObservation(env, shape=(84, 84))
obs, info = env.reset()
print(obs.shape) # (84, 84, 3)
Wrapper for Frame Stacking¶
from gymnasium.wrappers import FrameStack
env = gym.make("EldenGym-v0")
env = FrameStack(env, num_stack=4)
obs, info = env.reset()
print(obs.shape) # (4, H, W, 3) - 4 stacked frames
Combined Preprocessing¶
from gymnasium.wrappers import (
GrayScaleObservation,
ResizeObservation,
FrameStack,
)
# Create Atari-style preprocessing
env = gym.make("EldenGym-v0", frame_skip=4)
env = GrayScaleObservation(env)
env = ResizeObservation(env, (84, 84))
env = FrameStack(env, num_stack=4)
obs, info = env.reset()
print(obs.shape) # (4, 84, 84) - ready for DQN/PPO
Custom Observation Wrapper¶
import gymnasium as gym
import numpy as np
class NormalizeObservation(gym.ObservationWrapper):
"""Normalize observation values."""
def __init__(self, env):
super().__init__(env)
# Update observation space
self.observation_space = gym.spaces.Box(
low=0.0,
high=1.0,
shape=env.observation_space.shape,
dtype=np.float32
)
def observation(self, obs):
"""Normalize to [0, 1]."""
return obs.astype(np.float32) / 255.0
# Use it
env = NormalizeObservation(gym.make("EldenGym-v0"))
State-Only Observation¶
If you don't need frames:
class StateOnlyWrapper(gym.ObservationWrapper):
"""Return only game state, no frames."""
def __init__(self, env):
super().__init__(env)
self.observation_space = gym.spaces.Box(
low=0, high=np.inf, shape=(7,), dtype=np.float32
)
def observation(self, obs):
"""Extract state from info."""
info = self.env.unwrapped.last_info
return np.array([
info['player_hp'],
info['player_max_hp'],
info['target_hp'],
info['target_max_hp'],
info['distance'],
info['player_animation_id'],
info['target_animation_id'],
], dtype=np.float32)
env = StateOnlyWrapper(gym.make("EldenGym-v0"))
Performance Considerations¶
Reduce Frame Cost¶
# Don't capture frames if not needed
env = gym.make("EldenGym-v0", observation_mode="dict")
# Only use state
obs = {k: v for k, v in obs.items() if k != 'frame'}
Reduce Resolution¶
# Lower resolution = faster processing
env = gym.make("EldenGym-v0")
env = ResizeObservation(env, (320, 180)) # Much smaller
Skip Frames¶
Info Dictionary¶
Additional information available in info:
obs, info = env.reset()
# Available keys:
info['player_hp'] # Current HP
info['player_max_hp'] # Max HP
info['target_hp'] # Boss HP
info['target_max_hp'] # Boss max HP
info['distance'] # Distance to boss
info['player_animation_id'] # Player animation
info['target_animation_id'] # Boss animation
info['step_count'] # Steps in episode
# After step:
obs, reward, terminated, truncated, info = env.step(action)
info['player_hp_delta'] # HP change
info['target_hp_delta'] # Boss HP change