Unity以及游戏源码

基本认识

  1. FixedUpdate:每秒50次刷新:50帧,注意条件变量的控制(二段跳)

  2. 单词

    1. gravity:重力

    2. Rigdbody:刚体

    3.  

Unity

  1. 组件名在vs中不能更改,且vs要求组件名必须首字母大写;

  2. 视角跟随:在unity中选中GameObject为Sphere

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

    public class CameraControler : MonoBehaviour
    {
       public GameObject Sphere;//在unity中选中GameObject为Sphere
       private Vector3 offset;
       // Start is called before the first frame update
       void Start()
      {
           offset = transform.position - Sphere.transform.position;
      }

       // Update is called once per frame
       void LateUpdate()
      {
           transform.position = Sphere.transform.position + offset;
      }
    }

    分辨率:一个格子100dp=10*10;

    物体碰撞(2d):

    1. 物体设置为Rigidbody、Boxcollider,地面设置为Rigidbody并将bodytype修改为Kinematic、Boxcollider

    2. 碰撞会产生微小形变,可能会穿模,将主角的Rigidbody中的Interpolate改为Interpolate去除碰撞形变

物体运动

https://www.bilibili.com/video/BV14V411r7Tr?p=2视频教学

Kinematic:开启运动学,开启后不再受力的影响,只能通过Transform属性来操作。

  1. 初级运动

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

    public class Character : MonoBehaviour
    {
       public float speed = 3f;
       public Rigidbody2D rig;
       public float jumpForce;
       // Start is called before the first frame update
       void Start()
      {
           rig = GetComponent<Rigidbody2D>();
           jumpForce = 300f;
      }

       // Update is called once per frame
       void Update()
      {
           if (Input.GetKeyDown(KeyCode.K))
          {    //如果按下空格

               rig.AddForce(new Vector2(0, jumpForce));   //给刚体一个向上的力

          }
           float moveX = Input.GetAxisRaw("Horizontal");//控制水平方向A:-1 D:1 0
           //float moveY = Input.GetAxisRaw("Vertical");//控制数值方向S:-1 W:1 0

           Vector2 position = transform.position;
           position.x += moveX * speed * Time.deltaTime;
           transform.position = position;
      }
    }

     

  2. 高级

    1. 改为没有平滑过渡Editor--Project setting--Input--Gravity、Sensetivity修改为1000,与fire1相同

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

      public class Character : MonoBehaviour
      {
         public float WalkSpeed;
         public float AccelerrateTime;
         public float DecelerateTime;

         Rigidbody2D Rig;
         float velocityX;

         private void Awake()
        {
             Rig = GetComponent<Rigidbody2D>();
        }
         private void FixedUpdate()
        {
             if (Input.GetAxisRaw("Horizontal") < 0)
            {
                 Rig.velocity = new Vector2(Mathf.SmoothDamp(Rig.velocity.x, WalkSpeed * Time.deltaTime * 60, ref velocityX, AccelerrateTime), Rig.velocity.y);
            }
             else if (Input.GetAxisRaw("Horizontal") > 0)
            {
                 Rig.velocity = new Vector2(Mathf.SmoothDamp(Rig.velocity.x, WalkSpeed * Time.deltaTime * 60*(-1), ref velocityX, AccelerrateTime), Rig.velocity.y);
                 //使用加速时间控制启动、停止快慢
            }
             else if (Input.GetAxisRaw("Horizontal") == 0)
            {
                 Rig.velocity = new Vector2(Mathf.SmoothDamp(Rig.velocity.x, 0, ref velocityX, AccelerrateTime), Rig.velocity.y);
            }
        }
      }

使用

在Edit->project setting -> input 处可以对按键细节进行设置: 20200109141230272 扩展size ,即可添加按键配置。 Name:名称,调用或在外部设置的时候需要使用该名 Negative Button :缺省值为-1的按键 Positive Button :缺省值为1的按键 Alt Negative Button :备用的缺省值为-1的按键 Alt Positive Button :备用的缺省值为1的按键 Dead: 输入阈值, 触摸或者摇杆大于这个值才会触发输入 Gravity:表示松开按键时,从端点1或-1返回缺省值0时的速度 Sensitivity:按下按键时,从缺省值0到1或-1时的速度 Snap: 当触发反向操作时,当前值是否立即归零 Invet:是否取反值 Type:预设输入设备类型,可选键盘与鼠标按键、手柄、鼠标移动 Axis:装置选择,例如一个手柄有两个十字键两个摇杆,那么可以在这里设置当前设定作用于哪个装置 Joy Num: 手柄编号。指定连接的哪个设备 需要说明的是,在输入管理器中设置的输入基本上都是返回-1 - 1 区间的值。这比返回true false要好很多,因为优化输入体验的时候,比如我们希望根据按压力度来调整跳跃距离,又或者我们希望根据摇杆的摇摆程度来控制车辆的方向盘,都比较合适

函数说明

Rig.velocity:刚体的速度:矢量,

参数说明

Parameters,它就是使用Animator来切换动作的灵魂。可以把它理解为实现动作的条件,通过改变它来判断满足什么条件执行什么动作。点击右边的+号,可以看到有4个类型:Float,Int,Bool,Trigger。

绘制背景

  1. 创建tilemap

  2. 设置sortinglayer:通过Edit/Project Settings/Tags & Layers打开Sorting Layers创建*排列层*并调整它们的位置

  3. 放入背景,设置每个tilemap单元格的像素(设置tilemap的scale大小,自己调试)

    第一次人物做的太小,导致画地图时地图方块无法占满单个格子

  4. 调试物块大小:将物块放入tilepalete,在inspector界面中调整图片像素

设置地图

  1. 在对应的tilemap里边添加碰撞器,刚体

  2. 单独的每一块碰撞器,发现角色卡在某个位置不能移动,解决方法:将每个碰撞器合并成整体的复合碰撞器

    1. Tilemap Collidor 2d中选择used by Composite

    2. 添加Composite Collidor 2d

  3. 调整TileMap碰撞点

    在进行爬坡测试的时候,出现了一个问题就是斜坡的瓦片碰撞点不能和瓦片重合,且凹凸不平,运行体验不佳。

    不是正方形的瓦片的话,TileMap的碰撞点自动设置可能很奇怪,直接TileMap设置碰撞器的话,可能会有凹凸不平的情况,且凹凸不平的形状不能和瓦片完全重合。

    出现这个问题可能需要回到一开始编辑图片,在Sprite Editor里面,左边的红框选择第三个Custom Physics Shape,然后点击需要修改碰撞点的方形块,然后点击Generate就可以修改碰撞点。

  4. 物体勾选IsTriger:物体可以被穿过但仍视为有效碰撞,用于制作陷阱或者拾取道具

动画制作

  1. 创建空动画

  2. 将动画拉入主角,自动生成动画控制器

  3. 点击Animator,右键创建blendtree

  4. 点击blendtree,再双击,添加之前创建的空动画

  5. 选择主角,在animation处添加图片,生成动画

动画重写

  1. 已有Enermy1动画效果,在AnimationControllers文件夹内空白处右键,依次选择Create->Animator Override Controller,创建了一个动画重写控制器,我们命名为Enemy2

  2. 可以看到这个重写控制器右侧Inspector窗口内有个Controller选项,可以选择继承哪个动画控制器。在这里,我们可以把Enemy1直接拖入到输入框,或者点击输入框右侧的小圆圈选择Enemy1。

  3. 继承Enemy1的动画控制器后,还需要把美术资源也替换掉。Enemy1Attack改写成Enemy2Attack,Enemy1Idle改写成Enemy2Idle,这样重写控制器就配置好了。

  4. 这时候,怪物2的Animator组件使用的控制器还是Enemy1。选择Enemy2游戏对象,在Animator组件的Controller选项点击右侧小圆圈,在弹出的窗口中选择Enemy2即可。

  5. 这时候运行游戏,可以看到怪物2的动画正常。

  6. 通过这样重写控制器,以后在怪物1的动画控制器添加逻辑的时候,怪物2自动继承,不需要再额外给怪物2添加一样的逻辑。我们这个项目才2个小怪,如果怪物类型或者动画类型再多一点,重写控制器就非常有必要。而且修改起来也只需要改一个地方即可,非常方便。其实个人觉得和Prefab预制件有点相似。

链接:https://www.jianshu.com/p/5622f6db56b7

game

实现高度手感跳跃

public float LowJumpMultiplier;
   bool IsJumping;

   //触地判定
   public Vector2 PointOffset;
   public Vector2 Size;
   public LayerMask GroundLayerMask;
   Rigidbody2D Rig;
   float velocityX;
   bool GravatySwitch = true;
   bool IsOnGround;//判定是否在地面

   private void Awake()
  {
       Rig = GetComponent<Rigidbody2D>();
  }
   private void FixedUpdate()
  {
       IsOnGround = OnGround();
       //左右移动
       if (Input.GetAxisRaw("Horizontal") < 0)
      {
           Rig.velocity = new Vector2(Mathf.SmoothDamp(Rig.velocity.x, WalkSpeed * Time.deltaTime * 60*(-1), ref velocityX, AccelerrateTime), Rig.velocity.y);
      }
       else if (Input.GetAxisRaw("Horizontal") > 0)
      {
           Rig.velocity = new Vector2(Mathf.SmoothDamp(Rig.velocity.x, WalkSpeed * Time.deltaTime * 60, ref velocityX, AccelerrateTime), Rig.velocity.y);
      }
       else if (Input.GetAxisRaw("Horizontal") == 0)
      {
           Rig.velocity = new Vector2(Mathf.SmoothDamp(Rig.velocity.x, 0, ref velocityX, AccelerrateTime), Rig.velocity.y);
      }
       if (Input.GetAxisRaw("Jump") == 1&&!IsJumping)
      {
           Rig.velocity = new Vector2(Rig.velocity.x, JumpingSpeed);//x轴不变,y轴给个初速度
           IsJumping = true;//正在空中
      }
       if (IsOnGround && Input.GetAxisRaw("Jump") == 0)//在地面并且松开跳跃键
      {
           IsJumping = false;
      }
       //Physics2D.gravity.y是一个负值
       if (Rig.velocity.y < 0)//下坠时
      {
           //下落的更快
           Rig.velocity += Vector2.up * Physics2D.gravity.y * (FallMultiplier - 1) * Time.fixedDeltaTime;
      }
       else if(Rig.velocity.y>0&&Input.GetAxisRaw("Jump")!=1)//当玩家上升时,并且没有按跳跃键,实现按多久跳多高,范围内任意高度跳跃
      {
           //减缓上升
           Rig.velocity += Vector2.up * Physics2D.gravity.y * (LowJumpMultiplier - 1) * Time.fixedDeltaTime;
      }
  }
   bool OnGround()
  {
       Collider2D Coll = Physics2D.OverlapBox((Vector2)transform.position + PointOffset, Size, 0, GroundLayerMask);
       //触地判定框
       if (Coll != null)
      {
           return true;
      }
       else
      {
           return false;
      }
  }
   private void OnDrawGizmos()//在编辑器中显示判定框
  {
       Gizmos.DrawWireCube((Vector2)transform.position + PointOffset, Size);
  }
}

冲刺+

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using DG.Tweening;
public class Character : MonoBehaviour
{
   //移动
   public float WalkSpeed;
   public float AccelerrateTime;
   public float DecelerateTime;
   bool CanMove=true;//冲刺时关闭移动

   //跳跃
   public float JumpingSpeed;
   public float FallMultiplier;
   public float LowJumpMultiplier;
   bool IsJumping;
   bool CanJump=true;//冲刺时关闭跳跃

   //冲刺
   bool wasDashed;//冲刺状态
   Vector2 dir;
   public float Dashedforce;
   public float DragMaxForce;
   public float DragDuration;
   public float DashWaitTime;

   //触地判定
   public Vector2 PointOffset;
   public Vector2 Size;
   public LayerMask GroundLayerMask;
   Rigidbody2D Rig;
   float velocityX;
   bool IsOnGround;//判定是否在地面
   bool GravityModifier=true;//冲刺时关闭加速度

   private void Awake()
  {
       Rig = GetComponent<Rigidbody2D>();
  }
   private void FixedUpdate()
  {
       IsOnGround = OnGround();
       #region 左右移动
       if (CanMove)
      {
           if (Input.GetAxisRaw("Horizontal") < 0)
          {
               Rig.velocity = new Vector2(Mathf.SmoothDamp(Rig.velocity.x, WalkSpeed * Time.deltaTime * 60 * (-1), ref velocityX, AccelerrateTime), Rig.velocity.y);
          }
           else if (Input.GetAxisRaw("Horizontal") > 0)
          {
               Rig.velocity = new Vector2(Mathf.SmoothDamp(Rig.velocity.x, WalkSpeed * Time.deltaTime * 60, ref velocityX, AccelerrateTime), Rig.velocity.y);
          }
           else
          {
               Rig.velocity = new Vector2(Mathf.SmoothDamp(Rig.velocity.x, 0, ref velocityX, AccelerrateTime), Rig.velocity.y);
          }
      }
       #endregion
       #region 起跳
       if (CanJump)
      {
           if (Input.GetAxisRaw("Jump") == 1 && !IsJumping)//跳跃:给y轴一个初速度
          {
               Rig.velocity = new Vector2(Rig.velocity.x, JumpingSpeed);//x轴不变,y轴给个初速度
               IsJumping = true;//正在空中
          }
           if (IsOnGround && Input.GetAxisRaw("Jump") == 0)//在地面并且松开跳跃键
          {
               IsJumping = false;
          }
      }
       #endregion
       #region 跳跃优化
       if (GravityModifier)
      {
           //Physics2D.gravity.y是一个负值
           if (Rig.velocity.y < 0)//下坠时
          {
               //下落的更快
               Rig.velocity += Vector2.up * Physics2D.gravity.y * (FallMultiplier - 1) * Time.fixedDeltaTime;
          }
           else if (Rig.velocity.y > 0 && Input.GetAxisRaw("Jump") != 1)//当玩家上升时,并且没有按跳跃键,实现按多久跳多高,范围内任意高度跳跃
          {
               //减缓上升
               Rig.velocity += Vector2.up * Physics2D.gravity.y * (LowJumpMultiplier - 1) * Time.fixedDeltaTime;
          }
      }
       #endregion
       #region 冲刺检测
       //1.不受重力影响
       //2.不受其他按键影响
       if (Input.GetAxisRaw("Dash") == 1 && !wasDashed)//冲刺之后
      {
           wasDashed = true;
           dir = new Vector2(Input.GetAxisRaw("Horizontal"), Input.GetAxisRaw("Vertical"));//获得冲刺方向
           //玩家所有动量清零
           Rig.velocity = Vector2.zero;
           //给玩家施加一个力,进行冲刺
           Rig.velocity += dir * Dashedforce;
           StartCoroutine(Dash());
      }
       if (Input.GetAxisRaw("Dash") == 0 && IsOnGround)
      {
           wasDashed = false;
      }
     
       #endregion
  }
   IEnumerator Dash()//冲刺
  {
       //锁定玩家的按键功能
       //关闭重力调整器
       CanMove = false;
       CanJump = false;
       GravityModifier = false;
       //关闭重力影响
       Rig.gravityScale = 0;
       //施加空气阻力,快速停下Rigidody.Drag
       DOVirtual.Float(DragMaxForce, 0, DragDuration, RigidbodyDrag);
       //等待冲刺完毕
       yield return new WaitForSeconds(DashWaitTime);
       //开启所有关闭功能
       CanMove = true;
       CanJump = true;
       GravityModifier = true;
       Rig.gravityScale = 1;//应该为4,但GravityModifier会帮我们自动修改
  }
   public void RigidbodyDrag(float x)
  {
       Rig.drag = x;
  }
   bool OnGround()//判断是否接触地面
  {
       Collider2D Coll = Physics2D.OverlapBox((Vector2)transform.position + PointOffset, Size, 0, GroundLayerMask);
       //触地判定框
       if (Coll != null)
      {
           return true;
      }
       else
      {
           return false;
      }
  }
   private void OnDrawGizmos()//在编辑器中显示判定框
  {
       Gizmos.DrawWireCube((Vector2)transform.position + PointOffset, Size);
  }
}

触地判定

  1. 代码显示判定框,调整判定框大小:宽度略小于物体

  2. 设置地面:地板的layer添加一个layer,并在物体的Ground layermask选中这个layer

  3. 绘画出动作每一帧,添加进Animator中,勾选loop调为连续播放

完整

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using DG.Tweening;
public class Move : MonoBehaviour
{
   Rigidbody2D Rig;//定义刚体

   //移动
   public float WalkSpeed;
   public float AccelerrateTime;
   public float DecelerateTime;
   bool CanMove=true;//冲刺时关闭移动
   Animator Anim;//定义动画
   SpriteRenderer SR;

   //跳跃
   public float JumpingSpeed;
   public float FallMultiplier;
   public float LowJumpMultiplier;
   bool IsJumping;
   bool CanJump=true;//冲刺时关闭跳跃

   //冲刺
   bool wasDashed;//冲刺状态
   Vector2 dir;
   public float Dashedforce;
   public float DragMaxForce;
   public float DragDuration;
   public float DashWaitTime;

   //触地判定
   public Vector2 PointOffset;
   public Vector2 Size;
   public LayerMask GroundLayerMask;
   float velocityX;
   bool IsOnGround;//判定是否在地面
   bool GravityModifier=true;//冲刺时关闭加速度

   private void Awake()
  {
       Rig = GetComponent<Rigidbody2D>();//获得添加了此脚本的刚体
       Anim = GetComponent<Animator>();//获得添加了此脚本的动作
       SR = GetComponent<SpriteRenderer>();
  }
   private void FixedUpdate()
  {
       IsOnGround = OnGround();
       #region 左右移动
       if (CanMove)
      {
           if (Input.GetAxisRaw("Horizontal") < 0)//向左走
          {
               if (Rig.velocity.x < WalkSpeed * Time.fixedDeltaTime * 60)
              {
                   Rig.velocity = new Vector2(Mathf.SmoothDamp(Rig.velocity.x, WalkSpeed * Time.deltaTime * 60 * (-1), ref velocityX, AccelerrateTime), Rig.velocity.y);
              }
               SR.flipX = true;
               Anim.SetFloat("Walk", 0.5f);
          }
           else if (Input.GetAxisRaw("Horizontal") > 0)//向右走
          {
               if (Rig.velocity.x < WalkSpeed * Time.fixedDeltaTime * 60)
              {
                   Rig.velocity = new Vector2(Mathf.SmoothDamp(Rig.velocity.x, WalkSpeed * Time.deltaTime * 60, ref velocityX, AccelerrateTime), Rig.velocity.y);
              }
               SR.flipX = false;//不变
               if (!wasDashed)
              {
                   Anim.SetFloat("Walk", 0.5f);
              }
          }
           else
          {
               Rig.velocity = new Vector2(Mathf.SmoothDamp(Rig.velocity.x, 0, ref velocityX, AccelerrateTime), Rig.velocity.y);
               if (!wasDashed)
              {
                   Anim.SetFloat("Walk", 0f);
              }
          }
      }
       #endregion
       #region 起跳
       if (CanJump)
      {
           if (Input.GetAxisRaw("Jump") == 1 && !IsJumping)//跳跃:给y轴一个初速度
          {
               Rig.velocity = new Vector2(Rig.velocity.x, JumpingSpeed);//x轴不变,y轴给个初速度
               IsJumping = true;//正在空中
          }
           if (IsOnGround && Input.GetAxisRaw("Jump") == 0)//在地面并且松开跳跃键
          {
               IsJumping = false;
          }
      }
       #endregion
       #region 跳跃优化
       if (GravityModifier)
      {
           //Physics2D.gravity.y是一个负值
           if (Rig.velocity.y < 0)//下坠时
          {
               //下落的更快
               Rig.velocity += Vector2.up * Physics2D.gravity.y * (FallMultiplier - 1) * Time.fixedDeltaTime;
          }
           else if (Rig.velocity.y > 0 && Input.GetAxisRaw("Jump") != 1)//当玩家上升时,并且没有按跳跃键,实现按多久跳多高,范围内任意高度跳跃
          {
               //减缓上升
               Rig.velocity += Vector2.up * Physics2D.gravity.y * (LowJumpMultiplier - 1) * Time.fixedDeltaTime;
          }
      }
       #endregion
       #region 冲刺检测
       //1.不受重力影响
       //2.不受其他按键影响
       if (Input.GetAxisRaw("Dash") == 1 && !wasDashed)//冲刺之后
      {
           wasDashed = true;
           dir = GetDir();//获得冲刺方向
           //玩家所有动量清零
           Rig.velocity = Vector2.zero;
           //给玩家施加一个力,进行冲刺
           Anim.SetFloat("Dash", 1.0f);
           Rig.velocity += dir * Dashedforce;
           StartCoroutine(Dash());
      }
       if (Input.GetAxisRaw("Dash") == 0 && IsOnGround)
      {
           wasDashed = false;
           Anim.SetFloat("Dash", 0f);
      }
     
       #endregion
  }
   IEnumerator Dash()//冲刺
  {
       //锁定玩家的按键功能
       //关闭重力调整器
       CanMove = false;
       CanJump = false;
       GravityModifier = false;
       //关闭重力影响
       Rig.gravityScale = 0;
       //施加空气阻力,快速停下Rigidody.Drag
       DOVirtual.Float(DragMaxForce, 0, DragDuration, RigidbodyDrag);
       //等待冲刺完毕
       yield return new WaitForSeconds(DashWaitTime);
       //开启所有关闭功能
       CanMove = true;
       CanJump = true;
       GravityModifier = true;
       Rig.gravityScale = 1;//应该为4,但GravityModifier会帮我们自动修改
  }
   public void RigidbodyDrag(float x)
  {
       Rig.drag = x;
  }
   bool OnGround()//判断是否接触地面
  {
       Collider2D Coll = Physics2D.OverlapBox((Vector2)transform.position + PointOffset, Size, 0, GroundLayerMask);
       //触地判定框
       if (Coll != null)
      {
           return true;
      }
       else
      {
           return false;
      }
  }
   private void OnDrawGizmos()//在编辑器中显示判定框
  {
       Gizmos.DrawWireCube((Vector2)transform.position + PointOffset, Size);
  }
   public Vector2 GetDir()
  {
       Vector2 tempDir= dir = new Vector2(Input.GetAxisRaw("Horizontal"), Input.GetAxisRaw("Vertical"));
       if (tempDir.x == 0 && tempDir.y == 0)
      {
           if (!SR.flipX)
               tempDir.x = 1;
           else
               tempDir.x = -1;
      }
       return tempDir;
  }
}

问题:只能实现一段跳

制作完美手感二段跳

 private void Update()//避免多次按跳跃键落地后自动跳,
  {
       JumpPressed = false;
       if (Input.GetButtonDown("Jump")&& JumpCount>0)
      {
           JumpPressed = true;
      }
       #region 起跳
       if (CanJump)
      {
           if (JumpPressed && JumpCount > 0 && !IsOnWall)
          {
               Rig.velocity = new Vector2(Rig.velocity.x, JumpingSpeed);//x轴不变,y轴给个初速度
               JumpCount--;
               JumpPressed = false;
               //正在空中
          }
           else if (IsOnGround)//在地面并且松开跳跃键
          {
               JumpCount = JumpCountNumber;
               IsJumping = false;
          }
      }
       #endregion
  }
   private void FixedUpdate()
  {
       if (CanJump)
      {
           if (JumpPressed &&!IsOnWall)
          {
               Rig.velocity = new Vector2(Rig.velocity.x, JumpingSpeed);//x轴不变,y轴给个初速度
               JumpCount--;
               JumpPressed = false;
               //正在空中
          }
           else if (IsOnGround)//在地面并且松开跳跃键
          {
               JumpCount = JumpCountNumber;
          }
      }
  }
  1. 如果跳跃代码全在update中,跳跃可能无法二段

  2. 如果全在fixedupdate中,点击一次两端jumpcount一起消失

posted @ 2020-11-10 15:54  Deair  阅读(208)  评论(0编辑  收藏  举报