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
RevLine 
[81]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    },
[119]23    "sound":            {},
[84]24    "message":          null,
[109]25    "enemyImages":      new Array(),
[108]26    "enemies":          new Array(),
27    "players":          new Array(),
[112]28    "score":            {},
[123]29    "stage":            -1,
[81]30    "backgroundObject": new Array(),
[95]31    "deathPieces":      new Array(),
[81]32    "mainIntervalId":   0
33};
34
35
36/*
[108]37 *  Tiun Tiun Utilities
[95]38 */
39var DeathPiece = function(sizes, colors, x, y, dir, speed) {
[114]40    var that = new LinerBullet(sizes[0], colors[0], null,
41                               System.screen.width, System.screen.height,
42                               x, y, dir, speed);
[95]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
[108]62function addDeathPieces(x, y, sizes, colors, speed, way) {
63    if (way % 2)
64        way++;
[95]65
[108]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
[95]100/*
[81]101 *  Utility Functions
102 */
[108]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
[81]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(
[114]118            new LinerBullet(size, color, null,
119                            System.screen.width, System.screen.height,
120                            x, 0, 0.5 * Math.PI, s));
[81]121    }
122
123    var newObjs = new Array();
[108]124
[96]125    for (var i = 0; i < System.backgroundObject.length; i++) {
[81]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    }
[108]131
[81]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
[108]182function updateTrooper(trooper, enemyKey) {
183    trooper.update(System[enemyKey]);
[95]184
[108]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()) {
[119]190            playSound("se_destroy");
191
[108]192            addDeathPieces(
193                enemy.x, enemy.y,
194                [6, 8, 10], ["#55F", "#AAF"], 3, 8
195            );
[112]196
197            if (System.score[trooper.name] !== undefined) {
198                System.score[trooper.name] += enemy.maxLife * 100;
199            }
[108]200        }
201        else {
202            aliveEnemies.push(enemy);
203        }
[95]204    }
[108]205    System[enemyKey] = aliveEnemies;
[95]206
[108]207    trooper.draw(System.screen.ctx);
208}
209
[123]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;
[122]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
[123]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);
[122]243    }
244}
245
[119]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
[122]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
[110]268function numEnemies() {
269    return System.enemies.length;
270}
271
[109]272function addEnemyImage(image) {
273    System.enemyImages.push(image);
274}
275
[108]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()));
[95]297    }
[108]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];
[116]302        var frameColor;
[108]303
[116]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:
[117]312            frameColor = "rgba(64,64,128,0.7)";
[116]313        }
314
[108]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",
[116]322                    {"style": "rect", "color": frameColor,
[108]323                     "width": bulletFrameWidth, "height": bulletFrameHeight},
324                    bulletInterval,
325                    bulletSpeed,
326                    bulletWay
327                )
328            );
329        }
[95]330    }
331
[108]332    var size  = Math.ceil((System.screen.width / 2) * (1 / enemyData.defense));
333    var enemy = new Trooper(
334        enemyData.name,
335        new actList(acts),
[109]336        System.enemyImages[enemyData.hitpoint % System.enemyImages.length],
[108]337        size,
338        size,
339        "#F33",
340        "#F33",
[121]341        Math.floor(Math.random() * System.screen.width),
342        Math.floor(Math.random() * (System.screen.height / 4)),
[108]343        System.screen.width,
344        System.screen.height,
[111]345        Math.floor(enemyData.hitpoint / 25) + 1,
[108]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    );
[119]351    enemy.registerCallback("damaged", function() {playSound("se_damage_enemy")});
[81]352
[108]353    System.enemies.push(enemy);
[84]354}
355
356
[81]357/*
358 *  Main loop
359 */
360function mainLoop() {
361    // clear screen
362    drawScreen(
363        System.screen.ctx,
364        "source-over",
[106]365        "rgba(8,8,8,0.8)",
[81]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
[123]378    // switch stage
379    if (switchStage(50000))
380        switchBgm(System.stage);
[122]381
[112]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
[95]396    // update/draw troopers
[108]397    for (var i = 0; i < System.players.length; i++) {
398        var player = System.players[i];
[81]399
[108]400        updateTrooper(player, "enemies");
[81]401
[108]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    }
[81]455}
456
457
458/*
459 *  Initializer
460 */
[108]461function initGame(canvas, msg, playerData) {
[81]462    System.screen.canvas = canvas;
[84]463    System.message       = msg;
[81]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;
[95]467    System.gameOver      = false;
[81]468
469    System.screen.ctx.globalCompositeOperation = "lighter";
470
471    if (System.mainIntervalId) {
472        clearInterval(System.mainIntervalId);
[122]473        System.mainIntervalId   = 0;
474        System.players          = new Array();
475        System.enemies          = new Array();
476        System.backgroundObject = new Array();
477        System.deathPieces      = new Array();
[81]478    }
479
[119]480    var trooper = new Trooper(
[81]481        playerData.name,
482        new ActionList([new ManualAction(new ManualShot())]),
[109]483        playerData.image,
[81]484        playerData.size,
[97]485        playerData.hitsize,
[81]486        "#33F",
[97]487        "#F33",
[81]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,
[92]494        playerData.numbombs,
[98]495        ["rgba(255,0,0,0.3)", "rgba(0,0,255,0.3)"],
[81]496        [new LinerBarrage(YExtendBullet,
497                          playerData.shotsize,
[106]498                          "rgba(64,64,128,0.7)",
499                          null,
[81]500                          playerData.shotinterval,
501                          playerData.shotspeed,
502                          playerData.shotlevel,
503                          -0.5),
504         new LinerBarrage(YExtendBullet,
505                          playerData.shotsize,
[106]506                          "rgba(64,64,128,0.7)",
507                          null,
[81]508                          playerData.shotinterval,
509                          playerData.shotspeed,
510                          playerData.shotlevel,
511                          0.5),
512         new CircularBarrage(LinerBullet,
513                          playerData.shotsize,
[106]514                          "rgba(64,64,128,0.7)",
515                          null,
[81]516                          playerData.shotinterval,
517                          playerData.shotspeed,
518                          playerData.shotlevel + 2,
519                          -0.5)]
[119]520    );
[122]521    trooper.registerCallback("addBomb", function(){playSound("se_bomb")});
522    trooper.registerCallback("damaged", function(){playSound("se_damage_player")});
[81]523
[119]524    System.players.push(trooper);
525
[112]526    for (var i = 0; i < System.players.length; i++) {
527        System.score[System.players[i].name] = 0;
528    }
529
[122]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);
[81]543}
Note: See TracBrowser for help on using the repository browser.