導入
さあ、またピンボールをしましょう…(^_^)
しばらく独学で Unity を勉強しました。まずは 2D ゲームを作りましょう。実行時のエフェクトは次のとおりです。
目次
ダウンロード
ダウンロードリンク:
Unity2D ピンボール ゲームの実行可能完全なプロジェクト 0 クレジット
その他のダウンロード:
http://101.201.112.95/2021/Unity_Pong.zip
プロジェクトの構造、シーン Pong ファイルを開いて実行します (2017.3 で開発されました。それ以降のバージョンには互換性があるはずです。まだ試していません)。
以前に H5 および Python バージョンを作成しました。[ポータル]:
PyGame ゲーム制作:ピンボールゲーム Pong (完全な Python コードが添付されています)
HTML5ゲーム制作:ピンボールゲームPONG(完全コード添付)
プロジェクトの制作プロセス
制作過程を簡単にお話しますと、2Dゲームの開発も初めての試みです。
1. インターフェース
インターフェイスには 6 つの表示要素が含まれており、対応する位置にドラッグされます。彼らです:
背景画像:bg
ベゼル画像: 左ブロック、右ブロック
ボールの写真: ボール
スコア表示:leftScore、rightScore(使用するuguiのテキストコンポーネント)
注 1: 2D における画像単位とピクセル座標の比率は 1:100 (ピクセルと単位) です。
上の図では、3.7 のピクセル概念は 370 です。
注2: 絵の前後のオクルージョン関係のレイヤー内での順序を設定する必要があり、値が大きい方が上のレイヤーに表示されます
以下では、これらの値を使用してボールの動きと衝突を計算します (物理エンジンはありません...)
2. メインプログラム 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;
アップデート機能でボールの動きを実現
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) ボールの追跡
以下の図に示すように、ボール オブジェクト上で右クリックして軌跡を追加します。
完全なコード
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;
}
}
}