各位可以到Youtube支持他,他的视频底下有他个人的网站,各位可以从他拿素材。
像我这样的菜鸡,在我看codeMonkey零零散散的制作视频而不知所措时,Brackeys出现了,他耐心教导,他真的是太温柔了,我哭死。
另外该游戏,他是用JS写的游戏脚本,而我改用C#,接下来我会完整地展现如何制作这款简单的游戏,以便各位像我一样的初学者熟悉unity的操作,不过我不会像他的视频一样冗长。
就两个玩家互相对撞,碰球,计分产生音效等等。
链接:https://pan.baidu.com/s/1BFLubNjFuGdtBEV66pYUSw
提取码:gbjr
BallControl.cs
让球在等待几秒后,随机以任意方向抛出,控制随着到player的不同,碰撞后反弹的影响。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BallControl : MonoBehaviour
{
public float ballSpeed = 100f;
private float xVel;
void Start()
{
StartCoroutine(WaitAndGoBall(2f));
}
void Update()
{
xVel = GetComponent<Rigidbody2D>().velocity.x;
//Debug.Log("Velocity:" + xVel);
if(xVel <18f && xVel > -18f && xVel!=0)
{
if(xVel > 0)
{
GetComponent<Rigidbody2D>().velocity = new Vector2(20f, GetComponent<Rigidbody2D>().velocity.y);
}
else
{
GetComponent<Rigidbody2D>().velocity = new Vector2(-20f, GetComponent<Rigidbody2D>().velocity.y);
}
//Debug.Log("Velocity Before " + xVel);
//Debug.Log("Velocity after " + GetComponent().velocity.x);
}
}
void OnCollisionEnter2D(Collision2D colInfo)
{
//CompareTag 不能 == ,因为tag属性不能被检查
if (colInfo.collider.CompareTag("Player"))
{
GetComponent<Rigidbody2D>().velocity = new Vector2(
GetComponent<Rigidbody2D>().velocity.x,
GetComponent<Rigidbody2D>().velocity.y / 2 + colInfo.collider.GetComponent<Rigidbody2D>().velocity.y / 3
);
GetComponent<AudioSource>().pitch = Random.Range(0.8f, 1.2f);
GetComponent<AudioSource>().Play();
}
}
void GoBall()
{
float randomNumber = Random.Range(0f, 1f);
if (randomNumber <= 0.5f)
{
GetComponent<Rigidbody2D>().AddForce(new Vector2(ballSpeed, 10f));
}
else
{
GetComponent<Rigidbody2D>().AddForce(new Vector2(-1* ballSpeed, -10f));
}
}
void ResetBall()
{
GetComponent<Rigidbody2D>().velocity = Vector2.zero;
transform.position = Vector2.zero;
StartCoroutine(WaitAndGoBall(0.5f));
}
IEnumerator WaitAndGoBall(float waitTime)
{
yield return new WaitForSeconds(waitTime);
GoBall();
}
}
GameManager.cs
设置GUI,计分
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameManager : MonoBehaviour
{
public static int playerScore01 = 0;
public static int playerScore02 = 0;
public GUISkin theSkin;
private Transform theBall;
void Start()
{
theBall = GameObject.FindGameObjectWithTag("Ball").transform;
}
public static void Score(string wallName)
{
if (wallName == "rightWall")
{
playerScore01 += 1;
}
else
{
playerScore02 += 1;
}
//Debug.Log("Player Score 1 is " + playerScore01);
//Debug.Log("Player Score 2 is " + playerScore02);
}
void OnGUI()
{
GUI.skin = theSkin;
GUI.Label(new Rect(Screen.width / 2 - 150-18, 25, 100, 100), "" + playerScore01);
GUI.Label(new Rect(Screen.width / 2 + 150-18, 25, 100, 100), "" + playerScore02);
if(GUI.Button(new Rect(Screen.width / 2 -121/2, 35, 121, 53), "RESET"))
{
playerScore01 = 0;
playerScore02 = 0;
theBall.gameObject.SendMessage("ResetBall");
}
}
}
GameSetup.cs
固定player位置和设定边界
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameSetup : MonoBehaviour
{
//Reference the camera
public Camera mainCam;
//Reference the colliders we are going to adjust
public BoxCollider2D topWall;
public BoxCollider2D bottomWall;
public BoxCollider2D leftWall;
public BoxCollider2D rightWall;
//Reference the players
public Transform Player01;
public Transform Player02;
//check
public float po = 180f;
void Start ()
{
//Only set this to Update if you know the screen size can change during a playsession.
//Move each wall to its edge location:
topWall.size = new Vector2 (mainCam.ScreenToWorldPoint (new Vector3 (Screen.width * 2f, 0f, 0f)).x, 1f);
topWall.offset = new Vector2 (0f, mainCam.ScreenToWorldPoint (new Vector3 (0f, Screen.height, 0f)).y + 0.5f);
bottomWall.size = new Vector2 (mainCam.ScreenToWorldPoint (new Vector3 (Screen.width * 2, 0f, 0f)).x, 1f);
bottomWall.offset = new Vector2 (0f, mainCam.ScreenToWorldPoint (new Vector3(0f, 0f, 0f)).y - 0.5f);
leftWall.size = new Vector2(1f, mainCam.ScreenToWorldPoint(new Vector3(0f, Screen.height*2f, 0f)).y);
leftWall.offset = new Vector2(mainCam.ScreenToWorldPoint(new Vector3(0f, 0f, 0f)).x - 0.5f, 0f);
rightWall.size = new Vector2(1f, mainCam.ScreenToWorldPoint(new Vector3(0f, Screen.height*2f, 0f)).y);
rightWall.offset = new Vector2(mainCam.ScreenToWorldPoint(new Vector3(Screen.width, 0f, 0f)).x + 0.5f, 0f);
//Move the players to a fixed distance from the edges of the screen:
Player01.position = new Vector3(mainCam.ScreenToWorldPoint (new Vector3 (po, 0f, 0f)).x, Player01.position.y, Player01.position.z);
Player02.position = new Vector3(mainCam.ScreenToWorldPoint (new Vector3 (Screen.width -po, 0f, 0f)).x, Player02.position.y, Player02.position.z);
}
}
PlayerController.cs
控制移动方向与速度
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
public KeyCode moveUp;
public KeyCode moveDown;
public float speed = 10f;
private Rigidbody2D rb2D;
// Start is called before the first frame update
void Start()
{
rb2D = GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void Update()
{
if (Input.GetKey(moveUp))
{
rb2D.velocity = new Vector2(0, speed);
}else if (Input.GetKey(moveDown))
{
rb2D.velocity = new Vector2(0, speed*-1);
}
else
{
rb2D.velocity = Vector2.zero;
}
}
}
SideWall.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SideWall : MonoBehaviour
{
void OnTriggerEnter2D(Collider2D hitInfo)
{
if (hitInfo.name == "Ball")
{
string wallName = transform.name;
GameManager.Score(wallName);
GetComponent<AudioSource>().Play();
//发送消息
hitInfo.gameObject.SendMessage("ResetBall");
}
}
}
Scenes:unity自带
Script:C#脚本存放位置
Textures:贴图,存放游戏两块白小板和背景图(Brackeys的素材)
Thaleah-PixelFont:unity素材商城导入的字体文件(免费)
命名GameObject
调整 GameObject
的BG、Ball、Main Camera
的位置如下,以便让摄像头可以居中显示。
点击任意一个对象,到该Sprite
组件(没有的话,就Add Component该组件)
在该组件下的操作界面点击Add Sorting Layer。
后面让背景的sortings layer
成Background
就行了,而玩家要操作的player1
和player2
的图层则为GO
。
另外让Inspector
检查背景对象的Layer
,当然由于弄的并不是太过于复杂,其他的GameObject
并不需要这样干,默认即可。
player01
和player02
Size这样设置,才方便设定球Ball
能够撞击到player
的范围多大为有效。
将PlayerController.cs
拉进去,分别设置如下
mass设置的足够大,这样可以让ball
碰到player
时,不至于让player
发生旋转或者位移的情况(相当于固定在X轴了)。
Ball
碰撞还要能反弹到一定的距离
在Projects
栏中的Assets/Textures
,右键
命名如下,设置的参数可以自己调。
起碰撞的区域是有多大也自己调
_GM
(判断游戏输赢或者重开?)ScrollSkin
在Project
栏的Assets/Textures
文件目录中,右键
命名为ScrollSkin
,接着如下图设置,定义字体、字体大小、按钮点击效果等。
字体font
则是在商场中,导入的文件获取的,自己登录搜索查找即可。
同样地创建四个GameObject
,分别代表上下左右边界,拉入到_GM
对象
Add Component
组件,表示成能够被碰撞的物体。
将C#脚本SideWall
拉入到leftWall
和rightWall
,同时创建Audio Source
组件,音源是Audio
文件夹下的Bonus
,用来判断谁胜谁败了,以便之后让游戏管理的脚步计分。
将GameSetup.cs
和GameManager.cs
拉入到_GM
的Inspector
栏,设置如下。
这样在游戏运行时,就能看到顶部的RESET
按钮的点击效果和点击Gizmos
时显示边框效果
如果是switch选项的话,就照点,加载后再点击Build选择。
尽管我看了不少Youtube的视频创作者都推荐跟它的版本一样,但是谁管呢?
我用的版本是
当然不听老人言,吃亏在眼前,我也遇到了麻烦:
重启只是让球回到了原来的位置,但是没有改变player