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 URL_PCD_Root = "http://localhost/pcd2013dev/www/";
30 //var URL_PCD_Root = "http://192.168.6.242/pcd2013dev/www/";
31 //var URL_PCD_Root = "http://192.168.0.3/PCD2013GSCL/www/";
32 //var URL_PCD_Root = "http://192.168.6.242/pcd2013hikarupsp/pcd2013dev/www/";
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/";
41 function GameManager(){
45 this.networkManager = new NetworkManager();
46 //必要最低限のCanvasとコンテキストの設定
47 this.mainCanvas = createCanvas("MainCanvas", 640, 480, 0, 0, 1, "MainArea");
48 this.mainCanvas.style.border = "solid 1px";
49 this.mainContext = this.mainCanvas.getContext('2d');
50 this.debugText = document.getElementById('DebugText');
53 if(!this.isAvailableBrowser()){
57 this.mainContext.fillStyle = "rgba(200,255,200,0.5)";
58 this.mainContext.strokeStyle = "rgba(0, 0, 0, 0.5)";
59 this.mainContext.font = "normal 20px sans-serif";
60 //実行中のGameStageオブジェクトを格納
61 this.runningStage = null;
62 //現在存在しているWidghetのリストを格納
63 this.runningWidghets = [];
68 this.tickPerSecond = 60;
69 this.updateIntervalMs = 128;
70 //キーボード状態を格納するプロパティの設定
71 this.keyState = new Object();
72 this.keyState.upArrow = false;
73 this.keyState.downArrow = false;
74 this.keyState.leftArrow = false;
75 this.keyState.rightArrow = false;
76 // pauseStage()が呼ばれたときにnullじゃなくなる
77 this.stagePausedFunction = null;
79 this.backgroundMusic = null;
82 //コールバックを行うために、イベントリスナーのmanagerプロパティにGameManagerのインスタンスを代入する。
84 keyDownEventListener.manager = this;
85 window.addEventListener('keydown', keyDownEventListener, true);
87 keyUpEventListener.manager = this;
88 window.addEventListener('keyup', keyUpEventListener, true);
90 timerTickEventListener.manager = this;
91 window.setInterval(timerTickEventListener, 1000/this.tickPerSecond);
92 timeStampTimerTickEventListener.manager = this;
93 window.setInterval(timeStampTimerTickEventListener, this.updateIntervalMs);
95 GameManager.prototype = {
96 keyDown: function(event){
97 //コールバックではなくコールバック関数(keyDownEventListener)から呼び出されるので、thisはGameManagerのインスタンスとなる。
98 keyCode = event.keyCode;
99 switch(event.keyCode){
102 this.keyState.upArrow = true;
106 this.keyState.downArrow = true;
110 this.keyState.leftArrow = true;
114 this.keyState.rightArrow = true;
118 if(this.runningStage){
119 this.runningStage.keyDown(event);
120 switch(event.keyCode){
125 event.preventDefault();
130 keyUp: function(event){
131 //コールバックではなくコールバック関数(keyUpEventListener)から呼び出されるので、thisはGameManagerのインスタンスとなる。
132 keyCode = event.keyCode;
133 switch(event.keyCode){
136 this.keyState.upArrow = false;
140 this.keyState.downArrow = false;
144 this.keyState.leftArrow = false;
148 this.keyState.rightArrow = false;
152 if(this.runningStage){
153 this.runningStage.keyUp(event);
156 timerTick: function(){
157 //各オブジェクトの単位時間ごとの動作と再描画を行う
160 if(this.stagePausedFunction == null){
162 if(this.runningStage){
164 this.runningStage.timerTick();
167 for(var i = 0; i < this.runningWidghets.length; i++){
168 var w = this.runningWidghets[i];
170 // Widghetのtick()からfalseで帰ってきたらWidghetを開放
171 this.runningWidghets.splice(i, 1);
177 this.stagePausedFunction();
181 if(this.runningStage){
183 this.runningStage.draw();
186 for(var i = 0; i < this.runningWidghets.length; i++){
187 var w = this.runningWidghets[i];
191 timeStampTimerTick: function(){
194 this.timeStamp += this.updateIntervalMs;
196 if(this.userID != 0){
197 //ユーザーIDが設定されている=オンライン状態
198 request = this.networkManager.CreateRequestObject();
200 request.open('POST', URL_PCD_Root + "update.php?uid=" + this.userID + "&action=refresh", false);
201 request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
203 aData = new RequestData();
204 for(i = 0; i < this.runningStage.globalStageObjectList.length; i++){
205 anObj = this.runningStage.globalStageObjectList[i];
206 if(anObj.ownerUID == this.userID){
207 aData.append(i, anObj.objectID + "|" + anObj.origin.x + "|" + anObj.origin.y + "|" + anObj.movingSpeed.x + "|" + anObj.movingSpeed.y+ "|" + anObj.attribute);
211 this.networkManager.RequestObjectDisableCache(request);
212 request.send(aData.data);
214 if(request.status == 0){
215 alert("ネットワークにアクセスできません。" + this.status + ":" + this.statusText);
216 }else if((200 <= request.status && request.status < 300) || (request.status == 304)){
217 var res = request.responseText;
218 if(isValidResponseText(res)){
219 var retArray = eval(res);
220 this.timeStamp = retArray[0];
222 for(var i = 0; i < retArray[3].length; i++){
223 this.debugOut("Network:removeObject:ObjectID=" + retArray[3][i] + "\n");
224 var anObject = this.runningStage.getGlobalStageObject(retArray[3][i]);
226 this.runningStage.removeStageObject(anObject);
230 for(var i = 0; i < retArray[1].length; i++){
231 //this.debugOut("Network:refreshObject:ObjectID=" + retArray[1][i] + "\n");
232 anArray = retArray[1][i];
233 var anObject = this.runningStage.getGlobalStageObject(anArray[0]);
235 anObject.origin.x = anArray[1];
236 anObject.origin.y = anArray[2];
237 anObject.movingSpeed.x = anArray[3];
238 anObject.movingSpeed.y = anArray[4];
242 for(var i = 0; i < retArray[2].length; i++){
243 anArray = retArray[2][i];
244 var args = eval(anArray[7]);
245 var anObject = eval("new " + anArray[5] + "(this.runningStage, args);");
247 this.debugOut("Network:addObject:ObjectID=" + anArray[0] + "\n");
248 anObject.objectID = anArray[0];
249 anObject.origin.x = anArray[1];
250 anObject.origin.y = anArray[2];
251 anObject.movingSpeed.x = anArray[3];
252 anObject.movingSpeed.y = anArray[4];
253 this.runningStage.addStageObject(anObject, true);
258 alert("サーバーがエラーを返しました。" + this.status + ":" + this.statusText);
263 addWidghet: function(w){
264 this.runningWidghets.push(w);
266 runStage: function(stage){
268 //実行中のステージがあれば終了処理を行わせる。
269 if(this.runningStage){
273 //GameManager側の情報をGameStageに渡す。
274 stage.manager = this;
275 stage.mainCanvas = this.mainCanvas
276 stage.debugCanvas = this.debugCanvas
277 stage.mainContext = this.mainContext
278 stage.debugContext = this.debugContext
279 //GameStage側の初期化処理を行わせる。
281 //サーバーに追加オブジェクトの情報をアップロード
282 if(this.userID != 0){
283 request = this.networkManager.CreateRequestObject();
285 request.open('POST', URL_PCD_Root + "update.php?uid=" + this.userID + "&action=add", false);
286 request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
288 aData = new RequestData();
289 for(i = 0; i < stage.globalStageObjectList.length; i++){
290 anObj = stage.globalStageObjectList[i];
291 aData.append(i, anObj.origin.x.toString() + "|" + anObj.origin.y.toString() + "|" + anObj.movingSpeed.x.toString() + "|" + anObj.movingSpeed.y.toString() + "|" + anObj.className + "|" + parseArrayToStringSource(anObj.attribute) + "|" + parseArrayToStringSource(anObj.constructorArgs));
294 this.networkManager.RequestObjectDisableCache(request);
295 request.send(aData.data);
297 if(request.status == 0){
298 alert("ネットワークにアクセスできません。" + this.status + ":" + this.statusText);
299 }else if((200 <= request.status && request.status < 300) || (request.status == 304)){
300 var res = request.responseText;
301 if(isValidResponseText(res)){
302 var retArray = eval(res);
303 this.timeStamp = retArray[0];
304 //割り当てられたobjectIDを設定する
305 for(var i = 0; i < stage.globalStageObjectList.length; i++){
306 stage.globalStageObjectList[i].objectID = retArray[1][i];
308 //すでにステージ上にある他のユーザーのオブジェクトを追加する
309 for(var i = 0; i < retArray[2].length; i++){
310 var anArray = retArray[2][i];
311 var args = eval(anArray[7]);
312 var anObject = eval("new " + anArray[5] + "(stage, args);");
314 this.debugOut("Network:addObject:ObjectID=" + anArray[0] + "\n");
315 anObject.objectID = anArray[0];
316 anObject.origin.x = anArray[1];
317 anObject.origin.y = anArray[2];
318 anObject.movingSpeed.x = anArray[3];
319 anObject.movingSpeed.y = anArray[4];
320 anObject.attribute = eval(anArray[6]);
321 stage.addStageObject(anObject, true);
326 alert("サーバーがエラーを返しました。" + this.status + ":" + this.statusText);
330 //runningStageに登録することで、イベントの通知が開始され、GameStageは実行状態に入る。
331 mainManager.runningStage = stage;
333 pauseStage: function(func){
334 //ステージの実行を一時停止する。一時停止中、funcに指定された関数が毎tick毎に呼ばれる
335 if(this.stagePausedFunction == null){
336 this.stagePausedFunction = func;
339 //ステージが一時停止中のfunc()の中から二重にpauseStage()を呼んではいけない
343 resumeStage: function(){
345 if(this.stagePausedFunction != null) {
346 //必ずpauseStage()の引数に指定したfunc()の中から呼ばれる・・・はず。
347 this.stagePausedFunction = null;
353 stopStage: function(){
355 if(this.runningStage){
356 //runningStageから設定解除することで、イベントの通知は行われなくなる。
357 var aGameStage = this.runningStage;
358 this.runningStage = null;
359 //GameStage側の終了処理を行わせる。
360 aGameStage.stopStage();
361 //GameStageインスタンスからGameManagerの情報を削除する。
362 aGameStage.manager = null;
363 aGameStage.mainCanvas = null;
364 aGameStage.debugCanvas = null;
365 aGameStage.mainContext = null;
366 aGameStage.debugContext = null;
369 loadStageFromLocal: function(code){
371 URL_PCD_Auth = URL_PCD_Root + "auth.php";
372 URL_PCD_Audio = URL_PCD_Root + "audio/";
373 URL_PCD_Stage = URL_PCD_Root + "stage/";
374 var stage = eval(code);
375 mainManager.runStage(stage);
377 loadStageFromNetwork: function(name){
378 //URL_PCD_Stage/name.jsを利用してステージを作成する。
379 request = this.networkManager.CreateRequestObject();
381 request.open('GET', URL_PCD_Stage + name + ".js", false);
382 this.networkManager.RequestObjectDisableCache(request);
385 if(request.status == 0){
386 alert("ネットワークにアクセスできません。" + request.status + ":" + request.statusText);
387 }else if((200 <= request.status && request.status < 300) || (request.status == 304)){
388 var stage = eval(request.responseText);
389 mainManager.runStage(stage);
391 alert("サーバーがエラーを返しました。" + request.status + ":" + request.statusText);
393 //なんでここ以下の文がIEでは実行されないの????
396 debugOut: function(str){
400 this.debugText.value = str.replace(/\n/g,"\r\n") + this.debugText.value;
403 this.debugText.innerHTML = str + this.debugText.value;
406 isAvailableBrowser: function(){
407 //ブラウザの判別を行う。実行不可能な場合はfalseを返す。
408 //http://d.hatena.ne.jp/Naotsugu/20110927/1317140891
409 var userAgent = window.navigator.userAgent.toLowerCase();
410 var appVersion = window.navigator.appVersion.toLowerCase();
412 if (userAgent.indexOf('opera') != -1) {
414 this.debugOut("Browser:Opera\n");
415 } else if (userAgent.indexOf('msie') != -1) {
416 if (appVersion.indexOf("msie 9.") != -1) {
418 this.debugOut("Browser:IE9\n");
419 } else if (appVersion.indexOf("msie 8.") != -1) {
421 this.debugOut("Browser:IE8\n");
422 } else if (appVersion.indexOf("msie 7.") != -1) {
424 this.debugOut("Browser:IE7\n");
425 } else if (appVersion.indexOf("msie 6.") != -1) {
427 this.debugOut("Browser:IE6\n");
429 this.debugOut("Browser:IE?\n");
432 } else if (userAgent.indexOf('chrome') != -1) {
434 this.debugOut("Browser:Chrome\n");
435 } else if (userAgent.indexOf('safari') != -1) {
437 this.debugOut("Browser:Safari\n");
438 } else if (userAgent.indexOf('gecko') != -1) {
440 this.debugOut("Browser:Gecko\n");
443 this.debugOut("Browser:Unknown\n");
445 //this.debugOut(userAgent + "::" + appVersion + "\n");
446 //描画コンテキストからHTML5対応チェック
447 if(!this.mainCanvas || !this.mainCanvas.getContext){
449 alert("このゲームを遊ぶためには、HTML5に対応しているブラウザ(Google Chrome等)でアクセスしてください...。");
454 setBackgroundMusic: function(name){
456 if(this.backgroundMusic){
458 this.backgroundMusic.pause();
459 this.backgroundMusic = null;
462 //引数がnullでなければaudioオブジェクトを取得
463 this.backgroundMusic = createAudio(name);
464 if(this.backgroundMusic){
466 this.backgroundMusic.loop = true;
467 this.backgroundMusic.play();
476 //イベントリスナーにおけるthisは、イベントリスナーを登録したオブジェクトまたはwindowになり、通常とは異なるので注意。
478 function keyDownEventListener(event)
480 keyDownEventListener.manager.keyDown(event);
483 function keyUpEventListener(event)
485 keyUpEventListener.manager.keyUp(event);
486 event.preventDefault();
489 function timerTickEventListener(event)
491 timerTickEventListener.manager.timerTick(event);
494 function timeStampTimerTickEventListener(event)
496 timerTickEventListener.manager.timeStampTimerTick(event);