概述

阅读本文档,您可以了解如何使用MonoGame运行库。该运行库使用C#语言。我们将通过一个示例来说明如何加载导出的JSON文件并在场景中进行播放。

获取运行库

您可以直接从Creature游戏运行库窗口下载运行库,或点击 这里 从版本库获取运行库。

使用命名空间

以下是命名空间声明:

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Input.Touch;
using Microsoft.Xna.Framework.Storage;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Media;
using MeshBoneUtil;
using CreatureModule;
using CreatureRenderer;
using System.Collections.Generic;

加载和初始化

假设已导出一个名为dragonTest.json的龙动画文件,及其相应的纹理图谱character-dragon.png

首先加载文件资源:

Dictionary<string, object> load_data = 
	CreatureModule.Utils.LoadCreatureJSONData("dragonTest.json");
curCreature = new CreatureModule.Creature(ref load_data);

上述操作将从磁盘加载JSON数据并进入内存。然后,创建可以使用这些加载的资源的实际对象:

curManager = new CreatureModule.CreatureManager (curCreature);

curManager.CreateAnimation (ref load_data, "default");
curManager.CreateAnimation (ref load_data, "pose2");

在上述示例中,JSON文件有2个动画剪辑:标准姿势2。因此,您需要从Creature管理器对象创建2个动画,使它们可以播放。

已完成加载,可以设置活动状态的动画用于播放:

curManager.SetActiveAnimationName ("default");

上述操作将默认剪辑设置为当前活动的动画。

现在继续创建对象来渲染角色动画:

Texture2D curTexture;
curTexture = Content.Load<Texture2D> ("character-dragon");

curRenderer = new CreatureRenderer.Renderer (graphics.GraphicsDevice, curManager, ref curTexture);
curRenderer.world = Matrix.CreateScale (new Vector3(35.0f, 35.0f, 1.0f));

上述操作将创建一个含纹理图谱文件的Creature渲染器。该操作完成后,您可以继续设置一些播放属性:

curManager.SetIsPlaying (true);
curManager.should_loop = true;

角色动画和渲染更新

加载角色后,您需要在2个回调中调用相应的更新调用来更新动画并渲染角色。要用时间增量(如0.025)更新动画,请在**Update()**回调中放入以下代码:

protected override void Update (GameTime gameTime)
{
		// 待办:在此处添加更新逻辑		
		curManager.Update (0.025f);
		...
}

然后,放入以下代码来渲染**Draw()**回调中的角色:

protected override void Draw (GameTime gameTime)
{
	// 清除后台缓冲区
	graphics.GraphicsDevice.Clear (Color.CornflowerBlue);

	// 待办:在此处添加绘制代码
	
	// 渲染角色
	curRenderer.DoUpdate (graphics.GraphicsDevice);
}

完整代码示例

以下为完整的代码布局。大多数代码是从默认的MonoGame项目启动器模板生成的。请注意**loadContent()**方法,该方法执行了大部分工作:

#region Using Statements
using System;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Input.Touch;
using Microsoft.Xna.Framework.Storage;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Media;
using MeshBoneUtil;
using CreatureModule;
using CreatureRenderer;
using System.Collections.Generic;


#endregion

namespace Sample
{
	/// <summary>
	/// 默认项目模板
	/// </summary>
	public class Game1 : Game
	{

		CreatureModule.Creature curCreature;
		CreatureModule.CreatureManager curManager;
		CreatureRenderer.Renderer curRenderer;
		String curAnimationName;

		#region Fields

		GraphicsDeviceManager graphics;
		SpriteBatch spriteBatch;
		Texture2D logoTexture;

		#endregion

		#region Initialization

		public Game1 ()
		{

			graphics = new GraphicsDeviceManager (this);
			
			Content.RootDirectory = "Assets";

			graphics.IsFullScreen = false;
		}

		/// <summary>
		/// 从基本Game.Initialize覆盖。GraphicsDevice设置完成后,
		/// 使用视区初始化一些值。
		/// </summary>
		protected override void Initialize ()
		{
			base.Initialize ();
		}


		/// <summary>
		/// 加载图形内容。
		/// </summary>
		protected override void LoadContent ()
		{
			Dictionary<string, object> load_data = CreatureModule.Utils.LoadCreatureJSONData("dragonTest.json");
			curCreature = new CreatureModule.Creature(ref load_data);
			curManager = new CreatureModule.CreatureManager (curCreature);

			curManager.CreateAnimation (ref load_data, "default");
			curManager.CreateAnimation (ref load_data, "pose2");

			curAnimationName = "default";
			curManager.SetActiveAnimationName (curAnimationName);
			curManager.SetIsPlaying (true);
			curManager.should_loop = true;

			Texture2D curTexture;
			curTexture = Content.Load<Texture2D> ("character");

			curRenderer = new CreatureRenderer.Renderer (graphics.GraphicsDevice, curManager, ref curTexture);
			curRenderer.world = Matrix.CreateScale (new Vector3(35.0f, 35.0f, 1.0f));
		}

		#endregion

		#region Update and Draw

		/// <summary>
		/// 允许游戏运行逻辑,如更新世界、
		/// 检查冲突,收集输入和播放音频。
		/// </summary>
		/// <param name="gameTime">提供时间值的快照。</param>
		protected override void Update (GameTime gameTime)
		{
			// 待办:在此处添加更新逻辑		
			curManager.Update (0.025f);
            		
			base.Update (gameTime);
		}

		/// <summary>
		/// 当游戏绘制自身时调用。 
		/// </summary>
		/// <param name="gameTime">提供时间值的快照。</param>
		protected override void Draw (GameTime gameTime)
		{
			// 清除后台缓冲区
			graphics.GraphicsDevice.Clear (Color.CornflowerBlue);

			//待办:在此处添加绘制代码
			base.Draw (gameTime);

			curRenderer.DoUpdate (graphics.GraphicsDevice);
		}

		#endregion
	}
}

自定义时间/帧范围

您可以为当前活动的动画设置自定义时间/帧范围。假设您想将播放限制在10到20的帧范围内,您可以执行以下操作:

curManager.use_custom_time_range = true;
curManager.custom_start_time = 10;
curManager.custom_end_time = 30;

动画混合

您可以执行以下操作来混合2个动画剪辑:

curManager.SetBlending(true);	
curManager.SetBlendingAnimations("default", "pose2");
curManager.SetBlendingFactor(0.5);	 // 在混合时,可选数值为从0到1

覆盖、修改骨骼位置

某些情况下,您需要直接修改角色的骨骼位置。例如,为了添加布娃娃物理效果,您可能希望骨骼位置与若干由弹簧或关节连接在一起的刚体保持一致。在这种情况下,您需要为自己的自定义要求设置骨骼位置,您可以执行以下操作。首先,编写自定义骨骼覆盖方法。在下面的例子中,修改了骨骼y方向上的位置:

// 这表明覆盖或修改骨骼位置的能力 

void UpdateBonesToCustomPositions(Dictionary<string, MeshBoneUtil.MeshBone> bones_map)
{
	foreach(KeyValuePair<string, MeshBoneUtil.MeshBone> entry in bones_map)
	{
		var cur_bone = entry.Value;
		// 将每个骨向上移动y作为示例
		var cur_world_start_pos = cur_bone.getWorldStartPt();
		var cur_world_end_pos = cur_bone.getWorldEndPt();

		float displace_y = -20.0f;
		cur_world_start_pos.Y += displace_y;
		cur_world_end_pos.Y += displace_y;

		cur_bone.setWorldStartPt(cur_world_start_pos);
		cur_bone.setWorldEndPt(cur_world_end_pos);
	}

}

您还需要告诉Creature管理器使用您的自定义骨骼修改回调,如下所示:

	// 以下代码设置一个可选的骨骼覆盖回调以修改骨骼位置
	CreatureManager cur_manager = creature_renderer.creature_manager;
	cur_manager.bones_override_callback = UpdateBonesToCustomPositions;

角色实例和内存

如需实例一个角色的多个副本(如2条龙),您可以创建这样的动画:

var new_animation_1 = new CreatureModule.CreatureAnimation(ref load_data, "default");
var new_animation_2 = new CreatureModule.CreatureAnimation(ref load_data, "pose2");

然后,您可以继续创建一个新的Creature对象、一个新的Creature管理器对象和一个新的Creature渲染器对象。您可以添加创建的动画到您新创建的Creature管理器对象中,如下所示:

new_creature_manager_2.AddAnimation(new_animation_1);
new_creature_manager_2.AddAnimation(new_animation_2);

该示例和之前示例的区别在于:先创建动画,后将其添加到各自的Creature管理器中。这就意味着将为(最昂贵的)动画分配的内存存储在标准位置。多个Creature管理器对象将从Creature动画对象的公共池添加动画。