[wpdreams_ajaxsearchlite]

触发动画和状态

可以播放两种类型的动画,短期播放,如挥动或指向,以及长期播放(称为状态),直到它们被取消。这两种类型在Atavism处理方式上有很大不同,为了增加复杂性,Unity也使用两种不同的动画系统。如果您还没有,建议您阅读使用动画

为了简化本指南,我将首先介绍动画的短期和长期动画触发,然后介绍如何使用Legacy和Mecanim动画系统实际播放动画。


触发动画


在Assets / Scripts目录中的Atavism项目中提供了脚本的示例副本。脚本附加到AtavismObjects文件夹中的Scripts.prefab。

查看该文件,您将看到Update()函数的一些输入检查。当按下匹配键时,这些将运行其中一个功能。

短期

短期动画通过协调效果系统完成。这是因为它们不需要保存到角色中,只需要在动画播放时向附近的其他玩家显示。在示例脚本中,有以下功能:


  public void PlayWave() {
	Dictionary<string, object> props = new Dictionary<string, object> ();
	props.Add ("coordEffect", "PlayWaveAnimation"); // Put name of Coord Effect Prefab to play here
	props.Add ("hasTarget", false);
	NetworkAPI.SendExtensionMessage (ClientAPI.GetPlayerOid(), false, "ao.PLAY_COORD_EFFECT", props);
    }

函数内部的代码向服务器发送命令,告诉它使用名称“PlayWaveAnimation”播放协调效果。然后,服务器将向发送命令的玩家附近的所有玩家发送消息,告知客户端播放指定的协调效果。要播放不同的动画,只需创建一个新的协调效果并创建该示例函数的副本,但更改“coordEffect”属性的名称。

要创建新的协调效果,请进入Resources / Content / CoordinatedEffects文件夹并复制其中一个现有预制件。我建议复制PlayWaveAnimation预制件,因为它已经使用正确的组件进行设置,所需要做的就是更改动画名称和长度(并且可能会删除那里的其他组件,因此它只剩下Coord Animation一个)。


长期

长期动画被保存为播放器上的属性,以便稍后登录或走到该播放器的其他玩家将看到仍在播放动画。将这些视为一种状态可能是有用的,例如坐下或躺下的状态。


在本教程中,我决定创建一个名为“currentAnim”的新播放器属性。在示例文件中,有PlayLieDown函数,它将在将此设置为“lie”和“null”(如无状态)之间切换。这是这里的功能:


  public void PlayLieDown() {
	// First check if the player is already lying down
	bool playerLyingDown = false;
	if (ClientAPI.GetPlayerObject().PropertyExists("currentAnim")) {
		if ((string)ClientAPI.GetPlayerObject().GetProperty("currentAnim") == "lie")
			playerLyingDown = true;
	}
	
	if (playerLyingDown) {
		// Player is lying down so reset anim back to normal
		NetworkAPI.SendTargetedCommand (ClientAPI.GetPlayerOid(), "/setStringProperty currentAnim null");
	} else {
		// Player is not lying down so set anim to lie
		NetworkAPI.SendTargetedCommand (ClientAPI.GetPlayerOid(), "/setStringProperty currentAnim lie");
	}
    }

要为其他动画执行此操作,最低限度是将世界“谎言”的两个实例替换为您要使用的任何其他动画状态。

现在另一个棘手的部分是处理状态中断。也就是说,如果玩家在躺下时移动会发生什么?它应该自动将状态清除为null吗?这将在下面的部分中介绍。

播放动画

Legacy

Legacy系统更难添加新动画,因为它需要更改代码才能使其正常工作。当选择使用“Atavism Legacy Animation Mob Controller”的mob预制件时,您将看到动画属性列表,例如“待机动画”和“走路动画”。需要编辑该mob控制器文件以包含新动画的新属性,然后添加一些代码以便在播放这些动画时进行计算。

打开AtavismLegacyAnimationMobController3D.cs文件并在文件顶部附近为第15行后的新动画添加新行:

  public AnimationClip mountAnimation;

例如,对于新的Wave和Lie动画,您可以:


  public AnimationClip waveAnimation;
  public AnimationClip lieAnimation;

从这里开始,代码将根据短期或长期动画略有不同。


Short Term

要获得播放PlayAnimation()函数的短期动画,需要几行来将动画名称从Coordinated Effect转换为上面添加的AnimationClip。在PlayAnimation()函数中,您将看到以下行:

  if (animationName == "attack_normal" || animationName == "Attack") {
      overrideAnimation = unarmedAttackedAnimation;
  }

要添加新动画(例如上面的wave 1),请在其后添加以下代码字符串:


  else if (animationName == "Waving") {
      overrideAnimation = waveAnimation;
  }

我的功能现在看起来像这样:


我从上面显示的PlayWaveAnimation协调​​效果的动画名称属性中获得了“挥动”。 “waveAnimation”来自于本页前面几行添加的新变量。


Long Term

当我们使用新的播放器属性(称为“currentAnim”)时,需要添加一个新的属性处理程序来检测该属性何时发生更改。在Atavism代码中散布着很多属性处理程序的例子,所以我从MobController3D.cs中偷了一个并修改它以获取我们的动画。需要添加以下代码……


首先在PlayAnimation函数之后创建一个新函数。这是我的例子:


  public void HandleCurrentAnim (object sender, PropertyChangeEventArgs args)
    {
	// Get the value of the currentAnim property
	string currentAnim = (string)AtavismClient.Instance.WorldManager.GetObjectNode(oid).GetProperty("currentAnim");
	// Check if the value is "null", if so, set the overrideAnimationExpires time to -1 to reset it
	if (currentAnim == "null") {
		overrideAnimationExpires = -1;
	} else {
		// Otherwise call the PlayAnimation function with a very large amount of time
		PlayAnimation(currentAnim, float.MaxValue);
	}
    }

请注意,您需要按照上面“短期”部分中的步骤将动画名称转换为动画对象。

最后,需要注册此属性处理函数,以便在currentAnim属性更改时运行。这可以通过向ObjectNodeReady()函数添加几行代码来完成。

  GetComponent<AtavismNode>().RegisterObjectPropertyChangeHandler("currentAnim", HandleCurrentAnim);
  // If the currentAnim property already exists, run the handler now
  if (GetComponent<AtavismNode>().PropertyExists("currentAnim")) {
      HandleCurrentAnim(null, null);
  }
  

所以它现在看起来像:

请注意,您现在需要将动画剪辑添加到mob预制件上的Animation和AtavismLegacyMobController3D组件中。

移动时清除CurrentAnim

在Update()函数结束时,您可以检查玩家currentAnim是否未设置为null以及它们是否也在移动。如果满足这两个要求,则可以将currentAnim设置为null以取消它。这是我写的:


  if (isPlayer && controller.velocity.sqrMagnitude > 0.1 && ClientAPI.GetPlayerObject().PropertyExists("currentAnim")) {
      if ((string)ClientAPI.GetPlayerObject().GetProperty("currentAnim") != "null")
          NetworkAPI.SendTargetedCommand (ClientAPI.GetPlayerOid(), "/setStringProperty currentAnim null");
    }

为了帮助您将它放在正确的位置,这是我的看法: