Search Unity

  1. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice
  2. Unity is excited to announce that we will be collaborating with TheXPlace for a summer game jam from June 13 - June 19. Learn more.
    Dismiss Notice

Push a character from an enemy (Knockback) [SOLVED]

Discussion in 'Scripting' started by Teriki Tora, Aug 11, 2010.

  1. Teriki Tora

    Teriki Tora

    Joined:
    May 21, 2010
    Posts:
    132
    Ok, I've tried a couple of things, and because of my lack of coding skills (I have some, but they're still lacking), I have yet to figure out how to repel my character away from my enemies when I touch them... Although, even by grabbing the part of the script that forces my character up when I jump, and placing it in the spot where I want my character to move, it won't move my character.

    (Bouncing on top of an enemy)
    Code (csharp):
    1.  
    2. function OnControllerColliderHit (hit : ControllerColliderHit)
    3. {
    4. if (hit.gameObject.tag == "Enemy")
    5. {
    6. var hitVec = hit.point - transform.position;
    7.    if (hitVec.y < -0.3) {
    8.      moveDirection.y = jumpSpeed;
    9.      jumping = true;
    10.       hit.gameObject.SendMessage("Kill", SendMessageOptions.DontRequireReceiver);
    11.       Debug.Log("I killed it!");
    12.       }
    13.    }
    14. }
    15.  
    That piece of code is in the same script as my walking stuff (jumping and that stuff). But it refuses to push my character upwards.

    In addition to that, I want my enemies to push me away in a similar manner to the above code, but in the reverse direction that I entered the trigger. (Y direction will only be up, even when under an enemy for whatever reason) --- That's right, I said trigger. I couldn't fix the Lerps' script to work with enemy touching so I just said "#*$^ it! I'm using a trigger!", so now enemy damage gets applied via an OnTriggerEnter event, not an OnColliderCollisionHit event.


    ---I have checked other threads and I have looked for something similar to this, but they all use rigidbodies. I cannot use rigidbody movement with the Character controller, and even with one attached, it ignores rigidbody movement in-script.
     
  2. Teriki Tora

    Teriki Tora

    Joined:
    May 21, 2010
    Posts:
    132
    Anyone know how to move a the character controller forcefully in an external (enemy) or internal (player) Script? I have to be passing over a variable or function or something that forces my character in a certain movement direction. I've checked Tutorials, but whenever a character gets hit in the Unity Tutorials (Lerps and the 2D Tut), he just keeps going forward (Or backward, or however the player was originally moving the character).
     
  3. Kokumo

    Kokumo

    Joined:
    Jul 23, 2010
    Posts:
    416
    Maybe you find a clue using OnCollisionEnter.

    You can addForce to a rigidbody, so if your character has a rigidbody attached, you could do it on collision enter.

    If you still don't know how, i will try to answer with an example.

    Greets.
     
  4. Teriki Tora

    Teriki Tora

    Joined:
    May 21, 2010
    Posts:
    132
    Due to a previous problem I cannot use OnCollisionEnter. Because if I try to use OnCollisionEnter, it won't register collision. Which is why I need to use OnControllerColliderHit.

    And even with a rigidbody attached to my player, I cannot use rigidbody.AddForce as I've already mentioned

     
  5. Teriki Tora

    Teriki Tora

    Joined:
    May 21, 2010
    Posts:
    132
    As I still try to get this to work, what confuses me the most is the fact that I can't apply a force to my attached rigidbody (collider.attachedRigidbody.AddForce(0,5,0);) Using the same code as above, only exchanging the "moveDirection.y = jumpSpeed;
    jumping = true; " piece with the AddForce Piece, it'll hit that section of code and say I have a NullReferenceException, even when I have a rigidbody attached. This NullReference also pops up when I tell it which rigidbody to use (transform.Find("Player").rigidbody.AddForce(0,5,0);)

    Yes, I have tried "collider.attachedRigidbody.AddForce(0,5,0,ForceMode.Force);", same reaction.

    And before you say it... Yes I have a rigidbody attached >.> If you want proof I'll screenshot it if I have to.
     
  6. Teriki Tora

    Teriki Tora

    Joined:
    May 21, 2010
    Posts:
    132
    Well, yesterday, me and my instructor took a whack at the problem. We got a piece of the Lerpz script to work. However, we noticed that the Lerpz script only really worked with the Lerpz script. Which meant that I needed to scrap 60% of the code that was already in place in my game for code that was clunky, bulky, and not very well understood (That and it screwed up the camera). However, we did find that the Lerpz system would work so that means we were on the right track.

    So then, I'm looking for a simplified version (or at least an explanation of what this is doing) of this:

    Within the the enemy's code:
    Code (csharp):
    1. function OnTriggerEnter(col : Collider){
    2. //Debug.Log("Trigger Used");
    3. //Make sure it's the player and nothing else.
    4. if(col.gameObject.tag == "Player")
    5. {
    6. //Make sure the player's not in Invincible mode
    7. if (ThirdPSWalker.invincible == false)
    8.     {
    9.     if (Time.time > lastHitTime + 1.00 )
    10.         {
    11. //Apply the damage
    12.         target.SendMessage("ApplyDamage", 1, SendMessageOptions.DontRequireReceiver);
    13.  
    14. //This is the Lerpz code that worked in a certain respect
    15. var slamDirection = transform.InverseTransformDirection(target.position - transform.position);
    16.             slamDirection.y = 0;
    17.             slamDirection.z = 1;
    18.             if (slamDirection.x >= 0)
    19.                 slamDirection.x = 1;
    20.             else
    21.                 slamDirection.x = -1;
    22.             target.SendMessage("Slam", transform.TransformDirection(slamDirection));
    23.          lastHitTime = Time.time;
    24.         }
    25.     }
    26.     }
    27. }
    And this is within my Third Person Walker Script:
    I'm looking for this to be simplified

    Code (csharp):
    1. function Slam (direction : Vector3)
    2. {
    3.    
    4.     verticalSpeed = CalculateJumpVerticalSpeed (1);
    5.     inAirVelocity = direction * 6;
    6.     direction.y = 0.6;
    7.     Quaternion.LookRotation(-direction);
    8.     var controller : CharacterController = GetComponent(CharacterController);
    9.     collisionFlags = CollisionFlags.None;
    10.     SendMessage("DidJump", SendMessageOptions.DontRequireReceiver);
    11. }
    I have... Absolutely no idea what that does :/ But either way, it's using variables that I don't have in my script, so I at least need that simplified in order to utilize it (because it did work, but I needed to take way too much script from the Lerpz code, and when I did it screwed up my camera).
     
  7. Teriki Tora

    Teriki Tora

    Joined:
    May 21, 2010
    Posts:
    132
    Still not done with this, and I'm not going to let the topic die till I get some help done on this script >.> With this being the ONLY script that I need done (Cause the other stuff such as loading levels, and using the talking/reading GUI is super-simple), I'm not going to leave it alone until I can get this thing to work.
     
  8. dbp

    dbp

    Joined:
    Mar 3, 2010
    Posts:
    324
    we cannot simplify anything that is not working correctly. seeing only those small pieces of some copied code won't make it very easy for us to help you either.

    i think your problem is that you are trying to copy big pieces of code that you don't fully understand. because the copied pieces of code are so big, there are maybe 3-4 things in that piece, which don't work together with your already existing code, which will make it alot harder for you to fix any of them.
    somewhere along your posts here i have kind of lost track of which pieces of code you are currently using and which ones are working at all.
    you should post all your movement script here, if you want to make it easier for us to help you, because right now, i wouldn't even know where to start.
     
  9. Teriki Tora

    Teriki Tora

    Joined:
    May 21, 2010
    Posts:
    132
    Hm, alright, sounds fair. Especially when sometimes tidbits of codes can't tell a lot.

    This is the enemy trigger code. The trigger is set up where if I enter it at the side (and I don't land on top of an enemy) I will take damage.
    Code (csharp):
    1. var target : Transform;
    2. var damage = 1;
    3. private var lastHitTime = 0.0;
    4.  
    5. function Start ()
    6. {
    7.    if (!target)
    8.       target = GameObject.FindWithTag("Player").transform;
    9. }
    10.  
    11.  
    12. function OnTriggerEnter(col : Collider){
    13. //Make sure it's the player and nothing else.
    14. if(col.gameObject.tag == "Player")
    15. {
    16. //Make sure the player's not in Invincible mode
    17. if (ThirdPSWalker.invincible == false)
    18.     {
    19.     if (Time.time > lastHitTime + 1.00 )
    20.         {
    21. //Apply the damage
    22.         target.SendMessage("ApplyDamage", 1, SendMessageOptions.DontRequireReceiver);
    23. //This part should (like in the Lerpz Tutorial) declare how to push my character and send the variable.
    24. var slamDirection = transform.InverseTransformDirection(target.position - transform.position);
    25.             slamDirection.y = 0;
    26.             slamDirection.z = 1;
    27.             if (slamDirection.x >= 0)
    28.                 slamDirection.x = 1;
    29.             else
    30.                 slamDirection.x = -1;
    31.             target.SendMessage("Slam", transform.TransformDirection(slamDirection));
    32.          lastHitTime = Time.time;
    33.         }
    34.     }
    35.     }
    36. }
    37.  
    38.  
    This is my "ThirdPSWalker" script. It's a recreation of the FPSWalker script because I'm only using basic movements.
    Code (csharp):
    1. var speed = 6.0;
    2. var jumpSpeed = 8.0;
    3. var gravity = 20.0;
    4. var rotateSpeed = 3.0;
    5.  
    6. private var verticalSpeed = 0.0;
    7. private var inAirVelocity = Vector3.zero;
    8.  
    9. static var isControllable : boolean = true;
    10. static var invincible : boolean= false;
    11.  
    12. private var moveDirection = Vector3.zero;
    13. private var grounded : boolean = false;
    14.  
    15. //Are We Jumping?
    16. private var jumping = false;
    17. private var jumpingReachedApex = false;
    18. private var lastJumpStartHeight = 0.0;
    19.  
    20. function FixedUpdate() {
    21.  
    22. if (grounded) {
    23.         // We are grounded, so recalculate movedirection directly from axes
    24.         moveDirection = new Vector3(0, 0, Input.GetAxis("Vertical"));
    25.         moveDirection = transform.TransformDirection(moveDirection);
    26.         moveDirection *= speed;
    27.         jumping = false;
    28.        
    29.         if (Input.GetButton ("Jump")) {
    30.             moveDirection.y = jumpSpeed;
    31.             jumping = true;
    32.         }
    33.     }
    34.  
    35.  
    36.     // Apply gravity
    37.     moveDirection.y -= gravity * Time.deltaTime;
    38.    
    39.     // Move the controller
    40.     var controller : CharacterController = GetComponent(CharacterController);
    41.     var flags = controller.Move(moveDirection * Time.deltaTime);
    42.     transform.Rotate(0, Input.GetAxis("Horizontal") * rotateSpeed * Time.deltaTime, 0);
    43.     grounded = (flags  CollisionFlags.CollidedBelow) != 0;
    44. }
    45.  
    46. private var lastHitTime = 1.0;
    47.  
    48. function OnControllerColliderHit (hit : ControllerColliderHit)
    49. {
    50. if (hit.gameObject.tag == "Enemy")
    51. {
    52. var hitVec = hit.point - transform.position;
    53.    if (hitVec.y < -0.3) {
    54.       hit.gameObject.SendMessage("Kill", SendMessageOptions.DontRequireReceiver);
    55. collider.attachedRigidbody.AddForce(0,5,0);
    56.       Debug.Log("I killed it!");
    57.       }
    58.       else
    59.       {
    60. /* Don't worry about this, it worked, but my respawn script didn't like it.
    61. if (!invincible)
    62.     {
    63.     if (Time.time > lastHitTime + 1.00 )
    64.         {
    65.         SendMessage("ApplyDamage", 1, SendMessageOptions.DontRequireReceiver);
    66.          lastHitTime = Time.time;
    67.         }
    68.     }*/
    69.    //return;
    70.    }
    71.    }
    72. }
    73.  
    74. //This function is from the Lerpz Controller
    75. function CalculateJumpVerticalSpeed (targetJumpHeight : float)
    76. {
    77.     // From the jump height and gravity we deduce the upwards speed
    78.     // for the character to reach at the apex.
    79.     return Mathf.Sqrt(2 * targetJumpHeight* gravity);
    80. }
    81.  
    82. //This function is from the Lerpz Controller
    83. function Slam (direction : Vector3)
    84. {
    85.     verticalSpeed = CalculateJumpVerticalSpeed (1);
    86.     inAirVelocity = direction * 6;
    87.     direction.y = 0.6;
    88.     Quaternion.LookRotation(-direction);
    89.     var controller : CharacterController = GetComponent(CharacterController);
    90.     collisionFlags = CollisionFlags.None;
    91.     //SendMessage("DidJump", SendMessageOptions.DontRequireReceiver); */
    92. }
    93.  
    94.  
    95. //Don't worry about these, these hide and show the meshes on my character when I respawn.
    96. function HidePlayer()
    97. {
    98.      var EyeL = GameObject.FindWithTag("EyeL");
    99.      var EyeR = GameObject.FindWithTag("EyeR");
    100.       EyeL.GetComponent(MeshRenderer).enabled = false;
    101.       EyeR.GetComponent(MeshRenderer).enabled = false;
    102.       for (var child : Transform in transform) {
    103.       if (child.GetComponent(SkinnedMeshRenderer))
    104.     child.GetComponent(SkinnedMeshRenderer).enabled = false;
    105.     } // stop rendering the player.
    106.     isControllable = false; // disable player controls.
    107. }
    108.  
    109. // This is a complementary function to the above. We don't use it in the tutorial, but it's included for
    110. // the sake of completeness. (I like orthogonal APIs; so sue me!)
    111.  
    112. function ShowPlayer()
    113. {
    114.      var EyeL = GameObject.FindWithTag("EyeL");
    115.      var EyeR = GameObject.FindWithTag("EyeR");
    116.       EyeL.GetComponent(MeshRenderer).enabled = true;
    117.       EyeR.GetComponent(MeshRenderer).enabled = true;
    118.       for (var child : Transform in transform) {
    119.       if (child.GetComponent(SkinnedMeshRenderer))
    120.     child.GetComponent(SkinnedMeshRenderer).enabled = true;
    121.     } // start rendering the player again.
    122.     isControllable = true;  // allow player to control the character again.
    123. }
    124.  
    125. @script RequireComponent(CharacterController)
     
  10. Teriki Tora

    Teriki Tora

    Joined:
    May 21, 2010
    Posts:
    132
    Still pushing this concept. I haven't gotten anywhere thus far due to my classes, and I'm still at a dead-end at the moment (No I will not let this die... well until a solution is found).
     
  11. Teriki Tora

    Teriki Tora

    Joined:
    May 21, 2010
    Posts:
    132
    The only thing that I've gotten to work was:
    Code (csharp):
    1.  
    2. var player = GameObject.FindWithTag("Player");
    3. player.transform.Translate (0, 1, -2);
    4.  
    But that moves the player two units away from my enemy (like a teleport), it doesn't push the player away in this direction. I need a force applied to the character controller in the same way that it looks for the buttons, so that it moves it correctly. (Not even the programmer in the class knows how to do it... :/)

    ---There needs to be a way to get a rigidbody to work along-side the character controller... I don't see any other way.

    I have found a way to get the rigidbody to work, BUT, I need some more code tweaking. So close!
    (I can't get it to use the rigidbody again. Sigh...)
     
  12. Vimalakirti

    Vimalakirti

    Joined:
    Oct 12, 2009
    Posts:
    755
    Same as the guy in the newer post, you can't use rigidbody physics on your character with a character controller. Don't work, won't work, ain't gonna happen. So there's two ways to do it:

    1) "manually" with transform.position changes. Use a Lerp function so that the character slides instead of teleports.

    2) make a copy of your character and make a new prefab of that. Replace the character controller with a rigidbody in the copy. When your character needs to move put your prefab copy in the same place, rotation, etc. then hide the original (put it under the terrain so you don't need to destroy it and reset all the scripts) for a second while the physics movement happens. Finally put your original where the copy now is, and destroy the copy. Search for 'ragdoll' for more information.

    That's the best I can do. Maybe somebody else has a better way.
     
  13. Teriki Tora

    Teriki Tora

    Joined:
    May 21, 2010
    Posts:
    132
    Eh, you're right, I'm going to have to go back to character controller movement... Problem is, nothing wants to work other than transform.Translate.

    player.transform.position gives me an error
     
  14. Teriki Tora

    Teriki Tora

    Joined:
    May 21, 2010
    Posts:
    132
    Finally, figured it out :3

    Assuming you're using the FPSWalker script (or a modified one to make it a Third Person Controller), using the FixedUpdate (Or Update, doesn't entirely matter) you can fake a force by moving around a bit of code:

    Code (csharp):
    1.  
    2. var controller : CharacterController = GetComponent(CharacterController);
    3.     var flags = controller.Move(moveDirection * Time.deltaTime);
    4.     transform.Rotate(0, Input.GetAxis("Horizontal") * rotateSpeed * Time.deltaTime, 0);
    5.     grounded = (flags  CollisionFlags.CollidedBelow) != 0;
    6.  
    Thereby adding a while loop to constantly apply a force for a few frames to give the effect of a knockback:

    Code (csharp):
    1.  
    2. var controller : CharacterController = GetComponent(CharacterController);
    3.     if(slammed == true)
    4.     {
    5.     moveDirection = new Vector3(0, 1,-.5);
    6.     moveDirection = transform.TransformDirection(moveDirection);
    7.     moveDirection *= speed;
    8.     var flags = controller.Move (moveDirection * Time.deltaTime);
    9.     if (Time.time > lastHitTime + 0.25 ){
    10.     slammed = false;
    11.     }
    12.     }
    13.     flags = controller.Move(moveDirection * Time.deltaTime);
    14.     transform.Rotate(0, Input.GetAxis("Horizontal") * rotateSpeed * Time.deltaTime, 0);
    15.     grounded = (flags  CollisionFlags.CollidedBelow) != 0;
    16.  
    I can apply the same method using a bounce off of the enemy's top :3 (Just copying a lot more script than I need)