先分享下个人mirrordemo 的github :
https://github.com/IsaWinding/MirrorDemo.git
mirror 的官方下载地址:
https://assetstore.unity.com/packages/tools/network/mirror-129321
1.添加NetworkManager

2.添加NetworkMangerHud

3.制作玩家角色预制体并添加mirror 相关组件

networkTransform 和networkAnimator ClientAuthority 需要勾选
分享玩家操作脚本

using Mirror;
using Prime31;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class CharacterInput : NetworkBehaviour
{public float moveSpeed = 8f;public float jumpSpeed = 20f;public float rayDistance = 4f;public float atkDistance = 2f;public float atk = 10f;public float atkOffset = 1f;public bool isFaceRight = true;public KeyCode moveLeftKey;public KeyCode moveRightKey;public KeyCode attackKey;public KeyCode jumpKey;public LayerMask platformMask = 0;public LayerMask enemyMask = 0;private bool isMove = false;private bool isJump = false;private bool isOnGround = true;private Vector3 moveDelta;private bool isAttack = false;private bool curIsFaceRight = true;private Rigidbody2D body;private Vector3 oriScale;private NetworkIdentity identity;private CharacterAni characterAni;private CharacterHp characterHp;public int MaxHp = 100;[SyncVar(hook = "HpChange")]public int curHp = 100;public NetworkIdentity Identity { get { return identity; } }void Awake() {body = this.gameObject.GetComponent<Rigidbody2D>();oriScale = this.transform.localScale;identity = this.gameObject.GetComponent<NetworkIdentity>();characterAni = this.gameObject.GetComponent<CharacterAni>();characterHp = this.gameObject.GetComponent<CharacterHp>();characterHp.SetHpInfo(curHp, MaxHp);}private void Start(){if(identity.isLocalPlayer)CameraSmoothFollow.Instance.SetTarget(this.transform);}private bool isCanReborn = true;private void OnDead() {if (isCanReborn){Invoke("Reborn", 5f);isCanReborn = false;}   }[Command]private void Reborn(){curHp = MaxHp;SetHpInfo();RpcReborn();}[ClientRpc]private void RpcReborn(){this.transform.localPosition = Vector3.zero;isCanReborn = true;}public bool IsDead(){return curHp <= 0;}// the Update loop contains a very simple example of moving the character around and controlling the animationprivate void Update(){if (!identity.isLocalPlayer)return;if (IsDead())return;isMove = false;moveDelta = Vector3.zero;isOnGround = Physics2D.Raycast(this.transform.position, Vector2.down, rayDistance, platformMask);if (isOnGround && Input.GetKeyDown(jumpKey)){isJump = true;}if (Input.GetKeyDown(attackKey)){isAttack = true;}if (Input.GetKey(moveLeftKey)) {isMove = true;moveDelta.x = -moveSpeed;}else if (Input.GetKey(moveRightKey)){isMove = true;moveDelta.x = moveSpeed;}}public void HpChange(int pOld,int hp) {characterHp.SetHpInfo(hp, MaxHp);if (hp <= 0){OnDead();    }}public void SetHpInfo(){characterHp.SetHpInfo(curHp, MaxHp);}public void OnDamage(int pDamage){curHp -= pDamage;if (curHp > MaxHp)curHp = MaxHp;if (curHp < 0)curHp = 0;SetHpInfo();}private bool IsInAtkRange(Transform pTarget){var direction = curIsFaceRight ? Vector2.right* atkDistance : -Vector2.right* atkDistance;var targetPos = pTarget.position;var selfPos = this.transform.position;if (Mathf.Abs(targetPos.y - selfPos.y) <= atkOffset && Mathf.Abs(targetPos.x - (selfPos.x + direction.x)) <= atkOffset){return true;}return false;}[Command]public void CmdDoNormalAttack(){//Debug.LogError("CmdDoNormalAttack");var direction = curIsFaceRight ? Vector2.right : -Vector2.right;var identitys = GameObject.FindObjectsOfType<CharacterInput>(false);for (var i = 0; i < identitys.Length; i++){ if(identitys[i] != this){if (IsInAtkRange(identitys[i].transform)){identitys[i].OnDamage((int)atk);}}}var ai = GameObject.FindObjectsOfType<MonsterAI>(false);for (var i = 0; i < ai.Length; i++){if (ai[i] != this){if (IsInAtkRange(ai[i].transform)){ai[i].OnDamage((int)atk);}}}}[Command]void CmdSetCurFaceRight(bool pSetRight){curIsFaceRight = pSetRight;}private void FixedUpdate(){if (!identity.isLocalPlayer)return;if (IsDead())return;if (isAttack){characterAni.PlayAni("attack",4,()=> {isAttack = false;CmdDoNormalAttack();});}if (isMove){this.transform.localPosition += moveDelta * Time.deltaTime;int xS = isFaceRight == moveDelta.x > 0 ? 1 : -1;curIsFaceRight = xS == 1;CmdSetCurFaceRight(curIsFaceRight);this.transform.localScale = new Vector3(oriScale.x * xS, oriScale.y, oriScale.z);characterAni.PlayAni("move", 3);}if (isJump){body.AddForce(new Vector2(0,jumpSpeed));isJump = false;}if (!isAttack && !isMove){characterAni.PlayAni("idle", 1);}}
}

注意玩家进行攻击其他玩家的操作需要在服务器端运行,下面这段代码需要加上Command,加上Command的话是客户端在服务器段的玩家主体会运行该段逻辑,服务器改变后的血量信息通过
[SyncVar(hook = “HpChange”)]
public void HpChange(int pOld,int hp) {
characterHp.SetHpInfo(hp, MaxHp);
if (hp <= 0)
{
OnDead();
}
}
同步的方法在每个客户端同步血量信息

[Command]public void CmdDoNormalAttack(){//Debug.LogError("CmdDoNormalAttack");var direction = curIsFaceRight ? Vector2.right : -Vector2.right;var identitys = GameObject.FindObjectsOfType<CharacterInput>(false);for (var i = 0; i < identitys.Length; i++){ if(identitys[i] != this){if (IsInAtkRange(identitys[i].transform)){identitys[i].OnDamage((int)atk);}}}var ai = GameObject.FindObjectsOfType<MonsterAI>(false);for (var i = 0; i < ai.Length; i++){if (ai[i] != this){if (IsInAtkRange(ai[i].transform)){ai[i].OnDamage((int)atk);}}}}

角色动画播放添加了一个攻击动画播放完的事件用来驱动攻击伤害计算逻辑

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CharacterAni : MonoBehaviour
{private Animator animator;private string curAniName;private int curAniProx = 0;private void Awake(){animator = this.gameObject.GetComponent<Animator>();}private System.Action onFinish;public bool PlayAni(string pAniName,int pProx,System.Action pOnFinish = null){if (curAniName != null && IsPlayAning(curAniName) && pProx <= curAniProx)return false;animator.CrossFade(pAniName,0);curAniName = pAniName;curAniProx = pProx;onFinish = pOnFinish;return true;}private bool IsPlayAning(string pAniName){AnimatorStateInfo animatorInfo = animator.GetCurrentAnimatorStateInfo(0);if ((animatorInfo.normalizedTime <= 1.0f) && (animatorInfo.normalizedTime > 0f) && (animatorInfo.IsName(pAniName))){return true;}return false;}public void OnAttackFinish(){if (onFinish != null)onFinish.Invoke();}
}

血条显示设置

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CharacterHp : MonoBehaviour
{public SpriteRenderer hpBg;public SpriteRenderer hp;public int maxHp = 100;public float curHp = 100f;private float oriScale = 8;void Awake(){oriScale = hpBg.transform.localScale.x;}public void SetHpInfo(int pCurHp,int pMaxHp){curHp = pCurHp;maxHp = pMaxHp;SetCurHp();}private void SetCurHp(){var hpProgress = curHp / maxHp;hp.transform.localScale = new Vector3(hpProgress * oriScale,1,1);hp.transform.localPosition = new Vector3(-(1- hpProgress) * oriScale/2, 0,0);}
}

一下篇介绍服务器怪物的运行和创建

unity Mirror使用心得一(玩家角色创建,控制,及其攻击其他玩家的血量同步设置)相关推荐

  1. unity Mirror使用心得二(服务器端的怪物创建,及其怪物AI的行为)

    1.怪物必须由服务器创建: 创建代码: using Mirror; using System.Collections; using System.Collections.Generic; using ...

  2. Unity+Mirror实现虚拟现实下的多人连接

    实现虚拟现实环境中的多人连接顾名思义分为两步,首先通过Mirror插件实现3D空间下的多人连接基础功能,其后调整虚拟现实相关内容,最后添加虚拟化身并进行匹配.本篇文章也将从以下三个方面依次完成(使用设 ...

  3. [Unity Mirror] General

      Mirror 是一个为 Unity 游戏构建多人游戏功能的系统.它建立在较低级别的传输实时通信层之上,并处理多人游戏所需的许多常见任务.传输层支持任何类型的网络拓扑,而 Mirror 是服务器权威 ...

  4. UE4 回合游戏项目 15- 生成玩家、控制玩家

    在上一节(UE4 回合游戏项目 14- 添加敌人攻击)基础上继续完成生成玩家.控制玩家的功能 现在战斗地点基本完成,于是就需要制作玩家从外部走到指定地点,从而触发战斗.本节先完成 生成玩家.控制玩家的 ...

  5. 【Unity】【Pico】手柄摇杆控制第一人称移动和旋转

    [Unity][Pico]手柄摇杆控制第一人称移动和旋转 背景:开发影院系统 环境:Unity2021.3.PicoNeo3ProEye 描述:已经在Unity项目中实现第一人称WASD移动和鼠标旋转 ...

  6. [Unity Mirror] 同步

    英文原文: https://mirror-networking.gitbook.io/docs/guides/synchronization   状态同步是指对属于脚本的整数.浮点数.字符串和布尔值等 ...

  7. Unity UI或3d模型的动画控制(Animation类)

    文章目录 Animation动画控制类 一.动画设置: 二.模型的动作选择: 三.关键方法: 四:实践展示: 五.控制模型移动: Animation动画控制类 在Unity中,我们可以使用2D的Spi ...

  8. 项目思路---接口的权限控制、登陆校验以及白名单的设置

    接口的权限控制.登陆校验以及白名单的设置 在登陆成功之后,才可以去访问一些接口,否则其他的接口都是不可以访问状态,或者校验这个用户在发起请求的时候,是否是登陆状态,同时有些接口不需要登陆也可以访问,在 ...

  9. 球球大作战四亿人都在玩?玩家回归没有优越感,新玩家游戏被虐,游戏体验感极差!...

    球球大作战,这是一款很火的手游,自己曾经玩了3年的游戏,如今已经厌倦了,所以退游了. 当时任然记得猎魔模式,感觉身边都是人,这游戏身边都有人在玩.后面嘛,由于游戏氛围不太好,合作的人太多,一个人单排这 ...

最新文章

  1. 4.4学习笔记-REGEXP1(正则表达式)
  2. dbc2000找不到服务器控制台,控制面板没有BDE Administrator(安装好DBC2000找不到)
  3. 基于STM32的DS1302时钟芯片驱动
  4. Hadoop 2.2.0安装和配置lzo
  5. LeetCode 52. N-Queens II
  6. 快速排序quicksort算法优化
  7. 别样的1024程序员节“无Bug市集”
  8. open ball、closed ball 与 open set、closed set(interior point,limit point)、dense set
  9. JavaScript数据结构学习笔记(封装二叉树)
  10. 石油化工行业SCM供应链管理系统开发,优化供应链平台运营模式
  11. 网络知识汇总(基于W5500以太网)
  12. cpu顶盖怎么看步进_CPU步进是什么意思?i3-9100F B0步进和U0步进区别知识科普
  13. 【信息系统项目管理师】12项目合同管理
  14. redhat 7.4系统安装英伟达独立显卡驱动步骤
  15. Python案例1—人民币与美元的汇率兑换V_9.0(已完结)
  16. VS2013中添加现有窗体项
  17. python-docx教程
  18. 巨杉数据库支持的mysql兼容特性包括_核心特性_SequoiaDB简介_文档中心_SequoiaDB巨杉数据库...
  19. Vue基础入门(2) Vue.js下载与安装
  20. 神州战神电脑关闭触摸板

热门文章

  1. 马卡龙配色Icon·主题设计
  2. 如何在MAC上安装并运行Web漏洞扫描器Arachni
  3. 全国高校计算机能力挑战赛C语言编程题
  4. 【mkl】: ImportError: No module named mkl
  5. APP界面UI设计趋势(三)
  6. vue v-for in 对象 顺序排列
  7. 双边滤波opencv-python
  8. cmakelist官方教程_cmake教程.pdf
  9. 在Excel电子表格中用公式实现最最简易的标签套打
  10. ubuntu adb安装使用