OSDN Git Service

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