unity 2D乒乓球小游戏(单人Ai对战)

文章目录

    • 概要:了解乒乓球在Unity中的游戏规则,理解玩家与人机的对战运行思路
    • 整体架构流程
    • 技术细节:游戏使用的、Unity2023.1.16f1c1版本,为2D项目,如有问题请评论留言。                                          
    • 小结:该游戏Ai智能化程度较低,适合新手进行项目练习

游戏画面

中线为Line调整为0.1cm,左边为玩家操作的球拍,右边为Ai自动操控的球拍。注意中线设置的细一点不然会影响美观。


场景搭建

需要搭建的物体有四个墙体,球体,两个球拍。位置可以根据自己喜好摆放,下面我们进入物体设置。

场景设置

1.我们首先对墙体进行设置,我们需要四面墙体,来阻挡球体的运行和得分项的判断。

我们先进行墙体碰撞器的设置,我们需要当球体与墙体碰撞时给我们及时的反馈

这里我们使用的2D碰撞器,可以直接编辑碰撞器的长宽

我们在这里是需要设置四面墙体(碰撞器)将屏幕画面围起来,模拟桌面。这样我们发射球体的时候,球体就不会跑到屏幕外面,他就会按照我们设置到的速度和轨迹一直在游戏中运行。

需要注意的是我们将墙体摆设时不要在交界处留有缝隙,以免球体跑出,相对的墙体Tansform中的position的X,Y值是相反的。

2.设置球拍(两个长方体)

给两个球拍添加刚体组件用于球体碰撞时进行对球的弹回。

因为游戏只需要球拍进行Y轴的移动所以我们将X,Z轴进行锁定。

3.球体的设置:我们首先给球体添加RigidBody 2D(刚体组件),Box Collider 2D(碰撞器)

球体位置我们设置到桌子中心就可以了,球体大小自由设置。

脚本设置

在这里我就不解释代码的运行逻辑了,注释我都标注过了。有不懂问题可以评论留言。

球体代码:


using UnityEngine;

public class Ball : MonoBehaviour
{
    //初始速度
    public float speed = 200.0f;
    //刚体组件变量名
    private Rigidbody2D _rigidbody;
    private void Awake()
    {
        _rigidbody = GetComponent<Rigidbody2D>();
    }
    private void Start()
    {
        AddStartingForce();
        ResetPosition();
    }
    public  void AddStartingForce()
    {
        //初始时随机向一个方向移动
        float x = Random.value < 0.5f ? -1.0f : 1.0f;
        //为球初始发射提供方向角度
        float y = Random.value < 0.5f ? Random.Range(-1.0f, 0.5f):
                                    Random.Range(0.5f,1.0f);
        //给球体赋值
        Vector2 direction=new Vector2(x,y);
        //给球体发射速度
        _rigidbody.AddForce(direction*this.speed);
    }
    public void AddForce(Vector2 force)
    {
        _rigidbody.AddForce(force);
    }
    public void ResetPosition()
    {
        //重新定义球位置
        _rigidbody.position = Vector3.zero;
        _rigidbody.velocity= Vector3.zero;
        
        
    }
}

2.玩家球拍的脚本

移动脚本

using UnityEngine;

public class PlayerPaddle :Paddle
{
    //定义私有的方向变量 用于球拍跟踪
    private Vector2 _direction;
    
    private void Update()
    {
        //给球拍移动按键  判断往那个方向移动
        if (Input.GetKey(KeyCode.W)||Input.GetKey(KeyCode.UpArrow)) {
            _direction = Vector2.up;
        }else if (Input.GetKey(KeyCode.S) || Input.GetKey(KeyCode.DownArrow))
        {
            _direction=Vector2.down;
        }
        else
        {
            _direction= Vector2.zero;
        }
    }
    private void FixedUpdate()
    {
        //判断球是否在往某个方向移动
     if(_direction.sqrMagnitude != 0)
        {
            //调用Paddle中的变量名 给球体一个加速度
            _rigidbody.AddForce(_direction*this.speed);

        }   
    }
}

 给球拍反作用力脚本

using UnityEngine;

public class BouncySurface : MonoBehaviour
{
    public float bounceStrength;
    private void OnCollisionEnter2D(Collision2D collision)
    {
        //给球体一个反作用力
        Ball ball=collision .gameObject.GetComponent<Ball>();
        if(ball != null )
        {
            Vector2 normal =collision.GetContact(0).normal;
            ball.AddForce(-normal*this.bounceStrength);
        }
    }
}
 

 3.Ai脚本

using UnityEngine;
public class ComputerPaddle : Paddle
{
    public Rigidbody2D ball;
    private void FixedUpdate()
    {
        //判断球是否往电脑这边移动
        if (this.ball.velocity.x > 0.0f)
        {
            //球拍开始往球落点的位置移动
            //判断球的落点位置在球拍上方 还是下方
            //给电脑赋值移动速度
            if (this.ball.position.y > this.transform.position.y)
            { _rigidbody.AddForce(Vector2.up * this.speed);
            } else if (this.ball.position.y < this.transform.position.y)
            { _rigidbody.AddForce(Vector2.down * this.speed);
            }
        }
        else
        {
            if (this.transform.position.y > 0.0f)
            {
                _rigidbody.AddForce(Vector2.down * this.speed);
            }
            else if (this.transform.position.y < 0.0f)
            {
                _rigidbody.AddForce(Vector2.up * this.speed);
            }
        }
    }
}

给Ai添加反作用力脚本 (与玩家球拍的脚本同一个)

using UnityEngine;

public class BouncySurface : MonoBehaviour
{
    public float bounceStrength;
    private void OnCollisionEnter2D(Collision2D collision)
    {
        //给球体一个反作用力
        Ball ball=collision .gameObject.GetComponent<Ball>();
        if(ball != null )
        {
            Vector2 normal =collision.GetContact(0).normal;
            ball.AddForce(-normal*this.bounceStrength);
        }
    }
}
 

3.左右墙体脚本 

规则:当球体碰到对方墙面时,自己得一分。

所以我们要对左右墙体添加脚本判定当球体碰到对面墙体时执行的命令。

using UnityEngine;

using UnityEngine.EventSystems;
public class ScoringZone : MonoBehaviour
{
    //碰撞触发器
    public EventTrigger.TriggerEvent scoreTrigger;
    private void OnCollisionEnter2D(Collision2D collision)
    {
        Ball ball = collision.gameObject.GetComponent<Ball>();
        if (ball != null)
        {
           BaseEventData eventData=new BaseEventData(EventSystem.current);
            this.scoreTrigger.Invoke(eventData);        
        }
    }
}

最后我们设置管理脚本

using UnityEngine;
using UnityEngine.UI;
public class GameManager : MonoBehaviour
{
    public Ball ball;
    private int _playerScore;
    private int _computerScore;
    //ui 分值
    public Text plauerScoreText; 
    public Text computerScoreText;

    public Paddle ComputerPaddle;
    public Paddle PlayerPaddle;
    public  void PlayerScore()
    {
        //玩家积分累计
        _playerScore++;
        //ui界面
        this.plauerScoreText .text = _playerScore.ToString();
        RestRound();
    }
    public void CpmputerScore()
    {
        //电脑积分累计
        _computerScore++;
        //ui反馈
        this.computerScoreText.text = _computerScore.ToString();
        RestRound();
    }
  
    private void RestRound()
    {
        this.ball.AddStartingForce();
        this.ball.ResetPosition();
        this.PlayerPaddle.ResetPosition();
        this.ComputerPaddle.ResetPosition();
    }
}

我们还需要将得分的ui表示出来

因为我是用的2023版本unity我个人使用的text文本 是旧版

txt设置

值得一提的是我们在创建完游戏管理器后不要忘记添加对应的积分类(两面墙都需要添加对应的类)

有什么不懂的问题可以直接私聊我或者评论也可以。

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值