[TJS][伪翻译]面向对象的思路实现一个游戏
整理硬盘时发现的。还是去年对krkr着迷的时候做的,我来翻译,当然是不准确,随意翻的,错误很多,而且还有很多地方没有翻。更全面,更详细的还是看原文吧。(在二楼)
原文似乎是来自tjs primer.chm中的。
思路
大体的思路,使用3个类,游戏窗口类,游戏主类,鼹鼠类。类的说明如下:
类 作用 备注
游戏窗口类 窗口显示,菜单显示,剩余时间显示 从window类继承
游戏主体类 游戏流程控制:得分管理,鼹鼠的管理
鼹鼠类 鼹鼠图像的显示,声效的播放,鼠标事件处理从Layer类继承
构架游戏窗口类的骨架
///////////////////////////////////////////////////////////////////////
// 游戏窗口类
class GameWindow extends Window
{
var file_menu; //文件菜单
var start_menu;//游戏开始菜单
var exit_menu; //结束菜单
var master; //游戏主体
//游戏窗口
function GameWindow()
{
super.Window();// 从window类继承
}
//销毁资源
function finalize()
{
super.finalize();//从上面继承
}
// 菜单选择后的响应动作action()
function action(ev)
{
//暂时还没有
}
}
// 从游戏窗口类创建一个实例
var win = new GameWindow();
//////////////////////////////////////////////////////////////////////
tjs中的window类原本都是不带菜单的。所以要加入菜单才能做成我们所需要的窗口类。
类中声明的变量的说明:
变量 作用 备注
file_menu 生成“文件”菜单
start_menu 文件-游戏开始
exit_menu 文件-关闭
master 游戏主体对象 在后面说明
构建游戏主体类的骨架
要注意时间类和时间事件的处理,时间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() { }
}
/////////////////////////////////////////////////
构建鼹鼠类的骨架
鼹鼠类是从layer类继承。layer类的作用是图片的显示\不显示,以及鼠标事件的处理。
鼹鼠类中需要用到intrandom()函数,这个函数在kag3\template\system\Util.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);//从layer类继承
}
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();//继承一个
}
////////////////////////////////////////////////////////
主函数的说明
1.一开始是创建菜单对像。创建了三个菜单。
以后选择菜单的时后,就用到后面说的action()函数。
2.接着创建了主层。用add()来登陆游戏窗口自身。
以后主层就可以以primarylayer的属性和访问。
3.主层读入了背景图片。后面会用到缓冲层。
4.最好创建了游戏主体类,这个类里包括了窗口类和主层类。
以下是类的继承关系
krkr2Window类 方法add()、setInnerSize()
属性caption、visible
MenuItem类 主函数
方法add()
Layer类 主函数
方法loadImages()、SetSizeToImageSize()
属性width、height
主层创建的参数是null,即什么都不显示
实装游戏窗口类的“方法”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();
//设定字体
.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.top= 100;
moles.left =50;
moles.top= 100;
moles.left = 250;
moles.top= 100;
moles.left = 450;
//鼹鼠用的时间对象
timer1 = new Timer(onTimer1, "");
timer1.interval = 100;// 100ms间隔
//创建剩余时间用的时间类
timer2 = new Timer(onTimer2, "");
timer2.interval = 1000;//1000ms间隔
}
//销毁函数
function finalize()
{
//时间类无效化
invalidate timer2;
invalidate timer1;
//鼹鼠对象无效化
for (var i = 0; i < moles.count; i++)
{
invalidate moles;
}
// 主层副本无效化
invalidate fore;
}
/////////////////////////////////////////////////////////
1.亲层副本,用来缓冲用
2.创建了鼹鼠对象,并设定了其位置
3.两个时间对象
吉里吉里2 Layer类 方法assignImages()
属性visible、font、top、left
Font类 属性height
Timer类 主函数
属性interval
对于有父子关系的层,如果没有特别的限定,那么父层在里面,子层在前面。这个例子里面的顺序从里到外是,主层,主层副本,鼹鼠。
实装游戏主体类中的方法 start()和stop()
///////////////////////////////////////////////////////////
//游戏开始
function start()
{
point = 0;
rest_time = 20;
timer1.enabled = timer2.enabled = true;
}
//游戏结束
function stop()
{
timer1.enabled = timer2.enabled = false;
}
///////////////////////////////////////////////////////////
用到了timer类的一个属性enabled
实装游戏主体类的方法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()是在指定坐标画文字。如果原来有文字,自动覆盖以前的。没有比要特意去消。
用到了layer类中的方法copyRect()和drawText()
实装鼹鼠类中的主函数和销毁函数
主函数中的参数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();// 继承
}
////////////////////////////////////////////
1.创建WaveSoundBuffer对象,读入效果音
2.设定鼹鼠自身:读入图像,鼠标事件
WaveSoundBuffer类 主函数
方法open()
Layer类 属性hitType、hitThreshold
实装鼹鼠类中的方法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以上为显示。
实装鼹鼠类中的方法onMouseDown()
参数button传递鼠标点击的消息。
//处理鼠标事件
function onMouseDown(x, y, button, shift)
{
if (button == mbLeft && visible) {//在鼹鼠显示中按下了左键
hit_sound.play();// 效果音
master.point++; // 增加得点
reset();
}
}
////////////////////////////////////////////////////
鼹鼠显示中,在鼹鼠上点左键,播放效果音,增加得点。然后呼叫方法reset(),重新进人不显示的状态。
WaveSoundBuffer类 方法play()
Layer类 方法onMouseDown()
原文,复制过来格式上有点乱
実装
方針
大まかな方針として、ゲームウィンドウクラス、ゲームマスタークラス、モグラクラスの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.top= 100;
moles.left =50;
moles.top= 100;
moles.left = 250;
moles.top= 100;
moles.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.top= 100;
moles.left =50;
moles.top= 100;
moles.left = 250;
moles.top= 100;
moles.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();// スーパークラ?工违钎攻去楗 TJS Primer-v-
有这东西么-v- 有的。是第三方写的。
只是我记不清这个东西是不是这个chm里面的了。
http://homepage1.nifty.com/gutchie/archive/tjs_primer.lzh
另外还有一本说kag3的。
http://homepage1.nifty.com/gutchie/archive/game_dev.lzh 好东西……多谢分享~慢慢看着先…… 这个是RGSS吗 类似PASCAL/C 语法,不区分变量的类型,应该是RUBY.... 引用第5楼august于2007-05-18 14:49发表的:
这个是RGSS吗
当然不是了,是krkr中的tjs脚本语言。
引用第6楼Zelsazgh于2007-05-18 17:50发表的:
类似PASCAL/C 语法,不区分变量的类型,应该是RUBY....
也不是ruby,tjs是采用了c风格,类似javascript的脚本语言。
在运行机制上和ruby一样的,都是脚本语言。
本来tjs的东西是应该发在avg区,归在krkr中,可我觉得这东西不但思路上是面向对象,实现的出来,也并不是一个avg。相对来说,来这个区的人更需要,也更容易理解这个东西,所以就发这里了。 都已经这个样子了,建议不如直接用C++模拟C风格+一个引擎写巴...
偶个人对脚本只习惯于KAG3这层或者是RMXP的脚本这层,否则感觉是不是有点那个—— 不理解这些思路的话,也就没法理解kag3的原理,也就是说,没法对kag作较大幅度的个人定制。
只能是看着fate里面的特效流口水,却实现不了。
rmxp也是一样的。
而改这些东西,远比自己从头写一个引擎容易得多得多。
别的先不说,光资源打包这一块,就够c++写半天的了。
不光语言运用要过关,还得有不错的数据结构基础(设计自己的文件格式),以及加密解密知识(如des算法)。
而用krkr,rmxp,却得来不费半点工夫。
特别适合中阶制作者。
页:
[1]
2