Search Unity

collisions - help with "is trigger"

Discussion in 'Editor & General Support' started by psx, Aug 25, 2005.

  1. psx

    psx

    Joined:
    Aug 25, 2005
    Posts:
    80
    I'm just getting started with a basic prototype for a soccer game. One thing I'm stuck on is how to make the player kick the ball. I'm starting out very simple with the prefab fps controller.

    What I'm looking for is when the player is touching the ball (or better yet, within a few inches of the ball) he can press the mouse button and kick the ball.

    So far, I've tried simply setting "is trigger" on for the ball, but this makes it fall through my floor.

    I have some ideas about how to do it, but don't know how to actually implement them in Unity.

    My first idea is to somehow attach an invisible "foot" to the fps controller prefab. Essentially this would be a brick attached to the bottom-front area of the controller pill. So whenever the ball hits this brick, the player can kick the ball.

    I think I can figure out the kick action (apply some force to the ball in the direction the player is looking) but where I'm stuck is how to attach the foot to the player, and then get the collision event(s) and do something with them. I'm thinking here I'll have a script attached to either the player or possibly the foot.

    Also, I'm going to need 2 goal models that need to know when they've been hit by the ball. Again, I'm thinking an invisible cube inside the goal.

    I guess I'm just looking for advice/best-practices for this sort of stuff. Any feedback would be greatly appreciated!

    thanks!
    psx
     
  2. psx

    psx

    Joined:
    Aug 25, 2005
    Posts:
    80
    ok... I'm taking a break from kicking right now and working on the goal stuff.

    Here's what I have, but it isn't working:

    a large cube and a ball. I have a script attached to the cube with this function:
    Code (csharp):
    1.  
    2. function onTriggerEnter(c) {
    3.      print("trigger: "+ c);
    4. }
    5.  
    "is trigger" is checked for the cube. Anyone have any ideas why this doesn't print when the ball rolls into and through the cube?

    thanks!
    psx
     
  3. freyr

    freyr

    Joined:
    Apr 7, 2005
    Posts:
    1,148
    the function should be called OnTriggerEnter.

    Javascript is case-sensitive, so it matters how things are capitalised.
     
  4. psx

    psx

    Joined:
    Aug 25, 2005
    Posts:
    80
    Woot! Thanks. I can't believe I didn't think of that. I'm so used to not capitalizing function names.

    Any tips on how I can attach the "foot" to my player? I'm guessing something to do with the parent/child object relationships but I don't know where to look/start.

    thanks again!
    psx
     
  5. Jonathan Czeck

    Jonathan Czeck

    Joined:
    Mar 17, 2005
    Posts:
    1,713
    How much realism are you going for, here?

    There are just so many ways to set this up...

    I think the way I'd go about it is have 1 animated mesh, with lots of different animation clips for run, jump, etc...

    Then use triggers to know if the ball is within reach of the player, then link it up with the player using a script.

    This really wouldn't be trivial... might not be the best place to start. :/

    If it were me I'd probably start with a Box that is the player and a ball. I'd focus on just getting the box moving around right first.

    Hope I helped more than confused.
    -Jon
     
  6. psx

    psx

    Joined:
    Aug 25, 2005
    Posts:
    80
    Thanks Aarku.. that's where I'm heading. I'm not worrying at all about realism as far as graphics/models goes. Like I said, my player is simply the capsule/prefab. fps controller.

    What I need to do is link a "foot" to the capsule somehow, and then when that hits the ball, allow the user to initiate a kick. I just don't understand how to link things together.

    Another issue I'm running into...

    I have my ball successfully hitting my goal areas. I've created an empty object and attached a script called "GameController" to it. GameController's job is going to be updating the GUI scoreboard when goals are scored. Where I'm stuck is getting something like this to work from within the script on my goals.

    GameController.updateScoreBoard(teamName, score);

    I get an error saying that it needs an instance of GameController. As it stands... my entire GameController.js script looks like so:

    Code (csharp):
    1.  
    2. function updateScoreBoard(team, score) {
    3.       print("yay!");
    4. }
    5.  
    psx
     
  7. psx

    psx

    Joined:
    Aug 25, 2005
    Posts:
    80
    Woohoo!

    I'm slowly getting there! I've solved most of the issues mentioned above.

    Web-player version:
    http://johnrobinson.dyndns.org/unity/soccer/

    project source (45mb):
    http://johnrobinson.dyndns.org/unity/soccer/soccer_a_0.zip


    I still have questions but I'm not sure if I should start a seperate thread or not.

    1) I still can't get access to GameController. I can find it, but can't seem to call any functions on it.

    2) I'm sure it's in the docs somewhere, but I don't know where to look. Is there an easy way to hide the cursor? It's frustrating trying to look/move when I keep clicking off the page/game-screen.

    3) How do I make the hitboxes inside the goals as well as the 'foot' box transparent?

    4) I have 2 goal boxes. Each has a copy of 'GoalScript' attached. In that script, I have a var 'score'. This is supposed to increase each time that goal is hit, but what's happening is that the var is acting global. It increases each time any goal is hit. IOW.. I assumed the goal var would be unique to each instance of the script but it apparently isn't. Any ideas?


    thanks again!
    psx
     
  8. DaveyJJ

    DaveyJJ

    Joined:
    Mar 24, 2005
    Posts:
    1,558
    Just create an empty game object and add a box collider to it. Adjust the size of the box x-y-z and voila ... transparent box.

    Another way to solve the issue of a box is not to use a box but have your ball check if it's inside a defined "goal" space as a series of coordinates that are checked in one long statement, like this ...

    Code (csharp):
    1.  
    2. if (soccerball.position.x < -6.4  soccerball.position.z > -5.1  soccerball.position.z < 2.5  soccerball2.position.x < -6.4  soccerball2.position.z > -5.1  soccerball2.position.z < 2.5) {
    3.         dosomethinghere;
    4.     }  
    5. }
    This way you can just keep stringing conditions into the script to check for further things (like a y coordinate, another obejct, etc. In this case, "soccerball" awas declared like this outside of thre function

    Code (csharp):
    1.  
    2. var soccerball : Transform;
    3.  
    At least I was able to ansswer one question.
     
  9. freyr

    freyr

    Joined:
    Apr 7, 2005
    Posts:
    1,148
    Have you attached the script to a game object? Otherwise you can't call methods on it.

    Unless you have defined the variable as static, it should be different for each instance.
     
  10. psx

    psx

    Joined:
    Aug 25, 2005
    Posts:
    80
    Thanks again.

    DaveyJJ -

    I tried your first suggestion but couldn't get it working. I did solve the issue though by simply creating a new material with a base color that is transparent. What's neat is that (I think) by script I can toggle that material for debugging.

    I thought about something similar to your second idea (long 'if' statement) but I figured since the engine is already handling collisions for me that it'd be easier to just use 'is trigger' and his buddies. Hopefully it is faster that way as well.

    Is this Javascript? I come from the flash world and since AS2, we can type variables. I'm guessing that is what this line does but just wanted to verify.


    freyr -

    I created an empty object and named it GameController. Then I attached my script to it. Here's my entire GoalScript:

    Code (csharp):
    1.  
    2. var score = 0;
    3.  
    4. function OnTriggerEnter(t) {
    5.     // if it's the ball... score!
    6.     if(t.name == "redball") {
    7.         score ++;
    8.         // should notify gameController
    9.         // which should reset players and increase score display
    10.         // var gc = GameObject.FindGameObjectWithTag("GameController");
    11.         // gc.updateScoreBoard(this.name, score);
    12.     }
    13. }
    14.  
    and my GameController script:

    Code (csharp):
    1.  
    2. function updateScoreBoard(team, score) {
    3.    
    4.     if(team == "HitTest Goal Blue") {
    5.    
    6.     } else if(team == "Hit Test Goal Red") {
    7.    
    8.     }
    9. }
    10.  
    11. // reset scoreboards, player positions, round timers, etc.
    12. function startGame() {
    13.    
    14. }
    15.  
    I get an error saying that updateScoreBoard is not a member of GameController.

    For the score var... is there something different I should be doing?

    Also.. is there an easier way to access the object than via "FindGameObjectWithTag"?

    Finally... one new question. If I get GameController working, I then need to be able to update one of 2 GUIText objects to display the score for each team. I have added the text to the gui easy enough but don't know how to access them. My initial thought is something like this:

    Code (csharp):
    1.  
    2. gameObject.GUILayer.RedScoreText.text = "Red: "+redScore;
    3.  
    I haven't tried the above yet but wondered if it was even remotely close or if I have to use "FindGameObjectWithTag".

    psx
     
  11. freyr

    freyr

    Joined:
    Apr 7, 2005
    Posts:
    1,148
    FindGameObjectWIthTag returns a GameObject, not an instance of your script class. You will either need to call
    Code (csharp):
    1.  
    2.  go=FindObjectWithTag("TheTag");
    3.  var myScriptObj: yourScriptName = go.GetComponent(yourScriptName) ;
    4. myScriptObj.UpdateScore(42);
    5.  
    Or use SendMessage to let the game object take care of calling your method:
    Code (csharp):
    1.  
    2.  go=FindObjectWithTag("TheTag");
    3.  go.SendMessage("UpdateScore", 42);
    4.  
     
  12. freyr

    freyr

    Joined:
    Apr 7, 2005
    Posts:
    1,148
    Almost forgot... the third way is to have a variable in the calling class of type GameController, and then drag the GameController object to it in the inspector:

    Code (csharp):
    1.  
    2. var gc : GameController;
    3.  
    4. // ....
    5. gc.UpdateScore(42);
    6.  
    7.  
     
  13. psx

    psx

    Joined:
    Aug 25, 2005
    Posts:
    80
    thanks freyr!! I ended up using the last option and it works great!

    Now.. on to updating the gui/hud... any thoughts?

    EDIT: Duh! Figured it out. I just used the same technique as for finding the GameController. ex. var redScore : GUIText;

    psx
     
  14. psx

    psx

    Joined:
    Aug 25, 2005
    Posts:
    80
    On to making bots to play with/against...

    I'm taking a wild guess here. Does simply making a js script create a class with the name of the script? ie... this would be a BotPlayer class, assuming my script is named "BotPlayer"?

    Code (csharp):
    1.  
    2.  
    3. var someVar = "blah";
    4. var team = "Blue";
    5.  
    6. function findBall() {
    7.  
    8. }
    9.  
    10. function moveToPoint() {
    11.    
    12. }
    13. //... etc.
    14.  
    15.  
    And if so... how would I subclass it for say, a defense specific bot?

    something like this?

    Code (csharp):
    1.  
    2.  
    3. this.prototype = BotPlayer;
    4.  
    5. function defendGoal() {
    6.  
    7. }
    8. //... etc
    9.  
    10.  
    psx
     
  15. psx

    psx

    Joined:
    Aug 25, 2005
    Posts:
    80
    I still haven't even tried the class thing mentioned above, but I did manage to get some bots in there and somewhat functional. They do some weird things, especially when the ball gets up above their heads.

    latest web-player:
    http://johnrobinson.dyndns.org/unity/soccer/

    and source:
    http://johnrobinson.dyndns.org/unity/soccer/Soccer_a_0.zip

    I just ran into something really weird when building the game. I chose to compress textures just to see what it would do. It screwed things up big time! A few of the things I noticed:

    Scripts were detached from various objects. I think it only detached the scripts for the fps controller but I can't be sure.

    Textures/materials were also detached.

    GUIText materials are now broken for me. I had originally had red and blue text's, but now whenever I try to apply materials to them they just show up as boxes with the right color, but you can't see the lettering.

    Anyway, I'm slowly getting the hang of using Unity. Great stuff!

    psx
     
  16. DaveyJJ

    DaveyJJ

    Joined:
    Mar 24, 2005
    Posts:
    1,558
    Cool job so far! Quite a blast to play!
     
  17. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    Cool. It's fun to play.

    Make sure that the texture you use in the gui text material has alpha properly enabled. (The letters should be visible when viewing the alpha)

    You can check in the texture inspector, using the show alpha check box.
     
  18. psx

    psx

    Joined:
    Aug 25, 2005
    Posts:
    80
    Thanks guys! That did the trick Joachim. So should we not be messing with "compress textures" in the current version?

    Now... on to coding up some more bots...

    Joachim... any tips on the class/subclass questions I posted earlier (this thread) ? Basically I want all of my bot classes to inherit from a generic BotPlayer class.

    psx
     
  19. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    You can safely use texture compression you just need to make sure to use the DXTC3 RGBA instead of RGB.


    At the moment you can't do derivation in javascript. We will support that in the future. If you really need to use derivation you can use C#.

    Most of the time you can implement what you normally do with inheritance through get component. So you have two scripts attached to the game object that communicate with each other through GetComponent and SendMessage.
     
  20. DaveyJJ

    DaveyJJ

    Joined:
    Mar 24, 2005
    Posts:
    1,558
    psx ... i was able to boot the ball right out of the stadium after it had gotten stuck nehind one corner of the goal. it never returned. you shoukd add a bit of code that if the ball goes below a certain Y level it reappears in play. it's a fun game!
     
  21. psx

    psx

    Joined:
    Aug 25, 2005
    Posts:
    80
    Joachim - Thanks for the info. I'll do some experimenting tomorrow.

    Just out of curiousity.. what happens if I simply attach 2(or more) scripts to an object? IOW, if I attach my base script first, and then a secondary script would they both run (I think yes), and more importantly, if they both had say an Update function of their own, would only one run (yay!), or would both (argh!)?


    DaveyJJ - That's a feature :D Either way, thanks for the positive feedback!

    Since the graphics are so simple, I was thinking of just adding a ceiling and closing the whole thing in. That way I don't have to deal with 'out-of-bounds' rules and such. I'm picturing a game 'like' soccer, but with less rules and more action. I'm even thinking of ways to fight with the other players, or at least punch/kick the opposition when they are close to you.

    psx
     
  22. psx

    psx

    Joined:
    Aug 25, 2005
    Posts:
    80
    Ok.. I tried this out. It works! BUT.. I get a weird "Null exception error" pointing to the first line inside my first Update function. Simplified code:

    script 1:
    Code (csharp):
    1.  
    2. function Update() {
    3.      // do this
    4. }
    5.  
    script 2:
    Code (csharp):
    1.  
    2. // override original Update
    3. function Update() {
    4.     // do that
    5. }
    6.  
    psx
     
  23. freyr

    freyr

    Joined:
    Apr 7, 2005
    Posts:
    1,148
    Both Updates will be run.

    Attaching multiple components is not the same thing as inheritance. The two script components are run in two different instances and don't override anything in one or the other.

    The NullReference exception happens if you try to use a variable that hasn't been initialised, so I am afraid that you have "simplified" the line that gave the exception away in your example.

    If you want to implement basic functionality in one class and then the specific functionality in the other, you'll have to organise your code so that they do not duplicate each other or overlap.

    You can have an update in both, but you'll have to make sure that the updates made in each one don't conflict in any way. (Like setting the position of the object in both.) This also applies to using standard components. Eg. when you have a RigidBody attached to a game object, you can no longer modify the position at will in other components.

    edit: In CS terms, the relationship between a game object and a component is a has-a relationship and not an is-a relationship. The game object contains a set of Component objects. (At least one; a Transform otherwise it doesn't have a position, rotation, scale or a parent.)
     
  24. psx

    psx

    Joined:
    Aug 25, 2005
    Posts:
    80
    thanks freyr! You were right. I hadn't hooked up a var with his GameObject so that was what was causing the error.

    With a setup like above, could I do something like below, or would I have to manually grab vars from the 'base' script?

    base:
    Code (csharp):
    1.  
    2.  
    3. var someVar = "bob";
    4.  
    5.  
    sub:
    Code (csharp):
    1.  
    2.  
    3. function Update() {
    4.     kick(someVar);
    5. }
    6.  
    7.  
    And one more issue I just ran into. I'm working on making my bots a bit smarter. I have a 'kickBall' function that used to just aim for the opposite team's goal, but I want to modify it a bit.

    original:
    Code (csharp):
    1.  
    2. function kickBall() {
    3.     this.transform.LookAt(goal.transform.position);
    4.     redball.transform.rotation = this.transform.rotation;
    5.     redball.rigidbody.AddRelativeForce(redball.transform.position.forward * kickStrength);
    6. }
    7.  
    goal is defined in the same script, and the above code works fine.

    Here's what I want, but it generates errors...

    Code (csharp):
    1.  
    2.  
    3.  
    4.  
    5. function kickBall(target) {
    6.         //look at the target
    7.     this.transform.LookAt(target.transform.position);
    8.     redball.transform.rotation = this.transform.rotation;
    9.     redball.rigidbody.AddRelativeForce(redball.transform.position.forward * kickStrength);
    10. }
    11.  
    12. kickBall(goal);
    13.  
    The specific error is:

    "System.InvalidCastException: Cannot cast from source type to destination type"

    Any thoughts anyone?

    psx
     
  25. NicholasFrancis

    NicholasFrancis

    Joined:
    Apr 8, 2005
    Posts:
    1,587
    Of the top of my head:

    try with
    redball.rigidbody.AddRelativeForce(redball.transform.forward * kickStrength);

    instead of:
    redball.rigidbody.AddRelativeForce(redball.transform.position.forward * kickStrength);

    Also, when you get an error, you can see the exact line where it happened - remember to post it ;-)
     
  26. psx

    psx

    Joined:
    Aug 25, 2005
    Posts:
    80
    It seems to be complaining about this line:

    this.transform.LookAt(target.transform.position);

    where the same line worked fine if I replace 'target' with the variable 'goal'.

    It doesn't have any trouble kicking the ball but rather is getting stuck in the LookAt function (I think).

    edit:
    It gets even weirder... if I add this line "print(target === goal);" I get "True", but it still doesn't want to work.

    And even weirder than that... this function does what I expect, but it's kinda ugly...

    Code (csharp):
    1.  
    2. function kickBall(obj) {
    3.     print(obj === goal);
    4.     var pos = Vector3(obj.transform.position.x, obj.transform.position.y, obj.transform.position.z);
    5.     transform.LookAt(pos);
    6.     redball.transform.rotation = this.transform.rotation;
    7.     redball.rigidbody.AddRelativeForce(redball.transform.position.forward * kickStrength);
    8. }
    9.  
    * note, changing 'target' to 'obj' had no effect. Same errors. What makes it work is creating a new Vector3 from the obj's position variables.
     
  27. freyr

    freyr

    Joined:
    Apr 7, 2005
    Posts:
    1,148
    First re. accessing variables in other scripts. You'll have to call GetComponent first or have an instance of the other script assigned to a local variable before being able to get at them.

    Second re. the goal thing. It looks like a problem with the type referencing try defining the function with the type of the target parameter defined:

    Code (csharp):
    1.  
    2. function ( target : Typename ) {
    3.    // ...
    4. }
    5.  
     
  28. psx

    psx

    Joined:
    Aug 25, 2005
    Posts:
    80
    Thanks again freyr!

    just an update on my progress.. I hope nobody minds. I thought about posting it in the showcase forum but didn't want to spam/flood the forums. It's nowhere near finished, but almost fun to play. The links earlier in this thread have been updated with the most recent version (source as well).

    I made a widget for those with Tiger. I'm still rockin' 10.3 so I can't test it. If anyone wants to give it a go, please let me know whether it works or not. I'm assuming it will because... well.. it's made with Unity. :)

    soccer widget:
    http://johnrobinson.dyndns.org/unity/soccer/soccer_a1_widget.zip

    Thanks to all who've helped me out so far. Unity seriously kicks arse!!

    psx
     
  29. nmceri

    nmceri

    Joined:
    Aug 4, 2005
    Posts:
    56
    I have to say, this little project you have started is already really funny and fun. I love running around with the herd trying to smack the ball around! good job!
     
  30. psx

    psx

    Joined:
    Aug 25, 2005
    Posts:
    80
    Thanks nmceri!

    I had originally planned for it to be a spectator sport only so I could brush up on my AI programming but found that is was more interesting if you could play along. Hell.. sometimes they even try to pass the ball to you. The trick for that is to be closer to the goal then the herd. :)

    psx
     
  31. DaveyJJ

    DaveyJJ

    Joined:
    Mar 24, 2005
    Posts:
    1,558
    Two bananas way up! Great fun!
     
  32. psx

    psx

    Joined:
    Aug 25, 2005
    Posts:
    80
    Thanks man!

    Hehe.. one more question (I won't say final.. cuz I know it won't be the last)...

    I saw a post talking about shadows... anyone care to uh.. shed some light on what I need to do to give the ball a shadow? I guess I should also give it a soccer-ball style texture as well but I think I can figure that out on my own.

    psx