{"id":482785,"date":"2026-06-08T09:29:42","date_gmt":"2026-06-08T09:29:42","guid":{"rendered":"https:\/\/savepearlharbor.com\/?p=482785"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=482785","title":{"rendered":"\u041f\u0438\u0448\u0435\u043c Third Person Controller \u043d\u0430 MonoGame. \u0427\u0430\u0441\u0442\u044c II"},"content":{"rendered":"<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<h3>\u0412\u0432\u0435\u0434\u0435\u043d\u0438\u0435<\/h3>\n<p>\u042d\u0442\u043e \u0432\u0442\u043e\u0440\u0430\u044f \u0447\u0430\u0441\u0442\u044c \u0441\u0435\u0440\u0438\u0438 \u0442\u0443\u0442\u043e\u0440\u0438\u0430\u043b\u043e\u0432, \u0433\u0434\u0435 \u043c\u044b \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c Third Person Controller \u043d\u0430 MonoGame.<\/p>\n<p>\u041f\u0435\u0440\u0432\u0430\u044f \u0447\u0430\u0441\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u0430 \u0442\u0443\u0442: <a href=\"https:\/\/habr.com\/ru\/articles\/1040382\/\" rel=\"noopener noreferrer nofollow\">https:\/\/habr.com\/ru\/articles\/1040382\/<\/a><\/p>\n<p>\u0412 \u044d\u0442\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u043c\u044b \u0437\u0430\u043c\u0435\u043d\u0438\u043c \u043a\u0430\u043f\u0441\u0443\u043b\u0443 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0430 \u043d\u0430 \u0430\u043d\u0438\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u0443\u044e \u043c\u043e\u0434\u0435\u043b\u044c. \u0418 \u043f\u0440\u0438\u0446\u0435\u043f\u0438\u043c \u043c\u0435\u0447 \u043d\u0430 \u0441\u043f\u0438\u043d\u0443:<\/p>\n<div class=\"tm-iframe_temp\" data-src=\"https:\/\/embedd.srv.habr.com\/iframe\/6a268b8544e12a8f37365b39\" data-style=\"\" id=\"6a268b8544e12a8f37365b39\" width=\"\" data-habr-games=\"\"><\/div>\n<p>\u0414\u043b\u044f \u043f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u044f \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u0430 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0438\u043c\u0435\u0442\u044c \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043e \u0442\u043e\u043c, \u0447\u0442\u043e \u0442\u0430\u043a\u043e\u0435 gltf\/glb \u0438 \u043a\u0430\u043a \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0441\u043a\u0435\u043b\u0435\u0442\u043d\u0430\u044f \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044f. \u0412 \u0418\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0435 \u043f\u043e\u043b\u043d\u043e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043d\u0430 \u044d\u0442\u0443 \u0442\u0435\u043c\u0443. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0441\u0442\u0430\u0442\u044c\u044f \u043d\u0430 learnopengl: <a href=\"https:\/\/learnopengl.com\/Guest-Articles\/2020\/Skeletal-Animation\" rel=\"noopener noreferrer nofollow\">https:\/\/learnopengl.com\/Guest-Articles\/2020\/Skeletal-Animation<\/a><\/p>\n<hr\/>\n<h3>\u041e\u0431\u044a\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 fbx \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0439 \u0432 \u043e\u0434\u043d\u0443 \u043c\u043e\u0434\u0435\u043b\u044c gltf(\u043d\u0435\u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u0430\u044f \u0433\u043b\u0430\u0432\u0430)<\/h3>\n<p>\u042d\u0442\u0430 \u0433\u043b\u0430\u0432\u0430 \u043d\u0435\u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u0430 \u0434\u043b\u044f \u0442\u0443\u0442\u043e\u0440\u0438\u0430\u043b\u0430. \u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0432 \u043d\u0451\u043c \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0430 \u043c\u043e\u0434\u0435\u043b\u044c gltf \u0441\u0440\u0430\u0437\u0443 \u0441\u043e \u0432\u0441\u0435\u043c \u043d\u0443\u0436\u043d\u044b\u043c\u0438 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044f\u043c\u0438.<\/p>\n<p>\u041d\u043e \u0435\u0441\u043b\u0438 \u0432\u044b \u0441\u0430\u043c\u0438 \u0437\u0430\u0445\u043e\u0442\u0438\u0442\u0435 \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0441\u0432\u043e\u044e \u0430\u043d\u0438\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u0443\u044e \u043c\u043e\u0434\u0435\u043b\u044c \u043d\u0430 \u0431\u0430\u0437\u0435 mixamo, \u0442\u043e \u0432\u0430\u043c \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043b\u0435\u0437\u043d\u043e \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u044d\u0442\u043e \u0432\u0438\u0434\u0435\u043e, \u0433\u0434\u0435 \u0432\u043d\u0430\u0447\u0430\u043b\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438 \u0441\u043a\u0430\u0447\u0438\u0432\u0430\u044e\u0442\u0441\u044f. \u0410 \u043f\u043e\u0442\u043e\u043c \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u044f\u044e\u0442\u0441\u044f \u0432 blendere \u0438 \u044d\u043a\u0441\u043f\u043e\u0440\u0442\u044f\u0442\u0441\u044f \u0432 glb(\u0431\u0438\u043d\u0430\u0440\u043d\u0430\u044f \u0432\u0435\u0440\u0441\u0438\u044f gltf):<\/p>\n<div class=\"tm-iframe_temp\" data-src=\"https:\/\/embedd.srv.habr.com\/iframe\/6a268b857c20675d5a2e82b3\" data-style=\"\" id=\"6a268b857c20675d5a2e82b3\" width=\"\" data-habr-games=\"\"><\/div>\n<p>\u0412\u0430\u0436\u043d\u043e \u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0432 \u0443\u043c\u0435 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043c\u043e\u043c\u0435\u043d\u0442\u044b:<\/p>\n<ul>\n<li>\n<p>\u041f\u0435\u0440\u0432\u0443\u044e \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044e \u0438\u0437 Mixamo (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u00abIdle\u00bb) \u043d\u0443\u0436\u043d\u043e \u0441\u043a\u0430\u0447\u0430\u0442\u044c \u0441 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u043c \u00abWith Skin\u00bb, \u0432\u0441\u0435 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u2014 \u0441 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u043c \u00abWithout Skin\u00bb<\/p>\n<\/li>\n<li>\n<p>\u0423\u0431\u0435\u0434\u0438\u0442\u0435\u0441\u044c, \u0447\u0442\u043e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d \u0444\u043b\u0430\u0436\u043e\u043a \u00abIn Place\u00bb. \u0423 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0439 \u044d\u0442\u043e\u0442 \u0444\u043b\u0430\u0436\u043e\u043a \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442. \u042d\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u0432 Blender \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0434\u043e\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f In Placer<\/p>\n<\/li>\n<li>\n<p>\u0412 Blender \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u0443\u0439\u0442\u0435 FBX-\u0444\u0430\u0439\u043b, \u0441\u043a\u0430\u0447\u0430\u043d\u043d\u044b\u0439 \u0441 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u043c \u00abWith Skin\u00bb (\u0442\u043e \u0435\u0441\u0442\u044c \u0431\u0430\u0437\u043e\u0432\u0443\u044e \u043c\u043e\u0434\u0435\u043b\u044c), \u0430 \u0437\u0430\u0442\u0435\u043c \u0432\u0441\u0435 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435<\/p>\n<\/li>\n<li>\n<p>\u041d\u0435 \u0437\u0430\u0431\u0443\u0434\u044c\u0442\u0435 \u0443\u0434\u0430\u043b\u0438\u0442\u044c \u0432\u0441\u0435 \u0430\u0440\u043c\u0430\u0442\u0443\u0440\u044b (Armatures), \u043a\u0440\u043e\u043c\u0435 \u0430\u0440\u043c\u0430\u0442\u0443\u0440\u044b \u0431\u0430\u0437\u043e\u0432\u043e\u0439 \u043c\u043e\u0434\u0435\u043b\u0438, \u043f\u043e\u0441\u043b\u0435 \u043d\u0430\u0436\u0430\u0442\u0438\u044f \u043a\u043d\u043e\u043f\u043e\u043a \u00abPush Down Action\u00bb<\/p>\n<\/li>\n<\/ul>\n<hr\/>\n<h3>\u0421\u0442\u0430\u0440\u0442\u043e\u0432\u0430\u044f \u0442\u043e\u0447\u043a\u0430<\/h3>\n<p>\u041c\u044b \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0438\u043c \u0441 \u0442\u043e\u0433\u043e \u0436\u0435 \u0441\u0430\u043c\u043e\u0433\u043e \u043c\u0435\u0441\u0442\u0430, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043b\u0438\u0441\u044c \u0432 \u043a\u043e\u043d\u0446\u0435 \u043f\u0440\u043e\u0448\u043b\u043e\u0439 \u0447\u0430\u0441\u0442\u0438.<\/p>\n<p>\u0415\u0441\u043b\u0438 \u0443 \u0432\u0430\u0441 \u043d\u0435 \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u043b\u043e\u0441\u044c \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0430 \u0442\u043e\u0433\u043e \u0442\u0443\u0442\u043e\u0440\u0438\u0430\u043b\u0430, \u0442\u043e \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0432\u0437\u044f\u0442\u044c \u0435\u0433\u043e \u0437\u0434\u0435\u0441\u044c: <a href=\"https:\/\/github.com\/rds1983\/ThirdPersonTutorial\/tree\/master\/Step1-Capsule\" rel=\"noopener noreferrer nofollow\">https:\/\/github.com\/rds1983\/ThirdPersonTutorial\/tree\/master\/Step1-Capsule<\/a><\/p>\n<h3>\u041d\u0435\u0431\u043e\u043b\u044c\u0448\u0438\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f<\/h3>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u043c\u044b \u0432\u043d\u0435\u0441\u0451\u043c \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0438\u0435 QoL \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0432 \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u043a\u043e\u0434:<\/p>\n<ul>\n<li>\n<p>\u0412\u043a\u043b\u044e\u0447\u0438\u043c DefaultLights \u0432 BasicEffect<\/p>\n<\/li>\n<li>\n<p>\u0420\u0430\u0437\u043e\u0431\u044c\u0451\u043c \u043c\u0435\u0442\u043e\u0434 Update \u043d\u0430 \u0447\u0430\u0441\u0442\u0438<\/p>\n<\/li>\n<li>\n<p>\u0412\u044b\u043d\u0435\u0441\u0435\u043c \u0447\u0430\u0441\u0442\u044c \u043a\u043e\u0434\u0430 DrawMesh \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u043c\u0435\u0442\u043e\u0434<\/p>\n<\/li>\n<\/ul>\n<h4>\u0412\u043a\u043b\u044e\u0447\u0430\u0435\u043c DefaultLights<\/h4>\n<p>\u0423\u0434\u0430\u043b\u0438\u0442\u0435 \u043a\u043e\u0434, \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u044e\u0449\u0438\u0439 DirectionalLight0 \u0432 _basicEffect. \u0418 \u0434\u043e\u0431\u0430\u0432\u044c\u0442\u0435 \u0432\u043c\u0435\u0441\u0442\u043e \u043d\u0435\u0433\u043e(\u0442.\u0435. \u043a\u043e\u0434\u0430) \u0442\u0430\u043a\u0443\u044e \u0441\u0442\u0440\u043e\u043a\u0443:<\/p>\n<pre><code>_basicEffect.EnableDefaultLighting();<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:87px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u042d\u0442\u043e \u0441\u0434\u0435\u043b\u0430\u0435\u0442 \u0441\u0446\u0435\u043d\u0443 \u0431\u043e\u043b\u0435\u0435 \u043e\u0441\u0432\u0435\u0449\u0451\u043d\u043d\u043e\u0439: <\/p>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/\/post_images\/fe6\/2b5\/e73\/fe62b5e731570baef8932d97f3bd0655.png\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/\/post_images\/fe6\/2b5\/e73\/fe62b5e731570baef8932d97f3bd0655.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/\/post_images\/fe6\/2b5\/e73\/fe62b5e731570baef8932d97f3bd0655.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/figure>\n<h4>\u0420\u0435\u0444\u0430\u043a\u0442\u043e\u0440 Update<\/h4>\n<p>\u0414\u043e\u0431\u0430\u0432\u0438\u043c 3 \u043c\u0435\u0442\u043e\u0434\u0430: ProcessMouse, ProcessKeyboard \u0438 UpdateJump<\/p>\n<p>\u0418 \u043f\u0435\u0440\u0435\u043d\u0435\u0441\u0451\u043c \u0432 \u043d\u0438\u0445 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 \u043a\u043e\u0434:<\/p>\n<pre><code>\/\/ Handle mouse input for camera rotationprivate void ProcessMouse(){\/\/ Handle mouse input for camera rotationvar mouse = Mouse.GetState();if (_oldMouse != null){\/\/ Rotate hero by mouse X deltavar horizontalRotation = -(int)((mouse.X - _oldMouse.Value.X) * MouseSensitivity);_heroYaw += horizontalRotation;\/\/ Tilt camera by mouse Y deltavar verticalRotation = -(int)((mouse.Y - _oldMouse.Value.Y) * MouseSensitivity);_cameraMountPitch += verticalRotation;\/\/ Clamp pitch to valid range (5 to 90 degrees)_cameraMountPitch = MathHelper.Clamp(_cameraMountPitch, 5, 90);}_oldMouse = mouse;}\/\/ Handle keyboard input for movement and jump initiationprivate void ProcessKeyboard(){\/\/ Calculate movement velocity based on hero orientationvar velocity = Vector3.Zero;var heroTransform = ToMatrix(_heroPosition, Vector3.One, _heroYaw, 0, 0);var keyboard = Keyboard.GetState();\/\/ Track if hero is moving (for animation transitions)if (keyboard.IsKeyDown(Keys.W))velocity = heroTransform.Forward * -MovementSpeed;else if (keyboard.IsKeyDown(Keys.S))velocity = heroTransform.Forward * MovementSpeed;else if (keyboard.IsKeyDown(Keys.A))velocity = heroTransform.Right * MovementSpeed;else if (keyboard.IsKeyDown(Keys.D))velocity = heroTransform.Right * -MovementSpeed;\/\/ Apply velocity to hero position_heroPosition += velocity;\/\/ Initiate jump with momentum preservationif (keyboard.IsKeyDown(Keys.Space)){_jumpStarted = DateTime.Now;_jumpMovement = velocity;}}\/\/ Update hero position and animation during jump using projectile motionprivate void UpdateJump(){\/\/ Time elapsed since jump started (seconds)var t = (float)(DateTime.Now - _jumpStarted.Value).TotalSeconds;\/\/ Height from kinematic equation: h = h0 + v0*t - 0.5*g*t^2var jumpHeight = DefaultY + JumpForce * t - (0.5f * Gravity * t * t);\/\/ Apply height and preserve horizontal momentum_heroPosition.Y = jumpHeight;_heroPosition += _jumpMovement;\/\/ Land when reaching groundif (_heroPosition.Y &lt;= DefaultY){_heroPosition.Y = DefaultY;_jumpStarted = null;}}protected override void Update(GameTime gameTime){base.Update(gameTime);ProcessMouse();if (_jumpStarted == null){ProcessKeyboard();}else{UpdateJump();}}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043a\u043e\u0434 \u0441\u0442\u0430\u043b \u0431\u043e\u043b\u0435\u0435 \u043f\u0440\u043e\u0441\u0442\u044b\u043c \u0438 \u0447\u0438\u0442\u0430\u0435\u043c\u044b\u043c.<\/p>\n<h4>\u0420\u0435\u0444\u0430\u043a\u0442\u043e\u0440 DrawMesh<\/h4>\n<p>\u0412\u044b\u043d\u0435\u0441\u0435\u043c \u0440\u0438\u0441\u043e\u0432\u0430\u043d\u0438\u0435 DrMeshPart \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u043c\u0435\u0442\u043e\u0434:<\/p>\n<pre><code>\/\/ Draw a single mesh part with the given effectprivate void DrawMeshPart(Effect effect, DrMeshPart part){GraphicsDevice.SetVertexBuffer(part.VertexBuffer);GraphicsDevice.Indices = part.IndexBuffer;foreach (var pass in effect.CurrentTechnique.Passes){pass.Apply();GraphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, part.PrimitiveCount);}}\/\/\/ &lt;summary&gt;Render a mesh with color and texture.&lt;\/summary&gt;private void DrawMesh(DrMesh mesh, Matrix world, Color color, Texture2D texture){_basicEffect.DiffuseColor = color.ToVector3();_basicEffect.TextureEnabled = texture != null;_basicEffect.Texture = texture;_basicEffect.World = world;foreach (var part in mesh.MeshParts){DrawMeshPart(_basicEffect, part);}}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<h4>\u041f\u0440\u043e\u043c\u0435\u0436\u0443\u0442\u043e\u0447\u043d\u044b\u0439 \u0438\u0442\u043e\u0433<\/h4>\n<p>\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u043d\u0430\u0448\u0435\u0433\u043e \u0440\u0435\u0444\u0430\u043a\u0442\u043e\u0440\u0438\u043d\u0433\u0430 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0442\u0443\u0442: <a href=\"https:\/\/github.com\/rds1983\/ThirdPersonTutorial\/blob\/master\/Step2-Refactor\/MyGame.cs\" rel=\"noopener noreferrer nofollow\">https:\/\/github.com\/rds1983\/ThirdPersonTutorial\/blob\/master\/Step2-Refactor\/MyGame.cs<\/a><\/p>\n<hr\/>\n<h3>\u0417\u0430\u043c\u0435\u043d\u044f\u0435\u043c \u043a\u0430\u043f\u0441\u0443\u043b\u0443 \u043d\u0430 \u043c\u043e\u0434\u0435\u043b\u044c<\/h3>\n<p>\u0421\u043a\u0430\u0447\u0430\u0439\u0442\u0435 \u0438 \u0440\u0430\u0437\u0430\u0440\u0445\u0438\u0432\u0438\u0440\u0443\u0439\u0442\u0435 \u0432 \u043f\u0430\u043f\u043a\u0443 \u0441 \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u043c: <a href=\"https:\/\/github.com\/user-attachments\/files\/28683120\/Assets.zip\" rel=\"noopener noreferrer nofollow\">https:\/\/github.com\/user-attachments\/files\/28683120\/Assets.zip<\/a><\/p>\n<p>\u0410\u0440\u0445\u0438\u0432 \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u0438\u0437 gltf \u043c\u043e\u0434\u0435\u043b\u0438 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0430.<\/p>\n<p>\u041f\u0435\u0440\u0435\u0439\u0434\u0451\u043c \u043a \u043a\u043e\u0434\u0443.<\/p>\n<p>\u0423\u0434\u0430\u043b\u044f\u0435\u043c \u043f\u043e\u043b\u0435 _meshHero \u0438 \u0432\u0435\u0441\u044c \u043a\u043e\u0434, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441 \u043d\u0438\u043c \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442. \u0412\u043c\u0435\u0441\u0442\u043e \u043d\u0435\u0433\u043e \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043f\u043e\u043b\u044f:<\/p>\n<pre><code>\/\/ Hero character model instanceprivate DrModelInstance _modelHero;\/\/ Effect for rendering skeletal mesh with bone transformationsprivate SkinnedEffect _skinnedEffect;\/\/ Solid white texture for models without material texturesprivate Texture2D _textureWhite;<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>SkinnedEffect &#8212; \u044d\u0442\u043e \u0430\u043d\u0430\u043b\u043e\u0433 BasicEffect, \u0442\u043e\u043b\u044c\u043a\u043e \u0443\u043c\u0435\u044e\u0449\u0438\u0439 \u0432 \u0441\u043a\u0435\u043b\u0435\u0442\u043d\u0443\u044e \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044e.<\/p>\n<p>_textureWhite &#8212; \u0431\u0435\u043b\u0430\u044f \u0442\u0435\u043a\u0441\u0442\u0443\u0440\u0430 \u0435\u0434\u0438\u043d\u0438\u0447\u043d\u043e\u0433\u043e \u0440\u0430\u0437\u043c\u0435\u0440\u0430. \u041e\u043d\u0430 \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u0430, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0443 \u043d\u0430\u0448\u0435\u0439 \u043c\u043e\u0434\u0435\u043b\u0438 \u043d\u0435\u0442 \u0442\u0435\u043a\u0441\u0442\u0443\u0440.<\/p>\n<p>\u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u043d\u043e\u0432\u044b\u0445 \u043f\u043e\u043b\u0435\u0439 \u0432 LoadContent:<\/p>\n<pre><code>\/\/ Load hero modelDrModel model = assetManager.LoadModel(GraphicsDevice, \"Models\/mixamo.gltf\");_modelHero = new DrModelInstance(model);\/\/ Effect for rendering skeletal meshes with bone transformations_skinnedEffect = new SkinnedEffect(GraphicsDevice);_skinnedEffect.EnableDefaultLighting();\/\/ Create solid white texture for untextured mesh parts_textureWhite = new Texture2D(GraphicsDevice, 1, 1);_textureWhite.SetData(new Color[] { Color.White });<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0415\u0441\u043b\u0438 \u0441 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0435\u0439 _skinnedEffect \u0438 _textureWhite \u0432\u0441\u0451 \u0431\u043e\u043b\u0435\u0435 \u043d\u0438 \u043c\u0435\u043d\u0435\u0435 \u043f\u043e\u043d\u044f\u0442\u043d\u043e.<\/p>\n<p>\u0422\u043e \u043f\u0440\u043e \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0443 \u043c\u043e\u0434\u0435\u043b\u0438 \u0441\u0442\u043e\u0438\u0442 \u0441\u043a\u0430\u0437\u0430\u0442\u044c \u043f\u0430\u0440\u0443 \u0441\u043b\u043e\u0432. \u0417\u0434\u0435\u0441\u044c \u043c\u044b \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u043b\u0438 \u0434\u0432\u0430 \u043a\u043b\u0430\u0441\u0441\u0430 DrModel \u0438 DrModelInstance.<\/p>\n<p>DrModel \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u043c\u043e\u0434\u0435\u043b\u0438: \u043c\u0435\u0448\u0438, \u0438\u0435\u0440\u0430\u0440\u0445\u0438\u044f \u043a\u043e\u0441\u0442\u0435\u0439, \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438, \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u044b \u0438 \u0442.\u0434. \u0424\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 DrModel \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f immutable.<\/p>\n<p>DrModelInstance \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u043e\u043c DrModel. \u0418 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0442\u0430\u043a\u0443\u044e \u0438\u0437\u043c\u0435\u043d\u044f\u044e\u0449\u0443\u044e\u0441\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e, \u043a\u0430\u043a \u0442\u0440\u0430\u043d\u0441\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043a\u043e\u0441\u0442\u0435\u0439 \u0438 \u0442.\u0434.<\/p>\n<p>\u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043a\u0430\u0436\u0434\u0443\u044e DrModel \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u043e\u0431\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0442\u044c \u0432 DrModelInstance. \u0425\u043e\u0442\u044f \u0432 \u044d\u0442\u043e\u0439 \u0441\u0435\u0440\u0438\u0438 \u0442\u0443\u0442\u043e\u0440\u0438\u0430\u043b\u043e\u0432 \u043d\u0430 \u043e\u0434\u043d\u0443 DrModel \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u043e\u0434\u0438\u043d DrModelInstance. \u0412 \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u0445, \u043d\u0430 \u043e\u0434\u043d\u0443 \u043c\u043e\u0434\u0435\u043b\u044c \u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442\u044c\u0441\u044f \u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0443\u0433\u043e\u0434\u043d\u043e \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u043e\u0432.<\/p>\n<h4>\u041c\u0435\u0442\u043e\u0434 DrawModel<\/h4>\n<p>\u0414\u043e\u0431\u0430\u0432\u0438\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u043c\u0435\u0442\u043e\u0434:<\/p>\n<pre><code>\/\/ Render model with material colors and textures, handling both skinned and static meshesprivate void DrawModel(DrModelInstance model, Matrix world){foreach (var mesh in model.Model.Meshes){foreach (var part in mesh.MeshParts){\/\/ Extract material properties or use defaults if no material assignedvar color = Color.White;var texture = _textureWhite;if (part.Material != null){color = part.Material.DiffuseColor;if (part.Material.DiffuseTexture != null){texture = part.Material.DiffuseTexture;}}if (part.Skin != null){\/\/ Skinned mesh: bone transforms applied per-vertex in shader via SetBoneTransforms\/\/ World matrix only positions the entire model in world space_skinnedEffect.DiffuseColor = color.ToVector3();_skinnedEffect.Texture = texture;_skinnedEffect.World = world;_skinnedEffect.SetBoneTransforms(model.GetSkinTransforms(part.Skin.SkinIndex));DrawMeshPart(_skinnedEffect, part);}else{\/\/ Static mesh: must include bone transform in World matrix since GPU doesn't apply skeletal deformation\/\/ Bone transform positions this mesh part relative to the model, then world positions the whole model_basicEffect.DiffuseColor = color.ToVector3();_basicEffect.Texture = texture;_basicEffect.World = model.GetBoneGlobalTransform(mesh.ParentBone.Index) * world;DrawMeshPart(_basicEffect, part);}}}}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0412 \u044d\u0442\u043e\u043c \u043a\u043e\u0434\u0435 \u043d\u0430\u0438\u0431\u043e\u043b\u0435\u0435 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u0430 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 Part.Skin \u043d\u0430 null \u0438 \u0432\u044b\u0431\u043e\u0440 \u044d\u0444\u0444\u0435\u043a\u0442\u0430 \u0434\u043b\u044f \u0440\u0438\u0441\u043e\u0432\u0430\u043d\u0438\u044f \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430.<\/p>\n<p>\u0414\u043b\u044f \u043f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u044f \u044d\u0442\u043e\u0433\u043e \u043a\u043e\u0434\u0430 \u043d\u0443\u0436\u043d\u043e \u0438\u043c\u0435\u0442\u044c \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043e \u0442\u043e\u043c, \u043a\u0430\u043a \u0443\u0441\u0442\u0440\u043e\u0435\u043d\u0430 Gltf-\u043c\u043e\u0434\u0435\u043b\u044c.<\/p>\n<p>\u0412 \u043d\u0435\u0439 \u0441 \u043a\u0430\u0436\u0434\u044b\u043c \u043c\u0435\u0448\u0435\u043c \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0441\u0432\u044f\u0437\u0430\u043d \u0441\u043a\u0438\u043d. \u0421\u043a\u0438\u043d &#8212; \u044d\u0442\u043e \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u044f \u043a\u043e\u0441\u0442\u0435\u0439. \u0412\u044b\u0437\u043e\u0432 model.GetSkinTransforms \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043c\u0430\u0441\u0441\u0438\u0432 \u043c\u0430\u0442\u0440\u0438\u0446 \u0442\u0440\u0430\u043d\u0441\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438, \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 \u044d\u0442\u043e\u0439 \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0438. \u041a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u044b \u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0451\u043c \u0432 SkinnedEffect.<\/p>\n<p>\u0415\u0441\u043b\u0438 \u0441 \u043c\u0435\u0448\u0435\u043c \u043d\u0438\u043a\u0430\u043a\u043e\u0439 \u0441\u043a\u0438\u043d \u043d\u0435 \u0441\u0432\u044f\u0437\u0430\u043d, \u0442\u043e \u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u0441\u044f \u043e\u0431\u044b\u0447\u043d\u044b\u043c BasicEffect.<\/p>\n<p>\u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0442\u0430\u043a \u0436\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435, \u0447\u0442\u043e \u043f\u0440\u0438 \u043d\u0430\u043b\u0438\u0447\u0438\u0438 \u0441\u043a\u0438\u043d\u0430, \u043c\u044b \u043f\u0435\u0440\u0435\u0434\u0430\u0451\u043c \u0432 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 World \u0442\u043e\u043b\u044c\u043a\u043e \u043c\u0438\u0440\u043e\u0432\u0443\u044e \u043c\u0430\u0442\u0440\u0438\u0446\u0443 \u0442\u0440\u0430\u043d\u0441\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043c\u043e\u0434\u0435\u043b\u0438(world).<\/p>\n<p>\u0410 \u043f\u0440\u0438 \u0435\u0433\u043e \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0438, \u043c\u044b \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0443\u043c\u043d\u043e\u0436\u0430\u0435\u043c \u0435\u0451 \u043d\u0430 \u043c\u0430\u0442\u0440\u0438\u0446\u0443 \u0442\u0440\u0430\u043d\u0441\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043a\u043e\u0441\u0442\u0438, \u0441 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0441\u0432\u044f\u0437\u0430\u043d \u043c\u0435\u0448 &#8212; model.GetBoneGlobalTransform(mesh.ParentBone.Index).<\/p>\n<p>\u042d\u0442\u043e \u0441\u0432\u044f\u0437\u0430\u043d\u043e \u0441 \u0442\u0435\u043c, \u0447\u0442\u043e \u0432 \u043f\u0435\u0440\u0432\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043c\u0430\u0441\u0441\u0438\u0432 \u043c\u0430\u0442\u0440\u0438\u0446 \u0438\u0442\u0430\u043a \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0432\u0441\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0442\u0440\u0430\u043d\u0441\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043a\u043e\u0441\u0442\u0435\u0439.<\/p>\n<h4>\u041d\u043e\u0432\u044b\u0439 \u043c\u0435\u0442\u043e\u0434 Draw<\/h4>\n<p>\u041d\u0430\u043a\u043e\u043d\u0435\u0446 \u043d\u0430\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u0430\u0442\u044c \u043c\u0435\u0442\u043e\u0434 Draw, \u0434\u043e\u0431\u0430\u0432\u0438\u0432 \u0442\u0443\u0434\u0430 \u0432\u044b\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043c\u0430\u0442\u0440\u0438\u0446 \u043f\u0440\u043e\u0435\u043a\u0446\u0438\u0438 \u0438 \u0432\u0438\u0434\u0430 \u0434\u043b\u044f SkinnedEffect. \u0410 \u0442\u0430\u043a \u0436\u0435, \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0438\u0442\u044c \u0432\u044b\u0437\u043e\u0432 \u043d\u043e\u0432\u043e\u0433\u043e \u043c\u0435\u0442\u043e\u0434\u0430 DrawModel.<\/p>\n<p>\u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043f\u0435\u0440\u0435\u043f\u0438\u0448\u0435\u043c Draw \u0442\u0430\u043a:<\/p>\n<pre><code>protected override void Draw(GameTime gameTime){base.Draw(gameTime);var device = GraphicsDevice;device.Clear(Color.Black);\/\/ Set GPU statesdevice.DepthStencilState = DepthStencilState.Default;device.RasterizerState = RasterizerState.CullCounterClockwise;device.BlendState = BlendState.AlphaBlend;device.SamplerStates[0] = SamplerState.LinearWrap;\/\/ Set projectionvar projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(ViewAngle),device.Viewport.AspectRatio,NearPlaneDistance, FarPlaneDistance);_basicEffect.Projection = projection;_skinnedEffect.Projection = projection;\/\/ Build camera hierarchy: hero body -&gt; camera mount (head) -&gt; cameravar heroTransform = ToMatrix(_heroPosition, Vector3.One, _heroYaw, 0, 0);var cameraMountTransform = ToMatrix(new Vector3(0, 1f, 0), Vector3.One, 0, _cameraMountPitch, 0) * heroTransform;var cameraTransform = ToMatrix(new Vector3(0, 0, -5), Vector3.One, 180, 0, 0) * cameraMountTransform;var view = Matrix.Invert(cameraTransform);_basicEffect.View = view;_skinnedEffect.View = view;\/\/ Draw ground and heroDrawMesh(_meshGround, Matrix.CreateScale(200, 1, 200), Color.White, _textureGround);DrawModel(_modelHero, heroTransform);}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0415\u0441\u043b\u0438 \u043c\u044b \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u043c \u0438\u0433\u0440\u0443, \u0442\u043e \u0443\u0432\u0438\u0434\u0438\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0435: <\/p>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/\/post_images\/da8\/d85\/3bf\/da8d853bfa0430c7c96bbdcb3bb1ee86.png\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/\/post_images\/da8\/d85\/3bf\/da8d853bfa0430c7c96bbdcb3bb1ee86.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/\/post_images\/da8\/d85\/3bf\/da8d853bfa0430c7c96bbdcb3bb1ee86.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/figure>\n<p>\u041d\u0430\u043c \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u0437\u0430\u043c\u0435\u043d\u0438\u0442\u044c \u043a\u0430\u043f\u0441\u0443\u043b\u0443 \u043d\u0430 \u043c\u043e\u0434\u0435\u043b\u044c. \u041d\u043e \u043e\u043d\u0430 \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u043f\u0430\u0440\u0438\u0442 \u043d\u0430\u0434 \u0437\u0435\u043c\u043b\u0435\u0439. \u0410 \u0432\u0441\u0451 \u0434\u0435\u043b\u043e \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e DefaultY \u0443 \u043d\u0430\u0441 \u0441\u0442\u043e\u0438\u0442 \u0432 1. \u041c\u0435\u043d\u044f\u0435\u043c \u0435\u0433\u043e \u043d\u0430 0:<\/p>\n<pre><code>\/\/ Hero ground heightprivate const float DefaultY = 0;<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043e\u043d\u0430 \u0441\u0442\u043e\u0438\u0442 \u0440\u043e\u0432\u043d\u043e \u043d\u0430 \u0437\u0435\u043c\u043b\u0435: <\/p>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/\/post_images\/e69\/5c8\/394\/e695c83944174a4bb1fa476c5181e884.png\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/\/post_images\/e69\/5c8\/394\/e695c83944174a4bb1fa476c5181e884.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/\/post_images\/e69\/5c8\/394\/e695c83944174a4bb1fa476c5181e884.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/figure>\n<p>\u041d\u043e\u0432\u0430\u044f \u0432\u0435\u0440\u0441\u0438\u044f MyGame.cs: <a href=\"https:\/\/github.com\/rds1983\/ThirdPersonTutorial\/blob\/master\/Step3-Model\/MyGame.cs\" rel=\"noopener noreferrer nofollow\">https:\/\/github.com\/rds1983\/ThirdPersonTutorial\/blob\/master\/Step3-Model\/MyGame.cs<\/a><\/p>\n<hr\/>\n<h3>\u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438<\/h3>\n<p>\u041e\u0431\u044a\u044f\u0432\u0438\u043c \u043d\u043e\u0432\u043e\u0435 \u043f\u043e\u043b\u0435:<\/p>\n<pre><code>\/\/ Animation state machine for playing and transitioning clipsprivate AnimationController _player;<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>AnimationController &#8212; \u043a\u0430\u043a \u0438 \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u0438\u0437 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044f &#8212; \u0430\u043d\u0438\u043c\u0438\u0440\u0443\u0435\u0442 \u043c\u043e\u0434\u0435\u043b\u0438, \u0432\u044b\u0447\u0438\u0441\u043b\u044f\u044f \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u043c\u0430\u0442\u0440\u0438\u0446\u044b \u0442\u0440\u0430\u043d\u0441\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438.<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043a\u043e\u0434 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0432 LoadContent:<\/p>\n<pre><code>_player = new AnimationController(_modelHero);_player.StartClip(\"Idle\", AnimationFlags.Looped);<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0417\u0434\u0435\u0441\u044c \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u0451\u043c AnimationController, \u043f\u0440\u0438\u0432\u044f\u0437\u044b\u0432\u0430\u0435\u043c \u0435\u0433\u043e \u043a _modelHero \u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044e Idle(\u0431\u0435\u0437\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435). \u041c\u044b \u0435\u0451 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u0441 \u0444\u043b\u0430\u0433\u043e\u043c Looped, \u0447\u0442\u043e\u0431\u044b \u043e\u043d\u0430 \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u043a\u0430\u043b\u0430\u0441\u044c \u043f\u043e \u043e\u043a\u043e\u043d\u0447\u0430\u043d\u0438\u0438.<\/p>\n<p>\u041d\u0430\u043a\u043e\u043d\u0435\u0446 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043e\u0434\u043d\u0443 \u0441\u0442\u0440\u043e\u043a\u0443 \u0432 \u043c\u0435\u0442\u043e\u0434 Update:<\/p>\n<pre><code>_player.Update(gameTime.ElapsedGameTime);<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043c\u043e\u0434\u0435\u043b\u044c \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0438\u0433\u0440\u044b\u0432\u0430\u0442\u044c \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044e Idle \u043d\u0430 \u043f\u043e\u0432\u0442\u043e\u0440\u0435: <\/p>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/\/post_images\/422\/4d8\/69f\/4224d869f9daee75076becd181c55bed.png\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/\/post_images\/422\/4d8\/69f\/4224d869f9daee75076becd181c55bed.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/\/post_images\/422\/4d8\/69f\/4224d869f9daee75076becd181c55bed.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/figure>\n<p>\u041d\u043e\u0432\u044b\u0439 MyGame.cs: <a href=\"https:\/\/github.com\/rds1983\/ThirdPersonTutorial\/blob\/master\/Step4-AnimationController\/MyGame.cs\" rel=\"noopener noreferrer nofollow\">https:\/\/github.com\/rds1983\/ThirdPersonTutorial\/blob\/master\/Step4-AnimationController\/MyGame.cs<\/a><\/p>\n<hr\/>\n<h3>\u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438 \u0431\u0435\u0433\u0430 \u0438 \u043f\u0440\u044b\u0436\u043a\u0430<\/h3>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0435, \u043e\u0431\u043e\u0437\u043d\u0430\u0447\u0430\u044e\u0449\u0438\u0435 \u0441\u043f\u0438\u0441\u043e\u043a \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u0445 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438:<\/p>\n<pre><code>\/\/ Animation states for the hero characterprivate enum AnimationState{Idle,      \/\/ Standing stillRunning,   \/\/ MovingJumping,   \/\/ Jumping}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0422\u0430\u043a \u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043e\u0447\u0435\u0440\u0435\u0434\u043d\u0443\u044e \u043a\u043e\u043d\u0441\u0442\u0430\u043d\u0442\u0443, \u0435\u0451 \u0441\u043c\u044b\u0441\u043b \u044f \u043f\u043e\u044f\u0441\u043d\u044e \u0432 \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u043c:<\/p>\n<pre><code>\/\/ Duration for animation transitions between clipsprivate static readonly TimeSpan AnimationCrossfadeDelay = TimeSpan.FromSeconds(0.2f);<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u043f\u043e\u043b\u0435 \u0442\u0435\u043a\u0443\u0449\u0435\u0439 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438:<\/p>\n<pre><code>\/\/ Current animation stateprivate AnimationState _animationState = AnimationState.Idle;<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0414\u043e\u0431\u0430\u0432\u0438\u043c \u0432 ProcessKeyboard \u043a\u043e\u0434, \u043c\u0435\u043d\u044f\u044e\u0449\u0438\u0439 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438:<\/p>\n<pre><code>\/\/ Handle keyboard input for movement and jump initiationprivate void ProcessKeyboard(){\/\/ Calculate movement velocity based on hero orientationvar velocity = Vector3.Zero;var heroTransform = ToMatrix(_heroPosition, Vector3.One, _heroYaw, 0, 0);var keyboard = Keyboard.GetState();\/\/ Track if hero is moving (for animation transitions)var isRunning = true;if (keyboard.IsKeyDown(Keys.W))velocity = heroTransform.Forward * -MovementSpeed;else if (keyboard.IsKeyDown(Keys.S))velocity = heroTransform.Forward * MovementSpeed;else if (keyboard.IsKeyDown(Keys.A))velocity = heroTransform.Right * MovementSpeed;else if (keyboard.IsKeyDown(Keys.D))velocity = heroTransform.Right * -MovementSpeed;elseisRunning = false;\/\/ Transition between Run and Idle animationsif (_animationState != AnimationState.Running &amp;&amp; isRunning){_player.CrossfadeToClip(\"Run\", AnimationCrossfadeDelay, AnimationFlags.Looped);_animationState = AnimationState.Running;}else if (_animationState != AnimationState.Idle &amp;&amp; !isRunning){_player.CrossfadeToClip(\"Idle\", AnimationCrossfadeDelay, AnimationFlags.Looped);_animationState = AnimationState.Idle;}\/\/ Apply velocity to hero position_heroPosition += velocity;\/\/ Initiate jump with momentum preservationif (keyboard.IsKeyDown(Keys.Space)){_jumpStarted = DateTime.Now;_animationState = AnimationState.Jumping;_jumpMovement = velocity;_player.CrossfadeToClip(\"JumpStart\", AnimationCrossfadeDelay);}}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0421\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e, \u0437\u0430 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0439 \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0432\u044b\u0437\u043e\u0432 CrossfadeToClip.<\/p>\n<p>\u041c\u044b \u043c\u043e\u0433\u043b\u0438 \u0431\u044b &#8212; \u043a\u0430\u043a \u0438 \u0432 LoadContent &#8212; \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c StartClip. \u041d\u043e \u0442\u043e\u0433\u0434\u0430 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438 \u0431\u044b \u0440\u0435\u0437\u043a\u043e \u0441\u043c\u0435\u043d\u044f\u043b\u0438\u0441\u044c \u043e\u0434\u043d\u0430 \u043d\u0430 \u0434\u0440\u0443\u0433\u0443\u044e. CrossfadeToClip, \u0436\u0435, \u0434\u0435\u043b\u0430\u0435\u0442 \u044d\u0442\u043e \u043f\u043b\u0430\u0432\u043d\u043e \u0432 \u0442\u0435\u0447\u0435\u043d\u0438\u0438 \u0437\u0430\u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438. \u0412 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435, \u044d\u0442\u043e \u0440\u0430\u043d\u0435\u0435 \u0437\u0430\u0434\u0430\u043d\u043d\u0430\u044f \u043a\u043e\u043d\u0441\u0442\u0430\u043d\u0442\u0430 AnimationCrossfadeDelay, \u0440\u0430\u0432\u043d\u0430\u044f 200 \u043c\u0441.<\/p>\n<p>\u0415\u0441\u043b\u0438 \u043c\u044b \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u043c \u0438\u0433\u0440\u0443, \u0442\u043e \u0432\u0441\u0451 \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0431\u043e\u043b\u0435\u0435 \u043d\u0438 \u043c\u0435\u043d\u0435\u0435 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e, \u043a\u0440\u043e\u043c\u0435 \u043f\u0440\u0438\u0437\u0435\u043c\u043b\u0435\u043d\u0438\u044f. \u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044f \u043f\u0440\u044b\u0436\u043a\u0430 \u043d\u0430\u0447\u043d\u0451\u0442 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0430\u0442\u044c\u0441\u044f \u043d\u0430 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044e \u0431\u0435\u0437\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0432 \u043c\u043e\u043c\u0435\u043d\u0442 \u043f\u0440\u0438\u0437\u0435\u043c\u043b\u0435\u043d\u0438\u044f:<\/p>\n<div class=\"tm-iframe_temp\" data-src=\"https:\/\/embedd.srv.habr.com\/iframe\/6a268b85ba4e8d8f13084cbc\" data-style=\"\" id=\"6a268b85ba4e8d8f13084cbc\" width=\"\" data-habr-games=\"\"><\/div>\n<p>\u041c\u044b \u0431\u044b \u0445\u043e\u0442\u0435\u043b\u0438, \u0447\u0442\u043e\u0431\u044b \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044f \u043f\u0440\u0438\u0437\u0435\u043c\u043b\u0435\u043d\u0438\u044f \u043d\u0430\u0447\u0438\u043d\u0430\u043b\u0430\u0441\u044c \u0432 \u043c\u043e\u043c\u0435\u043d\u0442 \u043f\u0440\u044b\u0436\u043a\u0430, \u043a\u043e\u0433\u0434\u0430 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436 \u043f\u0430\u0434\u0430\u0435\u0442 \u0438 \u043f\u0440\u0438\u0431\u043b\u0438\u0436\u0430\u0435\u0442\u0441\u044f \u043a \u0437\u0435\u043c\u043b\u0435.<\/p>\n<p>\u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043f\u0435\u0440\u0435\u043f\u0438\u0448\u0435\u043c \u043a\u043e\u0434 UpdateJump \u0442\u0430\u043a:<\/p>\n<pre><code>\/\/ Update hero position and animation during jump using projectile motionprivate void UpdateJump(){\/\/ Time elapsed since jump started (seconds)var t = (float)(DateTime.Now - _jumpStarted.Value).TotalSeconds;\/\/ Height from kinematic equation: h = v0*t - 0.5*g*t^2var jumpHeight = JumpForce * t - (0.5f * Gravity * t * t);\/\/ Apply height and preserve horizontal momentum_heroPosition.Y = jumpHeight;_heroPosition += _jumpMovement;\/\/ Vertical velocity: v = v0 - g*t (positive = upward, negative = falling)var jumpVelocity = JumpForce - Gravity * t;\/\/ Start falling animation once we fall below height 2if (jumpVelocity &lt; 0 &amp;&amp; _heroPosition.Y &lt; 2 &amp;&amp; _animationState != AnimationState.Landing){_player.CrossfadeToClip(\"JumpEnd\", AnimationCrossfadeDelay);_animationState = AnimationState.Landing;}\/\/ Land when reaching groundif (_heroPosition.Y &lt;= DefaultY){_heroPosition.Y = DefaultY;_jumpStarted = null;}}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041c\u044b \u0432\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u043c \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c \u043f\u0440\u044b\u0436\u043a\u0430(jumpVelocity), \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u043d\u044f\u0442\u044c \u043f\u0430\u0434\u0430\u0435\u043c \u043b\u0438 \u043c\u044b(jumpVelocity &lt; 0). \u0415\u0441\u043b\u0438 \u043f\u0430\u0434\u0430\u0435\u043c \u0438 \u0443\u043f\u0430\u043b\u0438 \u043d\u0438\u0436\u0435 \u0432\u044b\u0441\u043e\u0442\u044b 2, \u0442\u043e \u0432\u043a\u043b\u044e\u0447\u0430\u0435\u043c \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044e \u043e\u043a\u043e\u043d\u0447\u0430\u043d\u0438\u044f \u043f\u0440\u044b\u0436\u043a\u0430.<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044f \u043f\u0440\u0438\u0437\u0435\u043c\u043b\u0435\u043d\u0438\u044f \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u043a\u0430\u043a \u043d\u0430\u0434\u043e:<\/p>\n<div class=\"tm-iframe_temp\" data-src=\"https:\/\/embedd.srv.habr.com\/iframe\/6a268b851188658f68334409\" data-style=\"\" id=\"6a268b851188658f68334409\" width=\"\" data-habr-games=\"\"><\/div>\n<p>\u0414\u0430 \u0438 \u0431\u0435\u0433 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u043e:<\/p>\n<div class=\"tm-iframe_temp\" data-src=\"https:\/\/embedd.srv.habr.com\/iframe\/6a268b856e2a155d357b2887\" data-style=\"\" id=\"6a268b856e2a155d357b2887\" width=\"\" data-habr-games=\"\"><\/div>\n<p>\u041d\u043e\u0432\u044b\u0439 MyGame.cs: <a href=\"https:\/\/github.com\/rds1983\/ThirdPersonTutorial\/blob\/master\/Step5-BasicAnimations\/MyGame.cs\" rel=\"noopener noreferrer nofollow\">https:\/\/github.com\/rds1983\/ThirdPersonTutorial\/blob\/master\/Step5-BasicAnimations\/MyGame.cs<\/a><\/p>\n<hr\/>\n<h3>\u0426\u0435\u043f\u043b\u044f\u0435\u043c \u043c\u0435\u0447 \u043d\u0430 \u0441\u043f\u0438\u043d\u0443<\/h3>\n<p>\u0421\u043a\u0430\u0447\u0430\u0439\u0442\u0435 \u043e\u0447\u0435\u0440\u0435\u0434\u043d\u043e\u0439 \u0430\u0440\u0445\u0438\u0432 \u0438 \u0440\u0430\u0437\u0430\u0440\u0445\u0438\u0432\u0438\u0440\u0443\u0439\u0442\u0435 \u0432 \u043f\u0430\u043f\u043a\u0443 \u043f\u0440\u043e\u0435\u043a\u0442\u0430: <a href=\"https:\/\/github.com\/user-attachments\/files\/28683215\/Assets.zip\" rel=\"noopener noreferrer nofollow\">https:\/\/github.com\/user-attachments\/files\/28683215\/Assets.zip<\/a><\/p>\n<p>\u041e\u043d \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u043c\u043e\u0434\u0435\u043b\u044c \u043c\u0435\u0447\u0430.<\/p>\n<p>\u0421\u043f\u043e\u0441\u043e\u0431 \u043f\u0440\u0438\u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f \u043c\u0435\u0447\u0430 \u043e\u0447\u0435\u043d\u044c \u043f\u0440\u043e\u0441\u0442. \u041c\u044b \u043f\u0440\u043e\u0441\u0442\u043e \u0432\u044b\u0431\u0435\u0440\u0435\u043c \u043e\u0434\u043d\u0443 \u0438\u0437 \u043a\u043e\u0441\u0442\u0435\u0439 \u043c\u043e\u0434\u0435\u043b\u0438 \u0438 \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u043c \u0435\u0451 \u0442\u0440\u0430\u043d\u0441\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043d\u0430 \u043c\u043e\u0434\u0435\u043b\u0438 \u043c\u0435\u0447\u0430.<\/p>\n<p>\u041f\u0435\u0440\u0435\u0439\u0434\u0451\u043c \u043a \u043a\u043e\u0434\u0443.<\/p>\n<p>\u0414\u043e\u0431\u0430\u0432\u0438\u043c \u043a\u043e\u043d\u0441\u0442\u0430\u043d\u0442\u0443:<\/p>\n<pre><code>\/\/ Sword local transform: position offset (-12, 0, -20), scale 16x, rotated 180 degrees on Z axis (sheathed on back)private static readonly Matrix _swordSheathedTransform = ToMatrix(new Vector3(-12, 0, -20), new Vector3(16), 0, 0, 180);<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u042d\u0442\u043e \u0432\u0440\u0443\u0447\u043d\u0443\u044e \u043f\u043e\u0434\u043e\u0431\u0440\u0430\u043d\u043d\u0430\u044f \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u0430\u044f \u0442\u0440\u0430\u043d\u0441\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u043c\u0435\u0447\u0430, \u043f\u0440\u0438\u0446\u0435\u043f\u043b\u0435\u043d\u043d\u043e\u0433\u043e \u043a \u0441\u043f\u0438\u043d\u0435.<\/p>\n<p>\u0414\u043e\u0431\u0430\u0432\u0438\u043c \u043f\u043e\u043b\u044f:<\/p>\n<pre><code>\/\/ Sword model instanceprivate DrModelInstance _modelSword;\/\/ Bone where sword is attachedprivate DrModelBone _swordAttachBone;<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0421\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e, \u044d\u0442\u043e \u043c\u043e\u0434\u0435\u043b\u044c \u043c\u0435\u0447\u0430 \u0438 \u043a\u043e\u0441\u0442\u044c \u043c\u043e\u0434\u0435\u043b\u0438 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0430, \u043a \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043c\u044b \u0435\u0433\u043e \u043f\u0440\u0438\u0446\u0435\u043f\u0438\u043c.<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0432 LoadContent \u0442\u0430\u043a\u043e\u0439 \u043a\u043e\u0434(\u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u043f\u043e\u0441\u043b\u0435 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 _modelHero:<\/p>\n<pre><code>\/\/ Load sword modelmodel = assetManager.LoadModel(GraphicsDevice, \"Models\/sword.gltf\");_modelSword = new DrModelInstance(model);\/\/ Set the bone we will attach the sword to_swordAttachBone = _modelHero.Model.FindBoneByName(\"mixamorig:Spine\");<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0417\u0434\u0435\u0441\u044c \u043c\u044b \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c \u043c\u043e\u0434\u0435\u043b\u044c \u043c\u0435\u0447\u0430 \u0438 \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043a\u043e\u0441\u0442\u0438 \u043f\u0440\u0438\u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f \u0432\u044b\u0431\u0438\u0440\u0430\u0435\u043c \u0441\u043f\u0438\u043d\u0443 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0430.<\/p>\n<p>\u041d\u0430\u043a\u043e\u043d\u0435\u0446 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043a\u043e\u0434 \u0432 Draw:<\/p>\n<pre><code>\/\/ Attach the sword to attachment bone\/\/ Transform chain: _swordSheathedTransform (local offset) -&gt; attachment bone transform -&gt; hero world transformvar swordTransform = _swordSheathedTransform * _modelHero.GetBoneGlobalTransform(_swordAttachBone.Index) * heroTransform;DrawModel(_modelSword, swordTransform);<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0412\u043d\u0430\u0447\u0430\u043b\u0435 \u043c\u044b \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u043c \u043a \u043c\u043e\u0434\u0435\u043b\u0438 \u0440\u0430\u043d\u0435\u0435 \u0432\u0432\u0435\u0434\u0451\u043d\u043d\u0443\u044e \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u0443\u044e \u0442\u0440\u0430\u043d\u0441\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e. \u0414\u0430\u043b\u044c\u0448\u0435 \u043c\u044b \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u043c \u043a \u043c\u043e\u0434\u0435\u043b\u0438 \u0442\u0440\u0430\u043d\u0441\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043a\u043e\u0441\u0442\u0438 \u0441\u043f\u0438\u043d\u044b. \u0410 \u0437\u0430\u0442\u0435\u043c \u0432\u0441\u0435\u0433\u043e \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0430.<\/p>\n<p>\u0412 \u0438\u0442\u043e\u0433\u0435 \u043c\u0435\u0447 \u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043d\u0430 \u0441\u043f\u0438\u043d\u0435: <\/p>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/\/post_images\/058\/30b\/0c2\/05830b0c20fec216cce7776e6da26746.png\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/\/post_images\/058\/30b\/0c2\/05830b0c20fec216cce7776e6da26746.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/\/post_images\/058\/30b\/0c2\/05830b0c20fec216cce7776e6da26746.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/figure>\n<hr\/>\n<h3>\u0417\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435<\/h3>\n<p>\u0422\u0443\u0442\u043e\u0440\u0438\u0430\u043b \u043e\u043a\u043e\u043d\u0447\u0435\u043d. \u0418\u0433\u0440\u0430 \u0434\u043e\u043b\u0436\u043d\u0430 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u0432\u0438\u0434\u0435\u043e \u0432 \u043d\u0430\u0447\u0430\u043b\u0435 \u0441\u0442\u0430\u0442\u044c\u0438.<\/p>\n<p>\u0424\u0438\u043d\u0430\u043b\u044c\u043d\u044b\u0439 MyGame.cs: <a href=\"https:\/\/github.com\/rds1983\/ThirdPersonTutorial\/blob\/master\/Step6-SwordOnBack\/MyGame.cs\" rel=\"noopener noreferrer nofollow\">https:\/\/github.com\/rds1983\/ThirdPersonTutorial\/blob\/master\/Step6-SwordOnBack\/MyGame.cs<\/a><\/p>\n<p>\u0412 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0447\u0430\u0441\u0442\u0438 \u043c\u044b \u0438\u0437\u0443\u0447\u0438\u043c \u0441\u043c\u0435\u0448\u0438\u0432\u0430\u043d\u0438\u0435 \u0440\u0430\u0437\u043d\u044b\u0445 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0439. \u0418 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0434\u043e\u0441\u0442\u0430\u0432\u0430\u043d\u0438\u0435\/\u0443\u0431\u0438\u0440\u0430\u043d\u0438\u0435 \u043c\u0435\u0447\u0430 \u0438 \u0432\u0437\u043c\u0430\u0445 \u0438\u043c.<\/p>\n<\/div>\n<p>\u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/1044786\/\">https:\/\/habr.com\/ru\/articles\/1044786\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u0412\u0432\u0435\u0434\u0435\u043d\u0438\u0435\u042d\u0442\u043e \u0432\u0442\u043e\u0440\u0430\u044f \u0447\u0430\u0441\u0442\u044c \u0441\u0435\u0440\u0438\u0438 \u0442\u0443\u0442\u043e\u0440\u0438\u0430\u043b\u043e\u0432, \u0433\u0434\u0435 \u043c\u044b \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c Third Person Controller \u043d\u0430 MonoGame.\u041f\u0435\u0440\u0432\u0430\u044f \u0447\u0430\u0441\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u0430 \u0442\u0443\u0442: https:\/\/habr.com\/ru\/articles\/1040382\/\u0412 \u044d\u0442\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u043c\u044b \u0437\u0430\u043c\u0435\u043d\u0438\u043c \u043a\u0430\u043f\u0441\u0443\u043b\u0443 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0430 \u043d\u0430 \u0430\u043d\u0438\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u0443\u044e \u043c\u043e\u0434\u0435\u043b\u044c. \u0418 \u043f\u0440\u0438\u0446\u0435\u043f\u0438\u043c \u043c\u0435\u0447 \u043d\u0430 \u0441\u043f\u0438\u043d\u0443:\u0414\u043b\u044f \u043f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u044f \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u0430 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0438\u043c\u0435\u0442\u044c \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043e \u0442\u043e\u043c, \u0447\u0442\u043e \u0442\u0430\u043a\u043e\u0435 gltf\/glb \u0438 \u043a\u0430\u043a \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0441\u043a\u0435\u043b\u0435\u0442\u043d\u0430\u044f \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044f. \u0412 \u0418\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0435 \u043f\u043e\u043b\u043d\u043e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043d\u0430 \u044d\u0442\u0443 \u0442\u0435\u043c\u0443. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0441\u0442\u0430\u0442\u044c\u044f \u043d\u0430 learnopengl: https:\/\/learnopengl.com\/Guest-Articles\/2020\/Skeletal-Animation\u041e\u0431\u044a\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 fbx \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0439 \u0432 \u043e\u0434\u043d\u0443 \u043c\u043e\u0434\u0435\u043b\u044c gltf(\u043d\u0435\u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u0430\u044f \u0433\u043b\u0430\u0432\u0430)\u042d\u0442\u0430 \u0433\u043b\u0430\u0432\u0430 \u043d\u0435\u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u0430 \u0434\u043b\u044f \u0442\u0443\u0442\u043e\u0440\u0438\u0430\u043b\u0430. \u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0432 \u043d\u0451\u043c \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0430 \u043c\u043e\u0434\u0435\u043b\u044c gltf \u0441\u0440\u0430\u0437\u0443 \u0441\u043e \u0432\u0441\u0435\u043c \u043d\u0443\u0436\u043d\u044b\u043c\u0438 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044f\u043c\u0438.\u041d\u043e \u0435\u0441\u043b\u0438 \u0432\u044b \u0441\u0430\u043c\u0438 \u0437\u0430\u0445\u043e\u0442\u0438\u0442\u0435 \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0441\u0432\u043e\u044e \u0430\u043d\u0438\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u0443\u044e \u043c\u043e\u0434\u0435\u043b\u044c \u043d\u0430 \u0431\u0430\u0437\u0435 mixamo, \u0442\u043e \u0432\u0430\u043c \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043b\u0435\u0437\u043d\u043e \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u044d\u0442\u043e \u0432\u0438\u0434\u0435\u043e, \u0433\u0434\u0435 \u0432\u043d\u0430\u0447\u0430\u043b\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438 \u0441\u043a\u0430\u0447\u0438\u0432\u0430\u044e\u0442\u0441\u044f. \u0410 \u043f\u043e\u0442\u043e\u043c \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u044f\u044e\u0442\u0441\u044f \u0432 blendere \u0438 \u044d\u043a\u0441\u043f\u043e\u0440\u0442\u044f\u0442\u0441\u044f \u0432 glb(\u0431\u0438\u043d\u0430\u0440\u043d\u0430\u044f \u0432\u0435\u0440\u0441\u0438\u044f gltf):\u0412\u0430\u0436\u043d\u043e \u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0432 \u0443\u043c\u0435 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043c\u043e\u043c\u0435\u043d\u0442\u044b:\u041f\u0435\u0440\u0432\u0443\u044e \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044e \u0438\u0437 Mixamo (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u00abIdle\u00bb) \u043d\u0443\u0436\u043d\u043e \u0441\u043a\u0430\u0447\u0430\u0442\u044c \u0441 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u043c \u00abWith Skin\u00bb, \u0432\u0441\u0435 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u2014 \u0441 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u043c \u00abWithout Skin\u00bb\u0423\u0431\u0435\u0434\u0438\u0442\u0435\u0441\u044c, \u0447\u0442\u043e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d \u0444\u043b\u0430\u0436\u043e\u043a \u00abIn Place\u00bb. \u0423 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0439 \u044d\u0442\u043e\u0442 \u0444\u043b\u0430\u0436\u043e\u043a \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442. \u042d\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u0432 Blender \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0434\u043e\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f In Placer\u0412 Blender \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u0443\u0439\u0442\u0435 FBX-\u0444\u0430\u0439\u043b, \u0441\u043a\u0430\u0447\u0430\u043d\u043d\u044b\u0439 \u0441 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u043c \u00abWith Skin\u00bb (\u0442\u043e \u0435\u0441\u0442\u044c \u0431\u0430\u0437\u043e\u0432\u0443\u044e \u043c\u043e\u0434\u0435\u043b\u044c), \u0430 \u0437\u0430\u0442\u0435\u043c \u0432\u0441\u0435 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435\u041d\u0435 \u0437\u0430\u0431\u0443\u0434\u044c\u0442\u0435 \u0443\u0434\u0430\u043b\u0438\u0442\u044c \u0432\u0441\u0435 \u0430\u0440\u043c\u0430\u0442\u0443\u0440\u044b (Armatures), \u043a\u0440\u043e\u043c\u0435 \u0430\u0440\u043c\u0430\u0442\u0443\u0440\u044b \u0431\u0430\u0437\u043e\u0432\u043e\u0439 \u043c\u043e\u0434\u0435\u043b\u0438, \u043f\u043e\u0441\u043b\u0435 \u043d\u0430\u0436\u0430\u0442\u0438\u044f \u043a\u043d\u043e\u043f\u043e\u043a \u00abPush Down Action\u00bb\u0421\u0442\u0430\u0440\u0442\u043e\u0432\u0430\u044f \u0442\u043e\u0447\u043a\u0430\u041c\u044b \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0438\u043c \u0441 \u0442\u043e\u0433\u043e \u0436\u0435 \u0441\u0430\u043c\u043e\u0433\u043e \u043c\u0435\u0441\u0442\u0430, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043b\u0438\u0441\u044c \u0432 \u043a\u043e\u043d\u0446\u0435 \u043f\u0440\u043e\u0448\u043b\u043e\u0439 \u0447\u0430\u0441\u0442\u0438.\u0415\u0441\u043b\u0438 \u0443 \u0432\u0430\u0441 \u043d\u0435 \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u043b\u043e\u0441\u044c \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0430 \u0442\u043e\u0433\u043e \u0442\u0443\u0442\u043e\u0440\u0438\u0430\u043b\u0430, \u0442\u043e \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0432\u0437\u044f\u0442\u044c \u0435\u0433\u043e \u0437\u0434\u0435\u0441\u044c: https:\/\/github.com\/rds1983\/ThirdPersonTutorial\/tree\/master\/Step1-Capsule\u041d\u0435\u0431\u043e\u043b\u044c\u0448\u0438\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u043c\u044b \u0432\u043d\u0435\u0441\u0451\u043c \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0438\u0435 QoL \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0432 \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u043a\u043e\u0434:\u0412\u043a\u043b\u044e\u0447\u0438\u043c DefaultLights \u0432 BasicEffect\u0420\u0430\u0437\u043e\u0431\u044c\u0451\u043c \u043c\u0435\u0442\u043e\u0434 Update \u043d\u0430 \u0447\u0430\u0441\u0442\u0438\u0412\u044b\u043d\u0435\u0441\u0435\u043c \u0447\u0430\u0441\u0442\u044c \u043a\u043e\u0434\u0430 DrawMesh \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u043c\u0435\u0442\u043e\u0434\u0412\u043a\u043b\u044e\u0447\u0430\u0435\u043c DefaultLights\u0423\u0434\u0430\u043b\u0438\u0442\u0435 \u043a\u043e\u0434, \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u044e\u0449\u0438\u0439 DirectionalLight0 \u0432 _basicEffect. \u0418 \u0434\u043e\u0431\u0430\u0432\u044c\u0442\u0435 \u0432\u043c\u0435\u0441\u0442\u043e \u043d\u0435\u0433\u043e(\u0442.\u0435. \u043a\u043e\u0434\u0430) \u0442\u0430\u043a\u0443\u044e \u0441\u0442\u0440\u043e\u043a\u0443:_basicEffect.EnableDefaultLighting();\u042d\u0442\u043e \u0441\u0434\u0435\u043b\u0430\u0435\u0442 \u0441\u0446\u0435\u043d\u0443 \u0431\u043e\u043b\u0435\u0435 \u043e\u0441\u0432\u0435\u0449\u0451\u043d\u043d\u043e\u0439: \u0420\u0435\u0444\u0430\u043a\u0442\u043e\u0440 Update\u0414\u043e\u0431\u0430\u0432\u0438\u043c 3 \u043c\u0435\u0442\u043e\u0434\u0430: ProcessMouse, ProcessKeyboard \u0438 UpdateJump\u0418 \u043f\u0435\u0440\u0435\u043d\u0435\u0441\u0451\u043c \u0432 \u043d\u0438\u0445 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 \u043a\u043e\u0434:\/\/ Handle mouse input for camera rotationprivate void ProcessMouse(){\/\/ Handle mouse input for camera rotationvar mouse = Mouse.GetState();if (_oldMouse != null){\/\/ Rotate hero by mouse X deltavar horizontalRotation = -(int)((mouse.X &#8212; _oldMouse.Value.X) * MouseSensitivity);_heroYaw += horizontalRotation;\/\/ Tilt camera by mouse Y deltavar verticalRotation = -(int)((mouse.Y &#8212; _oldMouse.Value.Y) * MouseSensitivity);_cameraMountPitch += verticalRotation;\/\/ Clamp pitch to valid range (5 to 90 degrees)_cameraMountPitch = MathHelper.Clamp(_cameraMountPitch, 5, 90);}_oldMouse = mouse;}\/\/ Handle keyboard input for movement and jump initiationprivate void ProcessKeyboard(){\/\/ Calculate movement velocity based on hero orientationvar velocity = Vector3.Zero;var heroTransform = ToMatrix(_heroPosition, Vector3.One, _heroYaw, 0, 0);var keyboard = Keyboard.GetState();\/\/ Track if hero is moving (for animation transitions)if (keyboard.IsKeyDown(Keys.W))velocity = heroTransform.Forward * -MovementSpeed;else if (keyboard.IsKeyDown(Keys.S))velocity = heroTransform.Forward * MovementSpeed;else if (keyboard.IsKeyDown(Keys.A))velocity = heroTransform.Right * MovementSpeed;else if (keyboard.IsKeyDown(Keys.D))velocity = heroTransform.Right * -MovementSpeed;\/\/ Apply velocity to hero position_heroPosition += velocity;\/\/ Initiate jump with momentum preservationif (keyboard.IsKeyDown(Keys.Space)){_jumpStarted = DateTime.Now;_jumpMovement = velocity;}}\/\/ Update hero position and animation during jump using projectile motionprivate void UpdateJump(){\/\/ Time elapsed since jump started (seconds)var t = (float)(DateTime.Now &#8212; _jumpStarted.Value).TotalSeconds;\/\/ Height from kinematic equation: h = h0 + v0*t &#8212; 0.5*g*t^2var jumpHeight = DefaultY + JumpForce * t &#8212; (0.5f * Gravity * t * t);\/\/ Apply height and preserve horizontal momentum_heroPosition.Y = jumpHeight;_heroPosition += _jumpMovement;\/\/ Land when reaching groundif (_heroPosition.Y &lt;= DefaultY){_heroPosition.Y = DefaultY;_jumpStarted = null;}}protected override void Update(GameTime gameTime){base.Update(gameTime);ProcessMouse();if (_jumpStarted == null){ProcessKeyboard();}else{UpdateJump();}}\u0422\u0435\u043f\u0435\u0440\u044c \u043a\u043e\u0434 \u0441\u0442\u0430\u043b \u0431\u043e\u043b\u0435\u0435 \u043f\u0440\u043e\u0441\u0442\u044b\u043c \u0438 \u0447\u0438\u0442\u0430\u0435\u043c\u044b\u043c.\u0420\u0435\u0444\u0430\u043a\u0442\u043e\u0440 DrawMesh\u0412\u044b\u043d\u0435\u0441\u0435\u043c \u0440\u0438\u0441\u043e\u0432\u0430\u043d\u0438\u0435 DrMeshPart \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u043c\u0435\u0442\u043e\u0434:\/\/ Draw a single mesh part with the given effectprivate void DrawMeshPart(Effect effect, DrMeshPart part){GraphicsDevice.SetVertexBuffer(part.VertexBuffer);GraphicsDevice.Indices = part.IndexBuffer;foreach (var pass in effect.CurrentTechnique.Passes){pass.Apply();GraphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, part.PrimitiveCount);}}\/\/\/ &lt;summary&gt;Render a mesh with color and texture.&lt;\/summary&gt;private void DrawMesh(DrMesh mesh, Matrix world, Color color, Texture2D texture){_basicEffect.DiffuseColor = color.ToVector3();_basicEffect.TextureEnabled = texture != null;_basicEffect.Texture = texture;_basicEffect.World = world;foreach (var part in mesh.MeshParts){DrawMeshPart(_basicEffect, part);}}\u041f\u0440\u043e\u043c\u0435\u0436\u0443\u0442\u043e\u0447\u043d\u044b\u0439 \u0438\u0442\u043e\u0433\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u043d\u0430\u0448\u0435\u0433\u043e \u0440\u0435\u0444\u0430\u043a\u0442\u043e\u0440\u0438\u043d\u0433\u0430 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0442\u0443\u0442: https:\/\/github.com\/rds1983\/ThirdPersonTutorial\/blob\/master\/Step2-Refactor\/MyGame.cs\u0417\u0430\u043c\u0435\u043d\u044f\u0435\u043c \u043a\u0430\u043f\u0441\u0443\u043b\u0443 \u043d\u0430 \u043c\u043e\u0434\u0435\u043b\u044c\u0421\u043a\u0430\u0447\u0430\u0439\u0442\u0435 \u0438 \u0440\u0430\u0437\u0430\u0440\u0445\u0438\u0432\u0438\u0440\u0443\u0439\u0442\u0435 \u0432 \u043f\u0430\u043f\u043a\u0443 \u0441 \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u043c: https:\/\/github.com\/user-attachments\/files\/28683120\/Assets.zip\u0410\u0440\u0445\u0438\u0432 \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u0438\u0437 gltf \u043c\u043e\u0434\u0435\u043b\u0438 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0430.\u041f\u0435\u0440\u0435\u0439\u0434\u0451\u043c \u043a \u043a\u043e\u0434\u0443.\u0423\u0434\u0430\u043b\u044f\u0435\u043c \u043f\u043e\u043b\u0435 _meshHero \u0438 \u0432\u0435\u0441\u044c \u043a\u043e\u0434, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441 \u043d\u0438\u043c \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442. \u0412\u043c\u0435\u0441\u0442\u043e \u043d\u0435\u0433\u043e \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043f\u043e\u043b\u044f:\/\/ Hero character model instanceprivate DrModelInstance _modelHero;\/\/ Effect for rendering skeletal mesh with bone transformationsprivate SkinnedEffect _skinnedEffect;\/\/ Solid white texture for models without material texturesprivate Texture2D _textureWhite;SkinnedEffect &#8212; \u044d\u0442\u043e \u0430\u043d\u0430\u043b\u043e\u0433 BasicEffect, \u0442\u043e\u043b\u044c\u043a\u043e \u0443\u043c\u0435\u044e\u0449\u0438\u0439 \u0432 \u0441\u043a\u0435\u043b\u0435\u0442\u043d\u0443\u044e \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044e._textureWhite &#8212; \u0431\u0435\u043b\u0430\u044f \u0442\u0435\u043a\u0441\u0442\u0443\u0440\u0430 \u0435\u0434\u0438\u043d\u0438\u0447\u043d\u043e\u0433\u043e \u0440\u0430\u0437\u043c\u0435\u0440\u0430. \u041e\u043d\u0430 \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u0430, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0443 \u043d\u0430\u0448\u0435\u0439 \u043c\u043e\u0434\u0435\u043b\u0438 \u043d\u0435\u0442 \u0442\u0435\u043a\u0441\u0442\u0443\u0440.\u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u043d\u043e\u0432\u044b\u0445 \u043f\u043e\u043b\u0435\u0439 \u0432 LoadContent:\/\/ Load hero modelDrModel model = assetManager.LoadModel(GraphicsDevice, &#171;Models\/mixamo.gltf&#187;);_modelHero = new DrModelInstance(model);\/\/ Effect for rendering skeletal meshes with bone transformations_skinnedEffect = new SkinnedEffect(GraphicsDevice);_skinnedEffect.EnableDefaultLighting();\/\/ Create solid white texture for untextured mesh parts_textureWhite = new Texture2D(GraphicsDevice, 1, 1);_textureWhite.SetData(new Color[] { Color.White });\u0415\u0441\u043b\u0438 \u0441 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0435\u0439 _skinnedEffect \u0438 _textureWhite \u0432\u0441\u0451 \u0431\u043e\u043b\u0435\u0435 \u043d\u0438 \u043c\u0435\u043d\u0435\u0435 \u043f\u043e\u043d\u044f\u0442\u043d\u043e.\u0422\u043e \u043f\u0440\u043e \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0443 \u043c\u043e\u0434\u0435\u043b\u0438 \u0441\u0442\u043e\u0438\u0442 \u0441\u043a\u0430\u0437\u0430\u0442\u044c \u043f\u0430\u0440\u0443 \u0441\u043b\u043e\u0432. \u0417\u0434\u0435\u0441\u044c \u043c\u044b \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u043b\u0438 \u0434\u0432\u0430 \u043a\u043b\u0430\u0441\u0441\u0430 DrModel \u0438 DrModelInstance.DrModel \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u043c\u043e\u0434\u0435\u043b\u0438: \u043c\u0435\u0448\u0438, \u0438\u0435\u0440\u0430\u0440\u0445\u0438\u044f \u043a\u043e\u0441\u0442\u0435\u0439, \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438, \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u044b \u0438 \u0442.\u0434. \u0424\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 DrModel \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f immutable.DrModelInstance \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u043e\u043c DrModel. \u0418 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0442\u0430\u043a\u0443\u044e \u0438\u0437\u043c\u0435\u043d\u044f\u044e\u0449\u0443\u044e\u0441\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e, \u043a\u0430\u043a \u0442\u0440\u0430\u043d\u0441\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043a\u043e\u0441\u0442\u0435\u0439 \u0438 \u0442.\u0434.\u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043a\u0430\u0436\u0434\u0443\u044e DrModel \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u043e\u0431\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0442\u044c \u0432 DrModelInstance. \u0425\u043e\u0442\u044f \u0432 \u044d\u0442\u043e\u0439 \u0441\u0435\u0440\u0438\u0438 \u0442\u0443\u0442\u043e\u0440\u0438\u0430\u043b\u043e\u0432 \u043d\u0430 \u043e\u0434\u043d\u0443 DrModel \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u043e\u0434\u0438\u043d DrModelInstance. \u0412 \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u0445, \u043d\u0430 \u043e\u0434\u043d\u0443 \u043c\u043e\u0434\u0435\u043b\u044c \u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442\u044c\u0441\u044f \u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0443\u0433\u043e\u0434\u043d\u043e \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u043e\u0432.\u041c\u0435\u0442\u043e\u0434 DrawModel\u0414\u043e\u0431\u0430\u0432\u0438\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u043c\u0435\u0442\u043e\u0434:\/\/ Render model with material colors and textures, handling both skinned and static meshesprivate void DrawModel(DrModelInstance model, Matrix world){foreach (var mesh in model.Model.Meshes){foreach (var part in mesh.MeshParts){\/\/ Extract material properties or use defaults if no material assignedvar color = Color.White;var texture = _textureWhite;if (part.Material != null){color = part.Material.DiffuseColor;if (part.Material.DiffuseTexture != null){texture = part.Material.DiffuseTexture;}}if (part.Skin != null){\/\/ Skinned mesh: bone transforms applied per-vertex in shader via SetBoneTransforms\/\/ World matrix only positions the entire model in world space_skinnedEffect.DiffuseColor = color.ToVector3();_skinnedEffect.Texture = texture;_skinnedEffect.World = world;_skinnedEffect.SetBoneTransforms(model.GetSkinTransforms(part.Skin.SkinIndex));DrawMeshPart(_skinnedEffect, part);}else{\/\/ Static mesh: must include bone transform in World matrix since GPU doesn&#8217;t apply skeletal deformation\/\/ Bone transform positions this mesh part relative to the model, then world positions the whole model_basicEffect.DiffuseColor = color.ToVector3();_basicEffect.Texture = texture;_basicEffect.World = model.GetBoneGlobalTransform(mesh.ParentBone.Index) * world;DrawMeshPart(_basicEffect, part);}}}}\u0412 \u044d\u0442\u043e\u043c \u043a\u043e\u0434\u0435 \u043d\u0430\u0438\u0431\u043e\u043b\u0435\u0435 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u0430 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 Part.Skin \u043d\u0430 null \u0438 \u0432\u044b\u0431\u043e\u0440 \u044d\u0444\u0444\u0435\u043a\u0442\u0430 \u0434\u043b\u044f \u0440\u0438\u0441\u043e\u0432\u0430\u043d\u0438\u044f \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430.\u0414\u043b\u044f \u043f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u044f \u044d\u0442\u043e\u0433\u043e \u043a\u043e\u0434\u0430 \u043d\u0443\u0436\u043d\u043e \u0438\u043c\u0435\u0442\u044c \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043e \u0442\u043e\u043c, \u043a\u0430\u043a \u0443\u0441\u0442\u0440\u043e\u0435\u043d\u0430 Gltf-\u043c\u043e\u0434\u0435\u043b\u044c.\u0412 \u043d\u0435\u0439 \u0441 \u043a\u0430\u0436\u0434\u044b\u043c \u043c\u0435\u0448\u0435\u043c \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0441\u0432\u044f\u0437\u0430\u043d \u0441\u043a\u0438\u043d. \u0421\u043a\u0438\u043d &#8212; \u044d\u0442\u043e \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u044f \u043a\u043e\u0441\u0442\u0435\u0439. \u0412\u044b\u0437\u043e\u0432 model.GetSkinTransforms \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043c\u0430\u0441\u0441\u0438\u0432 \u043c\u0430\u0442\u0440\u0438\u0446 \u0442\u0440\u0430\u043d\u0441\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438, \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 \u044d\u0442\u043e\u0439 \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0438. \u041a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u044b \u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0451\u043c \u0432 SkinnedEffect.\u0415\u0441\u043b\u0438 \u0441 \u043c\u0435\u0448\u0435\u043c \u043d\u0438\u043a\u0430\u043a\u043e\u0439 \u0441\u043a\u0438\u043d \u043d\u0435 \u0441\u0432\u044f\u0437\u0430\u043d, \u0442\u043e \u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u0441\u044f \u043e\u0431\u044b\u0447\u043d\u044b\u043c BasicEffect.\u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0442\u0430\u043a \u0436\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435, \u0447\u0442\u043e \u043f\u0440\u0438 \u043d\u0430\u043b\u0438\u0447\u0438\u0438 \u0441\u043a\u0438\u043d\u0430, \u043c\u044b \u043f\u0435\u0440\u0435\u0434\u0430\u0451\u043c \u0432 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 World \u0442\u043e\u043b\u044c\u043a\u043e \u043c\u0438\u0440\u043e\u0432\u0443\u044e \u043c\u0430\u0442\u0440\u0438\u0446\u0443 \u0442\u0440\u0430\u043d\u0441\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043c\u043e\u0434\u0435\u043b\u0438(world).\u0410 \u043f\u0440\u0438 \u0435\u0433\u043e \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0438, \u043c\u044b \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0443\u043c\u043d\u043e\u0436\u0430\u0435\u043c \u0435\u0451 \u043d\u0430 \u043c\u0430\u0442\u0440\u0438\u0446\u0443 \u0442\u0440\u0430\u043d\u0441\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043a\u043e\u0441\u0442\u0438, \u0441 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0441\u0432\u044f\u0437\u0430\u043d \u043c\u0435\u0448 &#8212; model.GetBoneGlobalTransform(mesh.ParentBone.Index).\u042d\u0442\u043e \u0441\u0432\u044f\u0437\u0430\u043d\u043e \u0441 \u0442\u0435\u043c, \u0447\u0442\u043e \u0432 \u043f\u0435\u0440\u0432\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043c\u0430\u0441\u0441\u0438\u0432 \u043c\u0430\u0442\u0440\u0438\u0446 \u0438\u0442\u0430\u043a \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0432\u0441\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0442\u0440\u0430\u043d\u0441\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043a\u043e\u0441\u0442\u0435\u0439.\u041d\u043e\u0432\u044b\u0439 \u043c\u0435\u0442\u043e\u0434 Draw\u041d\u0430\u043a\u043e\u043d\u0435\u0446 \u043d\u0430\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u0430\u0442\u044c \u043c\u0435\u0442\u043e\u0434 Draw, \u0434\u043e\u0431\u0430\u0432\u0438\u0432 \u0442\u0443\u0434\u0430 \u0432\u044b\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043c\u0430\u0442\u0440\u0438\u0446 \u043f\u0440\u043e\u0435\u043a\u0446\u0438\u0438 \u0438 \u0432\u0438\u0434\u0430 \u0434\u043b\u044f SkinnedEffect. \u0410 \u0442\u0430\u043a \u0436\u0435, \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0438\u0442\u044c \u0432\u044b\u0437\u043e\u0432 \u043d\u043e\u0432\u043e\u0433\u043e \u043c\u0435\u0442\u043e\u0434\u0430 DrawModel.\u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043f\u0435\u0440\u0435\u043f\u0438\u0448\u0435\u043c Draw \u0442\u0430\u043a:protected override void Draw(GameTime gameTime){base.Draw(gameTime);var device = GraphicsDevice;device.Clear(Color.Black);\/\/ Set GPU statesdevice.DepthStencilState = DepthStencilState.Default;device.RasterizerState = RasterizerState.CullCounterClockwise;device.BlendState =&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-482785","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/482785","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=482785"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/482785\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=482785"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=482785"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=482785"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}