游戏性编程是指通过一系列游戏系统将游戏想法变成现实的过程。
本次的简例以NPC设计为主。
通常在进行脚本设计前,对NPC的属性进行基本的添加和设定,诸如动画系统、物理系统等等。
1.动画系统
添加Animator组件,绑定骨骼。
创建Animator Controller文件,将之添加到组件的Controller部分。
打开Controller,考虑动画组件的主体需要实现什么功能。
以此例的NPC为例,需要实现他的移动功能。
所以在Controller中添加新的混合树命名为Locomotion(移动)。
打开混合树,为其添加三种不同的运动状态(空闲、走路、奔跑),并绑定相应的动画文件。
调整三个状态之间的数值阶段,初始为0:0.5:1,调整为0:1:8。
(这里的意义在于更流畅的移动体验,休闲到走路快速的过渡,走路到奔跑则需要速度到达一定阈值后才能切换。)
备注:
取消勾选Autonate Thresholds后,可以更改数值。
parameter是用于脚本中调用setFloat方法中的参数名,从而在动画间不断的切换。
【2】Player脚本
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
public float moveSpeed;
private Vector3 moveInput;
private Vector3 moveVelocity;
private Rigidbody rd;
private Camera mainCamera;
private Animator animator;
// Start is called before the first frame update
void Start()
{
rd = GetComponent<Rigidbody>();
mainCamera = Camera.main;
animator = GetComponent<Animator>();
}
// Update is called once per frame
void Update()
{
float lh = Input.GetAxis("Horizontal");//输入的是左右,即X轴数据,对应着AD键位。
float lv = Input.GetAxis("Vertical");//输入的是上下,即Z轴的数据,对应着WS键位。
moveInput =new Vector3(lh,0f,lv);
//一个即时的向量,当无输入时是零向量。
//在Unity中,人物面朝的方向是蓝轴,即Z轴;沿着人物双手方向的横轴是红轴,即X轴;||而沿着人物垂心的是绿轴,即Y轴。
Vector3 cameraForword = mainCamera.transform.forward;
//主相机在沿着z轴的矢量位置和方向
cameraForword.y = 0;
Quaternion s = Quaternion.FromToRotation(Vector3.forward, cameraForword);
//这个四元素包含了(0,0,1)到cameraForword的旋转信息
Vector3 lookToward = s * moveInput;
//四元数和向量相乘表示这个向量按照这个四元数进行旋转之后得到的新的向量。
if (moveInput.sqrMagnitude>0)
{
Ray ray = new Ray(transform.position,lookToward);
//transform.position为该脚本对应的对象的位置
transform.LookAt(ray.GetPoint(1));
//transform.LookAt:旋转自身,使得当前对象的正z轴指向目标对象target所在的位置(使对象朝向目标点)
//ray.GetPoint(1):获取一个沿着向量方向距离X的点
}
moveVelocity = transform.forward*moveSpeed* moveInput.sqrMagnitude;
//transform.forward给的是人物坐标轴Z轴的矢量方向,即面朝的方向
//(自动对物体旋转值算出前进方向向量的变量,vector3.forward则不计算旋转值,所以vector3.forward固定为(0,0,1))
//moveVector3.sqrMagnitude返回是坐标轴输入矢量的平方长度的Float数值,用于控制速度,当无输入时,速度为0。
Aniamting();
}
void FixedUpdate()
{
rd.velocity = moveVelocity;
}
void Aniamting()
{
animator.SetFloat("Blend",rd.velocity.magnitude);
//调用animator.SetFloat方法,可以设置混合树中的参数数值,参数名字以自定义的参数名为准
}
}
【3】scriptableobject(Unity中用于处理序列化的结构)
一个允许你存储大量独立于脚本实例的共享数据的类。
目的是通过避免对值进行复制而减少内存的开销。
定义了一个继承自ScriptableObject的类,你可以使用CreateAssetMenu attribute用你的类创建自定义assets。
下面为实例:
Player加载的类
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CharacterStats : MonoBehaviour
{
//Stats:一个统计玩家数据的类
#region MyRegion
//#region 是 C# 预处理器指令。 #region 是一个分块预处理命令,它主要是用于编辑器代码的分块,在编译时会被自动删除。
//#region 在使用 Visual Studio 代码编辑器的大纲显示功能时指定可展开或折叠的代码块。有助于代码的整洁。
//
public static CharacterStats instance;
void Awake()
{
instance = this;//传递自身的地址
}
#endregion
public int MaxHealth = 100;
public int CurrentHealth { get; private set; }
//可以公共获取,但只能在该类中设置。
void Start()
{
CurrentHealth = MaxHealth;
}
public void takeDamage(int damage)
{
CurrentHealth -= damage;
if (CurrentHealth <= 0)
{
Dead();
}
}
public void TreatHealth(int treat)
{
print("treat:"+treat);
CurrentHealth += treat;
print(CurrentHealth);
if (CurrentHealth >= 100)
{
print("你恢复了健康");
}
}
public void Dead()
{
print("You Dead");
}
}
互动对象体加载的类:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ItemPickUp : Interacrable
{
//继承自Interacrable类(含有与环境互动的代码)
public Itemss item;
CharacterStats charStatss=new CharacterStats();
public override void Interact()//重写了父类的方法,并搭载的自己的内容
{base.Interact();
PickUp();
}
void PickUp()
{
item.Use();//这里使用的派生类的基类,但实际上传递的是根据Item基类自定义的assets。
Destroy(gameObject);
}
}
以下是相关的类,并未直接加载到对象上:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[CreateAssetMenu(fileName = " NewItems",menuName = "Inventory/Item")]
public class Itemss : ScriptableObject
{//创建assets的基类
new public string name = "Item";
public Sprite icon = null;
public virtual void Use()
{
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[CreateAssetMenu(fileName = "New Health Potion",menuName = "Inventory/Item/Health Potion")]
public class HealthPotion : Itemss
{
//继承自Item类的子类,是assets新的蓝本。
public int HealthModifity;
private CharacterStats charStats;
void Start()
{
charStats=CharacterStats.instance;
}
public override void Use()
{
base.Use();
ApplyEffect();
}
void ApplyEffect()
{
CharacterStats.instance.TreatHealth(HealthModifity);//传递了玩家参数类的方法。
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Interacrable : MonoBehaviour
{
//包含玩家与环境互动的类
public bool interacting = false;
private Renderer rend;
public Material[] materials;
void Start()
{
rend = GetComponent<Renderer>();
rend.enabled=true;//启用渲染器,使渲染的对象可见
rend.sharedMaterial = materials[0];
//Renderer.sharedMaterial:修改模型材质的颜色,或者是修改材质Shader的一些属性。
//(此方法使用的材料是共享的材料,内存中只有一份,不建议对材料做修改)
}
void Update()
{
if (interacting&&Input.GetKeyDown(KeyCode.Alpha1))
{Interact();
}
if (interacting)
{
rend.sharedMaterial = materials[1];
}
else
{
rend.sharedMaterial = materials[0];
}
}
public virtual void Interact()
{//虚方法,子类可加Override进行重写,虚方法本身有方法体。
Destroy(gameObject);
}
void OnTriggerEnter(Collider other)
{
if (other.gameObject.tag == "Player")
{
interacting = true;
}
}
void OnTriggerExit(Collider other)
{
if (other.gameObject.tag == "Player")
{
interacting = false;
}
}
}