OSDN Git Service

ローカル開発環境など
[h58pcdgame/GameScriptCoreLibrary.git] / www / corelib / core.js
1 /*
2 ****PCD-2013 GameScriptCoreLibrary****
3 Tokyo Gakugei University Senior High School.
4
5 <Usage>
6 HTMLソース側に、
7 <div id="MainArea">
8 </div>
9 <div id="Resources">
10 </div>
11 が必要。
12
13 <Javascript Tips>
14 document.getElementById("main").style.display = "none";
15 (mainというIDが振られている要素の表示を消す)
16 this.effectSound.pause();
17 this.effectSound.currentTime = 0;
18 this.effectSound.play();
19 this.backgroundImage = new Image();
20 this.backgroundMusic = document.getElementById('BGM006');
21 this.effectSound = document.getElementById('SE_Select');
22 画像読み込み
23 this.backgroundImage.manager = this;
24 this.backgroundImage.onload = this.backgroundLoaded;
25 this.backgroundImage.src = "title.gif";
26
27 音楽再生
28 this.backgroundMusic.loop = true;
29 this.backgroundMusic.play();
30
31 MicrosoftInternetExplorerでは、ローカル変数でparentを使うとappendChildが使えなくなる…。
32
33 IEではXMLHTTPRequest.onreadystatechangeのthisの値が他と異なるようだ。
34 なので、
35 request.onreadystatechange = function(){
36         と無名関数で書いて、内部でrequestインスタンスを参照
37 };
38 しないとうまく動かない。
39 */
40
41 //
42 //定数
43 //
44 var URL_PCD_Root = "http://192.168.6.242/pcd2013dev/www/";
45 //var URL_PCD_Root = "http://192.168.0.8/PCD2013GSCL/www/";
46 var URL_PCD_Auth = URL_PCD_Root + "auth.php";
47 var URL_PCD_Stage = URL_PCD_Root + "stage/";
48 var URL_PCD_Stage_Local = "stage/";
49
50 //
51 //ゲームマネージャー
52 //
53
54 function GameManager(){
55         //****コンストラクタ****
56         //**インスタンス変数宣言・初期化**
57         //ユーザーID
58         this.userID = 0;
59         //ネットワークマネージャーの設定
60         this.networkManager = new NetworkManager();
61         //必要最低限のCanvasとコンテキストの設定
62         this.mainCanvas = createCanvas("MainCanvas", 640, 480, 0, 0, 1, "MainArea");
63         this.mainCanvas.style.border = "solid 1px";
64         this.debugCanvas = createCanvas("DebugCanvas", 640, 480, 0, 480, 2, "MainArea");
65         this.mainContext = this.mainCanvas.getContext('2d');
66         this.debugContext = this.debugCanvas.getContext('2d');
67         this.debugText = document.getElementById('DebugText');
68         //実行中のGameStageオブジェクトを格納
69         this.runningStage = null;
70         //タイマーカウントを初期化
71         this.tickCount = 0;
72         this.timeStamp = 0;
73         //タイマーカウントの秒あたりの回数を設定
74         this.tickPerSecond = 60;
75         this.updateIntervalMs = 250;
76         //キーボード状態を格納するプロパティの設定
77         this.keyState = new Object();
78         this.keyState.upArrow = false;
79         this.keyState.downArrow = false;
80         this.keyState.leftArrow = false;
81         this.keyState.rightArrow = false;
82         
83         //**描画コンテキスト取得、設定・HTML5対応チェック**
84         if(!this.mainCanvas || !this.mainCanvas.getContext){
85                 //HTML5未対応の場合
86                 alert("このゲームを遊ぶためには、HTML5に対応しているブラウザでアクセスしてください...。");
87                 return false;
88         }
89         
90         //**Canvas描画コンテキストの初期設定**
91         //mainContext
92         this.mainContext.fillStyle = "rgba(200,255,200,0.5)";
93         this.mainContext.strokeStyle = "rgba(0, 0, 0, 0.5)";
94         //debugContext
95         this.debugContext.fillStyle = "rgb(255,255,255)";
96         this.debugContext.strokeStyle = "rgb(0, 0, 0)";
97         this.debugContext.font = "normal 20px sans-serif";
98         
99         //**イベントリスナー設定**
100         //コールバックを行うために、イベントリスナーのmanagerプロパティにGameManagerのインスタンスを代入する。
101         //keyDown
102         keyDownEventListener.manager = this;
103         window.addEventListener('keydown', keyDownEventListener, true);
104         //keyUp
105         keyUpEventListener.manager = this;
106         window.addEventListener('keyup', keyUpEventListener, true);
107         //timerTick
108         timerTickEventListener.manager = this;
109         window.setInterval(timerTickEventListener, 1000/this.tickPerSecond);
110         timeStampTimerTickEventListener.manager = this;
111         window.setInterval(timeStampTimerTickEventListener, this.updateIntervalMs);
112 }
113 GameManager.prototype = {
114         //****プロトタイプ宣言****
115         //prototype以下のプロパティは、新規インスタンスに参照が引き継がれる。
116         keyDown: function(event){
117                 //****keyDown****
118                 //コールバックではなくコールバック関数(keyDownEventListener)から呼び出されるので、thisはGameManagerのインスタンスとなる。
119                 keyCode = event.keyCode;
120                 switch(event.keyCode){
121                         case 38:
122                                 //上カーソル
123                                 this.keyState.upArrow = true;
124                                 event.preventDefault();
125                                 break;
126                         case 40:
127                                 //下カーソル
128                                 this.keyState.downArrow = true;
129                                 event.preventDefault();
130                                 break;
131                         case 37:
132                                 //左カーソル
133                                 this.keyState.leftArrow = true;
134                                 event.preventDefault();
135                                 break;
136                         case 39:
137                                 //右カーソル
138                                 this.keyState.rightArrow = true;
139                                 event.preventDefault();
140                                 break;
141                 }
142
143                 this.debugOut("keyDw:" + keyCode + "\n");
144                 //実行中のステージに通知
145                 if(this.runningStage){
146                         this.runningStage.keyDown(event);
147                 }
148         },
149         keyUp: function(event){
150                 //****keyUp****
151                 //コールバックではなくコールバック関数(keyUpEventListener)から呼び出されるので、thisはGameManagerのインスタンスとなる。
152                 keyCode = event.keyCode;
153                 switch(event.keyCode){
154                         case 38:
155                                 //上カーソル
156                                 this.keyState.upArrow = false;
157                                 break;
158                         case 40:
159                                 //下カーソル
160                                 this.keyState.downArrow = false;
161                                 break;
162                         case 37:
163                                 //左カーソル
164                                 this.keyState.leftArrow = false;
165                                 break;
166                         case 39:
167                                 //右カーソル
168                                 this.keyState.rightArrow = false;
169                                 break;
170                 }
171
172                 this.debugOut("keyUp:" + keyCode + "\n");
173                 //実行中のステージに通知
174                 if(this.runningStage){
175                         this.runningStage.keyUp(event);
176                 }
177         },
178         timerTick: function(){
179                 //****timerTick****
180                 this.tickCount++;
181                 //実行中のステージに通知
182                 if(this.runningStage){
183                         this.runningStage.timerTick();
184                         this.runningStage.draw();
185                 }
186         },
187         timeStampTimerTick: function(){
188                 //サーバーとの同期カウンタ・タイマー
189                 //100msごとに呼ばれる
190                 this.timeStamp += this.updateIntervalMs;
191                 drawText(this.debugContext, "          timeStamp:" + this.timeStamp, 0, 40);
192                 
193                 //update
194                 if(this.userID != 0){
195                         request = this.networkManager.CreateRequestObject();
196                         request.onreadystatechange = function(){
197                                 //requestコールバックなのでthisはrequest!
198                                 //onloadedはステージプリロード用
199                                 switch(request.readyState){
200                                         case 0:
201                                                 //console.log("XMLHttpRequest created.");
202                                                 break;
203                                         case 1:
204                                                 //console.log("open() called.");
205                                                 break;
206                                         case 2:
207                                                 //console.log("Response header received.");
208                                                 break;
209                                         case 3:
210                                                 //console.log("Response body receiving.");
211                                                 break;
212                                         case 4:
213                                                 //mainManager.debugOut("send() compleated.\n");
214                                                 //mainManager.debugOut("status:" + this.status + ":" + this.statusText + "\n");
215                                                 if(request.status == 0){
216                                                         //alert("ネットワークにアクセスできません。" + this.status + ":" + this.statusText);
217                                                 }else if((200 <= request.status && request.status < 300) || (request.status == 304)){
218                                                         //console.log("ACK");
219                                                         var res = request.responseText
220                                                         this.timeStamp = eval(res);
221                                                         drawText(mainManager.debugContext, "ServertimeStamp:" + res.toString(), 0, 80);
222                                                 }else{
223                                                         //alert("サーバーがエラーを返しました。" + this.status + ":" + this.statusText);
224                                                 }
225                                                 break;
226                                 }
227                         };
228                         request.open('GET', URL_PCD_Root + "update.php?uid=" + this.userID);
229                         this.networkManager.RequestObjectDisableCache(request);
230                         request.send(null);
231                 }
232         },
233         runStage: function(stage){
234                 //****新たなステージを開始する****
235                 //実行中のステージがあれば終了処理を行わせる。
236                 if(this.runningStage){
237                         this.stopStage();
238                 }
239                 //**新たに開始するステージの初期化**
240                 //GameManager側の情報をGameStageに渡す。
241                 stage.manager = this;
242                 stage.mainCanvas = this.mainCanvas
243                 stage.debugCanvas = this.debugCanvas
244                 stage.mainContext = this.mainContext
245                 stage.debugContext = this.debugContext
246                 //GameStage側の初期化処理を行わせる。
247                 stage.runStage();
248                 //runningStageに登録することで、イベントの通知が開始され、GameStageは実行状態に入る。
249                 this.runningStage = stage;
250         },
251         stopStage: function(){
252                 //****現在実行中のステージを終了する****
253                 if(this.runningStage){
254                         //runningStageから解除することで、イベントの通知は行われなくなる。
255                         var aGameStage = this.runningStage;
256                         this.runningStage = null;
257                         //GameStage側の終了処理を行わせる。
258                         aGameStage.stopStage();
259                         //GameStageインスタンスからGameManagerの情報を削除する。
260                         aGameStage.manager = null;
261                         aGameStage.mainCanvas = null;
262                         aGameStage.debugCanvas = null;
263                         aGameStage.mainContext = null;
264                         aGameStage.debugContext = null;
265                 }
266         },
267         loadStageFromLocal: function(code, onLoaded){
268                 var ____stage = eval(code);
269                 mainManager.runStage(____stage);
270         },
271         loadStageFromNetwork: function(name, onLoaded){
272                 //urlに存在するjavascriptファイルを利用してステージを作成する。
273                 request = this.networkManager.CreateRequestObject();
274                 request.onreadystatechange = function(){
275                         //requestコールバックなのでthisはrequest!とは限らない(IE)
276                         console.log("state:" + request.readyState);
277                         switch(request.readyState){
278                                 case 0:
279                                         //console.log("XMLHttpRequest created.");
280                                         break;
281                                 case 1:
282                                         //console.log("open() called.");
283                                         break;
284                                 case 2:
285                                         //console.log("Response header received.");
286                                         break;
287                                 case 3:
288                                         //console.log("Response body receiving.");
289                                         break;
290                                 case 4:
291                                         //mainManager.debugOut("send() compleated.\n");
292                                         //mainManager.debugOut("status:" + this.status + ":" + this.statusText + "\n");
293                                         if(request.status == 0){
294                                                 alert("ネットワークにアクセスできません。" + request.status + ":" + request.statusText);
295                                         }else if((200 <= request.status && request.status < 300) || (request.status == 304)){
296                                                 //console.log("ACK");
297                                                 var stage = eval(request.responseText);
298                                                 mainManager.runStage(stage);
299                                         }else{
300                                                 alert("サーバーがエラーを返しました。" + request.status + ":" + request.statusText);
301                                         }
302                                         break;
303                         }
304                 };
305                 request.open('GET', URL_PCD_Stage + name + ".js");
306                 this.networkManager.RequestObjectDisableCache(request);
307                 //IEで使えない…
308                 //console.log("reqObject:" + request.toString());
309                 request.send(null);
310         },
311         debugOut: function(str){
312                 if(!/*@cc_on!@*/false)
313                 {
314                         this.debugText.value = str.replace(/\n/g,"\r\n") + this.debugText.value;
315                 }
316                 else
317                 {
318                         this.debugText.innerHTML = str + this.debugText.value;
319                 }
320         },
321 };
322
323
324
325
326 //
327 //その他のクラス
328 //
329
330 function Point2D(x, y){
331         this.x = x;
332         this.y = y;
333 }
334 Point2D.prototype = {
335         
336 }
337
338 function Rectangle(x, y, width, height){
339         this.origin = new Point2D(x,y);
340         this.size = new Point2D(width,height);
341 }
342 Rectangle.prototype = {
343         
344 }
345
346 function ResourceManager(){
347         //Not implemented.
348     this.resourceObjectList = new Array();
349     
350         this.ResourceTag.prototype = {
351         
352     }
353 }
354 ResourceManager.prototype = {
355         //Not implemented.
356     addAudioResource: function(id, src){
357         dobj = document.createElement("audio");
358         parent = document.getElementById("Resources");
359         dobj.id = id;
360         parent.appendChild(dobj);
361         
362         this.resourceObjectList.push(dobj);
363         
364         dobj.isLoaded = false;
365         dobj.onload = this.resourceLoaded;
366         dobj.src = src;
367     },
368     resourceLoaded: function(){
369         //コールバック関数のthisはコールバック関数の設定先オブジェクト(DOMObject)となる。
370         this.isLoaded = true;
371     },
372     waitForLoadResource: function(){
373         for(;;){
374             for(i = 0; i < resourceObjectList.length; i++){
375                 if(!resourceObjectList[i].isLoaded){
376                     
377                     break;
378                 }
379             }
380             if(i == resourceObjectList.length){
381                 return;
382             }
383         }
384     },
385 }
386
387 function NetworkManager(){
388
389 }
390 NetworkManager.prototype = {
391 //from http://hakuhin.jp/js/xmlhttprequest.html
392         CreateRequestObject: function(){
393                 var rq = null;
394                 // XMLHttpRequest
395                 try{
396                         // XMLHttpRequest オブジェクトを作成
397                         rq = new XMLHttpRequest();
398                 }catch(e){}
399                 // Internet Explorer
400                 try{
401                         rq = new ActiveXObject('MSXML2.XMLHTTP.6.0');
402                 }catch(e){}
403                 try{
404                         rq = new ActiveXObject('MSXML2.XMLHTTP.3.0');
405                 }catch(e){}
406                 try{
407                         rq = new ActiveXObject('MSXML2.XMLHTTP');
408                 }catch(e){}
409                 if(rq == null){
410                         return null;
411                 }
412                 return rq;
413         },
414         RequestObjectDisableCache: function(rq){
415                 //call after open request.
416                 //disable cache
417                 //http://vird2002.s8.xrea.com/javascript/XMLHttpRequest.html
418                 rq.setRequestHeader('Pragma', 'no-cache');                              // HTTP/1.0 における汎用のヘッダフィールド
419                 rq.setRequestHeader('Cache-Control', 'no-cache');               // HTTP/1.1 におけるキャッシュ制御のヘッダフィールド
420                 rq.setRequestHeader('If-Modified-Since', 'Thu, 01 Jun 1970 00:00:00 GMT');
421                 
422         },
423 }
424
425 //
426 //サブルーチン
427 //
428
429 function createCanvas(id, width, height, x, y, z, parent)
430 {
431         //識別名idで
432         //width * heightの大きさのCanvasを
433         //(x,y,z)に生成する。
434         //parentには、Canvasタグを包含することになるDOMオブジェクトのidを指定する。
435         canvas = document.createElement("canvas");
436         parent = document.getElementById(parent);
437
438         canvas.id = id;
439
440         parent.appendChild(canvas);
441
442         canvas.style.position = "absolute";
443         canvas.style.top = y + "px";
444         canvas.style.left = x + "px";
445         canvas.style.zIndex = z;
446
447         canvas.width = width;
448         canvas.height = height;
449
450         return canvas;
451 }
452
453 function createDOMObject(typestr, idstr, parentidstr)
454 {
455         dobj = document.createElement(typestr);
456         parentObj = document.getElementById(parentidstr);
457         
458         dobj.id = idstr;
459         parentObj.appendChild(dobj);
460         
461         return dobj;
462 }
463
464 function destroyDOMObjectByID(id)
465 {
466         //識別名idのDOMオブジェクトを破棄する。
467         object = document.getElementById(id);
468         parentObj = object.parentNode;
469
470         parentObj.removeChild(object);
471 }
472
473 function removeObjectFromArray(anArray, anObject)
474 {
475         //anArray中にある全てのanObjectを削除し、空いた部分は前につめる。
476         for(i = 0; i < anArray.length; i++){
477                 if(anArray[i] == anObject){
478                         anArray.splice(i, 1);
479                 }
480         }
481 }
482
483 //
484 //イベントリスナー
485 //
486 //イベントリスナーにおけるthisは、イベントリスナーを登録したオブジェクトになり、通常とは異なるので注意。
487
488 function keyDownEventListener(event)
489 {
490         keyDownEventListener.manager.keyDown(event);
491 }
492
493 function keyUpEventListener(event)
494 {
495         keyUpEventListener.manager.keyUp(event);
496         event.preventDefault();
497 }
498
499 function timerTickEventListener(event)
500 {
501         timerTickEventListener.manager.timerTick(event);
502 }
503
504 function timeStampTimerTickEventListener(event)
505 {
506         timerTickEventListener.manager.timeStampTimerTick(event);
507 }
508
509 //
510 //Canvas直接描画関連
511 //
512
513 function drawText(gcontext, text, x, y)
514 {
515         //背景をfillStyle
516         //前景をstrokeStyleで塗りつぶした文字列を描画する
517         //塗りつぶし高さは20px固定
518         //fillTextの座標は文字列の左下!
519         textsize = gcontext.measureText(text);
520         gcontext.fillRect(x, y, textsize.width, 20);
521         gcontext.save();
522         gcontext.fillStyle = gcontext.strokeStyle;
523         gcontext.fillText(text, x, y + 20 - 1);
524         gcontext.restore();
525 }
526
527 function drawArcDegree(gcontext, radius, startAngleDegree, endAngleDegree, x, y, anticlockwise)
528 {
529         //半径radius, 中心座標(x,y)の円弧の、
530         //startAngleDegreeからendAngleDegreeまでの範囲を、
531         //(!anticlockwise)=時計回り
532         //(anticlockwise) =反時計回り
533         //に描画する。
534         //角度は度を利用する。
535         startAngleRadian = startAngleDegree * Math.PI / 180;
536         endAngleRadian = endAngleDegree * Math.PI / 180;
537         
538         gcontext.beginPath();
539         gcontext.arc(drawCoordinatesInInteger(x), drawCoordinatesInInteger(y), drawCoordinatesInInteger(radius), startAngleRadian, endAngleRadian, anticlockwise);
540         gcontext.fill();
541         gcontext.stroke();
542         gcontext.closePath();
543 }
544
545 function fillRect(gContext, x, y, w, h)
546 {
547         gContext.fillRect(drawCoordinatesInInteger(x), drawCoordinatesInInteger(y), drawCoordinatesInInteger(w), drawCoordinatesInInteger(h));
548 }
549
550 function strokeRect(gContext, x, y, w, h)
551 {
552         gContext.strokeRect(drawCoordinatesInInteger(x), drawCoordinatesInInteger(y), drawCoordinatesInInteger(w), drawCoordinatesInInteger(h));
553 }
554
555 function drawCoordinatesInInteger(coordinateElement)
556 {
557         //from http://www.html5rocks.com/ja/tutorials/canvas/performance/
558         // With a bitwise or.
559         return ((0.5 + coordinateElement) | 0);
560 }
561
562