Unity学习记录——物理系统与碰撞

2023-11-16

Unity学习记录——物理系统与碰撞

前言

​ 本文是中山大学软件工程学院2020级3d游戏编程与设计的作业6

编程题:简单打飞碟——物理引擎改进版

1.题目要求

改进飞碟(Hit UFO)游戏:

  • 游戏内容要求:
  1. adapter模式设计图修改飞碟游戏
  2. 使他同时支持物理运动与运动学(变换)运动

2.基本介绍

(1)Adapter模式1
  • 定义:将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作。
  • 优点:
    1. 客户端通过适配器可以透明地调用目标接口。
    2. 复用了现存的类,程序员不需要修改原有代码而重用现有的适配者类。
    3. 将目标类和适配者类解耦,解决了目标类和适配者类接口不一致的问题。
    4. 在很多业务场景中符合开闭原则。
  • 实现:可采取多重继承的方式实现,釆用将现有组件库中已经实现的组件引入适配器类中,该类同时实现当前系统的业务接口。
(2)unity物理引擎
  • 物理引擎

​ 物理引擎(Physici Engine)是一个软件组织,它将游戏世界对象赋予现实世界物理属性(重量、形状等)并抽象为刚体(Rigid)模型(也包括滑轮、绳索等),使得游戏物体在力的作用下,仿真现实世界的运动及物体之间的碰撞过程。记载牛顿经典力学模型基础之上,提供简单的API完成计算物体的运动、旋转和碰撞,实现近乎真实的运动与碰撞效果。

  • unity物理引擎2

    unity物理引擎主要包含角色控制器、刚体、力与力矩、碰撞体、触发器等组件

    • 角色控制器:主要用于第三人称玩家控制或者是不使用刚体物理组件的第一人称玩家控制。
    • 刚体(Rigidbody):为游戏对象赋予物理属性,使游戏对象在物理系统的控制下接受推力与扭力,从而实现现实世界中的运动效果。
    • 力与力矩:在物体之间的作用过程表现出来。其中,力作用于物体的重心使物体产生该方向上的加速度,力矩则使物体产生角加速度
    • 碰撞体(Collider):定义物体形状以便用于物理碰撞。
    • 触发器:用来触发事件,可用于检测碰撞发生

3.代码解读

在这里插入图片描述

​ 本次项目是上一次项目的改进版本,主要是使用了物理引擎实现了本次飞碟的运动,以及利用Adapter模式实现了物理运动部分的代码复用。代码部分实现较为简单,只需要进行部分增加与修改即可。

必要操作

​ 打开之前的预制件,添加刚体组件,同时锁住三轴的Rotation防止飞碟在飞行的时候发生各个方向上的旋转

在这里插入图片描述

代码改正

​ 在写这一次作业的时候发现了上一次作业存在一处bug。

​ 上一次作业由于使用函数计算运动变换,所以此处bug并未显示出来,在使用运动引擎模拟运动之后就可以发现此bug。

​ 具体为飞碟工厂之中,回收飞碟的时候忘记了给free的对象的Active置为false,使得在物理引擎之中,后续发出的飞碟保留了原来的部分数值,导致其下降速度极其快,修改之后此问题已经解决。

public void FreeDisk()
{
   	for (int i = 0; i < used.Count; i++)
	{
   		if (used[i].gameObject.transform.position.y <= -10f)
        {
         	used[i].gameObject.SetActive(false); // 此处修复了bug
            free.Add(used[i]);
            used.Remove(used[i]);
        }
    }
}

SSAction

​ 为了适配物理引擎添加了FixedUpdate()

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SSAction : ScriptableObject
{
    public bool lived = true;
    public bool deleted = false;
    public GameObject gameobject;
    public Transform transform;
    public ISSActionCallback callback;
    // 不允许代码中生成该类
    protected SSAction() { }
    public virtual void Start()
    {
        throw new System.NotImplementedException();
    }
    public virtual void Update()
    {
        throw new System.NotImplementedException();
    }
    // 添加部分
    public virtual void FixedUpdate() {
        throw new System.NotImplementedException();
    }
}
SSActionManager

​ 同样是为了适配物理引擎添加了FixUpdate()

protected void Update()
{
    foreach (SSAction ac in waitingAdd)
    {
        actions[ac.GetInstanceID()] = ac;
	}
	waitingAdd.Clear();
	foreach (KeyValuePair<int, SSAction> kv in actions)
	{
		SSAction ac = kv.Value;
		if (ac.deleted)
        {
            waitingDelete.Add(ac.GetInstanceID());
        }
        else if (ac.lived)
        {
            ac.Update();
            ac.FixedUpdate();	// 新增部分
        }
    }
    foreach (int key in waitingDelete)
    {
        SSAction ac = actions[key];
        actions.Remove(key);
        Object.Destroy(ac);
   	}
    waitingDelete.Clear();
}
FlyAction

​ 同样是新增了FixUpdate(),但是不会对之前代码起作用,仅仅是起到派生父类代码的作用

public class FlyAction : SSAction
{
    public float gravity = -5;                                 //向下的加速度
    private Vector3 start_vector;                              //初速度向量
    private Vector3 gravity_vector = Vector3.zero;             //加速度的向量,初始时为0
    private Vector3 current_angle = Vector3.zero;              //当前时间的欧拉角
    private float time;                                        //已经过去的时间

    private FlyAction() { }
    public static FlyAction GetSSAction(int lor, float angle, float power)
    {
        //初始化物体将要运动的初速度向量
        FlyAction action = CreateInstance<FlyAction>();
        if (lor == -1)
        {
            action.start_vector = Quaternion.Euler(new Vector3(0, 0, -angle)) * Vector3.left * power;
        }
        else
        {
            action.start_vector = Quaternion.Euler(new Vector3(0, 0, angle)) * Vector3.right * power;
        }
        return action;
    }

    public override void Update()
    {
        //计算物体的向下的速度,v=at
        time += Time.fixedDeltaTime;
        gravity_vector.y = gravity * time;

        //位移模拟
        transform.position += (start_vector + gravity_vector) * Time.fixedDeltaTime;
        current_angle.z = Mathf.Atan((start_vector.y + gravity_vector.y) / start_vector.x) * Mathf.Rad2Deg;
        transform.eulerAngles = current_angle;

        //如果物体y坐标小于-10,动作就做完了
        if (this.transform.position.y < -10)
        {
            this.deleted = true;
            this.callback.SSActionEvent(this);
        }
    }
    public override void FixedUpdate() { }	// 新增部分
    public override void Start() { }
}
PhysisFlyAction

​ 新增的类,通过物理引擎实现运动,与上面的FlyAction实现思路一致

public class PhysisFlyAction : SSAction {
    private Vector3 start_vector;                              
    public float power;
    private PhysisFlyAction() { }
    public static PhysisFlyAction GetSSAction(int loc, float power) {
        PhysisFlyAction action = CreateInstance<PhysisFlyAction>();
        if (loc == -1) {
            action.start_vector = Vector3.left * power;
        }
        else {
            action.start_vector = Vector3.right * power;
        }
        action.power = power;
        return action;
    }

    public override void Update() { }

    public override void FixedUpdate() {
        if (transform.position.y <= -10f) {
            gameobject.GetComponent<Rigidbody>().velocity = new Vector3(0, 0, 0);
            this.deleted = true;
            this.callback.SSActionEvent(this);
        }
    }

    public override void Start() {
        gameobject.GetComponent<Rigidbody>().AddForce(start_vector*3, ForceMode.Impulse);
    }
}
FlyActionManager

​ 飞碟的动作管理类,新增了物理运动的调用函数。

​ 思路与之前运动学变换的函数思路基本一致,由于物理引擎特性,仅需要传入参数仅需要力的数值,无需传入角度

public class FlyActionManager : SSActionManager
{
    public FlyAction fly;
    public PhysisFlyAction ph_fly;
    public FirstController scene_controller;
    protected void Start()
    {
        scene_controller = (FirstController)SSDirector.GetInstance().CurrentSceneController;
        scene_controller.action_manager = this;
    }
    public void DiskFly(GameObject disk, float angle, float power)
    {
        disk.GetComponent<Rigidbody>().isKinematic = true;
        int loc = disk.transform.position.x < 0 ? 1 : -1;
        fly = FlyAction.GetSSAction(loc, angle, power);
        this.RunAction(disk, fly, this);
    }
    // 新增部分,与上面的函数实现思路一致
    public void DiskFly(GameObject disk, float power)
    {
        disk.GetComponent<Rigidbody>().isKinematic = false;
        int loc = disk.transform.position.x < 0 ? 1 : -1;
        ph_fly = PhysisFlyAction.GetSSAction(loc, power);
        this.RunAction(disk, ph_fly, this);
    }
}
FirstController

​ 新增了SendDisk()中切换运动方式的开关

private void SendDisk(int type)
{
    GameObject disk = disk_factory.GetDisk(type);

    float ran_y = 0;
    float ran_x = Random.Range(-1f, 1f) < 0 ? -1 : 1;

    float power = 0;
    float angle = 0;
    if (type == 1)
    {
        ran_y = Random.Range(5f, 8f);
        power = Random.Range(5f, 8f);
        angle = Random.Range(15f, 20f);
    }
    else if (type == 2)
    {
        ran_y = Random.Range(3f, 6f);
        power = Random.Range(10f, 13f);
        angle = Random.Range(10f, 15f);
    }
    else
    {
        ran_y = Random.Range(1f, 3f);
        power = Random.Range(15f, 18f);
        angle = Random.Range(5f, 10f);
    }
    disk.transform.position = new Vector3(ran_x * 16f, ran_y, 0);
    // action_manager.DiskFly(disk, angle, power);
    action_manager.DiskFly(disk, power);
}

4.演示

​ gif图如下,此处演示为物理引擎的运动,与上次基本一致

在这里插入图片描述

代码位置

​ 代码以及文档均已经上传至hw6 · XiaoChen04_3/3D_Computer_Game_Programming - gitee

部分资料参考


  1. 适配器模式(Adapter模式)详解 - 腾讯云开发者社区-腾讯云 (tencent.com) ↩︎

  2. unity物理引擎介绍-CSDN博客 ↩︎

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Unity学习记录——物理系统与碰撞 的相关文章

  • android Button背景高度被拉伸问题--解决方案

    接入第三方SDK后 发现SDK提供的弹窗里 有两个按钮的高度呈被拉伸状态 而 第三方提供的demo内 这两个按钮均呈正常状态 对于第一次接触Android的菜鸟来说 这个问题颇为难解 第三方在尝试了几种方法之后 也宣告失败 这种奇葩问题 让
  • element项目中遇到的小问题总结

    在用element UI框架做项目时遇到的问题 现在总结记录下来 此文档持续更新中 1 日期选择器el date picker赋值后再次修改时页面不回显
  • JS逆向进阶案例

    前情回顾 有道翻译参数破解 百度翻译参数破解 之前 我们介绍了两种基础的JS逆向案例 今天 就继续来分享一个稍微复杂的JS逆向案例吧 目录 一 寻找加密源码 二 查漏补全JS代码 三 全部代码 爬取网址 某网站 本次爬取仅供学习 无任何商业
  • Mac上安装双系统

    写在前面 Mac用户在使用过程中 多少有的时候还会使用Windows 想装一个咋办 找某宝需要花钱150元 看这篇文章 十几分钟看明白 自己动手丰衣足食 所以本文将以图文教程教你如何安装双系统 开机随意选择 想用什么用什么 尽管我不是很喜欢

随机推荐

  • FFmpeg 采用源码安装 、环境配置、卸载

    https blog csdn net qq 36397240 article details 107745149 FFmpeg 采用源码安装 环境配置 卸载 验证了几种ffmpeg x264安装方法 这篇文章清晰简洁 特别是对环境配置介绍
  • AES(加密,填充,模式)新手小结

    本小结的密码学术语如填充 模式 等等 均以AES为例进行说明 举一反三 其他算法涉及的相同术语 大致也就理解是怎么回事了 吧 1 AES https nvlpubs nist gov nistpubs FIPS NIST FIPS 197
  • 【电子电路】五款单按键开关机电路图

    一 单按键开关机电路图 本例电路可实现通过按一次按键S1实现开机 再按一次S1实现关机的功能 整个电路的工作过程 电路中连接器P1是一个电源连接器 电源 从1 2脚输入 电源地从3 4脚输入 电路上电后 P MOS管Q1的G极和S极都是为高
  • Matatalab:编程只是大人的专利?这款儿童实物编程机器人了解一下

    转自 http www sohu com a 294483601 485557 创始人 https www tianyancha com brand b5813253827 CEO 苏荣星 MatataLab CEO 曾任职 mBot Ra
  • 基于入侵杂草算法的函数寻优算法

    文章目录 一 理论基础 1 算法简介 2 杂草特性 二 案例背景 1 问题描述 2 解题思路及步骤 1 初始化种群 2 繁殖 3 空间分布 4 竞争性排斥规则 3 算法流程 三 MATLAB程序实现 1 清空环境变量 2 问题设定 3 参数
  • 用matlab计算超调,怎样用matlab计算超调量、峰值时间

    2018 01 19 Intel Xeon E5 2697 v2的CPU的峰值计算能力和Intel Xeon E7 8870的CPU的峰值计算能力哪个强 必然Xeon E5 2697 v2运算能力强 首先 看核心数 Xeon E5 2697
  • 动态环境下基于强化学习的无人机任务路径规划

    路径规划主要是指无人机环境中存在威胁障碍物 然后 规划无人机从起点到目的地避开障碍物的最佳路线也是无人机实现自主飞行的主要因素之一 在无人机的任务分配中 主要目的是增强无人机的时间性能和环境适应性 对于无人机的路径规划水平 修改和改进算法可
  • STL--map的应用

    STL之map的应用 map定义及用途 map翻译为映射 是STL中的常用容器 其实 数组就是一种映射 比如 int a 100 就是定义了一个int到int的映射 而a 5 25 就是把5映射到25 数组总是将int类型映射到其它基本类型
  • oracle优化-----监控指标

    author skatetime 2010 03 24 昨天一个朋友问我 如何优化数据库 在想优化数据库前 首先要确认数据库是否需要优化 这就需要一些监控指标了 如 事务响应时间 数据库的逻辑读 数据库的物理读 物理写等 日常监控这些指标
  • GetProcAddress错误码127

    表现为明明loadLibrary GetProcAddress就是拿不到地址 原因是C语言的函数使用C 编译时需要加上extern C 转载于 https www cnblogs com Jacket K p 11574624 html
  • 十个经典免费软件和五★级网站!

    十个经典免费软件和五 级网站 软件非常实用 都是 免费版本 ghost 诺顿杀毒 等经典软件哪里皆可下载到 就没列出 推荐的网站则是very出色实用 lt 一 gt 软件 1 代理甭猎手 v1 0 179 KB 绿色 推荐指数 介绍 全称是
  • 【目标检测之数据集预处理】继承Dataset定义自己的数据集【附代码】

    在深度学习训练中 除了设计有效的卷积神经网络框架外 更重要的是数据的处理 在训练之前需要对训练数据进行预处理 比如在目标检测网络训练中 首先需要划分训练集和测试集 然后对标签 边界框等进行处理后才能送入网络进行训练 本文章以VOC数据集格式
  • 【设计模式学习】11种高频设计模式之建造者模式

    文章目录 相关介绍 代码介绍 常规用法 静态内部类方法 系列文章目录 参考资料 相关介绍 1 定义 将一个复杂对象的构建与它的表示分离 使得同样得构建过程可以创建不同得表示 2 作用 在用户不知道对象得建造过程和细节的情况下就可以直接创建复
  • MySQL server has gone away

    一 可能是mysql连接超时 原因 mysql长连接时 很长时间没有新的请求发起到达服务端 当这个时间超过配置的最大超时时间时 mysql就会强行关闭链接 此后再通过这个connection发起查询的时候 就会报错server has go
  • WiFiAssistant 无线承载网络设置助手的开发历程(一)

    今年6月中旬 我曾经基于MFC写过一个WiFiHelper的小程序 开启和关闭虚拟WiFi 并且能够支持定时关机 当然 真正使用虚拟WiFi还需要手动设置共享 并且 由于我的是台式机 所以并没有去升级WiFiHelper 估计是即将毕业的缘
  • 【English】十大词性之连词

    连词 文章目录 连词 前言 一 并列连词 1 1 表并列关系的并列连词 2表示选择关系的并列连词 3 表示转折关系的并列连词 4 表示因果关系的并列连词 二 从属连词 总结 前言 连词是一种虚词 在句中起连接作用 可以用来连接单词 短语 从
  • 16个车辆信息检测数据集收集汇总(简介及链接)

    16个车辆信息检测数据集收集汇总 简介及链接 目录 1 UA DETRAC 2 BDD100K 自动驾驶数据集 3 综合汽车 CompCars 数据集 4 Stanford Cars Dataset 5 OpenData V11 0 车辆重
  • Python—使用tkinter制作一个小时钟

    网上搬运的 自己又调试了一下 分享一下 coding utf 8 from tkinter import import math time def points for i in range 1 13 x 200 130 math sin
  • 矩阵的广义逆及python实践

    机器学习的代码中经常有求矩阵的广义逆 本文先从概念上总结了矩阵的广义逆 然后用python的numpy库实践 概念 矩阵的广义逆 Generalized inverse 也称为伪逆 pseudo inverse 假设一个矩阵 及另一矩阵 若
  • Unity学习记录——物理系统与碰撞

    Unity学习记录 物理系统与碰撞 前言 本文是中山大学软件工程学院2020级3d游戏编程与设计的作业6 编程题 简单打飞碟 物理引擎改进版 1 题目要求 改进飞碟 Hit UFO 游戏 游戏内容要求 按adapter模式设计图修改飞碟游戏