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

Revision 126, 15.2 KB checked in by atzm, 13 years ago (diff)

komagoma

  • 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 getStageNumber() {
211    return System.stage;
212}
213
214function switchStage(base) {
215    var scores   = Object.keys(System.score);
216    var sum      = 0;
217    var stages   = new Array();
218    var score    = 0;
219    var stage    = 1;
220    var switched = false;
221
222    for (var i = 0; i < scores.length; i++) {
223        sum += System.score[scores[i]];
224    }
225
226    for (var name in System.sound) {
227        if (!name.match(/^bgm_stage/)) continue;
228        stages.push(name);
229    }
230
231    score        = Math.round(sum / scores.length);
232    stage        = Math.floor((score % (stages.length * base)) / base) + 1;
233    switched     = System.stage != stage;
234    System.stage = stage;
235
236    return switched;
237}
238
239function switchBgm(stage) {
240    for (var name in System.sound) {
241        if (!name.match(/^bgm_stage/))
242            continue;
243        if (("bgm_stage" + stage) == name)
244            playSound(name);
245        else
246            pauseSound(name, true);
247    }
248}
249
250function toggleSound(val) {
251    for (var name in System.sound)
252        System.sound[name].muted = !val;
253}
254
255function registerSound(name, audio) {
256    System.sound[name] = audio;
257}
258
259function playSound(name) {
260    if (System.sound[name])
261        System.sound[name].play();
262}
263
264function pauseSound(name, stop) {
265    if (System.sound[name]) {
266        System.sound[name].pause();
267        if (stop)
268            System.sound[name].currentTime = 0;
269    }
270}
271
272function getEnemiesOnScreen() {
273    return System.enemies.length;
274}
275
276function addEnemyImage(image) {
277    System.enemyImages.push(image);
278}
279
280function addEnemy(enemyData) {
281    var actList = EnemyActionLists[enemyData.mtime % EnemyActionLists.length];
282    var shot    = EnemyShots[enemyData.hitpoint % EnemyShots.length];
283    var numAct  = enemyData.agility       % (EnemyActions.length  - 1) + 1;
284    var numBlt  = enemyData.skills.length % (EnemyBullets.length  - 1) + 1;
285    var numBrrg = enemyData.skills.length % (EnemyBarrages.length - 1) + 1;
286    var acts    = new Array();
287    var brrgs   = new Array();
288
289    var bulletWay         = Math.ceil(enemyData.concentration / 10);
290    var bulletInterval    = Math.round(50 * 1 / Math.log(enemyData.skillpoint + 0.1));
291    var bulletSize        = Math.round(Math.log(enemyData.luck + 1));
292    var bulletFrameWidth  = (bulletSize + 5) * 2;
293    var bulletFrameHeight = (bulletSize + 5) * 4;
294    var bulletSpeed       = enemyData.strength / 15;
295
296    bulletSpeed = Math.log(bulletSpeed < 1.5 ? 1.5 : bulletSpeed);
297
298    for (var i = 0; i < numAct; i++) {
299        var idx = (enemyData.agility + i) % EnemyActions.length;
300        acts.push(new EnemyActions[idx](new shot()));
301    }
302
303    for (var i = 0; i < numBrrg; i++) {
304        var idx     = (enemyData.skillpoint + i * (enemyData.skills.length + 1)) % EnemyBarrages.length;
305        var brrgCls = EnemyBarrages[idx];
306        var frameColor;
307
308        switch(idx % 3) {
309        case 0:
310            frameColor = "rgba(128,32,32,0.7)";
311            break;
312        case 1:
313            frameColor = "rgba(32,128,32,0.7)";
314            break;
315        default:
316            frameColor = "rgba(64,64,128,0.7)";
317        }
318
319        for (var k = 0; k < numBlt; k++) {
320            var iidx = (enemyData.skills.length + i + k) % EnemyBullets.length;
321            brrgs.push(
322                new brrgCls(
323                    EnemyBullets[iidx],
324                    bulletSize,
325                    "#FF3",
326                    {"style": "rect", "color": frameColor,
327                     "width": bulletFrameWidth, "height": bulletFrameHeight},
328                    bulletInterval,
329                    bulletSpeed,
330                    bulletWay
331                )
332            );
333        }
334    }
335
336    var size  = Math.ceil((System.screen.width / 2) * (1 / enemyData.defense));
337    var enemy = new Trooper(
338        enemyData.name,
339        new actList(acts),
340        System.enemyImages[enemyData.hitpoint % System.enemyImages.length],
341        size,
342        size,
343        "#F33",
344        "#F33",
345        Math.floor(Math.random() * System.screen.width),
346        Math.floor(Math.random() * (System.screen.height / 4)),
347        System.screen.width,
348        System.screen.height,
349        Math.floor(enemyData.hitpoint / 25) + 1,
350        Math.log(enemyData.agility + 0.1) * 3,
351        0,
352        ["rgba(255,0,0,0.3)", "rgba(0,0,255,0.3)"],
353        brrgs
354    );
355    enemy.registerCallback("damaged", function() {playSound("se_damage_enemy")});
356
357    System.enemies.push(enemy);
358}
359
360
361/*
362 *  Main loop
363 */
364function mainLoop() {
365    // clear screen
366    drawScreen(
367        System.screen.ctx,
368        "source-over",
369        "rgba(8,8,8,0.8)",
370        System.screen.width,
371        System.screen.height
372    );
373
374    // update background objects
375    updateBackground(
376        System.screen.ctx,
377        System.screen.width,
378        System.screen.height,
379        1, "#CAF", 10
380    );
381
382    // switch stage
383    if (switchStage(50000))
384        switchBgm(getStageNumber());
385
386    // draw stage number
387    drawString(
388        System.screen.ctx,
389        "source-over",
390        "STAGE " + getStageNumber(),
391        System.screen.width - 10,
392        System.screen.height - 15,
393        "#ACF", "9pt monospace", "right"
394    );
395
396    // draw score
397    var scoreNames = Object.keys(System.score).sort();
398    for (var i = 0; i < scoreNames.length; i++) {
399        var name = scoreNames[i];
400        drawString(
401            System.screen.ctx,
402            "source-over",
403            name + " SCORE " + System.score[name],
404            (System.screen.width - 10),
405            i * 16 + 15,
406            "#ACF", "9pt monospace", "right"
407        );
408    }
409
410    // update/draw troopers
411    for (var i = 0; i < System.players.length; i++) {
412        var player = System.players[i];
413
414        updateTrooper(player, "enemies");
415
416        drawLifeGauge(
417            System.screen.ctx,
418            "lighter",
419            player,
420            10,
421            (System.screen.height - 20) - (i * 33),
422            System.screen.width
423        );
424
425        drawString(
426            System.screen.ctx,
427            "source-over",
428            player.name,
429            10,
430            (System.screen.height - 23) - (i * 33),
431            "#ACF", "9pt monospace", "left"
432        );
433    }
434
435    // update/draw enemies
436    for (var i = 0; i < System.enemies.length; i++) {
437        var enemy = System.enemies[i];
438
439        updateTrooper(enemy, "players");
440
441        drawLifeGauge(
442            System.screen.ctx,
443            "lighter",
444            enemy, 10, i * 33 + 10,
445            System.screen.width
446        );
447
448        drawString(
449            System.screen.ctx,
450            "source-over",
451            enemy.name, 10, i * 33 + 33,
452            "#FCA", "9pt monospace", "left"
453        );
454    }
455
456    updateDeathPieces(System.screen.ctx,
457                      System.screen.width,
458                      System.screen.height);
459
460    if (!System.players.length) {
461        drawString(
462            System.screen.ctx, "source-over",
463            "GAME OVER",
464            System.screen.width / 2,
465            System.screen.height / 2,
466            "#ACF", "24pt monospace", "center"
467        );
468    }
469}
470
471
472/*
473 *  Initializer
474 */
475function initGame(canvas, msg, playerData) {
476    System.screen.canvas = canvas;
477    System.message       = msg;
478    System.screen.ctx    = System.screen.canvas.getContext("2d");
479    System.screen.width  = System.screen.canvas.width;
480    System.screen.height = System.screen.canvas.height;
481    System.gameOver      = false;
482
483    System.screen.ctx.globalCompositeOperation = "lighter";
484
485    if (System.mainIntervalId) {
486        clearInterval(System.mainIntervalId);
487        System.mainIntervalId   = 0;
488        System.players          = new Array();
489        System.enemies          = new Array();
490        System.backgroundObject = new Array();
491        System.deathPieces      = new Array();
492    }
493
494    var trooper = new Trooper(
495        playerData.name,
496        new ActionList([new ManualAction(new ManualShot())]),
497        playerData.image,
498        playerData.size,
499        playerData.hitsize,
500        "#33F",
501        "#F33",
502        System.screen.width / 2,
503        System.screen.height - System.screen.height / 7,
504        System.screen.width,
505        System.screen.height,
506        playerData.hitpoint,
507        playerData.speed,
508        playerData.numbombs,
509        ["rgba(255,0,0,0.3)", "rgba(0,0,255,0.3)"],
510        [new LinerBarrage(YExtendBullet,
511                          playerData.shotsize,
512                          "rgba(64,64,128,0.7)",
513                          null,
514                          playerData.shotinterval,
515                          playerData.shotspeed,
516                          playerData.shotlevel,
517                          -0.5),
518         new LinerBarrage(YExtendBullet,
519                          playerData.shotsize,
520                          "rgba(64,64,128,0.7)",
521                          null,
522                          playerData.shotinterval,
523                          playerData.shotspeed,
524                          playerData.shotlevel,
525                          0.5),
526         new CircularBarrage(LinerBullet,
527                          playerData.shotsize,
528                          "rgba(64,64,128,0.7)",
529                          null,
530                          playerData.shotinterval,
531                          playerData.shotspeed,
532                          playerData.shotlevel + 2,
533                          -0.5)]
534    );
535    trooper.registerCallback("addBomb", function(){playSound("se_bomb")});
536    trooper.registerCallback("damaged", function(){playSound("se_damage_player")});
537
538    System.players.push(trooper);
539
540    for (var i = 0; i < System.players.length; i++) {
541        System.score[System.players[i].name] = 0;
542    }
543
544    drawScreen(
545        System.screen.ctx,
546        "source-over",
547        "rgba(0,0,0,1)",
548        System.screen.width,
549        System.screen.height
550    );
551
552    document.onkeydown  = function (ev) { setKeyDown(ev.keyCode); };
553    document.onkeyup    = function (ev) { setKeyUp(ev.keyCode); };
554    document.onkeypress = function (ev) { setKeyPress(ev.charCode); };
555
556    System.mainIntervalId = setInterval(mainLoop, 20);
557}
Note: See TracBrowser for help on using the repository browser.