美文网首页RPG游戏制作大师RPG Maker MVRPGmaker MV
【RPG Maker MV插件编程】【实例教程2】制作一个启动画

【RPG Maker MV插件编程】【实例教程2】制作一个启动画

作者: 鳗驼螺 | 来源:发表于2017-06-14 19:08 被阅读1680次

    作者:Mandarava(鳗驼螺)
    微博:@鳗驼螺pro

    启动画面是游戏开始时,在进入标题画面前的一个显示画面,通常用于展示游戏开发商的Logo。RMMV自带一个官方启动画面插件 MadeWithMv,可以设定自己的启动图,一般来说,这个插件足够使用。本文介绍如何制作类似的一个启动画面插件。

    首先,新建一个名为 MND_Splash.js 的文件放到 js/plugins 目录下,并在RMMV中安装该插件。

    从哪里开始?

    游戏在启动时,Scene_Boot 类用于初始化整个游戏,而 Scene_Boot.prototype.start 方法是场景开始时的处理方法。启动画面是游戏启动时的第一个“场景”,所以要创建启动画面,就应该在 start 方法中创建。来看一下 start 原始方法的实现:

    Scene_Boot.prototype.start = function() {
        Scene_Base.prototype.start.call(this);
        SoundManager.preloadImportantSounds();
        if (DataManager.isBattleTest()) {
            DataManager.setupBattleTest();
            SceneManager.goto(Scene_Battle);
        } else if (DataManager.isEventTest()) {
            DataManager.setupEventTest();
            SceneManager.goto(Scene_Map);
        } else {
            this.checkPlayerLocation();
            DataManager.setupNewGame();
            SceneManager.goto(Scene_Title);
            Window_TitleCommand.initCommandPosition();
        }
        this.updateDocumentTitle();
    };
    
    1. DataManager.isBattleTest() 检测当前是否为进行战斗测试,如果是就进入战斗场景,比如在 数据库-敌群 界面进行战斗测试时;
    2. DataManager.isEventTest() 检测当前是否为事件测试,如果是则进入当前的游戏地图界面,比如在编辑事件时进行事件内容的测试时。
    3. 除此之外, else 部份就是正常启动游戏时要进入的场景的选择,可以在这里创建并进入我们的启动画面场景。

    这里 SceneManager.goto(Scene_Title) 方法用于进入标题画面。从这里可以看出,RMMV在开始游戏时默认是直接进入标题画面的,所以很简单,只要将这里的 SceneManager.goto(Scene_Title) 改成进入我们的启动画面即可,如:SceneManager.goto(Scene_Splash)(假设我们的启动画面场景类叫做Scene_Splash),再由启动画面进入标题画面,为此就来创建我们的启动画面的场景类。

    创建启动画面的场景类

    要创建一个新的场景类,最简单的做法是改一个现有的场景类。场景类有很多,包括:Scene_BaseScene_BootScene_BattleScene_DebugScene_EquipScene_FileScene_GameEndScene_GameoverScene_ItemBaseScene_ItemScene_LoadScene_MapScene_MenuBaseScene_MenuScene_NameScene_OptionsScene_SaveScene_ShopScene_SkillScene_StatusScene_Title。分析一下这些场景类的实现,确定哪些方法需要,最后把我们要用到的方法拷贝到 MND_Splash.js 中,我们的场景类命名为:Scene_Splash。最后我们需要的方法包括以下几个:构建器部分、Scene_Splash.prototype.create 方法、Scene_Splash.prototype.start 方法、Scene_Splash.prototype.stop 方法、Scene_Splash.prototype.terminate 方法、Scene_Splash.prototype.update 方法等(当然除了构建器部分外,其它方法都是可选的)。下面就在Scene_Splash类中重写这些方法。

    构建器部分

    Scene_Base类是所有Scene类的基类,我们要创建的类Scene_Splash实际比较简单,所以只需要直接继承Scene_Base类就可以了。下面是Scene_Splash的构建器及初始化代码:

    function Scene_Splash() {
        this.initialize.apply(this, arguments);
    }
    
    Scene_Splash.prototype = Object.create(Scene_Base.prototype);
    Scene_Splash.prototype.constructor = Scene_Splash;
    
    Scene_Splash.prototype.initialize = function() {
        Scene_Base.prototype.initialize.call(this);
    };
    

    Scene_Splash.prototype.create方法

    该方法是在场景创建时要执行的处理,在这里创建组件并将它们加入渲染队列中。所以,我们可以在这里添加要显示logo图片。假设我们的Logo图片放在 img/system/MyLogo.png,那么该方法的重写实现如下:

    Scene_Splash.prototype.create = function() {
        Scene_Base.prototype.create.call(this);
    
        this.logo=new Sprite();
        this.logo.bitmap=ImageManager.loadSystem("MyLogo");    
        this.addChild(this.logo);
    };
    

    Scene_Base.prototype.create.call(this);这个是调用基类(父类)的同名方法,因为我们这里是重写基类的该方法,你需要让基类中的操作也执行一下(除非你明确不想执行;即使现在基类的该方法没有执行任何操作,为了以后的兼容,比如官方在未来的某个版本添加了操作,也应该用调用基类的实现)。this.logo 就是用于显示我们的Logo图片的精灵对象,使用场景的 addChild() 方法可以将精灵加入到场景。在这里我们并没有为精灵设置显示座标,因为此时的Logo图片还没有加载完毕,读取到的图片尺寸高宽都是0,如果你需要根据图片的高宽为其定位,那么,这个定位处理应该放到 start 方法中去。

    Scene_Splash.prototype.start方法

    该方法是场景启动时要执行的处理。这里用 startFadeIn(duration, white) 方法让场景出现淡入效果。同时将logo图片显示到场景正中间。

    Scene_Splash.prototype.start = function() {
        Scene_Base.prototype.start.call(this);
        this.startFadeIn(this.slowFadeSpeed(), false);
    
        //将this.logo定位到场景的正中(由于没有使用logo的尺寸来定位,所以下面这段代码放到 create 方法中也是没问题的)
        this.logo.anchor.x=0.5;
        this.logo.anchor.y=0.5;
        this.logo.x=Graphics.width/2;
        this.logo.y=Graphics.height/2;
    };
    

    Graphics.widthGraphics.height 用于获取游戏屏幕的宽高尺寸。这里将logo精灵的锚点设置到其正中心,再将其坐标设置到屏幕正中心,这样就能让精灵呈现在屏幕中心。

    Scene_Splash.prototype.stop方法

    该方法是场景停止时要执行的处理。这里用一个 fadeOutAll 淡出效果,淡出画面及所有背景音乐、音效。

    Scene_Splash.prototype.stop = function() {
        Scene_Base.prototype.stop.call(this);
        this.fadeOutAll();
    };
    

    Scene_Splash.prototype.terminate方法

    该方法是在切换到其它场景时终止当前场景的处理。假如你在启动画面中添加了背景音乐,那么可以在这里终止背景音乐或音效的播放。

    Scene_Splash.prototype.terminate = function() {
        Scene_Base.prototype.terminate.call(this);
        AudioManager.stopAll();
    };
    

    Scene_Splash.prototype.update方法

    该方法是每帧运行一次的更新处理,可以在该方法中检测是否需要切换到其它场景、要切换到哪个场景等。(当然,如果你要实现动态logo,那么也可以在这里更新logo动画。)
      现在,我们想在启动画面停留90帧,90帧后自动切换到标题画面。那么代码如下:

    Scene_Splash.prototype.update = function() {
        this._wait = this._wait || 0;//如果this._wait尚未定义,则定义并赋值为0;当然,这个_wait的定义代码最好放到构建器或create方法中进行
        if(this._wait>=0) {
            if (this._wait >= 90) {
                SceneManager.goto(Scene_Title);
                this._wait = -1;//让_wait=-1确保90帧后这段代码不会再被运行,否则会出现一直要goto却goto不了的情形
            } else {
                this._wait++;
            }
        }
        Scene_Base.prototype.update.call(this);
    };
    

    如果同时想在玩家点击启动画面或按下确定键后立即切换到标题画面而不用再等待完90帧,可以改为以下代码:

    Scene_Splash.prototype.update = function() {
        if (this.isActive() && !this.isBusy() && (Input.isTriggered('ok') || TouchInput.isTriggered())) {//新增
            SceneManager.goto(Scene_Title);
            return;
        }
        
        if (this._wait == undefined) { this._wait = 0; }
        if (this._wait >= 0) {
            if (this._wait >= 90) {
                SceneManager.goto(Scene_Title);
                this._wait = -1
            } else {
                this._wait++;
            }
        }
        Scene_Base.prototype.update.call(this);
    };
    

    Input.isTriggered('ok') 用于检测玩家是否按下了确定键,TouchInput.isTriggered() 用于检测玩家是否点击了屏幕,如果按下了确定键或点击了屏幕,则进入标题界面。

    至此,一个启动画面的插件就完成了,完整代码如下:

    
    Scene_Boot.prototype.start = function() {
        Scene_Base.prototype.start.call(this);
        SoundManager.preloadImportantSounds();
        if (DataManager.isBattleTest()) {
            DataManager.setupBattleTest();
            SceneManager.goto(Scene_Battle);
        } else if (DataManager.isEventTest()) {
            DataManager.setupEventTest();
            SceneManager.goto(Scene_Map);
        } else {
            this.checkPlayerLocation();
            DataManager.setupNewGame();
            SceneManager.goto(Scene_Splash);
            Window_TitleCommand.initCommandPosition();
        }
        this.updateDocumentTitle();
    };
    
    function Scene_Splash() {
        this.initialize.apply(this, arguments);
    }
    
    Scene_Splash.prototype = Object.create(Scene_Base.prototype);
    Scene_Splash.prototype.constructor = Scene_Splash;
    
    Scene_Splash.prototype.initialize = function() {
        Scene_Base.prototype.initialize.call(this);
    };
    
    Scene_Splash.prototype.create = function() {
        Scene_Base.prototype.create.call(this);
    
        this._wait = 0;
        this.logo=new Sprite();
        this.logo.bitmap=ImageManager.loadSystem("MyLogo");
        this.addChild(this.logo);
    };
    
    Scene_Splash.prototype.start = function() {
        Scene_Base.prototype.start.call(this);
        this.startFadeIn(this.slowFadeSpeed(), false);
    
        this.logo.anchor.x=0.5;
        this.logo.anchor.y=0.5;
        this.logo.x=Graphics.width/2;
        this.logo.y=Graphics.height/2;
    };
    
    Scene_Splash.prototype.update = function() {
        if (this.isActive() && !this.isBusy() && (Input.isTriggered('ok') || TouchInput.isTriggered())) {
            SceneManager.goto(Scene_Title);
            return;
        }
    
        this._wait = this._wait || 0;
        if (this._wait >= 0) {
            if (this._wait >= 90) {
                SceneManager.goto(Scene_Title);
                this._wait = -1
            } else {
                this._wait++;
            }
        }
        Scene_Base.prototype.update.call(this);
    };
    
    Scene_Splash.prototype.stop = function() {
        Scene_Base.prototype.stop.call(this);
        this.fadeOutAll();
    };
    
    Scene_Splash.prototype.terminate = function() {
        Scene_Base.prototype.terminate.call(this);
        AudioManager.stopAll();
    };
    

    可以改进的地方:启动图的图片、等待时间这二项可以做成插件参数,以便可以自由设置。有关如何实现插件参数,请参考我的另一篇教程:【RPG Maker MV插件编程】【实例教程1】怎样编写一个插件?

    by: Mandarava(鳗驼螺) 2017.06.14

    相关文章

      网友评论

      • 昆仑山下有昆仑:不知道你还在看关注这个吗,最近才进maker mv的坑,看到了一个仿SAO进入动画的一个视频我觉得点燃了我的欲望…请问从哪开始起步哦…很方
        鳗驼螺:@花散思起年回 你说动态图指gif?gif我不知道mv是否直接支持,不过,最好还是导出出帧序列后,再进行连播,这样比较好控制,比如可以控制播放速度。这方面可以参考我的另二篇教程,《玩转标题画面》和《制作小游戏:坦克大战(上)》。
        74e4bb08d6a4:您好请问这个启动页面如果是动态图的话怎么办呢。萌新、、
        鳗驼螺:@昆仑山下有昆仑 我几分钟热度过去了,最近也没什么研究。不过动画嘛想想就是些cg帧吧,你可以看看坦克大战小游戏这篇:http://www.jianshu.com/p/ddfa12f1acc9,有涉及动画方面的内容。

      本文标题:【RPG Maker MV插件编程】【实例教程2】制作一个启动画

      本文链接:https://www.haomeiwen.com/subject/hfhrqxtx.html