[U3D Learning Note] Unity C# Survival Guide (1) -- Quick Tips and Assets

Change GameObject Position

KEY: transform.positon

transform.position = new Vector3(1,2,3);
//or
public Vector3 newposi;
transform.position = newposi;

脚本已附加在某个GameObject上时 transform.position就是该物体的坐标

User Input

获取键盘的输入进行操作 因为是在游戏过程中进行操作 所以要放在Update()函数里

void Update()
{
    //if space key press down
    // print a message once
    if(Input.GetKeyDown(KeyCode.Space)){
        Debug.Log("press down space");
    }
    // if held on key A
    // print message every frame
    if(Input.GetKey(KeyCode.A)){
        Debug.Log("held on A");
    }
    // if key lift up
    // print message once
    if(Input.GetKeyUp(KeyCode.B)){
        Debug.Log("lift up B");
    }
}

Simple Movement

x轴或y上移动
KEY:

  • transform.Translate(): Moves the transform in the direction and
    distance of translation.
  • Time.deltaTime: The completion time in seconds since the last frame (Read Only). Use Time.deltaTime to move a GameObject in the y direction, at n units per second. Multiply n by Time.deltaTime and add to the y component.
  • Vector3.right : Shorthand for writing Vector3(1, 0, 0).
    Vector3.left: Shorthand for writing Vector3(-1, 0, 0).
    Vector3.up: Shorthand for writing Vector3(0, 1, 0).
    Vector3.down: Shorthand for writing Vector3(0, -1, 0).
  • [SerializeField]: 强制序列化 使成员变量出现在inspector中 public变量默认是序列化的 通常用于private变量
  • Input.GetAxis(): Returns the value of the virtual axis identified by axisName. 由键盘控制移动 获取方向上坐标 (查看: Edit -> Project Settings -> Input Manager)
    • 对于键盘和操纵杆: 以"Horizontal"为例 水平方向上(x轴) 往负方向由左键控制正方向由右键控制 The value will be in the range -1…1 for keyboard and joystick input devices.The meaning of this value depends on the type of input control, for example with a joystick’s horizontal axis a value of 1 means the stick is pushed all the way to the right and a value of -1 means it’s all the way to the left; a value of 0 means the joystick is in its neutral position.(场景:角色控制
    • 对于鼠标: 以"Mouse X"为例 光标在水平方向上移动时物体跟随移动 If the axis is mapped to the mouse, the value is different and will not be in the range of -1…1. Instead it’ll be the current mouse delta multiplied by the axis sensitivity. Typically a positive value means the mouse is moving right/down and a negative value means the mouse is moving left/up. (场景:附在Main Camera上视觉画面移动(农药挂了以后巡视全地图
      [U3D Learning Note] Unity C# Survival Guide (1) -- Quick Tips and Assets_第1张图片
	[SerializeField] private float _speed = 0.5f; 
    void Update()
    {
        transform.Translate(Vector3.right); 
        //automatically move obj to right, move 1unit per frame
        transform.Translate(Vector3.right*Time.deltaTime); 
        //automatically move obj to right, move 1unit per second, new Veector3(1,0,0)*0.5f*realtime
        transform.Translate(Vector3.right*Time.deltaTime*_speed);
        //automatically move obj to right, move 1*_speed unit per second
        float horizontalInput = Input.GetAxis("Horizontal");
        transform.Translate(new Vector3(horizontalInput, 0, 0)*Time.deltaTime*_speed);
        //use keyboard to control
        float h = 5*Input.GetAxis("Mouse X");
        transform.Translate(new Vector3(h, 0, 0)*Time.deltaTime*_speed);
        //use mouse to control
    }

Update loop run 60 frames per second --> move 60 unit per second

Collectible GameObject

KEY: Box Collider
- Is Trigger: if checked, we can pass through the object; else, it’s a solid object.
- Ridgebody: 刚体。向对象添加刚体组件将使其运动在Unity物理引擎的控制下。即使不添加任何代码,如果还存在正确的Collider组件,则刚体对象将在重力作用下被下拉,并且会对与传入对象的碰撞做出反应。是让物体更自然运动的组件
- onTriggerEnter(): get info about the object collide with us when a collision occurs.(if we use solid object, use onTriggerCollision() (此处视频讲错了 应该是OnCollisionEnter() 另外还有区别是传递的参数是Collision类而不是Collider 详情见文档
注意:两个GameObjects必须包含一个Collider组件。必须启用Collider.isTrigger并包含一个刚体。如果两个GameObjects都启用了Collider.isTrigger,则不会发生碰撞。当两个GameObjects都没有刚体组件时,情况相同。

	private void OnTriggerEnter(Collider other) {
        // Collider other: whatever obj hit
        if(other.tag == "Player"){
            Destroy(this.gameObject); 
            // when the obj with script hit by the object with tag "Player",
            // destory the obj with script
        }
    }

场景:smash hit, fps, 贪吃蛇

[补充] cf.onTriggerEnter() & OnCollisionEnter() 对比实验(x
共同点:相撞的两个物体都需要Collider(Box或者Mesh什么的都可以
onTriggerEnter() : (A向B移动

  • AB启用isTrigger并不包含刚体 撞击未发生
  • AB启用isTrigger, A包含一个刚体 撞击发生了
  • AB启用isTrigger ,B包含一个刚体 撞击发生了
  • AB启用isTrigger并包含一个刚体 撞击发生了
  • AB不启用isTrigger并不包含刚体, 撞击未发生
  • AB不启用isTrigger A包含一个刚体, 撞击未发生, A顶住B不移动
  • AB不启用isTrigger B包含一个刚体,撞击未发生
  • AB不启用isTrigger并包含一个刚体, A会推着B走,撞击未发生 (推箱子
  • A不启用任何 B启用isTrigger并包含一个刚体 撞击发生
  • A不启用任何 B启用isTrigger并不包含刚体 撞击未发生
  • A包含一个刚体 B启用isTrigger并包含一个刚体 撞击发生
  • A包含一个刚体 B启用isTrigger并不包含刚体 撞击发生
    (懒得列其他状况了 总结一下就是撞击的两者必须包含一个isTrigger和一个刚体才会产生撞击 除了注明特殊情况的 其余撞击未发生A都是穿过B的

OnCollisionEnter(): (A向B移动

  • AB都不启用isTrigger且都有刚体 撞击发生
  • AB都不启用isTrigger B包含一个刚体 撞击未发生
  • AB都不启用isTrigger A包含一个刚体 撞击发生
  • AB都不启用isTrigger并包含一个刚体 撞击发生
    (总结:AB都不启用isTrigger且撞击者(A)包含一个刚体 撞击发生

Pause System

(这节用到GameDevHQ一个自带动画的模型…emmmmm因为付费所以就没用 但是也不妨碍学习 给随便一个cube附加自动移动的脚本就可以检验了
KEY: Pause the Game 场景:smash hit关卡内加减速

  • Time.timeScale: The scale at which time passes. This can be used for slow motion effects. When timeScale is 1.0 time passes as fast as realtime. When timeScale is 0.5 time passes 2x slower than realtime. When timeScale is set to zero the game is basically paused if all your functions are frame rate independent.
	 // on main camera
	 void Update()
	{
	    if(Input.GetKeyDown(KeyCode.Space)){
	        Time.timeScale = 0;
	        Debug.Log("press on space and stop the sence");
	    }
	    if(Input.GetKeyDown(KeyCode.R)){
	        Time.timeScale = 1;
	        Debug.Log("press on R and continue the sence");
	    }
	}

一个疑问 timeScale的改变不单单只是附着的相机视角下画面减速(类似倍速看)而是整个场景真实减速???
cube移动脚本将Time.deltaTime*_speed序列化显示 并且暂停脚本暂停时改为Time.timeScale = 0.25f可以看到结果如下 说明是整个场景真实减速
[U3D Learning Note] Unity C# Survival Guide (1) -- Quick Tips and Assets_第2张图片
[U3D Learning Note] Unity C# Survival Guide (1) -- Quick Tips and Assets_第3张图片
然后看了眼官方文档有下面这句话:

Except for realtimeSinceStartup and fixedDeltaTime, timeScale affects all the time and delta time measuring variables of the Time class.

Time.deltaTime改成 Time.fixedDeltaTime 果然不受影响 但是返回的数值都是Time.fixedDeltaTime 的默认值0.22 也就是说_speed的附加影响没有成功 所以要注意FixedUpdate函数或 Update函数中,Time.fixedDeltaTime 将自动返回正确的增量时间(这就是为什么建议使用Time.deltaTime
如果降低timeScale,建议也将Time.fixedDeltaTime降低相同的量。设置为零时,不会调用 具体还是看官方链接的代码吧

Post-Processing Effects

Window ->Package Manager -> Post Processing

  • Post Processing: allows u to add filters in Main Camera

For Main Camera, in Inspector, add component Post Processing Layer and we can notice that in option “layers” there shows “Nothing”. Edit Layers, in user layer, add a layer call “Post Processing”. Then edit the option “layers” for Main Camera as “Post Processing” layer.

  • Post Processing Layer: decide which layer is going to accept a Post Processing Volume.

Create a GameObject called “Post Process Volume”, which will store all Post Processing Effects we want to apply to the scene. Add a component Post Processing Volume. Choose the layer “Post Processing Layer”. Option Is Gobal, if checked, this post processing effects will be applied to entire scene. Option Profile , click New to create effects. We can adjust the Intensity (强度), Threshold(阈值), Diffusion(扩散) and other attributes. 像还有其他的比如配合Color Grading食用可以让场景光效更酷炫 这边就不多提 用于场景处理

Destructible Crate

KEY: Smoke-Mirror Effect: When a solid object explodes, it breaks into a million pieces. (啊啊啊啊是我最喜欢的环节!!! 破坏破碎效果!!!!玩smash hit的时候就各种惊叹怎么做到的玻璃破碎得那么真实好看
原理:Physics and colliders 我们需要一个完整的solid object 还有一组fractured part(就是好多个碎块但是可以完整拼凑成一个一毛一样的solid object), 在solid object被执行Destory的同时, 这些fractured part形成爆炸飞出效果。对于fractured part,需要添加Rigidbody 组件, 并赋予重力选项(use gravity),再添加 Mesh Collider 使触面是几何映射(box collider是一个方体 而mesh collider是不规则几何图形即物体的样子,记得点选Convex。注意 这边fractured part是以prefabs的形式设置的。 然后看看代码

public class Crate : MonoBehaviour
{
    // Start is called before the first frame update
    public GameObject fracturedCrate;
    public GameObject explosionEffect;
    void Start()
    {
    }
    // Update is called once per frame
    void Update()
    {
        if(Input.GetKeyDown(KeyCode.Space)){
        	// before we destory the solid obj, we first instantiate the prefabs 
            // which is a series of fractured part as children in the same position and same rotation
            // and also the explosion effect
            Instantiate(explosionEffect, transform.position, Quaternion.identity);
            //Instantiate(fracturedCrate, transform.position, Quaternion.identity);
            // to let the power of destory more greater 
            GameObject fractureObj = Instantiate(fracturedCrate, transform.position, Quaternion.identity) as GameObject;
            Rigidbody[] allRigidbodies = fractureObj.GetComponentsInChildren<Rigidbody>();
            // grab rigidbody from all of the children elements 
            if(allRigidbodies.Length > 0){
                // if we grab rigidbody, write a loop, 
                // for each rigidbody we give it a invidual force
                foreach(var body in allRigidbodies){
                    body.AddExplosionForce(500, transform.position, 1);
                    // 500 newtons of force
                    // 1 explosionRadius: scale of affect other objects
                }
            }
            Destroy(this.gameObject);
        }
    }
}

emmmm但是这边讲的是爆炸场景效果 smash hit的话是对撞破碎 猜想smash hit也是一个完整的solid obj 和 一组破碎的prefabs 当撞击产生时根据弹珠接触点进行爆炸?

综合实践?

大致模拟了一下
创建一个蓝色的方块就是我们的Player, 因为要撞击嘛 就给他一个Box Collider, 并且给他一个简单的移动脚本(参见前面 Simple Movement(一句话的事

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

public class playerMovement : MonoBehaviour
{   
    [SerializeField] private float _speed = 0.5f;
    // Start is called before the first frame update
    void Start()
    {}
    
    // Update is called once per frame
    void Update()
    {   
        transform.Translate(Vector3.right*Time.deltaTime*_speed);
    }
}

然后是设置要被撞击的元大方块Solid Cube, 因为要能够产生撞击, 我们也给他一个Box Collider和RigidBody(参考前面Collectible GameObject 但因为我们想要让它安安稳稳的呆在上面 所以不选择use gravity, Is trigger记得打勾不然无法撞击
同时我们设置一组方块组成和SolidCube一样大小的prefab, 也就是后面生成的BigCube(取名无能的我orz 对于每个方块给他们一个Mesh Collider 其实这边给Box Collider也一样 但是要考虑到在以后会遇到里面的碎片是不规则形状的 就还是用Mesh Collider(养成习惯(x 记住要点选convex 是凸的才能产生交集 然后给每个方块RigidBody 在这边就得赋予重力了 因为想要撞击得飞起来
给Solid Cube一个受到撞击爆炸的脚本 当SolidCube被player击中 生成prefabs给prefabs每个部分增加爆炸威力 同时SolidCube消失(参考前面Destructible Crate

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

public class crash : MonoBehaviour
{
    // Start is called before the first frame update
    public GameObject fracturedCrate;
    private void OnTriggerEnter(Collider other) {
        if(other.tag == "Player"){
            Debug.Log("hit");
            GameObject fractureObj = Instantiate(fracturedCrate, transform.position, Quaternion.identity) as GameObject;
            Rigidbody[] allRigidbodies = fractureObj.GetComponentsInChildren<Rigidbody>();
            if(allRigidbodies.Length > 0){
                foreach(var body in allRigidbodies){
                    body.AddExplosionForce(500, transform.position, 1);
                    // 500 newtons of force
                    // 1 explosionRadius: scale of affect other objects
                }
            }
            Destroy(this.gameObject);
        }
    }
}

验收成果!(没有弹珠没有玻璃凑合着看(x

但是问题来了 如果把蓝色方块往上方移动 它爆炸的轨迹还是一样的 问题出在body.AddExplosionForce(500, transform.position, 1);这句, 爆炸中心是这个物体的坐标 我们应该改成 爆炸中心为撞击的点body.AddExplosionForce(500, other.transform.position, 1); 然后就发现了之前没注意的bug… 为啥实例化物体的坐标和之前不一样啊窒息了 而且在做prefabs的时候吧 就发现scale相同大小是不一样的…就很窒息… 这个问题列入待解决

你可能感兴趣的:(#,Unity,C#,Survival,Guide,Unity,3D,unity,unity3d)