OSDN Git Service

html の修繕
[h58pcdgame/GameScriptCoreLibrary.git] / www / corelib / core.js
1 /*
2 ****PCD-2013 GameScriptCoreLibrary****
3 Tokyo Gakugei University Senior High School.
4
5 <クライアント要件>
6 Mac OSX: Safari, Chrome
7 Windows: Chrome, IE(9 or later)
8
9 以下の技術が実行可能である必要があります:
10 HTML5
11         Canvas
12         FormData
13
14 <Usage>
15 HTMLソース側に、
16 <div id="MainArea">
17 </div>
18 <div id="Resources">
19 </div>
20 および
21 mainManager = new GameManager();
22 が必要。
23 */
24
25 //
26 //定数
27 //
28
29 var loc = document.location.href;
30
31 var URL_PCD_Root = loc.slice(0, loc.lastIndexOf("/") + 1);
32
33 //var URL_PCD_Root = "http://localhost/pcd2013dev/www/";
34 //var URL_PCD_Root = "http://192.168.6.242/pcd2013dev/www/";
35 //var URL_PCD_Root = "http://192.168.0.3/PCD2013GSCL/www/";
36 //var URL_PCD_Root = "http://192.168.6.242/pcd2013hikarupsp/pcd2013dev/www/";
37 var URL_PCD_Auth = URL_PCD_Root + "auth.php";
38 var URL_PCD_Audio = URL_PCD_Root + "audio/";
39 var URL_PCD_Stage = URL_PCD_Root + "stage/";
40
41 // ゲームを呼び出す関数       適切なdiv要素で呼び出すとゲームを初期化できる。
42 // つまり、自作ゲームをしたい場合
43 // audio, corelib, images, stageの各フォルダをコピーしたdirにhtmlを置き、<div>.InitGameManager() と実行するスクリプトを書く
44 // stageName == nullだとステージを開始しない。指定する時は.jsおよびパスを省く
45
46 HTMLDivElement.prototype.InitGameManager = function(stageName)
47 {
48         if(this instanceof HTMLDivElement)
49         {
50                 var man = new GameManager(this, null);
51                 if(stageName) man.loadStageFromNetwork.apply(man, [stageName]);
52                 return man;
53         }else
54         {
55                 throw new TypeError("InitGameManager はdiv要素にしか実行できません");
56         }
57 };
58
59 //
60 //ゲームマネージャー
61 //
62
63 function GameManager(parent, debugTextName){
64         
65         //引数チェック
66         if(debugTextName == undefined) debugTextName = "DebugText";
67         if(parent == undefined) parent = document.getElementById("MainArea");
68         
69         //parentの初期設定
70         if(parent.style.position != 'absolute') parent.style.position = 'relative';
71         
72         this.userID = 0;
73         //サブマネージャーの設定
74         this.networkManager = new NetworkManager(this);
75         this.UIManager = new UIManager(this);
76         this.userManager = new UserManager(this);
77         this.mainArea = parent;
78         //必要最低限のCanvasとコンテキストの設定
79         this.mainCanvas = createCanvas("MainCanvas", 640, 480, 0, 0, 1, parent);
80         this.mainCanvas.style.border = "solid 1px";
81         this.mainContext = this.mainCanvas.getContext('2d');
82         this.debugText = document.getElementById(debugTextName);        //要素が存在しないとnullになり、デバッグが無効になる
83         if(!this.debugText) this.debugText = null;
84         
85         // ステージのデバッグ表示を有効にするか
86         this.enableStageDebug = false;
87
88         
89         //ブラウザチェック
90         this.isIE = false;
91         if(!this.isAvailableBrowser()){
92                 return null;
93         }
94         //描画コンテキストの初期設定
95         this.mainContext.fillStyle = "rgba(200,255,200,0.5)";
96         this.mainContext.strokeStyle = "rgba(0, 0, 0, 0.5)";
97         this.mainContext.font = "normal 20px sans-serif";
98         //実行中のGameStageオブジェクトを格納
99         this.runningStage = null;
100         //現在存在しているWidghetのリストを格納
101         this.runningWidghets = [];
102         
103         //タイマーカウントを初期化
104         this.tickCount = 0;
105         //タイマーカウントの秒あたりの回数を設定
106         this.tickPerSecond = 60;
107         // pauseStage()が呼ばれたときにnullじゃなくなる
108         this.stagePausedFunction = null;
109         
110         this.backgroundMusic = null;
111         this.addWidget(new UserStateWidgetClass(this));
112         //**イベントリスナー設定**
113         //コールバックを行うために、イベントリスナーのmanagerプロパティにGameManagerのインスタンスを代入する。
114         //timerTick
115         timerTickEventListener.manager = this;
116         window.setInterval(timerTickEventListener, 1000/this.tickPerSecond);
117 }
118 GameManager.prototype = {
119         timerTick: function(){
120                 //各オブジェクトの単位時間ごとの動作と再描画を行う
121                 //単位時間ごとの動作
122                 this.tickCount++;
123                 if(this.stagePausedFunction == null){
124                         //ポーズしていなければ更新処理
125                         if(this.runningStage){
126                                 //ステージ
127                                 this.runningStage.timerTick();
128                         }
129                 }
130                 // runningStage.timerTick() 内でpauseStage()された時、ここで再度判定しないとWidghetのtickが実行されてしまう
131                 if(this.stagePausedFunction == null){
132                         //ウィジェット
133                         for(var i = 0; i < this.runningWidghets.length; i++){
134                                 var w = this.runningWidghets[i];
135                                 if(!w.tick()){
136                                         // Widghetのtick()からfalseで帰ってきたらWidghetを開放
137                                         this.removeWidget(w);
138                                         i--;
139                                 }
140                         }
141                 } else{
142                         //ポーズしているならば処理関数を実行
143                         this.stagePausedFunction();
144                 }
145                 
146                 //描画処理
147                 if(this.runningStage){
148                         //ステージ
149                         this.runningStage.draw();
150                 }
151                 //ウィジェット
152                 for(var i = 0; i < this.runningWidghets.length; i++){
153                         var w = this.runningWidghets[i];
154                         w.draw();
155                 }
156         },
157         addWidget: function(w){
158                 w.attach();
159                 this.runningWidghets.push(w);
160         },
161         removeWidget: function(w){
162                 removeObjectFromArray(this.runningWidghets, w);
163                 w.detach();
164         },
165         runStage: function(stage){
166                 //新たなステージを開始する
167                 //実行中のステージがあれば終了処理を行わせる。
168                 if(this.runningStage){
169                         this.stopStage();
170                 }
171                 //新たに開始するステージの初期化
172                 //GameManager側の情報をGameStageに渡す。
173                 stage.manager = this;
174                 stage.mainCanvas = this.mainCanvas
175                 stage.debugCanvas = this.debugCanvas
176                 stage.mainContext = this.mainContext
177                 stage.debugContext = this.debugContext
178                 //GameStage側の初期化処理を行わせる。
179                 stage.runStage();
180                 //ネットワーク同期初期化
181                 this.networkManager.joinStage(stage);
182                 //runningStageに登録することで、イベントの通知が開始され、GameStageは実行状態に入る。
183                 this.runningStage = stage;
184         },
185         pauseStage: function(func){
186                 //ステージの実行を一時停止する。一時停止中、funcに指定された関数が毎tick毎に呼ばれる
187                 if(this.stagePausedFunction == null){
188                         this.stagePausedFunction = func;
189                         return true;
190                 } else{
191                         //ステージが一時停止中のfunc()の中から二重にpauseStage()を呼んではいけない
192                         return false;
193                 }
194         },
195         resumeStage: function(){
196                 //ステージの実行を再開する
197                 if(this.stagePausedFunction != null) {
198                         //必ずpauseStage()の引数に指定したfunc()の中から呼ばれる・・・はず。
199                         this.stagePausedFunction = null;
200                         return true;
201                 } else{
202                         return false;
203                 }
204         },
205         stopStage: function(){
206                 //現在実行中のステージを終了する
207                 if(this.runningStage){
208                         //runningStageから設定解除することで、イベントの通知は行われなくなる。
209                         var aGameStage = this.runningStage;
210                         this.runningStage = null;
211                         //GameStage側の終了処理を行わせる。
212                         aGameStage.stopStage();
213                         //GameStageインスタンスからGameManagerの情報を削除する。
214                         aGameStage.manager = null;
215                         aGameStage.mainCanvas = null;
216                         aGameStage.debugCanvas = null;
217                         aGameStage.mainContext = null;
218                         aGameStage.debugContext = null;
219                 }
220         },
221         loadStageFromLocal: function(code){
222                 //各種パスをローカル用に変更
223                 URL_PCD_Root = "./";
224                 URL_PCD_Auth = URL_PCD_Root + "auth.php";
225                 URL_PCD_Audio = URL_PCD_Root + "audio/";
226                 URL_PCD_Stage = URL_PCD_Root + "stage/";
227                 
228                 var stage = eval(code);
229                 mainManager.runStage(stage);
230         },
231         loadStageFromNetwork: function(name){
232                 //URL_PCD_Stage/name.jsを利用してステージを作成する。
233                 request = this.networkManager.CreateRequestObject();
234                 //同期モード
235                 request.open('GET', URL_PCD_Stage + name + ".js", false);
236                 this.networkManager.RequestObjectDisableCache(request);
237                 request.send(null);
238                 
239                 if(request.status == 0){
240                         alert("ネットワークにアクセスできません。" + request.status + ":" + request.statusText);
241                 }else if((200 <= request.status && request.status < 300) || (request.status == 304)){
242                         var stage = eval(request.responseText);
243                         mainManager.runStage(stage);
244                 }else{
245                         alert("サーバーがエラーを返しました。" + request.status + ":" + request.statusText);
246                 }
247         },
248         debugOut: function(str){
249                 if(this.debugText != null)
250                 {
251                         if(this.isIE)
252                         {
253                                 //CRLF
254                                 this.debugText.value = str.replace(/\n/g,"\r\n") + this.debugText.value;
255                         } else{
256                                 //LF
257                                 this.debugText.innerHTML = str + this.debugText.value;
258                         }
259                 }
260         },
261         isAvailableBrowser: function(){
262                 //ブラウザの判別を行う。実行不可能な場合はfalseを返す。
263                 //http://d.hatena.ne.jp/Naotsugu/20110927/1317140891
264                 var userAgent = window.navigator.userAgent.toLowerCase();
265                 var appVersion = window.navigator.appVersion.toLowerCase();
266                 
267                 if (userAgent.indexOf('opera') != -1) {
268                         //opera
269                         this.debugOut("Browser:Opera\n");
270                 } else if (userAgent.indexOf('msie') != -1) {
271                         if (appVersion.indexOf("msie 9.") != -1) {
272                                 //ie9
273                                 this.debugOut("Browser:IE9\n");
274                         } else if (appVersion.indexOf("msie 8.") != -1) {
275                                 //ie8
276                                 this.debugOut("Browser:IE8\n");
277                         } else if (appVersion.indexOf("msie 7.") != -1) {
278                                 //ie7
279                                 this.debugOut("Browser:IE7\n");
280                         } else if (appVersion.indexOf("msie 6.") != -1) {
281                                 //ie6
282                                 this.debugOut("Browser:IE6\n");
283                         } else{
284                                 this.debugOut("Browser:IE?\n");
285                         }
286                         this.isIE = true;
287                 } else if (userAgent.indexOf('chrome') != -1) {
288                         //chrome
289                         this.debugOut("Browser:Chrome\n");
290                 } else if (userAgent.indexOf('safari') != -1) {
291                         //safari
292                         this.debugOut("Browser:Safari\n");
293                 } else if (userAgent.indexOf('gecko') != -1) {
294                         //gecko
295                         this.debugOut("Browser:Gecko\n");
296                 } else {
297                         //unknown
298                         this.debugOut("Browser:Unknown\n");
299                 }
300                 //描画コンテキストからHTML5対応チェック
301                         if(!this.mainCanvas || !this.mainCanvas.getContext){
302                                 //HTML5未対応の場合
303                                 alert("このゲームを遊ぶためには、HTML5に対応しているブラウザ(Google Chrome等)でアクセスしてください...。");
304                         return false;
305                 }
306                 return true;
307         },
308         setBackgroundMusic: function(name){
309                 if(this.backgroundMusic){
310                         //再生していたら止める
311                         this.backgroundMusic.pause();
312                         this.backgroundMusic = null;
313                 }
314                 if(name){
315                         //引数がnullでなければaudioオブジェクトを取得
316                         this.backgroundMusic = createAudio(name);
317                         if(this.backgroundMusic){
318                                 //ループを設定して再生開始
319                                 this.backgroundMusic.loop = true;
320                                 this.backgroundMusic.play();
321                         }
322                 }
323         },
324 };
325
326 //
327 //イベントリスナー
328 //
329 //イベントリスナーにおけるthisは、イベントリスナーを登録したオブジェクトまたはwindowになり、通常とは異なるので注意。
330
331 function timerTickEventListener(event)
332 {
333         timerTickEventListener.manager.timerTick(event);
334 }