Announcement

Collapse
No announcement yet.

GoW Camera Tutorial extension

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

    GoW Camera Tutorial extension

    Another gentlemen posted a great camera tutorial that would allow a zoom adjustable, Gears of War style camera. The only problem with it was it used some very low level classes as base classes. As most of you know, many people base their script off UTGame classes and UTGame uses CalcCamera() instead of a camera class. UTGame also implements bBehindView which initially is very similar but lacks the ability to zoom out etc. Below I've added the code necessary to create a zoomable 3rd person camera that has an aim implementation.


    Notes**
    All classes are prefaced in the following manner RE + Base class name. I.E (" REGameInfo")

    All values are easily adjusted both in default properties and at runtime for easy debugging/finding what you like.

    GameInfo - Main game type class
    Code:
    class REGameInfo extends UTGame;
    
    DefaultProperties
    {
    	DefaultPawnClass=class'REPawn'
    	HUDType=class'REHUD' //100% un-needed
    	PlayerControllerClass=class'REController'
    }

    Pawn - Where the magic happens
    Code:
    class REPawn extends UTPawn;
    
    var float CameraOffsetLength;
    
    var float GlobalCamZoom; /* Indexer value to allow camera memory of where the user last had his zoom set */
    
    /* The values that will actually be used in the camera calculation algorithm */
    var float CurrCamZoom; //The camera's position on the X axis or Forward/Backward
    var float CurrYZoom; //Camera's Left/Right position
    var float CurrFOV; // Camera's FOV used for a nice zoom effect
    var float CurrZ; // the camera's position on the Z axis or Up/Down
    /* Lerp values to allow smooth interpolation of the camera */
    var float TargetFOV;
    var float TargetCamZoom;
    var float TargetYZoom;
    var float TargetZ;
    
    /* Target values for where the camera should go when we shoulder/unshoulder the camera */
    var float ShoulderZoom;
    var float ShoulderYZoom;
    var float ShoulderFOV;
    var float ShoulderZ;
    var float NonShoulderZ;
    var float NonShoulderFOV;
    var float NonShoulderYZoom;
    /* Flag to indicate if the user zoomed in or not. */
    var bool bShoulderCam;
    
    var float CurrentCameraDistance, CurrentCameraOffsetLength;
    var Vector PawnEyeLocation;
    var Vector PlayerHitTarget;
    
    simulated function bool CalcCamera(float fDeltaTime, out vector out_CamLoc, out rotator out_CamRot, out float out_FOV)
    {
    	local vector CamStart, FirstHitLocation, HitLocation, HitNormal, CamDir, X, Y, Z, end;
    	local float DesiredCameraZOffset;
    	local bool bInsideHero, bObstructed;
    
    	local float DesiredCameraDistance;
    	local float CameraOffsetRatio;
    	local vector tempCamStart, tempCamEnd;
    	local Vector VectorX, VectorY, VectorZ;
    
    	local Actor CamTrace;
    
    	bObstructed = false;
    
    	//Mesh.SetOwnerNoSee(false);
    
    	// Handle the fixed camera
    	if (bFixedView)
    	{
    		out_CamLoc = FixedViewLoc;
    		out_CamRot = FixedViewRot;
    	}
    
    	if(bShoulderCam) // User has zoomed in, set our Lerp targets to where we're zooming to.
    	{
    		TargetYZoom = ShoulderYZoom;
    		TargetCamZoom = ShoulderZoom;
    		TargetFOV = ShoulderFOV;
    		TargetZ = ShoulderZ;
    	}
    	else // Default the Target, if the user was zoomed in, return the values back to normal otherwise do nothing
    	{
    		TargetYZoom = NonShoulderYZoom;
    		TargetCamZoom = GlobalCamZoom;
    		TargetFOV = NonShoulderFOV;
    		TargetZ = NonShoulderZ;
    	}
    
    	if(CurrZ != TargetZ) // Lerp the Z-Axis if the value changed
    	{
    		CurrZ = Lerp(CurrZ, TargetZ, 0.1);
    	}
    	if(CurrFOV != TargetFOV) // Lerp the FOV for the zoom effect
    	{
    		CurrFOV = Lerp(CurrFOV, TargetFOV, 0.1);
    		/* TODO: Change REController to the name of your PlayerController Class */
    		REController(Owner).SetFOV(CurrFOV); 
    	}
    	if(CurrCamZoom != TargetCamZoom) // Lerp the Zoom for a steady zoom in/out effect
    	{
    		CurrCamZoom = Lerp(CurrCamZoom, TargetCamZoom, 0.1);
    	}
    	
    	if(CurrYZoom != TargetYZoom) // Lerp the left/right movement of the camera when we zoom in to prevent model clipping
    	{
    		CurrYZoom = Lerp(CurrYZoom, TargetYZoom, 0.1);
    	}
    
    
    	ModifyRotForDebugFreeCam(out_CamRot);
    
    	CamStart = Location;
    	DesiredCameraZOffset = (Health > 0) ? GetCollisionRadius() * /*Default Value: 0.75*/ CurrZ : 0.f;
    	CameraZOffset = (fDeltaTime < 0.2) ? DesiredCameraZOffset * 5 * fDeltaTime + (1 - 5*fDeltaTime) * CameraZOffset : DesiredCameraZOffset;
    
    	CamStart.Z += CameraZOffset;
    	GetAxes(out_CamRot, X, Y, Z);
    
    	/*VectorX here you can implement camera zoom in/out or scaling or whatever you want to call it */
    	VectorX = X * GetCollisionRadius() * CurrCamZoom; //this vector determine depth of camera, how far from character it will be
    	VectorY = Y * GetCollisionRadius() * CurrYZoom; // this vector determine side of camera, negaive value pull character to left side, while positive to right side
    	VectorZ = (GetCollisionRadius() /* FMax(0,(1.0-CamRotZ.Z))*/ * Z) * -1.55; //this value try to pull camera forward while pitching down, and back while pitching up, but pulling back seems to dont work
    	CamDir = VectorX + VectorY + VectorZ;
    
    	if ( (Health <= 0) || bFeigningDeath )
    	{
    		// adjust camera position to make sure it's not clipping into world
    		// @todo fixmesteve.  Note that you can still get clipping if FindSpot fails (happens rarely)
    		FindSpot(GetCollisionExtent(),CamStart);
    	}
    	/*
    	if (CurrentCameraScale < CameraScale)
    	{
    		CurrentCameraScale = FMin(CameraScale, CurrentCameraScale + 5 * FMax(CameraScale - CurrentCameraScale, 0.3)*fDeltaTime);
    	}
    	else if (CurrentCameraScale > CameraScale)
    	{
    		CurrentCameraScale = FMax(CameraScale, CurrentCameraScale - 5 * FMax(CameraScale - CurrentCameraScale, 0.3)*fDeltaTime);
    	}*/
    	if (CamDir.Z <= GetCollisionHeight())
    	{
    		CamDir *= square(cos(out_CamRot.Pitch * 0.000000958738)); // 0.0000958738 = 2*PI/65536
    	}
    
    	out_CamLoc = CamStart - CamDir;
    
    	if (Trace(HitLocation, HitNormal, out_CamLoc, CamStart, false, vect(12,12,12)) != None)
    	{
    		out_CamLoc = HitLocation;
    		bObstructed = true;
    	}
    
    
    
    			/* This code is from ActionGam, thanks for fall, for creating this. 
    		 * It will determine back trace collision while closing to walls or sth like thaht*/
    		if (Trace(HitLocation, HitNormal, out_CamLoc, CamStart, false, vect(12,12,12),,TRACEFLAG_Blocking) != None)
    		{
        		DesiredCameraDistance = VSize(HitLocation-CamStart);
        		CurrentCameraDistance = (fDeltaTime < 0.5f) ? FClamp(DesiredCameraDistance * 2 * fDeltaTime + (1 - 2*fDeltaTime) * CurrentCameraDistance,0,DesiredCameraDistance) : DesiredCameraDistance;
    
        		HitLocation = CamStart + Normal(HitLocation-CamStart) * CurrentCameraDistance;
    
    			CameraOffsetRatio = CurrentCameraDistance/VSize(out_CamLoc - CamStart);
    			out_CamLoc = HitLocation;
    			bObstructed = true;
    		}
    
    		else
    		{
        		DesiredCameraDistance = VSize(out_CamLoc-CamStart);
        		CurrentCameraDistance = (fDeltaTime < 0.5f) ? FClamp(DesiredCameraDistance * 2 * fDeltaTime + (1 - 2*fDeltaTime) * CurrentCameraDistance,0,DesiredCameraDistance) : DesiredCameraDistance;
    
    			HitLocation = CamStart + Normal(out_CamLoc - CamStart) * CurrentCameraDistance;
    
    			CameraOffsetRatio = CurrentCameraDistance/VSize(out_CamLoc - CamStart);
    			out_CamLoc = HitLocation;
    		}
    
    		if (Trace(HitLocation, HitNormal, out_CamLoc, CamStart, false, vect(12,12,12)) != None)
    		{
    			out_CamLoc = HitLocation;
    			return false;
    		}
    		
    		/*Again thanks for fall, for this. It just inside character collision detection*/
    		tempCamStart = CamStart;
    		tempCamStart.Z = 0;
    		tempCamEnd = out_CamLoc;
    		tempCamEnd.Z = 0;
    
    		end = out_CamLoc + Normal(vector(out_CamRot))*32768; 
    		CamTrace = Trace(HitLocation, HitNormal, end, out_CamLoc, false);
    
    		PlayerHitTarget = HitLocation;
    
    		PawnEyeLocation = Location + EyeHeight * vect(0,0,1);
    
    		if(bObstructed && (VSize(tempCamEnd - tempCamStart) < CylinderComponent.CollisionRadius*1.25) && (out_CamLoc.Z<Location.Z+CylinderComponent.CollisionHeight) && (out_CamLoc.Z>Location.Z-CylinderComponent.CollisionHeight))
    		{
    			SetHidden(true);
    		}
    		else
    			SetHidden(false);
    
    		return !bObstructed;
    }
    
    
    
    DefaultProperties
    {
    	bShoulderCam = false;
    
    	/*TODO:  Modify camera zoom values to fit your tastes 
    	 * Be sure to set CurrCamZoom/TargetCamZoom to the GlobalCamZoom to prevent the 
    	 * camera from LERPing and giving a weird effect on game start */
    	CurrCamZoom = 5.0
    	TargetCamZoom = 5.0
    	GlobalCamZoom = 5.0
    	ShoulderZoom = 2.5
    
    	/*TODO: Modify Left/Right values to fit your tastes
    	 * Set Curr/Target values to your default values to avoid Lerping without change
    	 */
    	CurrYZoom=-0.5
    	TargetYZoom=-0.5
    	ShoulderYZoom=-1.0
    	NonShoulderYZoom=-0.5
    	/*TODO: Modify FOV values to fit your tastes
    	 * Set Curr/Target values to your default values to avoid Lerping without change
    	 */
    	CurrFOV=90.0
    	TargetFOV=90.0
    	ShoulderFOV=45.0
    	NonShoulderFOV=90.0
    	/*TODO: Modify Z values to fit your tastes
    	 * Set Curr/Target values to your default values to avoid Lerping without change
    	 */
    	CurrZ=0.75
    	TargetZ=0.75
    	ShoulderZ=0.50
    	NonShoulderZ=0.75
    
    
    }

    Player Controller - Allow us some interaction
    Code:
    class REController extends UTPlayerController;
    
    exec function NextWeapon()
    {
    	if(!REPawn(Pawn).bShoulderCam)
    		REPawn(Pawn).GlobalCamZoom += 1.0;
    }
    exec function PrevWeapon()
    {
    	if(!REPawn(Pawn).bShoulderCam)
    		REPawn(Pawn).GlobalCamZoom -= 1.0;
    }
    exec function ShoulderCam()//Set the camera into aim mode.  Decrease FOV and such
    {
    	REPawn(Pawn).bShoulderCam = true;
    }
    exec function ReturnCam() 
    {
    	REPawn(Pawn).bShoulderCam = false;
    }
    
    
    /**
     * Adjusts weapon aiming direction.
     * Gives controller a chance to modify the aiming of the pawn. For example aim error, auto aiming, adhesion, AI help...
     * Requested by weapon prior to firing.
    *
     * @param	W, weapon about to fire
     * @param	StartFireLoc, world location of weapon fire start trace, or projectile spawn loc.
     */
    
    //This function is required otherwise our aim will be off ever so slightly because we don't account for the camera offset in calculation.
    function Rotator GetAdjustedAimFor( Weapon W, vector StartFireLoc )
    {
    	local REPawn P;
    	local Rotator R;
    	local Vector V;
    	P = REPawn(Pawn);
    	// by default, return Rotation. This is the standard aim for controllers
    	// see implementation for PlayerController.
    	if ( Pawn != None )
    	{
    		// Gets the vector for our aim adjustment by taking the result of our HitLocation from running Trace() when our camera updates and subtracting from it our current location
    		V = P.PlayerHitTarget - P.PawnEyeLocation;
    
                    //Cast our Vector to a Rotator
    		R = Rotator(V);
    		
                    //Return our adjusted aim Rotator
    		return R;		
    	}
    	return Rotation;
    }
    
    DefaultProperties
    {
    	bBehindView=true //Required to route camera calculation to our portion of CalcCamera()
    }
    In UDKInput.ini, Find line 29. Find the LeftShift binding
    Code:
    Replace with this...
    Bindings=(Name="LeftShift",Command="ShoulderCam | OnRelease ReturnCam")

    OPTIONAL - Find line 142/RightMouseButton binding
    Code:
    Personally CoD and other random games have spoiled me with a RMB aim feature so this is why I added this little piece. 
    
    Replace with this...
    Bindings=(Name="RightMouseButton",Command="ShoulderCam | OnRelease ReturnCam")

    #2
    Perfect! Thank you so much Shozokui

    Comment


      #3
      can anyone tell me y this dont work when i play on pc it just plays with the default 1st person view any help b great

      Comment


        #4
        the camera works, but how do you make it so that the pawn turns with the camera once zoomed in?

        Comment


          #5
          Originally posted by colin2010 View Post
          can anyone tell me y this dont work when i play on pc it just plays with the default 1st person view any help b great
          The two reasons that come to mind are:

          1.) You're not using the proper game type.
          2.) You haven't initialized bBehindView to true in the default properties.

          Double check that your code is correct and setting bBehindView to true, then open the world properties in the editor and make sure default game for PIE is your game type.

          Comment


            #6
            Originally posted by JmPrsh153 View Post
            the camera works, but how do you make it so that the pawn turns with the camera once zoomed in?
            Double check your code. The camera should not turn independently ever.

            The camera and pawn should rotate simultaneously.

            Comment


              #7
              no sorry the camera does zoom in etc. as it should do but it doesnt like turn my pawn too.

              i want my pawn to always be facing forward etc.

              Comment


                #8
                Is there a way to force the character to walk/slow down while zoomed in, just like GoW? I mean, Left Shift doesn't even work, nor does "RightMouseButton",Command="ShoulderCam | Walking | OnRelease ReturnCam"

                Comment


                  #9
                  Hi
                  This is great!!

                  However, sometimes when i fire the "bullets" do not travel in the direction the character is facing, they go towards the box in the centre of the july build demo level (I think this may be the origin 0,0,0) any ideas??

                  Has anybody else had this problem??

                  Comment


                    #10
                    Edit: Nevermind. Good camera script.

                    Comment


                      #11
                      Originally posted by 3DG View Post
                      However, sometimes when i fire the "bullets" do not travel in the direction the character is facing, they go towards the box in the centre of the july build demo level (I think this may be the origin 0,0,0) any ideas??

                      Has anybody else had this problem??
                      The problem is that PlayerHitTarget gets bad data if your crosshairs are aiming up at the sky, etc.

                      To fix that problem, find this code near the end of CalcCamera( )...
                      Code:
                      CamTrace = Trace( HitLocation, HitNormal, end, out_CamLoc, false );
                      
                      PlayerHitTarget = HitLocation;
                      and change it to this...
                      Code:
                      if( Trace( HitLocation, HitNormal, end, out_CamLoc, false ) != none )
                      	PlayerHitTarget = HitLocation;
                      else
                      	PlayerHitTarget = end;
                      The problem was that HitLocation has unreliable value if the Trace misses. You don't really need the CamTrace actor anyway, so just avoid it.

                      Comment


                        #12
                        Originally posted by Geist
                        The problem is that PlayerHitTarget gets bad data if your crosshairs are aiming up at the sky, etc.

                        To fix that problem, find this code near the end of CalcCamera( )...
                        Code:

                        CamTrace = Trace( HitLocation, HitNormal, end, out_CamLoc, false );

                        PlayerHitTarget = HitLocation;

                        and change it to this...
                        Code:

                        if( Trace( HitLocation, HitNormal, end, out_CamLoc, false ) != none )
                        PlayerHitTarget = HitLocation;
                        else
                        PlayerHitTarget = end;

                        The problem was that HitLocation has unreliable value if the Trace misses. You don't really need the CamTrace actor anyway, so just avoid it.
                        Thanks.

                        While runing the editor with the command line "-log" i can see some errors:

                        Just after start the game in the editor (F8):


                        After typing "quit" in the console:


                        Tested it with one of the map templates of the "New map" dialog using Jully 2011 Beta.

                        Comment


                          #13
                          I confirm the errors above!

                          Comment


                            #14
                            My advice would be to read the errors better. They have script titles in there, but look at what they're trying to do.

                            Partly it's trying to update the minimap in UTGame's GFxHUD. In template levels there is no minimap data to be sent, aka it accessed none.

                            The other part is it's trying to set online status in online subsystems. Aka steam, etc.
                            The "errors" you see aren't actual errors.

                            Comment


                              #15
                              Originally posted by Geist View Post
                              The problem is that PlayerHitTarget gets bad data if your crosshairs are aiming up at the sky, etc.

                              To fix that problem, find this code near the end of CalcCamera( )...
                              Code:
                              CamTrace = Trace( HitLocation, HitNormal, end, out_CamLoc, false );
                              
                              PlayerHitTarget = HitLocation;
                              and change it to this...
                              Code:
                              if( Trace( HitLocation, HitNormal, end, out_CamLoc, false ) != none )
                              	PlayerHitTarget = HitLocation;
                              else
                              	PlayerHitTarget = end;
                              The problem was that HitLocation has unreliable value if the Trace misses. You don't really need the CamTrace actor anyway, so just avoid it.
                              Thank you very much. I had missed that and was trying to pinpoint that problem.

                              Comment

                              Working...
                              X