introduce
Here, let's play pinball again... (^_^)
I have taught myself Unity for a while, let’s make a 2D game first, the running effect is as follows:
Table of contents
2) Realize the movement of the ball
5) Collision between the baffle and the ball
download
download link:
Unity2D pinball game runnable complete project 0 credits
Other downloads:
http://101.201.112.95/2021/Unity_Pong.zip
The structure of the project, open the scene Pong file, and run it (developed in 2017.3, higher versions should be compatible, I haven't tried it yet)
I made H5 and Python versions before, [Portal]:
PyGame game production: pinball game Pong (complete Python code is attached)
HTML5 game production: pinball game PONG (complete code attached)
Project production process
Let’s briefly talk about the production process. Developing a 2D game is also my first attempt.
1. Interface
The interface includes 6 display elements, which are dragged to the corresponding positions. They are:
Background image: bg
Bezel image: leftBlock, rightBlock
Ball picture: ball
Score display: leftScore, rightScore (text component of ugui used)
Note 1: The ratio of image units to pixel coordinates in 2D is 1: 100 (Pixels To Units)
In the picture above, the pixel concept of 3.7 is 370
Note 2: It is necessary to set the order in layer of the front and rear occlusion relationship of the picture, and the larger value is displayed on the top layer
The following will use these values to calculate the movement and collision of the ball (no physics engine...)
2. The main program Game.cs
Organize the production ideas of the program.
1) Display initialization
First, define the same GameObject object as the interface, and initialize it in the Start function (bind the objects in the interface)
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) Realize the movement of the ball
Define the moving speed variable, and the unit pixel ratio variable (will be used many times later)
//单位与像素坐标比例为 1: 100 (Pixels To Units)
private float pixelScale = 100.0f;
//小球移动速度和方向
private float ballSpeed = 10.0f;
private float ballSpeedAngle = 0.25f * Mathf.PI;
Realize the movement of the ball in the Update function
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) Bezel movement
Here we take the movement of the left bezel as an example. In the Update function, add keyboard control events and control the moving speed of the bezel to achieve the effect.
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) The ball hits the wall
The idea is actually to calculate the position of the ball and change the movement angle of the ball.
//小球碰撞到边缘后反弹
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) Collision between the baffle and the ball
//左边挡板碰撞
//挡板的宽高分别是 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) Update score
When the ball hits the left and right edges of the screen, update the score display
//左边得分
leftScoreNum ++;
leftScore.text = leftScoreNum.ToString ();
7) Ball trailing
On the ball object, right-click to add Trail, as shown in the figure below:
full code
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;
}
}
}