说起炸弹超人,相信很多朋友都玩过类似的游戏,其中最为人熟知的莫过于《泡泡堂》。该类型游戏需要玩家在地图中一边跑动一边放置炸弹,同时还要躲避敌方炸弹保护自己。最初的炸弹超人游戏都是2D的,今天这篇文章将教大家在Unity中实现一款3D的炸弹超人游戏。

准备工作

将项目初始资源导入Unity项目,资源目录如下:

其中分别包含要用于游戏的动画、材质、模型、背景音乐、物理材质、预制件、场景、脚本、音效及图片资源。

放置炸弹

打开项目中的Game场景并运行。

可以通过WASD键或方向键来操作所有角色进行移动。下面来让角色可以放置炸弹。角色1(红色)通过按下空格键来放置炸弹,角色2(蓝色)则通过按下回车键进行同样的操作。

打开Player脚本,该脚本负责角色所有的移动及动画逻辑。找到DropBomb函数,添加代码如下:

 /// <summary>
/// Drops a bomb beneath the player
/// </summary>
private void DropBomb() {
if (bombPrefab) { //Check if bomb prefab is assigned first
// Create new bomb and snap it to a tile
Instantiate(bombPrefab,
new Vector3(Mathf.RoundToInt(myTransform.position.x), bombPrefab.transform.position.y, Mathf.RoundToInt(myTransform.position.z)),
bombPrefab.transform.rotation);
}
}

其中RoundToInt函数用于对炸弹的坐标参数四舍五入,以避免炸弹放置位置偏离出地块中心。

运行场景,效果如下:

创建爆炸效果

在Scripts文件夹下新建C#脚本命名为Bomb:

找到Prefabs文件夹下的Bomb预制件,将Bomb脚本绑定到该游戏对象上。然后打开Bomb脚本,添加代码如下:

 using UnityEngine;
using System.Collections;
using System.Runtime.CompilerServices; public class Bomb : MonoBehaviour {
public AudioClip explosionSound;
public GameObject explosionPrefab;
public LayerMask levelMask; // This LayerMask makes sure the rays cast to check for free spaces only hits the blocks in the level
private bool exploded = false; // Use this for initialization
void Start() {
Invoke("Explode", 3f); //Call Explode in 3 seconds
} void Explode() {
//Explosion sound
AudioSource.PlayClipAtPoint(explosionSound,transform.position); //Create a first explosion at the bomb position
Instantiate(explosionPrefab, transform.position, Quaternion.identity); //For every direction, start a chain of explosions
StartCoroutine(CreateExplosions(Vector3.forward));
StartCoroutine(CreateExplosions(Vector3.right));
StartCoroutine(CreateExplosions(Vector3.back));
StartCoroutine(CreateExplosions(Vector3.left)); GetComponent<MeshRenderer>().enabled = false; //Disable mesh
exploded = true;
transform.FindChild("Collider").gameObject.SetActive(false); //Disable the collider
Destroy(gameObject,.3f); //Destroy the actual bomb in 0.3 seconds, after all coroutines have finished
} public void OnTriggerEnter(Collider other) {
if (!exploded && other.CompareTag("Explosion")) { //If not exploded yet and this bomb is hit by an explosion...
CancelInvoke("Explode"); //Cancel the already called Explode, else the bomb might explode twice
Explode(); //Finally, explode!
}
} private IEnumerator CreateExplosions(Vector3 direction) {
for (int i = ; i < ; i++) { //The 3 here dictates how far the raycasts will check, in this case 3 tiles far
RaycastHit hit; //Holds all information about what the raycast hits Physics.Raycast(transform.position + new Vector3(,.5f,), direction, out hit, i, levelMask); //Raycast in the specified direction at i distance, because of the layer mask it'll only hit blocks, not players or bombs if (!hit.collider) { // Free space, make a new explosion
Instantiate(explosionPrefab, transform.position + (i * direction), explosionPrefab.transform.rotation);
}
else { //Hit a block, stop spawning in this direction
break;
} yield return new WaitForSeconds(.05f); //Wait 50 milliseconds before checking the next location
} }
}

在检视面板中,将Bomb预制件赋值给脚本的Explosion Prefab属性,该属性用于定义需要生成爆炸效果的对象。Bomb脚本使用了协程来实现爆炸的效果,StartCoroutine函数将朝着4个方向调用CreateExplosions函数,该函数用于生成爆炸效果,在For循环内遍历炸弹能够炸到的所有单元,然后为能够被炸弹影响的各个单元生成爆炸特效,炸弹对墙壁是没有伤害的。最后,在进入下一次循环前等待0.05秒。

代码作用类似下图:

红线就是Raycast,它会检测炸弹周围的单元是否为空,如果是,则朝着该方向生成爆炸效果。如果碰撞到墙,则不生成爆炸并停止检测该方向。所以前面需要让炸弹在地块中心生成,负责就会出现不太理想的效果:

Bomb代码中定义的LayerMask用于剔除射线对地块的检测,这里还需要在检视面板中编辑层,并新增用户层命名为“Blocks”,然后将层级视图中Blocks游戏对象的Layer设置为“Blocks”。

更改Blocks对象的层级时会跳出提示框,询问是否更改子节点,选择是即可:

然后选中Bomb对象,在检视面板中将Bomb脚本的Level Mask设为“Blocks”:

连锁反应

如果炸弹炸到了另一个炸弹,那么被炸到的炸弹也会爆炸。Bomb脚本中的OnTriggerEnter
函数是MonoBehaviour预定义的函数,会在触发器与Rigidbody碰撞之前调用。这里OnTriggerEnter会检测被碰撞的炸弹是否是被炸弹特效所碰撞,如果是,则该炸弹也要爆炸。

现在运行场景,效果如下:

判定游戏结果

打开Player脚本,添加下面的代码:

 //Manager
public GlobalStateManager GlobalManager; //Player parameters
[Range(, )] //Enables a nifty slider in the editor
public int playerNumber = ; //Indicates what player this is: P1 or P2
public float moveSpeed = 5f;
public bool canDropBombs = true; //Can the player drop bombs?
public bool canMove = true; //Can the player move?
public bool dead = false; //Is this player dead?

其中GlobalManager是GlobalStateManager脚本的引用,该脚本用于通知玩家获胜或死亡的消息。dead则用于标志玩家是否死亡。

更改OnTriggerEnter函数代码如下:

 public void OnTriggerEnter(Collider other) {
if (!dead && other.CompareTag("Explosion")) { //Not dead & hit by explosion
Debug.Log("P" + playerNumber + " hit by explosion!"); dead = true;
GlobalManager.PlayerDied(playerNumber); //Notify global state manager that this player died
Destroy(gameObject);
}
}

该函数作用为设置dead变量来通知玩家死亡,并告知全局状态管理器玩家的死亡信息,然后销毁玩家对象。

在检视面板中选中两个玩家对象,将Global State Manager游戏对象赋值给Player脚本的Global Manger字段。

再次运行场景,效果如下:

打开GlobalStateManager脚本,添加以下代码:

 public List<GameObject> Players = new List<GameObject>();

  private int deadPlayers = ;
private int deadPlayerNumber = -; public void PlayerDied(int playerNumber) {
deadPlayers++; if (deadPlayers == ) {
deadPlayerNumber = playerNumber;
Invoke("CheckPlayersDeath", .3f);
}
}

以上代码用于判断哪位玩家获得胜利,如果两位玩家均死亡,则打成平局。

运行场景,效果如下:

总结

到此本篇教程就结束了,大家还可以在此基础上对该项目进行扩展,例如添加“推箱子”功能,将位于自己脚边的炸弹推给敌方,或是限制能够放置的炸弹数量,添加快速重新开始游戏的界面,设置可以被炸弹炸毁的障碍物,设置一些道具用于获得炸弹或者增加生命值,还可以增加多人对战模式与朋友一起变身炸弹超人等等。大家都来发挥自己的创意吧!

文章来自:http://forum.china.unity3d.com/thread-24404-1-1.html

原文链接:https://www.raywenderlich.com/125559/make-game-like-bomberman
原作者:Eric Van de Kerckhove

制作一款3D炸弹超人游戏的更多相关文章

  1. 如何制作一款HTML5 RPG游戏引擎——第五篇,人物&人物特效

    上一次,我们实现了对话类,今天就来做一个游戏中必不可少的——人物类. 当然,你完全是可以自己写一个人物类,但是为了方便起见,还是决定把人物类封装到这个引擎里. 为了使这个类更有意义,我还给人物类加了几 ...

  2. 如何制作一款HTML5 RPG游戏引擎——第四篇,情景对话

    今天我们来实现情景对话.这是一个重要的功能,没有它,游戏将变得索然无味.所以我们不得不来完成它. 但是要知道,使用对话可不是一件简单的事,因为它内部的东西很多,比如说人物头像,人物名称,对话内容... ...

  3. 如何制作一款HTML5 RPG游戏引擎——第三篇,利用幕布切换场景

    开言: 在RPG游戏中,如果有地图切换的地方,通常就会使用幕布效果.所谓的幕布其实就是将两个矩形合拢,直到把屏幕遮住,然后再展开直到两个矩形全部移出屏幕. 为了大家做游戏方便,于是我给这个引擎加了这么 ...

  4. 如何制作一款HTML5 RPG游戏引擎——第二篇,烟雨+飞雪效果

    今天我们来实现烟雨+飞雪效果.首先来说,一款经典的RPG游戏难免需要加入天气的变化.那么为了使我们的RPG游戏引擎更完美,我们就只好慢慢地实现它. 本文为该系列文章的第二篇,如果想了解以前的文章可以看 ...

  5. 用Html5结合Qt制作一款本地化EXE游戏-太空大战(Space War)

    本次来说一说如何利用lufylegend.js引擎制作一款html5游戏后将其通过Qt转换成EXE程序.步骤其实非常简单,接下来就一步步地做一下解释和说明. 首先我们来开发一个有点类似于太空大战的游戏 ...

  6. 如何制作一款HTML5 RPG游戏引擎——第一篇,地图类的实现

    一,话说天下大事 前不久看到lufy的博客上,有一位朋友想要一个RPG游戏引擎,出于兴趣准备动手做一做.由于我研究lufylegend有一段时间了,对它有一定的依赖性,因此就准备将这个引擎基于lufy ...

  7. 3D跑酷游戏《月影忍者之疾风狂逃》

    <月影忍者之疾风狂逃>是一款3D跑酷游戏,也是我实习的时候参与的一个项目,在那个公司我学到了很多东西,谢谢他们.大家可以去玩玩这个游戏啊,还是不错的哦.

  8. 张瀚荣:如何用UE4制作3D动作游戏

    转自:http://www.gamelook.com.cn/2015/06/218267 GameLook报道/ 6月5日,2015年第三期GameLook开放日‧虚幻引擎专场活动在上海正式举行,此次 ...

  9. 基于html5制作3D拳击游戏源码下载

    今天给大家分享一款基于HTML5实现的3d拳王游戏源码.这款实例适用浏览器:360.FireFox.Chrome.Safari.Opera.傲游.搜狗.世界之窗. 不支持IE8及以下浏览器. 在线预览 ...

随机推荐

  1. 428. Pow(x, n)【medium】

    Implement pow(x, n). Notice You don't need to care about the precision of your answer, it's acceptab ...

  2. 从INT 到STRING的几种方法

    1.   int sprintf( char *buffer, const char *format [, argument] ... );      <stdio.h>例如: int s ...

  3. sql排它锁

    1.为什么需要排它锁 事务中,有时我们在操作一条数据时,是不能让其他事务同时去操作的. 如某商品库存数量为1,如果有多个事务对该库存进行减一操作,那么库存可能出现负数. 所以,在某个事务操作时,需要把 ...

  4. iOS-ARC-环境下如何查看引用计数的变化

    iOS-ARC-环境下如何查看引用计数的变化 一,新建立一个工程,用于测试引用计数的变化. 二,找到如下路径Build Phases---->Compile Sources---->App ...

  5. CEdit 控制键盘操作

    写在前面的话:在工作中要实现这样一个功能,在一个树形控件中选择要发送消息的客户,添加到一个列表控件中,点击确定跳到一个信息发送页面如下图,在发送人编辑框中显示选择的客户,要实现的就是即允许用户删除用户 ...

  6. 文件io之——open/close

    一个进程默认打开三个文件描述符: STDIN_FILENO 0STDOUT_FILENO 1STDERR_FILENO 2 man 2 open可查看详情: open函数可以打开或者创建一个文件: # ...

  7. grub安装centos

    grub安装centos http://hi.baidu.com/soulshape/item/e90302e50da5a710595dd8f7

  8. HTML文档的经常使用标记

    一.HTML文档中经常使用的标记有文字标记.段落标记.列表标记.超链接标记.图像标记.表格标记.框架标记和多媒体标记,以下对这些经常使用标记进行介绍: 1.文字标记:文字是网页重要的组成部分之中的一个 ...

  9. iOS彩票项目--第五天,新特性引导页的封装、返回按钮的自定义、导航控制器的滑动返回以及自定义滑动返回功能

    一.上次实现了在AppDelegate中通过判断app版本决定是否进入新特性页面,今天将AppDelegate中的一坨进行了封装.将self.window的根控制器到底应该为新特性界面,还是主页面,封 ...

  10. warning LNK4099: PDB 原因及解决方案

    0x00 现象及原因举例: warning LNK4099: PDB 'wxbase30ud.pdb' was not found with 'wxbase30ud.lib(any.obj)'使用VC ...