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

Revision 123, 14.9 KB checked in by atzm, 13 years ago (diff)

kourituka

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