source: pycodeshooter/trunk/shooter/system.js @ 122

Revision 122, 14.6 KB checked in by atzm, 12 years ago (diff)

add stage bgm rotation

  • Property svn:keywords set to Id
Line 
1/* -*- coding: utf-8 -*-
2 *
3 * Copyright (C) 2010 by Atzm WATANABE <atzm@atzm.org>
4 *
5 *  This program is free software; you can redistribute it and/or modify it
6 *  under the terms of the GNU General Public License (version 2) as
7 *  published by the Free Software Foundation.  It is distributed in the
8 *  hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
9 *  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
10 *  PURPOSE.  See the GNU General Public License for more details.
11 *
12 * $Id$
13 *
14 */
15
16System = {
17    "screen": {
18        "canvas": null,
19        "ctx":    null,
20        "width":  0,
21        "height": 0
22    },
23    "sound":            {},
24    "message":          null,
25    "enemyImages":      new Array(),
26    "enemies":          new Array(),
27    "players":          new Array(),
28    "score":            {},
29    "backgroundObject": new Array(),
30    "deathPieces":      new Array(),
31    "mainIntervalId":   0
32};
33
34
35/*
36 *  Tiun Tiun Utilities
37 */
38var DeathPiece = function(sizes, colors, x, y, dir, speed) {
39    var that = new LinerBullet(sizes[0], colors[0], null,
40                               System.screen.width, System.screen.height,
41                               x, y, dir, speed);
42
43    var sizeIdx  = -1;
44    var colorIdx = -1;
45
46    that.getSize = function() {
47        if (++sizeIdx >= sizes.length)
48            sizeIdx = 0;
49        return sizes[sizeIdx];
50    };
51
52    that.getColor = function() {
53        if (++colorIdx >= colors.length)
54            colorIdx = 0;
55        return colors[colorIdx];
56    };
57
58    return that;
59};
60
61function addDeathPieces(x, y, sizes, colors, speed, way) {
62    if (way % 2)
63        way++;
64
65    var pieces = new Array();
66    var angle  = 0;
67    var delta  = 2 / way;
68
69    for(var i = 0; i < way; i++) {
70        pieces.push(new DeathPiece(sizes, colors, x, y, angle * Math.PI, speed));
71        angle += delta;
72    }
73
74    System.deathPieces.push(pieces);
75}
76
77function updateDeathPieces(ctx, width, height) {
78    var newObjs = new Array();
79
80    for (var i = 0; i < System.deathPieces.length; i++) {
81        var pieces    = System.deathPieces[i];
82        var newPieces = new Array();
83
84        for (var k = 0; k < pieces.length; k++) {
85            pieces[k].next();
86            pieces[k].draw(ctx);
87            if (!pieces[k].vanished(width, height))
88                newPieces.push(pieces[k]);
89        }
90
91        if (newPieces.length)
92            newObjs.push(newPieces);
93    }
94
95    System.deathPieces = newObjs;
96}
97
98
99/*
100 *  Utility Functions
101 */
102function setMessage(elem, msg) {
103    if (elem)
104        elem.innerHTML = msg;
105}
106
107function addMessage(elem, msg) {
108    if (elem)
109        elem.innerHTML += msg;
110}
111
112function updateBackground(ctx, width, height, size, color, max) {
113    if (System.backgroundObject.length < max) {
114        var x = Math.ceil(Math.random() * width);
115        var s = Math.ceil(Math.random() * 5);
116        System.backgroundObject.push(
117            new LinerBullet(size, color, null,
118                            System.screen.width, System.screen.height,
119                            x, 0, 0.5 * Math.PI, s));
120    }
121
122    var newObjs = new Array();
123
124    for (var i = 0; i < System.backgroundObject.length; i++) {
125        System.backgroundObject[i].next();
126        System.backgroundObject[i].draw(ctx);
127        if (!System.backgroundObject[i].vanished(width, height))
128            newObjs.push(System.backgroundObject[i]);
129    }
130
131    System.backgroundObject = newObjs;
132}
133
134function drawScreen(ctx, op, style, width, height) {
135    var c = ctx.globalCompositeOperation;
136    ctx.globalCompositeOperation = op;
137    ctx.beginPath();
138    ctx.fillStyle = style;
139    ctx.fillRect(0, 0, width, height);
140    ctx.fill();
141    ctx.closePath();
142    ctx.globalCompositeOperation = c;
143}
144
145function drawLifeGauge(ctx, op, trooper, x, y, width) {
146    var length = trooper.life;
147
148    if (length > width - 20)
149        length = width - 20;
150
151    var c = ctx.globalCompositeOperation;
152    ctx.globalCompositeOperation = op;
153    ctx.beginPath();
154    ctx.fillStyle = trooper.color;
155    ctx.fillRect(x, y, length, 10);
156    ctx.fill();
157    ctx.closePath();
158    ctx.globalCompositeOperation = c;
159
160    drawString(ctx, op, trooper.life, x + 2, y + 8, trooper.color,
161               "6pt monospace", "left");
162}
163
164function drawString(ctx, op, string, x, y, color, font, align) {
165    var a = ctx.textAlign;
166    var f = ctx.font;
167    var c = ctx.globalCompositeOperation;
168    ctx.globalCompositeOperation = op;
169    ctx.beginPath();
170    ctx.textAlign = align;
171    ctx.fillStyle = color;
172    ctx.font      = font;
173    ctx.fillText(string, x, y);
174    ctx.fill();
175    ctx.textAlign = a;
176    ctx.font      = f;
177    ctx.closePath();
178    ctx.globalCompositeOperation = c;
179}
180
181function updateTrooper(trooper, enemyKey) {
182    trooper.update(System[enemyKey]);
183
184    var aliveEnemies = new Array();
185    for (var i = 0; i < System[enemyKey].length; i++) {
186        var enemy = System[enemyKey][i];
187
188        if (enemy.isDead()) {
189            playSound("se_destroy");
190
191            addDeathPieces(
192                enemy.x, enemy.y,
193                [6, 8, 10], ["#55F", "#AAF"], 3, 8
194            );
195
196            if (System.score[trooper.name] !== undefined) {
197                System.score[trooper.name] += enemy.maxLife * 100;
198            }
199        }
200        else {
201            aliveEnemies.push(enemy);
202        }
203    }
204    System[enemyKey] = aliveEnemies;
205
206    trooper.draw(System.screen.ctx);
207}
208
209function switchStageBgm() {
210    var sum    = 0;
211    var stage  = 1;
212    var stages = new Array();
213    var base   = 50000;
214    var score  = 0;
215    var scores = Object.keys(System.score);
216
217    for (var i = 0; i < scores.length; i++) {
218        sum += System.score[scores[i]];
219    }
220    score = Math.round(sum / scores.length);
221
222    for (var name in System.sound) {
223        if (!name.match(/^bgm_stage/)) continue;
224        stages.push(name);
225    }
226    stage = Math.floor((score % (stages.length * base)) / base) + 1;
227
228    for (var i = 0; i < stages.length; i++) {
229        if (("bgm_stage" + stage) == stages[i]) {
230            playSound(stages[i]);
231        }
232        else {
233            pauseSound(stages[i], true);
234        }
235    }
236}
237
238function toggleSound(val) {
239    for (var name in System.sound)
240        System.sound[name].muted = !val;
241}
242
243function registerSound(name, audio) {
244    System.sound[name] = audio;
245}
246
247function playSound(name) {
248    if (System.sound[name])
249        System.sound[name].play();
250}
251
252function pauseSound(name, stop) {
253    if (System.sound[name]) {
254        System.sound[name].pause();
255        if (stop)
256            System.sound[name].currentTime = 0;
257    }
258}
259
260function numEnemies() {
261    return System.enemies.length;
262}
263
264function addEnemyImage(image) {
265    System.enemyImages.push(image);
266}
267
268function addEnemy(enemyData) {
269    var actList = EnemyActionLists[enemyData.mtime % EnemyActionLists.length];
270    var shot    = EnemyShots[enemyData.hitpoint % EnemyShots.length];
271    var numAct  = enemyData.agility       % (EnemyActions.length  - 1) + 1;
272    var numBlt  = enemyData.skills.length % (EnemyBullets.length  - 1) + 1;
273    var numBrrg = enemyData.skills.length % (EnemyBarrages.length - 1) + 1;
274    var acts    = new Array();
275    var brrgs   = new Array();
276
277    var bulletWay         = Math.ceil(enemyData.concentration / 10);
278    var bulletInterval    = Math.round(50 * 1 / Math.log(enemyData.skillpoint + 0.1));
279    var bulletSize        = Math.round(Math.log(enemyData.luck + 1));
280    var bulletFrameWidth  = (bulletSize + 5) * 2;
281    var bulletFrameHeight = (bulletSize + 5) * 4;
282    var bulletSpeed       = enemyData.strength / 15;
283
284    bulletSpeed = Math.log(bulletSpeed < 1.5 ? 1.5 : bulletSpeed);
285
286    for (var i = 0; i < numAct; i++) {
287        var idx = (enemyData.agility + i) % EnemyActions.length;
288        acts.push(new EnemyActions[idx](new shot()));
289    }
290
291    for (var i = 0; i < numBrrg; i++) {
292        var idx     = (enemyData.skillpoint + i * (enemyData.skills.length + 1)) % EnemyBarrages.length;
293        var brrgCls = EnemyBarrages[idx];
294        var frameColor;
295
296        switch(idx % 3) {
297        case 0:
298            frameColor = "rgba(128,32,32,0.7)";
299            break;
300        case 1:
301            frameColor = "rgba(32,128,32,0.7)";
302            break;
303        default:
304            frameColor = "rgba(64,64,128,0.7)";
305        }
306
307        for (var k = 0; k < numBlt; k++) {
308            var iidx = (enemyData.skills.length + i + k) % EnemyBullets.length;
309            brrgs.push(
310                new brrgCls(
311                    EnemyBullets[iidx],
312                    bulletSize,
313                    "#FF3",
314                    {"style": "rect", "color": frameColor,
315                     "width": bulletFrameWidth, "height": bulletFrameHeight},
316                    bulletInterval,
317                    bulletSpeed,
318                    bulletWay
319                )
320            );
321        }
322    }
323
324    var size  = Math.ceil((System.screen.width / 2) * (1 / enemyData.defense));
325    var enemy = new Trooper(
326        enemyData.name,
327        new actList(acts),
328        System.enemyImages[enemyData.hitpoint % System.enemyImages.length],
329        size,
330        size,
331        "#F33",
332        "#F33",
333        Math.floor(Math.random() * System.screen.width),
334        Math.floor(Math.random() * (System.screen.height / 4)),
335        System.screen.width,
336        System.screen.height,
337        Math.floor(enemyData.hitpoint / 25) + 1,
338        Math.log(enemyData.agility + 0.1) * 3,
339        0,
340        ["rgba(255,0,0,0.3)", "rgba(0,0,255,0.3)"],
341        brrgs
342    );
343    enemy.registerCallback("damaged", function() {playSound("se_damage_enemy")});
344
345    System.enemies.push(enemy);
346}
347
348
349/*
350 *  Main loop
351 */
352function mainLoop() {
353    // clear screen
354    drawScreen(
355        System.screen.ctx,
356        "source-over",
357        "rgba(8,8,8,0.8)",
358        System.screen.width,
359        System.screen.height
360    );
361
362    // update background objects
363    updateBackground(
364        System.screen.ctx,
365        System.screen.width,
366        System.screen.height,
367        1, "#CAF", 10
368    );
369
370    switchStageBgm();
371
372    // draw score
373    var scoreNames = Object.keys(System.score).sort();
374    for (var i = 0; i < scoreNames.length; i++) {
375        var name = scoreNames[i];
376        drawString(
377            System.screen.ctx,
378            "source-over",
379            name + " score " + System.score[name],
380            (System.screen.width - 10),
381            i * 16 + 15,
382            "#ACF", "9pt monospace", "right"
383        );
384    }
385
386    // update/draw troopers
387    for (var i = 0; i < System.players.length; i++) {
388        var player = System.players[i];
389
390        updateTrooper(player, "enemies");
391
392        drawLifeGauge(
393            System.screen.ctx,
394            "lighter",
395            player,
396            10,
397            (System.screen.height - 20) - (i * 33),
398            System.screen.width
399        );
400
401        drawString(
402            System.screen.ctx,
403            "source-over",
404            player.name,
405            10,
406            (System.screen.height - 23) - (i * 33),
407            "#ACF", "9pt monospace", "left"
408        );
409    }
410
411    // update/draw enemies
412    for (var i = 0; i < System.enemies.length; i++) {
413        var enemy = System.enemies[i];
414
415        updateTrooper(enemy, "players");
416
417        drawLifeGauge(
418            System.screen.ctx,
419            "lighter",
420            enemy, 10, i * 33 + 10,
421            System.screen.width
422        );
423
424        drawString(
425            System.screen.ctx,
426            "source-over",
427            enemy.name, 10, i * 33 + 33,
428            "#FCA", "9pt monospace", "left"
429        );
430    }
431
432    updateDeathPieces(System.screen.ctx,
433                      System.screen.width,
434                      System.screen.height);
435
436    if (!System.players.length) {
437        drawString(
438            System.screen.ctx, "source-over",
439            "GAME OVER",
440            System.screen.width / 2,
441            System.screen.height / 2,
442            "#ACF", "24pt monospace", "center"
443        );
444    }
445}
446
447
448/*
449 *  Initializer
450 */
451function initGame(canvas, msg, playerData) {
452    System.screen.canvas = canvas;
453    System.message       = msg;
454    System.screen.ctx    = System.screen.canvas.getContext("2d");
455    System.screen.width  = System.screen.canvas.width;
456    System.screen.height = System.screen.canvas.height;
457    System.gameOver      = false;
458
459    System.screen.ctx.globalCompositeOperation = "lighter";
460
461    if (System.mainIntervalId) {
462        clearInterval(System.mainIntervalId);
463        System.mainIntervalId   = 0;
464        System.players          = new Array();
465        System.enemies          = new Array();
466        System.backgroundObject = new Array();
467        System.deathPieces      = new Array();
468    }
469
470    var trooper = new Trooper(
471        playerData.name,
472        new ActionList([new ManualAction(new ManualShot())]),
473        playerData.image,
474        playerData.size,
475        playerData.hitsize,
476        "#33F",
477        "#F33",
478        System.screen.width / 2,
479        System.screen.height - System.screen.height / 7,
480        System.screen.width,
481        System.screen.height,
482        playerData.hitpoint,
483        playerData.speed,
484        playerData.numbombs,
485        ["rgba(255,0,0,0.3)", "rgba(0,0,255,0.3)"],
486        [new LinerBarrage(YExtendBullet,
487                          playerData.shotsize,
488                          "rgba(64,64,128,0.7)",
489                          null,
490                          playerData.shotinterval,
491                          playerData.shotspeed,
492                          playerData.shotlevel,
493                          -0.5),
494         new LinerBarrage(YExtendBullet,
495                          playerData.shotsize,
496                          "rgba(64,64,128,0.7)",
497                          null,
498                          playerData.shotinterval,
499                          playerData.shotspeed,
500                          playerData.shotlevel,
501                          0.5),
502         new CircularBarrage(LinerBullet,
503                          playerData.shotsize,
504                          "rgba(64,64,128,0.7)",
505                          null,
506                          playerData.shotinterval,
507                          playerData.shotspeed,
508                          playerData.shotlevel + 2,
509                          -0.5)]
510    );
511    trooper.registerCallback("addBomb", function(){playSound("se_bomb")});
512    trooper.registerCallback("damaged", function(){playSound("se_damage_player")});
513
514    System.players.push(trooper);
515
516    for (var i = 0; i < System.players.length; i++) {
517        System.score[System.players[i].name] = 0;
518    }
519
520    drawScreen(
521        System.screen.ctx,
522        "source-over",
523        "rgba(0,0,0,1)",
524        System.screen.width,
525        System.screen.height
526    );
527
528    document.onkeydown  = function (ev) { setKeyDown(ev.keyCode); };
529    document.onkeyup    = function (ev) { setKeyUp(ev.keyCode); };
530    document.onkeypress = function (ev) { setKeyPress(ev.charCode); };
531
532    System.mainIntervalId = setInterval(mainLoop, 20);
533}
Note: See TracBrowser for help on using the repository browser.