因为这个玩意和C差不多
要从头开始学习相关语法
由于我们的主要目的是为了与unity游戏架构相匹配,那我们主要学习重要的代码块
#1 使物体随着时间进行相应重复动作的代码


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

public class 钻圈圈 : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        //这里就不用初始化了
    }

    // Update is called once per frame
    void Update()
    {
        对于被绑定脚本的物体,使用gameobject中的方法调用组件transform,并使用其中Rolate 的方法
        gameObject.transform.Rotate(0, 5*Time.deltaTime, 0, Space.Self);
    }
}

#2 获得目标物体控制权并控制其进行移动的代码

using System.Collections;         
using System.Collections.Generic;**这里引入要使用的方法**
using UnityEngine;

public class NewBehaviourScript : MonoBehaviour
{
    // Start is called before the first frame update
    GameObject go; 这里声明一个游戏对象 go 并对其进行相关的初始化。
    void Start()
    {
        go = GameObject.Find("ME");//这里的意思是对于游戏对象go的确定,通过gameobject的find方法找到名为“ME”的游戏对象。
    }

    // Update is called once per frame
    void Update()
    {
        这里进行移动功能的产出。
        if如果input输入的方法,getkey中得到keycode-w,那么就执行接下来的操作
        在对象go上调用方法类transfrom中的方法类Translate来进行移动,
        这个Translate方法要包含四个参数
        (x,y,z,坐标系)
        注意,这里的xyz是世界坐标系,真正的上下左右是以摄像头的角度来确定的。
        坐标系分为spase.self与space.world
        即自我坐标系和世界坐标系
        自我坐标系以自我坐标系为参考系,即游戏对象拥有正面,若是正面被转到场景的相对后面,那么按下前进的w是会向相对后面前进的,并且正面确定后左右方向也会随之变化。
        而最重要的是样例中的 -5 * Time.deltaTime 这个表示随着每一帧的时间,进行多少单位的移动。
        if(Input.GetKey(KeyCode.W))
        {
            go.transform.Translate(0, 0, -5 * Time.deltaTime, Space.Self);
        }
        if (Input.GetKey(KeyCode.A))
        {
            go.transform.Translate(5*Time.deltaTime,0,0, Space.Self);
        }
        if (Input.GetKey(KeyCode.S))
        {
            go.transform.Translate(0, 0, 5*Time.deltaTime, Space.Self);
        }
        if (Input.GetKey(KeyCode.D))
        {
            go.transform.Translate(-5*Time.deltaTime, 0, 0, Space.Self);
        }
        if(Input.GetKey(KeyCode.Space)) 
        {
            go.transform.Translate(0, 5 * Time.deltaTime, 0, Space.Self);
        }
    }
}

3让鼠标操作触发一些事件的代码

总共有四大操作
鼠标进入,即光标放在绑定物体上时
void onmouseenter()
{}
鼠标离开,即光标离开物体时
void onmouseexit()
{}
鼠标点击,即click时
void onmousedown()
{}
鼠标抬起,这个就是按下后的回弹
void onmouseup()
{}
关于实操,由于一些小问题,这里欢迎后续补充

4 使得物体与某个位置被克隆的代码

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
首先在unity中就要做好提前到准备
1创建一个新空物体作为克隆点
2选择母体进行预设
3编写脚本之后把母体移到脚本组件中
public class cone : MonoBehaviour  
{
    public GameObject go;这个是声明一个外部变量,注意,只有加了这个public才可在unity编译器中显示该变量的相关信息。
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        这里判断是否抬起空格,这样一次按下就产出一个,但若是getkey(keycode.space),那就会瞬间产出一堆
        if (Input.GetKeyUp(KeyCode.Space))
        {
            这里使用Gameobject中的方法,克隆,instantiate,要求三个参数,(克隆母体,克隆位置,克隆旋转角度)
            GameObject.Instantiate(go, gameObject.transform.position, gameObject.transform.rotation);这里声明参数时可以这么理解,gameobject的transform组件中的position。
        }
    }
}

#5 点击某个物体使其消失的代码

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

public class 钻圈圈 : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
    }

    // Update is called once per frame
    void Update()
    {   这里是钻圈圈的代码,不管他
        gameObject.transform.Rotate(0, 5*Time.deltaTime, 0, Space.Self);
    }
    private void OnMouseUp()
    {

        当鼠标点击抬起后,使用Gameobject中的方发
        Destroy(),gameobject表示该脚本依附的对象。
        GameObject.Destroy(gameObject);
    }
}

关于GUI

他是单独写在一个主括号中的一样大类别,用来对游戏选项按钮进行相应的布局。设置窗口,开始界面,还有登录界面都需要GUI的出现。注意他的脚本安在camera里
###关于其代码


private void OnGUI()
{   创建按钮,返回的是布尔值,所以用if来桥接接下来的操作。
其中,new rect 用来规定该按钮的位置宽高(x,y,width,height),后面一个来显示按钮上的文本
其中有两类按钮,一个是点一下出一个结果的普通butto你,还有一个就是进行长按操作识别的repeatbutton
    if (GUI.Button(new Rect(10,20 , 70, 20), "我是按钮"))
    {
        print("嗨嗨嗨");
    };
    if (GUI.RepeatButton(new Rect(50, 60, 70, 20), "我是长按按钮"))
    {
        print("!!!");
    }
这里介绍两个输入框,文本输入框和密码输入框,
由于直接在rect 后面写下文本是不可被更改的,这与输入的预期不符,于是我们这里要设置全句变量,即 private string(输入的是字符嘛)str1 , str2同理。
其中一个比较特殊的是passwordfiled方法中多了一个参数,即密码marker,用单引号选择将密码用什么符号来遮盖。
    str2 = GUI.PasswordField(new Rect(40, 40, 100, 20), str2, '*');
    str1 = GUI.TextArea(new Rect(20, 30, 100, 20), str1);
这里介绍单选与多选的代码
由于也是输入性数据,那么还是要先规定一个全局变量,只不过这里要注意这里选择的变量输入为布尔值,即全局变量 写为 private bool sex=false;

     sex =GUI.Toggle(new Rect(0,60, 30, 30), sex, "男");
     sex = GUI.Toggle(new Rect(0, 90, 30, 30), !sex, "女");
     这里对于同一个变量sex有两个选择,且最终结果只有一个,那么在其他的选项上要加上!表示单选的结果,若是多选,那么就根据实际情况创建多个变量或者选项。
}

因为这个GUL布局老是要去算位置,来避免视图重叠的情况
所以我们引入不用担心重叠的GUIlayout方法

private void OnGUI()
{
    GUILayout.BeginHorizontal();这个表示横向排列的起点
    GUILayout.Button("我手机在哪!");
    GUILayout.Button("我手机在哪!");
    GUILayout.Button("我手机在哪!");
    GUILayout.Button("我手机在哪!");
    GUILayout.EndHorizontal();这个是终点

    GUILayout.BeginVertical();这个是纵向排列的起点
    GUILayout.Button("我的手机在哪?");
    GUILayout.Button("我的手机在哪?");
    GUILayout.Button("我的手机在哪?");
    GUILayout.Button("我的手机在哪?");
    GUILayout.EndVertical();这个是终点。

}

2024年1月28日20:43:40
这里触及到了人物模型导入并进行相应动作的动画剪辑,可是因为素材的问题还有版本问题,未产生预期的效果,待后面技术力提升后,再来尝试

关于application方法

application是对场景进行一些特定指令的方法。
同样,要使用需要把相关脚本放在camera里
这里介绍常用的四种application方法

 void Update()
 {
     if (UnityEngine.Input.GetKey(KeyCode.A))
     {
         Application.LoadLevel(0);
     }
     if (UnityEngine.Input.GetKey(KeyCode.B))
     {
         Application.LoadLevel(1);
     }
     上面的是切换场景的方法,按下某个keyboard之后就可跳转到下一场景。只不过之间还要进行场景的关联building,在unity文件菜单的选项中有这个,把场景按一定顺序拖入即可,系统会自动配上序列号,这也就是Loadlevel中的0,1,的源头了。
     if (UnityEngine.Input.GetKey(KeyCode.C))
     {
         Application.OpenURL("https://www.bilibili.com/video/BV1qA411M7dY/?p=18&vd_source=5e9d27e51ed19325b67ec992fb5dd70b");
     }
     上面这个是在Game中按下某个keyboard后进入某个wab的方法
     挺好懂的。
     if (UnityEngine.Input.GetKey(KeyCode.Q)) 
    {
         Application.Quit();
    }
    上面的这个是表示游戏程序退出
   
  }

注意,这里的一些代码在VS2022中显示的是过时,也就是这些代码的通用性还有待更新.因为我们的教程年代还是有点久远的 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

关与射线

通过摄像机发出的射线来对物体进行指示。

写在update里的,同样是放在摄像机上的脚本
这里是调用检测鼠标左键输入的方法,这个getmousebuttondown后面()中0代表的左键,而右键是1,2代表的就是中键了
if (UnityEngine.Input.GetMouseButtonDown(0))
{
   这里我们定义一个射线Ray类 ray他的值源于调用camera方法,中mian方法中的screenpointToray,即从摄像机中发出一条射线,那么射线指向哪?所以紧接着我们规定为输入鼠标的位置,
   Ray ray = Camera.main.ScreenPointToRay
       (UnityEngine.Input.mousePosition);
   接下来射中了我们需要存储射中的信息,那么我们就定义一个射线撞击类的变量 hit
   RaycastHit hit;
   之后使用这个变量的bool值做出消除的指令
   调用physics中的Raycast方法写入参数 ray 和撞击信息
   之后调用Destroy方法,对撞击信息的持有者gameobject进行消除,完成整个指令。
   if (Physics.Raycast(ray, out hit))
   {
       Destroy(hit.collider.gameObject);
   }
}

让我们欢迎大佬!第一人称移动代码!

因为是大佬教的,人家有丰富的学术基础,我们菜dog只能大致的去了解,争取理解的去记住。我会敲那么知识就是我们的了

首先我们来猜测原理
我们是对player进行移动,那么改脚本要放在player身上。那么我们首先就要定义一个游戏物体Gameobject player ;但大佬使用的是public Gameobject 那么我们先跟大佬走,后面看看为什么这么定义。

public Transform player;

根据鼠标的移动来进行视角的旋转,那么我们肯定要用到鼠标的移动数据。而鼠标于二维移动,那么我们就可以定义浮点数(更精确)的mouseX与mouseY
定义数值一般定在方法的外面,

private float MouseX;
private float MouseY;

得知现实的鼠标移动距离,想要计算出屏幕光标的移动情况我们还要设置一波鼠标灵敏度
什么是鼠标灵敏度?
相当于与个k,实际鼠标移动速度乘以这个k可以看成光标的移动速度。
那么就定义一个吧,放在外面好调节

public float MouseSensitivity;
private void Update()
{
    MouseX=Input.GetAxis("Mouse X")*MouseSensitivity*Time.deltaTime;
    MouseY=Input.GetAxis("Mouse Y")*MouseSensitivity*Time.deltaTime;
}

这里我们介绍一下这个Getaxis方法,他可以统计鼠标的轴向移动距离并返回一个-1-1的值,
把相关的数据收集起来,我们就可以得到光标的移动数据,

接下来我们需要然我们的player旋转来让相机旋转,从而达到相机的视角方向即为player的移动方向。
那么就要对player的角度rotate进行操作

     player.Rotate(Vector3.up*MouseX);

这边介绍Vector3.up是啥?
这是一个向上的三维变量。嗯,就这么多。

我们在这里提出一个了解和一个问题
了解:一个脚本的使用套在某个物体上,也可以对另外的物体产生影响,在定义的时候所定义出的public 是可以在unity中塞入其他物体的信息来代替这个定义的物体的.
那我们就可以窥探到前面大佬为甚么会定义一个public Translate player ;就是为了之后把外部player的Translate信息塞进去,好对他的移动进行控制。而我们之前的理解也因此产生矛盾,现在我们想通哩,我们的脚本挂在谁身上,就是对谁起作用,而为了某个目的我们也可以通过public 引入外界物体信息,在该脚本内进行相关操作,所以我们这个第一人称视角的脚本归根结底还是要挂在摄像机上面。
问题:
在大佬的描述中我们通过鼠标垫的x向移动信息来实现向上的操作,而y轴的移动信息来实现左右的旋转,那么就应该是这样的一个坐标图,但
与我对坐标的理解有点矛盾
猜测,unity使用的是右手系。

  △X
  |
  |
  |
  __________>Y

重新整理思绪后,我们知道了这个脚本依附的主人是摄像机。
但还有一个问题,为什么到老讲的是把player的角度旋转,达到上下视角转换的效果,虽说player是父对象,他的旋转可以带动摄像机的旋转,但为什么不直接改变摄像机的旋转呢。而是在下面单独对摄像机进行左右的旋转?
看看后面有没有解答吧。但是实操发现我们如果采用单摄像机旋转根本转不动

transform.localRotation = Quaternion.Euler(-MouseY, 0, 0);

这个便是对摄像机进行角度转换的操作,采用的localrotation可以以摄像机的自身方位进行角度改变
这是一个相当于变量的东东,实际上是一个属性,所以要对它进行赋值的操作,而后面的quaternion的euler方法可以接受旋转的角度。
这之后进行了实操但发现上下旋转不动,后续了解到我们的Getaxis方法在鼠标不动是进行数据的回弹即归为0,使得上下旋转出现问题。
所以我们需要把y方向的数据进行累加。
大佬在这里运用的是累减,这样在放入数据时不用加负号了。

public Transform player;
public float MouseX;
public float MouseY;
public float MouseSensitivity;
public float Xrotation;
public float Yrotation;

private void Update()
{
    MouseX=Input.GetAxis("Mouse X")*MouseSensitivity*Time.deltaTime;
    MouseY=Input.GetAxis("Mouse Y")*MouseSensitivity*Time.deltaTime;
    Yrotation-=MouseY;
    player.Rotate(Vector3.up * MouseX);
    transform.localRotation = Quaternion.Euler(Yrotation,0 , 0);

}

完成!

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

///<summary>
///
///</summary>

public class view : MonoBehaviour
{
    public Transform player;
    public float MouseX;
    public float MouseY;
    public float MouseSensitivity=600;
    public float Xrotation;
    public float Yrotation;

    private void Update()
    {
        MouseX=Input.GetAxis("Mouse X")*MouseSensitivity*Time.deltaTime;
        MouseY=Input.GetAxis("Mouse Y")*MouseSensitivity*Time.deltaTime;
        Yrotation-=MouseY;
        player.Rotate(Vector3.up * MouseX);
        transform.localRotation = Quaternion.Euler(Yrotation,0 , 0);

    }
}    

搭配上我们的move方法就可以达到第一人称移动的效果。

欢迎欢迎,让我们欢迎敌人攻击代码!

自动追踪

近战敌人首先要自动追踪靠近再进行接下来的操作
那么首先就要得到玩家的位置信息
那么就
public Transform player
走起!
然后判断是否看见player
if(player)
{
那么我们就执行追踪的操作
transform.position += (player.position-transform.position)Time.deltaTimespeed;
这个代码使得组件绑定的物体的位置数值向player位置的数值靠近,相减累加可以实现position数值的相近,后面乘上时间帧,再乘上速度来控制追踪的速度。
细节优化,看到player后会专向并朝着player的方向运动。
transform.forward = Vector3.Lerp (transform.forward, player.position - transform.position ,0.1f);
这里的transform.forward是物体的正面方向向量,而vector3.lerp是调用三维中的lerp方法使得有一个旋转正面朝向player的过程。
}

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐