幻想森林

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 5015|回复: 15

[TJS][伪翻译]面向对象的思路实现一个游戏

[复制链接]

136

主题

1751

帖子

548

积分

版主

Rank: 7Rank: 7Rank: 7

积分
548
发表于 2007-5-17 21:43:22 | 显示全部楼层 |阅读模式
整理硬盘时发现的。还是去年对krkr着迷的时候做的,我来翻译,当然是不准确,随意翻的,错误很多,而且还有很多地方没有翻。
更全面,更详细的还是看原文吧。(在二楼)
原文似乎是来自tjs primer.chm中的。
  1. 思路
  2. 大体的思路,使用3个类,游戏窗口类,游戏主类,鼹鼠类。类的说明如下:
  3. 类           作用                                    备注
  4. 游戏窗口类   窗口显示,菜单显示,剩余时间显示          从window类继承
  5. 游戏主体类   游戏流程控制:得分管理,鼹鼠的管理
  6. 鼹鼠类       鼹鼠图像的显示,声效的播放,鼠标事件处理  从Layer类继承
  7. 构架游戏窗口类的骨架
  8. ///////////////////////////////////////////////////////////////////////
  9. // 游戏窗口类
  10. class GameWindow extends Window
  11. {
  12.   var file_menu;   //文件菜单
  13.   var start_menu;  //游戏开始菜单
  14.   var exit_menu;   //结束菜单
  15.   var master;      //游戏主体
  16.   //游戏窗口
  17.   function GameWindow()
  18.   {
  19.     super.Window();  // 从window类继承
  20.   }
  21.   //销毁资源
  22.   function finalize()
  23.   {
  24.     super.finalize();  //从上面继承
  25.   }
  26.   // 菜单选择后的响应动作action()
  27.   function action(ev)
  28.   {
  29.   //暂时还没有
  30.   }
  31. }
  32. // 从游戏窗口类创建一个实例
  33. var win = new GameWindow();
  34. //////////////////////////////////////////////////////////////////////
  35. tjs中的window类原本都是不带菜单的。所以要加入菜单才能做成我们所需要的窗口类。
  36. 类中声明的变量的说明:
  37. 变量         作用             备注
  38. file_menu    生成“文件”菜单
  39. start_menu   文件-游戏开始
  40. exit_menu    文件-关闭
  41. master       游戏主体对象     在后面说明
  42. 构建游戏主体类的骨架
  43. 要注意时间类和时间事件的处理,时间1的作用是空控制鼹鼠的活动和得点的更新,时间2的作用是更新剩余时间。
  44. 一个时间类就够了,具体的判断分成两个部分。
  45. /////////////////////////////////////////////////////
  46. //游戏主体类(管理鼹鼠对象)
  47. class GemeMaster
  48. {
  49.   var window;      //游戏窗口类
  50.   var parent;      //父层,游戏窗口的主层
  51.   var fore;        //父层的副本
  52.   var moles = [];  //鼹鼠对像数组
  53.   var timer1;      // 时间1:鼹鼠类用
  54.   var timer2;      // 时间2:剩余时间用
  55.   var rest_time;   // 剩余时间
  56.   var point;       // 得点
  57. //游戏主体类的主函数
  58.   function GemeMaster(win, par) { }
  59. //销毁资源
  60.   function finalize() { }
  61. //游戏开始
  62.   function start() { }
  63. //游戏结束
  64.   function stop() { }
  65. //时间事件处理:鼹鼠的活动
  66.   function onTimer1() { }
  67. //时间事件处理:剩余时间更新
  68.   function onTimer2() { }
  69. }
  70. /////////////////////////////////////////////////
  71. 构建鼹鼠类的骨架
  72. 鼹鼠类是从layer类继承。layer类的作用是图片的显示\不显示,以及鼠标事件的处理。
  73. 鼹鼠类中需要用到intrandom()函数,这个函数在kag3\template\system\Util.tjs中
  74. ///////////////////////////////////////////////////////
  75. //从Util.tjs中引入intrandom()函数
  76. function intrandom(min = 0, max = 0)
  77. {
  78.   //返回min以上max以下的整数随机数
  79.   //参数是一个的时侯,返会0到这个数字之间的随机数
  80.   if(min>max) { min <-> max; }
  81.   return int(Math.random() * (max-min+1)) + min;
  82. }
  83. //鼹鼠类
  84. class Mole extends Layer
  85. {
  86.   var master;        //游戏主体类
  87.   var hit_sound;     //敲击的效果音
  88.   var counter;       //事件的次数(-hidden_time~visible_time)
  89.   var hidden_time;   //隐藏的时间
  90.   var visible_time;  //出现的时间
  91.   function Mole(gm, window, parent)  //主函数
  92.   {
  93.     super.Layer(window, parent);  //从layer类继承
  94.   }
  95.   function finalize()  // 销毁资源
  96.   {
  97.     super.finalize();  //从上级继承
  98.   }
  99.   function reset() { }  // 重设参数
  100.   function move()  { }  // 鼹鼠的图片显示不显示的切换
  101.   function onMouseDown(x, y, button, shift) { }  //鼠标事件的处理
  102. }
  103. ////////////////////////////////////////////////////////////
  104. 成员变量的说明:
  105. 变量           说明                               备注
  106. master        游戏主体类
  107. hit_sound     WaveSoundBuffer对象,效果音
  108. counter       时间事件的计次  
  109.               从hidden_time到visible_time之间变化
  110.               负数,不显示鼹鼠
  111.               0以上为显示  
  112. hidden_time   鼹鼠隐藏的时间,由reset()随机设置    单位是时间事件的次数
  113. visible_time  鼹鼠出现的时间。由reset()随机设置    同上
  114. 游戏窗口类中的,主函数和销毁函数的实装
  115. ////////////////////////////////////////////////////////
  116. //主函数
  117. function GameWindow()
  118. {
  119.   super.Window();  // 继承一个窗口类
  120.   // 生成[文件]、[文件-游戏开始]、[文件-结束]
  121.   menu.add(file_menu = new MenuItem(this, "文件(&F)"));
  122.   file_menu.add(start_menu = new MenuItem(this, "游戏开始(&S)"));
  123.   file_menu.add(exit_menu = new MenuItem(this, "结束(&C)"));
  124.   // 创建主层,登陆游戏主窗口
  125.   add(new Layer(this, null));
  126.   with (primaryLayer)
  127.   {
  128.     //载入背景图像,及其尺寸
  129.     .loadImages("stage");
  130.     .setSizeToImageSize();
  131.   }
  132.   //游戏窗口的大小和主层抱持一致
  133.   setInnerSize(primaryLayer.width, primaryLayer.height);
  134.   caption = "打鼹鼠游戏";  //设置游戏窗口的标题
  135.   visible = true;          //游戏窗口为可见
  136.   //创建游戏主体类
  137.   master = new GemeMaster(this, primaryLayer);
  138. }
  139. //销毁函数
  140. function finalize()
  141. {
  142. //游戏主体类无效化
  143.   invalidate master;
  144. //菜单无效化
  145.   invalidate exit_menu;
  146.   invalidate start_menu;
  147.   invalidate file_menu;
  148.   super.finalize();  //继承一个
  149. }
  150. ////////////////////////////////////////////////////////
  151. 主函数的说明
  152. 1.一开始是创建菜单对像。创建了三个菜单。
  153.   以后选择菜单的时后,就用到后面说的action()函数。
  154. 2.接着创建了主层。用add()来登陆游戏窗口自身。
  155.   以后主层就可以以primarylayer的属性和访问。
  156. 3.主层读入了背景图片。后面会用到缓冲层。
  157. 4.最好创建了游戏主体类,这个类里包括了窗口类和主层类。
  158. 以下是类的继承关系
  159. krkr2  Window类        方法add()、setInnerSize()
  160.                        属性caption、visible
  161.        MenuItem类      主函数
  162.                        方法add()
  163.        Layer类         主函数
  164.                        方法loadImages()、SetSizeToImageSize()
  165.                        属性width、height
  166. 主层创建的参数是null,即什么都不显示
  167. 实装游戏窗口类的“方法”action()
  168. 参数ev是一个枚举类型的对象。传递按键type事件的种类,按键target事件
  169. //菜单选择处理的action()方法
  170. function action(ev)
  171. {
  172.   if (ev.type == "onClick")
  173.   {
  174.     switch (ev.target) {
  175.       case start_menu:  //当选择了[ゲーム開始]菜单
  176.         master.start(); //游戏开始
  177.         break;
  178.       case exit_menu:   //当选择了[閉じる]菜单
  179.         close();
  180.     }
  181.   }
  182. }
  183. 事件的类型是onClick,事件发生后,处理start_menuかexit_menu
  184. action()方法的具体资料,参看「吉里吉里2リファレンス」的「イベントシステム」
  185. 实装游戏主体类中的主函数和销毁函数
  186. /////////////////////////////////////////////
  187. //主函数
  188. function GemeMaster(win, par)
  189. {
  190.   window = win;
  191.   parent = par;
  192.   // 创建亲层的副本
  193.   fore = new Layer(win, par);
  194.   with (fore)
  195.   {
  196.     .visible = true;
  197.     .assignImages(parent);
  198.     .setSizeToImageSize();
  199.     //设定字体
  200.     .font.height = 30;
  201.    }
  202.   //创建三个鼹鼠对象
  203.   moles.add(new Mole(this, window, fore));
  204.   moles.add(new Mole(this, window, fore));
  205.   moles.add(new Mole(this, window, fore));
  206.   //鼹鼠的位置
  207.   moles[0].top  = 100;
  208.   moles[0].left =  50;
  209.   moles[1].top  = 100;
  210.   moles[1].left = 250;
  211.   moles[2].top  = 100;
  212.   moles[2].left = 450;
  213.   //鼹鼠用的时间对象
  214.   timer1 = new Timer(onTimer1, "");
  215.   timer1.interval = 100;  // 100ms间隔
  216.   //创建剩余时间用的时间类
  217.   timer2 = new Timer(onTimer2, "");
  218.   timer2.interval = 1000;  //1000ms间隔
  219. }
  220. //销毁函数
  221. function finalize()
  222. {
  223.   //时间类无效化
  224.   invalidate timer2;
  225.   invalidate timer1;
  226.   //鼹鼠对象无效化
  227.   for (var i = 0; i < moles.count; i++)
  228.   {
  229.     invalidate moles[i];
  230.   }
  231.   // 主层副本无效化
  232.   invalidate fore;
  233. }
  234. /////////////////////////////////////////////////////////
  235. 1.亲层副本,用来缓冲用
  236. 2.创建了鼹鼠对象,并设定了其位置
  237. 3.两个时间对象
  238. 吉里吉里2   Layer类         方法assignImages()
  239.                             属性visible、font、top、left
  240.             Font类          属性height
  241.             Timer类         主函数
  242.                             属性interval
  243. 对于有父子关系的层,如果没有特别的限定,那么父层在里面,子层在前面。这个例子里面的顺序从里到外是,主层,主层副本,鼹鼠。
  244. 实装游戏主体类中的方法 start()和stop()
  245. ///////////////////////////////////////////////////////////
  246. //游戏开始
  247. function start()
  248. {
  249.   point = 0;
  250.   rest_time = 20;
  251.   timer1.enabled = timer2.enabled = true;
  252. }
  253. //游戏结束
  254. function stop()
  255. {
  256.   timer1.enabled = timer2.enabled = false;
  257. }
  258. ///////////////////////////////////////////////////////////
  259. 用到了timer类的一个属性enabled
  260. 实装游戏主体类的方法onTimer1()、onTimer2()
  261. //////////////////////////////////////////
  262. //鼹鼠的活动
  263. function onTimer1()
  264. {
  265. //让鼹鼠活动
  266.   for (var i = 0; i < moles.count; i++) {
  267.     moles[i].move();
  268.   }
  269. //更新得点
  270.   with (fore)
  271.   {
  272.     .copyRect(500, 0, parent, 500, 0, 160, 30);
  273.     .drawText(500, 0, "得点:"+point, 0x000000);
  274.   }
  275. }
  276. //更新剩余时间
  277. function onTimer2()
  278. {
  279.   //更新剩余时间
  280.   with (fore)
  281.   {
  282.     .copyRect(0, 0, parent, 0, 0, 160, 30);
  283.     .drawText(0, 0, "残り時間:"+(rest_time--), 0x000000);
  284.   }
  285.   if (rest_time < 0) {
  286.     stop();
  287.   }
  288. }
  289. //////////////////////////////////////////////////////
  290. copyRect()复制了主层的一部分图像。drawText()是在指定坐标画文字。如果原来有文字,自动覆盖以前的。没有比要特意去消。
  291. 用到了layer类中的方法copyRect()和drawText()
  292. 实装鼹鼠类中的主函数和销毁函数
  293. 主函数中的参数parent,不是指向游戏窗口类的主层,而是指向游戏主体类的fore类。
  294. ///////////////////////////////////////////////////////////
  295. //主函数
  296. function Mole(gm, window, parent)
  297. {
  298.   super.Layer(window, parent);  // 继承
  299.   master = gm;
  300.   //读入声效
  301.   hit_sound = new WaveSoundBuffer(window);
  302.   hit_sound.open("hit.wav");  // ←拡張子もつけないとダメらしい
  303.   // 获取鼠标事件
  304.   hitType = htMask;
  305.   hitThreshold = 0;
  306.   //读入鼹鼠的图像,并设置层的大小为图像大。
  307.   loadImages("mole");
  308.   setSizeToImageSize();
  309. }
  310. //销毁
  311. function finalize()
  312. {
  313.   invalidate hit_sound;
  314.   super.finalize();  // 继承
  315. }
  316. ////////////////////////////////////////////
  317. 1.创建WaveSoundBuffer对象,读入效果音
  318. 2.设定鼹鼠自身:读入图像,鼠标事件
  319. WaveSoundBuffer类   主函数
  320.                     方法open()
  321. Layer类             属性hitType、hitThreshold
  322. 实装鼹鼠类中的方法reset()、move()
  323. ///////////////////////////////////////////////////////
  324. // 重设参数
  325. function reset()
  326. {
  327.   visible = false;  // 不显示
  328.   var interval = master.timer1.interval;
  329.   // 隐藏的时间是1~5秒
  330.   hidden_time = intrandom(1*1000\interval, 5*1000\interval);
  331.   // 显示的时间是0.5~2秒
  332.   visible_time = intrandom(1\2*1000\interval, 2*1000\interval);
  333.   counter = -hidden_time;
  334. }
  335. // 鼹鼠是显示还是不显示
  336. function move()
  337. {
  338.   if (counter > visible_time) {  // 当counter比time大时
  339.     reset();
  340.   }
  341.   else {
  342.     if (counter == 0) {  // 当counter为0、或以上,显示鼹鼠
  343.       visible = true;
  344.     }
  345.     counter++;
  346.   }
  347. }
  348. //////////////////////////////////////////////
  349. 方法reset(),随机决定显示隐藏。方法move(),决定鼹鼠的显示。counter为负数,不显示。0以上为显示。
  350. 实装鼹鼠类中的方法onMouseDown()
  351. 参数button传递鼠标点击的消息。
  352. //处理鼠标事件
  353. function onMouseDown(x, y, button, shift)
  354. {
  355.   if (button == mbLeft && visible) {  //在鼹鼠显示中按下了左键
  356.     hit_sound.play();  // 效果音
  357.     master.point++;    // 增加得点
  358.     reset();
  359.   }
  360. }
  361. ////////////////////////////////////////////////////
  362. 鼹鼠显示中,在鼹鼠上点左键,播放效果音,增加得点。然后呼叫方法reset(),重新进人不显示的状态。
  363. WaveSoundBuffer类        方法play()
  364. Layer类                  方法onMouseDown()
复制代码
え~え~お!!!
回复

使用道具 举报

136

主题

1751

帖子

548

积分

版主

Rank: 7Rank: 7Rank: 7

积分
548
 楼主| 发表于 2007-5-17 21:44:02 | 显示全部楼层
原文,复制过来格式上有点乱
[code]
実装
方針
大まかな方針として、ゲームウィンドウクラス、ゲームマスタークラス、モグラクラスの3つに分けることにします。それぞれのクラスの役割は以下の通りです。

クラス
役割
備考

ゲームウィンドウクラス
ウィンドウの表示、メニューの表示、残り時間の表示
Windowクラスを継承

ゲームマスタークラス
ゲームの進行役:得点の管理、モグラの管理を行う
  

モグラクラス
モグラ(の画像)の表示、マウスイベントの処理、効果音の再生
Layerクラスを継承




骨組みの実装:ゲームウィンドウクラス
まずは骨組みを実装してみましょう。メソッドの中身は徐々に実装していきます。最初はゲームウィンドウクラスの骨組みです。

// ゲームウィンドウクラス

class GameWindow extends Window

{

  var file_menu;   // ファイルメニュー

  var start_menu;  // ゲーム開始メニュー

  var exit_menu;   // 終了メニュー



  var master;      // ゲームマスター



  // コンストラクタ

  function GameWindow()

  {

    super.Window();  // スーパークラスのコンストラクタを呼び出す

  }



  // デストラクタ

  function finalize()

  {

    super.finalize();  // スーパークラスのデストラクタを呼び出す

  }



  // メニュー選択を処理するaction()メソッド

  function action(ev) { }

}



// ゲームウィンドウオブジェクトを作成

var win = new GameWindow();


?謦幞渐氓蒩ction()の説明は、「吉里吉里2リファレンス」の「イベントシステム」を参照してください。MenuItemオブジェクトがaction()メソッドを呼び出すとは明記されていませんが、同梱のTJSサンプル(viewerなど)から、それが推測できます。□

Windowクラスのオブジェクトは、それ単体ではメニューなどを一切持っていません。そこで、Windowクラスを継承し、必要なメニューなどを加えたゲームウィンドウクラスを作成するのです。

メンバ変数は次のように使うことにします。

メンバ変数
役割
備考

file_menu
[ファイル]メニューを作る
  

start_menu
[ファイル‐ゲーム開始]メニューを作る
  

exit_menu
[ファイル‐閉じる]メニューを作る
  

master
ゲームマスターオブジェクト
後述




骨組みの実装:ゲームマスタークラス
次はゲームマスタークラスの骨組みです。タイマーオブジェクトと、タイマーイベントを処理するメソッドが2つずつあることに注意してください。タイマー1の役割は、モグラを動かし、得点を更新することです。また、タイマー2の役割は、残り時間を更新することです。

■1つのタイマーオブジェクトでも事足りますが、判りやすくするために2つに分けています。□

// ゲームマスタークラス(モグラオブジェクトの管理などを行う)

class GemeMaster

{

  var window;      // ゲームウィンドウオブジェクト

  var parent;      // 親レイヤー:(ゲームウィンドウの)プライマリレイヤー

  var fore;        // 親レイヤーのコピー:表画面として使う

  var moles = [];  // モグラオブジェクトの配列

  var timer1;      // タイマー1:モグラ用

  var timer2;      // タイマー2:残り時間用



  var rest_time;   // 残り時間

  var point;       // 得点



  // コンストラクタ

  function GemeMaster(win, par) { }



  // デストラクタ

  function finalize() { }



  // ゲームを開始

  function start() { }



  // ゲームを終了

  function stop() { }



  // タイマーイベントを処理:モグラを動かす

  function onTimer1() { }



  // タイマーイベントを処理:残り時間を更新する

  function onTimer2() { }

}




骨組みの実装:モグラクラス
最後にモグラクラスの骨組みです。モグラクラスはレイヤークラスを継承します。もちろん、現実のモグラがレイヤーを継承することなどあり得ません。レイヤーの持つ機能――画像の表示・非表示やマウスイベントの処理――を特化し、ゲーム用のモグラに仕立てているだけです。モグラクラスではonMouseDown()メソッドをオーバーライドします。

モグラクラスではKAGの関数intrandom()を使います。この関数はKAGからしか使えないため、あらかじめkag3\\template\\system\\Util.tjsから該当コードをコピーしておきます。

■intrandom()では、いくつか説明していない演算子を使っていますが、各自で調べてみてください。□

// Util.tjsからintrandom()のコードを拝借

function intrandom(min = 0, max = 0)

{

  // min 以上 max 以下の整数の乱数を返す

  // 引数が一個だけの場合は 0 ~ その数までの整数を返す

  if(min>max) { min <-> max; }

  return int(Math.random() * (max-min+1)) + min;

}



// モグラクラス(のスケルトンコード)

class Mole extends Layer

{

  var master;        // ゲームマスター

  var hit_sound;     // 叩かれたときの効果音

  var counter;       // イベントのカウンター(-hidden_time~visible_time)

  var hidden_time;   // 隠れている時間

  var visible_time;  // 出現している時間



  function Mole(gm, window, parent)  // コンストラクタ

  {

    super.Layer(window, parent);  // スーパークラスのコンストラクタを呼び出し

  }



  function finalize()  // デストラクタ

  {

    super.finalize();  // スーパークラスのデストラクタを呼び出し

  }



  function reset() { }  // パラメータを再設定

  function move()  { }  // モグラの画像を表示したり非表示したりする



  function onMouseDown(x, y, button, shift) { }  // マウスイベントを処理

}


メンバ変数は次のように使うことにします。

メンバ変数
説明
備考

master
ゲームマスターオブジェクト
  

hit_sound
WaveSoundBufferオブジェクト。モグラが叩かれたとき、効果音を鳴らす
  

counter
タイマーイベントのカウンター。-hidden_timeからvisible_timeの間で変化する。負ならモグラを非表示、0以上なら表示させる
  

hidden_time
モグラが隠れている時間。reset()が呼び出されるたびに乱数で設定
単位はタイマーイベントの回数

visible_time
モグラが出現している時間。reset()が呼び出されるたびに乱数で設定
同上




ゲームウィンドウクラス:コンストラクタ、デストラクタ
ゲームウィンドウクラスのコンストラクタ、デストラクタを実装します。

// コンストラクタ

function GameWindow()

{

  super.Window();  // スーパークラスのコンストラクタを呼び出す



  // [ファイル]、[ファイル‐ゲーム開始]、[ファイル‐閉じる]メニューを作成

  menu.add(file_menu = new MenuItem(this, "ファイル(&F)"));

  file_menu.add(start_menu = new MenuItem(this, "ゲーム開始(&S)"));

  file_menu.add(exit_menu = new MenuItem(this, "閉じる(&C)"));



  // プライマリレイヤーを作成し、ゲームウィンドウ自身に登録

  add(new Layer(this, null));

  with (primaryLayer)

  {

    // 背景画像を読み込み、そのサイズに設定

    .loadImages("stage");

    .setSizeToImageSize();

  }



  // ゲームウィンドウをプライマリレイヤーのサイズに合わせる

  setInnerSize(primaryLayer.width, primaryLayer.height);



  caption = "モグラ叩きゲーム";  // ゲームウィンドウのタイトルを設定

  visible = true;                // ゲームウィンドウを表示



  // ゲームマスターオブジェクトを作成

  master = new GemeMaster(this, primaryLayer);

}



// デストラクタ

function finalize()

{

  // ゲームマスターを無効化

  invalidate master;



  // メニューを無効化

  invalidate exit_menu;

  invalidate start_menu;

  invalidate file_menu;



  super.finalize();  // スーパークラスのデストラクタを呼び出す

}


デストラクタの説明は必要ないでしょうから、コンストラクタのみ説明します。

最初にメニューアイテムオブジェクトを作り、[ファイル]、[ファイル‐ゲーム開始]、[ファイル‐閉じる]メニューを作成しています。これらのメニューを選択したら、(後述の)メソッドaction()が呼ばれるようになります

次にプライマリレイヤーオブジェクトを作り、add()メソッドゲームウィンドウ自身に登録します。以降、プライマリレイヤーはprimaryLayerプロパティでアクセスできるようになります

プライマリレイヤーに背景画像などを読み込ませます。プライマリレイヤーは、後で裏画面として使います

最後にゲームマスターオブジェクトを作成します(引数はゲームウィンドウ自身とプライマリレイヤー)

以下のトピックも参照してください。

リファレンス
トピック
サブトピック

吉里吉里2リファレンス
Windowクラス
メソッドadd()、setInnerSize()

プロパティcaption、visible

MenuItemクラス
コンストラクタ

メソッドadd()

Layerクラス
コンストラクタ

メソッドloadImages()、SetSizeToImageSize()

プロパティwidth、height


プライマリレイヤーを作るときの引数nullは、「オブジェクトではあるが、何のオブジェクトも示していない」ことを示す、TJSのキーワードです。voidとは少し意味が異なります。



ゲームウィンドウクラス:メソッドaction()
ゲームウィンドウクラスのメソッドaction()を実装します。引数evは辞書オブジェクトで、キー"type"にイベントの種類が、キー"target"にイベントを発生させたオブジェクトが渡されます。

// メニュー選択を処理するaction()メソッド

function action(ev)

{

  if (ev.type == "onClick")

  {

    switch (ev.target) {

      case start_menu:  // [ゲーム開始]メニューを選択

        master.start();

        break;

      case exit_menu:   // [閉じる]メニューを選択

        close();

    }

  }

}


イベントの種類が"onClick"、イベント発生させたオブジェクトがstart_menuかexit_menuの場合のみ、処理します。

■メソッドaction()の詳細は、「吉里吉里2リファレンス」の「イベントシステム」を参照してください。□



ゲームマスタークラス:コンストラクタ、デストラクタ
ゲームマスタークラスのコンストラクタとデストラクタを実装します。

// コンストラクタ

function GemeMaster(win, par)

{

  window = win;

  parent = par;



  // 親レイヤーのコピーを作る

  fore = new Layer(win, par);

  with (fore)

  {

    .visible = true;

    .assignImages(parent);

    .setSizeToImageSize();



    // フォントの高さを30ピクセルに設定(残り時間、得点の文字に使う)

    .font.height = 30;

  }



  // モグラオブジェクトを作成

  moles.add(new Mole(this, window, fore));

  moles.add(new Mole(this, window, fore));

  moles.add(new Mole(this, window, fore));



  // モグラの表示位置を設定

  // (モグラの画像サイズによって調整してください)

  moles[0].top  = 100;

  moles[0].left =  50;

  moles[1].top  = 100;

  moles[1].left = 250;

  moles[2].top  = 100;

  moles[2].left = 450;



  // モグラ用タイマーオブジェクトを作成

  timer1 = new Timer(onTimer1, "");

  timer1.interval = 100;  // タイマーイベントは100ミリ秒間隔で発生



  // 残り時間用タイマーオブジェクトを作成

  timer2 = new Timer(onTimer2, "");

  timer2.interval = 1000;  // タイマーイベントを1秒間隔で発生させる

}



// デストラクタ

function finalize()

{

  // タイマーを無効化

  invalidate timer2;

  invalidate timer1;



  // モグラを無効化

  for (var i = 0; i < moles.count; i++) {

    invalidate moles;

  }



  // 表画面を無効化

  invalidate fore;

}


デストラクタの説明は必要ないでしょうから、コンストラクタのみ説明します。

親レイヤー(プライマリレイヤー)のコピーforeを作ります。以降、foreを表画面レイヤーとして扱い、モグラ、残り時間、得点の表示を行います。また、親レイヤーは裏画面として扱うことにします(後述)

モグラオブジェクトを作成し、表示する座標を設定します

タイマーオブジェクトを2つ作成します。timer1はモグラを動かすため、timer2は残り時間をカウントするためのタイマーです

以下のトピックも参照してください。

リファレンス
トピック
サブトピック

吉里吉里2リファレンス
Layerクラス
メソッドassignImages()

プロパティvisible、font、top、left

Fontクラス
プロパティheight

Timerクラス
コンストラクタ

プロパティinterval


親子関係を持つレイヤーは、特に指定しない限り、親レイヤーが奥、子レイヤーが手前に表示されます。今回のスクリプトでは、奥から順番にプライマリレイヤー、表画面レイヤー、モグラ(レイヤー)…となるようにします。



ゲームマスタークラス:メソッドstart()、stop()
ゲームマスタークラスのメソッドstart()とstop()を実装します。メソッドstart()では、得点や残り時間を設定し、タイマーを発生させています。メソッドstop()ではタイマーの発生を停止させます。

// ゲームを開始

function start()

{

  point = 0;

  rest_time = 20;

  timer1.enabled = timer2.enabled = true;

}



// ゲームを終了

function stop()

{

  timer1.enabled = timer2.enabled = false;

}


以下のトピックも参照してください。

リファレンス
トピック
サブトピック

吉里吉里2リファレンス
Timerクラス
プロパティenabled




ゲームマスタークラス:メソッドonTimer1()、onTimer2()
ゲームマスタークラスのメソッドonTimer1()、onTimer2()を実装します。

// タイマーイベントを処理:モグラを動かす

function onTimer1()

{

  // モグラを動かす

  for (var i = 0; i < moles.count; i++) {

    moles.move();

  }



  // 得点を更新する

  with (fore) {

    .copyRect(500, 0, parent, 500, 0, 160, 30);

    .drawText(500, 0, "得点:"+point, 0x000000);

  }

}



// タイマーイベントを処理:残り時間を更新する

function onTimer2()

{

  // 残り時間を更新する

  with (fore) {

    .copyRect(0, 0, parent, 0, 0, 160, 30);

    .drawText(0, 0, "残り時間:"+(rest_time--), 0x000000);

  }



  if (rest_time < 0) {

    stop();

  }

}


どちらのメソッドも、copyRect()で親レイヤー(プライマリレイヤー)の画像の一部をコピーしていることに注意してください。drawText()で同じ座標に文字を描くと、以前の文字が残ったまま上書きされてしまうので、あらかじめ消しておく必要があるのです。

以下のトピックも参照してください。

リファレンス
トピック
サブトピック

吉里吉里2リファレンス
Layerクラス
メソッドcopyRect()、drawText()


■copyRect()、drawText()への引数(左上端の座標、幅、高さ)は、背景画像ファイルのサイズに合わせて調整してください。このスクリプトでは640×480ピクセルの画像ファイルを想定しています。□

メンバ変数rest_timeは、メソッドonTimer2()が呼び出されるたびに-1され、負になった時点でメソッドstop()を呼び出します。

メンバ変数pointを変更するのはゲームマスターオブジェクトではありません。後述のモグラオブジェクトが値を変更します。



モグラクラス:コンストラクタ、デストラクタ
モグラクラスのコンストラクタ、デストラクタを実装します。

■コンストラクタ引数のparentには、ゲームウィンドウのプライマリレイヤーではなく、ゲームマスターのforeが渡されます(ゲームマスタークラスのコンストラクタを参照)。モグラクラスにとっての親レイヤー、と言う意味です。□

// コンストラクタ

function Mole(gm, window, parent)

{

  super.Layer(window, parent);  // スーパークラスのコンストラクタを呼び出し



  master = gm;



  // 効果音ファイルを読み込む

  hit_sound = new WaveSoundBuffer(window);

  hit_sound.open("hit.wav");  // ←拡張子もつけないとダメらしい



  // マウスイベントを受け取る

  hitType = htMask;

  hitThreshold = 0;



  // モグラの画像を読み込み、レイヤーのサイズを画像のそれと同じにする

  loadImages("mole");

  setSizeToImageSize();

}



// デストラクタ

function finalize()

{

  invalidate hit_sound;



  super.finalize();  // スーパークラスのデストラクタを呼び出し

}


デストラクタの説明は必要ないでしょうから、コンストラクタのみ説明します。

WaveSoundBufferオブジェクトを作り、効果音ファイルを読み込んでおく

モグラ自身の設定を行う:マウスイベントを拾うように設定し、モグラの画像を読み込む

以下のトピックも参照してください。

リファレンス
トピック
サブトピック

吉里吉里2リファレンス
WaveSoundBufferクラス
コンストラクタ

メソッドopen()

Layerクラス
プロパティhitType、hitThreshold




モグラクラス:メソッドreset()、move()
モグラクラスのメソッドreset()、move()を実装します。

// パラメータを再設定

function reset()

{

  visible = false;  // 非表示にする



  var interval = master.timer1.interval;



  // 隠れている時間は1~5秒

  hidden_time = intrandom(1*1000\\interval, 5*1000\\interval);



  // 出現している時間は0.5~2秒

  visible_time = intrandom(1\\2*1000\\interval, 2*1000\\interval);



  counter = -hidden_time;

}



// モグラの画像を非表示したり表示したりする

function move()

{

  if (counter > visible_time) {  // counterがtimeより大きい

    reset();

  }

  else {

    if (counter == 0) {  // counterが0なら、以降からモグラを表示

      visible = true;

    }

    counter++;

  }

}


メソッドreset()では、隠れている時間と出現している時間を乱数で決定します。メソッドmove()では、モグラ(の画像)をどのタイミングで表示させるかを決定します。counterが負の間は画像を非表示に、0以上になったら画像を表示させるようにします。

■メンバ変数hidden_timeには、大して意味がありません。継承したときに使い道があればどうぞ…と言う程度のものです。□



モグラクラス:メソッドonMouseDown()
モグラクラスのメソッドonMouseDown()を実装します(スーパークラスLayerのメソッドonMouseDown()をオーバーライド)。引数buttonにはマウスのどのボタンを押したかの情報が渡されます。

// マウスイベントを処理

function onMouseDown(x, y, button, shift)

{

  if (button == mbLeft && visible) {  // モグラが表示中にマウス左ボタンがクリックされた

    hit_sound.play();  // 効果音を鳴らす

    master.point++;    // 得点を加算

    reset();

  }

}


もし、モグラが表示中に、モグラ上をマウス左クリックしたら、効果音を鳴らし、得点を加算します。また、メソッドreset()を呼び出し、非表示状態から再開します。

以下のトピックも参照してください。

リファレンス
トピック
サブトピック

吉里吉里2リファレンス
WaveSoundBufferクラス
メソッドplay()

Layerクラス
メソッドonMouseDown()




全コード
完成したモグラ叩きゲームの全コードを示します。プロジェクトフォルダ名はgame、ファイル名はstartup.tjsとします。

// モグラ叩きゲーム



// Util.tjsからintrandom()のコードを拝借

function intrandom(min = 0, max = 0)

{

  // min 以上 max 以下の整数の乱数を返す

  // 引数が一個だけの場合は 0 ~ その数までの整数を返す

  if(min>max) { min <-> max; }

  return int(Math.random() * (max-min+1)) + min;

}



// モグラクラス

class Mole extends Layer

{

  var master;        // ゲームマスター

  var hit_sound;     // 叩かれたときの効果音

  var counter;       // イベントのカウンター(-hidden_time~visible_timeの間で変化)

  var hidden_time;   // 隠れている時間

  var visible_time;  // 出現している時間



  // コンストラクタ

  function Mole(gm, window, parent)

  {

    super.Layer(window, parent);  // スーパークラスのコンストラクタを呼び出し



    master = gm;



    // 効果音ファイルを読み込む

    hit_sound = new WaveSoundBuffer(window);

    hit_sound.open("hit.wav");  // ←拡張子もつけないとダメらしい



    // マウスイベントを受け取る

    hitType = htMask;

    hitThreshold = 0;



    // モグラの画像を読み込み、レイヤーのサイズを画像のそれと同じにする

    loadImages("mole");

    setSizeToImageSize();

  }



  // デストラクタ

  function finalize()

  {

    invalidate hit_sound;



    super.finalize();  // スーパークラスのデストラクタを呼び出し

  }



  // パラメータを再設定

  function reset()

  {

    visible = false;  // 非表示にする



    var interval = master.timer1.interval;



    // 隠れている時間は1~5秒

    hidden_time = intrandom(1*1000\\interval, 5*1000\\interval);



    // 出現している時間は0.5~2秒

    visible_time = intrandom(1\\2*1000\\interval, 2*1000\\interval);



    counter = -hidden_time;

  }



  // モグラの画像を非表示したり表示したりする

  function move()

  {

    if (counter > visible_time) {  // counterがtimeより大きい

      reset();

    }

    else {

      if (counter == 0) {  // counterが0なら、以降からモグラを表示

        visible = true;

      }

      counter++;

    }

  }



  // マウスイベントを処理

  function onMouseDown(x, y, button, shift)

  {

    if (button == mbLeft && visible) {  // モグラが表示中にマウス左ボタンがクリックされた

      hit_sound.play();  // 効果音を鳴らす

      master.point++;    // 得点を加算

      reset();

    }

  }

}



// ゲームマスタークラス(モグラオブジェクトの管理などを行う)

class GemeMaster

{

  var window;      // ゲームウィンドウオブジェクト

  var parent;      // 親レイヤー:(ゲームウィンドウの)プライマリレイヤー

  var fore;        // 親レイヤーのコピー:表画面として使う

  var moles = [];  // モグラオブジェクトの配列

  var timer1;      // タイマー1:モグラ用

  var timer2;      // タイマー2:残り時間用



  var rest_time;   // 残り時間

  var point;       // 得点



  // コンストラクタ

  function GemeMaster(win, par)

  {

    window = win;

    parent = par;



    // 親レイヤーのコピーを作る

    fore = new Layer(win, par);

    with (fore)

    {

      .visible = true;

      .assignImages(parent);

      .setSizeToImageSize();



      // フォントの高さを30ピクセルに設定(残り時間、得点の文字に使う)

      .font.height = 30;

    }



    // モグラオブジェクトを作成

    moles.add(new Mole(this, window, fore));

    moles.add(new Mole(this, window, fore));

    moles.add(new Mole(this, window, fore));



    // モグラの表示位置を設定

    // (モグラの画像サイズによって調整してください)

    moles[0].top  = 100;

    moles[0].left =  50;

    moles[1].top  = 100;

    moles[1].left = 250;

    moles[2].top  = 100;

    moles[2].left = 450;



    // モグラ用タイマーオブジェクトを作成

    timer1 = new Timer(onTimer1, "");

    timer1.interval = 100;  // タイマーイベントは100ミリ秒間隔で発生



    // 残り時間用タイマーオブジェクトを作成

    timer2 = new Timer(onTimer2, "");

    timer2.interval = 1000;  // タイマーイベントを1秒間隔で発生させる

  }



  // デストラクタ

  function finalize()

  {

    // タイマーを無効化

    invalidate timer2;

    invalidate timer1;



    // モグラを無効化

    for (var i = 0; i < moles.count; i++) {

      invalidate moles;

    }



    // 表画面を無効化

    invalidate fore;

  }



  // ゲームを開始

  function start()

  {

    point = 0;

    rest_time = 20;

    timer1.enabled = timer2.enabled = true;

  }



  // ゲームを終了

  function stop()

  {

    timer1.enabled = timer2.enabled = false;

  }



  // タイマーイベントを処理:モグラを動かす

  function onTimer1()

  {

    // モグラを動かす

    for (var i = 0; i < moles.count; i++) {

      moles.move();

    }



    // 得点を更新する

    with (fore) {

      .copyRect(500, 0, parent, 500, 0, 160, 30);

      .drawText(500, 0, "得点:"+point, 0x000000);

    }

  }



  // タイマーイベントを処理:残り時間を更新する

  function onTimer2()

  {

    // 残り時間を更新する

    with (fore) {

      .copyRect(0, 0, parent, 0, 0, 160, 30);

      .drawText(0, 0, "残り時間:"+(rest_time--), 0x000000);

    }



    if (rest_time < 0) {

      stop();

    }

  }

}



// ゲームウィンドウクラス

class GameWindow extends Window

{

  var file_menu;   // ファイルメニュー

  var start_menu;  // ゲーム開始メニュー

  var exit_menu;   // 終了メニュー



  var master;      // ゲームマスター



  // コンストラクタ

  function GameWindow()

  {

    super.Window();  // スーパークラスのコンストラクタを呼び出す



    // [ファイル]、[ファイル‐ゲーム開始]、[ファイル‐閉じる]メニューを作成

    menu.add(file_menu = new MenuItem(this, "ファイル(&F)"));

    file_menu.add(start_menu = new MenuItem(this, "ゲーム開始(&S)"));

    file_menu.add(exit_menu = new MenuItem(this, "閉じる(&C)"));



    // プライマリレイヤーを作成

    add(new Layer(this, null));

    with (primaryLayer)

    {

      // 背景画像を読み込み、そのサイズに設定

      .loadImages("stage");

      .setSizeToImageSize();

    }



    // ゲームウィンドウをプライマリレイヤーのサイズに合わせる

    setInnerSize(primaryLayer.width, primaryLayer.height);



    caption = "モグラ叩きゲーム";  // ゲームウィンドウのタイトルを設定

    visible = true;                // ゲームウィンドウを表示



    // ゲームマスターオブジェクトを作成

    master = new GemeMaster(this, primaryLayer);

  }



  // デストラクタ

  function finalize()

  {

    // ゲームマスターを無効化

    invalidate master;



    // メニューを無効化

    invalidate exit_menu;

    invalidate start_menu;

    invalidate file_menu;



    super.finalize();  // スーパークラ?工违钎攻去楗
え~え~お!!!
回复 支持 反对

使用道具 举报

18

主题

428

帖子

5260

积分

⑦老手

在美工荒中挣扎的全能

积分
5260
QQ
发表于 2007-5-18 03:31:34 | 显示全部楼层
TJS Primer-v-
有这东西么-v-
回复 支持 反对

使用道具 举报

136

主题

1751

帖子

548

积分

版主

Rank: 7Rank: 7Rank: 7

积分
548
 楼主| 发表于 2007-5-18 04:24:47 | 显示全部楼层
有的。是第三方写的。
只是我记不清这个东西是不是这个chm里面的了。
http://homepage1.nifty.com/gutchie/archive/tjs_primer.lzh
另外还有一本说kag3的。
http://homepage1.nifty.com/gutchie/archive/game_dev.lzh
え~え~お!!!
回复 支持 反对

使用道具 举报

36

主题

996

帖子

350万

积分

⑧专业

积分
3507413
发表于 2007-5-18 07:55:25 | 显示全部楼层
好东西……多谢分享~慢慢看着先……
回复 支持 反对

使用道具 举报

313

主题

1574

帖子

1万

积分

⑧专业

*永恒国度*

积分
14145
QQ
发表于 2007-5-18 14:49:57 | 显示全部楼层
这个是RGSS吗 [s:3]  [s:3]
[img][/img] http://shop33698673.taobao.com被别人嫉妒,证明你优秀,嫉妒别人说明你无能
回复 支持 反对

使用道具 举报

20

主题

197

帖子

2641

积分

⑥精研

积分
2641
QQ
发表于 2007-5-18 17:50:35 | 显示全部楼层
类似PASCAL/C 语法,不区分变量的类型,应该是RUBY....
签名要少于60,SO,i haven't upload my pic
回复 支持 反对

使用道具 举报

136

主题

1751

帖子

548

积分

版主

Rank: 7Rank: 7Rank: 7

积分
548
 楼主| 发表于 2007-5-18 19:03:25 | 显示全部楼层
引用第5楼august2007-05-18 14:49发表的:
这个是RGSS吗 [s:3]  [s:3]
当然不是了,是krkr中的tjs脚本语言。
引用第6楼Zelsazgh2007-05-18 17:50发表的:
类似PASCAL/C 语法,不区分变量的类型,应该是RUBY....
也不是ruby,tjs是采用了c风格,类似javascript的脚本语言。
在运行机制上和ruby一样的,都是脚本语言。

本来tjs的东西是应该发在avg区,归在krkr中,可我觉得这东西不但思路上是面向对象,实现的出来,也并不是一个avg。相对来说,来这个区的人更需要,也更容易理解这个东西,所以就发这里了。
え~え~お!!!
回复 支持 反对

使用道具 举报

50

主题

742

帖子

402

积分

版主

自定义头衔

Rank: 7Rank: 7Rank: 7

积分
402
发表于 2007-5-18 21:38:29 | 显示全部楼层
都已经这个样子了,建议不如直接用C++模拟C风格+一个引擎写巴...

偶个人对脚本只习惯于KAG3这层或者是RMXP的脚本这层,否则感觉是不是有点那个—— [s:4]
Style-C
回复 支持 反对

使用道具 举报

136

主题

1751

帖子

548

积分

版主

Rank: 7Rank: 7Rank: 7

积分
548
 楼主| 发表于 2007-5-18 22:28:46 | 显示全部楼层
不理解这些思路的话,也就没法理解kag3的原理,也就是说,没法对kag作较大幅度的个人定制。
只能是看着fate里面的特效流口水,却实现不了。 [s:6]
rmxp也是一样的。
而改这些东西,远比自己从头写一个引擎容易得多得多。
别的先不说,光资源打包这一块,就够c++写半天的了。
不光语言运用要过关,还得有不错的数据结构基础(设计自己的文件格式),以及加密解密知识(如des算法)。
而用krkr,rmxp,却得来不费半点工夫。
特别适合中阶制作者。
え~え~お!!!
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|幻想森林

GMT+8, 2024-4-28 19:18 , Processed in 0.032213 second(s), 21 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表