添加背景

新建一个图层
选中bg这一对象 点击右上角Layer AddLayer 新建一个图层将Layer设置为新建的图层

在scence 中添加player png 设置合适大小 添加BoxCollide 2D 设置合适size

设计Player 预制体

控制player
添加ridebody 2D
没有重力 所以设置Gravity scale ==0
并且锁定旋转 Constraints-》选中Freeze rotation z x
为了控制Player 移动 给他添加newscript PlayerController.cs
把该脚本拖到Scripts文件夹里面
最后一步把灰色的player对象拖到Prefabs文件夹里面 对象变成蓝色

设立围墙边界

设置四面刚体 boxclollides

设置upWall 的boxCollide来阻挡player越界
gameManagerScript.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class gameManagerScripts : MonoBehaviour

{

	private BoxCollider2D rightWall;
	private BoxCollider2D leftWall;
	private BoxCollider2D upWall;
	private BoxCollider2D downWall;

    // Start is called before the first frame update
    void Start()
    {
        ResetWall();//引用下面设置围墙的这个方法
    }

    // Update is called once per frame
    void Update()
    {
        
    }
    void ResetWall()
    {
    	//初始化墙的对象为之前在Scence里创建的对象
    	rightWall=transform.Find("rightWall").GetComponent<BoxCollider2D>();
    	leftWall=transform.Find("leftWall").GetComponent<BoxCollider2D>();
    	upWall=transform.Find("upWall").GetComponent<BoxCollider2D>();// x=Screen.width/2 y=Screen.hight
    	downWall=transform.Find("downWall").GetComponent<BoxCollider2D>();
		//新建一个三维坐标来确定upWall的坐标
    	Vector3 upWallPositon=Camera.main.ScreenToWorldPoint(new Vector3(Screen.width/2,Screen.height));
    	//将上墙的y坐标位置设置为屏幕顶端加上上墙宽度的一半
           upWall.transform.position=upWallPositon+new Vector3(0,0.5f,0);
           //获取屏幕宽度
           float width=Camera.main.ScreenToWorldPoint(new Vector2(Screen.width,Screen.height)).x*2;
           //设置上墙的长度宽度尺寸
           upWall.size=new Vector2(width,1);

    	

    }
}

优化
四面墙的位置和尺寸

Vector3 tempPosition=Camera.main.ScreenToWorldPoint(new              Vector3(Screen.width,Screen.height));

           upWall.transform.position=new Vector3(0,tempPosition.y+0.5f,0);
           upWall.size=new Vector2(tempPosition.x*2,1);

    	
           downWall.transform.position=new Vector3(0,-tempPosition.y-0.5f,0);
           downWall.size=new Vector2(tempPosition.x*2,1);

           rightWall.transform.position=new Vector3(tempPosition.x+0.5f,0,0);
           rightWall.size=new Vector2(1,tempPosition.y*2);

        
           leftWall.transform.position=new Vector3(-tempPosition.x-0.5f,0,0);
           leftWall.size=new Vector2(1,tempPosition.y*2);

因为屏幕大小不确定
因此墙和player的位置和尺寸都要重新用代码生成
借用
Camera.main.ScreenToWorldPoint(new Vector3(Screen.width,Screen.height))
来转化坐标(屏幕坐标转化为世界坐标)

控制player的位置生成

gameManagerScript.cs中添加下面代码

public Transform player1;
public Transform player2;
    // Start is called before the first frame update
    void Start()
    {
        ResetWall();
        ResetPlayer();
    }

    void ResetPlayer()
    {
        Vector3 player1Position=Camera.main.ScreenToWorldPoint(new Vector3(100,Screen.height/2,0));
        player1Position.z=0;
        player1.position=player1Position;

        Vector3 player2Position=Camera.main.ScreenToWorldPoint(new Vector3(Screen.width-100,Screen.height/2,0));
        player2Position.z=0;
        player2.position=player2Position;      

    }

添加运动的小球

选中小球
给小球添加碰撞体circle collide2D
添加刚体rigidbody2D
创建新材质physics material 2D
Friction摩擦力设置为0
Bounciness弹力设置为1
刚体质量设小点0.2
Angular drug 摩擦力设置为0
重力设置为0
添加脚本ball.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Ball : MonoBehaviour
{
	private Rigidbody2D rigidbody2D;//声明一个刚体引用

    // Start is called before the first frame update
    void Start()
    {
        rigidbody2D=GetComponent<Rigidbody2D>();//把前面声明的对象初始化为ball的刚体对象
        int number=Random.Range(0,2);//生成随机数0,1
        if (number==1)
        {
        	rigidbody2D.AddForce(new Vector2(100,0));//是1的话,向右边运动
        }
        else
        {
        	rigidbody2D.AddForce(new Vector2(-100,0));//是0的话,向左边运动
        }
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

目前的BUG
小球运动着运动着某一时间就会上下运动触碰不到两个平板了
或者飞就出去了

控制playe平板的侧边运动产生的摩擦对小球的影响

碰撞检测
首先,给player12加上“Player”标签
然后,写碰撞检测代码
控制小球在碰到平板player的时候速度改变

void OnCollisionEnter2D(Collision2D col)//当小球遇到碰撞提col时,执行以下
    {
        if(col.collider.tag=="Player")//判断碰撞体是否为player
        {
        	Vector2 velocity=rigidbody2D.velocity;//获取小球速度
        	velocity.y=velocity.y+col.rigidbody.velocity.y/2;
        	rigidbody2D.velocity=velocity;//小球新的y方向速度为原始速度加上平板palyer的y方向速度的一半
        }
    }

在优化下X方向的速度
当速度小于9的时候将小球速度恢复成10,这样小球水平方向就不会越来越慢了

void Update()
    {
    	Vector2 velocity=rigidbody2D.velocity;
    	if (velocity.x<9 && velocity.x>-9 && velocity.x!=0)
    	{
    		if(velocity.x>0)
    		{
    			velocity.x=10;
    		}
    		else
    		{
    			velocity.x=-10;

    		}
    		rigidbody2D.velocity=velocity;
    	}
    }

不过现在出现了个bug
球的速度一高就飞出去了
解决方法
把小球的rigidbody2D设置中的Collision detection设置为continues

设置画面积分UI

新建text

然后在ball脚本里检测小球碰撞左右墙的次数
碰左墙 右边玩家2加一分
碰右墙 左边一号玩家加一分
先在ball.cs的碰撞检测方法里判断小球碰到的对象名字是rightWall或者leftWall时。。。
分值处理的部分放在gameManagerScript.cs里面(用单例模式)
添加以下代码

using UnityEngine.UI;
public class gameManagerScripts : MonoBehaviour

{
      private static gameManagerScripts _instance;//单例模式

      public static gameManagerScripts Instance//单例模式
      {
        get 
        {
          return _instance;
        }
      }

     private int score1;
     private int score2;

     public static Text score1Text;
     public static Text score2Text;


    void Awake()//单例模式
    {
      _instance=this;
    }
public void ChangeScore(string wallName)
    {
      if(wallName=="leftWall")
      {
        score2++;
      }
      else if(wallName=="rightWall")
      {
        score1++;
      }

   //   Debug.Log(score1.ToString());
      //Debug.Log(score2.ToString());
      score1Text= GameObject.Find("Canvas").transform.GetChild(0).gameObject.GetComponent<Text>();

      score1Text.text=score1.ToString();
     // Debug.Log(score1Text.text);
      score2Text= GameObject.Find("Canvas").transform.GetChild(1).gameObject.GetComponent<Text>();
      
      score2Text.text=score2.ToString();
    }

ball.cs 脚本里碰撞检测器部分加入以下代码

if(col.gameObject.name=="rightWall" || col.gameObject.name=="leftWall")
        {
        	gameManagerScripts.Instance.ChangeScore(col.gameObject.name);
        }

出现问题 得分数值score不更新
Object reference not set to an instance of an object
解决方法
初始化对象(注意获取的是Canvas的子对象)
后再复制

score1Text= GameObject.Find("Canvas").transform.GetChild(0).gameObject.GetComponent<Text>();
score1Text.text=score1.ToString();

添加音效

载入Audio文件
在player对象上添加Audio source组件,然后把音频文件click拖进AudioClip ,然后取消选中Audio on Awake
在PlayerController.cs脚本里添加下面代码

private AudioSource audio;
    void Start()
    {
        
        rigidbody2D=GetComponent<Rigidbody2D>();
        audio=GetComponent<AudioSource>();
    }
    void OnCollisionEnter2D()
    {
    	audio.pitch=Random.Range(0.8f,1.2f);//随机产生一个数字表示语音播放的速度
    	audio.Play();
    }

在下面给两边的墙添加生效,小球碰到墙的时候产生音效
给rightWall 添加wall.cs脚本,然后添加AudioSource组件,play on awake取消勾选

private AudioSource audio;

        // Start is called before the first frame update 
    void Start()
    {
        
        audio=GetComponent<AudioSource>();
    }
    void OnCollisionEnter2D()
    {
    	audio.pitch=Random.Range(0.8f,1.2f);
    	audio.Play();
    }

背景音乐的话,给GameManager添加一个AudioSource组件,吧Music.MP3拖进去,play on awake和Loop勾选,Volume设置0.8

添加游戏重置按钮

新建一个Button,手动修改text为“Reset”,在gameManagerScripts.cs脚本里添加如下方法

public void ReSet()
    {
       GameObject.Find("Ball").SendMessage("Reset");
       ResetPlayer();


       score1=0;
       score2=0;
       score1Text= GameObject.Find("Canvas").transform.GetChild(0).gameObject.GetComponent<Text>();
       score1Text.text=score1.ToString();

       score2Text= GameObject.Find("Canvas").transform.GetChild(1).gameObject.GetComponent<Text>();
       score2Text.text=score2.ToString();


   //    Debug.Log(score1Text.text);

    }

手动将Button重命名为“ResetButton",将GameManager对象拖进On Click里,然后在On Click里选择在gameManagerScripts的ReSet()方法。