unity双人对战游戏完整版是利用了什么技术

unity3d一个简单的对打游戏
我发现没有动画想做什么都不行噢~~~,这个动画还是一个大侠给我的,网上找了很多bip动作文件,但是转成FBX格式不行,好像是版本不一样的缘故。后来为了做进度条我之前学了一下EZGUI,但是没有得到想要的效果,高手说是因为没有SM2的缘故,后来我又学习iGUI,的确简单又多用,不错哦~~~至于NGUI我还没用过,以后看看再说~~~呵呵呵,如果要说他们的区别的话,EZGUI是3D的,但是控件较少;iGUI简单易用,控件多,是2D的和unity本身的GUI相似,NGUI没用过还不知道噢~~~~。还有就是我一运行unity就卡死,害我做了半天的东西都没保存噢,大家一定要多保存哈~~~找了半天原因,后来发现原来是我在update函数里面写了一个while循环,把while改成if就好了(千万别在update里面用while,一不小心就卡死咯,要用的话在start里面可以的)。
下面看看今天的demo吧,如果不懂动画的兄弟,可以先去前面看看我写的一个动画的博文,应该是看得懂的啦。我把这个demo的工程放到资源里面去了,里面有动画的,大家可以去下来看看哈~~~~~
注意:这里面没有用碰撞检测,因为如果要发生碰撞的话,刀可能会飞的,而且也砍不下去啊,所以只能用触发器了。
下面简单来说说触发器的用法吧,和碰撞一样,必须至少有一个物体有rigidbody,而且两个物体必须都有含有触发器的的collider,我们这用boxcollider(meshcollider不能触发),而且在collider中的Is Trigger要勾上哦~~~~
我们的游戏对象控制代码player.js:
//游戏角色的移动控制
var playerprogressbar:iGUI.iGUIProgressB
var play1:boolean=
var isdie:boolean=
function Update(){
if(!isdie){
if(Input.GetKey(KeyCode.UpArrow)){
animation.Play("walk");
transform.Translate(Vector3.forward*1*Time.deltaTime);
if(Input.GetKey(KeyCode.DownArrow)){
transform.Rotate(Vector3.up*180);
if(Input.GetKey(KeyCode.RightArrow)){
transform.Rotate(Vector3.up*10);
if(Input.GetKey(KeyCode.LeftArrow)){
transform.Rotate(Vector3.up*-10);
if(Input.GetKey(KeyCode.Space)){
animation.Play("attack");
if (!animation.isPlaying){
animation.Play("Take 001");
//游戏对象的血条控制
function OnTriggerEnter(obj:Collider){
if(obj.gameObject.name!="playerarrow"){
if(playerprogressbar.value!=0){
playerprogressbar.value-=10;
print(obj.gameObject.name);
animation.Play("die");
敌人的游戏对象控制代码 enemy.js:
var player:T
var flag:boolean=
var enemyprogressbar:iGUI.iGUIProgressB
function Update () {
animation.Play("walk");
transform.LookAt(player);
transform.Translate(Vector3.forward*0.5*Time.deltaTime);
if(Vector3.Distance(player.position,transform.position)&3){
animation.Play("attack");
function OnTriggerEnter(obj:Collider){
if(obj.gameObject.name!="enemyarrow"){
if(enemyprogressbar.value!=0){
enemyprogressbar.value-=10;
print(obj.gameObject.name);
animation.Play("die");
没有更多推荐了,Unity各类知识
Unity3D利用Photon实现实时联网对战(三)创建和加入房间
今天和大家交流一下利用Photon创建和加入房间。&
Photon创建局域网的原理是通过一台机器创建房间,这台机器就是担负服务器的功能,负责与各个客户端之间的通信,而其也是一台客户端。&
之后其他机器加入房间,就是客户端。
直接上代码:
[code]phpcode:
size=&4&&using
public&class&RoomController
: MonoBehaviour
&&&&private&static&byte
Version =0;
&&&&&&&&PhotonNetwork.automaticallySyncScene
&&&&&&&&if&(PhotonNetwork.connectionStateDetailed
== ClientState.PeerCreated)
&&&&&&&&&&&&
&&&&&&&&&&&&PhotonNetwork.ConnectUsingSettings(Version
+&&.&&+
SceneManagerHelper.ActiveSceneBuildIndex);
&&&&&&&&StartCoroutine(CreateOrJoinRoom());
&&&&IEnumerator
CreateOrJoinRoom()
&&&&&&&&yield&return&new&WaitForSeconds(0.5f);
&&&&&&&&Debug.Log(&CreateOrJoinRoom&);
&&&&&&&&if&(!PhotonNetwork.inRoom)
&&&&&&&&&&&&PhotonNetwork.JoinOrCreateRoom(&RoomOne&,&new&RoomOptions
{ MaxPlayers = 10 },TypedLobby.Default);
&&&&public&void
OnJoinedRoom()
&&&&&&&&Debug.Log(&join
the room&);
&&&&public&&void
OnFailedToConnectToPhoton(DisconnectCause cause)
&&&&&&&&Debug.LogError(&Cause:
&&&&public&void
OnApplicationQuit()
&&&&&&&&PhotonNetwork.LeaveRoom();
在这里介绍几个常用的方法:
1、CreateRoom&
其功能就是创建房间,执行该代码的机器即担负服务器也担负客户端的功能。&
CreateRoom(“RoomOne”, new RoomOptions { MaxPlayers = 10 }, null);其参数中第一个参数是房间名称;第二个参数是创建房间的选择,这里MaxPlayers 设置的为该房间的最大连接数;第三个参数为大厅类型,在这里不做设置。这样就可以创建一个房间啦。
但是在创建房间之前最好判断一下该程序是否已经在房间内,这里就说到Photon的一个缺点啦,如果在退出程序时不设置离开房间,等到再次创建房间时可能保留了上次创建的房间,这样房间名字是重复的,就会发生错误。这是为了避免这个因素,所以在创建房间之前做判断。&
所以上面的代码也在OnApplicationQuit方法中调用离开房间的方法,即退出该程序时,也退出该房间。
2、JoinOrCreateRoom&
其功能就是加入或者创建房间,如果之前已经创建了一个房间(创建的房间和加入的房间必须房间名称一致),就直接加入该房间即可;如果之前没有创建该房间,则直接创建房间。其参数和CreateRoom方法的相同。
3、JoinRoom&
其功能是加入房间,如果之前已经创建了一个房间(创建的房间和加入的房间必须房间名称一致),就直接加入房间即可;如果之前没有创建该房间,则会报错。&
JoinRoom(“RoomOne”),其参数为房间名。
4、JoinRandomRoom&
其功能是加入一个随机的房间,如果之前已经创建了一个或多个房间,其随机加入一个房间;如果之前没有创建该房间,则会报错。&
该方法没有参数。
这就是一些常用的创建和加入房间的方法。
下面介绍几个常用的回调方法:
1、OnCreatedRoom&
在创建房间之后自动调用该方法,在该方法中一般做人物角色的生成和初始化以及其他一些初始化等。
2、OnJoinedRoom&
在加入房间之后自动调用该方法,在该方法中一般做人物角色的生成和初始化以及其他一些初始化等。
3、OnFailedToConnectToPhoton&
如果连接Photon失败,则会调用该方法。
上面的方法都是在Photon中用到的频率比较高的,那下一篇就介绍如何生成角色。
没有更多推荐了,Unity3D基础案例-双人乒乓
引言:人生无处不代码,无代码处不人生。今天给大家分享双人打乒乓游戏的主要开发流程。开发版本:unity 5.3.5f适合人群:初学Unity者源文件链接请见文末!开启学习之旅吧!游戏效果预览:玩法:两人使用W/S键,上下键来分别控制左右的挡板,当一方没有接到球时,另一方加一分01 场景搭建创建2D工程PingPong,并创建新场景MainScene,导入素材,完成初始场景搭建注意工程路径最好不要有中文注意Order in Layer可以控制sprite渲染先后顺序,数值越大,后渲染,显示在其他sprite的上面例如:上图中间线数值为0,显示在背景数值为-1的上面02 开发围墙新建四个空对象,分别添加BoxCollider2D组件,并设置父对象WallGroup使用代码控制Collider的大小和位置,新建脚本GameManager.cs将GameManager设置为单例模式在我们的整个游戏生命周期当中,有很多对象从始至终有且只有一个。这个唯一的实例只需要生成一次,并且直到游戏结束才需要销毁。 单例模式一般应用于管理器类,或者是一些需要持久化存在的对象。
private static GameManager _
public static GameManager Instance
private void Awake()
_instance =
}a点为世界坐标中心点,A点为屏幕坐标中心点新建方法ResetWallPos(),在Start()里调用一次即可
void ResetWallPos()
//分别获取各个墙的collider组件
_upWallBoxCollider2D = _upWall.GetComponent&BoxCollider2D&();
_downWallBoxCollider2D = _downWall.GetComponent&BoxCollider2D&();
_rightWallBoxCollider2D = _rightWall.GetComponent&BoxCollider2D&();
_leftWallBoxCollider2D = _leftWall.GetComponent&BoxCollider2D&();
//new Vector2(Screen.width, Screen.height) 该点是屏幕的右上角
//Camera.main.ScreenToWorldPoint将屏幕坐标点转化为世界坐标点
//_screenToWorldPointPos就是图中的(x,y)
Vector3 _screenToWorldPointPos = Camera.main.ScreenToWorldPoint(new Vector2(Screen.width, Screen.height));
//_screenToWorldPointPos.y + 0.5f的偏差是为了让上面的墙向上偏移0.5m,以下同理
_upWall.transform.position = new Vector3(0, _screenToWorldPointPos.y + 0.5f, 0);
//设置Collider的Size属性,长度为_screenToWorldPointPos.x * 2
_upWallBoxCollider2D.size = new Vector2(_screenToWorldPointPos.x * 2, 1);
_downWall.transform.position = new Vector3(0, -_screenToWorldPointPos.y - 0.5f, 0);
_downWallBoxCollider2D.size = new Vector2(_screenToWorldPointPos.x * 2, 1);
_rightWall.transform.position = new Vector3(_screenToWorldPointPos.x + 0.5f, 0, 0);
_rightWallBoxCollider2D.size = new Vector2(1, _screenToWorldPointPos.y * 2);
_leftWall.transform.position = new Vector3(-_screenToWorldPointPos.x - 0.5f, 0, 0);
_leftWallBoxCollider2D.size = new Vector2(1, _screenToWorldPointPos.y * 2);
}03 开发Player新建一个2D精灵对象,标签设置为Player,设置为预制体,然后创建两个Player,即Player_Left和Player_Right挂载Rigidbody2D和Box Collider2D组件,设置Gravity Scale为0,冻结Z轴旋转,X轴位移Collision Detection也可以设置为continuous,防止因为速度过快而穿越player的现象添加PlayerController.cs脚本首先利用添加刚体速度控制挡板的上下移动
//Public 用于外部设置控制键
public KeyCode _upK
public KeyCode _downK
public float speed = 10;
private void Update()
//Input.GetKey()当按键不放时,一直返回true
//通过if else if来判断按键情况,并设置player运动状态
if (Input.GetKey(_upKey))
//通过修改Rigidbody2D.velocity刚体速度,来模拟逐渐加速的过程,可以理解为加速度
//该命令会使物体向Y轴上方移动
_rigidbody2D.velocity = new Vector2(0, speed);
else if (Input.GetKey(_downKey))
//该命令会使物体向Y轴下方移动
_rigidbody2D.velocity = new Vector2(0, -speed);
//不按上下键时,刚体速度设为0
_rigidbody2D.velocity = new Vector2(0, 0);
}Player上下移动地按键可以在Inspector面板设置左边的Player设置为W/S键,右边的设置为S上下键代码控制Player的位置,使得挡板分别位于左右两边的中间,距离边缘10像素距离在GameManager.cs中添加ResetPlayer()方法,在Start()方法中调用一次private void ResetPlayer()
rightPlayerPos = Camera.main.ScreenToWorldPoint(new Vector2(Screen.width - 10, Screen.height / 2));
_rightPlayer.position = rightPlayerP
leftPlayerPos = Camera.main.ScreenToWorldPoint(new Vector2(10, Screen.height / 2));
_leftPlayer.position = leftPlayerP
}04 开发Ball制作小球Ball,可以将其位置放在画面中点,并设置其标签为Ball右键Creat一个Physics2D material ,弹性设置为1Ball上挂载脚本Wall.cs首先实现Ball随机左右发球,InitForce()在Start()中只调用一次private void InitForce()
//Random.Range随机取整值,但取不到右边的值2,可以取值0,1
int number = Random.Range(0, 2);
if (number == 1)
//AddForce对刚体添加一个方向的力
//Vector2.right等于new Vector2(1,0)
_rigidbody2D.AddForce(Vector2.right * 100);
_rigidbody2D.AddForce(-Vector2.right * 100);
}当小球碰撞到挡板后,获取上下移动的速度private void OnCollisionEnter2D(Collision2D collision)
if (collision.collider.CompareTag("Player"))
//获取Ball的Rigidbody2D组件的速度
Vector2 velocity = _rigidbody2D.
//给Ball添加一个y轴方向的刚体速度
//为了防止Ball速度,无限增加,减半增加
velocity.y = velocity.y / 2f + collision.rigidbody.velocity.y /2f;
_rigidbody2D.velocity =
}控制小球运动速度,防止其速度过低,影响游戏体验
private void Update()
Vector2 velocity = _rigidbody2D.
if (velocity.x & 10 && velocity.x & -10 && velocity.x != 0)
if (velocity.x & 0)
velocity.x = 10;
velocity.x = -10;
_rigidbody2D.velocity =
}05 设计分数用UGUI创建两个Text用来计分,需要引入命名空间using UnityEngine.UI;在GameManager中添加以下代码public Text leftT
public Text rightT
private int leftS
private int rightS
public void ChangeScore(string name)
if (name == "leftWall")
rightScore++;
else if (name == "rightWall")
leftScore++;
//分数更改后,更新Text
leftText.text = leftScore.ToString();
rightText.text = rightScore.ToString();
}在Ball.cs中调用ChangeScore方法private void OnCollisionEnter2D(Collision2D collision)
if (collision.collider.CompareTag("Player"))
Vector2 velocity = _rigidbody2D.
velocity.y = velocity.y / 2f + collision.rigidbody.velocity.y /2f;
_rigidbody2D.velocity =
//当小球碰撞到左右两边的墙时,进行加分
if (collision.collider.name == "rightWall" || collision.collider.name == "leftWall")
//GameManager.Instance调用Gamemanager的唯一实例
GameManager.Instance.ChangeScore(collision.collider.name);
}06 添加音效在MainCamera上添加组件AudioSource,audioclip设置背景音乐ChillMusic,勾选play on awake,loop选项为四面墙添加AudioSource组件,并为AudioClip添加Click音效,挂载Wall.cs脚本public class Wall : MonoBehaviour
private AudioSource _
private void Start()
_audio = GetComponent&AudioSource&();
private void OnCollisionEnter2D(Collision2D collision)
if (collision.collider.CompareTag("Ball"))
//修改音量
_audio.volume = 0.6f;
//获取随机播放音效的音调
_audio.pitch = Random.Range(0.8f, 1.2f);
_audio.Play();
}同理为PlayerController.cs 添加如下方法 并添加hit音效//OnCollisionEnter2D方法用于碰撞检测,is trigger不能勾选
//当发生碰撞时,将碰撞到的物体Collider信息存储在Collision中
private void OnCollisionEnter2D(Collision2D collision)
if (collision.collider.CompareTag("Ball"))
_audio.pitch = Random.Range(0.8f, 1.2f);
_audio.Play();
}07 发布PC端File-BuildSettings 点击Build完成打包,注意打包出的文件要放在同一个文件夹内做完后,叫上你的小伙伴一起来玩吧!喜欢我的分享就关注我吧!以后会陆续分享案例教程的!素材及工程文件百度云链接:链接:https://pan.baidu.com/s/1eT5iCcM 密码:s5w5
没有更多推荐了,Unity联网对战游戏小Demo
开发3D游戏听起来门槛很高,但是Unity的出现让门槛大大降低。开发联网实时对战的3D游戏门槛就更高,因为即便熟悉掌握了Unity的开发技术,联网的游戏还要涉及到熟悉网络协议栈、掌握后端知识以及面对服务器带来的高额成本。但是Bmob最近在内测一款,让普通开发者开发一款联网实时对战游戏这个梦想变得触手可及。
第一步,准备一个单机的Unity游戏
访问 Unity 的 下载游戏项目,并且Import到 Unity 内。
我选择了一款可爱的射击打怪游戏:
项目导入后是这个样子的:
下面简要介绍项目结构:
场景上的摆设物体都包括在Environment上,比如图上的闹钟、柜子等,它们的Layer都设置为了Shootable字段,代码在玩家开激光枪、激光碰撞检测时检测到Shootable为Layer的物体才会触发碰撞事件。
怪物的生成由EnemyManage来控制,能够管理何种怪物在哪个出生点按什么时间间隔出生。
怪物主要由三个脚本来管理,分别是EnemyHealth.cs(管理怪物的hp,被玩家射击到时扣血,血量小于等于0时死掉)、EnemyMovement.cs(管理怪物的移动,用UnityEngine.AI.NavMeshAgent,把玩家的坐标设为目的地,这样怪物会按设置的行走速度自动走向玩家位置)和EnemyAttack.cs(管理怪物的自动攻击,按一定的时间间隔进行发招)。
玩家也主要由三个脚本来管理,分别是PlayerHealth.cs(管理玩家的hp,主要是收到怪物攻击时掉血)、PlayerMovement.cs(管理玩家的移动,当键盘按wsad时上下左右的移动)和PlayerShooting.cs(管理玩家的射击动作,当鼠标左键点击时对玩家枪口面对的方向发出激光Ray,如果在范围内碰撞检测到了怪物则对怪物进行扣血)。
这里不说太详细,想学习更多细节的童鞋可以去看。
第二步,开始改造
将玩家角色(和角色控制器)克隆一份,去掉主动操作行为,添加被动展现方法。
可以在上一步骤中看到项目中只有一个玩家Player,要改造成联网的游戏就需要多个玩家,所以我把场景中的Player物体克隆一份,命名为Player2,当然控制它的脚本也不能少,克隆克隆克隆!
Player2Health.cs:
因为Player2Health控制的是其他玩家的血量,所以把玩家收到怪物攻击时减的血量设为0,让其他玩家的血量不受本地控制。
Player2Movement.cs:
删掉根据键盘的操作引起的移动,加上传入数据时的操作角色移动方法。
public void MoveTo(float x, float z){
playerRigidbody.MovePosition (new Vector3(x, playerRigidbody.position.y,z));
Animating (x, z);
public void TurnTo(float y){
transform.eulerAngles = new Vector3 (0, y, 0);
Player2Shooting.cs:
删掉根据鼠标的操作引起的射击,加上传入射击指令时的方法,考虑到网络延时原因,是否射中怪物的判断不由这里判断,这个射击方法给怪物的伤害要设置为0,仅显示出UI效果。
以上改好后再把对应的脚本替换掉原脚本放到Player2物体上,将物体拖进Project一栏中,这样物体就变成预设物体,可以随时调用啦。除了克隆、修改玩家之外,还需要修改一些细节:
更改怪物的移动方式:
上面我们有提到怪物是根据玩家的位置来自动寻路的,那现在有两个玩家了怎么办呢?根据玩游戏的经验告诉我们,怪物会跟着离他更近的玩家走哟。下面贴出代码:
// UnityEngine.AI.NavMeshA
// nav = GetComponent &UnityEngine.AI.NavMeshAgent& ();
void Update ()
// If the enemy and the player have health left...
if(enemyHealth.currentHealth & 0)
Vector3 enemyPosition = transform.position,
float minDist = float.MaxValue,
Vector3 target = Vector3.
for (int i = 0; i & targetHealths.L i++) {
if (targetHealths [i].currentHealth & 0) {
tempPosition = trackTargets [i].
tempFloat = Vector3.Distance (enemyPosition, tempPosition);
if (tempFloat & minDist) {
minDist = tempF
target = tempP
if (minDist != float.MaxValue) {
// ... set the destination of the nav mesh agent to the player.
nav.SetDestination (target);
// Otherwise...
// ... disable the nav mesh agent.
nav.enabled =
更改怪物受到伤害减血的触发方式:
上面提到,其他玩家射击到怪物的事件不能在我这里减血,那么怪物的血量怎么控制呢,我把EnemyManager.cs的脚本改了下,把生成的每个怪物都命名,当检测到射击时,把我伤害的怪物的名称发送给其他玩家,就能同步好每个怪物的血量了。
第三步,结合Bmob Game Sdk
访问 ,注册账号并下载 Unity SDK、GameCloud SDK;
将 BmobGame_UnitySDK_vx.x.x_xxxxxx.unitypackage Import 到Unity内;
修改SDK,将游戏开始跳转的 Scene 改为本游戏的场景”_Complete-Game/_Complete-Game”;
SceneManager.LoadSceneAsync ("_Complete-Game/_Complete-Game")
在 Demo Scene 进行SDK的初始化,绑定 delegate 用于处理各种通知;
将处理事件转发的脚本绑定给本地角色Player,将Player的移动、旋转、hp等数据,调用SDK接口同步到服务器;
void Update ()
BmobGame.UpdateFrame ()
if (isOver)
Vector3 position = transform.position
BmobGame.EditMyStatus ("position", new float[]{ position.x, position.z })
BmobGame.EditMyStatus ("rotation", transform.eulerAngles.y)
BmobGame.EditMyStatus ("hp", GetComponent&PlayerHealthBase&().currentHealth&0?0:GetComponent&PlayerHealthBase&().currentHealth)
将 Player 的瞬时动作射击、射中的怪物名通过transfer接口直接发送到其他玩家;
// Game_BmobSDKTest里面SendFireEvent和SendDamageEvent方法,
// 都是把传来的参数转成byte数组(数组第一位设为事件类别),
// 通过transfer接口传递数组给其他玩家:BmobGame.SendTransferToAllExceptSelf (notify)
// Game_BmobSDKTest mBGS
// mBGS = GetComponentInParent&Game_BmobSDKTest& ()
// 把发射起点、角度、长度,用transfer接口传
mBGS.SendFireEvent (transform.position.x, transform.position.z, transform.eulerAngles.y, range)
// 把射中的怪物名发送出去,用transfer接口传
mBGS.SendDamageEvent (shootHit.collider.name)
读取服务器同步的数据,渲染其它玩家的位置、角度。获取其它玩家直接发送的瞬时动作,作出射击和射中某个怪物的处理;
void OnOthersGameStatus (int no, ArrayList attrNames, Hashtable status)
Debug.Log ("Player[" + no + "] game status is changed: " + status.Count);
if(attrNames.Contains("position")){
float[] position = status ["position"] as float[];
mOtherPlayers [no].GetComponent&Player2Movement& ().MoveTo (position [0], position [1]) ;
if(attrNames.Contains("rotation")){
float y = (float)(status ["rotation"]);
mOtherPlayers [no].GetComponent&Player2Movement& ().TurnTo (y) ;
if(attrNames.Contains("hp")){
int hp = (int)(status ["hp"]);
mOtherPlayers [no].GetComponent&Player2Health& ().currentHealth =
void OnTransfer (int fromNo, byte[] data)
Debug.Log ("Get transfer data flag = " + data[0] + " & len = " + data.Length + " & from: " + fromNo);
switch(data[0]){
ReceiveFireEvent (fromNo, data);
ReceiveDamageEvent (fromNo, data);
Debug.Log ("Player[" + fromNo + "] transfer: " + data [0] + ", len = " + data.Length);
void OnCloudNotifyJson(string jsonStr){
Debug.Log ("Handle cloud notify: " + jsonStr);
JSONNode json = JSON.Parse (jsonStr);
if (json == null) {
string a = json ["action"];
if (a == null || a.Length == 0) {
if ("gameover".Equals (a)) {
Invoke ("BackToRoom", 3);
在 BGS官网 登录管理后台,创建游戏,修改服务器运行配置,包括:每秒帧率(默认60Hz)、房间最多玩家数 (2个或以上);
修改 玩家属性配置,设置各个属性的名称、类型、长度、值域、由云端/客户端编辑、其它玩家是否可见等。我这里仅有hp、position和rotation。
"player": {
"attributes": {
"type": "int",
"max": 101
"position": {
"type": "float[]",
"count": 2,
"editable": true,
"export": true
"rotation": {
"type": "float",
"editable": true,
"export": true
10 . 打开 Eclipse 或 Android Studio,创建Java项目,导入 BmobGame_JavaCloud_vx.x.x_xxxxxx.jar,并创建 Player.java 和 Room.java,分别继承自 PlayerBase.class 和 RoomBase.class 后,编写游戏逻辑代码。
Player.java :
package cn.bmob.gamesdk.server.
import cn.bmob.gamesdk.server.api.BmobGameSDKH
import cn.bmob.gamesdk.server.api.JSON;
import cn.bmob.gamesdk.server.api.PlayerB
public class Player extends PlayerBase {
@BmobGameSDKHook
public native int getHp();
@BmobGameSDKHook
public strictfp void onUpdate_Hp() {
for (Player p : roommates)
if (p.getHp() != 0)
gameOver();
private final void gameOver() {
sendToAll(JSON.toJson("action", "gameover").toString().getBytes());
room.dispatchGameOver();
Room.java :
package cn.bmob.gamesdk.server.
import cn.bmob.gamesdk.server.api.RoomB
public class Room extends RoomBase{
11 . 打包运行游戏,就可以多人同时在线对战啦~
怎么样,会了吗?
不服来战,不懂来问!
内测中,感兴趣加官方群:
其他教程:
没有更多推荐了,Unity3D基础案例-双人坦克
引言:小生今日分享的是双人坦克大战,这也是Unity的官方案例。开发版本:unity 5.3.5f适合人群:初学Unity者源文件链接请见文末!开启学习之旅吧!玩法:双方分别用WSAD键或上下左右键来控制两个坦克移动,用空格键或回车键来控制发射炮弹,当一方血条为0,则重新开始01 场景搭建新建3D工程TankWar,新建MainScene场景,导入Assets资源,将Prefabs文件夹中LevelArt预制体拖入场景中。场景预制体中已经包含方向光,可以将场景原有的方向光删除。如果出现如下场景,由于渲染原因Window-lighting窗口 build一下场景 等右下的进度结束就可了,时间稍微有点长~02 开发坦克将Models中Tank模型拖入场景,并设为预制体,标签设置为Play注意,对场景中的Tank进行一些操作后,需要Apply一下,才可以将这些操作映射到其他预制体上。给Tank添加BoxCollider,并对Collider大小进行调节,可以切换到正交视图进行调节刚体需要冻结Y轴移动,X轴和Z轴的旋转为Tank添加拖尾效果,将Prefabs文件夹中的DustTrail粒子特效,放在Tank左右后轮将拖尾粒子特效分别作为左右后轮的子物体,方便随Tank一起移动在Tank身上挂载TankController.cs脚本添加Move方法,在FixedUpdate()内调用,FixedUpdate是固定帧时间调用 void Move()
//Input.GetAxis("Vertical")在键盘按下W/S键或上下键时候,会返回范围在-1到1的值
float v = Input.GetAxis("Vertical");
//修改刚体速度,transform.forward控制物体在Z轴移动
_rigidbody.velocity = transform.forward * v *
//Input.GetAxis("Horizontal")在键盘按下A/D键或左右键时候,会返回范围在-1到1的值
float h = Input.GetAxis("Horizontal");
//angularVelocity是刚体角速度向量,可以控制物体旋转,transform.up是物体旋转的轴
_rigidbody.angularVelocity = transform.up * h * rotateS
}03 开发子弹控制Tank子弹发射Models文件夹中的Shell拖入场景,添加Rigidbody和CapsuleCollider,并设为预制体为坦克添加一个发射子弹的位置ShootPos,设为Tank的子物体,要注意这个位置不要在坦克自身的碰撞体内在PlayerController.cs中添加发射子弹的方法Attack(),在FixedUpdate()方法内调用
void Attack()
//发射键_keyCode可以在Inspector面板设置
if (Input.GetKeyDown(_keyCode))
//在发射位置ShootPos实例化子弹
GameObject go = GameObject.Instantiate(shellPrefab, shootPos.position, shootPos.rotation) as GameO
//方法一:可以通过修改刚体速度
//go.GetComponent&Rigidbody&().velocity = go.transform.forward * shellS
//方法二:可以给物体添加一个方向的力
go.GetComponent&Rigidbody&().AddForce(go.transform.forward * shellSpeed);
}可以玩家一设置发射键为空格键,玩家二设置发射键为回车键在子弹身上挂载脚本ShellController.cspublic class ShellController : MonoBehaviour
//prefabs文件夹中的爆炸预设
public GameObject explosionP
private void OnTriggerEnter(Collider other)
//实例化爆炸效果,并赋值给go
GameObject go = GameObject.Instantiate(explosionPrefabs, transform.position, transform.rotation) as GameO
//在爆炸效果实例化1.5s后销毁,因为这个爆炸效果的时长就是1.5s
Destroy(go, 1.5f);
//立即销毁该子弹
Destroy(this.gameObject);
//如果子弹碰到的是坦克,则调用对象身上的TakeDamage()方法
if (other.CompareTag("Player"))
//SendMessage()消息推送,可以调用该对象身上的私有或公有方法
other.SendMessage("TakeDamage");
}TakeDamage()方法请看下文。04 优化坦克控制由于游戏中需要有两个坦克,目前的代码会让两个Tank控制方式一致我们希望一台Tank由WSAD键控制,另一台由上下左右来控制在InputManager里添加两个新的虚拟键Edit-Project Setting-Input将原有的Horizontal右键复制两个新的,并修改名称和监听按键Vertical同样的操作我们根据不同的虚拟键名来分别控制两个Tank新建一个枚举类型,用来区别操作方式public enum Player
//public可以外部设置,默认为玩家一
public Player player = Player.Player01;
private int PlayerNum = 1;
private Rigidbody _
private void Start()
_rigidbody = gameObject.GetComponent&Rigidbody&();
switch (player)
case Player.Player01:
PlayerNum = 1;
_keyCode = KeyCode.S
case Player.Player02:
PlayerNum = 2;
_keyCode = KeyCode.R
private void FixedUpdate()
//Attack();
void Move()
float v = Input.GetAxis("VerticalPlayer0" + PlayerNum);
float h = Input.GetAxis("HorizontalPlayer0" + PlayerNum);
_rigidbody.velocity = transform.forward * v *
_rigidbody.angularVelocity = transform.up * h * rotateS
}在Inspector面板,玩家一可以设置为Player01,玩家二可以设置为Player02修改两个坦克的颜色,可以将Materials文件夹中的不同颜色材质直接拖到场景中坦克对象上即可05 摄像机跟随public class CamFellowPlayer : MonoBehaviour
public Transform player1;
public Transform player2;
public float maxSize = 20f;
public float minSize = 6.5f;
private Vector3
private void Start()
//计算摄像机距离两个坦克中心点的偏差值
offset = transform.position - (player1.position + player2.position) / 2f;
//计算初始的两个坦克的距离
distance = Vector3.Distance(player1.position, player2.position);
//计算初始正交大小和初始Tank距离的比例
ratio = minSize /
private void Update()
//防止因为坦克销毁后报错
if (player1!=null&&player2!=null)
transform.position = (player1.position + player2.position) / 2f +
distance = Vector3.Distance(player1.position, player2.position);
//计算当前的坦克距离和比例的乘积,则得到当前的正交大小
float size = distance *
//Mathf.Clamp可以限制Size的值在minSize和maxSize之间
size = Mathf.Clamp(size, minSize, maxSize);
//将得到的size赋值给主摄像机的正交大小
//Camera.main返回的是主摄像机
Camera.main.orthographicSize =
06 计算伤害并设计血条为tank添加脚本TankHealth.cs我们使用UGUI的滑动条来设计血条因为涉及到UGUI一些知识,我先将血条做成了预制体注意别忘记在Inspector面板,把血条hpSlider赋值public class TankHealth : MonoBehaviour
//设计血量为100,可以在Inspector面板调整
public int hp = 100;
//prefabs文件夹中的坦克爆炸效果预设
public GameObject tankE
public Slider hpS
private int hpT
private void Start()
//初始化hpTotal
private void TakeDamage()
//如果当前hp值已经低于0,则返回
if (hp &= 0)
hp -= Random.Range(10, 20);
//根据当前的hp和总血量hpTotal的比值还赋予滑动条的值
hpSlider.value = (float)hp / hpT
//受到伤害之后,血量为零,则实例化爆炸效果,并销毁该坦克
if (hp&=0)
//transform.position + Vector3.up因为坦克的中心点在坦克的底部,可以向上偏移一米,爆炸效果更好
GameObject.Instantiate(tankExplosion, transform.position + Vector3.up, transform.rotation);
//销毁该坦克对象
Destroy(this.gameObject);
//重新加载当前场景
UnityEngine.SceneManagement.SceneManager.LoadScene("MainScene");
}至此,游戏基本开发完成,如果觉得单调可以加一些音乐音效,可以参照我之前的案例,就不在此赘述啦!喜欢我的,就关注我吧,你的关注,就是我的动力!素材及工程百度云链接:链接:https://pan.baidu.com/s/1raupjkS 密码:745i
没有更多推荐了,

我要回帖

更多关于 unity联网对战 的文章

 

随机推荐