您的位置:首页 > 移动开发 > Unity3D

Unity学习笔记3 简易2D横版RPG游戏制作(三)

2014-05-01 14:10 791 查看
这一篇本来应该是在上一篇后面直接补进去的。不过因为排版的问题。所以我就另开一篇来整理了,好了,废话不多说,马上整理:

十八、关卡的锁定与解锁
前面我们已经解决了在游戏开始时可以选择关卡的问题,接下来我们就要解决下一个问题了。那就是游戏关卡的解锁问题。玩过像愤怒的小鸟、植物大战僵尸等等的游戏的人应该知道,很多游戏都有这样的设定,在你还没有开始过完第一关的时候,是不可以玩第二关和第三关的。有些游戏需要这种功能,有些游戏则不需要。不管需不需要,我们在这里就顺便把这个问题也给研究一下吧:
首先先想一下思路,思路当然就是制作一个变量,来进行判定,如果过了某一关,某个变量就会变成某个值,那么打开下一关的按钮就可以顺利执行了。现在我们来处理一下之前的Door脚本,我就整个贴出来吧:
using UnityEngine;
using System.Collections;

public class Door : MonoBehaviour {

    public string Level;
    GameManager gameManager;
    GameObject gameObjectGM;

    void Start() {
        gameObjectGM = GameObject.FindGameObjectWithTag("GameManager");
        gameManager = gameObjectGM.GetComponent<GameManager>();
    }

    void OnTriggerEnter(Collider other)
    {
        if (other.tag == "Player")
        {
           gameManager.SaveGame();
           PlayerPrefs.SetInt("LevelUnlock",2);
           Application.LoadLevel(Level); 
         } 
     }
}

在这个脚本里面,我主要是加了这么一句:PlayerPrefs.SetInt("LevelUnlock", 2); 里面的这个LevelUnlock是自己随便起的一个变量,保存这个脚本之后,我们进入游戏场景1,然后撞击里面的door物体,就会在跳到下一个场景之前先保存这么一个变量。这里有个地方需要注意一下,PlayerPrefs.SetInt("LevelUnlock", 2);这句话最好是放在Application.LoadLevel(Level); 的前面,虽然我测试过,放在前面的话,载入新场景的时候它还是有顺便储存这么一个变量。但是有可能只是因为这句话比较短,在跳到下一个场景之前就已经执行完毕了。如果在Application.LoadLevel(Level); 这句话后面放了太多句话,让它根本没有时间去执行的话,它可能就没办法全部执行的。因为直接使用Application.LoadLevel(Level); 的话,在进入新场景的时候是会摧毁旧有场景的一切物体的,自然也包括他们身上的所有脚本了。所以在这个地方大家最好注意一下。

接着我们来到LevelSelect场景,打开摄像机上面的LevelSelect脚本,然后照下面这样编辑:

using UnityEngine;
using System.Collections;

public class LevelSelect : MonoBehaviour {

int sw = Screen.width;
int sh = Screen.height;

public string Level1;
public string Level2;

void OnGUI(){
//进入第一关的按钮
if (GUI.Button(new Rect(0, 0, sw * .5f, sh), "第一关"))
{
Application.LoadLevel(Level1);
}
//判断是否进入第二关
if (PlayerPrefs.GetInt("LevelUnlock", 0) >= 2)
{
if (GUI.Button(new Rect(sw * .5f, 0, sw * .5f, sh), "第二关")) {
PlayerPrefs.DeleteKey("LevelUnlock");
Application.LoadLevel(Level2);
}
}
else
{
GUI.Box(new Rect(sw * .5f, 0, sw * .5f, sh),"未解锁\n"+ "第二关");
}
}
}


GUI.Box就是显示一个无法点击的东西,这个就不解释了。当然,你用GUI.Button也是完全没问题的。如果LevelUnlock这个变量加载之后大于等于2的话,那么我们就可以启动第二关的GUI按钮功能,否则的话,第二关的按钮就会变成一个无法点击的东西。在没有进入第一关碰到那个door物体之前,如果直接载入LevelSelect场景的话,LevelUnlock值由于没有赋值,就是零,自然就不可能大于等于2了。这样就可以实现我们的解锁功能了。至于那句PlayerPrefs.DeleteKey("LevelUnlock");是用来删除某个已经保存的变量的。在这里我们可不是想把整个游戏存档给清理了,所以只需要使用DeleteKey功能而不是DeleteAll,千万不要弄错了哈哈。

这样清理掉这个变量仅仅是我在测试的过程中使用的。清理掉之后,如果我们再次载入LevelSelect,就会发现第二关的按钮又被锁定了。可能有人会说,这样搞有什么用?这样搞当然是很有用的。我们在制作游戏的过程中可能需要重复测试,自然不希望被某个已经保存了的变量干扰到我们的测试结果。而且,这种“反解锁”的idea可以用于一些比较狡猾的游戏设计:比如你在游戏里面连续输了太多次,或者是因为某些原因降级了,那么就可以通过这种设计方法,反锁你的某些已进入的关卡,或者是已经习得的技能。同样的,在一些任务和剧情设计中,有可能在某个特定时间上,你是不可以进入某个地方的。比如你的剧情设计自己的小镇外面突然来了一大堆进击的巨人,那么可能在巨人来袭的时候,玩家是不可以出城的,我们就可以在城门进行一个这样的设定,就打不开了。(不是每个人都是兵长,可以把巨人当白萝卜切割的嘛~~)

下面我截了一些图来看看测试结果,我先把所有的存档给清空。然后将场景1复制多了一个,变成场景2,并且把这个场景2中的door物体删掉,用于区分两个场景。

首先我们来到Mainmenu场景,改一下摄像机的MainMenu脚本里面的Level,改成LevelSelect,这样是为了点击“载入游戏”时载入LevelSelect场景。



接下来运行:



然后我们点击载入游戏,我们看到的就是这样。因为还没弄画面,所以有点丑,不过我们先学好基本原理再说,大家见谅。(画面中间那个quad物体是我之前随便摆放进去的,不用管它,直接无视就行。)



接着我们点击左边的按钮进入我们熟悉的场景1,并且去碰撞我们的door物体。(我设定为深绿色的那个物体)



碰到之后我们会自动跳转到下一个场景,下一个场景是没有door物体的,刚刚我们删了,其他的和场景1一模一样。(因为下面的图是我事后截的图,游戏存档被我清理过一次,所以细心一些的朋友会发现左上角的红心减少了,其实你正常进入的话是不会影响你保存的curHealth的变量的。)

我们可以看到,深绿色的door不见了,我们已经来到场景2了。现在我们保存一下游戏,然后退出。然后重新进入到LevelSelect的画面中:



这一次,右边的第二关按钮已经解锁了。我们可以按第二关的按钮进入我们的游戏了!!到这里,解锁功能就做好了,我们马上点一下看看:



嗯,没错,是我们的第二关。

但是在实际操作中会有这样一个问题。因为我的设计是让载入第二关的瞬间就清理掉LevelUnlock的值,所以如果这样做的话,在那个LevelSelect画面进入第二关的画面的过程中,你会看到第二关的GUI.Button会变成GUI.Box,虽然只是一瞬间,但要是真的做成游戏的话,视觉体验上就会很差了。解决这个问题的最简单方法就是不要在那里删掉LevelUnlock这个变量,就不会出事。当然,如果你实在要这样做,也还有一个办法的,那就是让整个场景变暗,然后再重新亮起来,这样就可以实现我们要的效果了。关于淡入淡出效果,我还在研究,所以暂时没办法整理到教程里面来。请见谅。

好了,关于解锁关卡的研究就到这里,下面我们继续学习。

十九、金钱

如果说前面几讲稍微有点复杂的话,那么这一讲就实在是太简单了。这一讲其实就是增加一个简单的变量。因为我们暂时还没有涉及到交易系统,所以也没什么好说的。

首先呢,我们建一个变量,static public int curCoins = 0;这个是弄在我们的GameManager脚本里面的,就不再解释了。

接着修改void Awake(),在里面读取存档后增加一个curCoins = PlayerPrefs.GetInt("Player Coins");

修改Update()里面的这个:if (playerStats) {statsDisplay.text = "等级:" + level + "\n经验:" + curEXP + "/" + maxEXP + "\n攻击力:" + bulletDamage + "\n金钱" + curCoins;} 

这样的话在显示的时候就可以连“金钱”也一起显示出来。

在SaveGame()里面增加PlayerPrefs.SetInt("Player Coins", curCoins);这一句。

然后保存我们的脚本。

为了大家方便,我将这个脚本重新贴出来:

using UnityEngine;
using System.Collections;

public class GameManager : MonoBehaviour {
//引用Controller2D
public Controller2D controller2D;
//角色生命值
public Texture playersHealthTexture;
//控制上面那个Teture的屏幕所在位置
public float screenPositionX;
public float screenPositionY;
//控制桌面图标的大小
public int iconSizeX = 25;
public int iconSizeY = 25;
//初始生命值
static public int curHealth = 3;
//游戏刚开始时,第一级的最大生命值,以后每级增加1。
public int maxHealth = 3;

GameObject player;
//我们的子弹的攻击力
static public int bulletDamage = 1;
//当前经验值
public int curEXP;
//从第一级升到下一级需要的经验值(以后每一级增加50)
int maxEXP = 50;
//游戏刚开始时的等级
int level = 1;
//游戏刚开始的金钱
static public int curCoins = 0;

//这个布尔值用于判定是否显示角色的状态
bool playerStats;
//下面这个用于显示角色的状态
public GUIText statsDisplay;
//用于暂停的布尔值
bool pauseMenu;
//用于判断是否是否保存
int saved = 0;
//自动保存计时器
public float autoSaveTimer;

void Awake(){
saved = PlayerPrefs.GetInt ("Game Saved");
if (saved == 1) {
curEXP = PlayerPrefs.GetInt ("Player EXP");
level = PlayerPrefs.GetInt ("Player Level");
curCoins = PlayerPrefs.GetInt("Player Coins");
maxEXP = level * 50;
maxHealth = level + 2;
curHealth = maxHealth;
}
}

//这个地方定义了私有变量player作为一个GameObject,然后用下面的FindGameObjectWithTag获取它,这样的话,在下面的伤害判断时,就可以用player.renderer了。
void Start(){
player = GameObject.FindGameObjectWithTag("Player");
}

void Update(){
//自动存档功能
autoSaveTimer += Time.deltaTime;
if (autoSaveTimer >= 10f) {
SaveGame();
print ("保存啦~~");
autoSaveTimer =0;
}

if (Input.GetKeyDown (KeyCode.P)) {
pauseMenu = !pauseMenu;
}

if (curEXP >= maxEXP) {
LevelUp();
}

if (Input.GetKeyDown (KeyCode.C)) {
playerStats = !playerStats;
}

if (Input.GetKeyDown (KeyCode.E)) {
curEXP += 10;
}

if (playerStats) {
statsDisplay.text = "等级:" + level + "\n经验:" + curEXP + "/" + maxEXP + "\n攻击力:" + bulletDamage + "\n金钱" + curCoins;
}
else {
statsDisplay.text = "";
}

if (curHealth > maxHealth) {
curHealth = maxHealth;
}
}
//这个函数用于角色升级
void LevelUp(){
curEXP = 0;
maxEXP = maxEXP + 50;
level++;

//升级的功效
maxHealth++;
}

//OnGUI函数最好不要出现多次,容易造成混乱,所以我把要展示的东西都整合在这个里面
void OnGUI(){

//控制角色生命值的心的显示
for (int h =0; h < curHealth; h++) {
GUI.DrawTexture(new Rect(screenPositionX + (h*iconSizeX),screenPositionY,iconSizeX,iconSizeY),playersHealthTexture,ScaleMode.ScaleToFit,true,0);
}

if (pauseMenu) {
//“保存游戏”按钮
if(GUI.Button(new Rect(Screen.width*.25f,Screen.height*.4f,Screen.width*.5f,Screen.height*.1f),"保存游戏")){
SaveGame();
}
//“显示保存的数据”按钮
if(GUI.Button(new Rect(Screen.width*.25f,Screen.height*.6f,Screen.width*.5f,Screen.height*.1f),"显示保存的数据")){
print ("显示保存的数据");
print("当前等级:"+ PlayerPrefs.GetInt("Player Level"));
print("当前经验:"+ PlayerPrefs.GetInt("Player EXP"));
print("是否保存:"+ PlayerPrefs.GetInt("Game Saved"));
}
}
}

public void SaveGame(){
saved = 1;
PlayerPrefs.SetInt("Player Level",level);
PlayerPrefs.SetInt("Player EXP",curEXP);
PlayerPrefs.SetInt("Player Coins", curCoins);
PlayerPrefs.SetInt("Game Saved",saved);
print ("已保存");
}

void PlayerDamaged(int damage){   //此处使用player.renderer.enabled来进行判断,如果角色没有在闪烁,也就是存在的状态为真,那么才会受到伤害,这样可以避免角色连续受伤,还有另外一种方法是采用计时,这里没有采用那种方法。
if (player.renderer.enabled) {
if (curHealth > 0) {
curHealth -= damage;
}

if (curHealth <= 0) {
RestartScene ();
}
}
}

void RestartScene(){
Application.LoadLevel (Application.loadedLevel);
}
}


不想认真看那几处修改位置的可以直接复制之后覆盖原来的GameManager脚本。

然后打开Enemy2D脚本,修改一处:

void EnemyDamaged(int damage){
if (enemyHealth > 0) {
enemyHealth -= damage;
}

if (enemyHealth <= 0) {
enemyHealth = 0;
Destroy(gameObject);
if(basicEnemy)
{
gameManager.curEXP += 5;
GameManager.curCoins += 5;
}
if (advancedEnemy)
{
gameManager.curEXP += 10;
GameManager.curCoins += 10;
}
}
}

修改完成之后,我们打到basic级别的敌人就会得到五点经验,五块钱,advanced级别的敌人就是十点经验和十块钱。这样就比较像正常的RPG游戏了。

好了,这一讲没什么内容,我们马上看下一讲。

二十、开始我们的武器设置

其实视频里面这一讲是非常简单的,首先是调整一下原本的LevelSelect画面的尺寸,我就不唠叨了,直接贴出代码:

using UnityEngine;
using System.Collections;

public class LevelSelect : MonoBehaviour
{
int sw = Screen.width;
int sh = Screen.height;

public string Level1;
public string Level2;

void OnGUI()
{
//进入第一关的按钮
if (GUI.Button(new Rect(sw * .1f, sh * .2f, sw * .3f, sh * .5f), "第一关"))
{
Application.LoadLevel(Level1);
}
//判断是否进入第二关
if (PlayerPrefs.GetInt("LevelUnlock", 0) >= 2)
{
if (GUI.Button(new Rect(sw * .6f, sh * .2f, sw * .3f, sh * .5f), "第二关"))
{
PlayerPrefs.DeleteKey("LevelUnlock");
Application.LoadLevel(Level2);
}
}
else
{
GUI.Box(new Rect(sw * .6f, sh * .2f, sw * .3f, sh * .5f), "\n\n\n未解锁\n" + "第二关");
}
}
}

(我用了VS 2013的自动排版,感觉挺不错的,这样看起来就整齐多了。其实看很多视频,mono也是可以自动排版的,但是我实在搞不懂是怎么实现那些功能的。)

然后就是截个图让大家看看调整之后的效果:



这样是不是整齐多了呢?
接着是对GameManager进行修改,由于下一节还要继续改,就暂时不放代码。我们先看看要改哪个部分。首先是pauseMenu,也就是暂停按钮的设置。



上面这个,在之前的p按钮里面稍微改下就可以的。我就不多说了。退出游戏的话,可以利用Application.LoadLevel("Mainmenu");回到主菜单,然后再在主菜单那里退出。或者也可以用Application.Quit();这个是直接退出游戏的,不推荐现在使用,因为这个无法在我们的unity里面测试,要测试这个指令就必须把游戏导出来,然后再去测试。现在知道有这么个东西就行了。
if (Input.GetKeyDown(KeyCode.P))
{
//pauseMenu = !pauseMenu;
pauseMenu = true;
Time.timeScale = 0;
}

input这里,增加一个Time.timeScale = 0;就可以让整个游戏画面禁止。当然,也包括我们的玩家。暂停游戏就是这么实现的。当这个数字为1时则是正常速度运行游戏,数值变小或者变大都会对我们整个游戏的运行产生影响。在弄这个玩意的时候我突然灵光一闪,想到了一点很有趣的东西。有时候我们需要实现一种这样的效果,让除了主角之外的全场变慢,这个是很多电影里面经常看到的东西。最笨的方法,就是把和主角在一起的全部互动物体通通减速,但是这样除非所有物体都标有相同的tag,否则很难实现。另一种方法就是利用这个Time.timeScale,比如说,我们可以让它等于0.5,那么就可以实现敌人慢动作的效果了。有人会说,你进水了呀,这样调整之后我们主角也慢动作了啊。可是,我们可以在这种特殊的情况下提高主角的速度嘛。如果只是针对主角一人的话,那就好办了。主角可以速度翻倍,甚至翻四倍,那就够了,嘿嘿。这样才能让全场的机关慢下来,哈哈哈哈。我在想,也许有些忍者游戏可以这样设计~~
好了,如果我们想要回到游戏,只需要让Time.timeScale的值重新等于1就可以了。也可以让它在一定时间内慢慢增加或者慢慢减少,来让我们的游戏达到某种突然变得松弛或紧张起来的感觉。
至于武器菜单,看下一讲吧:
二十一、简单的武器菜单
在这个游戏教程里面,并没有那种NPC式的商店或者是比较复杂的购物系统,所以,目前我们的金钱暂时没办法用来进行复杂的购物设计,只能用来做一些比较简单的解锁。首先我先将整个修改之后的GameManager脚本贴出来吧,贴出来之后我再来说明一下:
using UnityEngine;
using System.Collections;

public class GameManager : MonoBehaviour
{
//引用Controller2D
public Controller2D controller2D;
//角色生命值
public Texture playersHealthTexture;
//控制上面那个Teture的屏幕所在位置
public float screenPositionX;
public float screenPositionY;
//控制桌面图标的大小
public int iconSizeX = 25;
public int iconSizeY = 25;
//初始生命值
static public int curHealth = 3;
//游戏刚开始时,第一级的最大生命值,以后每级增加1。
public int maxHealth = 3;

GameObject player;
//我们的子弹的攻击力
static public int bulletDamage = 1;
//当前经验值
public int curEXP;
//从第一级升到下一级需要的经验值(以后每一级增加50)
int maxEXP = 50;
//游戏刚开始时的等级
int level = 1;
//游戏刚开始的金钱
static public int curCoins = 0;

//这个布尔值用于判定是否显示角色的状态
bool playerStats;
//下面这个用于显示角色的状态
public GUIText statsDisplay;
//用于暂停的布尔值
bool pauseMenu;
//用于判断是否是否保存
int saved = 0;
//自动保存计时器
public float autoSaveTimer;
//用于是否显示武器菜单
bool weaponsMenu;
//屏幕宽度
int sw = Screen.width;
//屏幕高度
int sh = Screen.height;
void Awake()
{
saved = PlayerPrefs.GetInt("Game Saved");
if (saved == 1)
{
curEXP = PlayerPrefs.GetInt("Player EXP");
level = PlayerPrefs.GetInt("Player Level");
curCoins = PlayerPrefs.GetInt("Player Coins");
maxEXP = level * 50;
maxHealth = level + 2;
curHealth = maxHealth;
}
}

//这个地方定义了私有变量player作为一个GameObject,然后用下面的FindGameObjectWithTag获取它,这样的话,在下面的伤害判断时,就可以用player.renderer了。
void Start()
{
player = GameObject.FindGameObjectWithTag("Player");
}

void Update()
{
//洗钱 if(Input.GetKeyDown(KeyCode.M)){ curCoins += 100; }
//自动存档功能
autoSaveTimer += Time.deltaTime;
if (autoSaveTimer >= 10f)
{
SaveGame();
print("保存啦~~");
autoSaveTimer = 0;
}

if (Input.GetKeyDown(KeyCode.P)) { //pauseMenu = !pauseMenu; pauseMenu = true; Time.timeScale = 0; }

if (curEXP >= maxEXP)
{
LevelUp();
}

if (Input.GetKeyDown(KeyCode.C))
{
playerStats = !playerStats;
}

if (Input.GetKeyDown(KeyCode.E))
{
curEXP += 10;
}

if (playerStats)
{
statsDisplay.text = "等级:" + level + "\n经验:" + curEXP + "/" + maxEXP + "\n攻击力:" + bulletDamage + "\n金钱" + curCoins;
}
else
{
statsDisplay.text = "";
}

if (curHealth > maxHealth)
{
curHealth = maxHealth;
}
}
//这个函数用于角色升级
void LevelUp()
{
curEXP = 0;
maxEXP = maxEXP + 50;
level++;

//升级的功效
maxHealth++;
}

//OnGUI函数最好不要出现多次,容易造成混乱,所以我把要展示的东西都整合在这个里面
void OnGUI()
{

//控制角色生命值的心的显示
for (int h = 0; h < curHealth; h++)
{
GUI.DrawTexture(new Rect(screenPositionX + (h * iconSizeX), screenPositionY, iconSizeX, iconSizeY), playersHealthTexture, ScaleMode.ScaleToFit, true, 0);
}

if (pauseMenu)
{
//武器菜单按钮
if (GUI.Button(new Rect(Screen.width * .25f, Screen.height * .3f, Screen.width * .5f, Screen.height * .1f), "武器菜单"))
{
pauseMenu = false;
weaponsMenu = true;
}

//保存游戏按钮
if (GUI.Button(new Rect(Screen.width * .25f, Screen.height * .4f, Screen.width * .5f, Screen.height * .1f), "保存游戏"))
{
SaveGame();
}
//“显示保存的数据”按钮
//if (GUI.Button(new Rect(Screen.width * .25f, Screen.height * .6f, Screen.width * .5f, Screen.height * .1f), "显示保存的数据"))
//{
// print("显示保存的数据");
// print("当前等级:" + PlayerPrefs.GetInt("Player Level"));
// print("当前经验:" + PlayerPrefs.GetInt("Player EXP"));
// print("是否保存:" + PlayerPrefs.GetInt("Game Saved"));
//}

//回到游戏按钮
if (GUI.Button(new Rect(Screen.width * .25f, Screen.height * .5f, Screen.width * .5f, Screen.height * .1f), "回到游戏"))
{
Time.timeScale = 1;
pauseMenu = false;
}
//退出游戏按钮
if (GUI.Button(new Rect(Screen.width * .25f, Screen.height * .6f, Screen.width * .5f, Screen.height * .1f), "退出游戏"))
{
Application.LoadLevel("Mainmenu");
//Application.Quit();
}
}

if (weaponsMenu)
{
//第一武器
if (PlayerPrefs.GetInt("Weapon1", 0) >= 1)
{
bulletDamage = 3;
if (GUI.Button(new Rect(sw * .1f, sh * .2f, sw * .3f, sh * .5f), "已装备武器1"))
{
bulletDamage = 3;
}
}
else
{
if (GUI.Button(new Rect(sw * .1f, sh * .2f, sw * .3f, sh * .5f), "购买武器1"+"\n价格:200金币"))
{
if (curCoins >= 200)
{
curCoins -= 200;
PlayerPrefs.SetInt("Weapon1", 1);
}
}
}
//第二武器
if (PlayerPrefs.GetInt("Weapon2", 0) >= 1)
{
bulletDamage = 6;
if (GUI.Button(new Rect(sw * .6f, sh * .2f, sw * .3f, sh * .5f), "已装备武器2"))
{
bulletDamage = 6;
}
}
else
{
if (GUI.Button(new Rect(sw * .6f, sh * .2f, sw * .3f, sh * .5f), "购买武器2" + "\n价格:500金币"))
{
if (curCoins >= 500)
{
curCoins -= 500;
PlayerPrefs.SetInt("Weapon2", 1);
}
}
}
//回到游戏按钮
if (GUI.Button(new Rect(Screen.width * .25f, Screen.height * .5f, Screen.width * .5f, Screen.height * .1f), "回到游戏"))
{
Time.timeScale = 1;
weaponsMenu = false;
}
}
}

public void SaveGame()
{
saved = 1;
PlayerPrefs.SetInt("Player Level", level);
PlayerPrefs.SetInt("Player EXP", curEXP);
PlayerPrefs.SetInt("Player Coins", curCoins);
PlayerPrefs.SetInt("Game Saved", saved);
PlayerPrefs.SetInt("Player Damage", bulletDamage);
print("已保存");
}

void PlayerDamaged(int damage)
{ //此处使用player.renderer.enabled来进行判断,如果角色没有在闪烁,也就是存在的状态为真,那么才会受到伤害,这样可以避免角色连续受伤,还有另外一种方法是采用计时,这里没有采用那种方法。
if (player.renderer.enabled)
{
if (curHealth > 0)
{
curHealth -= damage;
}

if (curHealth <= 0)
{
RestartScene();
}
}
}

void RestartScene()
{
Application.LoadLevel(Application.loadedLevel);
}
}

内容很长,所以有兴趣的要耐心地好好看,虽然增加的内容也并不是很多。哈哈。我用VS 2013进行了自动排版操作,所以看起来整齐多了。mono的排版并不是很给力,所以我并不是很喜欢。首先我们增加了一个参数。bool weaponsMenu;用于判定是否显示武器菜单,这个在武器菜单的GUI中用到的。接着呢,我们做了个这样的小东西:
//洗钱
if(Input.GetKeyDown(KeyCode.M)){
curCoins += 100;
}

这个只是我在测试过程中用于快速增加金钱,不用慢慢去打怪收钱就可以马上购买装备的一个测试而已,好孩纸不要研究怎么作弊哈。接着呢,就在GUI这一块做了点处理,并且我已经设计好了,购买了武器1的话,我们的bulletDamage(也就是攻击力,因为在目前来说,我们只有一种武器,没有一堆武器)就会变成3,购买了武器2的话,我们的bulletDamage就会变成6,不过有个小问题我还没处理的,就是购买了武器2之后,理论上来说还是可以购买武器1的,而且购买了武器1之后,理应还保持武器2的战斗力(除非进行武器的切换)不过这个是个小问题,大家可以用一些布尔值来解决,我就不再赘述了。至于武器的切换,以及武器在场景中的实际发挥(尤其是近战武器),这个是以后的研究重点,这一篇就暂时先不说了。

其实前面提到的关卡解锁和这次提到的所谓购买武器,并没有什么本质上的区别。武器的购买系统并没有真正的做出来,武器的合成、锤炼、优化等等这方面的内容那就更不用说了。所以,目前只能算是个非常非常简单的2D RPG的雏形,但是这几天的总结和学习也确实让我掌握了很多很多的东西。我觉得,搞开发的人确实很有必要写博客。因为有些东西只有写出来才不会忘记,也才能加深印象。自己稍微懂了和能够用文字表述出来是两个完全不同的档次,还是有很大区别的。所以,我建议有学习Unity的朋友也一起写写博客,有空多多交流吧。

二十二、结束场景

这是本篇中的最后一讲了。下一篇博客暂时不会继续讲2D RPG的内容。好了,我们继续看内容,这一篇只是在炒冷饭,并没有增加什么新的知识点。就是制作一个游戏结尾的场景而已。

我们建一个新的场景,命名Endscene,然后命名一个叫做EndScene的脚本,扔到这个场景的摄像机上面去,进行以下编辑:

using UnityEngine;
using System.Collections;

public class EndScene : MonoBehaviour
{
public Texture backgroundTexture;

public float sPlaceX;
public float sPlaceY;
public float sSizeX;
public float sSizeY;

public string Level;

void OnGUI()
{
GUI.DrawTexture(new Rect(0, 0, Screen.width, Screen.height), backgroundTexture);

if (GUI.Button(new Rect(Screen.width * sPlaceX, Screen.height * sPlaceY, Screen.width * sSizeX, Screen.height * sSizeY), "回到主菜单"))
{
Application.LoadLevel(Level);
}
}
}

然后就随便找一张图片做背景(这个随你喜欢),然后在外面设置你要返回的那个Level的名字。这个嘛,我们就设置为Mainmenu就可以了。

接着我们在场景2里面随便建一个物体,让主角碰到它之后就会跳转到结束场景。这个比较简单,我自己就没弄了。有需要的再去弄一下。然后不要忘了,我们还要把这个叫做Endscene的场景拖拽到菜单栏的File→Build Settings的场景里面去:



然后测试运行,基本没什么问题的,我就不截图了。
好啦,到这里,我们就已经实现了一个2D横版RPG游戏的许多基本功能,包括场景加载、简单的战斗计算、经验系统、游戏存档、跳跃、踏板、解锁装置、自动存档、武器系统等等。虽然说这些东西都比较简单,暂时做不出什么大型和炫酷的效果,而且既没有音效,也没有贴图和动画,非常单调。不过这些基本的要素掌握了之后,相信很多人可以利用发散性的想法设计出很多有趣的东西来了。我觉得看教程最大的意义是学习一种方法并借鉴别人的解决方案,而不是从头到尾照做一遍,那样的话还是没办法设计出属于自己的东西的。接下来的这几天可能稍有点忙,估计暂时不更新博客了。不过一有空我就会马上更新的。
这篇写了三天的博客就先到这里,如果大家有什么看的不太清楚的可以留言。欢迎大家一起学习,一起交流,以后我会尽量把一些好东西上传到自己的资源里面去。当然,我也会把这两天的教程的内容上传到我的CSDN资源里面共享给大家。需要注意的是必须使用4.3或者以上版本的Unity才能打开我的资源。这些资源将免费公开,不收取任何下载币,嘻嘻。

本次教程的工程文件下载:http://download.csdn.net/detail/sinolzeng/7279823
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息