Skip to content

Instantly share code, notes, and snippets.

@kdrnic
Created December 12, 2017 23:03
Show Gist options
  • Select an option

  • Save kdrnic/7d493259cb290ca21e4f19fc6262dbcc to your computer and use it in GitHub Desktop.

Select an option

Save kdrnic/7d493259cb290ca21e4f19fc6262dbcc to your computer and use it in GitHub Desktop.
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