UNITY-个人练习FPS(Demo)-5

本次将创建玩家控制类,实现玩家基本移动和跑跳蹲等功能

一、定义玩家控制中所需的变量

1.定义常规速度、走跳速度、疾跑速度、跑跳速度、走蹲速度、走蹲跳速度

2.定义变量speed和jumpSpeed来保存玩家当前状态应有的速度

如在疾跑状态时 :speed应为sprintSpeed,jumpSpeed为 sprintJumpSpeed;

在蹲下状态时:speed应为crouchSpeed,jumpSpeed为 crouchJumpSpeed;

    public float sprintSpeed = 10;//疾跑速度
    public float sprintJumpSpeed = 8;//跑跳速度
    public float normalSpeed = 6;//正常速度
    public float normalJumpSpeed = 7;//正常走跳速度
    public float crouchSpeed = 2;//蹲走速度
    public float crouchJumpSpeed = 5;//蹲跳速度
    public float crouchDeltaHeight = 0.5f;//蹲下高度
    public float gravity = 20;//重力
    public float cameraMoveSpeed = 8;//相机移动速度
    public AudioClip jumpAudio;//跳跃音频

    private float speed;//玩家当前速度
    private float jumpSpeed;//玩家跳跃速度
    private Transform mainCamera;//相机变换组件
    private float standardCamHeight;//正常相机高度
    private float crouchingCamHeight;//蹲下相机高度
    private bool grounded=false;//玩家是否在地面
    private bool walking = false;//玩家是否在行走
    private bool crouching = false;//玩家是否在蹲
    private bool stopCrouching = false;//玩家是否停止蹲
    private bool runing = false;//玩家是否在跑

    private Vector3 normaControllerCenter= Vector3.zero;//角色控制器中心点坐标
    private float normalControllerHeight = 0;//正常控制器高度
    private float timer = 0;//计时器
    private CharacterController controller;
    private AudioSource audioSource;
    private fps_PlayerParameter parameter;
    private Vector3 moveDirection= Vector3.zero;//角色移动方向

二、定义玩家状态的枚举enum

  1. 将玩家五种基本状态列举

  1. 初始化玩家状态为None

  1. 用属性对玩家状态的字段进行保护,并加以限制

如当“walking”时 玩家状态state为walk

public enum PlayerState
{
    None,
    Idle,
    Walk,
    Crouch,
    Run,
}
    private PlayerState state = PlayerState.None;
    public PlayerState State
    {
        get
        {
            if (walking)
                state = PlayerState.Walk;
            else if (crouching)
                state = PlayerState.Crouch;
            else if (runing)
                state = PlayerState.Run;
            else state = PlayerState.Idle;
            return state;
        }
    }

三、定义计算当前速度的方法

利用前面所定义的枚举,用属性进行判断,用对应的状态去定义四种状态(Idle、Walk、Crouch、Run)的Speed和jumpSpeed,方便后面只要角色状态切换,对应的speed和jumpSpeed自动随之切换。将状态进行封装,后面加状态,如趴下等,只需修改状态和计算速度的相关方法。

    private void CurrentSpeed()
    {    switch (State)
        {
            case PlayerState.Idle:
                speed = normalSpeed;
                jumpSpeed= normalJumpSpeed;
                break;
            case PlayerState.Walk:
                speed = normalSpeed;
                jumpSpeed = normalJumpSpeed;
                break;
            case PlayerState.Crouch:
                speed = crouchSpeed;
                jumpSpeed = crouchJumpSpeed;
                break;
            case PlayerState.Run:
                speed =sprintSpeed;
                jumpSpeed =sprintJumpSpeed;
                break;
        }
    }

四、定义脚步音频管理方法

本游戏前提设定为:只有走、跑状态下有脚步声音

  • audioSource.pitch:来定义两种状态不同的脚步速度

  • audioSource.isPlaying :判断音频片段是否正在播放

  • audioSource.Play():播放音频片段

  • audioSource.Stop():停止播放音频片段

    private void AudioManagement()
    {
        //若状态为走路状态 音频播放速度为1
        if (State==PlayerState.Walk)
        {
            audioSource.pitch = 1.0f;//音频倍速
            if (!audioSource.isPlaying)
            {
                audioSource.Play();
            }
        }
        else if (State == PlayerState.Run)
        {
            audioSource.pitch = 1.3f;//音频倍速
            if (!audioSource.isPlaying)
            {
                audioSource.Play();
            }
        }
        else audioSource.Stop();//除走和跑两种状态之外 其他状态没有声音
    }

五、定义下蹲更新相机方法

  1. 用crouching判断两种状态:在下蹲/不在下蹲

  1. 用mainCamera.localPosition.y相机当前高度和crouchDeltaHeight*Time.deltaTime*cameraMoveSpeed当前帧相机即将的移动量作比较

来判断相机是否蹲完或者站完。

private void UpdateCrouch()
    {    //若crouching为真
        if (crouching)
        {   //若主摄像机高度大于正在蹲的高度
            if (mainCamera.localPosition.y>crouchingCamHeight)
            {   //若相机高度减去当前帧相机移动量<蹲后相机高度
                if (mainCamera.localPosition.y-(crouchDeltaHeight*Time.deltaTime*cameraMoveSpeed)<crouchingCamHeight)
                {
                    mainCamera.localPosition=new Vector3(mainCamera.localPosition.x,crouchingCamHeight,mainCamera.localPosition.z);
                }//否则按帧减小
                else { mainCamera.localPosition -= new Vector3(0, (crouchDeltaHeight * Time.deltaTime * cameraMoveSpeed),0); }
            }//若不大于,就直接赋值
            else { mainCamera.localPosition = new Vector3(mainCamera.localPosition.x, crouchingCamHeight, mainCamera.localPosition.z); }
        }else//若crouching不为真
        {
            if (mainCamera.localPosition.y < standardCamHeight)
            {   
                if (mainCamera.localPosition.y + (crouchDeltaHeight * Time.deltaTime * cameraMoveSpeed) > standardCamHeight)
                {
                    mainCamera.localPosition = new Vector3(mainCamera.localPosition.x, standardCamHeight, mainCamera.localPosition.z);
                }
                else { mainCamera.localPosition += new Vector3(0, (crouchDeltaHeight * Time.deltaTime * cameraMoveSpeed), 0); }
            }
            else { mainCamera.localPosition = new Vector3(mainCamera.localPosition.x, standardCamHeight, mainCamera.localPosition.z); }

        }

    }

六、移动更新方法

  1. 当处于地板上时,进行移动。将键盘输入方向inputMoveVector交给移动变量moveDirection

注意这里要将moveDirection转换为自身坐标,因为移动方向要随视角方向改变。

  • 对moveDirection进行操作后 将moveDirection赋值给角色控制器controller

  • transform.TransformDirection():世界坐标变为自身坐标;

  • AudioSource.PlayClipAtPoint():在某点播放音频片段;

  • controller.Move():移动(不自动加grativity);

  • controller.SimpleMove():移动(自动加grativity);

  • CollisionFlags.CollidedBelow 底部发生了碰撞"flags & CollisionFlags.CollidedBelow"返回1;

  • CollisionFlags.CollidedNone 没发生碰撞"flags & CollisonFlags.CollidedNone"返回1;

  • CollisionFlags.CollidedSides 四周发生碰撞"flags & CollisionFlags.CollidedSides"返回1;

  • CollisionFlags.CollidedAbove 顶端发生了碰撞"flags & CollisionFlags.CollidedAbove"返回1;

  • &:按位与运算符 两边都为1 结果才为1;

private void UpdateMove()
    {   //若在地板上
        if (grounded)
        {
            //将键盘输入移动交给角色移动变量
            moveDirection = new Vector3(parameter.inputMoveVector.x, 0, parameter.inputMoveVector.y);
            //将移动的世界坐标转为自身坐标 因为移动方向要随视角方向改变
            moveDirection = transform.TransformDirection(moveDirection);
            moveDirection *= speed;

            //若跳跃
            if (parameter.inputJump)
            {
                moveDirection.y = jumpSpeed;
                AudioSource.PlayClipAtPoint(jumpAudio, transform.position);
                //跳跃后速度增加 因此重新计算速度
                CurrentSpeed();
            }
        }

        //赋予重力
        moveDirection.y -= gravity * Time.deltaTime;
        //将moveDirection交给Controller
        CollisionFlags falgs = controller.Move(moveDirection * Time.deltaTime);
        //若有碰撞信息且底部发生了碰撞  grounded为真
        grounded = (falgs & CollisionFlags.CollidedBelow) != 0;
        //CollisionFlags.CollidedBelow 底部发生了碰撞"flags & CollisionFlags.CollidedBelow"返回1;
        //CollisionFlags.CollidedNone 没发生碰撞"flags & CollisonFlags.CollidedNone"返回1;
        //CollisionFlags.CollidedSides 四周发生碰撞"flags & CollisionFlags.CollidedSides"返回1;
        //CollisionFlags.CollidedAbove 顶端发生了碰撞"flags & CollisionFlags.CollidedAbove"返回1;

        //若有移动且在地面
        if (Mathf.Abs(moveDirection.x) > 0 && grounded || Mathf.Abs(moveDirection.z) > 0 && grounded)
        {
            //若输入冲刺
            if (parameter.inputSprint)
            {
                walking = false;
                runing = true;
                crouching = false;

            }
            //若输入蹲下
            else if (parameter.inputCrouch)
            {
                walking = false;
                runing = false;
                crouching = true;

            }
            //否则为走
            else
            {
                walking = true;
                runing = false;
                crouching = false;
            }


        }
        //若无移动或者不在地面
        else
        {   //当前状态为走 那就不走
            if (walking) walking = false;
            if (runing) runing = false;
            if (parameter.inputCrouch) crouching = true;
            else crouching = false;
        }

        if (crouching)
        {
            controller.height = normalControllerHeight - crouchDeltaHeight;
            controller.center = new Vector3(0, (normaControllerCenter.y - crouchDeltaHeight / 2) , 0);
        }
        else
        {
            controller.height = normalControllerHeight;
            controller.center = normaControllerCenter;
        }

        UpdateCrouch();
        CurrentSpeed();
    }
  • 13
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
- Added Grenades - Bug Fixes - Adapted to new Photon Updates EZFPS is a multiplayer first person shooter template for Unity3d, using Photon Unity Networking. EZFPS is designed to make a simple FPS Deathmatch style game, with Ai bots, zombies, player classes, weapon loadouts, weapon skins and attachments, and player customization. As the player gets kills, they receive XP points, in-game currency, and rank up- allowing them to buy and unlock new weapons, attachments, skins, and cosmetics. The kit comes fully setup with 5 maps, a zombie-only mode, 9 weapons, and 3 classes, but an infinite amount of maps, weapons, and classes can be added easily by following the included tutorials and documentation. Youtube | Demo | Docs | Tutorials Features: - Player Classes - Synced Bot Ai - Synced Zombie Ai - Custom Loadouts - Player Cosmetic Customization - Weapon Attachments and Skins - Rank System - Weapon Unlocks - Machine Guns, Sniper Rifles, Shotguns, Knifes, Rocket Launchers, Grenade Launchers - Grenades - Settings Menu - More! 谷歌翻译: ——添加手榴弹 ——错误修复 -适应新的光子更新 EZFPS是一个多玩家的Unity3d第一人称射击模板,使用光子统一网络。EZFPS是设计来做一个简单的FPS死亡比赛风格的游戏,与Ai机器人,僵尸,玩家类,武器加载,武器皮肤和附件,和玩家定制。当玩家获得技能时,他们将获得经验值、游戏内货币和等级——允许他们购买和解锁新的武器、附件、皮肤和化妆品。这个工具包有5张地图,只有僵尸模式,9件武器和3个职业,但是无限数量的地图,武器,和职业可以很容易地添加遵循所包含的教程和文档。 Youtube |演示|文档|教程 特点: ——玩家类 -同步机器人Ai -同步僵尸Ai ——自定义面板 -玩家化妆品定制 -武器附件和皮肤 ——排名系统 ——武器解锁 -机关枪,狙击步枪,猎枪,刀,火箭发射器,手榴弹发射器 ——手榴弹 ——设置菜单 - - - - - -更多!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值