Unity 3 Dがケースを持つAngryBots分析(二)――人物動作制御ロジック

15297 ワード

Unity 3 Dは、C:UsersPublicDocumentsUnity Projects4-0_AngryBotsではopenプロジェクトで直接選択するか、そのディレクトリからAssetsをダブルクリックしてAngryBotsにアクセスすればよい.
HierarchyビューでPlayerおよび展開Playerの下のサブオブジェクトを選択し、各オブジェクトを選択すると、関連オブジェクトに掛けられているスクリプトやその他のcomponentsがInspectorで表示されます.Transformは各オブジェクトにあり、位置、方向、スケール係数を格納するので、オブジェクトの平行移動、回転、スケールなどの変換を担当します.Capsule Colliderは、イベントをトリガーできない摩擦のない衝突器を人物に追加しました.Rigidbodyは人物を物理的要因の作用の下に置いて、空気の抵抗がなくて、トルクと重力を設定して、急速に移動して他のobjectの設定の離散衝突の検出を通り抜けることを防止します.このコンポーネントは、物理的属性に従って人物のTransformを変更する能力を提供し、よりリアルな効果をもたらす、FreeMovementMotor.jsにはRigidbodyが必要で、剛体を操作します.player_rootオブジェクトは人物の体の骨格全体の構築を完了した.Skinned Mesh Rendererは影の効果を示すことができて、血筋(healthbar_player)と人物の外観(play-01-default)の材質を設定して、頂点の最大骨格数autoに影響して、offscreenの範囲を設定して、main_を追加しましたplayer_lorezのMesh.
人物動作制御スクリプトは以下のように分析される.
MovementMotor.js:3つの変数を含む
#pragma strict
@HideInInspector
public var movementDirection : Vector3;

@HideInInspector
public var movementTarget : Vector3;

@HideInInspector
public var facingDirection : Vector3;
 
  
  • #pragma strict为js中强制使用静态类型,禁用动态类型,输入变量时必须明确指定变量类型不能让编译器自己去推测类型。
  • @HideInInspector为编译器属性,作用是使变量不会显示在Inspector中,但是会被实例化。
  • movementDirection为角色世界坐标系中的移动方向,该向量长度应该保持0~1内。
  • movementTarget为在仅有目标的情况下使用,来驱动角色向目标前进。
  • facingDirection为角色在世界坐标系中面朝的方向。

    一般情况是,有了target则使用movementTarget来控制变换,而movementDirection和facingDirection一般都一起使用,两者合在一起驱动角色的运动。该脚本主要用于刚体控制物体的移动旋转时用到,使用起来更像接口,适用于完成人物、敌人、各种实体的运动控制。

FreeMovementMotor.js:

#pragma strict
@script RequireComponent (Rigidbody)//      Rigidbody   object ,    ,  Rigidbody      。
class FreeMovementMotor extends MovementMotor {		
	public var walkingSpeed : float = 5.0;     //      
	public var walkingSnappyness : float = 50; //        
	public var turningSmoothing : float = 0.3; //        
	
	function FixedUpdate () {
		//      
		var targetVelocity : Vector3 = movementDirection * walkingSpeed;//                   
		var deltaVelocity : Vector3 = targetVelocity - rigidbody.velocity;//    
		if (rigidbody.useGravity)
			deltaVelocity.y = 0;//          ,   y        0,                。
		rigidbody.AddForce (deltaVelocity * walkingSnappyness, ForceMode.Acceleration);//       ,      
		
		//      
		var faceDir : Vector3 = facingDirection;//     facingDirection
		if (faceDir == Vector3.zero)
			faceDir = movementDirection;//  Zero   ,          (                  )
		
		//          
		if (faceDir == Vector3.zero) {
			rigidbody.angularVelocity = Vector3.zero;
		}
		else {//      ,    transform      ,               
			var rotationAngle : float = AngleAroundAxis (transform.forward, faceDir, Vector3.up);
			rigidbody.angularVelocity = (Vector3.up * rotationAngle * turningSmoothing);//       ,      
		}
	}
	
	//  dirA  axis     dirB       
	static function AngleAroundAxis (dirA : Vector3, dirB : Vector3, axis : Vector3) {
	    //dirA dirB            ,             
	    dirA = dirA - Vector3.Project (dirA, axis);
	    dirB = dirB - Vector3.Project (dirB, axis);
	   
	    //dirA dirB       
	    var angle : float = Vector3.Angle (dirA, dirB);
	   
	    //  dirA   dirB      axis  ,         
	    return angle * (Vector3.Dot (axis, Vector3.Cross (dirA, dirB)) < 0 ? -1 : 1);
	}
	
}
  • ゲームでは人物の向きと人物の移動方向が一致せず、ゲームをしていると、人物がカニのように横に移動できることがわかります.
  • var deltaVelocity : Vector3 = targetVelocity - rigidbody.velocity; targetVelocityは我々が指定した一定の速度でありrigidbody.velocityは、剛体自身の速度(剛体は物理的要因にかかわるため、この速度はいずれも物理的要因に関連しており、人物の移動速度とは別物であり、移動速度に影響を及ぼす)である.従って、移動速度は固定速度と物理的要因の影響を受ける速度と共に作用する.
  • rigidbody.AddForce (deltaVelocity * walkingSnappyness, ForceMode.Acceleration);オブジェクトの質量の大きさに関係なく同じ方法でオブジェクトを移動する加速モード(ForceMode.Acceleration)を使用します.walkingSnappynessは、物理的要因の影響に関連してインスペクタで設定できる因子です.
  • rigidbody.angularVelocity = (Vector3.up * rotationAngle * turningSmoothing);中turningSmoothingは回転平滑因子、Vector 3である.upは角速度の正方向であり、人物は世界座標系において上方向が世界座標系のy軸であり、rotationAngleは回転角度であり、これにより人物を指定された向きに回転させる.

  • PlayerMoveController.js
    #pragma strict
    
    //     
    public var motor : MovementMotor;
    public var character : Transform;
    public var cursorPrefab : GameObject;
    public var joystickPrefab : GameObject;
    
    //     
    public var cameraSmoothing : float = 0.01;
    public var cameraPreview : float = 2.0f;
    
    //    
    public var cursorPlaneHeight : float = 0;
    public var cursorFacingCamera : float = 0;
    public var cursorSmallerWithDistance : float = 0;
    public var cursorSmallerWhenClose : float = 1;
    
    //      
    private var mainCamera : Camera;
    //       
    private var cursorObject : Transform;
    private var joystickLeft : Joystick;
    private var joystickRight : Joystick;
    //     
    private var mainCameraTransform : Transform;
    private var cameraVelocity : Vector3 = Vector3.zero;
    private var cameraOffset : Vector3 = Vector3.zero;
    private var initOffsetToPlayer : Vector3;
    
    //   (PC     ,          ) 
    private var cursorScreenPosition : Vector3;
    //      
    private var playerMovementPlane : Plane;
    
    private var joystickRightGO : GameObject;
    //                 
    private var screenMovementSpace : Quaternion;
    private var screenMovementForward : Vector3;
    private var screenMovementRight : Vector3;
    
    function Awake () {		
    	motor.movementDirection = Vector2.zero;//        
    	motor.facingDirection = Vector2.zero;//      
    	
    	//        
    	mainCamera = Camera.main;
    	mainCameraTransform = mainCamera.transform;
    	
    	//       ,             transform
    	if (!character)
    		character = transform;
    	//                  
    	initOffsetToPlayer = mainCameraTransform.position - character.position;
    	
    	#if UNITY_IPHONE || UNITY_ANDROID || UNITY_WP8 || UNITY_BLACKBERRY || UNITY_TIZEN//Iphone,Android,WP8,BlackBerry,Tizen  
    		if (joystickPrefab) {
    			//      
    			var joystickLeftGO : GameObject = Instantiate (joystickPrefab) as GameObject;//       
    			joystickLeftGO.name = "Joystick Left";
    			joystickLeft = joystickLeftGO.GetComponent. ();
    			
    			//       
    			joystickRightGO = Instantiate (joystickPrefab) as GameObject;//       (GameObject  )
    			joystickRightGO.name = "Joystick Right";
    			joystickRight = joystickRightGO.GetComponent. ();//Joystick  			
    		}
    	#elif !UNITY_FLASH// flash  
    		if (cursorPrefab) {
    			cursorObject = (Instantiate (cursorPrefab) as GameObject).transform;//      
    		}
    	#endif
    	
    	//                  ,       
    	cameraOffset = mainCameraTransform.position - character.position;
    	
    	//             
    	cursorScreenPosition = Vector3 (0.5 * Screen.width, 0.5 * Screen.height, 0);
    	
    	//         
    	playerMovementPlane = new Plane (character.up, character.position + character.up * cursorPlaneHeight);
    }
    
    function Start () {
    	#if UNITY_IPHONE || UNITY_ANDROID || UNITY_WP8 || UNITY_BLACKBERRY || UNITY_TIZEN
    		//             
    		var guiTex : GUITexture = joystickRightGO.GetComponent. ();
    		guiTex.pixelInset.x = Screen.width - guiTex.pixelInset.x - guiTex.pixelInset.width;			
    	#endif	
    	
    	// Start                   forward、right   ,             	
    	screenMovementSpace = Quaternion.Euler (0, mainCameraTransform.eulerAngles.y, 0);// y             
    	screenMovementForward = screenMovementSpace * Vector3.forward;//         forward  
    	screenMovementRight = screenMovementSpace * Vector3.right;//         right  
    }
    
    function OnDisable () {
    	if (joystickLeft) //      
    		joystickLeft.enabled = false;
    	
    	if (joystickRight)//      
    		joystickRight.enabled = false;
    }
    
    function OnEnable () {
    	if (joystickLeft) //      
    		joystickLeft.enabled = true;
    	
    	if (joystickRight)//      
    		joystickRight.enabled = true;
    }
    
    private var button8Down : boolean = false;
    private var button9Down : boolean = false;
    private var moveF : int;
    private var moveB : int;
    
    function Update () {
    
    	if(GLOBAL.isJSConnected)
    	{// iphone    ,        
    		if(Input.GetButtonDown("Joystick button 8"))
    		{
    			button8Down = true;
    		}
    
    		if(Input.GetButtonUp("Joystick button 8"))
    		{
    			button8Down = false;
    		}
    
    		if(Input.GetButtonDown("Joystick button 9"))
    		{
    			button9Down = true;
    		}
    
    		if(Input.GetButtonUp("Joystick button 9"))
    		{
    			button9Down = false;
    		}
    
    		//     
    		if(!button8Down)
    		{
    			moveF = 1;
    		}
    		else
    		{
    			moveF = 0;
    		}
    
    		if(button9Down)
    		{
    			moveB = 1;
    		}
    		else
    		{
    			moveB = 0;
    		}
    	}
    
    	#if UNITY_ANDROID || UNITY_WP8 || UNITY_BLACKBERRY || UNITY_TIZEN
    		motor.movementDirection = joystickLeft.position.x * screenMovementRight + joystickLeft.position.y * screenMovementForward;
    	#elif UNITY_IPHONE
    		if(GLOBAL.isJSConnected)
    		{
    			if (GLOBAL.isJSExtended)
    				motor.movementDirection = Input.GetAxis("Horizontal") * screenMovementRight + Input.GetAxis("Vertical") * screenMovementForward;
    			else
    				motor.movementDirection = -moveB * (motor.facingDirection*2) + moveF * (motor.facingDirection*2);
    		}
    		else
    		{//      Android   
    			motor.movementDirection = joystickLeft.position.x * screenMovementRight + joystickLeft.position.y * screenMovementForward;
    		}
    
    	#else//PC ,  Input   Horizontal、Vertical         
    		motor.movementDirection = Input.GetAxis ("Horizontal") * screenMovementRight + Input.GetAxis ("Vertical") * screenMovementForward;//   Vertical      (-1~1)     screenMovementForward                      ;Horizontal  ,          (ASWD)
    	#endif
    				
    	//           1,                       (                          ,                    )
    	if (motor.movementDirection.sqrMagnitude > 1)
    		motor.movementDirection.Normalize();
    	
    	
    	//             
    	
    	playerMovementPlane.normal = character.up;//            up 
    	playerMovementPlane.distance = -character.position.y + cursorPlaneHeight;//                 
    		
    	var cameraAdjustmentVector : Vector3 = Vector3.zero;//                         
    	
    	#if UNITY_ANDROID || UNITY_WP8 || UNITY_BLACKBERRY || UNITY_TIZEN
    	
    		//            ,           
    		motor.facingDirection = joystickRight.position.x * screenMovementRight + joystickRight.position.y * screenMovementForward;
    				
    		cameraAdjustmentVector = motor.facingDirection;//         		
    	
    	#else			
    		#if (UNITY_XBOX360 || UNITY_PS3 || UNITY_IPHONE)
    			//           
    			var axisX : float;
    			var axisY : float;
    			if(GLOBAL.isJSConnected)
    			{
    				if (GLOBAL.isJSExtended)
    				{
    					axisX = Input.GetAxis("RightHorizontal");
    					axisY = Input.GetAxis("RightVertical");
    					motor.facingDirection = axisX * screenMovementRight + axisY * screenMovementForward;
    				}
    				else
    				{
    					axisX = Input.GetAxis("Horizontal");
    					axisY = Input.GetAxis("Vertical");
    					motor.facingDirection = axisX * screenMovementRight + axisY * screenMovementForward;
    				}
    			}
    			else
    			{
    				motor.facingDirection = joystickRight.position.x * screenMovementRight + joystickRight.position.y * screenMovementForward;
    				cameraAdjustmentVector = motor.facingDirection;
    			}		
    		
    		#else
    	
    			//PC          
    			var cursorScreenPosition : Vector3 = Input.mousePosition;
    						
    			//          ,                              
    			var cursorWorldPosition : Vector3 = ScreenPointToWorldPointOnPlane (cursorScreenPosition, playerMovementPlane, mainCamera);
    			
    			var halfWidth : float = Screen.width / 2.0f;
    			var halfHeight : float = Screen.height / 2.0f;
    			var maxHalf : float = Mathf.Max (halfWidth, halfHeight);
    			
    			//          (                 [      ])			
    			var posRel : Vector3 = cursorScreenPosition - Vector3 (halfWidth, halfHeight, cursorScreenPosition.z);		
    			posRel.x /= maxHalf; 
    			posRel.y /= maxHalf;//       ,         
    						
    			cameraAdjustmentVector = posRel.x * screenMovementRight + posRel.y * screenMovementForward;
    			cameraAdjustmentVector.y = 0.0;	
    									
    			//                        
    			motor.facingDirection = (cursorWorldPosition - character.position);
    			motor.facingDirection.y = 0;			
    			
    			//              
    			HandleCursorAlignment (cursorWorldPosition);
    			
    		#endif		
    	#endif
    		
    	//       		
    	//    target        
    	var cameraTargetPosition : Vector3 = character.position + initOffsetToPlayer + cameraAdjustmentVector * cameraPreview;
    	
    	//            
    	mainCameraTransform.position = Vector3.SmoothDamp (mainCameraTransform.position, cameraTargetPosition, cameraVelocity, cameraSmoothing);
    	
    	//                ,       
    	cameraOffset = mainCameraTransform.position - character.position;
    }
    
    public static function PlaneRayIntersection (plane : Plane, ray : Ray) : Vector3 {//          
    	var dist : float;
    	plane.Raycast (ray, dist);//              
    	return ray.GetPoint (dist);//    
    }
    //                                     
    public static function ScreenPointToWorldPointOnPlane (screenPoint : Vector3, plane : Plane, camera : Camera) : Vector3 {
    	//                         
    	var ray : Ray = camera.ScreenPointToRay (screenPoint);
    	
    	//         
    	return PlaneRayIntersection (plane, ray);
    }
    
    function HandleCursorAlignment (cursorWorldPosition : Vector3) {
    	if (!cursorObject)
    		return;
    	
    	//      
    	
    	//           
    	cursorObject.position = cursorWorldPosition;
    	
    	#if !UNITY_FLASH
    		//                
    		Screen.showCursor = (Input.mousePosition.x < 0 || Input.mousePosition.x > Screen.width || Input.mousePosition.y < 0 || Input.mousePosition.y > Screen.height);
    	#endif
    	
    	
    	//      	
    	var cursorWorldRotation : Quaternion = cursorObject.rotation;
    	if (motor.facingDirection != Vector3.zero)
    		cursorWorldRotation = Quaternion.LookRotation (motor.facingDirection);//         
    	
    	//           
    	var cursorScreenspaceDirection : Vector3 = Input.mousePosition - mainCamera.WorldToScreenPoint (transform.position + character.up * cursorPlaneHeight);
    	cursorScreenspaceDirection.z = 0;
    	var cursorBillboardRotation : Quaternion = mainCameraTransform.rotation * Quaternion.LookRotation (cursorScreenspaceDirection, -Vector3.forward);
    	
    	//      
    	cursorObject.rotation = Quaternion.Slerp (cursorWorldRotation, cursorBillboardRotation, cursorFacingCamera);
    	
    	
    	//      
    	
    	//            ,                 ,        
    	//                     
    	var compensatedScale : float = 0.1 * Vector3.Dot (cursorWorldPosition - mainCameraTransform.position, mainCameraTransform.forward);
    	
    	//         
    	var cursorScaleMultiplier : float = Mathf.Lerp (0.7, 1.0, Mathf.InverseLerp (0.5, 4.0, motor.facingDirection.magnitude));
    	
    	//          
    	cursorObject.localScale = Vector3.one * Mathf.Lerp (compensatedScale, 1, cursorSmallerWithDistance) * cursorScaleMultiplier;
    	
    }
    
    PlayerMoveController.jsスクリプトでは、フレームごとにUpdate関数が呼び出されます.この関数では、プレイヤーのマウスの移動、キーやレバーの操作などによって、プレイヤーが人物キャラクタを移動または回転させたい量を取得し、人物の移動方向、向きを設定し、カメラが画面上での調整表示などを調整します.そして、次のフレームのFixedUpdate関数呼び出し時に、FreeMovementMotor.jsスクリプトの計算は、設定されたmovementDirectionとfacingDirectionに基づいて人物の位置の向きを調整します.このフレームにプレイヤーが入力していない場合、次のフレームでは人物のリジッドボディから得られる物理的要因の影響に基づいて移動回転するだけです.
    また重要な点は、カーソルの位置を設定し、人物がカーソル方向に人物を向いていることで、プレイヤーはカーソルの位置を変えることで人物に相応の移動回転を生じさせることができる.カメラもカーソルに合わせて画面の調整を行います.