零基础开发RPG游戏开源讲座(四)-游戏脚本化&地图跳转
html5[color=rgb(68, 68, 68) !important]游戏开发-零基础开发RPG游戏-开源讲座(一)
http://www.html5cn.org/article-1737-1.html
html5游戏开发-零基础开发RPG游戏-开源讲座(二)-跑起来吧英雄
http://www.html5cn.org/article-1738-1.html
html5游戏开发-零基础开发RPG游戏-开源讲座(三)-卷轴&对话实现
http://www.html5cn.org/article-1740-1.html
首先,本篇文章是零基础开发RPG游戏-开源讲座系列文章的第四篇,来实现游戏的脚本化,和利用游戏脚本实现地图场景的切换。如下应该是我们先了解的。
一,什么是游戏脚本
简单说,游戏脚本就是依据一定的格式编写的可执行文件,游戏可以通过脚本中自定义的语句来执行相应的逻辑。
二,为什么要将游戏脚本化
游戏脚本,可以令我们的游戏动态化,比如当我们开发了一款rpg游戏,里面的剧情,事件以及地图等,我们如果将这些全部写进程序里,当然是可以的,但是一旦出现问题,哪怕几个错别字,我们需要先将这几个错别字改正,并且将整个程序重新编译发布一遍,这个过程是相当令人反感的,因为如果游戏的程序跟着游戏的内容不断进行修改的话,那只会使你的程序越来越复杂。但是如果我们将这些可重复的数据,都定义到游戏程序之外的文件里面,当游戏引擎开发完毕,我们的游戏通过读取这些外部文件,来执行相应的剧情和事件,那么,像上述当我们的游戏出现了问题,我们只需要改动这些外部文件就可以了,并不需要重新编译整个程序,这样便使得我们的游戏开发,变得便利简洁。
*当然,对于html5来说,不需要重新编译程序,但是对于rpg的游戏来说,脚本还是必不可少的,因为游戏的剧本不可能全都写到程序里。
三,如何来实现游戏的脚本化
好了,接下来,先来考虑以什么形式来制作游戏的脚本,我们有多种选择,可以选择xml,可以选择json,也可以选择纯自定义语法,
这次,我为了省事,选用比较方便处理的json,因为javascript可以很轻松的处理json数据。
目前游戏中实现的内容有,地图场景添加,游戏人物添加,以及人物对话的实现。那么,我在设计游戏脚本的时候,必须包含这些数据,然后才能将这三项功能用脚本来控制。
首先看下面的json
- var script = {
- stage01:{
- map:[
- [18,18,18,18,18,18,18,18,18,18,18,18,55,55,18,18,18],
- [18,18,18,17,17,17,17,17,17,17,17,17,55,55,17,17,18],
- [18,18,17,17,17,17,18,18,17,17,17,17,55,55,17,17,18],
- [18,17,17,17,18,18,18,18,18,17,17,55,55,17,17,17,18],
- [18,17,17,18,22,23,23,23,24,18,17,55,55,17,17,17,18],
- [18,17,17,18,25,28,26,79,27,18,55,55,17,17,17,17,18],
- [18,17,17,17,17,10,11,12,18,18,55,55,17,17,17,17,18],
- [18,18,17,17,10,16,16,16,11,55,55,17,17,17,17,17,18],
- [18,18,17,17,77,16,16,16,16,21,21,17,17,17,17,17,18],
- [18,18,17,17,77,16,16,16,16,55,55,17,17,17,17,17,18],
- [18,18,18,18,18,18,18,18,18,55,55,18,18,18,18,18,18]],
- mapdata:[
- [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
- [1,1,1,0,0,0,0,0,0,0,0,0,1,1,0,0,1],
- [1,1,0,0,0,0,1,1,0,0,0,0,1,1,0,0,1],
- [1,0,0,0,1,1,1,1,1,0,0,1,1,0,0,0,1],
- [1,0,0,1,1,1,1,1,1,1,0,1,1,0,0,0,1],
- [1,0,0,1,1,1,0,1,1,1,1,1,0,0,0,0,1],
- [1,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,1],
- [1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,1],
- [1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
- [1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,1],
- [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]],
- add:[
- {chara:"player",img:"mingren",x:5,y:6},
- {chara:"npc",img:"npc1",x:7,y:6},
- {chara:"npc",img:"npc1",x:3,y:3}],
- talk:{
- talk1:[
- {img:"m",name:"鸣人",msg:"我是木叶村的鸣人,你是谁?"},
- {img:"n",name:"黑衣忍者甲",msg:"你就是鸣人?九尾还在你身体里吗?"}
- ],
- talk2:[
- {img:"n",name:"黑衣忍者乙",msg:"鸣人,听说忍者大战就要开始了。"},
- {img:"m",name:"鸣人",msg:"真的吗?一定要想想办法啊。"}
- ]
- }
- }
-
-
- };
我将脚本定义成了变量,实际游戏制作的时候,脚本应该储存到一个外部文档当中,在这里我只是讲解一下理论,如何完善那是后话了。
可以看到,json中,包含了地图相关的map数组和mapdata数组,添加人物的相关数据,以及对话的数组。这样,我在游戏显示的时候,只需要读入json数据,然后根据这些内容来显示游戏画面就可以了,定义一个initScript函数来进行这些操作。
- function initScript(){
- //地图位置初始化
- mapLayer.x = 0;
- mapLayer.y = 0;
-
-
- //地图层初始化
- mapLayer.removeAllChild();
- //人物层初始化
- charaLayer.removeAllChild();
- //效果层初始化
- effectLayer.removeAllChild();
- //对话层初始化
- talkLayer.removeAllChild();
-
- //地图数据获取
- map = stage.map;
- mapdata = stage.mapdata;
- //对话数据获取
- talkScriptList = stage.talk;
-
- //添加地图
- addMap(0,0);
- delMap();
- //添加人物
- addChara();
- }
removeAllChild方法是legendForHtml5Programming引擎独有的方法,可以用来移出LScript显示层上的所有子对象,从而实现本游戏中各个显示层的初始化工作。
修改一下addChara方法,如下
- //添加人物
- function addChara(){
- var charaList = stage.add;
- var chara,charaObj;
- for(var i=0;i
- charaObj = charaList[i];
- if(charaObj.chara == "player"){
- //加入英雄
- bitmapdata = new LBitmapData(imglist[charaObj.img]);
- chara = new Character(true,i,bitmapdata,4,4);
- player = chara;
- }else{
- //加入npc
- bitmapdata = new LBitmapData(imglist[charaObj.img]);
- chara = new Character(false,i,bitmapdata,4,4);
- }
- chara.x = charaObj.x * 32;
- chara.y = charaObj.y * 32;
- charaLayer.addChild(chara);
- }
- }
即,根据json脚本中的add数组,来添加游戏中的人物。
好了,运行一下游戏,可以看到,游戏正常显示了,和之前一模一样,实现了同样的功能。
四,利用游戏脚本实现地图的切换
为了让大家看到游戏脚本的便利性,现在利用脚本实现游戏中的场景切换。
将json脚本修改如下
- var script = {
- stage01:{
- map:[
- [18,18,18,18,18,18,18,18,18,18,18,18,55,55,18,18,18],
- [18,18,18,17,17,17,17,17,17,17,17,17,55,55,17,17,18],
- [18,18,17,17,17,17,18,18,17,17,17,17,55,55,17,17,18],
- [18,17,17,17,18,18,18,18,18,17,17,55,55,17,17,17,18],
- [18,17,17,18,22,23,23,23,24,18,17,55,55,17,17,17,18],
- [18,17,17,18,25,28,26,79,27,18,55,55,17,17,17,17,18],
- [18,17,17,17,17,10,11,12,18,18,55,55,17,17,17,17,18],
- [18,18,17,17,10,16,16,16,11,55,55,17,17,17,17,17,18],
- [18,18,17,17,77,16,16,16,16,21,21,17,17,17,17,17,18],
- [18,18,17,17,77,16,16,16,16,55,55,17,17,17,17,17,18],
- [18,18,18,18,18,18,18,18,18,55,55,18,18,18,18,18,18]],
- mapdata:[
- [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
- [1,1,1,0,0,0,0,0,0,0,0,0,1,1,0,0,1],
- [1,1,0,0,0,0,1,1,0,0,0,0,1,1,0,0,1],
- [1,0,0,0,1,1,1,1,1,0,0,1,1,0,0,0,1],
- [1,0,0,1,1,1,1,1,1,1,0,1,1,0,0,0,1],
- [1,0,0,1,1,1,0,1,1,1,1,1,0,0,0,0,1],
- [1,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,1],
- [1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,1],
- [1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
- [1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,1],
- [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]],
- add:[
- {chara:"player",img:"mingren",x:5,y:6},
- {chara:"npc",img:"npc1",x:7,y:6},
- {chara:"npc",img:"npc1",x:3,y:3}],
- talk:{
- talk1:[
- {img:"m",name:"鸣人",msg:"我是木叶村的鸣人,你是谁?"},
- {img:"n",name:"黑衣忍者甲",msg:"你就是鸣人?九尾还在你身体里吗?"}
- ],
- talk2:[
- {img:"n",name:"黑衣忍者乙",msg:"鸣人,听说忍者大战就要开始了。"},
- {img:"m",name:"鸣人",msg:"真的吗?一定要想想办法啊。"}
- ]
- },
- jump:[
- {at:{x:6,y:5},to:"stage02"}
- ]
- },
- stage02:{
- map:[
- [0,0,1,2,2,2,2,2,2,2,2,1,0,0,0],
- [0,0,1,3,5,5,1,5,5,5,5,1,0,0,0],
- [0,0,1,80,4,4,1,80,4,4,4,1,0,0,0],
- [0,0,1,80,4,4,1,80,8,7,8,1,0,0,0],
- [0,0,1,80,4,4,5,81,4,4,4,1,0,0,0],
- [0,0,1,2,2,2,6,4,4,4,4,1,0,0,0],
- [0,0,1,3,5,5,81,4,4,4,4,1,0,0,0],
- [0,0,1,80,4,4,4,4,4,4,9,1,0,0,0],
- [0,0,1,2,2,2,2,6,2,2,2,1,0,0,0]],
- mapdata:[
- [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
- [1,1,1,0,0,0,1,0,0,0,0,1,1,1,1],
- [1,1,1,0,0,0,1,0,0,0,0,1,1,1,1],
- [1,1,1,0,0,0,1,0,0,1,0,1,1,1,1],
- [1,1,1,0,0,0,0,0,0,0,0,1,1,1,1],
- [1,1,1,1,1,1,0,0,0,0,0,1,1,1,1],
- [1,1,1,0,0,0,0,0,0,0,0,1,1,1,1],
- [1,1,1,0,0,0,0,0,0,0,1,1,1,1,1],
- [1,1,1,1,1,1,1,0,1,1,1,1,1,1,1]],
- add:[
- {chara:"player",img:"mingren",x:7,y:8},
- {chara:"npc",img:"npc1",x:8,y:3},
- {chara:"npc",img:"npc1",x:10,y:3}],
- talk:{
- talk1:[
- {img:"m",name:"鸣人",msg:"你们在干什么啊?"},
- {img:"n",name:"黑衣忍者甲",msg:"我们在喝茶。"}
- ],
- talk2:[
- {img:"n",name:"黑衣忍者乙",msg:"我们在喝茶,你不要打扰我们。"},
- {img:"m",name:"鸣人",msg:"....."}
- ]
- },
- jump:[
- {at:{x:7,y:8},to:"stage01"}
- ]
- }
-
-
- };
可以看到,我添加了stage02,即第二个场景,并且在脚本里引入了jump节点来控制游戏场景的切换,其中jump中的at表示游戏主人公移动到达的坐标,to表示到达这个坐标后跳转到的画面名称。这里的jump之所以是数组,是因为一个场景也可以跳转到其他多个场景。
上面的脚本实现了stage01和stage02两个场景的互相跳转。
为了读取这个jump,以及实现跳转,我们需要在游戏主人公移动一个步长之后,判断一下是否应该跳转了,修改Character类的onmove方法
- /**
- * 开始移动
- **/
- Character.prototype.onmove = function (){
- var self = this;
- //设定一个移动步长中的移动次数
- var ml_cnt = 4;
- //计算一次移动的长度
- var ml = STEP/ml_cnt;
- //根据移动方向,开始移动
- switch (self.direction){
- case UP:
- if(mapmove){
- mapLayer.y += ml;
- charaLayer.y += ml;
- }
- self.y -= ml;
- break;
- case LEFT:
- if(mapmove){
- mapLayer.x += ml;
- charaLayer.x += ml;
- }
- self.x -= ml;
- break;
- case RIGHT:
- if(mapmove){
- mapLayer.x -= ml;
- charaLayer.x -= ml;
- }
- self.x += ml;
- break;
- case DOWN:
- if(mapmove){
- mapLayer.y -= ml;
- charaLayer.y -= ml;
- }
- self.y += ml;
- break;
- }
- self.moveIndex++;
- //当移动次数等于设定的次数,开始判断是否继续移动
- if(self.moveIndex >= ml_cnt){
- //一个地图步长移动完成后,判断地图是否跳转
- if(self.isHero && self.moveIndex > 0)checkJump();
- self.moveIndex = 0;
- //一个地图步长移动完成后,如果地图处于滚动状态,则移除多余地图块
- if(mapmove)delMap();
- //如果已经松开移动键,或者前方为障碍物,则停止移动,否则继续移动
- if(!isKeyDown || !self.checkRoad()){
- self.move = false;
- return;
- }else if(self.direction != self.direction_next){
- self.direction = self.direction_next;
- self.anime.setAction(self.direction);
- }
- //地图是否滚动
- self.checkMap(self.direction);
- }
- };
- if(self.isHero && self.moveIndex > 0)checkJump();
表示,移动完后如果该人物是游戏主人公则进行跳转判断
所以,我们需要添加一个checkJump方法
- //游戏场景跳转测试
- function checkJump(){
- var jump = stage.jump;
- var jumpstage;
- for(var i=0;i
- jumpstage = jump[0];
- if(player.x == jumpstage.at.x * 32 && player.y == jumpstage.at.y * 32){
- //获取该场景脚本数据
- stage = script[jumpstage.to];
- //开始跳转
- initScript(stage);
- return;
- }
- }
- }
好了,一切都很简单吧,运行游戏看看效果吧,小鸣人走到地图的小房门的部分是,场景发生跳转
游戏测试URL:
http://fsanguo.comoj.com/html5/rpg5/index.html
本次更新源代码下载:
http://legend-demo.googlecode.com/files/rpg5.zip

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

Video Face Swap
完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック











uniapp がミニ プログラムと H5 の間で迅速な変換を実現するには、具体的なコード例が必要ですが、近年、モバイル インターネットの発展とスマートフォンの普及に伴い、ミニ プログラムと H5 は不可欠なアプリケーション形式となっています。クロスプラットフォーム開発フレームワークとして、uniapp は一連のコードに基づいて小規模プログラムと H5 間の変換を迅速に実現し、開発効率を大幅に向上させます。この記事では、uniapp がミニ プログラムと H5 の間で迅速な変換を実現する方法と、具体的なコード例を紹介します。 1. uniapp uniaの紹介

Windows 101909 は現在、最も安定しており信頼できるバージョンの 1 つと考えられていますが、残念ながら、このバージョンのサービス サポートは最近終了しました。 21H2 は比較的安定したバージョンであり、実際の状況からすると、どちらも非常に良い選択です。 win101909 と 21h2 のどちらが優れていますか? 回答: 1909 の方が安定しており、21h2 の方が安全です。現在の環境では、1909 は依然として最も安定しており信頼できるバージョンの 1 つであると一般に考えられています。ただし、Win101909 バージョンは、2021 年 5 月 11 日に正式にサービスの提供を停止しました。WindowsServer21h2 は、大多数のユーザーに、より専門的な IT 機能のサポートを提供することに取り組んでいます。 1. 多くのユーザーによる実際のテストの後、

win1121h2 と 22h2 の 2 つのバージョンを比較すると、後者の 22h2 の方が安定しており、22h2 の方が機能が多く、前の 21h2 と比べて多くの機能が改善されています。 win1121h2 と 22h2 はどちらの方が安定していますか: 回答: 22h2 の方が安定しています win1121h2 と 22h2 を比較すると、22h2 の方が安定しています。 22h2では多くの機能が追加されており、21h2の問題点も22h2では改善されています。 22h2 アップデート機能: スタート メニューのアプリケーション フォルダー。 [スタート] メニューの調整可能な固定領域。タスクバーにドラッグアンドドロップします。フォーカス アシストは通知センターと統合されています。新しい「スポットライト」壁紙機能。新しい

該当するシナリオ: 1. プロジェクトの規模が大きくない 2. ユーザー数があまり多くなく、同時実行性の要件がそれほど強くない 3. 専任の運用保守要員が存在しない 4. チームの規模が絶妙である通常のプロジェクト、または企業の責任分担が明確ではない部門。多くの場合、システムは要件から設計、開発、テスト、そして最終的な立ち上げ、運用、保守へと進みます。多くの場合、タスクの 80% は開発チームによって完了されます。したがって、開発者はシステムの機能を実装するだけでなく、顧客の相談に応じ、質問に答え、生産上の問題を解決する必要もあります。想像してみてください。アプリケーションが起動された後は、監視手段が何もありません。ダッシュボードのない車を運転するのと同じように、このような道路では誰も安全を感じません。シンプルさと効率性のバランスをどう取るかは、考える価値のあることです。 1.スプリングブ

Windows 11 システムの 23h2 バージョンと 22h2 バージョンは、それぞれ 2023 年と 2022 年にリリースされる予定です。一般的に、システム アップデートはますます改善されています。編集者も、23h2 バージョンは 22h2 バージョンよりも優れていると考えています。 win1123h2 と 22h2 のどちらが優れていますか? 回答: win1123h2 の方が優れています。報告によると、win1123h2 は 22h2 から次のバージョンへの累積的なバージョン アップデートであり、プラットフォームはすべて同じです。これは、2 つのバージョン間に互換性の問題がないことを意味するため、適時に更新することをお勧めします。 win1123h2 バージョンでは、タスクバー ウィンドウ アプリケーションのマージ禁止モードなど、多くの実用的な機能が提供されます。他にもあります

最近、誰もが Win11 の 23H2 バージョンにアップデートしたいと考えていますが、少数のユーザーがアップデートのプッシュ メッセージをまだ受け取っていません。バックグラウンドでのアップデートの進行中のプロセスが停止している可能性があり、しばらくすると正常になります。 Win11 アップデートが 23H2 を取得できない場合の対処方法. 方法 1: 辛抱強く待つ. ユーザーがコンピューターのアップデート ステータスを確認し、スタックしていることがわかった場合は、しばらく待つことができ、システムはアップデートを続行します。方法 2: 更新されたキャッシュをクリアします。ユーザーが以前にシステムを更新していて、より詳細なキャッシュをクリアしていない場合は、23h2 の通常の更新に影響します。手動でクリアできます。方法 3: イメージ インストールを使用する Microsoft の公式 Web サイトにアクセスして win1123h2 のイメージ ファイルをダウンロードし、ファイルを更新することをお勧めします。

このファイルを変更するには、管理者から提供されたアクセス許可が必要です。解決策: 1. ログイン インターフェイスで管理者アカウントを選択し、パスワードを入力すると、ファイルをスムーズに変更できます。2. ファイルを右クリックして、 「管理者として」の解決策: 3. ファイルのアクセス許可を変更し、ファイルを右クリックして「プロパティ」を選択し、「セキュリティ」タブをクリックして「編集」ボタンをクリックし、ユーザー名を選択して「フル コントロール」にチェックを入れます。オプション ; 4. コマンド プロンプトを使用して問題を解決します; 5. UA 権限を設定します。
