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

Revision 129, 15.6 KB checked in by atzm, 12 years ago (diff)

modified damaged behavior

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