Created
December 12, 2017 23:03
-
-
Save kdrnic/7d493259cb290ca21e4f19fc6262dbcc to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| frame = 0; | |
| GAME_STATE_WAIT = 0; | |
| GAME_STATE_GAMEOVER = 1; | |
| GAME_STATE_PLAY = 2; | |
| gameState = 0; | |
| oldButtons = [0, 0, 0, 0]; | |
| debug = false; | |
| render = true; | |
| clearScreen = true; | |
| #define SCREEN_W 320 | |
| #define SCREEN_H 200 | |
| ship = { | |
| x: screen.w / 2, | |
| y: screen.h / 2, | |
| dx: 0, | |
| dy: 0, | |
| angle: 0, | |
| alive: false, | |
| radius: 4, | |
| accel: 0.1, | |
| turnSpeed: 0.1, | |
| friction: 0.005 | |
| }; | |
| laserSound = LoadSample("laser.wav"); | |
| teleSound = LoadSample("tele.wav"); | |
| explosionSounds = [LoadSample("expl1.wav"), LoadSample("expl2.wav"), LoadSample("expl3.wav")]; | |
| laserBitmap = LoadBitmap("laser.pcx"); | |
| bulletSpritesheet = CreateSpriteSheet(laserBitmap, 25, 25); | |
| shipSprite = CreateSpriteSheet(LoadBitmap("ship.pcx"), 25, 25); | |
| asteroidSpritesheet = CreateSpriteSheet(LoadBitmap("asteroid.pcx"), 51, 54); | |
| SetPalette(LastBitmapPalette()); | |
| bulletAnimSpeed = 3; | |
| bulletLifetime = 45; | |
| bulletSpeed = 5; | |
| bulletRadius = 2; | |
| asteroidScale = [1, 0.6, 0.35, 0.225]; | |
| asteroidAnimLength = asteroidSpritesheet.numberOfFrames / 2; | |
| asteroidAnimSpeed = [4.5, 4, 3.5, 3]; | |
| asteroidSpeed = [1, 1.5, 1.75, 1.875]; | |
| asteroidRadius = [27, 27/2, 27/4, 27/8]; | |
| maxAsteroids = 10 * 8; | |
| maxBullets = 3; | |
| asteroids = []; | |
| bullets = []; | |
| asteroidSprites = new Int32Array(maxAsteroids * 6); | |
| for(var i = 0; i < maxAsteroids * 6; i += 6) asteroidSprites[i + 2] = -1; | |
| bulletSprites = new Int32Array(maxBullets * 4); | |
| for(var i = 0; i < maxBullets * 4; i += 4) bulletSprites[i + 2] = -1; | |
| bulletIndex = 0; | |
| asteroidIndex = 0; | |
| function PlayExplosion(){ | |
| PlaySample(explosionSounds[Math.floor(explosionSounds.length * Math.random())], 175, 128, 900 + Math.random() * 100, 0); | |
| } | |
| #define Move(obj) \ | |
| obj.x += obj.dx; \ | |
| obj.y += obj.dy; \ | |
| if(obj.x < 0 - obj.radius) obj.x = SCREEN_W + obj.radius; \ | |
| if(obj.y < 0 - obj.radius) obj.y = SCREEN_H + obj.radius; \ | |
| if(obj.x > SCREEN_W + obj.radius) obj.x = 0 - obj.radius; \ | |
| if(obj.y > SCREEN_H + obj.radius) obj.y = 0 - obj.radius; | |
| //#define Collision(a, b) ((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y) < (a.radius + b.radius) * (a.radius + b.radius)) | |
| #define Collision(a, b) (Math.abs(a.x - b.x) < (a.radius + b.radius) && Math.abs(a.y - b.y) < (a.radius + b.radius)) | |
| function XCompare(a, b){ | |
| return (b.x + b.radius < a.x + a.radius) ? 1 : (b.x + b.radius == a.x + a.radius) ? 0 : -1; | |
| } | |
| function CreateAsteroid(g, x, y){ | |
| var moveAngle = Math.random() * 999; | |
| var spd = 0.75 + Math.random() * 0.25; | |
| var a = { | |
| generation: g, | |
| x: x, | |
| y: y, | |
| dx: Math.cos(moveAngle) * asteroidSpeed[g] * spd, | |
| dy: Math.sin(moveAngle) * asteroidSpeed[g] * spd, | |
| angle: FloatToFix(Math.random() * 256), | |
| scale: FloatToFix(asteroidScale[g]), | |
| fScale: asteroidScale[g], | |
| flips: (Math.random() > 0.5 ? FLIP_V : 0) | (Math.random() > 0.5 ? FLIP_H : 0), | |
| time: Math.random() * 999, | |
| animSpeed: asteroidAnimSpeed[g], | |
| type: Math.random() > 0.5 ? 1 : 0, | |
| radius: asteroidRadius[g], | |
| spr: ((asteroidIndex++) % maxAsteroids) * 6 | |
| }; | |
| asteroidSprites[a.spr + 3] = a.angle; | |
| asteroidSprites[a.spr + 4] = a.scale; | |
| asteroidSprites[a.spr + 5] = a.flips; | |
| return a; | |
| } | |
| function SpawnAsteroid(){ | |
| asteroids.push(CreateAsteroid(0, Math.random() * screen.w, Math.random() * screen.h)); | |
| } | |
| function DestroyShip(){ | |
| if(!ship.alive) return; | |
| PlayExplosion(); | |
| ship.alive = false; | |
| } | |
| function SpawnShip(){ | |
| ship.alive = true; | |
| ship.x = screen.w / 2; | |
| ship.y = screen.h / 2; | |
| ship.dx = ship.dy = 0; | |
| } | |
| function SpawnBullet(){ | |
| PlaySample(laserSound, 150, 128, 990 + Math.random() * 20, 0); | |
| var b; | |
| if(bullets.length >= maxBullets) bullets.shift(); | |
| bullets.push(b = { | |
| x: ship.x, | |
| y: ship.y, | |
| time: 0, | |
| dx: Math.cos(ship.angle) * bulletSpeed, | |
| dy: Math.sin(ship.angle) * bulletSpeed, | |
| angle: FloatToFix(256 * ship.angle / (Math.PI * 2)), | |
| radius: bulletRadius, | |
| spr: ((bulletIndex++) % maxBullets) * 4 | |
| }); | |
| bulletSprites[b.spr + 3] = b.angle; | |
| } | |
| function DrawCircle(obj){ | |
| Circle(screen, obj.x, obj.y, obj.radius, 1 + Math.random() * 254); | |
| } | |
| //#define GRID_COLLISION 1 | |
| //#define SORT_COLLISION 1 | |
| #define BROAD_COLLISION 1 | |
| #ifdef SORT_COLLISION | |
| #define SORT_ASTEROIDS() asteroids = asteroids.sort(XCompare) | |
| #else | |
| #define SORT_ASTEROIDS() | |
| #endif | |
| #ifdef GRID_COLLISION | |
| #define AST_PUTINGRID(a, i) asteroidCollision[Math.abs(a.x) >> 5].push(i); asteroidCollision[Math.abs(a.x - a.radius) >> 5].push(i); asteroidCollision[Math.abs(a.x + a.radius) >> 5].push(i); | |
| #define CLEAR_GRID() asteroidCollision = [[], [], [], [], [], [], [], [], [], [], [], [], [], []]; | |
| #else | |
| #define AST_PUTINGRID(a, i) | |
| #define CLEAR_GRID() | |
| #endif | |
| #ifdef BROAD_COLLISION | |
| #define BROADPHASE_COLL(a, b) ((3584 >> (a.x >= 0 ? (a.x >> 5) : 0)) & (1024 >> (b.x >= 0 ? (b.x >> 5) : 0))) | |
| #else | |
| #define BROADPHASE_COLL(a, b) 1 | |
| #endif | |
| function DestroyAsteroid(i, a){ | |
| asteroidSprites[a.spr + 2] = -1; | |
| PlayExplosion(); | |
| if(a.generation < 3){ | |
| asteroids[i] = CreateAsteroid(a.generation + 1, a.x, a.y); | |
| asteroids.push(CreateAsteroid(a.generation + 1, a.x, a.y)); | |
| } | |
| else{ | |
| asteroids[i] = asteroids[asteroids.length - 1]; | |
| asteroids[asteroids.length - 1] = a; | |
| asteroids.pop(); | |
| } | |
| SORT_ASTEROIDS(); | |
| } | |
| CLEAR_GRID(); | |
| function Loop(){ | |
| frame++; | |
| if(asteroids.length == 0){ | |
| SpawnAsteroid(); | |
| SpawnAsteroid(); | |
| SpawnAsteroid(); | |
| asteroids = asteroids.sort(XCompare); | |
| } | |
| //UpdateShip(); | |
| if(!ship.alive){ | |
| if(buttons[0] & BUTTON_START) SpawnShip(); | |
| ship.frame = 1; | |
| } | |
| else { | |
| if(buttons[0] & (~oldButtons[0]) & BUTTON_A){ | |
| SpawnBullet(); | |
| } | |
| if(buttons[0] & (~oldButtons[0]) & BUTTON_B){ | |
| PlaySample(teleSound, 160, 128, 1000, 0); | |
| ship.x = Math.random() * screen.w; | |
| ship.y = Math.random() * screen.h; | |
| } | |
| ship.frame = 0; | |
| ship.dx -= Math.cos(ship.angle) * dpad[0].y * ship.accel; | |
| ship.dy -= Math.sin(ship.angle) * dpad[0].y * ship.accel; | |
| ship.dx -= ship.dx * ship.friction; | |
| ship.dy -= ship.dy * ship.friction; | |
| ship.angle += dpad[0].x * ship.turnSpeed; | |
| Move(ship); | |
| } | |
| //UpdateBullets(); | |
| var numBullets = bullets.length; | |
| for(var i = 0; i < numBullets; i++){ | |
| var b = bullets[i]; | |
| Move(b); | |
| b.time++; | |
| if(b.time > bulletLifetime) b.dead = true; | |
| #ifdef SORT_COLLISION | |
| var j; | |
| for(j = 0; j < asteroids.length; j++){ | |
| if(asteroids[j].x + asteroids[j].radius >= b.x - b.radius) break; | |
| } | |
| for(; j < asteroids.length; j++){ | |
| if(asteroids[j].x - asteroids[j].radius > b.x + b.radius) break; | |
| var a = asteroids[j]; | |
| if(Collision(b, a)){ | |
| DestroyAsteroid(j, asteroids[j]); | |
| b.dead = true; | |
| break; | |
| } | |
| } | |
| #elif GRID_COLLISION | |
| if(1) | |
| { | |
| var k = Math.abs(b.x) >> 5; | |
| for(var j = 0; j < asteroidCollision[k].length; j++){ | |
| var ai = asteroidCollision[k][j]; | |
| var a = asteroids[ai]; | |
| if(Collision(b, a)){ | |
| DestroyAsteroid(ai, a); | |
| b.dead = true; | |
| break; | |
| } | |
| } | |
| } | |
| #else | |
| var numAsteroids = asteroids.length; | |
| for(j = 0; j < asteroids.length; j++){ | |
| var a = asteroids[j]; | |
| if(BROADPHASE_COLL(a, b) && Collision(b, a)){ | |
| DestroyAsteroid(j, a); | |
| b.dead = true; | |
| break; | |
| } | |
| } | |
| #endif | |
| bulletSprites[b.spr + 0] = b.x - bulletSpritesheet.width * 0.5; | |
| bulletSprites[b.spr + 1] = b.y - bulletSpritesheet.height * 0.5; | |
| bulletSprites[b.spr + 2] = 0; | |
| if(b.dead){ | |
| bulletSprites[b.spr + 2] = -1; | |
| bullets[i] = bullets[bullets.length - 1]; | |
| bullets.pop(); | |
| numBullets--; | |
| } | |
| } | |
| //UpdateAsteroids(); | |
| CLEAR_GRID(); | |
| var numAsteroids = asteroids.length; | |
| var oA = false; | |
| for(var i = 0; i < numAsteroids; i++){ | |
| var a = asteroids[i]; | |
| Move(a); | |
| if(Collision(a, ship)){ | |
| DestroyShip(); | |
| } | |
| asteroidSprites[a.spr + 0] = a.x - asteroidSpritesheet.width * a.fScale * 0.5; | |
| asteroidSprites[a.spr + 1] = a.y - asteroidSpritesheet.height * a.fScale * 0.5; | |
| asteroidSprites[a.spr + 2] = (((frame / a.animSpeed) % asteroidAnimLength) | 0) + asteroidAnimLength * a.type; | |
| AST_PUTINGRID(a, i); | |
| /* | |
| if(oA && (oA.x + oA.radius > a.x + a.radius)){ | |
| asteroids[i] = oA; | |
| asteroids[i - 1] = a; | |
| } | |
| oA = a; | |
| */ | |
| } | |
| SORT_ASTEROIDS(); | |
| if(clearScreen) ClearToColor(screen, 1); | |
| if(render){ | |
| DrawSpriteBatch(screen, asteroidSpritesheet, SPRITE_ROTATE | SPRITE_SCALE | SPRITE_FLIP, asteroidSprites.subarray(0, asteroidIndex * 6)); | |
| if(bulletIndex) DrawSpriteBatch(screen, bulletSpritesheet, SPRITE_ROTATE, bulletSprites.subarray(0, bulletIndex * 4)); | |
| DrawTransformSprite(screen, shipSprite, SPRITE_ROTATE, ship.x - 12.5, ship.y - 12.5, ship.frame, FloatToFix(256 * ship.angle / (Math.PI * 2))); | |
| } | |
| if(debug || !render){ | |
| var stuff = bullets.concat(asteroids); | |
| stuff.forEach(DrawCircle); | |
| Triangle(screen, ship.x + Math.cos(ship.angle) * 8, ship.y + Math.sin(ship.angle) * 8, ship.x + Math.cos(ship.angle - 2.5) * 5, ship.y + Math.sin(ship.angle - 2.5) * 5, ship.x + Math.cos(ship.angle + 2.5) * 5, ship.y + Math.sin(ship.angle + 2.5) * 5, 1 + Math.random() * 254); | |
| } | |
| TextOut(screen, "FPS: " + fps, 0, 0, 128); | |
| oldButtons = buttons.slice(); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment