unity3D实现摄像机抖动特效
本文实例为大家分享了unity3D实现摄像机抖动的具体代码,供大家参考,具体内容如下
摄像机抖动特效在需要的地方调用CameraShake.Shake()方法就可以
publicclassCameraShake:MonoBehaviour { /// ///Thecamerastoshake. /// publicListcameras=newList(); /// ///Themaximumnumberofshakestoperform. /// publicintnumberOfShakes=2; /// ///Theamounttoshakeineachdirection. /// publicVector3shakeAmount=Vector3.one; /// ///Theamounttorotateineachdirection. /// publicVector3rotationAmount=Vector3.one; /// ///Theinitialdistanceforthefirstshake. /// publicfloatdistance=00.10f; /// ///Thespeedmultiplierfortheshake. /// publicfloatspeed=50.00f; /// ///Thedecayspeed(between0and1).Highervalueswillstopshakingsooner. /// publicfloatdecay=00.20f; /// ///ThemodifierappliedtospeedinordertoshaketheGUI. /// publicfloatguiShakeModifier=01.00f; /// ///Iftrue,multipliesthefinalshakespeedbythetimescale. /// publicboolmultiplyByTimeScale=true; //Shakerect(forGUI) privateRectshakeRect; //States privateboolshaking=false; privateboolcancelling=false; internalclassShakeState { internalreadonlyVector3startPosition; internalreadonlyQuaternionstartRotation; internalreadonlyVector2guiStartPosition; internalVector3shakePosition; internalQuaternionshakeRotation; internalVector2guiShakePosition; internalShakeState(Vector3position,Quaternionrotation,Vector2guiPosition) { startPosition=position; startRotation=rotation; guiStartPosition=guiPosition; shakePosition=position; shakeRotation=rotation; guiShakePosition=guiPosition; } } privateDictionary>states=newDictionary>(); privateDictionaryshakeCount=newDictionary(); //Minimumshakevalues privateconstboolcheckForMinimumValues=true; privateconstfloatminShakeValue=0.001f; privateconstfloatminRotationValue=0.001f; #regionSingleton /// ///TheCameraShakesingletoninstance. /// publicstaticCameraShakeinstance; privatevoidOnEnable() { if(cameras.Count<1) { if(camera) cameras.Add(camera); } if(cameras.Count<1) { if(Camera.main) cameras.Add(Camera.main); } if(cameras.Count<1) { Debug.LogError("CameraShake:Nocamerasassignedintheinspector!"); } instance=this; } #endregion #regionStaticproperties publicstaticboolisShaking { get { returninstance.IsShaking(); } } publicstaticboolisCancelling { get { returninstance.IsCancelling(); } } #endregion #regionStaticmethods publicstaticvoidShake() { instance.DoShake(); } publicstaticvoidShake(intnumberOfShakes,Vector3shakeAmount,Vector3rotationAmount,floatdistance,floatspeed,floatdecay,floatguiShakeModifier,boolmultiplyByTimeScale) { instance.DoShake(numberOfShakes,shakeAmount,rotationAmount,distance,speed,decay,guiShakeModifier,multiplyByTimeScale); } publicstaticvoidShake(System.Actioncallback) { instance.DoShake(callback); } publicstaticvoidShake(intnumberOfShakes,Vector3shakeAmount,Vector3rotationAmount,floatdistance,floatspeed,floatdecay,floatguiShakeModifier,boolmultiplyByTimeScale,System.Actioncallback) { instance.DoShake(numberOfShakes,shakeAmount,rotationAmount,distance,speed,decay,guiShakeModifier,multiplyByTimeScale,callback); } publicstaticvoidCancelShake() { instance.DoCancelShake(); } publicstaticvoidCancelShake(floattime) { instance.DoCancelShake(time); } publicstaticvoidBeginShakeGUI() { instance.DoBeginShakeGUI(); } publicstaticvoidEndShakeGUI() { instance.DoEndShakeGUI(); } publicstaticvoidBeginShakeGUILayout() { instance.DoBeginShakeGUILayout(); } publicstaticvoidEndShakeGUILayout() { instance.DoEndShakeGUILayout(); } #endregion #regionEvents /// ///Occurswhenacamerastartsshaking. /// publiceventSystem.ActioncameraShakeStarted; /// ///Occurswhenacamerahascompletelystoppedshakingandhasbeenresettoitsoriginalposition. /// publiceventSystem.ActionallCameraShakesCompleted; #endregion #regionPublicmethods publicboolIsShaking() { returnshaking; } publicboolIsCancelling() { returncancelling; } publicvoidDoShake() { Vector3seed=Random.insideUnitSphere; foreach(Cameracamincameras) { StartCoroutine(DoShake_Internal(cam,seed,this.numberOfShakes,this.shakeAmount,this.rotationAmount,this.distance,this.speed,this.decay,this.guiShakeModifier,this.multiplyByTimeScale,null)); } } publicvoidDoShake(intnumberOfShakes,Vector3shakeAmount,Vector3rotationAmount,floatdistance,floatspeed,floatdecay,floatguiShakeModifier,boolmultiplyByTimeScale) { Vector3seed=Random.insideUnitSphere; foreach(Cameracamincameras) { StartCoroutine(DoShake_Internal(cam,seed,numberOfShakes,shakeAmount,rotationAmount,distance,speed,decay,guiShakeModifier,multiplyByTimeScale,null)); } } publicvoidDoShake(System.Actioncallback) { Vector3seed=Random.insideUnitSphere; foreach(Cameracamincameras) { StartCoroutine(DoShake_Internal(cam,seed,this.numberOfShakes,this.shakeAmount,this.rotationAmount,this.distance,this.speed,this.decay,this.guiShakeModifier,this.multiplyByTimeScale,callback)); } } publicvoidDoShake(intnumberOfShakes,Vector3shakeAmount,Vector3rotationAmount,floatdistance,floatspeed,floatdecay,floatguiShakeModifier,boolmultiplyByTimeScale,System.Actioncallback) { Vector3seed=Random.insideUnitSphere; foreach(Cameracamincameras) { StartCoroutine(DoShake_Internal(cam,seed,numberOfShakes,shakeAmount,rotationAmount,distance,speed,decay,guiShakeModifier,multiplyByTimeScale,callback)); } } publicvoidDoCancelShake() { if(shaking&&!cancelling) { shaking=false; this.StopAllCoroutines(); foreach(Cameracamincameras) { if(shakeCount.ContainsKey(cam)) { shakeCount[cam]=0; } ResetState(cam.transform,cam); } } } publicvoidDoCancelShake(floattime) { if(shaking&&!cancelling) { this.StopAllCoroutines(); this.StartCoroutine(DoResetState(cameras,shakeCount,time)); } } publicvoidDoBeginShakeGUI() { CheckShakeRect(); GUI.BeginGroup(shakeRect); } publicvoidDoEndShakeGUI() { GUI.EndGroup(); } publicvoidDoBeginShakeGUILayout() { CheckShakeRect(); GUILayout.BeginArea(shakeRect); } publicvoidDoEndShakeGUILayout() { GUILayout.EndArea(); } #endregion #regionPrivatemethods privatevoidOnDrawGizmosSelected() { foreach(Cameracamincameras) { if(!cam) continue; if(IsShaking()) { Vector3offset=cam.worldToCameraMatrix.GetColumn(3); offset.z*=-1; offset=cam.transform.position+cam.transform.TransformPoint(offset); Quaternionrot=QuaternionFromMatrix(cam.worldToCameraMatrix.inverse*Matrix4x4.TRS(Vector3.zero,Quaternion.identity,newVector3(1,1,-1))); Matrix4x4matrix=Matrix4x4.TRS(offset,rot,cam.transform.lossyScale); Gizmos.matrix=matrix; } else { Matrix4x4matrix=Matrix4x4.TRS(cam.transform.position,cam.transform.rotation,cam.transform.lossyScale); Gizmos.matrix=matrix; } Gizmos.DrawWireCube(Vector3.zero,shakeAmount); Gizmos.color=Color.cyan; if(cam.isOrthoGraphic) { Vector3pos=newVector3(0,0,(cam.near+cam.far)/2f); Vector3size=newVector3(cam.orthographicSize/cam.aspect,cam.orthographicSize*2f,cam.far-cam.near); Gizmos.DrawWireCube(pos,size); } else { Gizmos.DrawFrustum(Vector3.zero,cam.fov,cam.far,cam.near,(.7f/cam.aspect)); } } } privateIEnumeratorDoShake_Internal(Cameracam,Vector3seed,intnumberOfShakes,Vector3shakeAmount,Vector3rotationAmount,floatdistance,floatspeed,floatdecay,floatguiShakeModifier,boolmultiplyByTimeScale,System.Actioncallback) { //Waitforasynccanceloperationstocomplete if(cancelling) yieldreturnnull; //Setrandomvalues varmod1=seed.x>.5f?1:-1; varmod2=seed.y>.5f?1:-1; varmod3=seed.z>.5f?1:-1; //Firstshake if(!shaking) { shaking=true; if(cameraShakeStarted!=null) cameraShakeStarted(); } if(shakeCount.ContainsKey(cam)) shakeCount[cam]++; else shakeCount.Add(cam,1); //Pixelwidthisalwaysbasedonthefirstcamera floatpixelWidth=GetPixelWidth(cameras[0].transform,cameras[0]); //Setothervalues TransformcachedTransform=cam.transform; Vector3camOffset=Vector3.zero; QuaternioncamRot=Quaternion.identity; intcurrentShakes=numberOfShakes; floatshakeDistance=distance; floatrotationStrength=1; floatstartTime=Time.time; floatscale=multiplyByTimeScale?Time.timeScale:1; floatpixelScale=pixelWidth*guiShakeModifier*scale; Vector3start1=Vector2.zero; QuaternionstartR=Quaternion.identity; Vector2start2=Vector2.zero; ShakeStatestate=newShakeState(cachedTransform.position,cachedTransform.rotation,newVector2(shakeRect.x,shakeRect.y)); ListstateList; if(states.TryGetValue(cam,outstateList)) { stateList.Add(state); } else { stateList=newList(); stateList.Add(state); states.Add(cam,stateList); } //Mainloop while(currentShakes>0) { if(checkForMinimumValues) { //Earlybreakwhenrotationislessthantheminimumvalue. if(rotationAmount.sqrMagnitude!=0&&rotationStrength<=minRotationValue) break; //Earlybreakwhenshakeamountislessthantheminimumvalue. if(shakeAmount.sqrMagnitude!=0&&distance!=0&&shakeDistance<=minShakeValue) break; } vartimer=(Time.time-startTime)*speed; state.shakePosition=start1+newVector3( mod1*Mathf.Sin(timer)*(shakeAmount.x*shakeDistance*scale), mod2*Mathf.Cos(timer)*(shakeAmount.y*shakeDistance*scale), mod3*Mathf.Sin(timer)*(shakeAmount.z*shakeDistance*scale)); state.shakeRotation=startR*Quaternion.Euler( mod1*Mathf.Cos(timer)*(rotationAmount.x*rotationStrength*scale), mod2*Mathf.Sin(timer)*(rotationAmount.y*rotationStrength*scale), mod3*Mathf.Cos(timer)*(rotationAmount.z*rotationStrength*scale)); state.guiShakePosition=newVector2( start2.x-(mod1*Mathf.Sin(timer)*(shakeAmount.x*shakeDistance*pixelScale)), start2.y-(mod2*Mathf.Cos(timer)*(shakeAmount.y*shakeDistance*pixelScale))); camOffset=GetGeometricAvg(stateList,true); camRot=GetAvgRotation(stateList); NormalizeQuaternion(refcamRot); Matrix4x4m=Matrix4x4.TRS(camOffset,camRot,newVector3(1,1,-1)); cam.worldToCameraMatrix=m*cachedTransform.worldToLocalMatrix; varavg=GetGeometricAvg(stateList,false); shakeRect.x=avg.x; shakeRect.y=avg.y; if(timer>Mathf.PI*2) { startTime=Time.time; shakeDistance*=(1-Mathf.Clamp01(decay)); rotationStrength*=(1-Mathf.Clamp01(decay)); currentShakes--; } yieldreturnnull; } //Endconditions shakeCount[cam]--; //Lastshake if(shakeCount[cam]==0) { shaking=false; ResetState(cam.transform,cam); if(allCameraShakesCompleted!=null) { allCameraShakesCompleted(); } } else { stateList.Remove(state); } if(callback!=null) callback(); } privateVector3GetGeometricAvg(Liststates,boolposition) { floatx=0,y=0,z=0,l=states.Count; foreach(ShakeStatestateinstates) { if(position) { x-=state.shakePosition.x; y-=state.shakePosition.y; z-=state.shakePosition.z; } else { x+=state.guiShakePosition.x; y+=state.guiShakePosition.y; } } returnnewVector3(x/l,y/l,z/l); } privateQuaternionGetAvgRotation(Liststates) { Quaternionavg=newQuaternion(0,0,0,0); foreach(ShakeStatestateinstates) { if(Quaternion.Dot(state.shakeRotation,avg)>0) { avg.x+=state.shakeRotation.x; avg.y+=state.shakeRotation.y; avg.z+=state.shakeRotation.z; avg.w+=state.shakeRotation.w; } else { avg.x+=-state.shakeRotation.x; avg.y+=-state.shakeRotation.y; avg.z+=-state.shakeRotation.z; avg.w+=-state.shakeRotation.w; } } varmag=Mathf.Sqrt(avg.x*avg.x+avg.y*avg.y+avg.z*avg.z+avg.w*avg.w); if(mag>0.0001f) { avg.x/=mag; avg.y/=mag; avg.z/=mag; avg.w/=mag; } else { avg=states[0].shakeRotation; } returnavg; } privatevoidCheckShakeRect() { if(Screen.width!=shakeRect.width||Screen.height!=shakeRect.height) { shakeRect.width=Screen.width; shakeRect.height=Screen.height; } } privatefloatGetPixelWidth(TransformcachedTransform,CameracachedCamera) { varposition=cachedTransform.position; varscreenPos=cachedCamera.WorldToScreenPoint(position-cachedTransform.forward*.01f); varoffset=Vector3.zero; if(screenPos.x>0) offset=screenPos-Vector3.right; else offset=screenPos+Vector3.right; if(screenPos.y>0) offset=screenPos-Vector3.up; else offset=screenPos+Vector3.up; offset=cachedCamera.ScreenToWorldPoint(offset); return1f/(cachedTransform.InverseTransformPoint(position)-cachedTransform.InverseTransformPoint(offset)).magnitude; } privatevoidResetState(TransformcachedTransform,Cameracam) { cam.ResetWorldToCameraMatrix(); shakeRect.x=0; shakeRect.y=0; states[cam].Clear(); } privateListoffsetCache=newList(10); privateListrotationCache=newList(10); privateIEnumeratorDoResetState(Listcameras,DictionaryshakeCount,floattime) { offsetCache.Clear(); rotationCache.Clear(); foreach(Cameracamincameras) { offsetCache.Add((Vector3)((cam.worldToCameraMatrix*cam.transform.worldToLocalMatrix.inverse).GetColumn(3))); rotationCache.Add(QuaternionFromMatrix((cam.worldToCameraMatrix*cam.transform.worldToLocalMatrix.inverse).inverse*Matrix4x4.TRS(Vector3.zero,Quaternion.identity,newVector3(1,1,-1)))); if(shakeCount.ContainsKey(cam)) { shakeCount[cam]=0; } states[cam].Clear(); } floatt=0; floatx=shakeRect.x,y=shakeRect.y; cancelling=true; while(t