Porting an old shoot 'em up game to JavaScript on the knee

There is an ancient toy LaserAge, which is written in Flash (on a very ancient Macromedia Flash 4) and works only under Windows. As a child, I really liked it, so I decided to port it for the soul so that I could play from the browser from all devices.



The goal of the game is to destroy opponents with your spaceship at various levels and get bonuses, if you catch a bonus, the weapon is improved. When an enemy torpedo hits, the player's weapon is downgraded.



When all enemies on a level are destroyed, it switches to the next level. There are 100 levels in total.



In terms of the game, the level is a wave (Wave), and several waves are combined into a large level (Level), which is simply a change in the background, i.e. only 4 large levels in each of which 25 waves. In the last wave of a high level, there is usually a boss - an enemy with a huge life value and powerful weapons.



https://github.com/EntityFX/laseroid/blob/master/doc/LaserAgeNext.png?raw=true



Business logic game



Play space



It is an ordinary rectangular area, in the upper part there are enemy ships, and below the player.



, , .



https://github.com/EntityFX/laseroid/blob/master/doc/Stage.png?raw=true





.

( ) ( ).



, : ( ), .

1 (), 0 .







    • — 1
    • — 2
    • — 3


    • — 4
    • — 5
  • — 6 7 ( )
  • — 8 ( )
  • — 9 ( , , )


:



  • — 15-19 ( , , )
  • — 20-24
  • — 25-29
  • — 30-34
  • — 30-34
  • — 35 — 39
  • — 40+




Hit Points
1 5 25 , ,
1 5 50
3 7 30
2 8 30 3
2 4 30
4 4.5 30
2 3.8 40
4 - 15/55 5




1
2 +
3 + +
4 + + +
5 + + + +
6 + +
7 + +
8 + +
9 + +
15 — 19 + + +
20 — 24 + + +
25 — 29 + + +
30 — 34 + + +
35 — 39 + + +
40+ + + +






2.5
3.5
4.5
5
3
3.2 — 3.8
4 — 6
-


, .



, . ().



:



"torpedo": {
    "sprite": "Bullet1_1.png", // 
    "isRandomIntensity": false, //     - true    - false
    "intensity": [
        // 0
        {
            "min": 50, //  
            "max": 200, //  
            "type": "pause" //pause -  , shoot -  ()
        },
        // 1
        {
            "min": 100,
            "max": 200,
            "type": "shoot"
        },
        {
            "min": 50,
            "max": 80,
            "type": "pause"
        },
        {
            "min": 30,
            "max": 100,
            "repeat": 2
        }
    ],
    "speed": 2.5, //
    "type": "bullet", // 
    "sound": "alienTorpedo"
}






, .



. .



( ).





, , , . .



1 2
2 4
10 ()
10 -
10 ( )
30 ( ) ( )
30 ( )
30
1 2
30 ( )
30
35 +
35 + + +
100 ( ) + ( )
250 ( )
500 + + + + + + +
1000 () + + + + + + + + ( )


JSON- :



"alien10": {
    "life": 35,
    "weapons": [
        {
            "weapon": "blueTorpedo",
            "position": {
                "x": -6,
                "y": 0
            }
        },
        {
            "weapon": "blueTorpedo",
            "position": {
                "x": 6,
                "y": 0
            }
        }
    ],
    "sprite": "AlienShip10_1.png",
    "movement": "horizontalFast",
    "killPoints": 2100
}


JSON- :



"horizontalFast": {
    "movements": [
        {
            "type": "freeMovement", //freeMovement - , followPlayer -    (  )
            "speedDelta": {
                "vx": -6,
                "vy": 0
            },
            "intensity": [ //    
                {
                    "min": 20,
                    "max": 150
                },
                {
                    "min": 150,
                    "max": 350
                }
            ]
        }
    ]
}






https://raw.githubusercontent.com/EntityFX/laseroid/master/resources/laser-age/graphics/PowerUps_1.png,



https://raw.githubusercontent.com/EntityFX/laseroid/master/resources/laser-age/graphics/Upgrade.png, . , ().





, . .



JSON- :



        "2": {
            "level": 1, 
            "enemies": [ //  
                {
                    "id": "alien1",
                    "position": {
                        "x": 200,
                        "y": 35
                    }
                },
                //...
                {
                    "id": "alien1",
                    "position": {
                        "x": 525,
                        "y": 40
                    }
                }
            ],
            "bonuses": [ //  
                {
                    "id": "bonus1",
                    "position": {
                        "x": 350,
                        "y": 10
                    }
                }
            ]
        },


JavaScript



JavaScript, Hexi JS: https://github.com/kittykatattack/hexi .



:



  • (, )
  • , ,


    • -. JSON (, )
  • (), -.


- TexturePacker



https://github.com/EntityFX/laseroid/blob/master/doc/ships-atlas-texture.png?raw=true



: https://github.com/kittykatattack/sound.js



:







:



https://github.com/EntityFX/laseroid/blob/master/doc/diagrams/game.png?raw=true





https://github.com/EntityFX/laseroid/blob/master/doc/diagrams/core.png?raw=true



Main



.



:



  • resources — (, , json)
  • sounds — : — , —
  • gameScene — HexiJS
  • game — Game
  • hexi — HexiJS
  • gameStorage — localStorage


:



  • init() — HexiJS
  • load() — (, , json)
  • setup() — , ,
  • playLoop() — ( , , , ).
  • saveGame()
  • loadGame()


:



Main.resources = [
        "images/environment1.png",
        "images/environment2.png",
        "images/environment3.png",
        "images/environment4.png",
        "images/interface.png",
        "images/life-icon.png",

        "images/ships-texture.json",
        "images/bullet-texture.json",

        "sounds/alien-torpedo-shoot.wav",
        "sounds/alien-red-plasma-shoot.wav",
        "sounds/hero-torpedo-shoot.wav",
        "sounds/explode.wav",
        "sounds/hero-green-plasma-shoot.wav",
        "sounds/alien-green-plasma-shoot.wav",
        "sounds/alien-blue-torpedo-shoot.wav",
        "sounds/alien-yellow-laser.wav",
        "sounds/pulse-plasma.wav",
        "sounds/laser.wav",

        "sounds/track0.ogg",
        "sounds/track1.ogg",
        "sounds/track2.ogg",
        "sounds/track3.ogg",
        "sounds/track4.ogg",

        "data/hero-configuration.json",
        "data/levels-configuration.json",
        "data/enemy-configuration.json",
        "data/ui-configuration.json",
    ];


Game



.



:



  • level — . : { "wave": 1 // , "type": 1 }
  • score — . : {"points": 0 }
  • bulletsControllerBulletsController.
  • enemyControllerEnemyController. ( .. )
  • playerPlayer
  • hexi — Hexi ()
  • game — Game
  • gameStorage — GameStorage


:



  • clearShips() — ,
  • setupLevel() — ( , , )
  • nextLevel()
  • previousLevel()
  • forwardLevel() — ( 5)
  • rewindLevel() — ( 5)
  • restoreState(gameState: JSON) — gameState
  • resetGame() — ( )
  • update()
  • enemyDestroyed()


GameStorage



.



:



  • game — Game


:



  • save()
  • load()


InputDevice



: click touch , .



:



  • game — Game


:



  • init() — callback'
  • loadTapped() — "Load"
  • storeTapped() — "Store"
  • resetTapped() — "Reset"
  • pauseTapped() — "Pause"




https://github.com/EntityFX/laseroid/blob/master/doc/diagrams/actors.png?raw=true



Actor



.



:



  • hexi — Hexi ()
  • game — Game
  • life
  • initialLife
  • sprite — Hexi.Sprite
  • shipConfiguration


:



  • move()
  • update()
  • setPosition(position: {x, y})


WeaponedActor



( ) .



:



  • automatedWeapons
  • canShoot
  • isWeaponShooting


:



  • startShoot()
  • stopShoot()
  • onShootStarted() — ,
  • onShootStopped() — ,
  • updateShooting()


Enemy



.



:



  • type
  • syncWeapons
  • movementEngineMovementEngine


:



  • setWeapon()
  • shootWithWeapon()
  • setLifeLine()
  • hit() — ()


MovementEngine



.



, . vx, vy . ( ).



:



  • movementsConfiguration
  • firstMovementConfiguration
  • movementItensity
  • movementItensityCounter
  • movementItensitySlot
  • isBounceBottom — . false,


:



  • setMovement()
  • updateMovement()


Player



.



:



  • weapons
  • collisionSprite — ( , )
  • weaponLifeLevels
  • invisibilityCounter — ( , )


:



  • upgrade() — (+1 )
  • downgrade() — (+1 )
  • shootWithLaser(currentWeapon, weapon)
  • shootWithBullets(currentWeapon, weapon)
  • setWeapon()
  • setLife(life: number) — ( )
  • hitUpgrade(upgradeItem)


Bonus



. .



:



  • type
  • movementEngineMovementEngine
  • upgradeBonus


:



  • shootWithUpgrade(upgradeBonus: JSON)


EnemyController



, , .



:



  • enemies
  • bonuses
  • player
  • upgrades


:



  • isLevelCompleted() — ( , )
  • update()
  • clear() — ,


BulletsController



(), .



:



  • playerBullets
  • enemyBullets
  • explosionSplashes
  • playerLaser — ( ).


:



  • update() — ,
  • clear() — ,
  • updatePlayerBullets()
  • updatePlayerLaser()
  • updateEnemyBullets()
  • updateExplosions()




JavaScript.



, , .



, , ..



, !



!





http://laseroid.azurewebsites.net/

https://github.com/EntityFX/laseroid




All Articles