2 ****PCD-2013 GameScriptCoreLibrary****
3 Tokyo Gakugei University Senior High School.
6 Mac OSX: Safari, Chrome
7 Windows: Chrome, IE(9 or later)
21 mainManager = new GameManager();
29 var loc = document.location.href;
31 var URL_PCD_Root = loc.slice(0, loc.lastIndexOf("/") + 1);
33 var URL_PCD_Auth = URL_PCD_Root + "auth.php";
34 var URL_PCD_Audio = URL_PCD_Root + "audio/";
35 var URL_PCD_Stage = URL_PCD_Root + "stage/";
37 // ゲームを呼び出す関数 適切なdiv要素で呼び出すとゲームを初期化できる。
39 // audio, corelib, images, stageの各フォルダをコピーしたdirにhtmlを置き、<div>.InitGameManager() と実行するスクリプトを書く
40 // stageName == nullだとステージを開始しない。指定する時は.jsおよびパスを省く
45 var CollideBottom = 4;
49 HTMLDivElement.prototype.InitGameManager = function(stageName)
51 if(this instanceof HTMLDivElement)
53 var man = new GameManager(this, null);
54 if(stageName) man.loadStageFromNetwork.apply(man, [stageName]);
58 throw new TypeError("InitGameManager はdiv要素にしか実行できません");
66 function GameManager(parent, debugTextName){
69 if(debugTextName == undefined) debugTextName = "DebugText";
70 if(parent == undefined) parent = document.getElementById("MainArea");
73 if(parent.style.position != 'absolute') parent.style.position = 'relative';
77 this.networkManager = new NetworkManager(this);
78 this.UIManager = new UIManager(this);
79 this.userManager = new UserManager(this);
80 this.mainArea = parent;
81 //必要最低限のCanvasとコンテキストの設定
82 this.mainCanvas = createCanvas("MainCanvas", 640, 480, 0, 0, 1, parent);
83 this.mainCanvas.style.border = "solid 1px";
84 this.mainContext = this.mainCanvas.getContext('2d');
85 this.debugText = document.getElementById(debugTextName); //要素が存在しないとnullになり、デバッグが無効になる
86 if(!this.debugText) this.debugText = null;
90 if(!this.isAvailableBrowser()){
94 this.mainContext.fillStyle = "rgba(200,255,200,0.5)";
95 this.mainContext.strokeStyle = "rgba(0, 0, 0, 0.5)";
96 this.mainContext.font = "normal 20px sans-serif";
97 //実行中のGameStageオブジェクトを格納
98 this.runningStage = null;
99 this.runningStageName = null;
100 //現在存在しているWidghetのリストを格納
101 this.runningWidgets = [];
105 //タイマーカウントの秒あたりの回数を設定
106 this.tickPerSecond = 60;
107 // pauseStage()が呼ばれたときにnullじゃなくなる
108 this.stagePausedFunction = null;
110 this.backgroundMusic = null;
113 //コールバックを行うために、イベントリスナーのmanagerプロパティにGameManagerのインスタンスを代入する。
115 timerTickEventListener.manager = this;
116 window.setInterval(timerTickEventListener, 1000/this.tickPerSecond);
118 //各種コールバック(使用元のスクリプトで使う用)
119 this.stageStartedEvent = null; //ステージが開始されたときに呼ばれる。引数: stage
120 this.stageStoppedEvent = null; //ステージが終了されたときに呼ばれる。引数: stage
122 GameManager.prototype = {
123 timerTick: function(){
124 //各オブジェクトの単位時間ごとの動作と再描画を行う
127 if(this.stagePausedFunction == null){
129 if(this.runningStage){
131 this.runningStage.timerTick();
134 // runningStage.timerTick() 内でpauseStage()された時、ここで再度判定しないとWidghetのtickが実行されてしまう
135 if(this.stagePausedFunction == null){
137 for(var i = 0; i < this.runningWidgets.length; i++){
138 var w = this.runningWidgets[i];
140 // Widghetのtick()からfalseで帰ってきたらWidghetを開放
141 this.removeWidget(w);
147 this.stagePausedFunction();
152 if(this.runningStage){
154 this.runningStage.draw();
157 for(var i = 0; i < this.runningWidgets.length; i++){
158 var w = this.runningWidgets[i];
162 //各オブジェクトの走査が終わってから、死亡判定およびステージ再読み込みを行う。
163 if(this.runningStage && this.runningStage.userControlledCharacter){
164 if(this.runningStage.userControlledCharacter.HP == 0){
165 this.runningStage.userControlledCharacter.HP = this.runningStage.userControlledCharacter.max_HP;
166 this.addWidget(new MessageWidgetClass(this, ["死んでしまった……\n", null, function(w){
167 w.manager.UIManager.clearInput();
168 w.manager.runningStage.userControlledCharacter.HP = w.manager.runningStage.userControlledCharacter.max_HP;
169 if(w.manager.runningStageName){
170 w.manager.loadStageFromNetwork(w.manager.runningStageName);
172 //ローカルモード時は動作を停止させるだけ
173 w.manager.stopStage();
180 addWidget: function(w){
182 this.runningWidgets.push(w);
184 removeWidget: function(w){
185 if(removeObjectFromArray(this.runningWidgets, w))
190 runStage: function(stage){
192 //実行中のステージがあれば終了処理を行わせる。
193 if(this.runningStage){
197 //GameManager側の情報をGameStageに渡す。
198 stage.manager = this;
199 stage.mainCanvas = this.mainCanvas
200 stage.debugCanvas = this.debugCanvas
201 stage.mainContext = this.mainContext
202 stage.debugContext = this.debugContext
203 //GameStage側の初期化処理を行わせる。
206 this.networkManager.joinStage(stage);
207 //runningStageに登録することで、イベントの通知が開始され、GameStageは実行状態に入る。
208 this.runningStage = stage;
210 this.addWidget(new UserStateWidgetClass(this));
211 this.addWidget(new PickedItemWidgetClass(this));
213 if(this.stageStartedEvent)
215 this.stageStartedEvent.apply(window, [stage]);
219 pauseStage: function(func){
220 //ステージの実行を一時停止する。一時停止中、funcに指定された関数が毎tick毎に呼ばれる
221 if(this.stagePausedFunction == null){
222 this.stagePausedFunction = func;
225 //ステージが一時停止中のfunc()の中から二重にpauseStage()を呼んではいけない
229 resumeStage: function(){
231 if(this.stagePausedFunction != null) {
232 //必ずpauseStage()の引数に指定したfunc()の中から呼ばれる・・・はず。
233 this.stagePausedFunction = null;
239 stopStage: function(){
241 if(this.runningStage){
242 //runningStageから設定解除することで、イベントの通知は行われなくなる。
243 var aGameStage = this.runningStage;
244 this.runningStage = null;
245 //GameStage側の終了処理を行わせる。
246 aGameStage.stopStage();
247 //GameStageインスタンスからGameManagerの情報を削除する。
248 aGameStage.manager = null;
249 aGameStage.mainCanvas = null;
250 aGameStage.debugCanvas = null;
251 aGameStage.mainContext = null;
252 aGameStage.debugContext = null;
254 //画面上に表示されたすべてのWidgetを解放する
255 for(;this.runningWidgets.length>0;)
257 this.removeWidget(this.runningWidgets[0]);
260 if(this.stageStoppedEvent)
262 this.stageStoppedEvent.apply(window, [aGameStage]);
266 loadStageFromLocal: function(code){
269 URL_PCD_Auth = URL_PCD_Root + "auth.php";
270 URL_PCD_Audio = URL_PCD_Root + "audio/";
271 URL_PCD_Stage = URL_PCD_Root + "stage/";
273 var stage = eval(code);
274 mainManager.runStage(stage);
276 loadStageFromNetwork: function(name){
277 //URL_PCD_Stage/name.jsを利用してステージを作成する。
278 var request = this.networkManager.CreateRequestObject();
280 request.open('GET', URL_PCD_Stage + name + ".js", false);
281 this.networkManager.RequestObjectDisableCache(request);
284 if(request.status == 0){
285 alert("ネットワークにアクセスできません。" + request.status + ":" + request.statusText);
286 }else if((200 <= request.status && request.status < 300) || (request.status == 304)){
287 if(this.userID != 0){
288 var rq2 = this.networkManager.CreateRequestObject();
290 rq2.open('GET', URL_PCD_Auth + "?action=chstg&name=" + name + "&id=" + this.userID);
291 this.networkManager.RequestObjectDisableCache(rq2);
294 var stage = eval(request.responseText);
295 this.runStage(stage);
296 this.runningStageName = name;
298 alert("サーバーがエラーを返しました。" + request.status + ":" + request.statusText);
301 debugOut: function(str){
302 if(this.debugText != null)
307 this.debugText.value = str.replace(/\n/g,"\r\n") + this.debugText.value;
310 this.debugText.innerHTML = str + this.debugText.value;
314 isAvailableBrowser: function(){
315 //ブラウザの判別を行う。実行不可能な場合はfalseを返す。
316 //http://d.hatena.ne.jp/Naotsugu/20110927/1317140891
317 var userAgent = window.navigator.userAgent.toLowerCase();
318 var appVersion = window.navigator.appVersion.toLowerCase();
320 if (userAgent.indexOf('opera') != -1) {
322 this.debugOut("Browser:Opera\n");
323 } else if (userAgent.indexOf('msie') != -1) {
324 if (appVersion.indexOf("msie 9.") != -1) {
326 this.debugOut("Browser:IE9\n");
327 } else if (appVersion.indexOf("msie 8.") != -1) {
329 this.debugOut("Browser:IE8\n");
330 } else if (appVersion.indexOf("msie 7.") != -1) {
332 this.debugOut("Browser:IE7\n");
333 } else if (appVersion.indexOf("msie 6.") != -1) {
335 this.debugOut("Browser:IE6\n");
337 this.debugOut("Browser:IE?\n");
340 } else if (userAgent.indexOf('chrome') != -1) {
342 this.debugOut("Browser:Chrome\n");
343 } else if (userAgent.indexOf('safari') != -1) {
345 this.debugOut("Browser:Safari\n");
346 } else if (userAgent.indexOf('gecko') != -1) {
348 this.debugOut("Browser:Gecko\n");
351 this.debugOut("Browser:Unknown\n");
353 //描画コンテキストからHTML5対応チェック
354 if(!this.mainCanvas || !this.mainCanvas.getContext){
356 alert("このゲームを遊ぶためには、HTML5に対応しているブラウザ(Google Chrome等)でアクセスしてください...。");
361 setBackgroundMusic: function(name){
362 if(this.backgroundMusic){
364 this.backgroundMusic.pause();
365 this.backgroundMusic = null;
368 //引数がnullでなければaudioオブジェクトを取得
369 this.backgroundMusic = createAudio(name);
370 if(this.backgroundMusic){
372 this.backgroundMusic.loop = true;
373 this.backgroundMusic.play();
382 //イベントリスナーにおけるthisは、イベントリスナーを登録したオブジェクトまたはwindowになり、通常とは異なるので注意。
384 function timerTickEventListener(event)
386 timerTickEventListener.manager.timerTick(event);