使用unity制作的一款生存类游戏demo(二)

论坛 期权论坛 编程之家     
选择匿名的用户   2021-6-1 13:45   11   0

项目源码:https://git.coding.net/huiseguiji/survival-game-demo.git

上一篇博客已经介绍了这个demo整体的玩法和各种功能的实现效果。这篇详细说明实现的每种功能所采用的方法。

动画控制

找了很久都没有找到一整套合适的动画资源,最终使用了三套动画资源才完成动下图的状态机,而这样也就有一个很严重的问题就是,每套动画资源绑定的骨骼可能略有差别,而人物模型进行动画重定向之后不能同时完全匹配三个动画资源的骨骼导致人物动作有偏差(我个人理解是因为这个原因)。本身也不是技术美术出生,网上搜了一圈也没找到好的解决方法所以只能将就一下。3dsmax只会一点点,不然把fbx文件导入3dsmax重新绑定一下骨骼应该可以解决。

关于动画状态机开始时是想采用两个动画层来实现,base layer有完整的状态转换,如站立,行走,奔跑,攀爬跳跃等。另外一个动画层则只在需要的时候控制人物上半身的动作,如持斧子攻击,持枪射击,并且用mask屏蔽掉下半身的动作。但代码写到一半时发现这样做控制逻辑很混乱,而且貌似之后要用到的matchTarget只支持base layer。于是就采用了如下的设计。

玩家状态机:

idle,walk,run三个子状态机下都是用的1D混合树。

敌人状态机:

UI

背包系统里的物品拖放功能是通过继承NGUI的UIDragDropItem类重写其OnDragDropRelease方法实现的

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class DragDropItem :UIDragDropItem {

 protected override void OnDragDropStart ()
 {
  base.OnDragDropStart ();
  UISprite sprite = transform.GetComponent<UISprite> ();
  sprite.width = 45;
  sprite.height = 45;
  sprite.depth = 10;
 }

 protected override void OnDragDropRelease (GameObject surface)
 {
  base.OnDragDropRelease (surface);

  UISprite sprite = transform.GetComponent<UISprite> ();
  sprite.width = 40;
  sprite.height = 40;
  sprite.depth = 2;

  if (surface == null) {
   transform.localPosition = Vector3.zero;
   return;
  }
  Debug.Log(surface.name);

  GameObject equippedItemsUI = GameObject.Find ("equippedItemsUI");
  if (equippedItemsUI == null) {
   Debug.Log ("cant find the equippedItemsUI!");
   return;
  }
  
  if (surface.tag == "cells") {
   
   if (transform.parent.tag == "equipmentsCells")
    equippedItemsUI.GetComponent<EquipmentItemsManager> ().ChangeEquipment (transform.GetComponent<ItemObj>(),null,false);
   
   transform.parent = surface.transform;
   transform.localPosition = Vector3.zero;

  } else if (surface.tag == "item") {
   if (surface.transform.parent.name.StartsWith ("cell")) {
    //drag item from equipmentItemUI to backpackUI or goodsUI
    if (transform.parent.tag=="equipmentsCells") {
     if (transform.GetComponent<ItemObj> ().type == surface.transform.GetComponent<ItemObj> ().type) {
      Transform temp;
      temp = transform.parent;
      transform.parent = surface.transform.parent;
     
      surface.transform.parent = temp;
      surface.transform.localPosition = Vector3.zero;

      equippedItemsUI.GetComponent<EquipmentItemsManager> ().ChangeEquipment (transform.GetComponent<ItemObj>(),surface.transform.GetComponent<ItemObj>(),false);

     }
     transform.localPosition = Vector3.zero;
     return;
    }

    if (surface.name == transform.name) {
     //----------------------------------------
     GameObject bagUI = GameObject.Find ("backpackUI");
     if (bagUI == null)
      Debug.Log ("cant find the backpackUI");
     else {

      bagUI.GetComponent<BackPagManager> ().CombineItemsInside (transform, surface.transform);
     }

    } else {
     Transform temp;
     temp = transform.parent;
     transform.parent = surface.transform.parent;
     transform.localPosition = Vector3.zero;

     surface.transform.parent = temp;
     surface.transform.localPosition = Vector3.zero;

    }
   } else {
    equippedItemsUI.GetComponent<EquipmentItemsManager> ().EquippedWith (transform,surface.transform);
   }
     

  } else if (surface.tag == "equipmentsCells") {
   if(transform.parent.tag=="equipmentsCells")
    transform.localPosition = Vector3.zero;
   
   equippedItemsUI.GetComponent<EquipmentItemsManager> ().EquippedWith (transform,surface.transform);
  } else {
   transform.localPosition = Vector3.zero;
  }
   
 }

}

合成建造系统

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ComposeSystem : MonoBehaviour {


 public List<ComponentInfo> components=new List<ComponentInfo>();
 public BackPagManager backPackManager;
 public Transform equipment;
 public Transform composeUI;
 public Camera uiCamera;
 public UIController uiController;

 public Transform grid;
 public GameObject itemPrefab;
 public GameObject needsPrefab;


 ComponentInfo comp1;
 ComponentInfo comp2;
 ComponentInfo comp3;

 private bool uiOpened = false;

 // Use this for initialization
 void Start () {
  comp1 = new ComponentInfo ("ammo",new string[2]{"shellCase","powder"},new int[2]{1,1},null);
  comp2 = new ComponentInfo ("board",new string[1]{"wood"},new int[1]{2},new string[1]{"axe"});
  comp3 = new ComponentInfo ("friedMeat",new string[1]{"freshMeat"},new int[1]{1},new string[1]{"campFire"});


  components.Add (comp1);
  components.Add (comp2);
  components.Add (comp3);


  //InitComposingSys ();
 }
 
 // Update is called once per frame
 void Update () {
  
 }

// void OnDisable(){
//  for (int i = 0; i < grid.childCount; i++)
//   Destroy (grid.GetChild(i).gameObject);
//
// }
//
// void OnEnable(){
//  InitComposingSys ();
// }

 ComponentInfo GetComponentInfo(string name){
 
  foreach (ComponentInfo info in components) {
   if (info.name == name)
    return  info;
  }

  Debug.Log ("can't find ComponentInfo in list!");
  return null;
 
 }

 //初始化合成栏UI
 public void InitComposingSys(){
  Transform itemUI=null;
  Transform needListUI=null;
  Transform temp=null;
  Transform needsGrid=null;
  Transform button=null;
  GameObject item;

  foreach (ComponentInfo componentInfo in components) {
   item = Instantiate (itemPrefab)as GameObject;
   item.name = componentInfo.name;
   item.transform.parent = grid;
   item.transform.localScale = Vector3.one;

   for (int n = 0; n < item.transform.childCount; n++) {
    temp=item.transform.GetChild(n);
    if (temp.name == "item")
     itemUI = temp;
    if (temp.name == "button")
     button = temp;
    if (temp.name == "needList")
     needListUI = temp;
   }
   //为每个“build”按钮添加监听方法
   EventDelegate delegate1=new EventDelegate(this,"OnBuildClick") ;
   delegate1.parameters[0] = new EventDelegate.Parameter (item.transform,"");
   button.GetComponent<UIButton> ().onClick.Add(delegate1);

   if (itemUI != null) {
    itemUI.GetComponent<UISprite> ().spriteName = componentInfo.name;
    itemUI.GetComponentInChildren<UILabel> ().text = componentInfo.name;
   }else
    Debug.Log ("can't find \"item\" transform!");

   for (int i = 0; i < componentInfo.requiredGoods.Length; i++) {
    GameObject need = Instantiate (needsPrefab)as GameObject;
    need.GetComponentInChildren<UILabel> ().text = componentInfo.requiredGoodsNum [i] + "";
    need.GetComponent<UISprite> ().spriteName = componentInfo.requiredGoods [i];
    need.name=componentInfo.requiredGoods [i];

    if (!CheckGoodsNumber (componentInfo.requiredGoods [i], componentInfo.requiredGoodsNum [i])) {
     need.GetComponentInChildren<UILabel> ().color = Color.red;
     //button.GetComponent<BoxCollider> ().enabled = false;
    }
    
    //获取needList下的grid子物体
    if (needListUI != null) {
     needsGrid = needListUI.GetChild (0).GetChild (0);
     need.transform.parent = needsGrid;
     need.transform.localScale = Vector3.one;

    } else
     Debug.Log ("can't find \"needList\" transform!");

   }
   needsGrid.GetComponent<UIGrid> ().Reposition ();
  }

  grid.GetComponent<UIGrid> ().Reposition ();
 }

 //检查背包中相关物品的数量是否足够
 bool CheckGoodsNumber(string name,int num){
  int totalNum = 0;
  for (int i = 0; i < backPackManager.cellNum; i++) {
   if (backPackManager.itemBars [i].childCount != 0) {
    Transform obj = backPackManager.itemBars [i].GetChild (0);

    if (obj != null) {
     if (obj.GetComponent<ItemObj> ().name == name)
      totalNum += int.Parse (obj.GetComponentInChildren<UILabel> ().text);

     if (totalNum >= num)
      return true;
    }

   }
  }
  return false;
 }

 //build 按钮被点击时调用此方法
 public void OnBuildClick(Transform obj){
  Transform button = null;
  Transform grid=null;
  Transform numUI = null;
  Transform temp;
  bool canBuild = true;

  for (int i = 0; i < obj.childCount; i++) {
   temp = obj.GetChild (i);
   if (temp.name == "num")
    numUI = temp;
   if (temp.name == "button")
    button = temp;
   if (temp.name == "needList")
    grid = temp.GetChild (0).GetChild (0);
  }

  int num = int.Parse (numUI.GetComponentInChildren<UILabel> ().text);
  Debug.Log ("nnnnum");
  ComponentInfo componentInfo = GetComponentInfo (obj.name);

  for(int n=0;n<componentInfo.requiredGoods.Length;n++){
   Transform need=null;
   need = GetChildWithName (grid,componentInfo.requiredGoods[n]);

   if (!CheckGoodsNumber (componentInfo.requiredGoods [n], componentInfo.requiredGoodsNum [n] * num)) {
    need.GetComponentInChildren<UILabel> ().color = Color.red;
    canBuild = false;
   }
   else 
    need.GetComponentInChildren<UILabel> ().color = Color.black;
   

   need.GetComponentInChildren<UILabel> ().text = componentInfo.requiredGoodsNum [n] * num + "";

  }

  if (canBuild) {
   
   StartCoroutine (BuildItem(grid,obj.name,num));
  }

 }

 IEnumerator BuildItem(Transform grid,string name,int num){
  for (int m = 0; m < grid.childCount; m++) {
   backPackManager.Reduce (grid.GetChild (m).name, int.Parse (grid.GetChild (0).GetComponentInChildren<UILabel> ().text));
  }

  yield return new WaitForSeconds (0.3f);

  int n=backPackManager.Increase (name, num);


  if (n !=0){
   StartCoroutine (backPackManager.AlpheAni());
   uiController.ShowBuildPanelUI (false);
   StartCoroutine (uiController.InstantiateItemModel (name, n));
  }
 }

 Transform GetChildWithName(Transform parent,string name){
  Transform temp = null;
  for (int i = 0; i < parent.childCount; i++) {
   temp = parent.GetChild (i);
   if (temp.name == name)
    return temp;
  }

  return null;
 }
}

因为使用了NGUI插件,所以整个背包系统UI做起来并不会太复杂。比较麻烦的是控制逻辑的编写,由于一开始并没有计划好整个背包系统要实现那些功能以及一些细节问题的处理,导致后面代码显得有点混乱,结构不够清晰。

BackpackManager:存储背包栏容量,人物状态信息及物品信息等,检测物品数量,增加或减少物品,检测背包容量等等。

EquippedItemsManager: 负责装备切换控制,并同时修改人物各种属性

攀爬跳跃系统

要完成一个这样的系统无非就是利用碰撞检测和TargetMatching。先利用physics的RayCast方法确定物体的高度,再决定是播放攀爬动画还是跳跃动画,并计算出动画匹配的目标位置。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public enum JumpType{
 HIGH,
 LOW,
 OVER,
 NONE
}

public class JumpSystem : MonoBehaviour {

 public Transform player;
 public Animator animator;
 public float lowHitHeight=1.2f;
 public float hitHeight = 2f;
 public float maxHitHeight=3.0f;

 public float turnOverWidth = 0.5f;
 public float lineDurationTime=5.0f;
 private Vector3 matchPoint ;

 [Range(0f,0.2f)]
 public float targetOffsetZ=0.08f;
 [Range(0f,0.2f)]
 public float targetOffsetY=0.08f;

 [Range(1f,2f)]
 public float fwdHitDistance=1.5f;
 public float playerHeight = 2.0f;

 public JumpType type = JumpType.NONE;

 RaycastHit hit1;
 RaycastHit hit2;
 // Use this for initialization
 void Start () {
  matchPoint = Vector3.zero;
 }
 


 public Vector3 CheckHit(){
  matchPoint = Vector3.zero;

  //Debug.DrawLine (transform.position,transform.position + transform.up * hitHeight,Color.yellow,lineDurationTime);
  //Debug.DrawLine(transform.position + transform.up * hitHeight,transform.position + transform.up * hitHeight+transform.forward*fwdHitDistance,Color.red,lineDurationTime);
  Debug.DrawLine(transform.position + transform.up * lowHitHeight,transform.position + transform.up * lowHitHeight+transform.forward*fwdHitDistance,Color.red,lineDurationTime/2);
  if (Physics.Raycast (transform.position + transform.up * lowHitHeight, transform.forward, out hit1,fwdHitDistance)) {
   ResetPlayerPosition (hit1.point);
   ClimbHighCheck ();
  } else {
//   if (Physics.Raycast (transform.position + transform.up * lowHitHeight, transform.forward, out hit2, fwdHitDistance))
//    JumpMidCheck ();
//   else
   JumpLowCheck ();
  }

  return matchPoint;
 }

 void ResetPlayerPosition(Vector3 hitPoint){
  if((hit1.point - (transform.position + transform.up * hitHeight)).magnitude<1.0f)
   player.position=player.position-player.forward*(1.0f-(hit1.point - (transform.position + transform.up * hitHeight)).magnitude+0.02f);
 }

 //攀爬
 void ClimbHighCheck(){
  
  RaycastHit hit;
  Debug.DrawLine (transform.position + transform.up * hitHeight,transform.position + transform.up * maxHitHeight,Color.yellow,lineDurationTime);
  Debug.DrawLine (transform.position + transform.up * maxHitHeight,transform.position + transform.up * maxHitHeight+transform.forward*fwdHitDistance,Color.red,lineDurationTime);
  if (Physics.Raycast (transform.position + transform.up * maxHitHeight, transform.forward, fwdHitDistance))
   return ;
  
  Vector3 start = transform.position + transform.up * maxHitHeight + transform.forward * fwdHitDistance;
  if (Physics.Raycast (start, Vector3.down, out hit, 20.0f)) {
   Debug.DrawLine (start, hit.point, Color.green,lineDurationTime);
   //如果平台上方的空间尺寸小于游戏角色高度,结束方法
   Debug.DrawLine (hit.point + Vector3.up * targetOffsetY, hit.point + Vector3.up * targetOffsetY + Vector3.up * playerHeight,Color.black,lineDurationTime);
   if (Physics.Raycast (hit.point + Vector3.up * targetOffsetY, Vector3.up, playerHeight)) {
    return;
   }

   RaycastHit hit2;
   if (!Physics.Raycast (hit.point + Vector3.up * targetOffsetY, -transform.forward, out hit2, fwdHitDistance,~(1<<8))) {
    float dis = (hit1.point - (transform.position + transform.up * hitHeight)).magnitude;
    type = JumpType.HIGH;
    matchPoint= hit.point + Vector3.up * targetOffsetY - transform.forward * (fwdHitDistance - dis+targetOffsetZ)+transform.right*0.3f;
    Debug.DrawLine (hit.point + Vector3.up * targetOffsetY, matchPoint, Color.blue,lineDurationTime);
    Debug.Log ("...JumpHigh"+matchPoint);
   } 

  } 

  
 }
 //跳跃或者翻越
 void JumpLowCheck(){
  RaycastHit hitTest;
  Debug.DrawLine (transform.position + transform.up * 0.1f,transform.position + transform.up * 0.1f+transform.forward*fwdHitDistance,Color.white,lineDurationTime);

  if (!Physics.Raycast (transform.position + transform.up * 0.1f, transform.forward, out hitTest, fwdHitDistance))
   return;
  //ResetPlayerPosition (hitTest.point);

  RaycastHit hit;
  Debug.DrawLine (transform.position,transform.position + transform.up * lowHitHeight,Color.yellow,lineDurationTime);
  Debug.DrawLine (transform.position + transform.up * lowHitHeight,transform.position + transform.up * lowHitHeight+transform.forward*fwdHitDistance*0.5f,Color.red,lineDurationTime);

  Vector3 start = transform.position + transform.up * lowHitHeight + transform.forward * fwdHitDistance*0.9f;
  float dis = (hitTest.point - (transform.position + transform.up * 0.1f)).magnitude;
  if (Physics.Raycast (start, Vector3.down, out hit, lowHitHeight-0.01f)) {
   Debug.DrawLine (start, hit.point, Color.red,lineDurationTime);
   //如果平台上方的空间尺寸小于游戏角色高度,结束方法
   Debug.DrawLine (hit.point + Vector3.up * targetOffsetY, hit.point + Vector3.up * targetOffsetY + Vector3.up * playerHeight,Color.black,lineDurationTime);
   if (Physics.Raycast (hit.point + Vector3.up * targetOffsetY, Vector3.up, playerHeight))
    return;

   RaycastHit hit2;
   if (!Physics.Raycast (hit.point , -transform.forward, out hit2, fwdHitDistance*0.5f, ~(1 << 8))) {
    type = JumpType.LOW;
    matchPoint = hit.point + Vector3.up * 0.1f - transform.forward * (fwdHitDistance*0.5f - dis)/2f;
    Debug.DrawLine (hit.point + Vector3.up * 0.1f, matchPoint, Color.blue, lineDurationTime);
    Debug.Log ("...JumpLow"+matchPoint);

   } 

  } else if (Physics.Raycast (transform.position + transform.up * lowHitHeight + transform.forward * (dis + 0.01f), Vector3.down, out hit, lowHitHeight-0.01f)) {
   Debug.DrawLine(transform.position + transform.up * lowHitHeight + transform.forward * (dis + 0.01f),hit.point,Color.green,lineDurationTime);
   type = JumpType.OVER;
   matchPoint = hit.point+Vector3.up*0.1f-transform.forward*0.3f;
   Debug.DrawLine (hit.point+Vector3.up*targetOffsetY,matchPoint,Color.blue,lineDurationTime);
   Debug.Log ("...OverRailing"+matchPoint);

  } else
   return;
 
 }
}

建造系统

部分代码如下:

void BuildObj(){
        //获取屏幕鼠标位置射线
  screenPointRay = Camera.main.ScreenPointToRay (Input.mousePosition);
  if (Physics.Raycast (screenPointRay, out hit)) {
   buildObj.transform.position = hit.point;
   float angle = Vector3.Angle (Vector3.up,hit.normal);
        //旋转物体,使其up方向永远和碰撞点法线方向一致
   if (angle > 0.1f) {
    Vector3 axis = Vector3.Cross (buildObj.transform.up,hit.normal);
    buildObj.transform.Rotate (axis.normalized * angle, Space.World);
   }
         //如果碰撞点所在面的倾斜角度大于5度,则无法建造
   if (Vector3.Angle (hit.normal, Vector3.up) > 5.0f) {
    IFCanBuild (false);
   }else {
       
    if (buildObj.GetComponent<MeshFilter> () != null)
     filter = buildObj.GetComponent<MeshFilter> ();
    else
     filter = buildObj.GetComponentsInChildren<MeshFilter> () [0];
        
    Bounds bounds = filter.mesh.bounds;
            //利用模型网格的包围盒数据检测范围内是否有其他物体,如果有则无法建造
    if (Physics.OverlapBox (hit.point + hit.normal * (bounds.extents.y + 0.015f), bounds.size*0.5f,buildObj.transform.rotation).Length !=0) {

     IFCanBuild (false);

    } else {
     IFCanBuild (true);
    }
   }
    
  }
 }

see through效果

在摄像机和人物角色之间有一个面片网格,为其创建一个材质并指定一个新创建的着色器(默认的表面着色器就行)

在新创建的shader中加入下面两行代码:

zwrite on //开启深度缓存写入
colormask 0 //不往颜色缓冲中写入任何信息

在材质面板将渲染队列改为3000(只要比默认的geometry队列大即可)

真正实现see through 还需要脚本控制。

原理其实就是先检测摄像机和人物之间是否有物体遮挡,有的话就将该物体的渲染队列的值改为比面片网格的队列更大的值,这样一来渲染顺序就是:普通物体和人物角色>面片网格>遮挡体。由于人物角色先渲染并且面片网格只写入深度信息,不会覆盖颜色缓冲中的值,所以面片不会对人物进行遮挡,而遮挡体在面片之后渲染并且处在面片和人物之间,所以被遮挡的部分会被剔除,从而实现透视效果。

换装

看了一些换装的例子,采用的方法都差不多,我的做法是

首先定义一些list存储对所有蒙皮的引用,并且每种类型的装备(背包,上衣,鞋子,头盔,面罩,裤子)用一个变量

存储当前使用的是哪种蒙皮,切换装备时先修改该装备对应变量所指向的蒙皮,再依次用list存储人物躯干蒙皮和装备蒙皮的materials和bones信息,并将蒙添加到CombineInstance类型的list中,最后只需要用mesh的CombineMeshs方法合并所有蒙皮并将materials和bones赋予合并后的蒙皮即可。

合并蒙皮只是为了降低draw call,但感觉作用不大。不合并的话,代码更简单,只需要修改对应装备蒙皮的mesh,materials和bones信息即可。

主要代码如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public enum SkinType{
 BACKPACK,
 BAG,
 BODYKIT,
 HAIRSTYLE,
 HELMET,
 MASK,
 PAINTS,
 SHIRT,
 SHOES,
 VEST,
 WEAPON,
 WEAPON_GUN,
 NONE
}


public class SkinGenerater : MonoBehaviour {

 public List<GameObject> backPackList = new List<GameObject> ();
 public List<GameObject> bagList = new List<GameObject> ();
 public List<GameObject> bodyKitList = new List<GameObject> ();
 public List<GameObject> hairStyleList = new List<GameObject> ();
 public List<GameObject> helmetList = new List<GameObject> ();
 public List<GameObject> maskList = new List<GameObject> ();
 public List<GameObject> paintsList = new List<GameObject> ();
 public List<GameObject> shirtList = new List<GameObject> ();
 public List<GameObject> shoesList=new List<GameObject> ();
 public List<GameObject> vestList=new List<GameObject>();
 public List<GameObject> weaponList=new List<GameObject>();
 public List<GameObject> weapon_gunList=new List<GameObject>();

 private SkinnedMeshRenderer backPack;
 private SkinnedMeshRenderer bag;
 private SkinnedMeshRenderer bodyKit;
 private SkinnedMeshRenderer hairStyle;
 private SkinnedMeshRenderer helmet;
 private SkinnedMeshRenderer mask;
 private SkinnedMeshRenderer pants;
 private SkinnedMeshRenderer shirt;
 private SkinnedMeshRenderer shoes;
 private SkinnedMeshRenderer vest;
 private SkinnedMeshRenderer weapon;
 private SkinnedMeshRenderer weapon_gun;

 public SkinnedMeshRenderer combineSkin;

 List<Material> materials=new List<Material>();
 List<Transform> bones=new List<Transform>();
 List<CombineInstance> combineList = new List<CombineInstance> ();

 Transform[] bonesTransform;
 public GameObject root;

 public SkinnedMeshRenderer[] baseSkins;
 private SkinnedMeshRenderer temp;

 void Init(){

  bonesTransform = root.GetComponentsInChildren<Transform> ();
  Debug.Log (bonesTransform[0].name);
  //root.transform.GetChild(0).parent = transform;
  //Destroy (root);
  if (materials != null)
   materials.Clear ();

  if (bones != null)
   bones.Clear ();

  if (combineList != null)
   combineList.Clear ();

  SkinnedMeshRenderer[] skins = GetComponentsInChildren<SkinnedMeshRenderer> ();

  for (int i = 0; i < skins.Length; i++) {
  
   if (skins [i].name == "combineSkin")
    continue;

   CombineInstance combine = new CombineInstance ();
   combine.mesh = skins [i].sharedMesh;
   combineList.Add (combine);

   materials.AddRange (skins[i].materials);

   GetBone (skins[i].bones);
   Destroy (skins[i].gameObject);
  }

  Mesh mesh = new Mesh ();
  mesh.CombineMeshes (combineList.ToArray (), false, false);

  combineSkin.sharedMesh = mesh;
  combineSkin.materials = materials.ToArray ();
  combineSkin.bones = bones.ToArray ();

  backPack = null;
  bag = null;
  bodyKit = null;
  hairStyle = null;
  helmet = null;
  mask = null;
  pants = null;
  shirt = null;
  shoes = null;
  vest = null;
  weapon = null;
  weapon_gun = null;
 }

 void GetBone(Transform[] bones){
 
  for (int i = 0; i < bones.Length; i++) {

   for (int j = 0; j < bonesTransform.Length; j++) {


    if (bonesTransform[j].name.Equals (bones [i].name)) {
     this.bones.Add (bonesTransform[j]);
     break;
    }
   }

  }


 }

 public void ResetSkin(){
  
  materials.Clear ();
  bones.Clear ();
  combineList.Clear ();

  for (int i = 0; i < baseSkins.Length; i++) {
   
   CombineInstance combine = new CombineInstance ();
   combine.mesh = baseSkins [i].sharedMesh;
   combineList.Add (combine);

   materials.AddRange (baseSkins[i].materials);

   GetBone (baseSkins[i].bones);
  }

  Mesh mesh = new Mesh ();
  mesh.CombineMeshes (combineList.ToArray (), false, false);

  combineSkin.sharedMesh = mesh;
  combineSkin.materials = materials.ToArray ();
  combineSkin.bones = bones.ToArray ();



 }


 public void ChangeSkin(string skinName,SkinType type,bool reset=false){
 
  materials.Clear ();
  bones.Clear ();
  combineList.Clear ();


  if (type == SkinType.BACKPACK) {
   if (reset)
    backPack = null;
   else {
    GetMeshRenderer (skinName, backPackList);
    if (temp != null)
     backPack = temp;
   }
  } else if (type == SkinType.BAG) {
   if (reset)
    bag = null;
   else {
    GetMeshRenderer (skinName, bagList);
    if (temp != null)
     bag = temp;
   }
  } else if (type == SkinType.BODYKIT) {
   if (reset)
    bodyKit = null;
   else {
    GetMeshRenderer (skinName, bodyKitList);
    if (temp != null)
     bodyKit = temp;
   }
  } else if (type == SkinType.HAIRSTYLE) {
   if (reset)
    hairStyle = null;
   else {
    GetMeshRenderer (skinName, hairStyleList);
    if (temp != null)
     hairStyle = temp;
   }
  } else if (type == SkinType.HELMET) {
   if (reset)
    helmet = null;
   else {
    GetMeshRenderer (skinName, helmetList);
    if (temp != null)
     helmet = temp;
   }
  } else if (type == SkinType.MASK) {
   if (reset)
    mask = null;
   else {
    GetMeshRenderer (skinName, maskList);
    if (temp != null)
     mask = temp;
   }
  } else if (type == SkinType.PAINTS) {
   if (reset)
    pants = null;
   else {
    GetMeshRenderer (skinName, paintsList);
    if (temp != null)
     pants = temp;
   }
  } else if (type == SkinType.SHIRT) {
   if (reset)
    shirt = null;
   else {
    GetMeshRenderer (skinName, shirtList);
    if (temp != null)
     shirt = temp;
   }
  } else if (type == SkinType.SHOES) {
   if (reset)
    shoes = null;
   else {
    GetMeshRenderer (skinName, shoesList);
    if (temp != null)
     shoes = temp;
   }
  } else if (type == SkinType.VEST) {
   if (reset)
    vest = null;
   else {
    GetMeshRenderer (skinName, vestList);
    if (temp != null)
     vest = temp;
   }
  }
  else if (type == SkinType.WEAPON)
   //***********************************
   ;
  else if (type == SkinType.WEAPON_GUN)
   //***********************************
   ;
  else
   Debug.Log ("unknow skinType!");

  if (temp != null) {

   CombineBaseMesh ();

   CombineMesh ();


   Mesh mesh = new Mesh ();
   mesh.CombineMeshes (combineList.ToArray (), false, false);

   combineSkin.sharedMesh = mesh;
   combineSkin.materials = materials.ToArray ();
   combineSkin.bones = bones.ToArray ();
  }
 
 }



 void CombineBaseMesh(){

  for (int i = 0; i < baseSkins.Length; i++) {

   CombineInstance combine = new CombineInstance ();
   combine.mesh = baseSkins [i].sharedMesh;
   combineList.Add (combine);

   materials.AddRange (baseSkins[i].materials);

   GetBone (baseSkins[i].bones);
  }

 }

 void CombineMesh(){


  AddMeshToCombineLsit (backPack);
  AddMeshToCombineLsit (bag);
  AddMeshToCombineLsit (bodyKit);
  AddMeshToCombineLsit (hairStyle);
  AddMeshToCombineLsit (helmet);
  AddMeshToCombineLsit (mask);
  AddMeshToCombineLsit (pants);
  AddMeshToCombineLsit (shirt);
  AddMeshToCombineLsit (shoes);
  AddMeshToCombineLsit (vest);
  AddMeshToCombineLsit (weapon);
  AddMeshToCombineLsit (weapon_gun);

 }

 void AddMeshToCombineLsit (SkinnedMeshRenderer skin){

  if (skin == null) {
   Debug.Log ("skin is null");
   return;
  }

  CombineInstance com = new CombineInstance ();
  com.mesh = skin.sharedMesh;

  combineList.Add (com);
  materials.AddRange (skin.materials);

  GetBone (skin.bones);
 }

 void GetMeshRenderer(string name,List<GameObject> skinList){
 
  temp = null;
  foreach (GameObject obj in skinList) {
   if (obj.name == name)
    temp = obj.GetComponent<SkinnedMeshRenderer> ();
  }

  if (temp == null) {
   Debug.Log ("can't find the skinnedMesh!!!");
  }
 }


 // Use this for initialization
 void Start () {
  Init ();
 }

}

分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:3875789
帖子:775174
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP