nodes/particle.pyΒΆ
Part of Q1K3.
1"""Particle entities for blood, gibs, explosion fragments."""
2
3from __future__ import annotations
4
5import random
6from typing import TYPE_CHECKING
7
8from simvx.core import Material, MeshInstance3D, Node3D, Vec3
9
10from . import meshes, textures
11from .physics import PhysicsBody, update_physics
12
13if TYPE_CHECKING: # pragma: no cover
14 from .root import Q1K3Root
15
16
17_PART_MAT_CACHE: dict[int, Material] = {}
18
19
20def _mat_for(tex_id: int) -> Material:
21 if tex_id not in _PART_MAT_CACHE:
22 _PART_MAT_CACHE[tex_id] = Material(albedo_map=textures.get(tex_id), roughness=0.6, metallic=0.0)
23 return _PART_MAT_CACHE[tex_id]
24
25
26class Particle(Node3D, PhysicsBody):
27 def __init__(self, game: Q1K3Root, pos: Vec3, vel: Vec3, lifetime: float, tex_id: int) -> None:
28 super().__init__()
29 self._physics_init()
30 self.game = game
31 self.position = pos
32 self.p = Vec3(pos.x, pos.y, pos.z)
33 self.v = Vec3(vel.x, vel.y, vel.z)
34 self.s = Vec3(2, 2, 2)
35 self.f = 0.1
36 self._gravity = 1.0
37 self._bounciness = 0.5
38 self._die_at = game.game_time + lifetime
39 self._dead = False
40 self._yaw = random.random()
41 self._pitch = random.random()
42
43 self._inst = MeshInstance3D(
44 mesh=meshes.cube(),
45 material=_mat_for(tex_id),
46 scale=(2.5, 2.5, 2.5),
47 )
48 self.add_child(self._inst)
49
50 def on_update(self, dt: float) -> None:
51 if self._dead:
52 return
53 if self._die_at <= self.game.game_time:
54 self._kill()
55 return
56 self._yaw += float(self.v.y) * 0.001
57 self._pitch += float(self.v.x) * 0.001
58 update_physics(self, self.game.world, [], [], dt, self.game.game_time)
59 self.position = self.p
60 from simvx.core.math.types import Quat
61
62 self.rotation = Quat.from_axis_angle(Vec3(0, 1, 0), self._yaw)
63
64 def _kill(self) -> None:
65 if self._dead:
66 return
67 self._dead = True
68 self.game.queue_remove(self)
69
70
71def spawn_burst(game: Q1K3Root, pos: Vec3, count: int, speed: float, lifetime: float, tex_id: int) -> None:
72 for _ in range(count):
73 v = Vec3(
74 (random.random() - 0.5) * speed,
75 random.random() * speed,
76 (random.random() - 0.5) * speed,
77 )
78 p = Particle(game, pos, v, lifetime + random.random() * lifetime * 0.2, tex_id)
79 game.add_entity(p)