HOME
BLOG
Unity 3D部分
9月 12 2022

3D 坐标系

  • 2D坐标

    • 只考虑 XY 坐标
  • 屏幕坐标

    • 左下(0,0)类似一个象限
  • 3D坐标(世界坐标)

    • XYZ 坐标

3D物理系统:刚体

类似2D刚体


3D物理系统:碰撞体

类似2D碰撞体

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

public class L6_3Demo : MonoBehaviour
{
    // 碰撞进入
    private void OnCollisionEnter(Collision collision)
    {
        Debug.Log(collision.gameObject.name);
    }
    // 碰撞中
    private void OnCollisionStay(Collision collision)
    {
        Debug.Log(collision.gameObject.name);
    }
    // 碰撞退出
    private void OnCollisionExit(Collision collision)
    {
        Debug.Log(collision.gameObject.name);
    }
}

3D物理系统:触发

类似2D触发

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

public class L6_4Demo : MonoBehaviour
{
    // Enter
    private void OnTriggerEnter(Collider other)
    {
        print("Enter: " + other.gameObject.name);
    }
    // Stay
    private void OnTriggerStay(Collider other)
    {
        print("Stay: " + other.gameObject.name);
    }
    // Exit
    private void OnTriggerExit(Collider other)
    {
        print("Exit: " + other.gameObject.name);
    }
}

3D物理系统:物理材质

类似2D物理材质


物理射线

用于判断射击是否命中、点击地面建造建筑物等功能

  • Ray:射线类

  • Physics.Raycast:计算射线碰撞

  • RaycastHit:射线检测信息类

  • Debug.DrawLine:绘制线条(玩家看不到,仅编辑器测试)

演示:

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

public class L6_6Demo : MonoBehaviour
{
    void Update()
    {
        // 射线, 向上, 从 0 0 0 到 0 1 0
        //Ray ray = new Ray(Vector3.zero,new Vector3(0,1,0));

        // 类似射击游戏的实现
        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);

        if (Physics.Raycast(ray,out RaycastHit hitinfo,1000))
        {
            // hitinfo: 射线碰撞的相关信息
            Debug.Log(string.Format("Rayline hit: {0}, Where: {1}", hitinfo.collider.gameObject.name,hitinfo.point));

            Debug.DrawLine(ray.origin, hitinfo.point,Color.red);
        }
    }
}

刚体移动

Rigidbody.MovePosition(Vector3 target) :target 是一个具体要到达的位置

演示:

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

public class L6_7Demo : MonoBehaviour
{
    private Rigidbody rb;
    void Start()
    {
        rb = GetComponent<Rigidbody>();
    }

    // 帧率更新
    void Update()
    {

    }

    //固定更新
    void FixedUpdate()
    {
        Move();
    }

    private void Move()
    {
        // 获取输入
        float h = Input.GetAxis("Horizontal");
        float v = Input.GetAxis("Vertical");

        Vector3 offset = new Vector3(h, 0, v) * Time.deltaTime * 1.5f;
        rb.MovePosition(transform.position + offset);
    }
}

案例:方块保卫战

| 场景搭建

  • 介绍

    • 敌人向玩家走来

    • 玩家点击屏幕可以发射子弹

    • 子弹击中敌人两次则敌人死亡销毁

    • 敌人如果到达指定位置,则玩家失败,进行重新游玩

  • 分析

    • 搭建基本场景和敌人外观

    • 实现敌人自动移动

    • 实现玩家发射子弹逻辑

      • UI 显示当前得分
    • 游戏结果,需要 UI 弹窗提醒结果

      • 击毙全部敌人胜利

      • 敌人进入指定位置触发失败

  • 搭建

| 核心逻辑

  • 实现敌人自动移动

  • 实现玩家攻击敌人

  • 敌人死亡逻辑

  • 游戏胜利逻辑

  • 游戏失败逻辑

| UI逻辑

  • UI 显示当前得分

  • 游戏结果面板(胜利与失败)

代码部分:

L6_8_Enemy

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

public class L6_8_Enemy : MonoBehaviour
{
    private Rigidbody rb;
    private float speed = 2;
    private int hp = 100;

    void Start()
    {
        rb = GetComponent<Rigidbody>();
    }

    private void FixedUpdate()
    {
        Move();
    }

    private void Move()
    {
        Vector3 offset = transform.forward * Time.fixedDeltaTime * speed;
        rb.MovePosition(transform.position + offset);
    }

    public void Hurt(int demage)
    {
        hp -= demage;
        if (hp <= 0)
        {
            Dead();
        }
    }
    private void Dead()
    {
        // check 还有没有同类,如果没有,则游戏胜利
        L6_8_Player.Instance.EnemyDead(this);

        // die
        Destroy(gameObject);
    }
}

L6_8_Player

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

public class L6_8_Player : MonoBehaviour
{
    public static L6_8_Player Instance;

    private int AttackValue = 50;
    public List<L6_8_Enemy> enemies;

    private int score = 0;
    private bool isOver = false;
    private void Awake()
    {
        Instance = this;

    }

    void Update()
    {
        Shoot();
    }

    private void Shoot()
    {
        if (Input.GetMouseButtonDown(0))
        {
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);

            if (Physics.Raycast(ray, out RaycastHit hitinfo, 1000))
            {
                Debug.DrawLine(ray.origin, hitinfo.point, Color.red);

                // 如果我射击到的是敌人,则附加伤害
                if (hitinfo.collider.gameObject.tag == "Enemy")
                {
                    // 附加伤害
                    L6_8_Enemy enemy = hitinfo.collider.gameObject.GetComponent<L6_8_Enemy>();
                    enemy.Hurt(AttackValue);
                }
            }
        }
    }

    public void EnemyDead(L6_8_Enemy enemy)
    {
        score += 1;
        L6_8_UIManager.Instance.UpdateScoreNumText(score);

        enemies.Remove(enemy);
        if(enemies.Count == 0)
        {
            // victory
            Win();
        }
    }

    private void Win()
    {
        L6_8_UIManager.Instance.GameResult(true);
    }

    private void Over()
    {
        isOver = true;
        //Time.timeScale = 0;
        L6_8_UIManager.Instance.GameResult(false);
    }

    private void OnTriggerEnter(Collider other)
    {
        if (other.gameObject.tag == "Enemy" && isOver == false)
        {
            Over();
        }
    }
}

L6_8_UIManager

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

public class L6_8_UIManager : MonoBehaviour
{
    public static L6_8_UIManager Instance;
    public Text ScoreNumText;

    public GameObject resultPanel;
    public Text resultText;

    private void Awake()
    {
        Instance = this;
    }

    public void UpdateScoreNumText(int num)
    {
        ScoreNumText.text = num.ToString();
    }

    public void GameResult(bool isWin)
    {
        resultPanel.SetActive(true);
        if (isWin)
        {
            resultText.text = "Victory";
        }
        else
        {
            resultText.text = "Defeat";
        }
    }
}


👾森木清树👾

Unity Study