Unity游戏制作:2D弹球游戏 Pong(附完整项目)

介绍

这里,又来做弹球游戏了……(^_^)

之前自学了一段时间的 unity,还是先做一款 2D 的小游戏吧,运行效果如下:

Unity游戏制作:2D弹球游戏 Pong(附完整项目)

目录

下载

项目制作过程

一、拼界面

二、主程序Game.cs

1)显示初始化

2)实现小球移动

3)挡板移动

4)小球碰撞墙壁

5)挡板与小球的碰撞

6)更新得分

7)小球拖尾

完整代码


下载

下载地址:

Unity2D弹球游戏 可运行完整项目  0 积分

其他下载:

http://101.201.112.95/2021/Unity_Pong.zip

 

项目的结构,打开场景Pong文件,运行就可以了(2017.3开发的,更高版本应该可以兼容吧,还真没试过)

Unity游戏制作:2D弹球游戏 Pong(附完整项目)

 

之前做了H5和Python版本的,【传送门】:

PyGame游戏制作: 弹球游戏Pong(附上Python完整代码)

HTML5游戏制作: 弹球游戏PONG (附完整代码)

 

 

项目制作过程

简单聊下制作过程吧,开发2D游戏也是第一次尝试。

一、拼界面

Unity游戏制作:2D弹球游戏 Pong(附完整项目)

界面中包括6个显示元素,通过拖拽到了对于的位置上。分别是:

背景图片:bg

挡板图片:leftBlock、rightBlock

小球图片:ball

分数显示:leftScore、rightScore (使用的ugui的 text组件)

 

注意1:2D中图片单位与像素坐标比例为 1 : 100 (Pixels To Units)

Unity游戏制作:2D弹球游戏 Pong(附完整项目)

上图中,3.7对于的像素概念是370

 

注意2:需要设置图片的前后遮挡关系order in layer,数值大的在顶层显示

Unity游戏制作:2D弹球游戏 Pong(附完整项目)

下面会使用这些数值计算小球的运动以及碰撞(没用物理引擎...)

 

 

二、主程序Game.cs

整理下程序的制作思路。

1)显示初始化

首先、定义与界面相同的GameObject对象,并在Start函数中进行初始化(绑定下界面中的物体)

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

public class Game : MonoBehaviour {

  //挡板
    private GameObject leftBlock;
    private GameObject rightBlock;

    //小球
    private GameObject ball;

    //左右得分 ugui text
    private Text leftScore;
    private Text rightScore;

    void Start () {
        Application.targetFrameRate = 60; //关掉垂直同步后,设置帧频

        leftBlock = GameObject.Find ("leftBlock");
        rightBlock = GameObject.Find ("rightBlock");

        ball = GameObject.Find ("ball");

        leftScore = GameObject.Find ("leftScore").GetComponent<Text> ();
        rightScore = GameObject.Find ("rightScore").GetComponent<Text> ();

    }

 

2)实现小球移动

定义移动速度变量、及单位像素比例变量(后面会多次用到)

    //单位与像素坐标比例为 1: 100 (Pixels To Units)
    private float pixelScale = 100.0f;

    //小球移动速度和方向
    private float ballSpeed = 10.0f;
    private float ballSpeedAngle = 0.25f * Mathf.PI;

在Update函数中实现小球移动

void Update() {

	//计算小球移动速度(极坐标计算)
	float speedY = Mathf.Cos(ballSpeedAngle) * ballSpeed / pixelScale;
	float speedX = Mathf.Sin (ballSpeedAngle) * ballSpeed / pixelScale;

	//小球移动
	Vector2 ballPosition = ball.transform.position;
	ballPosition.x += speedX;
	ballPosition.y += speedY;
	ball.transform.position = ballPosition;

}

 

3)挡板移动

这里以左侧挡板移动举例,在Update函数中,添加键盘的控制事件,并通过控制挡板的移动速度,实现效果。

void Update() {

	//按下按键
	if (Input.GetKeyDown (KeyCode.W)) {  
		Debug.Log("您按下了W键");  
		leftMoveSpeed = 0.08f;
	}  

	if (Input.GetKeyDown (KeyCode.S)) {  
		Debug.Log("您按下了S键");  
		leftMoveSpeed = -0.08f;
	}  

	//抬起按键  
	if (Input.GetKeyUp (KeyCode.W))  
	{  
		Debug.Log("您抬起了W键");  
		leftMoveSpeed = 0.0f;
	}  

	if (Input.GetKeyUp (KeyCode.S))  
	{  
		Debug.Log("您抬起了S键");  
		leftMoveSpeed = 0.0f;
	} 

	//左右挡板移动
	Vector2 leftBlockPosition = leftBlock.transform.position;
	leftBlockPosition.y += leftMoveSpeed;
	//碰到边缘处理
	if (leftBlockPosition.y > 2.5f) {
		leftBlockPosition.y = 2.5f;
	}
	//碰到边缘处理
	if (leftBlockPosition.y < -2.5f) {
		leftBlockPosition.y = -2.5f;
	}
	leftBlock.transform.position = leftBlockPosition;

}

 

4)小球碰撞墙壁

思路实际上就是计算小球的位置,改变小球的移动角度。

    //小球碰撞到边缘后反弹
    if (ballPosition.x > 400 / pixelScale) { //右侧
        ballSpeedAngle = -ballSpeedAngle;
    }
    if (ballPosition.x < -400 / pixelScale) { //左侧
        ballSpeedAngle = -ballSpeedAngle;
    }
    if (ballPosition.y > 300 / pixelScale) { //上侧
        ballSpeedAngle = -(ballSpeedAngle - Mathf.PI);
    }
    if (ballPosition.y < -300 / pixelScale) { //下侧
        ballSpeedAngle = -(ballSpeedAngle - Mathf.PI);
    }

 

5)挡板与小球的碰撞

	//左边挡板碰撞
	//挡板的宽高分别是 20、100像素,所以计算碰撞区域时,按照宽高一半进行计算
	if (ballPosition.x < leftBlockPosition.x + 10 / pixelScale && ballPosition.x > leftBlockPosition.x - 10 / pixelScale
		&& ballPosition.y < leftBlockPosition.y + 50 / pixelScale && ballPosition.y > leftBlockPosition.y - 50 / pixelScale) {

		//碰撞上了
                   
	}

 

6)更新得分

当小球碰到屏幕左右边缘时,进行得分显示更新

    //左边得分
 	leftScoreNum ++;
	leftScore.text = leftScoreNum.ToString ();

 

7)小球拖尾

在小球对象上,右键添加Trail即可,如下图操作:

Unity游戏制作:2D弹球游戏 Pong(附完整项目)

 

完整代码

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

public class Game : MonoBehaviour {

	//挡板
	private GameObject leftBlock;
	private GameObject rightBlock;

	//小球
	private GameObject ball;

	//左右得分 ugui text
	private Text leftScore;
	private Text rightScore;

	//单位与像素坐标比例为 1: 100 (Pixels To Units)
	private float pixelScale = 100.0f;

	//小球移动速度和方向
	private float ballSpeed = 10.0f;
	private float ballSpeedAngle = 0.25f * Mathf.PI;

	//左右挡板的移动速度
	private float leftMoveSpeed = 0.0f;
	private float rightMoveSpeed = 0.0f;

	private int leftScoreNum = 0;
	private int rightScoreNum = 0;

	// Use this for initialization
	void Start () {

		Application.targetFrameRate = 60; //关掉垂直同步后,设置帧频

		leftBlock = GameObject.Find ("leftBlock");
		rightBlock = GameObject.Find ("rightBlock");

		ball = GameObject.Find ("ball");

		leftScore = GameObject.Find ("leftScore").GetComponent<Text> ();
		rightScore = GameObject.Find ("rightScore").GetComponent<Text> ();

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

		//## 小球移动
		//计算小球移动速度(极坐标计算)
		float speedY = Mathf.Cos(ballSpeedAngle) * ballSpeed / pixelScale;
		float speedX = Mathf.Sin (ballSpeedAngle) * ballSpeed / pixelScale;

		//小球移动
		Vector2 ballPosition = ball.transform.position;
		ballPosition.x += speedX;
		ballPosition.y += speedY;
		ball.transform.position = ballPosition;

		//小球碰撞到边缘后反弹
		if (ballPosition.x > 400 / pixelScale) {
			ballSpeedAngle = -ballSpeedAngle;
			//左边得分
			leftScoreNum ++;
			leftScore.text = leftScoreNum.ToString ();
		}
		if (ballPosition.x < -400 / pixelScale) {
			ballSpeedAngle = -ballSpeedAngle;
			//右边得分
			rightScoreNum ++;
			rightScore.text = rightScoreNum.ToString ();
		}
		if (ballPosition.y > 300 / pixelScale) {
			ballSpeedAngle = -(ballSpeedAngle - Mathf.PI);
		}
		if (ballPosition.y < -300 / pixelScale) {
			ballSpeedAngle = -(ballSpeedAngle - Mathf.PI);
		}


		//左右挡板移动
		Vector2 leftBlockPosition = leftBlock.transform.position;
		leftBlockPosition.y += leftMoveSpeed;
		//碰到边缘处理
		if (leftBlockPosition.y > 2.5f) {
			leftBlockPosition.y = 2.5f;
		}
		//碰到边缘处理
		if (leftBlockPosition.y < -2.5f) {
			leftBlockPosition.y = -2.5f;
		}
		leftBlock.transform.position = leftBlockPosition;


		Vector2 rightBlockPosition = rightBlock.transform.position;
		rightBlockPosition.y += rightMoveSpeed;
		//碰到边缘处理
		if (rightBlockPosition.y > 2.5f) {
			rightBlockPosition.y = 2.5f;
		}
		if (rightBlockPosition.y < -2.5f) {
			rightBlockPosition.y = -2.5f;
		}
		rightBlock.transform.position = rightBlockPosition;


		//### 左挡板控制 ###
		//按下按键
		if (Input.GetKeyDown (KeyCode.W)) {  
			Debug.Log("您按下了W键");  
			leftMoveSpeed = 0.08f;
		}  

		if (Input.GetKeyDown (KeyCode.S)) {  
			Debug.Log("您按下了S键");  
			leftMoveSpeed = -0.08f;
		}  

		//抬起按键  
		if (Input.GetKeyUp (KeyCode.W))  
		{  
			Debug.Log("您抬起了W键");  
			leftMoveSpeed = 0.0f;
		}  

		if (Input.GetKeyUp (KeyCode.S))  
		{  
			Debug.Log("您抬起了S键");  
			leftMoveSpeed = 0.0f;
		} 


		//### 右挡板控制 ###
		//按下按键
		if (Input.GetKeyDown (KeyCode.UpArrow)) {  
			rightMoveSpeed = 0.08f;
		}  

		if (Input.GetKeyDown (KeyCode.DownArrow)) {   
			rightMoveSpeed = -0.08f;
		}  

		//抬起按键  
		if (Input.GetKeyUp (KeyCode.UpArrow)) {  
			rightMoveSpeed = 0.0f;
		}  

		if (Input.GetKeyUp (KeyCode.DownArrow)) {  
			rightMoveSpeed = 0.0f;
		} 

		//### 计算小球与挡板的碰撞 ###
		//左边挡板碰撞
		bool isLeftBlockCrash = false;
		//挡板的宽高分别是 20、100像素,所以计算碰撞区域时,按照宽高一半进行计算
		if (ballPosition.x < leftBlockPosition.x + 10 / pixelScale && ballPosition.x > leftBlockPosition.x - 10 / pixelScale
		    && ballPosition.y < leftBlockPosition.y + 50 / pixelScale && ballPosition.y > leftBlockPosition.y - 50 / pixelScale) {

			Debug.Log ("crash");
			if (isLeftBlockCrash == false) {
				if (speedX < 0) {
					ballSpeedAngle = (leftBlockPosition.y - ballPosition.y) / 50.0f * pixelScale + Mathf.PI / 2.0f;

				}
				isLeftBlockCrash = true;
			}
		
		} else {
			isLeftBlockCrash = false;
		}

		//右边挡板碰撞
		bool isRightBlockCrash = false;
		//挡板的宽高分别是 20、100像素,所以计算碰撞区域时,按照宽高一半进行计算
		if (ballPosition.x < rightBlockPosition.x + 10 / pixelScale && ballPosition.x > rightBlockPosition.x - 10 / pixelScale
			&& ballPosition.y < rightBlockPosition.y + 50 / pixelScale && ballPosition.y > rightBlockPosition.y - 50 / pixelScale) {

			Debug.Log ("crash");
			if (isRightBlockCrash == false) {
				if (speedX > 0) {
					ballSpeedAngle =  Mathf.PI * 3 / 2 - (rightBlockPosition.y - ballPosition.y) / 50.0f * pixelScale;

				}
				isRightBlockCrash = true;
			}

		} else {
			isRightBlockCrash = false;
		}



	}
}

 

上一篇:Unity 热更新实例一、C#Light 和UI系统使用实例


下一篇:HTML5 2D Graphic 实现五朵金花版型设计