Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Third person shooter - Learning project

Discussion in 'Made With Unity' started by TwiiK, Mar 29, 2009.

  1. NoMaD

    NoMaD

    Joined:
    Feb 1, 2010
    Posts:
    41
    Hi TwiiK
    Could you please post a package that contains your Blood Particles that instantiate when you hit an enemy? :oops: I really like yours, I tried making it but mine's not even close :?
    Particles hate me lol.
     
  2. TwiiK

    TwiiK

    Joined:
    Oct 23, 2007
    Posts:
    1,729
    @MojoTunc, glad I could help. :)

    @NoMaD, heh, that effect is not really particles. It's just an animated texture. And I can't post it here because its not mine to share, sorry.
     
  3. NoMaD

    NoMaD

    Joined:
    Feb 1, 2010
    Posts:
    41
    @ TwiiK: Oh ok gotcha :) I'll try to find another way to achieve the effect. thanks for reply
     
  4. botumys

    botumys

    Joined:
    Apr 16, 2009
    Posts:
    707
    hi, great game!

    For radiosity backing : Maybe you can try to separate ground and walls.
    For exemple,

    1*2K map for the ground
    2 or 3 *2K map for walls

    For fake shadowing, maybe can you try this:

    Calculate in max a top view of the level (orthographic view) with just black for shadows and white for light.
    let's say that you have now an image 512*512 in black and white of the whole level. Upper left of image = upper left of the unity level. Lower right = lower right im unity.
    Now you have just to create a piece of code that read the pixel color at x,y relatively to the player's position in the world. If black, lower the luminosity of the shader, if white back luminosity to normal.

    exemple: world size : 1000/1000 image size 512/512

    player position: 245,753
    in shadowing image, pixel position:

    x = 512 / (1000/245)
    y = 512 / (1000/753)
    ---------------------
    x= 125
    y= 386


    Olivier.
     
  5. TwiiK

    TwiiK

    Joined:
    Oct 23, 2007
    Posts:
    1,729
    Some interesting tips and information there, botumys.

    Thanks a lot.

    Can't wait fiddle some more with my game this weekend and try some of it out. :)

    I've been playing Halo 3 some lately as the Reach beta ended and I still needed my Halo fix. The lighting in Halo 3 is beautiful and they're obviously doing something like what you're saying here because the player reacts to the baked lighting/shadows.
     
  6. botumys

    botumys

    Joined:
    Apr 16, 2009
    Posts:
    707
    Games uses kind of precomputed radiance volumes that affect the ambient lighting of entities. A kind of point cloud of lighting information read in realtime.

    About my example, you can bake shadow and radiosity. In this case, you can add color information of the pixel in the ambient color of player's shader. Near a reddish wall, player color will tend to red.

    My tips is like a radiance volume, but in 2d :D

    ps: Obviously, this tip don't work with tunnels or layered geometries.
     
  7. TwiiK

    TwiiK

    Joined:
    Oct 23, 2007
    Posts:
    1,729
    I haven't been able to test out your lighting idea yet botumys, but it makes sense and it sounds like it should give me what I'm after.

    I'm however fiddling some with my lighting and I've stumbled upon another issue.

    As you can see in this crop of the Mirror's Edge image I posted further up:


    They have this really cool effect going with the normal map creating this concrecte look out of just a plain white cube.

    This effect was easy to create (although I have to find a better texture :)):


    But when my entire map is lighted by a lightmap I have no pixel lights to make the normal map visible. It's only visible in explosions etc. as you can see above.

    Is there a way to make my normal map visible without messing up the brightness of my map?

    Alternatively is there a way to merge/bake my normal map in a software like Photoshop or 3ds max? Because my lighting image is static if I could just bake the normal map lit from the position of my ingame sun I could just put that in the diffuse slot and it would look good? :)
     
  8. TwiiK

    TwiiK

    Joined:
    Oct 23, 2007
    Posts:
    1,729
    Another texture question:

    Imagine the 4 main walls in my map. I can either have them as 1 object and use a 2k texture on them or I can split them up and use 4 1k textures on them.

    Obviously I will save 3 draw calls with the 2k texture, but what is the most efficient in terms of performance?

    I'm guessing mip maps etc. will have a big impact on this. With the 2k texture I will always be close to 1 of the walls and I'm guessing the texture will have to be rendered at a high quality all the time.

    While with the 4 textures I will be far from 2 or 3 of the walls at all times and they can be rendered at much lower qualities?

    And is it just as easy for a graphics card to render a 2k texture as 4 1k textures? Does this go for 1 4k texture vs 4 2k textures as well?

    Is the choice an obvious one, if so why? Or is it something that depends on the situation? :)

    Guess I'll have to ask these questions in their respective forums, but I like to have it all here so when/if I get an answer I can just put it here and have an easy reference to it.
     
  9. EducaSoft

    EducaSoft

    Joined:
    Sep 9, 2007
    Posts:
    650
    I would say. Test it out, but it all depends how many objects you want in your scene or course.

    If you compare 1 x 2K texture = 1 drawcall to 4 x 1K texture = 4 drawcalls, then there is not a big impact of difference, but if you do this 200 times, then you have 200 versus 800 drawcalls for the same and thats something which is obviously in favor of the 1 x 2K texture
     
  10. novashot

    novashot

    Joined:
    Dec 12, 2009
    Posts:
    373
    For anyone looking for weapons similar to the ones in this game, check out my gun script here:

    http://forum.unity3d.com/viewtopic.php?t=56262

    Big fan of your work on this project Twiik. Also, thanks for pointing me in the right direction as I was building my weapons scripts a while ago... you'll see they have come quite a way and I like to know what you think of them.
     
  11. Tudor_n

    Tudor_n

    Joined:
    Dec 10, 2009
    Posts:
    359
    This is one of the most enjoyable prototypes I've ever played. Good job! (60k points - guest)
     
  12. 3dDude

    3dDude

    Joined:
    Jul 4, 2010
    Posts:
    1,067
    this is awsome man :D
     
  13. tatelax

    tatelax

    Joined:
    Feb 4, 2010
    Posts:
    1,168
    This is awesome. How did you do the "Gore" mode?? I agree with the other guy. The game would be way better if it was a multiplayer game.
     
  14. Blacklight

    Blacklight

    Joined:
    Dec 6, 2009
    Posts:
    1,241
    Are you still working on this?
     
  15. TwiiK

    TwiiK

    Joined:
    Oct 23, 2007
    Posts:
    1,729
    Yeah, but it's summer now. :)

    I haven't actually done anything on it since my last reply. So about 40 days without activity. I just can't bring myself to open Unity these days when it's so nice outside and I still have to work 8-10 hours a day on my day job.

    When Unity 3 arrives I will probably kickstart the project again, and maybe even go Pro because some of the new features look spectacular. :)
     
  16. Blacklight

    Blacklight

    Joined:
    Dec 6, 2009
    Posts:
    1,241
    I know how you feel.

    I spent quite a while picking through and trying to get my Unity and Blender projects onto my USB because I was going on a holiday for a while.

    And guess what... I never opened it once.

    Anyway, enjoy your summer. :D
     
  17. ugur

    ugur

    Joined:
    Jun 3, 2008
    Posts:
    692
    Hello TwiiK, i like your game a lot and sent you a pm on it, have you seen it or is it that whole summer thing? :)
     
  18. walfish3d

    walfish3d

    Joined:
    Jun 20, 2010
    Posts:
    4
    just wanted to drop some words after I played your cubeclonedemo:

    it's awesome! keep it going!
    this was actually the first unity-webplayer game I really enjoyed playing. reminds me of the serious sam scenes where you have to fight hundreds of frogs.

    btw nice to see there are still some q3 fans out there :)
     
  19. Blacklight

    Blacklight

    Joined:
    Dec 6, 2009
    Posts:
    1,241
    Hell yeah!
     
  20. gl33mer

    gl33mer

    Joined:
    May 24, 2010
    Posts:
    281
    Been enjoying this thread.

    Lot's of code to look through and experience shared. Thanks.

    All the great stuff being said about the game - I went ahead and tried to play it.

    (http://www.twiik.net/unity)

    But, alas, can't get it to work.

    Is it playable at the moment? Is this some quirk on my side. Tried it on both Firefox and Safari.

    When the game loads...if I press resume it just seems to reload the whole player.

    If I press escape I can get about 3 seconds of some kind of game play before it reloads.

    :) just wondering if you've uploaded a build that might be buggy.

    Thanks again for all the sharing.
     
  21. TwiiK

    TwiiK

    Joined:
    Oct 23, 2007
    Posts:
    1,729
    Works fine for me and I've made no changes to the game in the last month or more.

    I will have to test it out more thoroughly later on. And there are some bugs in the current build, but none like what you're describing here.
     
  22. 3dDude

    3dDude

    Joined:
    Jul 4, 2010
    Posts:
    1,067
    @twiik can you post the smoke tex you are using? i know that is not nice to ask for peoples assets :roll: . but it look really cool :D
     
  23. TwiiK

    TwiiK

    Joined:
    Oct 23, 2007
    Posts:
    1,729
    Sorry, no can do.

    I've made it myself and I don't want to share it. :)

    It took me 10 minutes though so you can probably make something just as good yourself.

    Just google image something like "black smoke", "oil fire", "explosion", or whatever.

    Find a good source image, like this one: http://www.outlookseries.com/N7/Science/3908_D5.jpg

    and cut out 1 or more interesting parts of the smoke.
     
  24. 3dDude

    3dDude

    Joined:
    Jul 4, 2010
    Posts:
    1,067
    ohhhh i see how it is :D
     
  25. 3dDude

    3dDude

    Joined:
    Jul 4, 2010
    Posts:
    1,067
  26. TwiiK

    TwiiK

    Joined:
    Oct 23, 2007
    Posts:
    1,729
    The gore mode is just a static variable, some game objects with particle emitters and some planes with blood splats on them.

    When the enemy dies and he is "gibbed" (This depends on which weapon killed him and how much damage he took in the final hit) I spawn some gibs and send them flying:
    Code (csharp):
    1. if (gibbed) {
    2.     // Spawn a random number of gibs
    3.     int gibs = Random.Range(minGibs, maxGibs);
    4.  
    5.     for (int i = 0; i < gibs; i++) {
    6.  
    7.         Vector3 direction = Random.onUnitSphere;
    8.         if(direction.y < 0)
    9.             direction.y = -direction.y;
    10.  
    11.         Vector3 dropPosition = transform.TransformPoint(Vector3.up * 1.5f) + (direction / 2);
    12.  
    13.         gib = Instantiate(gib, dropPosition, Quaternion.identity) as GameObject;
    14.         gib.rigidbody.velocity = direction;
    15.  
    16.         Vector3 multiplier = transform.localScale;
    17.         float scale = Random.Range(0.2f, 0.35f);
    18.         gib.transform.localScale = new Vector3(scale * multiplier.x, scale * multiplier.y, scale * multiplier.z);
    19.     }
    20.  
    21.     if (GameManager.gore) {
    22.         Instantiate(ExplosionGore, transform.position + (Vector3.up), transform.rotation);
    23.     }
    24.     else {
    25.         Instantiate(ExplosionNormal, transform.position + (Vector3.up), transform.rotation);
    26.     }
    27.  
    28.     Destroy(gameObject);
    29. }
    One gib is just a cube with a particle system attached.

    When a gib hits some geometry it spawns a blood splat:
    Code (csharp):
    1. void OnCollisionEnter (Collision collision) {
    2.     if (GameManager.gore) {
    3.  
    4.         ContactPoint contact = collision.contacts[0];
    5.         Quaternion rotation = Quaternion.FromToRotation(Vector3.up, contact.normal);
    6.  
    7.         if (contact.otherCollider.tag == "Geometry"  !splatted) {
    8.             if(child.particleEmitter) {
    9.                 child.particleEmitter.emit = false;
    10.             }
    11.             Instantiate(splatter, contact.point + contact.normal * 0.1f, rotation);
    12.             splatted = true;
    13.         }
    14.     }
    15. }
    Basically if the option is set in the menu and the guts hits an object tagged as "Geometry" I instantiate a blood splat on the object.

    My blood splat is just a plane with a blood splat texture.

    I saw your PM now and replied to it. :)

    That looks really good. :)

    My fire is done the same way except it is an animated texture with about 10 frames of animation. I made them from some stock footage of explosions I bought online.
     
  27. TwiiK

    TwiiK

    Joined:
    Oct 23, 2007
    Posts:
    1,729
    I received a PM asking about my Drupal integration, user login and highscore saving so here it is.

    It is entirely based on the Server Side Highscores entry in the wiki: http://www.unifycommunity.com/wiki/index.php?title=Server_Side_Highscores

    For those without Drupal the above link should work perfectly in itself. To make it work with Drupal I made some changes.

    Without knowledge or interest in Drupal the following is of no use to you: :)

    This is Drupal 6.

    First I made a module to contain my server side code containing two files, the .info-file detailing what the module does and the .module-file containing the code itself. I would normally create a third file called an install file. This file would contain instructions for Drupal on where and how to create the neccessary table in the database, but I had already created it manually with phpmyadmin following the wiki article so I didn't bother making it. For instructions on creating the database table look in the article. The only change I made was that I only save the Drupal user id and the highscore in the table because saving the username as well would be superfluous the way Drupal works.

    A module in Drupal is a collection of code which can be enabled and disabled on your site. It is preferably made to fit a certain purpose so it can easily be copied to other projects needing the same functionality.

    highscores.info
    Code (csharp):
    1. name = Highscores
    2. description = Handles and displays highscores for my Unity game
    3. core = 6.x
    The info file. Contains info about the module and not much more.

    highscores.module
    Code (csharp):
    1. <?php
    2. drupal_add_js(drupal_get_path('module', 'highscores') .'/highscores.js');
    3.  
    4. /**
    5.  * Implementation of hook_menu().
    6.  */
    7. function highscores_menu() {
    8.   $items['unity'] = array(
    9.     'page callback' => 'highscores_game',
    10.     'access arguments' => array('access content'),
    11.     'type' => MENU_CALLBACK,
    12.   );
    13.   $items['unity/addscore'] = array(
    14.     'page callback' => 'highscores_add',
    15.     'access arguments' => array('access content'),
    16.     'type' => MENU_CALLBACK,
    17.   );
    18.   $items['unity/displayscores'] = array(
    19.     'page callback' => 'highscores_display',
    20.     'access arguments' => array('access content'),
    21.     'type' => MENU_CALLBACK,
    22.   );
    23.   $items['unity/sendscores'] = array(
    24.     'page callback' => 'highscores_send_scores',
    25.     'access arguments' => array('access content'),
    26.     'type' => MENU_CALLBACK,
    27.   );
    28.   return $items;  
    29. }
    30.  
    31. /**
    32.  * Adds a score for the current user to the high scores table
    33.  */
    34. function highscores_add() {
    35.   $uid = $_GET['uid'];
    36.   $score = $_GET['score'];
    37.   $hash = $_GET['hash'];
    38.  
    39.   $secretKey = "It's a secret"; # Must match the value in our game script
    40.  
    41.   $real_hash = md5($uid.$score.$secretKey);
    42.  
    43.   // Compare the server hash with the hash sent from the game.
    44.   // If they don't match the request is not coming from our game
    45.   if ($real_hash == $hash) {
    46.     if (!$old_score = db_result(db_query("SELECT score FROM {unity_highscores} WHERE uid = %d LIMIT 1", $uid))) {
    47.       $old_score = 0;
    48.     }
    49.    
    50.     // If the new score for this player is higher than the old score we replace it in the db
    51.     if ($score > $old_score) {
    52.       db_query("REPLACE INTO {unity_highscores} (uid, score) VALUES (%d, %d)", $uid, $score);
    53.     }
    54.   }
    55. }
    56.  
    57. /**
    58.  * Outputs our high scores as a html table
    59.  */
    60. function highscores_display() {
    61.   $result = db_query("SELECT * FROM {unity_highscores} ORDER BY score DESC LIMIT 30");
    62.   $output .= '<div id="highscore-table">';
    63.   $output .= '<table><thead><th></th><th>Name</th><th>Score</th></thead><tbody>';
    64.   $position = 1;
    65.   $zebra = 'odd';
    66.   while ($record = db_fetch_object($result)){
    67.     $user = user_load($record->uid);
    68.     $output .= '<tr class="'.$zebra.'"><td>'.$position.'</td><td>'.$user->name.'</td><td>'.$record->score.'</td></tr>';
    69.     $position++;
    70.     if ($zebra == 'odd') {
    71.       $zebra = 'even';
    72.     }
    73.     else {
    74.       $zebra = 'odd';
    75.     }
    76.   }
    77.   $output .= '</tbody></table>';
    78.   $output .= '</div>';
    79.  
    80.   return $output;
    81. }
    82.  
    83. /**
    84.  * Sends the user information to our game in the format uid;user information
    85.  * @todo change the name of the function to reflect that
    86.  */
    87. function highscores_send_scores() {
    88.   global $user;
    89.   if ($user->uid) {
    90.     print $user->uid.';Logged in as: '.$user->name;
    91.   }
    92.   else {
    93.     print "0;You're playing as a guest. To save your highscore log in or create an account.";
    94.   }
    95. }
    96.  
    97. function highscores_game() {
    98.   jquery_ui_add('ui.tabs');
    99.   drupal_add_css(drupal_get_path('module', 'jquery_ui') .'/jquery.ui/themes/base/ui.tabs.css');
    100.   $output = '<div id="tabs">
    101.                <ul>
    102.                   [*][url="#tabs-1"]High scores[/url]
    103.                   [*][url="#tabs-2"]Controls[/url]
    104.                   [*][url="#tabs-3"]Change log[/url]
    105.                [/list]
    106.                <div id="tabs-1">
    107.                   '.highscores_display().'
    108.                </div>
    109.                <div id="tabs-2">
    110.                  <div id="controls">
    111.                    <table>
    112.                      <thead>
    113.                        <tr><th>Input</th><th>Action</th></tr>
    114.                      </thead>
    115.                      <tbody>
    116.                        <tr><td>WASD or arrow keys</td><td>Move character</td></tr>
    117.                        <tr><td>Spacebar</td><td>Jump</td></tr>
    118.                        <tr><td>1</td><td>Pistol</td></tr>
    119.                        <tr><td>2</td><td>Shotgun</td></tr>
    120.                        <tr><td>3</td><td>Machinegun</td></tr>
    121.                        <tr><td>4</td><td>Grenade launcher</td></tr>
    122.                        <tr><td>5</td><td>Rocket launcher</td></tr>
    123.                        <tr><td>6</td><td>Howitzer</td></tr>
    124.                        <tr><td>Mouse</td><td>Aim weapon</td></tr>
    125.                        <tr><td>Scrollwheel</td><td>Control time</td></tr>
    126.                        <tr><td>Esc</td><td>Show menu  cursor</td></tr>
    127.                      </tbody>
    128.                    </table>
    129.                  </div>
    130.                </div>
    131.                <div id="tabs-3">
    132.                  <div id="dev-log">
    133.                    Hang on...
    134.                  </div>
    135.                </div>
    136.             </div>';
    137.   return $output;
    138. }
    139.  
    The module file. Contains all our code. I will go through it one part of a time below.

    The first line is just adding some javascript to handle some of the fancy fluff on my site, not important here.

    Then we have the highscores_menu() function:
    Code (csharp):
    1. function highscores_menu() {
    2.   $items['unity'] = array(
    3.     'page callback' => 'highscores_game',
    4.     'access arguments' => array('access content'),
    5.     'type' => MENU_CALLBACK,
    6.   );
    7.   $items['unity/addscore'] = array(
    8.     'page callback' => 'highscores_add',
    9.     'access arguments' => array('access content'),
    10.     'type' => MENU_CALLBACK,
    11.   );
    12.   $items['unity/displayscores'] = array(
    13.     'page callback' => 'highscores_display',
    14.     'access arguments' => array('access content'),
    15.     'type' => MENU_CALLBACK,
    16.   );
    17.   $items['unity/sendscores'] = array(
    18.     'page callback' => 'highscores_send_scores',
    19.     'access arguments' => array('access content'),
    20.     'type' => MENU_CALLBACK,
    21.   );
    22.   return $items;  
    23. }
    It is best practice in Drupal to prefix your functions with your module name to avoid namespace collisions. That's why all the functions are called highscores_xxx.

    This function contains our menu hooks. These are paths that will activate their respective functions when accessed.

    So when a user goes to www.twiik.net/unity the function highscores_game() is called because of this menu hook:
    Code (csharp):
    1. $items['unity'] = array(
    2.   'page callback' => 'highscores_game',
    3.   'access arguments' => array('access content'),
    4.   'type' => MENU_CALLBACK,
    5. );
    These are also the paths our Unity game will use when adding scores to the database. For instance www.twiik.net/unity/addscore adds the current score to the database.

    This is the equivalent to creating addscore.php in the wiki article. Then you would access www.twiik.net/addscore.php instead.

    Then follows the highscores_add() function:
    Code (csharp):
    1. function highscores_add() {
    2.   $uid = $_GET['uid'];
    3.   $score = $_GET['score'];
    4.   $hash = $_GET['hash'];
    5.  
    6.   $secretKey = "It's a secret";
    7.  
    8.   $real_hash = md5($uid.$score.$secretKey);
    9.  
    10.   if ($real_hash == $hash) {
    11.     if (!$old_score = db_result(db_query("SELECT score FROM {unity_highscores} WHERE uid = %d LIMIT 1", $uid))) {
    12.       $old_score = 0;
    13.     }
    14.  
    15.     if ($score > $old_score) {
    16.       db_query("REPLACE INTO {unity_highscores} (uid, score) VALUES (%d, %d)", $uid, $score);
    17.     }
    18.   }
    19. }
    This is the function that does the work of actually adding the score to the database, which is basically all the work needed for this to work.

    First we get the uid, score and hash from their respective GET parameters. uid is the user ID of the user currently playing, score is his score and hash is a md5 hash, sort of like a fingerprint, of the sent uid, score and secret key. We then compare this to a hash we create on the server to make sure it's not a false request. We know this because only our own game knows the matching secret key.

    If the two hashes match we continue adding the score to the database. We first check if there's already a score for this user in the database and if there isn't we just set it to 0 so any score coming from the game will be higher. Then we insert the score into the database. We use REPLACE so if there's already a score for this user in the table we replace the old one. This way there's only one high score per user.

    I won't go into the details of highscores_display() and highscores_game() because they just to some simple displaying of the high scores etc.

    highscores_send_scores():
    Code (csharp):
    1. function highscores_send_scores() {
    2.   global $user;
    3.   if ($user->uid) {
    4.     print $user->uid.';Logged in as: '.$user->name;
    5.   }
    6.   else {
    7.     print "0;You're playing as a guest. To save your highscore log in or create an account.";
    8.   }
    9. }
    This is the function that our game actually access to see if we have a user playing or a guest. The name of the function is of course wrong and needs to be changed. This whole thing is a work in progress. :)

    If there is a user logged in, in Drupal you can check for that if the global $user variable has an user ID, we print the user ID so our game can fetch it.


    Then we have the client side code (extremely similar to the wiki article).

    HSController.cs
    Code (csharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using System;
    4.  
    5. public class HSController : MonoBehaviour {
    6.  
    7.     private string secretKey = "It's a secret"; // Secret key. Must match the secret key I've defined on my server
    8.     private string addScoreUrl = "http://www.twiik.net/unity/addscore"; // The url to the script that adds the score to the db
    9.     private string highscoreUrl = "http://www.twiik.net/unity/sendscores";  // The url to the script that sends the user information to the game
    10.  
    11.     private PlayerStatus playerInfo; // A link to the player status
    12.     private int userID = 0; // Default is user ID 0 = guest
    13.     public string userText = "";
    14.     public string scoreText = "No score uploaded";
    15.  
    16.     // Cache a link to the player status script. We use this to get the
    17.     // current score of the player
    18.     void Awake() {
    19.         playerInfo = (PlayerStatus)FindObjectOfType(typeof(PlayerStatus));
    20.     }
    21.  
    22.     // When we start the game we get the user information from the server
    23.     void Start() {
    24.         StartCoroutine(GetUserInfo());
    25.     }
    26.  
    27.     // Function called from the menu when the user clicks the "Upload score" button
    28.     public void UploadScore() {
    29.  
    30.         // If the user has a ID he is logged in and can upload his score
    31.         if (userID != 0) {
    32.             StartCoroutine(PostScore(userID, playerInfo.score));
    33.         }
    34.         else {
    35.             scoreText = "You're not logged in and can't upload your score";
    36.         }
    37.     }
    38.  
    39.     // This sends the user ID, score and hash to the server side script which compares the hashes
    40.     // to make sure it's coming from the game and adds the score to the database for the user
    41.     // corresponding to the user ID
    42.     IEnumerator PostScore(int uid, int score) {
    43.         string hash = Utility.Md5Sum(uid.ToString() + score.ToString() + secretKey);
    44.  
    45.         string highscore_url = addScoreUrl + "?uid=" + uid + "&score=" + score + "&hash=" + hash;
    46.            
    47.         // Post the URL to the site and create a download object to get the result.
    48.         WWW hs_post = new WWW(highscore_url);
    49.  
    50.         yield return hs_post; // Wait until the upload is done
    51.  
    52.         if (hs_post.error == null) {
    53.             scoreText = "Score uploaded successfully";
    54.         }
    55.         else {
    56.             scoreText = "There was an error posting the high score: " + hs_post.error;
    57.         }
    58.     }
    59.      
    60.     // Get the user from the server so we know which user is playing
    61.     // or if the player is a guest
    62.     IEnumerator GetUserInfo() {
    63.         userText = "Getting user information...";
    64.  
    65.         WWW hs_get = new WWW(highscoreUrl);
    66.        
    67.         yield return hs_get; // Wait until the download is done
    68.  
    69.         if (hs_get.error == null) {
    70.             if (hs_get.data == "") {
    71.                 userText = "Not logged in... You are now playing as a guest and your progress will not be saved.";
    72.             }
    73.             else {
    74.                 // The data we recieved is a string separated by ;
    75.                 string[] info = hs_get.data.Split(';'); // Split it
    76.                            
    77.                 userID = Convert.ToInt32(info[0]); // The first part is the user ID
    78.  
    79.                 userText = info[1]; // The last part is the username and we display that for the player
    80.             }
    81.         }
    82.         else {
    83.             print("There was an error getting your user information: " + hs_get.error);
    84.         }
    85.     }
    86.  
    87.     // Attempt to upload the score when the user quits the game
    88.     void OnApplicationQuit() {
    89.         if (userID != 0) {
    90.             StartCoroutine(PostScore(userID, playerInfo.score));
    91.         }
    92.         else {
    93.             scoreText = "You're not logged in and can't upload your score";
    94.         }
    95.     }
    96. }
    First we define our secret key. This must match the one we have on our server of course. Then the url we use for posting scores and the url for getting the user ID.

    On Awake() we find the player status script. This contains a number of things, but we only care about his score in this case.

    On Start() we start the GetUserInfo() coroutine:
    Code (csharp):
    1. IEnumerator GetUserInfo() {
    2.     userText = "Getting user information...";
    3.  
    4.     WWW hs_get = new WWW(highscoreUrl);
    5.        
    6.     yield return hs_get; // Wait until the download is done
    7.  
    8.     if (hs_get.error == null) {
    9.         if (hs_get.data == "") {
    10.             userText = "Not logged in... You are now playing as a guest and your progress will not be saved.";
    11.         }
    12.         else {
    13.             // The data we recieved is a string separated by ;
    14.             string[] info = hs_get.data.Split(';'); // Split it
    15.                            
    16.             userID = Convert.ToInt32(info[0]); // The first part is the user ID
    17.  
    18.             userText = info[1]; // The last part is the username and we display that for the player
    19.         }
    20.     }
    21.     else {
    22.         print("There was an error getting your user information: " + hs_get.error);
    23.     }
    24. }
    I'm honestly not entirely sure how the WWW thingy in Unity works, but at least it fetches some data from the url we supply it and that works for me. :)

    If there is no error and the data object is empty the current player is playing as a guest. If there is no error, but there is data we split the data on ";" because we sent it as "uid;information" from the server. So the first part is the current player's user ID and the last part is the info we display in the menu. If there was an error we print the error message.

    You'll probably notice at the bottom that I'm trying to upload the user's score automatically when he or she quits the game, but this is currently not working. So for now the player has to click the upload score button to add his score to the server. If he is logged in we start the PostScore() coroutine:
    Code (csharp):
    1. IEnumerator PostScore(int uid, int score) {
    2.     string hash = Utility.Md5Sum(uid.ToString() + score.ToString() + secretKey);
    3.  
    4.     string highscore_url = addScoreUrl + "?uid=" + uid + "&score=" + score + "&hash=" + hash;
    5.            
    6.     // Post the URL to the site and create a download object to get the result.
    7.     WWW hs_post = new WWW(highscore_url);
    8.  
    9.     yield return hs_post; // Wait until the upload is done
    10.  
    11.     if (hs_post.error == null) {
    12.         scoreText = "Score uploaded successfully";
    13.     }
    14.     else {
    15.         scoreText = "There was an error posting the high score: " + hs_post.error;
    16.     }
    17. }
    This function first hashes together our user ID, score and secret key. Then it creates a string out of our addscore url, user ID, score and hash. This string looks something like: "http://www.twiik.net/unity/addscore?uid=25&score=1200&hash=somegibberish"

    We then creates a new WWW object using the above url and wait until the upload is done before posting the result. If it was successful our score was successfully added to the database and we print a message to the player to show him it worked. If it didn't work we tell the player and print the error.

    The code in its entirety is attached in the zip-file. The highscores folder is the drupal module and the two C# files is the Unity code. The second C# file is just an utility class containing the md5 function.
     

    Attached Files:

  28. NoMaD

    NoMaD

    Joined:
    Feb 1, 2010
    Posts:
    41
    :eek: I have no idea what drupal is lol
     
  29. Thor

    Thor

    Joined:
    Aug 17, 2010
    Posts:
    15
  30. TwiiK

    TwiiK

    Joined:
    Oct 23, 2007
    Posts:
    1,729
    Thanks for the offer, Thor, but I'm not really interested.

    I have too little free time as it is and I prefer to spend it on myself. :)

    As for anyone reading this. This project is on hold for now as I'm waiting for Unity 3 and I've begun relearning some 3ds Max instead.
     
  31. eric_c

    eric_c

    Joined:
    Sep 19, 2010
    Posts:
    44
    Hi TwiiK, i played your game, and liked it alot.Just have a few questions regarding your scripts.

    1. How do you make your bullet speed "infinite", but able to collide with collider, like you mentioned above? more info?

    2. About the Ai in your game, did you make them follow you, then make an attack message, or you just make them apply damage whenever they collide with the player? Any chance to share the script?
     
  32. EmadGh

    EmadGh

    Joined:
    Jun 10, 2009
    Posts:
    147
    hi, CSHen042
    The bullet must be done with raycast.An object have a script that raycast forward.

    I myself made them this way with raycast.
     
  33. TwiiK

    TwiiK

    Joined:
    Oct 23, 2007
    Posts:
    1,729
    1. The bullet speed is not infinite. If you play the game you'll see it actually takes quite a bit of time for one bullet to hit the opposite side. And each weapon has a different bullet speed. Also, the bullets are affected by drag (i.e simple air resistance) and by gravity.

    I am using Raycasts for the bullets, but not in the way emadgh thinks. The whole point of using a standard Raycast for your weapons is that you won't need bullets, because bullet speed will be infinite there is nothing between the weapon firing and the bullet hitting and thus no need for an actual bullet.

    Using raycasts for fast speed weapons is what most games do because it's extremely simple and easy to keep track of, which is especially important in multiplayer. Halo Reach for instance went from a ballistic model in Halo 3 to raycasts in Halo Reach.

    What I do in my game is actually taken from Spk (a user on these forums who posted his bullet code a while ago). My bullets are actual game objects which move at an actual speed and then each frame I raycast from the bullets previous position to its current position. This enables me to have bullets that have gravity, drag, and actual speed so the player can dodge them and you can see the actual tracers of the bullets instead of just fake tracers like in many games. And because I'm raycasting each frame it will be as accurate as a normal raycast. Because if the bullet moves so fast it goes through a collider in a single frame then the raycast from the bullets previous position will hit the collider and I register a hit with the collider.

    2. The "AI" is taken from the third person platform tutorial hosted here on unity3d.com. They just apply damage when you enter a small collider they have in front of them.
     
  34. eric_c

    eric_c

    Joined:
    Sep 19, 2010
    Posts:
    44
    Thanks for the quick reply you gave, really appriciated it!
    Still not quite understand what you or the script from spk you mentioned means...did you seperated the raycast and the bullet? Or you used the bullet as the raycast subject? I liked the bullet "trails" which you made from the trail renderer. But another question, how do you make the gun aim toward the centre of the camera? I used an orbit script and a script that makes your object rotate to the direction of the camera, but the result wouch be the character tilting a direction or not aiming towards the centre of the camera. Any ways to fix this? Thanks! :)
     
  35. TwiiK

    TwiiK

    Joined:
    Oct 23, 2007
    Posts:
    1,729
    That's actually one of the things I struggled most with and I still don't understand how they do it in most games.

    What I do is shoot a ray (i.e physics raycast) directly out from the center of my camera and position a gameobject at the point where my ray intersects the first geometry it hits. Then I have a LookAt script (I think one is included with the standard assets package) attached to my weapons which looks at that target gameobject.

    This is not perfect, but it's the best I've been able to come up with. Like I said I have no idea how they do it in games like Gears of War or even first person shooters like Unreal Tournament or Halo because even in those first person shooters you fire a projectile from the right side of your screen and it still hits the center of the screen every time.

    The trails are just a trail renderer with a gradient texture applied.

    As for the bullets, you are right in the fact that the bullets are the objects actually raycasting. Every frame I do a new raycast from the bullet to the bullet, but at two different points in time if you can call it that. :) I raycast from the position the bullet had last frame to the position the bullet had this frame. If the bullet is moving slow the raycast will just be across a tiny distance and if the bullet is moving very fast the raycast will go a long distance, but either way the raycast will always register a hit with whatever the bullet has gone through during that frame.

    Edit: Here's a link to Spk's thread: http://forum.unity3d.com/viewtopic.php?t=21871&highlight= and a direct link to the bullet code he posted: http://forum.unity3d.com//files/bullet_536.cs

    His bullet code seems more complex than mine because I didn't understand quite a bit of it and simplified it. :)
     
  36. Newnab

    Newnab

    Joined:
    Oct 25, 2010
    Posts:
    7
    Twiik, you're an absolute inspiration. I'm attempting to make a third person shooter myself and after doing a lot of design and planning, was suffering a crisis of confidence when it came to coding but your guidance here has now seen me implement enemies in waves that attack the player and just having that functioning is such a boost. Onwards and upwards, and hopefully I can share my work with you sometime in the near future!
     
  37. NinjaCodeMonkey

    NinjaCodeMonkey

    Joined:
    Aug 15, 2010
    Posts:
    5
    Hi Twiik would you please let me look at your source code to learn I really think that this game is looking really cool
     
    Last edited: Nov 8, 2010
  38. Khyrid

    Khyrid

    Joined:
    Oct 8, 2010
    Posts:
    1,790
    Hey TwiiK, I just read the entire 12 pages of this thread!, anyway what lead me here was my quest for bullet trails or tracers or visible bullets lol.

    Anyway I used the code you suggested and I got about the same results that I reached myself previously.

    Problem: With the speed cranked up anything past about 150 the bullets "hit" in mid air a few feet from me, if I set the speed lower they somewhat work (at an unsatisfying 150 speed) but they still pass through colliders! <-UPDATE!!!: I found this script called Don'tGoThroughThings Just set everything you want bullets to collide with to a layer (I called mine "Solids") And use that as the target of the script. Works like a charm. Using it with my bullet code(posted below) I went up to 1000 bullet speed and it still collides fine.

    I was* using the Java form of the code you posted (I think a billion pages ago), so maybe it has soemthing to do with not being C#. So any advice as to what's happening would be greatly appreciated and thanks fr posting so much info on here also. :)

    Another Problem: When strafing and shooting at the same time the bullets start from the side of the gun, not the tip of the barrel. Maybe it's an optical illusion because the gun is quickly moving away from where the bullets start. Still how do the AAA games handle this? <-UPDATE!!!:
    I played some AAA games to study this and I found Unreal 3 has the same issue!. When strafing the bullets don't start from the barrel. I also played a game called Killing Floor and they found some way for the bullets to come from the gun even when strafing.


    Also I found my bullet script to be better than yours, as with your script the bullets seemed to collide fine, but they didn't register damage with their targets sometimes, this could be due to some error on my part though. Anyway I use a different method of colliding and my hits always resister damage. Did you have any trouble with some bullets not causing damage? You should test. Anyway here is my bullet code:

    Code (csharp):
    1. var damage = 5;
    2. var explosion : Transform; //GameObject;
    3. var timeOut = 3.0;
    4.  
    5. function SlowIt() {
    6. speed = 1;
    7. }
    8.  
    9. // Kill the bullet after a while automatically
    10. function Start () {
    11.     Invoke("Kill", timeOut);
    12. }
    13.  
    14. function Update () {
    15. var fwd = transform.TransformDirection (Vector3.forward);
    16. if (Physics.Raycast (transform.position, fwd, 3)) {
    17. print ("There is something in front of the object!");
    18. //Make visible bullet hit
    19. var rotation = Quaternion.FromToRotation( Vector3.up,transform.position);
    20.  
    21. // Create the explosion
    22. if (explosion)
    23.     Instantiate (explosion, transform.position, transform.rotation);
    24. }
    25. }
    26.  
    27. //Collision code
    28. function OnCollisionEnter (collision : Collision) {
    29.  
    30. if(collision.gameObject.CompareTag("DamageObj"))
    31. {
    32. collision.gameObject.SendMessage("ApplyDamage", damage);
    33. }
    34.  
    35. //Make visible bullet hit
    36. var contact : ContactPoint = collision.contacts[0];
    37.  
    38. var rotation = Quaternion.FromToRotation( Vector3.up, contact.normal );
    39.  
    40. // Create the explosion
    41. if (explosion)
    42.     Instantiate (explosion, transform.position, transform.rotation);
    43.    
    44. //Die
    45. Destroy(gameObject);
    46. }
    47.  
    48. function Kill () {
    49.     // Destroy the projectile
    50.     Destroy(gameObject);
    51. }
    *Note there is some junk code in here. The SlowIt function and Update function are probably obsolete and the explosion created is not like a rocket, it's for the sparks that are made when the bullet hits something.
     
    Last edited: Nov 14, 2010
  39. Khyrid

    Khyrid

    Joined:
    Oct 8, 2010
    Posts:
    1,790
    Bump! And another thing. I went back to using the bullet code you recommended because I couldn't get bullet holes to work with mine. Anyway, I noticed that when shooting walls at an angle sometimes bullets will overshoot and hit further away, even though the tracer object goes where it's supposed to, the sparks and bullet hole are drawn away from where I was aiming. It's hard to explain so I drew this:



    When aiming at a wall at an angle it sometimes fires half the rounds too far away. But all the bullet objects go where they are supposed to 100% of the time. Just the bullet holes and sparks are effected by this problem.

    Here is the bullet object code:
    Code (csharp):
    1. var speed = 500.0;
    2. var life = 12;
    3. var impactEffect : GameObject;
    4. var explosion : Transform; //GameObject;
    5. var bulletHole : GameObject;
    6. var damage = 20;
    7. var impactForce = 10;
    8.  
    9. private var xvelocity : Vector3;
    10. private var newPos : Vector3;
    11. private var oldPos : Vector3;
    12. private var hasHit = false;
    13.  
    14. function Start() {
    15. newPos = transform.position;
    16. oldPos = newPos;
    17. xvelocity = speed * transform.forward;
    18.  
    19. // schedule for destruction if bullet never hits anything
    20. Destroy( gameObject, life );
    21. }
    22.  
    23. function Update() {
    24.  
    25. if( hasHit )
    26. return;
    27.  
    28. // assume we move all the way
    29. newPos += xvelocity * Time.deltaTime;
    30.  
    31. // Check if we hit anything on the way
    32. var direction = newPos - oldPos;
    33. var distance = (direction.magnitude); //(direction.magnitude);
    34.  
    35. if (distance > 0) {
    36. var hit : RaycastHit;
    37.        
    38. if (Physics.Raycast(oldPos, direction, hit, distance)) {
    39. // adjust new position
    40. newPos = hit.point;
    41.  
    42. // notify hit
    43. hasHit = true;
    44.  
    45. var rotation = Quaternion.FromToRotation(Vector3.up, hit.normal);
    46. Instantiate(impactEffect, hit.point, rotation);
    47.  
    48. if (hit.rigidbody)
    49. hit.rigidbody.AddForce( transform.forward * impactForce, ForceMode.Impulse );
    50.  
    51.     // if we hit geometry we spawn a bullet hole
    52.     if (hit.transform.tag == "Geometry")
    53.         Instantiate(bulletHole, hit.point, rotation);
    54.  
    55.     hit.transform.SendMessageUpwards("ApplyDamage", damage, SendMessageOptions.DontRequireReceiver);
    56.     Destroy (gameObject, 0);
    57.        
    58.     }
    59. }
    60.  
    61. oldPos = transform.position;
    62. transform.position = newPos;
    63. }
    64.  
    65. //Collision code
    66. function OnCollisionEnter (collision : Collision) {
    67.  
    68. var contact : ContactPoint = collision.contacts[0];
    69. var rotationX = Quaternion.FromToRotation(Vector3.up, contact.normal);
    70.    
    71. if(collision.gameObject.CompareTag("DamageObj"))
    72. {
    73. collision.gameObject.SendMessage("ApplyDamage", damage);
    74. // Create the explosion
    75. if (explosion)
    76.     Instantiate (explosion, contact.point, rotationX);
    77.    
    78. Destroy (gameObject, 0);
    79. }
    80.  
    81. if(collision.gameObject.CompareTag("Player"))
    82. {
    83. collision.gameObject.SendMessage("ApplyDamage", damage);
    84. // Create the explosion
    85. if (explosion)
    86.     Instantiate (explosion, contact.point, rotationX);
    87.    
    88. Destroy (gameObject, 0);
    89. }
    90. }
     
  40. Nikolay116

    Nikolay116

    Joined:
    Mar 21, 2010
    Posts:
    421
    is the source available for the project or not
     
  41. boomcrash

    boomcrash

    Joined:
    Aug 31, 2010
    Posts:
    72
    I am relatively new to scripting, how are you handling player respawn? The reason I ask is that all the example i have found for spawning a player are in Java Script, and I'm primarily using C#.
    Thanks!
     
    Last edited: Jan 8, 2011
  42. konedj

    konedj

    Joined:
    Dec 7, 2010
    Posts:
    84
    hell damn!! thats a reaally good game
    Have you made it all by your own? or you've followed some tutorials
    if its the second case please tell me please because i'm learning too
    thanks and very very good job
     
  43. eric_c

    eric_c

    Joined:
    Sep 19, 2010
    Posts:
    44
    bullet tracer problem driving me nuts
     
  44. Khyrid

    Khyrid

    Joined:
    Oct 8, 2010
    Posts:
    1,790
    What I finally settled on is having the actual invisible ray casted bullet do their thing just like in the FPS tutorial, then using an object for the tracer round that fires each time a bullet fires. The tracer just dies on impact it doesn't calculate any damage or create bullet holes etc. Allows infinite speed bullets and perfect accuracy short of whatever recoil system you employ.
     
  45. NinjaCodeMonkey

    NinjaCodeMonkey

    Joined:
    Aug 15, 2010
    Posts:
    5
    Twiik you probably are the best game dev/artist i have seen in my 4-5 years of programming and i really would like to look at your source code could you email it to me at alecchan1@gmail.com please :)
     
  46. thetnswe

    thetnswe

    Joined:
    Aug 23, 2010
    Posts:
    46
    I know that this thread is out of date... I am working on the third person controller right now as I would like to make third person controller such as in Gear of Wars 2.. If you can share me a bit of your third person controller, it would be really kind from you...... please pm me and thetnswe@gmail.com ... looking forward from you.. Thanks
     
  47. TwiiK

    TwiiK

    Joined:
    Oct 23, 2007
    Posts:
    1,729
    Ages since I've posted here so I've gather up all the replies since my last post and attempted to answer them as best I can.

    No.

    It's been so long since I've worked on this, but my bullet code is still based on what Spk made public in his Paintrain thread (I think I've linked to his version as well as posted most, if not all, of my own version a while back). I've never experienced mid air hits. Btw, the "Dontgothroughthings" script does the same thing my code does. My bullet is a normal gameobject and each frame I move it forward then I raycast from the position the bullet had last frame to the position it has this frame. So even if the speed is a billion and the bullet moved completely through your entire level in one frame it would still correctly register a hit because you would raycast from the last position to the current position.

    Funny Unreal 3 doesn't account for this. To fix this you must just add the momentum of the player to the bullet/rocket/grenade/whatever when it is fired. So if the player moves sideways at 10 units per frame you must add that speed to the projectile when it is fired. In my game you can hit yourself because I don't account for this. :)

    I haven't noticed bullets hitting and not causing damage. But there's so much code and a lot is cut and paste from examples etc. so it sure is possible. :)

    I haven't got the time to look at your code, but if I do continue this project I will make sure to fix any bugs and keep you updated on what I did to remedy them. :)

    No

    Player respawn is taken from the official Third Person Platform tutorial.

    Of course it's not all by my own when you put it like that. I've made it myself, but I've looked at all the offical tutorials, examples, other peoples work, gamasutra, gamedev, the scripts wiki etc.

    What problem is that? I'm sorry if you've asked before, but I'm doing my best to get back into this thread.

    Multiplayer or co-op will be a feature I will add at some point if I do continue with this and then I will probably reevaluate my bullet code to see what works best. Raycasts are undoubtably the easiest to work with.

    Thanks, but no source code. :)

    I will share what I can if I open this project up.
     
  48. xXToastyXx

    xXToastyXx

    Joined:
    Jan 25, 2011
    Posts:
    38
    hey Twiik, where did you get those nice weapon sounds from?
     
  49. TwiiK

    TwiiK

    Joined:
    Oct 23, 2007
    Posts:
    1,729
    Gathered around the interweb from mods etc. Probably don't have the rights to use most of them, but it's just for fun so I don't see any harm to it.

    FPSbanana, ModDB, sites like that.
     
  50. Khyrid

    Khyrid

    Joined:
    Oct 8, 2010
    Posts:
    1,790
    Okay, so I must make a variable that stores the player's momentum and then when a bullet object (or in my case a tracer) is created apply that momentum to the object.

    I'm using this in my tracer code:

    Code (csharp):
    1. instantiatedProjectile.velocity = transform.TransformDirection(Vector3 (tracerAccuX, tracerAccuY , initialSpeed));
    I assume this is where I insert the momentum adjustments to the X and Y? And how do I store the player's momentum? var playerXspeed = ???? var playerYspeed = ???? ......profit? Any help much appreciated. :)