Unity 3D液体浮力实现

前言

本文以unity的StandardAssets中的water资源为基础,实现物体在水中的漂浮效果。

 

 

概述

1.    建立场景并添加水详见https://docs.unity3d.com/Manual/HOWTO-Water.html

2.    给水添加碰撞体组件,编写脚本现实物体出入水的检测。

3.    创建立方体预制体,添加刚体组件,碰撞体组件,编辑脚本处理入水后的浮力计算。

 

实现细节

1.    给水体添加碰撞体

需要注意的是要勾选 Is Trigger ,y方向的范围要控制好,不然可能会出现物体掉到水面一下太多会触发OnTriggerExit() (见脚本部分)。

Unity 3D液体浮力实现_第1张图片

 

 

2.    创建立方体

我创建了一个长宽高分别为1,质量为0.5的立方体,预期效果是在水中漂浮一半露出水面。之后可以通过脚本改变大小及质量验证效果。

3.    水的脚本

水的脚本主要实现OnTriggerEnter和OnTriggerExit两个方法,当其他碰撞体进入水中,触发OnTriggerEnter,将cube中的isInWater置为ture,OnTriggerExit相反。

4.    立方体脚本

       立方体脚本的核心是calFloatage方法,计算立方体下表面与水面高度差,通过公式计算浮力,并通过Rigidbody.AddForce()方法施加浮力。

       进入水中后将阻力系数调高。

       需要注意的是物体完全进入水中后保持h = 立方体高度

5.    代码

 

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

public class Floatage : MonoBehaviour {

	// Use this for initialization
	void Start () {
		
	}
	
	// Update is called once per frame
	void Update () {
		
	}

	/// 
	/// OnTriggerEnter is called when the Collider other enters the trigger.
	/// 
	/// The other Collider involved in this collision.
	void OnTriggerEnter(Collider other)
	{	
		
		if(other.gameObject.GetComponent()){
			other.gameObject.GetComponent().setIsInWater(true);
		}
	}
	/// 
	/// OnTriggerExit is called when the Collider other has stopped touching the trigger.
	/// 
	/// The other Collider involved in this collision.
	void OnTriggerExit(Collider other)
	{
		if(other.gameObject.GetComponent()){
			other.gameObject.GetComponent().setIsInWater(false);
		}
	}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Cube : MonoBehaviour {
	private bool isInWater;
	private GameObject water;  
	private	 float waterY;
	private const float floatageForce = 0;
	private const float density = 1;
	private const float g = 9.8f;
	private const float waterDrag = 5;
	public bool getIsInWater(){
		return isInWater;
	}
	public void setIsInWater(bool isInWater){
		 this.isInWater = isInWater;
	}
	// Use this for initialization
	void Start () {
		isInWater = false;
		water = GameObject.FindWithTag("water");
	}
	
	// Update is called once per frame
	void Update () {
		
	}
	/// 
	/// This function is called every fixed framerate frame, if the MonoBehaviour is enabled.
	/// 
	void FixedUpdate()
	{
		if(isInWater){
			//calculate floatage
			calFloatage();
			//change darg
			GetComponent().drag = waterDrag;
		}
	}
		//calculate and add floatage force to the box.
		private void calFloatage(){
			waterY = water.transform.position.y;

			if(waterY>(transform.position.y-transform.localScale.y)){
				float h = waterY-(transform.position.y-transform.localScale.y/2)>transform.localScale.y? transform.localScale.y:waterY-(transform.position.y-transform.localScale.y/2);
				float floatageForce = density * g *transform.localScale.x*transform.localScale.z*h;
				GetComponent().AddForce(0,floatageForce,0);
			}
	}
}


 

6.    效果

 

 

 

 

 

 

 

 

问题

1.    物体出现旋转的话要很久才能停下来,不知道调整什么阻力可以实现更加逼真的效果,或者手动实现。

      已经解决。进入水中增大angular drag即可。

 

 

 

小弟第一次写博客,才开始学习unity,望大佬们多多指教!


你可能感兴趣的:(Unity)