Os, animations et effets

Lire et déformer le squelette des props, des joueurs et des PNJ, retrouver leurs points d'attache, jouer les animations d'un modèle, changer son rendu, l'enflammer ou le désintégrer, et secouer l'écran. Noms de Garry's Mod ; unités du jeu : mètres et degrés.

Os

Ces méthodes existent sur les props et entités scriptées (le squelette de leur modèle, s'il en a un), sur les joueurs (le mannequin ou leur playermodel) et sur les PNJ. Les os sont numérotés à partir de 0.

MéthodeCôtéRenvoie
ent:LookupBone(nom)partagéNuméro de l'os, ou nil. Les noms ValveBiped.Bip01_… de GMod marchent (voir plus bas).
ent:GetBoneCount()partagéNombre d'os (0 sans squelette).
ent:GetBoneName(n)partagéNom de l'os, ou "__INVALIDBONE__".
ent:GetBoneParent(n)partagéNuméro de l'os parent, -1 pour la racine.
ent:GetBonePosition(n)partagéDeux valeurs : position (Vector) et angles (Angle) de l'os dans le monde, ou nil.
ent:GetBoneMatrix(n)partagéUne matrice (Transform3D de Godot) dans le monde : m:GetTranslation(), m:GetAngles(), m:GetScale(), m:GetForward(), m:GetRight(), m:GetUp(). nil si l'os n'existe pas.
ent:ManipulateBonePosition(n, Vector)serveur / clientDécale l'os (mètres, dans le repère de l'os), en plus de l'animation.
ent:ManipulateBoneAngles(n, Angle)serveur / clientTourne l'os (degrés : pitch, yaw, roll), en plus de l'animation.
ent:ManipulateBoneScale(n, Vector)serveur / clientMultiplie la taille de l'os (Vector(1, 1, 1) = normale).
ent:GetManipulateBonePosition(n), …Angles(n), …Scale(n)partagéLes valeurs données par le serveur (zéro, ou Vector(1, 1, 1) pour la taille, par défaut).
ent:HasBoneManipulations()partagéUn os est-il déformé (par le serveur, ou par ce client) ?

Côté serveur, ManipulateBone* est envoyé à tous les joueurs (y compris ceux qui arrivent plus tard). Côté client, la déformation ne se voit que chez ce joueur, en plus de celles du serveur. Décalage et taille sont bornés à ±50. Remettre zéro (ou Vector(1, 1, 1) pour la taille) enlève la déformation. ent:SetupBones() et ent:InvalidateBoneCache() recalculent tout de suite la pose des os (GetBonePosition à jour juste après un ManipulateBone*).

-- Serveur : grosse tête pour tout le monde.
local function grosse_tete(ply)
	local tete = ply:LookupBone("ValveBiped.Bip01_Head1")
	if tete then ply:ManipulateBoneScale(tete, Vector(2, 2, 2)) end
end

-- Client : une lumière qui suit la main droite d'un joueur.
local pos, ang = ply:GetBonePosition(ply:LookupBone("ValveBiped.Bip01_R_Hand"))

Noms ValveBiped

LookupBone cherche d'abord le nom exact, puis, pour un nom de GMod, l'os équivalent des squelettes du jeu (mannequin Rigify DEF-…, Character Creator CC_Base_…, Mixamo mixamorig:…, Unreal …_l / …_r). Noms reconnus :

PartieNoms ValveBiped.
Tronc et têteBip01_Pelvis, Bip01_Spine, Bip01_Spine1, Bip01_Spine2, Bip01_Spine4, Bip01_Neck1, Bip01_Head1
Bras (L / R)Bip01_L_Clavicle, Bip01_L_UpperArm, Bip01_L_Forearm, Bip01_L_Hand (et _R_)
Jambes (L / R)Bip01_L_Thigh, Bip01_L_Calf, Bip01_L_Foot, Bip01_L_Toe0 (et _R_)

Les doigts n'ont pas d'équivalent : utilise le nom réel de l'os (ent:GetBoneName(n) en boucle sur GetBoneCount() pour les lister).

Points d'attache

MéthodeRenvoie
ent:LookupAttachment(nom)Numéro du point (à partir de 1), 0 s'il n'existe pas.
ent:GetAttachment(n){ Pos = Vector, Ang = Angle } dans le monde, ou nil.
ent:GetAttachments(){ { id = 1, name = "…" }, … }

Sur un prop, les points d'attache sont les pièces nommées de son modèle (celles de l'éditeur de modèles). Sur un joueur ou un PNJ, ce sont les noms de GMod, placés sur l'os correspondant : eyes (8 cm au-dessus de l'os de la tête), mouth, forward, anim_attachment_head (tête), chest (Spine2), anim_attachment_RH et anim_attachment_LH (mains).

-- Client : un chapeau sur la tête du joueur local.
local chapeau = ents.CreateClientProp("builtin:cone")
chapeau:Spawn()
hook.Add("Think", "chapeau", function()
	local point = LocalPlayer():GetAttachment(LocalPlayer():LookupAttachment("eyes"))
	if point then
		chapeau:SetPos(point.Pos + Vector(0, 0.15, 0))
		chapeau:SetAngles(Angle(0, point.Ang.y, 0))
	end
end)

Animations des props (séquences)

Les animations d'un modèle importé (voir Éditeur de modèles) sont ses séquences, numérotées à partir de 0 dans l'ordre de GetSequenceList(). Les changements faits par le serveur sont vus par tous.

MéthodeCôtéRôle
ent:LookupSequence(nom)partagéNuméro de l'animation, -1 si elle n'existe pas.
ent:GetSequenceList()partagéLes noms, indexés à partir de 0 (for i = 0, ent:GetSequenceCount() - 1).
ent:GetSequenceCount(), ent:GetSequenceName(n)partagéNombre d'animations ; nom (ou "Unknown").
ent:SetSequence(n ou nom), ent:ResetSequence(n ou nom)serveurJoue cette animation en boucle, depuis le début.
ent:GetSequence()partagéNuméro de l'animation en cours, -1 sans.
ent:SetCycle(0 à 1), ent:GetCycle()serveur / partagéSaute à cet endroit de l'animation (0 = début, 1 = fin) ; où elle en est.
ent:SetPlaybackRate(vitesse), ent:GetPlaybackRate()serveur / partagéVitesse de lecture (1 = normale, de -10 à 10, négative = à l'envers).
ent:SequenceDuration(n)partagéDurée en secondes (sans argument : l'animation en cours).

Un prop n'a qu'un corps physique : ent:GetPhysicsObjectCount() vaut 1 et ent:GetPhysicsObjectNum(0) donne le même objet que GetPhysicsObject().

Matériaux et rendu

MéthodeCôtéRôle
ent:GetMaterials()partagéNoms des matériaux du modèle, une entrée par surface (dans l'ordre des surfaces).
ent:SetSubMaterial(n, id)serveurMet un matériau de l'outil Matériau ("metal", "gold"…, comme SetMaterial) sur la surface n seulement (à partir de 0). id = "" rend son matériau à cette surface ; ent:SetSubMaterial() sans argument les rend toutes.
ent:GetSubMaterial(n)partagéMatériau mis sur cette surface, ou "".
ent:SetRenderMode(RENDERMODE_…), ent:GetRenderMode()serveur / partagéMode de rendu (voir ci-dessous).

Les constantes RENDERMODE_* de GMod existent toutes (NORMAL, TRANSCOLOR, TRANSTEXTURE, GLOW, TRANSALPHA, TRANSADD, ENVIROMENTAL, TRANSALPHADD, WORLDGLOW, NONE). Seules deux familles changent l'apparence : RENDERMODE_NONE cache le modèle, et RENDERMODE_GLOW, TRANSADD, TRANSALPHADD et WORLDGLOW le dessinent en additif (lumineux, comme un hologramme). Les autres modes laissent le rendu normal.

Feu et désintégration

MéthodeCôtéRôle
ent:Ignite(durée, rayon)serveurEnflamme un prop ou un joueur pendant durée secondes (5 par défaut, 3600 au plus). Rallumer prolonge le feu. rayon (0 par défaut, 50 m au plus) : les joueurs à cette distance brûlent aussi.
ent:Extinguish()serveurÉteint.
ent:IsOnFire()partagéEn feu ?
ent:Dissolve()serveurDésintègre un prop : il flotte sans gravité, brille en bleu électrique, s'efface en lançant des étincelles, puis est supprimé au bout de 1,6 s.

Ce qui brûle perd 2 points toutes les 0,5 s : un prop reçoit des dégâts de type DMG_BURN (ENT:OnTakeDamage), un joueur perd de la vie (« a brûlé »), de même que chaque joueur dans le rayon. L'eau éteint le feu, comme la fin de la durée ou la mort du joueur. Les flammes et leur lumière se voient chez tous les joueurs.

-- Serveur : un baril qui prend feu au premier dégât, puis disparaît.
function ENT:OnTakeDamage(dmg)
	if self:IsOnFire() then return end
	self:Ignite(8, 3)
	timer.Simple(8, function() if IsValid(self) then self:Dissolve() end end)
end

Secouer l'écran : util.ScreenShake

util.ScreenShake(pos, amplitude, fréquence, durée, rayon) fait trembler la caméra. Côté serveur, envoyé à tous les joueurs ; côté client, seulement chez ce joueur. amplitude de 0 à 16 (5 par défaut), fréquence en Hz (5 par défaut), durée en secondes (1 par défaut, 30 au plus). Avec un rayon (mètres), seuls les joueurs à cette distance de pos tremblent, de moins en moins loin du centre ; 0 = partout. La secousse faiblit jusqu'à la fin de sa durée.

-- Serveur : une explosion qui secoue les joueurs à moins de 30 m.
util.BlastDamage(pos, 6, 80)
util.ScreenShake(pos, 12, 20, 1.5, 30)

Voir aussi le dessin des entités (ENT:Draw, ent:DrawModel()), les entités cachées aux joueurs (ENT:UpdateTransmitState), les variables NetworkVar et ents.CreateClientProp dans Entités scriptées.