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

Revision 124, 14.8 KB checked in by atzm, 12 years ago (diff)

fixed muda

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