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

Scripting AI for 2D Pong Game

Discussion in 'Scripting' started by lewis1682, Feb 18, 2014.

  1. lewis1682

    lewis1682

    Joined:
    Feb 18, 2014
    Posts:
    4
    Hey guys,

    So I have recently been developing a 2D game of Pong. Currently there are two players, player 1 and player 2, both from the same prefab. Player 1 is controlled using the W and S buttons, where as player 2 is crontrolled using the arrows.

    This all works perfect. However I now want to move up a step where I include the option to turn AI controlled on or off. The AI would take over player 2, obviously the aim for the AI would be to move up and down to hit the ball and hit the players back wall to score points, and at the same time to move to save the ball from hittings their own wall.

    How would it be possible to script something that allows the AI to control the player and see the ball and move to intercept it. I would like to make it that the player does stand some sort of chance against the AI though.

    Thanks in advance for helping me.

    P.S I really want to begin learning AI scripting, therefor if anyone knows where I can find some decent tutorials that would be great, my main scripting language is Javascript.
     
  2. Josh707

    Josh707

    Joined:
    Jul 12, 2012
    Posts:
    71
    I'm pretty sure the computer paddles in most if not all pong games don't try to prevent the ball from passing them and score on the player, they just follow the ball. Normally you'd just test the paddle's position on one axis against the ball's, if the ball is higher move the paddle up and vice versa, to make it smoother scale the speed by the distance of the paddle and ball on the one axis and cap it or it will be unbeatable.
     
  3. lewis1682

    lewis1682

    Joined:
    Feb 18, 2014
    Posts:
    4
    Okay so I see the concept now, but how could I put that into a script?
     
  4. Josh707

    Josh707

    Joined:
    Jul 12, 2012
    Posts:
    71
    Something like this:

    Code (csharp):
    1.  
    2. Vector3 move = Vector3.zero;
    3. float speed = 2.0f;
    4.  
    5. void Update(){
    6.     float d = ball.position.y - transform.position.y;
    7.     if(d > 0){
    8.         move.y = speed * Mathf.Min(d, 1.0f);    
    9.     }
    10.     if(d < 0){
    11.         move.y = -(speed * Mathf.Min(-d, 1.0f));
    12.     }
    13.     transform.position += move * Time.deltaTime;
    14. }
    15.  
    I'm not sure how you're handling movement and stuff but maybe this gives you an idea
     
  5. lewis1682

    lewis1682

    Joined:
    Feb 18, 2014
    Posts:
    4
    Okay so I put your code into a script and this is what I came up with:
    Code (csharp):
    1.  
    2. var speed : float = 80;
    3. var Ball : Transform;
    4. private var d : float;
    5. var move : Vector3;
    6.  
    7. function Update () {
    8.     d = Ball.position.y - transform.position.y;
    9.     if (d > 0)
    10.     {
    11.         move.y = speed * Mathf.Min(d, 40);
    12.     }  
    13.     if (d < 0)
    14.     {
    15.         move.y = -speed * Mathf.Min(-d, 40);
    16.     }
    17. }
    This does what I want it to do, however when it hits one of the top walls, these have a box collider, it will glitch and start to shake, is there a way to tell it that if it hits that collider to stop moving in that direction. These walls are called top and bottom wall. They are set up in a gameSetup script:
    Code (csharp):
    1.  
    2.     topWall.size = new Vector2 (mainCam.ScreenToWorldPoint (new Vector3 (Screen.width * 2f, 0f, 0f)).x, 1f);
    3.     topWall.center = new Vector2 (0f, mainCam.ScreenToWorldPoint (new Vector3 ( 0f, Screen.height, 0f)).y + 0.5f);
    4.    
    5.     bottomWall.size = new Vector2 (mainCam.ScreenToWorldPoint (new Vector3 (Screen.width * 2, 0f, 0f)).x, 1f);
    6.     bottomWall.center = new Vector2 (0f, mainCam.ScreenToWorldPoint (new Vector3( 0f, 0f, 0f)).y - 0.5f);
    7.  
     
  6. Josh707

    Josh707

    Joined:
    Jul 12, 2012
    Posts:
    71
    Hmm I had that problem too but I didn't use any colliders, I checked the paddles height and position against some limits and used it to prevent the movement altogether, something like this:

    Code (csharp):
    1.  
    2. bool PaddleBoundsUp(){
    3.     if(pos.y >= y_limits.y - paddle_halfheight){
    4.         pos.y = y_limits.y - paddle_halfheight;
    5.         return true;
    6.     }
    7.     else{
    8.         return false;  
    9.     }
    10. }
    Then put that into the if statement for moving it

    Code (csharp):
    1. if(d > 0  !PaddleBoundsUp())
    You could probably do something similar with colliders, maybe use OnCollisionEnter/Exit and check if the paddle is above or below whatever Y value is the middle of the play area
     
  7. Marcus-Nighitngale

    Marcus-Nighitngale

    Joined:
    Jan 25, 2015
    Posts:
    1
    Not Sure about c# but have it work in java script like this.

    Code (JavaScript):
    1.  
    2. #pragma strict
    3.  
    4. var speed       : float = 10;
    5. var Ball           : Transform;
    6. var Computer : float;
    7.  
    8. function Update ()
    9. {
    10.     Computer = Ball.position.y - transform.position.y;
    11.     if (Computer > 0){
    12.         rigidbody2D.velocity.y = speed;
    13.     }
    14.     else if(Computer < 0){
    15.         rigidbody2D.velocity.y = speed *-1;
    16.     }
    17.     else{
    18.         rigidbody2D.velocity.y = 0;
    19.     }
    20.    
    21.     rigidbody2D.velocity.x = 0;
    22. }
     
  8. nanthsree22

    nanthsree22

    Joined:
    Mar 21, 2014
    Posts:
    1
    I tried the above code in my game, but like you said in the earlier post, the Bot paddle begins to shake and slowly drifts off the screen, that is, there is a drift in the x direction :O. Please help
     
  9. gouthammannuru

    gouthammannuru

    Joined:
    Sep 9, 2015
    Posts:
    16
    hi , checck my compleate code for ping pong game in javascript


    #pragma strict

    var S1 = 200;
    var S2 = 200;
    var XBall = 200;
    var YBall = 400;
    var Direction = 1;
    var XBallDirection = 1;
    var YBallDirection = 1;
    var RightWall = 800;
    var leftwall = 0;
    var player1:int = 0;
    var player2 = 0;


    function Start () {


    }

    function Update () {


    if(Input.GetKey(KeyCode.W)){
    S1 = S1-5;
    }
    if(Input.GetKey(KeyCode.S)){
    S1 = S1+5;
    }
    if(Input.GetKey(KeyCode.UpArrow)){
    S2 = S2-5;
    }
    if(Input.GetKey(KeyCode.DownArrow)){
    S2 = S2+5;
    }

    if(XBall<-10){
    XBall = 400;
    YBall = 240;
    }
    if(XBall>810){
    XBall = 400;
    YBall = 240;
    }

    YBall = YBall + 2*YBallDirection;
    XBall = XBall + 2*XBallDirection;

    if(YBall<0){
    YBallDirection = -YBallDirection;
    }
    if(YBall>480){
    YBallDirection = -YBallDirection;

    }

    if(XBall>10&&XBall<30&&YBall>S1&&YBall<S1 + 100){
    XBallDirection = -XBallDirection;

    }
    if(XBall>750&&XBall<790&&YBall>S2&&YBall<S2 + 100){
    XBallDirection = -XBallDirection;

    }
    if(XBall == RightWall){
    player1 += 1;
    }
    //if(YBall == RightWall){
    //player1 += 1;
    //}
    if(XBall == leftwall){
    player2 += 1;
    }
    //if(YBall == leftwall){
    //player2 += 1;
    //}

    }

    function OnGUI() {

    GUI.Box(Rect(10,S1,20,100),"S1");
    GUI.Box(Rect(770,S2,20,100),"S2");
    GUI.Box(Rect(XBall,YBall,20,20),"Ball");
    GUI.Box(Rect(0,0,100,20),"Player1");
    GUI.Box(Rect(120,0,30,20),player1.ToString());
    GUI.Box(Rect(700,0,100,20),"Player2");
    GUI.Box(Rect(650,0,30,20),player2.ToString());
    }
     
  10. gouthammannuru

    gouthammannuru

    Joined:
    Sep 9, 2015
    Posts:
    16
  11. ICantCode

    ICantCode

    Joined:
    Dec 9, 2015
    Posts:
    1
    This is my AI script, in c#, and I don't have the glitching problem through walls. The paddle and the walls all have box colliders on.
    Hope this helps!

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class AI : MonoBehaviour {
    5.     public GameObject Ball;
    6.     private Transform CurrentTransform;
    7.     private int speed = 30;
    8.     // Use this for initialization
    9.     void Start () {
    10.         CurrentTransform = this.transform;
    11.     }
    12.  
    13.     // Update is called once per frame
    14.     void FixedUpdate () {
    15.         CurrentTransform = this.transform;
    16.         if (CurrentTransform.position.x < Ball.transform.position.x) {
    17.             if (CurrentTransform.position.y < Ball.transform.position.y) {
    18.                 GetComponent<Rigidbody2D> ().velocity = new Vector2 (0, 1) * speed;
    19.             } else if (CurrentTransform.position.y > Ball.transform.position.y) {
    20.                 GetComponent<Rigidbody2D> ().velocity = new Vector2 (0, -1) * speed;
    21.             } else {
    22.                 GetComponent<Rigidbody2D> ().velocity = new Vector2 (0, 0) * speed;
    23.             }
    24.         }
    25.     }
    26. }
    One problem I don have though is that the Ai paddle is constantly stuttering. I think this is due to the fixed update being called so many times but I'm not sure how to fix it.
     
  12. jnouel

    jnouel

    Joined:
    Oct 12, 2014
    Posts:
    1
    @ICantCode
    The reason it stutters is because there's always some difference (very minor sometimes) in the Y position between the 2 objects. Set an offset for the difference in Y before moving instead . Don't just test if it's less than or greater than. Test with 0.10 or 0.20. You will see the difference immediately.

    Also, assign the RigidBody2D reference to a variable in the Awake or Start method. It improves performance.

    PS. I'm not sure why you're testing the X position before entering the Y move determination section.
     
  13. kylewill713

    kylewill713

    Joined:
    Jun 22, 2016
    Posts:
    5
    @ICantCode
    Super simple AI code that doesn't stutter could be like this. Just Lerp the velocity.

    Code (CSharp):
    1.     public Ball theBall;
    2.     public float speed = 30;
    3.     public float lerpSpeed = 1f;
    4.     private Rigidbody2D rigidBody;
    5.  
    6.     void Start()
    7.     {
    8.         rigidBody = GetComponent<Rigidbody2D>();
    9.     }
    10.    
    11.     void FixedUpdate () {
    12.         if (theBall.transform.position.y > transform.position.y)
    13.         {
    14.             if (rigidBody.velocity.y < 0) rigidBody.velocity = Vector2.zero;
    15.             rigidBody.velocity = Vector2.Lerp(rigidBody.velocity, Vector2.up * speed, lerpSpeed * Time.deltaTime);
    16.         }
    17.         else if (theBall.transform.position.y < transform.position.y)
    18.         {
    19.             if (rigidBody.velocity.y > 0) rigidBody.velocity = Vector2.zero;
    20.             rigidBody.velocity = Vector2.Lerp(rigidBody.velocity, Vector2.down * speed, lerpSpeed * Time.deltaTime);
    21.         }
    22.         else
    23.         {
    24.             rigidBody.velocity = Vector2.Lerp(rigidBody.velocity, Vector2.zero * speed, lerpSpeed * Time.deltaTime);
    25.         }
    26.     }
     
    FancyACuppa and MehreenMalik like this.
  14. gouthammannuru

    gouthammannuru

    Joined:
    Sep 9, 2015
    Posts:
    16
  15. ojaseminem

    ojaseminem

    Joined:
    Apr 26, 2021
    Posts:
    1
  16. tinyotter

    tinyotter

    Joined:
    Feb 4, 2023
    Posts:
    1
    I know this was a long time ago, but can someone explain to me why @kylewill713 's solution works?
     
  17. sa723697

    sa723697

    Joined:
    Dec 23, 2020
    Posts:
    1
    @tinyotter I think he used lerp for avoiding stuttering. Lerp helps to smooth the movement, as far I know.
    if (rigidBody.velocity.y < 0)
    rigidBody.velocity = Vector2.zero;
    I am confused with these 2 lines, can anyone explain this to me.