nodes/door.pyΒΆ

Part of Q1K3.

 1"""Sliding door for Q1K3 port.
 2
 3Mirrors upstream `entity_door.js`. Door slides along its yaw axis when the
 4player is nearby. Optionally locked behind a key pickup.
 5"""
 6
 7from __future__ import annotations
 8
 9import math
10from typing import TYPE_CHECKING
11
12from simvx.core import Material, MeshInstance3D, Node3D, Vec3
13
14from . import meshes, textures
15from .mathutil import rotate_y
16
17if TYPE_CHECKING:  # pragma: no cover
18    from .root import Q1K3Root
19
20
21class Door(Node3D):
22    SCALE = (96, 96, 16)
23    OPEN_DISTANCE = 96.0
24    PROXIMITY = 128.0
25    OPEN_HOLD_TIME = 3.0
26
27    def __init__(
28        self,
29        game: Q1K3Root,
30        pos: Vec3,
31        yaw_dir: int = 0,
32        needs_key: bool = False,
33        tex_id: int = textures.TEX_DOOR,
34    ) -> None:
35        super().__init__()
36        self.game = game
37        self.position = pos
38        # Doors live in both enemy and friendly collision lists, so they need
39        # `.p` and `.s` like any PhysicsBody (sphere collision check).
40        self.p = Vec3(pos.x, pos.y, pos.z)
41        self.s = Vec3(64, 64, 64)
42        self._yaw = yaw_dir * math.pi / 2
43        self._start_pos = Vec3(pos.x, pos.y, pos.z)
44        self._reset_state_at = 0.0
45        self._open = 0.0
46        self.needs_key = needs_key
47        self._dead = False
48
49        self._inst = MeshInstance3D(
50            mesh=meshes.cube(),
51            material=Material(
52                albedo_map=textures.get(tex_id),
53                roughness=0.6,
54                metallic=0.0,
55            ),
56            scale=type(self).SCALE,
57        )
58        self.add_child(self._inst)
59
60    def on_update(self, dt: float) -> None:
61        player = self.game.player
62        if player is None:
63            return
64
65        d = (self.position - player.p).length()
66        if d < type(self).PROXIMITY:
67            if self.needs_key and not self.game.has_key:
68                self.game.show_message("YOU NEED THE KEY...")
69                return
70            if self.needs_key and self.game.has_key:
71                self.needs_key = False
72            self._reset_state_at = self.game.game_time + type(self).OPEN_HOLD_TIME
73
74        if self._reset_state_at < self.game.game_time:
75            self._open = max(0.0, self._open - dt)
76        else:
77            self._open = min(1.0, self._open + dt)
78
79        offset_x = type(self).OPEN_DISTANCE * self._open
80        # Slide perpendicular to the door's yaw axis
81        slide = rotate_y(Vec3(offset_x, 0, 0), self._yaw)
82        self.position = self._start_pos + slide
83        self.p = Vec3(self.position.x, self.position.y, self.position.z)