Unity3D的物理引擎做得很不错,让物体的运动更加贴近现实了。没有人喜欢高深的数学,去计算复杂的运动曲线和力学。使用物理引擎,而你仅需要高中的物理(牛顿!三定律, F = m * a)。

物理引擎( Physics Engine)
  1. 物理引擎是一种软件组件,用于仿真物理世界运动。 这种仿真包括刚体力学、流体力学以及碰撞检测。
  2. 物理引擎通过为刚性物体赋予真实的物理属性,在外部力的作用下,计算运动、旋转和碰撞。
       如何利用物理引擎呢?Rigidbody(刚体)组件可使游戏对象在物理系统的控制下来运动 。这次我们利用物理引擎来改进飞碟游戏。请记住一点修改物理引擎相关组件属性,必须使用Fixed-Update。
       首先为了提高代码的利用率和开发速度,我们先想一想我们可以复用代码。我们看看下上次飞碟游戏留下来的资源吧。
SSDirector,SceneController,UserGUI,Factory,Singleton,Recorder,SSAction,SSActionManager 和DiskData2这些脚本不用改直接实现共用即可。
SSDirector.cs
public interface ISceneController//导演场记通信接口
{void LoadResources();//void Pause ();//void Resume ();
}public class SSDirector : System.Object
{private static SSDirector _instance;public ISceneController currentScenceController { get; set; }public bool running { get; set; }public static SSDirector getInstance(){if (_instance == null){_instance = new SSDirector();}return _instance;}public int getFPS(){return Application.targetFrameRate;}public void setFPS(int fps){Application.targetFrameRate = fps;}
}
SceneController.cs
public class SceneController : MonoBehaviour, ISceneController, IUserAction
{public IActionManager actionManager { get; set; }//动作管理器public DiskFactory factory { get; set; }//游戏工厂public Recorder scoreRecorder { get; set; }//游戏记分员public int round = 0;//轮数public Text RoundText;//轮数文本public Text GameText;//倒计时文本public Text FinalText;//结束文本public int game = 0;//记录游戏进行情况public int num = 0;//每轮的飞碟数量GameObject explosion;//爆炸效果public int CoolTimes = 3; //准备时间// Use this for initializationvoid Awake()//创建导演实例并载入资源{SSDirector director = SSDirector.getInstance();director.setFPS(60);director.currentScenceController = this;director.currentScenceController.LoadResources();}void Start(){round = 1;//开始游戏设置为第一轮}// Update is called once per framevoid Update(){RoundText.text = "Round:" + round.ToString();//将轮数信息打印出来if(game == 2){GameOver();//判断游戏结束}}public IEnumerator waitForOneSecond()  //协程技术实现倒计时3秒{while (CoolTimes >= 0 && game == 3){GameText.text = CoolTimes.ToString();  //将倒计时剩余时间打印在屏幕上print("还剩" + CoolTimes);yield return new WaitForSeconds(1);//等待一秒CoolTimes--;}GameText.text = "";game = 1;  //标记游戏开始}public void GameOver(){FinalText.text = "Game Over!!!";//游戏结束显示}public void StartGame()  //实现IUserAction接口开始游戏{num = 0;if (game == 0){game = 3;  //进入倒计时模式StartCoroutine(waitForOneSecond());  //启动协程}}public void ReStart()  //实现IUserAction接口重启游戏{SceneManager.LoadScene("task1");game = 0;}public void ShowDetail()  //实现IUserAction接口显示游戏介绍{GUI.Label(new Rect(220, 50, 350, 250), "Use your mouse click disk, you will get 1 point for green Disk,2 for yellow Disk,3 for red Disk,you should get 20 points to pass round1,40 to pass round2,60 to pass round3.There are three round.Good Luck!!!");}public void hit()  //实现IUserAction接口判断击中事件{if (game == 1){Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);RaycastHit hit;if (Physics.Raycast(ray, out hit)){if (hit.transform.tag == "Disk"){explosion.transform.position = hit.collider.gameObject.transform.position;explosion.GetComponent<Renderer>().material = hit.collider.gameObject.GetComponent<Renderer>().material;explosion.GetComponent<ParticleSystem>().Play();hit.collider.gameObject.SetActive(false);print("Hit!!!");hit.collider.gameObject.GetComponent<DiskData2>().hit = true;scoreRecorder.add();}}}}public void LoadResources()  //载入资源{explosion = Instantiate(Resources.Load("prefabs/Explosion"), new Vector3(-40, 0, 0), Quaternion.identity) as GameObject;Instantiate(Resources.Load("prefabs/Light"));}
}

UserGUI.cs
public interface IUserAction
{void StartGame();void ShowDetail();void ReStart();void hit();
}public class UserGUI : MonoBehaviour
{private IUserAction action;// Use this for initializationvoid Start(){action = SSDirector.getInstance().currentScenceController as IUserAction;}void OnGUI(){GUIStyle fontstyle1 = new GUIStyle();fontstyle1.fontSize = 50;fontstyle1.normal.textColor = new Color(255, 255, 255);if (GUI.RepeatButton(new Rect(0, 0, 120, 40), "Shooting Disk")){action.ShowDetail();}if (GUI.Button(new Rect(0, 60, 120, 40), "STARTGAME")){action.StartGame();}if (GUI.Button(new Rect(0, 120, 120, 40), "RESTART")){action.ReStart();}if (Input.GetMouseButtonDown(0)){action.hit();}}// Update is called once per framevoid Update(){//}
}

Factory.cs
public class DiskFactory : MonoBehaviour
{private static DiskFactory _instance;public SceneController sceneControler { get; set; }//场记public Recorder scoreRecorder;//计分员GameObject diskPrefab;//飞碟模板DiskData2 diskData;//飞碟数据public List<GameObject> used;public List<GameObject> free;// Use this for initializationprivate void Awake(){if (_instance == null){_instance = Singleton<DiskFactory>.Instance;//单实例化_instance.used = new List<GameObject>();_instance.free = new List<GameObject>();diskPrefab = Instantiate(Resources.Load<GameObject>("Prefabs/disk"), new Vector3(40,0,0), Quaternion.identity);}}public void Start(){sceneControler = (SceneController)SSDirector.getInstance().currentScenceController;             //引入场记sceneControler.factory = this;//设置场记的工厂scoreRecorder = sceneControler.scoreRecorder;//引入记分员}public GameObject getDisk(int round)  //取得飞碟{if (sceneControler.num == 31 && scoreRecorder.Score >= round * 20)                              //每轮31个飞碟,看分数是否达标决定进入下一轮或者结束游戏{sceneControler.round++;sceneControler.num = 0;} else if(sceneControler.num == 31 && scoreRecorder.Score < round * 20){sceneControler.game = 2;//游戏结束}GameObject newDisk;if (free.Count == 0){newDisk = GameObject.Instantiate(diskPrefab) as GameObject;}else{newDisk = free[0];free.Remove(free[0]);}diskData = newDisk.GetComponent<DiskData2>();                                                   //取出飞碟数据实现复用,提高效率switch (round)  //根据轮数选择飞碟{case 1:diskData.size = 0.8f;diskData.color = Color.green;newDisk.transform.localScale = new Vector3(diskData.size, diskData.size, diskData.size);newDisk.GetComponent<Renderer>().material.color = diskData.color;break;case 2:diskData.size = 0.7f;diskData.color = Color.yellow;newDisk.transform.localScale = new Vector3(diskData.size, diskData.size, diskData.size);newDisk.GetComponent<Renderer>().material.color = diskData.color;break;case 3:diskData.size = 0.6f;diskData.color = Color.red;newDisk.transform.localScale = new Vector3(diskData.size, diskData.size, diskData.size);newDisk.GetComponent<Renderer>().material.color = diskData.color;break;}used.Add(newDisk);return newDisk;}public void freeDisk(GameObject disk1)  //释放飞碟{for (int i = 0; i < used.Count; i++){if (used[i] == disk1){used.Remove(disk1);disk1.SetActive(true);free.Add(disk1);}}return;}
}

Sington.cs
public class Singleton<T> : MonoBehaviour where T : MonoBehaviour{//场景单实例protected static T instance;public static T Instance{get{if(instance == null){instance = (T)FindObjectOfType(typeof(T));if(instance == null){Debug.LogError("An instance of " + typeof(T) + " is needed in the scene, but there is none.");}}return instance;}}
}

Recorder.cs
public class Recorder : MonoBehaviour {public Text ScoreText;//分数文本public float Score = 0;//分数public SceneController sceneControler { get; set; }//引入场记// Use this for initializationvoid Start () {sceneControler = (SceneController)SSDirector.getInstance().currentScenceController;sceneControler.scoreRecorder = this;//设置记分员}public void add() //加分{Score += sceneControler.round;}public void miss() //扣分{Score -= sceneControler.round;}// Update is called once per framevoid Update () {ScoreText.text = "Score:" + Score.ToString();//更新分数}
}

SSAction.cs
public enum SSActionEventType : int { Started, Competeted }public interface ISSActionCallback //动作管理器与动作通信接口
{void SSActionEvent(SSAction source, SSActionEventType events = SSActionEventType.Competeted,int intParam = 0, string strParam = null, Object objectParam = null);
}
//动作基类
public class SSAction : ScriptableObject
{public bool enable = true;public bool destroy = false;public GameObject gameobject { get; set; }public Transform transform { get; set; }public ISSActionCallback callback { get; set; }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.cs
public class SSActionManager : MonoBehaviour  //动作管理器基类
{private Dictionary<int, SSAction> actions = new Dictionary<int, SSAction>();private List<SSAction> waitingAdd = new List<SSAction>();private List<int> waitingDelete = new List<int>();// Use this for initializationvoid Start(){}// Update is called once per frameprotected 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.destroy){waitingDelete.Add(ac.GetInstanceID());}else if (ac.enable){ac.Update();ac.FixedUpdate();}}foreach (int key in waitingDelete){SSAction ac = actions[key]; actions.Remove(key); DestroyObject(ac);}waitingDelete.Clear();}public void RunAction(GameObject gameobject, SSAction action, ISSActionCallback manager){action.gameobject = gameobject;action.transform = gameobject.transform;action.callback = manager;waitingAdd.Add(action);action.Start();}
}

DiskData2.cs
public class DiskData2 : MonoBehaviour {public float size;public Color color;public float speed;public bool hit = false;public SSAction action;//记录动作
}

我们真正需要设计的只是动作和动作管理器的派生类,再看看我们的需求
首先我们编写IActionManager.cs
public interface IActionManager
{void playDisk();
}
然后编写下Emit.cs
public class Emit : SSAction
{bool enableEmit = true;//使力作用一次,不想产生变加速运动Vector3 force;//力float startX;//起始位置public SceneController sceneControler = (SceneController)SSDirector.getInstance().currentScenceController;//引入场记// Use this for initializationpublic override void Start () {startX = 6 - Random.value * 12;this.transform.position = new Vector3(startX, 0, 0);force = new Vector3(6 * Random.Range(-1, 1), 6 * Random.Range(0.5f, 2), 13 + 2 * sceneControler.round);//根据轮数设置力的大小}public static Emit GetSSAction(){Emit action = ScriptableObject.CreateInstance<Emit>();return action;}public override void Update(){//}public void Destory()//回调函数{this.destroy = true;this.callback.SSActionEvent(this);}// Update is called once per framepublic override void FixedUpdate () {if(!this.destroy){if(enableEmit){gameobject.GetComponent<Rigidbody>().velocity = Vector3.zero;gameobject.GetComponent<Rigidbody>().AddForce(force, ForceMode.Impulse);enableEmit = false;}}}
}
最后编写Physics.cs
public class physicsManager : SSActionManager, ISSActionCallback, IActionManager
{public SceneController sceneController;//场记public DiskFactory diskFactory;//游戏工厂public Recorder scoreRecorder;//记分员public Emit EmitDisk;public GameObject Disk;int count = 0;// Use this for initializationprotected void Start(){sceneController = (SceneController)SSDirector.getInstance().currentScenceController;diskFactory = sceneController.factory;scoreRecorder = sceneController.scoreRecorder;sceneController.actionManager = this;//设置动作管理器}// Update is called once per frameprotected new void Update(){if (sceneController.round <= 3 && sceneController.game == 1)//游戏总轮数为3轮{count++;if (count == 60)//每60帧发射一个飞碟{playDisk();sceneController.num++;//print(sceneController.num);count = 0;}base.Update();}}public void playDisk(){EmitDisk = Emit.GetSSAction();Disk = diskFactory.getDisk(sceneController.round);this.RunAction(Disk, EmitDisk, this);Disk.GetComponent<DiskData2>().action = EmitDisk;}public void SSActionEvent(SSAction source, SSActionEventType events = SSActionEventType.Competeted,int intParam = 0, string strParam = null, Object objectParam = null)              //回调函数回收飞碟记录是否失分{if (!source.gameobject.GetComponent<DiskData2>().hit)scoreRecorder.miss();diskFactory.freeDisk(source.gameobject);source.gameobject.GetComponent<DiskData2>().hit = false;}
}
我们还需要确定何时回收飞碟,在背景板设置触发器。碰触到背景板即回收,将check.js挂在背景板上。
public class Check : MonoBehaviour {public int num;public Emit EmitDisk;void OnTriggerEnter(Collider other){Debug.Log(other.gameObject.tag);if (other.gameObject.tag == "Disk"){EmitDisk = (Emit)other.gameObject.GetComponent<DiskData2>().action;EmitDisk.Destory();}}
}
来个成品图压压惊
这是挂在主摄像机的脚本,代码复用的好处这时就体现出来了,如果我想改回原来的运动学控制的飞碟要怎么做呢?很简单勾上CCActionManager然后取消Physics Manager就行了
还有提醒下大家如果有在脚本里使用到其他脚本的东西,一定要注意脚本的执行顺序,否则会出现未初始化的错误,而且往往都是以为自己代码写错了
有兴趣可以去我的GItHub看,这是传送门

Unity3D学习(7)之物理引擎的应用与代码复用相关推荐

  1. 【Unity3d学习】使用物理引擎——打飞碟游戏的物理引擎改进与射箭游戏设计

    文章目录 写在前面 HitUFO的物理引擎改进版本 物理引擎的改进版本思路与实现 PhysicsAction PhysicsManager 新接口类IActionManager 动作管理器基类的变化 ...

  2. 【Unity3D入门教程】物理引擎之碰撞解析

    Unity3D内置物理引擎,可以模拟物理效果.典型的一个物理效果就是碰撞.本文将会针对最简单的案例讲述Unity3D的碰撞规律. 1 碰撞规律 首先在场景中创建一个Sphere和一个Cube,它们都是 ...

  3. python 物理引擎 摩擦力_Python 愤怒的小鸟代码实现:物理引擎pymunk使用

    游戏介绍 最近比较忙,周末正好有时间写了python版本的愤怒的小鸟,使用了物理引擎pymunk,图片资源是从github上下载的,实现了一个可玩的简单版本. 功能实现如下:支持小鸟类型:红色小鸟,蓝 ...

  4. three.js学习笔记(十)——物理引擎

    我们可以利用数学函数和一些解决方案像RayCaster来实现自己的物理效果,但是如果需求更加真实的物理效果,像是物体张力.摩擦力.拉伸.反弹等真实物理效果,最好使用外部库 原理 我们会创建一个Thre ...

  5. Unity学习第一周-物理引擎-项目——坦克大战单机版

    项目需求及策划

  6. unity 下一帧执行_Unity中的Havok Physics物理引擎

    在GDC 2019上,我们宣布将Havok Physics作为预览版资源包加入到Unity资源包管理器,这意味着所有Unity开发者都可以使用这款知名的物理引擎.在当今主机平台中,Havok Phys ...

  7. 关于物理引擎的使用,及其重力感应的小test

    好久没写博文了,过去那些天比较忙,一直在做点别的东西,不过作为小菜的我也不忘记学习,现在跟大家分享下我的小知识吧! 首先建立个带有box2d物理引擎的项目,在头文件中加入 public:// Here ...

  8. Unity3d学习 第一天 使用Unity3d的物理引擎制作 小球打砖块 游戏

    做一个打砖块的游戏,最终的结果是如下图所示 这个游戏很简单,主要就是利用了Unity3d的物理引擎,有兴趣的朋友可以先自己做一下,游戏虽然简单,但我中间遇到很多坑,看看有没有人能一下做好. 一.创建四 ...

  9. Unity3D游戏开发初探—3.初步了解U3D物理引擎

    一.什么是物理引擎? 四个世纪前,物理学家牛顿发现了万有引力,并延伸出三大牛顿定理,为之后的物理学界的发展奠定了强大的理论基础.牛顿有句话是这么说的:"如果说我看得比较远的话,那是因为我站在 ...

最新文章

  1. NLP深度学习:近期趋势概述
  2. VMware Workstations三种网卡模式
  3. 贪心算法之——独木舟上的旅行(nyoj71)
  4. Visual Basic 15语言新特性
  5. 远程计算机需要网络级别身份验证,而您的计算机不支持该验证,请联系您的系统管理员或者技术人员来获得帮助...
  6. 【HDU - 1937 】Finding Seats(二维前缀和+尺取法)
  7. 使用pymysql进行数据库的增删改查
  8. android向h5传递参数,H5与安卓传递多个参数
  9. C语言小游戏,游戏设计,500+行代码
  10. MATLAB除法运算的精度问题及其解决方案
  11. matlab的小波分析,matlab小波分析步骤是什么
  12. 人工智能的现状与未来(附PPT)
  13. springboot读取文件
  14. android launcher启动过程,Android应用启动过程-Launcher源码浅析
  15. SpringCloud与微服务Ⅴ --- Eureka服务注册与发现
  16. 家庭教育的重要性,家庭教育是一切教育的基石
  17. 头牌知产介绍空气炸锅商标转让类别
  18. 英国内政大臣:科技公司给信息加密不可接受
  19. 关于DebugView无法打印出KdPrint信息
  20. 图像处理课程大设计--汽车牌照自动识别

热门文章

  1. 零基础C++学习(1)——数据类型、运算符和流程图
  2. 如何有效提升你的论证写作能力?
  3. Linux定时任务及企业级案例故障模拟
  4. 暑假清凉套餐小说+漫画
  5. 14-排序优化:如何实现一个通用的、高性能排序函数?
  6. 把Python当PS用,你见过没?
  7. [原创]水知道答案吗?(一)
  8. 物联网Lora模块从入门到精通(一)Lora模块初识-新大陆物联网
  9. 百度贴吧挖坟实时监控 python版
  10. 日本人为何能拿这么多诺贝尔奖