Skip to content

navigation

Black Ram edited this page Jul 4, 2024 · 6 revisions

Navigation

For implementing the navigation, you need create rooms, loocations and maps.

The navigation system is designed in the following way:

  • The player is placed in a room
  • To be reachable, each room must be connected to a location and a map
  • The player, from the current room, can move to another room at the same location.
  • For move in another location the player need to use the map.

Rooms

The rooms are the places where the player can interact. The rooms are part of a location. For creating a room, you need to create a new instance of the RoomBaseModel class and add it into a game rooms dictionary, when the game is initialized.

For create a new instance of RoomBaseModel you need to pass:

  • id: a unique identifier for the room. It is used to reference the room in the game (must be unique).
  • location: the location instance.
  • props: the room properties. The properties are:
    • name: the room name.
    • renderImage: the room image. It can be a string, an JSX.Element, GraphicItemInterface or a Pixi'VN Canvas Item. Or an object to manage multiple image types. For example to have a image based on time.
    • defaultActivities: the activities that are available in this room.
    • disabled: whether is disabled. You can also pass a Pixi'VN flag name.
    • hidden: whether is hidden. You can also pass a Pixi'VN flag name.
    • renderIcon: the room icon. It can be a string, an JSX.Element, GraphicItemInterface or a Pixi'VN Canvas Item. Or a function to manage multiple icon types. For example to have a icon based on time.
    • isEntrance: whether is an entrance room, so when the player enters in the location, it will be the first room to be shown.
export const mcRoom = new RoomBaseModel('mc_room', home, {
    name: "MC room",
    renderImage: 'https://images.com/myroom.webp',
    defaultActivities: [sleepActivity, studyActivity],
})

saveRoom([mcRoom, bathroom, lounge]);

Room activities

The room have 2 types of activities:

  • RoomBaseModel.defaultActivities: This list can't edited in runtime, but only by code (the room properties).
  • RoomBaseModel.activities: This list can be edited in runtime. You can add or remove activities with the RoomBaseModel.addActivity() and RoomBaseModel.removeActivity() functions.

Room routines

You can use RoomBaseModel.getRoutine() to get the current room routine.

Entrance room

The entrance room is the first room that the player will see when enter in a location. You can set the RoomBaseModel.isEntrance property to true in the room properties. If a location has multiple entrance rooms, the first room that is added in the location will be the entrance room. If a location doesn't have an entrance room, the first room that is added in the location will be the entrance room.

Locations

The locations are the collection of rooms. The locations are part of a map. For creating a location, you need to create a new instance of the LocationBaseModel class.

For create a new instance of LocationBaseModel you need to pass:

  • id: a unique identifier for the location. It is used to reference the location in the game (must be unique).
  • map: the map instance.
  • props: the location properties. The properties are:
const home = new LocationBaseModel('home', map, {
    name: "Home",
    renderIcon: 'https://images.com/homeicon.webp',
})

export const mcRoom = new RoomBaseModel('mc_room', home, {
    name: "MC room",
    renderImage: 'https://images.com/myroom.webp',
    defaultActivities: [sleepActivity, studyActivity],
})

saveRoom([mcRoom, bathroom, lounge]);

Get rooms

You can use LocationBaseModel.getRooms() to get the rooms of the location.

Get entrance room

You can use LocationBaseModel.getEntrance() to get the entrance room of the location.

Maps

The maps are the collection of locations. The maps are part of the navigation system. For creating a map, you need to create a new instance of the MapBaseModel class.

For create a new instance of MapBaseModel you need to pass:

  • id: a unique identifier for the map. It is used to reference the map in the game (must be unique).
  • props: the map properties. The properties are:
    • name: the map name.
    • renderImage: the map image. It can be a string, an JSX.Element, GraphicItemInterface or a Pixi'VN Canvas Item. Or an object to manage multiple image types. For example to have a image based on time.
    • neighboringMaps: the neighboring maps that are available in this map. For example, if the player is in the current map and want to move to another map, the player can use the neighboring maps. Read the Overriding the Neighboring Maps Interface section for more information.
    • disabled: whether is disabled. You can also pass a Pixi'VN flag name.
    • hidden: whether is hidden. You can also pass a Pixi'VN flag name.

Overriding the Neighboring Maps Interface

You can override the NeighboringMapsInterface to set required parameters for the neighboring maps.

For example:

// nqtr.types.ts
declare module '@drincs/nqtr/dist/override' {
    interface NeighboringMapsInterface {
        "north": string,
        "south": string,
        "east": string,
        "west": string,
    }
}

Best sites for creating map images

Change Room

The player can only move to another rooms. To move to another room you can use the setCurrentRoom() function. Automatically the location and the real map changed based on the room. This function has 1 parameters:

  • room: the room instance.
setCurrentRoom(mcRoom);

Get Current Room

For get the current room you can use the getCurrentRoom() function.

const currentRoom = getCurrentRoom();
// or if you have a custom room model
const currentRoom = getCurrentRoom<MyRoomModel>();

Get Current Location

For get the current location you can use the getCurrentLocation() function.

const currentLocation = getCurrentLocation();
// or if you have a custom location model
const currentLocation = getCurrentLocation<MyLocationModel>();

Get Current Map

For get the current map you can use the getCurrentMap() function.

const currentMap = getCurrentMap();
// or if you have a custom map model
const currentMap = getCurrentMap<MyMapModel>();

Extend Room Location Map

It recommend creating a subclass of RoomBaseModel, LocationBaseModel or MapBaseModel to add new properties or methods to the class.

For example, you can create a subclass RoomBaseModel to add a new property color:

class RoomModel extends RoomBaseModel {
    color: string;

    constructor(id: string, location: LocationBaseModel, props: RoomProps) {
        super(id, location, props);
        this.color = props.color;
    }
}

React Example

export default function RoomList() {
    const [{ currentLocation, currentRoom }, setCurrentNavigationData] = useState({
        currentLocation: getCurrentLocation(),
        currentRoom: getCurrentRoom(),
    })

    useEffect(() => {
        let room = getCurrentRoom()
        let location = getCurrenrLocation()

        setCurrentNavigationData((prev) => ({
            currentLocation: location || prev.currentLocation,
            currentRoom: room || prev.currentRoom,
        }))
    }, [hour])

    useEffect(() => {
        if (currentRoom.renderImage) {
            let backgroundImage = currentRoom.renderImage({})
            let container = new CanvasContainer()
            if (backgroundImage instanceof CanvasBase) {
                container.addChild(backgroundImage)
            }
            if (typeof backgroundImage === 'string') {
                let image = new CanvasImage()
                image.imageLink = backgroundImage
                image.load()
                container.addChild(image)
            }

            GameWindowManager.addCanvasElement(BACKGROUND_ID, container)
        }
    }, [currentRoom])

    return (
        <Stack
            direction="row"
            justifyContent="center"
            alignItems="flex-end"
            spacing={0.5}
        >
            {currentLocation.getRooms().map((room) => {
                let renderImage = room.renderIcon || room.renderImage
                let disabled = room.disabled
                let selected = room.id === currentRoom?.id
                if (!renderImage) {
                    return
                }
                let image = renderImage({})
                if (typeof image === "string") {
                    return (
                        <IconButton
                            key={"room" + room.id}
                            disabled={disabled || selected}
                            selected={selected}
                            onClick={() => {
                                if (!disabled) {
                                    setCurrentRoom(room)
                                    let r = getCurrentRoom()
                                    if (r && r.id !== currentRoom.id) {
                                        setCurrentNavigationData((prev) => ({ ...prev, currentRoom: r }))
                                    }
                                }
                            }}
                            ariaLabel={room.name}
                        >
                            {image && <img src={image} />}
                        </IconButton>
                    )
                }
                else if (isValidElement(image)) {
                    return image
                }
            })}
        </Stack>
    );
}