Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
  • Help Room /
avatar image
0
Question by Hyakkidouran · Oct 31, 2015 at 09:52 AM · rotationcollisiongravity

How to create "Gravity Roads" in a FPS?

For a student project, I have to figure out a way to create "gravity roads". It would be roads to which the player would stick (kinda like cars do in F-zero or other sci-fi racers). A small subtlety is that those roads would also change the gravity accordingly. The demo/exercise will have to be played with standard FPS controls. Jump can be disabled but keeping it would be extra.

I think i have the basic principle : read the normal of the collided polygon, and rotate the gravity and character controller accordingly. I spent some hours to get this :

 void OnControllerColliderHit(ControllerColliderHit hit)
     {
         if ( hit.controller.isGrounded ) {
 
             if (hit.collider.tag == "GravityRoad")
             {
                 isOnGravRoad = true;
                 Debug.Log(currentGravity + " " + currentGravity.magnitude);
 
                 if (hit.normal.normalized != -currentGravity.normalized)
                 {
                     currentGravity = -(hit.normal.normalized) * 9.81f;
                     Physics.gravity = currentGravity;
                 }
 
             }
             else
             {
                 isOnGravRoad = false;
             }
         }
     }

The gravity seems to update. But my character does not rotate and is unable to keep climbing the gravity road once the slope becomes too important.

My theory is that I can't do this with the FPS character provided in default packages, and that I have to code my own. Any input would be welcome, thank you.

Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

3 Replies

· Add your reply
  • Sort: 
avatar image
0

Answer by hexagonius · Oct 31, 2015 at 10:29 AM

You're correct about the CharacterController. It's the one "special" collider in Unity, that doesn't allow rotation, you will need an ordinary capsule collider to mimic that, OR, you fake it by making the CharacterController round by setting it's hight to 0 (or nearly zero, not sure what happens with 0) and only rotate the visual according to surface normal. Using a rigidbody you'd definitely have a lot more work first. I'd also avoid jumping and implement following surfaces first.

Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Hyakkidouran · Nov 04, 2015 at 09:34 PM 0
Share

I am trying to code a whole new controller. Starting slowly, I want to use a sphere as my "player" and try to make it roll on my "gravity road" with the arrow keys.

I am using SphereCast to detect the ground. It seemed to work until i realized the normal of the collided polygon was somehow always vertical, even when the road under the sphere clearly was not.

The road uses $$anonymous$$eshCollider, the sphere uses SphereCollider with Rigidbody.

Here is a screenshot : I draw the normal with a red line. It clearly always remain vertical and doesn't change. https://www.dropbox.com/s/q64q6r8uvol3wf7/unityDebug.jpg?dl=0

Any idea on what is causing this?

avatar image
0

Answer by Hyakkidouran · Nov 05, 2015 at 09:18 AM

Thanks for helping, @Hexagonius. At this point I might as well share my new code. it's probably full of rookie mistakes I might learn how to correct. I copied a few extracts from the original FPS controller and tried to go from there.

 using System;
 using UnityEngine;
 using UnityStandardAssets.CrossPlatformInput;
 using UnityStandardAssets.Utility;
 using Random = UnityEngine.Random;
 
 namespace Assets.Scripts
 {
 
     public class FPS_Control : MonoBehaviour
     {
         [SerializeField] private bool m_IsWalking;
         [SerializeField] private float m_WalkSpeed;
         [SerializeField] private float m_RunSpeed;
         [SerializeField] private float m_StickToGroundForce;
         [SerializeField] private bool m_UseFovKick;
         [SerializeField] private FOVKick m_FovKick = new FOVKick();
         [SerializeField] private float m_GravityMultiplier;
 
         private Camera m_Camera;
         private bool m_Jump;
         private float m_YRotation;
         private Vector2 m_Input;
         private Vector3 m_MoveDir = Vector3.zero;
         private CollisionFlags m_CollisionFlags;
 
         private bool isGrounded = false;
 
         private Transform m_PhysicalBody;
         private Rigidbody m_PhysicalBody_rigidBody;
         private SphereCollider m_PhysicalBody_hitbox;
 
         Vector3 currentGravity;
         bool isOnGravRoad = false;
 
         // Use this for initialization
         private void Start()
         {
             m_PhysicalBody = transform.Find("TestPlayer_Sphere");
             m_PhysicalBody_rigidBody = m_PhysicalBody.GetComponent<Rigidbody>();
             m_PhysicalBody_hitbox = m_PhysicalBody.GetComponent<SphereCollider>();
             currentGravity = Physics.gravity;
         }
 
         private void FixedUpdate()
         {
             m_PhysicalBody_rigidBody.WakeUp();
 
             float speed;
             GetInput(out speed);
             // always move along the camera forward as it is the direction that it being aimed at
             Vector3 desiredMove = transform.forward * m_Input.y + transform.right * m_Input.x;
 
             // get a normal for the surface that is being touched to move along it
             RaycastHit hitInfo;
             Physics.SphereCast(m_PhysicalBody.position, m_PhysicalBody_hitbox.radius, currentGravity.normalized, out hitInfo,
                                (m_PhysicalBody_hitbox.radius+2f) / 2f);
 
             desiredMove = Vector3.ProjectOnPlane(desiredMove, hitInfo.normal).normalized;
 
             Debug.DrawLine(m_PhysicalBody.position + Vector3.zero, m_PhysicalBody.position + desiredMove * 20, Color.green, 1f, false);
 
             // attempt to change the gravity depending on surface
             if (hitInfo.collider != null)
             {
                 if (hitInfo.collider.tag == "GravityRoad")
                 {
                     isOnGravRoad = true;
                     if (hitInfo.normal.normalized != -currentGravity.normalized)
                     {
                         currentGravity = -(hitInfo.normal.normalized) * 9.81f;
                         Physics.gravity = currentGravity;
                     }
 
                 }
                 else
                 {
                     isOnGravRoad = false;
                 }
             }
 
             //Debug.Log(hitInfo.normal);
             Debug.DrawLine(m_PhysicalBody.position + Vector3.zero, m_PhysicalBody.position + hitInfo.normal*20, Color.red, 1f, false);
 
             m_MoveDir.x = desiredMove.x * speed;
             m_MoveDir.z = desiredMove.z * speed;
 
             if (isGrounded)
             {
                 m_MoveDir.y = -m_StickToGroundForce;
             }
             else
             {
                 m_MoveDir += Physics.gravity * m_GravityMultiplier * Time.fixedDeltaTime;
             }
             m_PhysicalBody_rigidBody.MovePosition(m_PhysicalBody_rigidBody.position + m_MoveDir);
 
             UpdateCameraPosition(speed);
         }
 
         private void GetInput(out float speed)
         {
             // Read input
             float horizontal = CrossPlatformInputManager.GetAxis("Horizontal");
             float vertical = CrossPlatformInputManager.GetAxis("Vertical");
 
             bool waswalking = m_IsWalking;
 
             // On standalone builds, walk/run speed is modified by a key press.
             // keep track of whether or not the character is walking or running
             m_IsWalking = !Input.GetKey(KeyCode.LeftShift);
 
             // set the desired speed to be walking or running
             speed = m_IsWalking ? m_WalkSpeed : m_RunSpeed;
             m_Input = new Vector2(horizontal, vertical);
 
             // normalize input if it exceeds 1 in combined length:
             if (m_Input.sqrMagnitude > 1)
             {
                 m_Input.Normalize();
             }
 
             // handle speed change to give an fov kick
             // only if the player is going to a run, is running and the fovkick is to be used
             if (m_IsWalking != waswalking && m_UseFovKick && m_PhysicalBody_rigidBody.velocity.sqrMagnitude > 0)
             {
                 StopAllCoroutines();
                 StartCoroutine(!m_IsWalking ? m_FovKick.FOVKickUp() : m_FovKick.FOVKickDown());
             }
         }
 
     }
 }
Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image
0

Answer by hexagonius · Nov 05, 2015 at 07:20 AM

what value is your debug red line based of? If it's the normal from the collision object, that's always the direction the collision came in from. usually you need to raycast against the collider in that spot to get the actual surface normal

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

39 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

how can I align a rotating block that falls onto another with the correct face? 2 Answers

how would I make a capsule rotate and go down a platform on the y axis? 0 Answers

Rotate the player around the z axis, using a mouse look type script 0 Answers

Glider sim with CharacterController (no rigid body allowed) 0 Answers

Rotate camera on collision of character 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges