• 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 /
avatar image
0
Question by Aggressor · May 01, 2012 at 04:15 AM · movementcharacter controllerrtsisometric

Keeping A Character On The Terrain (Allow no Y movement)

Hello!

I am working on an RTS game with a top-down orthographic camera.

I have the click to move functionality working except for 1 hiccup. I cannot get the character to stay on a height level of 1 only.

Basically I have the character trapped inside a crater and I want him to have to stay in the crater. However when I click to move anywhere he always moves UP the terrain (even if I try clamping the Y value to 1). I haven't added colliders to the terrain yet so I don't care if hes walking through the crater walls at the moment --- I just don't want him walking UP them.

The logs show that even when the Y value is "clamped" to 1, the character still moves in an upward direction along any terrain height. What am I missing to keep this character grounded on a height of 1 max?

Here is the code:

 using UnityEngine;
 using System.Collections;

 public class ClickCharacterController : MonoBehaviour 
 {
    bool canMove = false;
    public int speed = 5;
    RaycastHit hit; //Create an object to store all the raycast data
    Vector3 groundedHitPoint;
 
 void Start()
 {}
 
 
 void Update() 
 {
     if(Input.GetMouseButton(1))
         {    
             //create a new ray from the source point from the camera to the mouse position
             Ray ray = (Camera.main.ScreenPointToRay(Input.mousePosition));
             
             
             //ray is the origin and vector, and out hit is a vector, passing by reference so it needs out keyword
             if (Physics.Raycast(ray, out hit)) 
             {
                 //Debug.Log("Hit: " + hit.transform.name);
                     if (hit.transform.name == "Ground")
                         {
                             Debug.DrawLine(Camera.main.transform.position, hit.point);
                         }
                 //have the cube turn to face the point
                 transform.LookAt(hit.point);
                 groundedHitPoint = hit.point;
                 groundedHitPoint.y = 1;
                 Debug.Log("groundedhitpoint is : " + groundedHitPoint);
                 canMove = true;
             }
         
         }
     if (canMove)
     {
         //this moves an object
         transform.Translate(Vector3.forward*Time.deltaTime*speed);
         Debug.Log ("Vector3.forward is: " + Vector3.forward);
         //GameObject.FindWithTag("ScavengerSprite").transform.position.y.Equals(1000);
         
         float  distance = Vector3.Distance(transform.position, groundedHitPoint);
         if (distance <= 0.1F)
         {
             canMove = false;
         }
     }
     
 }

}

Thank you!

P.S. I am very new to unity so as simple an answer as possible is much appreciated :)

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

2 Replies

· Add your reply
  • Sort: 
avatar image
2
Best Answer

Answer by Seth-Bergman · May 01, 2012 at 04:24 AM

try moving the "transform.LookAt(hit.point);" line to below where you set groundedHitPoint:

       groundedHitPoint = hit.point;
       groundedHitPoint.y = 1;
 transform.LookAt(groundedHitPoint);

that may work, it would fit the simple criteria

edit:

to be sure, you could go a little further.. Instead of the line:

 transform.Translate(Vector3.forward*Time.deltaTime*speed);

use:

     transform.position = Vector3.Lerp(transform.position, groundedHitPoint, Time.deltaTime * speed);
Comment
Add comment · Show 4 · 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 Aggressor · May 01, 2012 at 01:16 PM 0
Share

Thank you for the fresh eyes and laser solution! That worked. I am using this Lerp function and Im going to have to read up on this it looks like something I should know. Thank you Seth!

avatar image Aggressor · May 01, 2012 at 02:49 PM 0
Share

Seth, would you know how to add collision to the terrain? I've tried making a bool trigger event (and I have tagged the terrain as Ground):

 bool OnCollisionEnter (Collision col)
 {
     if (col.GameObject("Ground"))
     {
         return false;
     }
     else 
     {
         return true;
     }
 }

The point of this is to turn off movement off when it collides with the terrain.

However I am getting this error "error CS1061: Type UnityEngine.Collision' does not contain a definition for GameObject' and no extension method GameObject' of type UnityEngine.Collision' could be found (are you missing a using directive or an assembly reference?)"

Any advice?

Thanks again

avatar image Seth-Bergman · May 01, 2012 at 03:23 PM 0
Share

if(col.gameObject.tag == "Ground")

also, I don't think adding a return boolean to the OnCollisionEnter is the way to go:

void OnCollisionEnter (Collision col) {

 if (col.gameObject.tag == ("Ground"))
 {

    can$$anonymous$$ove = false;

     // or 

    Stop$$anonymous$$oving(); // if you need more control

   

}

}

avatar image Aggressor · May 01, 2012 at 05:40 PM 0
Share

Ahh...I've given it my best shot, here is the whole code. Currently getting a null reference error

NullReferenceException: Object reference not set to an instance of an object ClickCharacterController.OnCollisionEnter (UnityEngine.Collision col, Boolean can$$anonymous$$ove) (at Assets/Scripting/ClickCharacterController.cs:18) ClickCharacterController.Update () (at Assets/Scripting/ClickCharacterController.cs:58)

using UnityEngine;

using System.Collections;

public class ClickCharacterController : $$anonymous$$onoBehaviour

{

 bool can$$anonymous$$ove = false;
 public int speed = 5;
 RaycastHit hit; //Create an object to store all the raycast data
 Vector3 groundedHitPoint;
 Collision ground;
 
 void Start()
 {}
 
 
 void OnCollisionEnter (Collision col, bool can$$anonymous$$ove)
 {
     if (col.gameObject.tag == "Ground" )
     {
         can$$anonymous$$ove = false;
     }
     else 
     {
         can$$anonymous$$ove = true;
     }
 }
 
 
 void Update() 
 {
     if(Input.Get$$anonymous$$ouseButton(1))
         {    
             //create a new ray from the source point from the camera to the mouse position
             Ray ray = (Camera.main.ScreenPointToRay(Input.mousePosition));
             
             
             //ray is the origin and vector, and out hit is a vector, passing by reference so it needs out keyword
             if (Physics.Raycast(ray, out hit)) 
             {
                 //Debug.Log("Hit: " + hit.transform.name);
                     if (hit.transform.name == "Ground")
                         {
                             Debug.DrawLine(Camera.main.transform.position, hit.point);
                         }
                 //have the cube turn to face the point
                 
                 groundedHitPoint = hit.point;
                 groundedHitPoint.y = 1;
                 transform.LookAt(groundedHitPoint);
                 //Debug.Log("groundedhitpoint is : " + groundedHitPoint);
                 can$$anonymous$$ove = true;
             }
         
         }
     if (can$$anonymous$$ove)
     {
         //check for terrain collision
         OnCollisionEnter(ground, can$$anonymous$$ove);
         
         //this moves an object
         transform.Translate(Vector3.forward*Time.deltaTime*speed);
         //Debug.Log ("Vector3.forward is: " + Vector3.forward);
         //GameObject.FindWithTag("ScavengerSprite").transform.position.y.Equals(1000);
         
         float  distance = Vector3.Distance(transform.position, groundedHitPoint);
         if (distance <= 0.1F)
         {
             can$$anonymous$$ove = false;
         }
     }
     
     
     
 }
 

}

avatar image
0

Answer by Seth-Bergman · May 02, 2012 at 12:33 AM

you don't need to pass "canMove" into the collision function.

 void OnCollisionEnter (Collision col)
 {
     if (col.gameObject.tag == "Ground" )
     {
        canMove = false;
     }
    
 }

the var "canMove" is part of the same script, so it's already accessible.Next:

OnCollisionEnter(ground, canMove);

this line is unnecessary; OnCollisionEnter is automatically entered every time the collider attached to the object hits another collider.

so :

 using UnityEngine;
 
 using System.Collections;
 
 public class ClickCharacterController : MonoBehaviour
 
 {
 
 bool canMove = false;
 public int speed = 5;
 RaycastHit hit; //Create an object to store all the raycast data
 Vector3 groundedHitPoint;
 
 
 void Start()
 {}
 
 
 void OnCollisionEnter ()
 {
     if (col.gameObject.tag == "Ground" )
     {
        canMove = false;
     }
     //else 
     //{
        //canMove = true;
     //}
 }
 
 
 void Update() 
 {
     if(Input.GetMouseButton(1))
         {  
          //create a new ray from the source point from the camera to the mouse position
          Ray ray = (Camera.main.ScreenPointToRay(Input.mousePosition));
 
 
          //ray is the origin and vector, and out hit is a vector, passing by reference so it needs out keyword
             if (Physics.Raycast(ray, out hit)) 
          {
                 //Debug.Log("Hit: " + hit.transform.name);
               if (hit.transform.name == "Ground")
                  {
                    Debug.DrawLine(Camera.main.transform.position, hit.point);
                  }
           //have the cube turn to face the point
 
           groundedHitPoint = hit.point;
           groundedHitPoint.y = 1;
           transform.LookAt(groundedHitPoint);
           //Debug.Log("groundedhitpoint is : " + groundedHitPoint);
           canMove = true;
            }
 
        }
     if (canMove)
     {
 
        //this moves an object
        transform.Translate(Vector3.forward*Time.deltaTime*speed);
        //Debug.Log ("Vector3.forward is: " + Vector3.forward);
        //GameObject.FindWithTag("ScavengerSprite").transform.position.y.Equals(1000);
 
        float  distance = Vector3.Distance(transform.position, groundedHitPoint);
        if (distance <= 0.1F)
        {
          canMove = false;
        }
     }
 
 }
Comment
Add comment · Show 6 · 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 Aggressor · May 02, 2012 at 02:11 AM 0
Share

Thanks I'll keep hammering away at this till I get it! (Right now its not even registering terrain collision (using a debug.log check). Thanks though your help has definitely put me on the right track!

avatar image Seth-Bergman · May 02, 2012 at 02:24 AM 0
Share

hmmm.. isTrigger isn't checked, is it (on the player or the terrain)? It shouldn't be for OnCollisionEnter.. also, I think the player shouldn't be kinematic, that might do it too.. Are you using a character controller, or a collider? If it's a collider, rather than a controller, I think you need a rigidbody too.. Just noticed the original post says you haven't added colliders yet, both objects would need one for this to work.

avatar image Aggressor · May 02, 2012 at 12:27 PM 0
Share

I have an empty game object which has the click to move script. In that I have the herosprite+collider nested in that empty game object I have the script attached to the empty object (which I used to orient the feet at ground level. (though the same happens when I just have the script on just the herosprite+collider).

So the object's child (the hero sprit) has the collider and the empty object has the click to move script. The terrain does not have istrigger checked.

When I add a rigid body it doesn't go through the wall, but it ends up bouncing ridiculously high and all over the place. Sometimes straight up and over. I don't know if theres a particular tutorial or walkthrough you might suggest I look into that explains collisions (the reference manual was not quite helping me). Thanks

avatar image Seth-Bergman · May 02, 2012 at 12:43 PM 0
Share

does the collision function get entered once you attach the rigidbody?

I think you need the script on the same object as the collider, don't feel like it would work as you describe.. how about attaching the collider to the parent (empty) object?

either way, the alternative is to use a trigger ins$$anonymous$$d, which I believe does not need a rigidbody at any rate, if you don't want one change OnCollisionEnter to OnTriggerEnter and set one of the objects to isTrigger, that should work.. Still need to get the script on the same object though, I'm pretty sure

avatar image Aggressor · May 03, 2012 at 01:37 AM 0
Share

Im going to have my professor look at this tomorrow. If the answer turns up Ill update you. If not, Ill give a full situation rep :)

Show more comments

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.

Welcome to Unity Answers

If you’re new to Unity Answers, please check our User Guide to help you navigate through our website and refer to our FAQ for more information.

Before posting, make sure to check out our Knowledge Base for commonly asked Unity questions.

Check our Moderator Guidelines if you’re a new moderator and want to work together in an effort to improve Unity Answers and support our users.

Follow this Question

Answers Answers and Comments

4 People are following this question.

avatar image avatar image avatar image avatar image

Related Questions

RTS movement with walking animation. 1 Answer

Moving forward towards the cursor with LookAtMouse? 0 Answers

How to fix horizontal movement code causing fast speed bug? 0 Answers

Player movement ignores some collision 0 Answers

Merging pathfinding and following the player Scripts 0 Answers


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