Created
August 14, 2019 02:40
-
-
Save eguneys/3ff4e0f10e4c08776b87296669ceab62 to your computer and use it in GitHub Desktop.
This file contains 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
var GAME = (function(){ | |
var states = {}; | |
assets = { | |
// font:{ | |
// string: "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_!@.'\"?/<()", | |
// | |
// // bin: '~cQz??I#_CH?|Ba<?FcdO~Rz90B?uFs,q:bwQKH2?h}/A`}yHc.FT$1VW"Q'+ | |
// // 'F!D>#g"xtR|!?Ayx=_"t.Eg"x.:bpH!xo-j}/TC mQ@" BB', | |
// // bin: [ | |
// // ["111111111011111111001111111111111111000111111111111000110000100011000101110111100111011110011111111110001100011000110001100011111100100011101111010010111110111111111011100111001110000000010011111010100000000110110110111000001000100001001000"], | |
// // ["100011000110000100101000010000100001000100100000101001010000110111100110001100011000110001100000010010001100011000101010010100001001100100010000110010100001000000001100011000110001000000010010001111110000000010010011000100010001000010000100"], | |
// // ["111111111010000100011110011100101111111100100000101110010000101011010110001100101000111110011100010010001100011010100100001000010000100000100011011111111101111000010011100111110001000000010010111010100000000100100100011000100010000010000100"], | |
// // ["100011000110000100011000010000100011000100100100101001010000100011001110001111001001010001000010010010001010101010101010001000100000100001000000100010000011000100100100010000110001000000000010101111110000000000000000000001000001000010000100"], | |
// // ["100011111001111111101111110000111111000111111111101000111111100011000101110100000111110001111100010001110001000111010001001001111101110111111111000010111100111000100011100111001110111110010010111010100010000000000000010010000000100001001000"] | |
// // ], | |
// // bigString: "11111100011111110001100011111010001111101000111110111111000010000100000111111100100101000110001111101111110000111001000011111111111000"+ | |
// // "0111001000010000111111000010111100011111110001100011111110001100011111100100001000010011111111110001000010100101111010001100101110010010100011000"+ | |
// // "0100001000010000111111000111011101011000110001100011100110101100111000101110100011000110001011101111010001100101110010000011101000110001100100111"+ | |
// // "1111101000111110100011000101111100000111000001111101111100100001000010000100100011000110001100010111010001100011000101010001001000110001101011010"+ | |
// // "1011101000101010001000101010001100010101000100001000010011111000100010001000111110010001100001000010001110011101000100010001001111111110000010011"+ | |
// // "0000011111010010100101111100010000101111110000111100000111110011111000011110100010111011111000010001000100001000111010001011101000101110011101000"+ | |
// // "1011110000101110011101000110001100010111000000000000000000000111110010000100001000000000100111111000110111101011011101010111110101011111010100000"+ | |
// // "000000000000000000100001100001000100000000000011011010011001000000000000111010001001100000000100000010001000100010001000000010001000100000100000100001000100001000010000010" | |
// | |
// }, | |
laser: { | |
"osc1_oct": 7, | |
"osc1_det": 0, | |
"osc1_detune": 0, | |
"osc1_xenv": 1, | |
"osc1_vol": 255, | |
"osc1_waveform": 3, | |
"osc2_oct": 8, | |
"osc2_det": 0, | |
"osc2_detune": 0, | |
"osc2_xenv": 1, | |
"osc2_vol": 255, | |
"osc2_waveform": 0, | |
"noise_fader": 61, | |
"env_attack": 22, | |
"env_sustain": 22, | |
"env_release": 21759, | |
"env_master": 255, | |
"fx_filter": 3, | |
"fx_freq": 4067, | |
"fx_resonance": 176, | |
"fx_delay_time": 4, | |
"fx_delay_amt": 12, | |
"fx_pan_freq": 2, | |
"fx_pan_amt": 84, | |
"lfo_osc1_freq": 0, | |
"lfo_fx_freq": 1, | |
"lfo_freq": 3, | |
"lfo_amt": 96, | |
"lfo_waveform": 0 | |
}, | |
}; | |
//--this gets wrapped in a closure, so no namespace object, compresses better. | |
const WIDTH = 512; | |
const HEIGHT = 256; | |
var | |
C = document.getElementById('canvas'); | |
ctx = C.getContext('2d'), | |
renderTarget = 0x00000, | |
renderSource = 0x20000, | |
//Richard Fhager's DB32 Palette http://http://pixeljoint.com/forum/forum_posts.asp?TID=16247 | |
//ofcourse you can change this to whatever you like, up to 256 colors. | |
//one GOTCHA: colors are stored 0xAABBGGRR, so you'll have to flop the values from your typical hex colors. | |
colors = [0xff000000, 0xff342022, 0xff3c2845, 0xff313966, 0xff3b568f, 0xff2671df, 0xff66a0d9, 0xff9ac3ee, 0xff36f2fb, | |
0xff50e599, 0xff30be6a, 0xff6e9437, 0xff2f694b, 0xff244b52, 0xff393c32, 0xff743f3f, 0xff826030, 0xffe16e5b, | |
0xffff9b63, 0xffe4cd5f, 0xfffcdbcb, 0xffffffff, 0xffb7ad9b, 0xff877e84, 0xff6a6a69, 0xff525659, 0xff8a4276, | |
0xff3232ac, 0xff6357d9, 0xffba7bd7, 0xff4a978f, 0xff306f8a], | |
//default palette index | |
palDefault = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31], | |
//active palette index. maps to indices in colors[]. can alter this whenever for palette effects. | |
pal = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31]; | |
ctx.imageSmoothingEnabled = false; | |
ctx.mozImageSmoothingEnabled = false; | |
C.width = WIDTH; | |
C.height = HEIGHT; | |
var imageData = ctx.getImageData(0, 0, 512, 256), | |
buf = new ArrayBuffer(imageData.data.length), | |
buf8 = new Uint8Array(buf), | |
data = new Uint32Array(buf), | |
ram = new Uint8ClampedArray(0x100000); | |
//--------------graphics functions---------------- | |
function clear(color){ | |
ram.fill(color, renderTarget, renderTarget + 0x20000); | |
} | |
function pset(x, y, color) { //from colors array, 0-31 | |
x = x|0; y = y|0; color = color|0; | |
if (x > -1 && x < WIDTH && y > -1 && y < HEIGHT) { | |
ram[renderTarget + (y * WIDTH + x)] = color; | |
} | |
} | |
function line(x1, y1, x2, y2, color) { | |
x1 = x1|0; | |
x2 = x2|0; | |
y1 = y1|0; | |
y2 = y2|0; | |
var dy = (y2 - y1); | |
var dx = (x2 - x1); | |
var stepx, stepy; | |
if (dy < 0) { | |
dy = -dy; | |
stepy = -1; | |
} else { | |
stepy = 1; | |
} | |
if (dx < 0) { | |
dx = -dx; | |
stepx = -1; | |
} else { | |
stepx = 1; | |
} | |
dy <<= 1; // dy is now 2*dy | |
dx <<= 1; // dx is now 2*dx | |
pset(x1, y1, color); | |
if (dx > dy) { | |
var fraction = dy - (dx >> 1); // same as 2*dy - dx | |
while (x1 != x2) { | |
if (fraction >= 0) { | |
y1 += stepy; | |
fraction -= dx; // same as fraction -= 2*dx | |
} | |
x1 += stepx; | |
fraction += dy; // same as fraction -= 2*dy | |
pset(x1, y1, color); | |
} | |
; | |
} else { | |
fraction = dx - (dy >> 1); | |
while (y1 != y2) { | |
if (fraction >= 0) { | |
x1 += stepx; | |
fraction -= dy; | |
} | |
y1 += stepy; | |
fraction += dx; | |
pset(x1, y1, color); | |
} | |
} | |
} | |
function circle(xm, ym, r, color) { | |
var x = -r, y = 0, err = 2 - 2 * r; | |
/* II. Quadrant */ | |
do { | |
pset(xm - x, ym + y, color); | |
/* I. Quadrant */ | |
pset(xm - y, ym - x, color); | |
/* II. Quadrant */ | |
pset(xm + x, ym - y, color); | |
/* III. Quadrant */ | |
pset(xm + y, ym + x, color); | |
/* IV. Quadrant */ | |
r = err; | |
if (r <= y) err += ++y * 2 + 1; | |
/* e_xy+e_y < 0 */ | |
if (r > x || err > y) err += ++x * 2 + 1; | |
/* e_xy+e_x > 0 or no 2nd y-step */ | |
} while (x < 0); | |
} | |
function fillCircle(xm, ym, r, color) { | |
if(r < 0) return; | |
xm = xm|0; ym = ym|0, r = r|0; color = color|0; | |
var x = -r, y = 0, err = 2 - 2 * r; | |
/* II. Quadrant */ | |
do { | |
line(xm-x, ym-y, xm+x, ym-y, color); | |
line(xm-x, ym+y, xm+x, ym+y, color); | |
r = err; | |
if (r <= y) err += ++y * 2 + 1; | |
if (r > x || err > y) err += ++x * 2 + 1; | |
} while (x < 0); | |
} | |
function rect(x, y, w, h, color) { | |
x1 = x|0; | |
y1 = y|0; | |
x2 = (x+w)|0; | |
y2 = (y+h)|0; | |
line(x1,y1, x2, y1, color); | |
line(x2, y1, x2, y2, color); | |
line(x1, y2, x2, y2, color); | |
line(x1, y1, x1, y2, color); | |
} | |
function fr(x, y, w, h, color) { //draw a filled rectangle | |
x1 = x|0; | |
y1 = y|0; | |
x2 = (x+w)|0; | |
y2 = (y+h)|0; | |
var i = Math.abs(y2 - y1); | |
line(x1, y1, x2, y1, color); | |
if(i > 0){ | |
while (--i) { | |
line(x1, y1+i, x2, y1+i, color); | |
} | |
} | |
line(x1,y2, x2, y2, color); | |
} | |
function triangle(x1, y1, x2, y2, x3, y3, color) { | |
line(x1,y1, x2,y2, color); | |
line(x2,y2, x3,y3, color); | |
line(x3,y3, x1,y1, color); | |
} | |
function fillTriangle( x1, y1, x2, y2, x3, y3, color ) { | |
var canvasWidth = 256; | |
// http://devmaster.net/forums/topic/1145-advanced-rasterization/ | |
// 28.4 fixed-point coordinates | |
var x1 = Math.round( 16 * x1 ); | |
var x2 = Math.round( 16 * x2 ); | |
var x3 = Math.round( 16 * x3 ); | |
var y1 = Math.round( 16 * y1 ); | |
var y2 = Math.round( 16 * y2 ); | |
var y3 = Math.round( 16 * y3 ); | |
// Deltas | |
var dx12 = x1 - x2, dy12 = y2 - y1; | |
var dx23 = x2 - x3, dy23 = y3 - y2; | |
var dx31 = x3 - x1, dy31 = y1 - y3; | |
// Bounding rectangle | |
var minx = Math.max( ( Math.min( x1, x2, x3 ) + 0xf ) >> 4, 0 ); | |
var maxx = Math.min( ( Math.max( x1, x2, x3 ) + 0xf ) >> 4, 256 ); | |
var miny = Math.max( ( Math.min( y1, y2, y3 ) + 0xf ) >> 4, 0 ); | |
var maxy = Math.min( ( Math.max( y1, y2, y3 ) + 0xf ) >> 4, 256 ); | |
// Block size, standard 8x8 (must be power of two) | |
var q = 8; | |
// Start in corner of 8x8 block | |
minx &= ~(q - 1); | |
miny &= ~(q - 1); | |
// Constant part of half-edge functions | |
var c1 = -dy12 * x1 - dx12 * y1; | |
var c2 = -dy23 * x2 - dx23 * y2; | |
var c3 = -dy31 * x3 - dx31 * y3; | |
// Correct for fill convention | |
if ( dy12 > 0 || ( dy12 == 0 && dx12 > 0 ) ) c1 ++; | |
if ( dy23 > 0 || ( dy23 == 0 && dx23 > 0 ) ) c2 ++; | |
if ( dy31 > 0 || ( dy31 == 0 && dx31 > 0 ) ) c3 ++; | |
// Note this doesn't kill subpixel precision, but only because we test for >=0 (not >0). | |
// It's a bit subtle. :) | |
c1 = (c1 - 1) >> 4; | |
c2 = (c2 - 1) >> 4; | |
c3 = (c3 - 1) >> 4; | |
// Set up min/max corners | |
var qm1 = q - 1; // for convenience | |
var nmin1 = 0, nmax1 = 0; | |
var nmin2 = 0, nmax2 = 0; | |
var nmin3 = 0, nmax3 = 0; | |
if (dx12 >= 0) nmax1 -= qm1*dx12; else nmin1 -= qm1*dx12; | |
if (dy12 >= 0) nmax1 -= qm1*dy12; else nmin1 -= qm1*dy12; | |
if (dx23 >= 0) nmax2 -= qm1*dx23; else nmin2 -= qm1*dx23; | |
if (dy23 >= 0) nmax2 -= qm1*dy23; else nmin2 -= qm1*dy23; | |
if (dx31 >= 0) nmax3 -= qm1*dx31; else nmin3 -= qm1*dx31; | |
if (dy31 >= 0) nmax3 -= qm1*dy31; else nmin3 -= qm1*dy31; | |
// Loop through blocks | |
var linestep = (canvasWidth-q); | |
for ( var y0 = miny; y0 < maxy; y0 += q ) { | |
for ( var x0 = minx; x0 < maxx; x0 += q ) { | |
// Edge functions at top-left corner | |
var cy1 = c1 + dx12 * y0 + dy12 * x0; | |
var cy2 = c2 + dx23 * y0 + dy23 * x0; | |
var cy3 = c3 + dx31 * y0 + dy31 * x0; | |
// Skip block when at least one edge completely out | |
if (cy1 < nmax1 || cy2 < nmax2 || cy3 < nmax3) continue; | |
// Offset at top-left corner | |
var offset = (x0 + y0 * canvasWidth); | |
// Accept whole block when fully covered | |
if (cy1 >= nmin1 && cy2 >= nmin2 && cy3 >= nmin3) { | |
for ( var iy = 0; iy < q; iy ++ ) { | |
for ( var ix = 0; ix < q; ix ++, offset ++ ) { | |
ram[renderTarget + offset] = color; | |
} | |
offset += linestep; | |
} | |
} else { // Partially covered block | |
for ( var iy = 0; iy < q; iy ++ ) { | |
var cx1 = cy1; | |
var cx2 = cy2; | |
var cx3 = cy3; | |
for ( var ix = 0; ix < q; ix ++ ) { | |
if ( (cx1 | cx2 | cx3) >= 0 ) { | |
ram[renderTarget + offset] = color; | |
} | |
cx1 += dy12; | |
cx2 += dy23; | |
cx3 += dy31; | |
offset ++; | |
} | |
cy1 += dx12; | |
cy2 += dx23; | |
cy3 += dx31; | |
offset += linestep; | |
} | |
} | |
} | |
} | |
} | |
function spr(sx = 0, sy = 0, sw = 16, sh = 16, x=0, y=0, flipx = false, flipy = false){ | |
for(var i = 0; i < sh; i++){ | |
for(var j = 0; j < sw; j++){ | |
if(y+i < HEIGHT && x+j < WIDTH && y+i > -1 && x+j > -1){ | |
if(flipx & flipy){ | |
if(ram[(renderSource + ( ( sy + (sh-i) )*WIDTH+sx+(sw-j)))] > 0) { | |
ram[ (renderTarget + ((y+i)*WIDTH+x+j)) ] = pal[ ram[(renderSource + ((sy+(sh-i))*WIDTH+sx+(sw-j)))] ]; | |
} | |
} | |
else if(flipy && !flipx){ | |
if(ram[(renderSource + ( ( sy + (sh-i) )*WIDTH+sx+j))] > 0) { | |
ram[ (renderTarget + ((y+i)*WIDTH+x+j)) ] = ram[(renderSource + ((sy+(sh-i))*WIDTH+sx+j))]; | |
} | |
} | |
else if(flipx && !flipy){ | |
if(ram[(renderSource + ((sy+i)*WIDTH+sx+(sw-j)))] > 0) { | |
ram[ (renderTarget + ((y+i)*WIDTH+x+j)) ] = ram[(renderSource + ((sy+i)*WIDTH+sx+(sw-j)))]; | |
} | |
} | |
else if(!flipx && !flipy){ | |
if(ram[(renderSource + ((sy+i)*WIDTH+sx+j))] > 0) { | |
ram[ (renderTarget + ((y+i)*WIDTH+x+j)) ] = pal[ ram[(renderSource + ((sy+i)*WIDTH+sx+j))] ]; | |
} | |
} | |
} | |
} | |
} | |
} | |
function sspr(sx = 0, sy = 0, sw = 16, sh = 16, x=0, y=0, dw=16, dh=16, flipx = false, flipy = false){ | |
var xratio = sw / dw; | |
var yratio = sh / dh; | |
for(var i = 0; i < dh; i++){ | |
for(var j = 0; j < dw; j++){ | |
px = (j*xratio)|0; | |
py = (i*yratio)|0; | |
if(y+i < HEIGHT && x+j < WIDTH && y+i > -1 && x+j > -1) { | |
if (ram[(renderSource + ((sy + py) * WIDTH + sx + px))] > 0) { | |
ram[(renderTarget + ((y + i) * WIDTH + x + j))] = ram[(renderSource + ((sy + py) * WIDTH + sx + px))] | |
} | |
} | |
} | |
} | |
} | |
function rspr( sx, sy, sw, sh, destCenterX, destCenterY, scale, angle ){ | |
angle = angle * 0.0174533 //convert to radians in place | |
var sourceCenterX = sx + sw / 2; | |
var sourceCenterY = sy + sh / 2; | |
var destWidth = sw * scale; | |
var destHeight = sh * scale; | |
var halfWidth = (destWidth / 2 * 1.41421356237)|0 + 5; //area will always be square, hypotenuse trick | |
var halfHeight = (destHeight / 2 * 1.41421356237)|0 + 5; | |
var startX = -halfWidth; | |
var endX = halfWidth; | |
var startY = -halfHeight; | |
var endY = halfHeight; | |
var scaleFactor = 1.0 / scale; | |
var cos = Math.cos(-angle) * scaleFactor; | |
var sin = Math.sin(-angle) * scaleFactor; | |
for(let y = startY; y < endY; y++){ | |
for(let x = startX; x < endX; x++){ | |
let u = sourceCenterX + Math.round(cos * x + sin * y); | |
let v = sourceCenterY + Math.round(-sin * x + cos * y); | |
let drawX = (x + destCenterX)|0; | |
let drawY = (y + destCenterY)|0; | |
if(u >= 0 && v >= 0 && u < sw && v < sh){ | |
if( ram[ (renderSource + (v * WIDTH + u)) ] > 0) { | |
ram[(renderTarget + (drawY * WIDTH + drawX)) ] = ram[(renderSource + ( v * WIDTH + u )) ] | |
} | |
} | |
} //end x loop | |
} //end outer y loop | |
} | |
function checker(w, h, nRow, nCol, color) { | |
//var w = 256; | |
//var h = 256; | |
var x = 0; | |
var y = 0; | |
nRow = nRow || 8; // default number of rows | |
nCol = nCol || 8; // default number of columns | |
w /= nCol; // width of a block | |
h /= nRow; // height of a block | |
for (var i = 0; i < nRow; ++i) { | |
for (var j = 0, col = nCol / 2; j < col; ++j) { | |
x = 2 * j * w + (i % 2 ? 0 : w); | |
y = i * h; | |
fr(x, y, w-1, h-1, color); | |
} | |
} | |
} | |
// util: { | |
// | |
// toPolarScreen(p){ | |
// let degrees = (360/256) * p.x * 0.0174533; | |
// let radius = p.y / 2; | |
// return util.polarToPoint(degrees, radius); | |
// }, | |
// | |
// norm(value, min, max){ | |
// return (value - min) / (max - min); | |
// }, | |
// | |
// dist(x0, y0, x1, y1) { | |
// if(arguments.length === 2) { | |
// return this.dist(x0.x, x0.y, y0.x, y0.y); | |
// } | |
// var dx = x1 - x0, | |
// dy = y1 - y0; | |
// return Math.sqrt(dx * dx + dy * dy); | |
// }, | |
// | |
// | |
// polarToPoint(angle, radius) { | |
// return { | |
// x: Math.cos(angle) * radius, | |
// y: Math.sin(angle) * radius | |
// }; | |
// }, | |
// | |
// pointToPolar(p) { | |
// return { | |
// angle: Math.atan2(p.y, p.x), | |
// radius: this.magnitude(p) | |
// }; | |
// }, | |
// | |
// magnitude(p) { | |
// return this.dist(0, 0, p.x, p.y); | |
// }, | |
// | |
// scale(p) { | |
// | |
// } | |
// | |
// | |
// }, | |
function render() { | |
var i = 0x20000; // display is first 0x20000 bytes of ram | |
while (i--) { | |
/* | |
data is 32bit view of final screen buffer | |
for each pixel on screen, we look up it's color and assign it | |
*/ | |
data[i] = colors[pal[ram[i]]]; | |
} | |
imageData.data.set(buf8); | |
ctx.putImageData(imageData, 0, 0); | |
} | |
playSound = function(buffer, playbackRate, pan, loop) { | |
var source = audioCtx.createBufferSource(); | |
var gainNode = audioCtx.createGain(); | |
var panNode = audioCtx.createStereoPanner(); | |
source.buffer = buffer; | |
source.connect(panNode); | |
panNode.connect(gainNode); | |
gainNode.connect(audioCtx.destination); | |
//gainNode.connect(audioCtx.destination); | |
source.playbackRate.value = playbackRate; | |
source.loop = loop; | |
gainNode.gain.value = 1; | |
panNode.pan.value = pan; | |
source.start(); | |
return {volume: gainNode, sound: source}; | |
} | |
init = function(){ | |
last = 0; | |
dt = 0; | |
now = 0; | |
t = 0; | |
moveX = 0; | |
speedFactor = .6; | |
songTrigger = false; | |
state = 'menu'; | |
demostate = 0; | |
audioCtx = new AudioContext; | |
fontString = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_!@.'\"?/<()"; | |
fontBitmap = "11111100011111110001100011111010001111101000111110111111000010000100000111111100100101000110001111101111110000111001000011111111111000"+ | |
"0111001000010000111111000010111100011111110001100011111110001100011111100100001000010011111111110001000010100101111010001100101110010010100011000"+ | |
"0100001000010000111111000111011101011000110001100011100110101100111000101110100011000110001011101111010001100101110010000011101000110001100100111"+ | |
"1111101000111110100011000101111100000111000001111101111100100001000010000100100011000110001100010111010001100011000101010001001000110001101011010"+ | |
"1011101000101010001000101010001100010101000100001000010011111000100010001000111110010001100001000010001110011101000100010001001111111110000010011"+ | |
"0000011111010010100101111100010000101111110000111100000111110011111000011110100010111011111000010001000100001000111010001011101000101110011101000"+ | |
"1011110000101110011101000110001100010111000000000000000000000111110010000100001000000000100111111000110111101011011101010111110101011111010100000"+ | |
"000000000000000000100001100001000100000000000011011010011001000000000000111010001001100000000100000010001000100010001000000010001000100000100000100001000100001000010000010" | |
// asciiBinary = '~cQz??I#_CH?|Ba<?FcdO~Rz90B?uFs,q:bwQKH2?h}/A`}yHc.FT$1VW"Q'+ | |
// 'F!D>#g"xtR|!?Ayx=_"t.Eg"x.:bpH!xo-j}/TC mQ@" BB'; | |
//console.log( getCharacter('A') ); | |
//console.log( assets.font.string.length ); | |
//console.log( flattenArray() ); | |
//console.log( binToAscii(assets.font.bigString) ); | |
//console.log( asciiToBin('~cQz??I#_CH?|Ba<?FcdO~Rz90B?uFs,q:bwQKH2?h}/A`}yHc.FT$1VW"Q'+ 'F!D>#g"xtR|!?Ayx=_"t.Eg"x.:bpH!xo-j}/TC mQ@" BB')); | |
//assets.font.bigString = asciiToBin(assets.font.bin); | |
//fontBitmap = (function(asciiBinary,b,i){b="";for(i in asciiBinary)b+=(1e7+s.charCodeAt(i).toString(2)).slice(-7);return b})(); | |
bulletPool = new Pool(100, Particle); | |
sounds = {}; | |
stats = new Stats(); | |
document.body.appendChild( stats.dom ); | |
bulletPool.init(); | |
player.init(); | |
soundInit(); | |
eventInit(); | |
//init vid capture | |
//capturer = new CCapture( {format: 'gif', workersPath: ''}); | |
//capturer.start(); | |
//start the game loop | |
loop(); | |
}, | |
stopCapture = (e) => { | |
//capturer.stop(); | |
//capturer.save(); | |
} | |
loop = () => { | |
stats.begin(); | |
//game timer | |
let now = new Date().getTime(); | |
dt = Math.min(1, (now - last) / 1000); | |
t += dt; | |
//draw current state to buffer | |
states[state].render(); | |
//update | |
states[state].step(dt); | |
last = now; | |
//draw buffer to screen | |
render(); | |
//GIF capture | |
//capturer.capture(C); | |
stats.end(); | |
requestAnimationFrame(loop); | |
} | |
soundInit = () => { | |
sounds = {}; | |
//if(audioCtx){audioCtx.close()}; | |
window.AudioContext = window.AudioContext || window.webkitAudioContext; | |
if(!audioCtx) audioCtx = new AudioContext; | |
let soundGen = new sonantx.SoundGenerator(assets.laser); | |
soundGen.createAudioBuffer(147, function(buffer) { | |
sounds.laser = buffer; | |
}); | |
} | |
eventInit = () => { | |
//initialize keypress event listeners | |
window.addEventListener('keyup', function (event) { | |
Key.onKeyup(event); | |
}, false); | |
window.addEventListener('mousedown', function (event){ | |
stopCapture(event); | |
}, false); | |
window.addEventListener('keydown', function (event) { | |
Key.onKeydown(event); | |
}, false); | |
window.addEventListener('blur', function (event) { | |
paused = true; | |
}, false); | |
window.addEventListener('focus', function (event) { | |
paused = false; | |
}, false); | |
} | |
states.gameover = { | |
step: function(dt) { | |
if(Key.isDown(Key.r)){ | |
state = 'menu'; | |
} | |
}, | |
render: function(dt) { | |
renderTarget = 0x0; | |
clear(0); | |
//fr(0,0,64,64,2); | |
text({ | |
x: 256, | |
y: 80 + Math.sin(t*2.5)*15, | |
text: 'GAME OVER', | |
hspacing: 8 + Math.cos(t*2.9)*4, | |
vspacing: 15 + Math.sin(t*3.5)*5, | |
halign: 'center', | |
valign: 'top', | |
scale: 9, | |
snap: 1, | |
render: 1, | |
color: 27, | |
}); | |
}, | |
}; | |
states.menu = { | |
step: function(dt) { | |
//game update | |
if(Key.isDown(Key.p)){ | |
state = 'game'; | |
} | |
}, | |
render: function(dt) { | |
renderTarget = 0x0; | |
clear(0); | |
let s = 256; | |
let i = t/3; | |
for(let y = -128; y < 128; y += 1 ){ | |
for(let x = -256; x < 256; x += 2 ){ | |
pset(s+x+256*Math.cos( (y/128+i)*4 )+y, s+y+128*Math.sin( (x/256+i)*4 )+x, x/8%32) | |
} | |
} | |
text({ | |
x: 256, | |
y: 40 + Math.sin(t*2.5)*15, | |
text: 'PROTOGAME', | |
hspacing: 8 + Math.cos(t*2.9)*4, | |
vspacing: 15 + Math.sin(t*3.5)*5, | |
halign: 'center', | |
valign: 'top', | |
scale: 9, | |
snap: 1, | |
render: 1, | |
color: 21, | |
}); | |
text({ | |
x: 256, | |
y: 230, | |
text: "PRESS P TO CONTINUE", | |
hspacing: 2, | |
vspacing: 2, | |
halign: 'center', | |
valign: 'top', | |
scale: 1, | |
snap: 1, | |
render: 1, | |
color: 21, | |
}); | |
//draw stuff here. | |
}, | |
}; | |
states.game = { | |
step(dt) { | |
player.update(dt); | |
//----hacky sound test | |
if(Key.justReleased(Key.SPACE)){ | |
songTrigger = true | |
} | |
if(songTrigger){ | |
playSound(sounds.laser, 1, 1, 0); | |
songTrigger = false; | |
} | |
//---end hacky sound test | |
bulletPool.use(); | |
Key.update(); | |
}, | |
render(dt) { | |
renderTarget = 0x0; | |
//background dot waves | |
clear(1); | |
let s = 256; | |
let i = t/3; | |
for(let y = -128; y < 128; y += 1 ){ | |
for(let x = -256; x < 256; x += 2 ){ | |
pset(s+x+256*Math.cos( (y/128+i)*4 )+y, s+y+128*Math.sin( (x/256+i)*4 )+x, x/8%32) | |
} | |
} | |
//foreground octopus thing | |
renderTarget = 0x40000; //rendering to different area, for collision checks and composite effects. | |
clear(0); | |
for(var a = 0; a < 2 * Math.PI; a+= 0.7){ | |
for(var r = 20; r < 200; r += 9){ | |
let v = a + .4 * Math.sin(a*8-r/20+t*1.7); | |
fillCircle((256+r*Math.cos(v)), 80+r*Math.sin(v), (10-r/12)|0, 10+(r/9%32)|0 ); | |
} | |
} | |
renderTarget = 0x0; | |
renderSource = 0x40000; | |
spr(0,0,512,256); | |
player.draw(); | |
renderTarget = 0; | |
text({ | |
x: 256, | |
y: 20, | |
text: "YOU CANT DEFEAT HIM, THIS IS JUST A PIXEL-PERFECT COLLISION\nAND MULTI-LAYER DRAWING DEMO\nARROW KEYS OR WASD AND SPACE TO SHOOT", | |
hspacing: 2, | |
vspacing: 2, | |
halign: 'center', | |
valign: 'top', | |
scale: 1, | |
snap: 1, | |
render: 1, | |
color: 21, | |
}); | |
}, | |
}; | |
function drawExplode(x,y){ | |
fillCircle(x,y, 20, 21); | |
} | |
function textLine(opt) { | |
var textLength = opt.text.length, | |
size = 5; | |
for (var i = 0; i < textLength; i++) { | |
var letter = []; | |
letter = getCharacter( opt.text.charAt(i) ); | |
//console.log(letter); | |
//console.log(assets.letters[ opt.text.charAt(i)]); | |
for (var y = 0; y < size; y++) { | |
for (var x = 0; x < size; x++) { | |
//if (letter[y][x] == 1) { | |
if (letter[y*size+x] == 1){ | |
if(opt.scale == 1){ | |
pset( | |
opt.x + ( x * opt.scale ) + ( ( size * opt.scale ) + opt.hspacing ) * i, | |
opt.y + (y * opt.scale), | |
opt.color | |
); | |
} | |
else { | |
fr( | |
opt.x + ( x * opt.scale ) + ( ( size * opt.scale ) + opt.hspacing ) * i, | |
opt.y + (y * opt.scale), | |
opt.scale, | |
opt.scale, | |
opt.color); | |
} | |
} //end draw routine | |
} //end x loop | |
} //end y loop | |
} //end text loop | |
} //end textLine() | |
function text(opt) { | |
var size = 5, | |
letterSize = size * opt.scale, | |
lines = opt.text.split('\n'), | |
linesCopy = lines.slice(0), | |
lineCount = lines.length, | |
longestLine = linesCopy.sort(function (a, b) { | |
return b.length - a.length; | |
})[0], | |
textWidth = ( longestLine.length * letterSize ) + ( ( longestLine.length - 1 ) * opt.hspacing ), | |
textHeight = ( lineCount * letterSize ) + ( ( lineCount - 1 ) * opt.vspacing ); | |
if(!opt.halign)opt.halign = 'left'; | |
if(!opt.valign)opt.valign = 'bottom'; | |
var sx = opt.x, | |
sy = opt.y, | |
ex = opt.x + textWidth, | |
ey = opt.y + textHeight; | |
if (opt.halign == 'center') { | |
sx = opt.x - textWidth / 2; | |
ex = opt.x + textWidth / 2; | |
} else if (opt.halign == 'right') { | |
sx = opt.x - textWidth; | |
ex = opt.x; | |
} | |
if (opt.valign == 'center') { | |
sy = opt.y - textHeight / 2; | |
ey = opt.y + textHeight / 2; | |
} else if (opt.valign == 'bottom') { | |
sy = opt.y - textHeight; | |
ey = opt.y; | |
} | |
var cx = sx + textWidth / 2, | |
cy = sy + textHeight / 2; | |
if (opt.render) { | |
for (var i = 0; i < lineCount; i++) { | |
var line = lines[i], | |
lineWidth = ( line.length * letterSize ) + ( ( line.length - 1 ) * opt.hspacing ), | |
x = opt.x, | |
y = opt.y + ( letterSize + opt.vspacing ) * i; | |
if (opt.halign == 'center') { | |
x = opt.x - lineWidth / 2; | |
} else if (opt.halign == 'right') { | |
x = opt.x - lineWidth; | |
} | |
if (opt.valign == 'center') { | |
y = y - textHeight / 2; | |
} else if (opt.valign == 'bottom') { | |
y = y - textHeight; | |
} | |
if (opt.snap) { | |
x = Math.floor(x); | |
y = Math.floor(y); | |
} | |
textLine({ | |
x: x, | |
y: y, | |
text: line, | |
hspacing: opt.hspacing || 0, | |
scale: opt.scale || 1, | |
color: opt.color | |
}); | |
} | |
} | |
return { | |
sx: sx, | |
sy: sy, | |
cx: cx, | |
cy: cy, | |
ex: ex, | |
ey: ey, | |
width: textWidth, | |
height: textHeight | |
} | |
} | |
function getCharacter(char){ | |
index = fontString.indexOf(char); | |
return fontBitmap.substring(index * 25, index*25+25).split('') ; | |
} | |
// function flattenArray(){ | |
// var bigString = ""; | |
// bin = assets.font.bin; | |
// for(var i = 0; i < assets.font.string.length; i++){ | |
// for(var j = 0; j < 5; j++){ | |
// bigString += bin[j][0].substring(i * 5, i*5+5); | |
// } | |
// } | |
// console.log(bigString); | |
// return bigString; | |
// } | |
// function binToAscii(b,a,i){ | |
// a=""; | |
// for(i=0;i<b.length;i+=7)a+=String.fromCharCode(parseInt(b.substr(i,7),2)); | |
// return a | |
// } | |
//function asciiToBin(s,b,i){b="";for(i in s)b+=(1e7+s.charCodeAt(i).toString(2)).slice(-7);return b} | |
player = { | |
// x: 0, | |
// y: 0, | |
// radius: 12, | |
// xvel: 0, | |
// yvel: 0, | |
// speed: 6, | |
// drag: .97, | |
bullet: { | |
x: 0, y:0, xvel: 0, yvel: 0 | |
}, | |
init (){ | |
this.x = 64; | |
this.y = 230; | |
this.radius = 12; | |
this.xvel = 0; | |
this.yvel = 0; | |
this.xspeed = 400; | |
this.yspeed = 400; | |
this.drag = .6; | |
}, | |
update (dt) { | |
this.bullet.x = player.x; | |
this.bullet.y = player.y; | |
this.xvel *= player.drag; | |
this.yvel *= player.drag; | |
let xIntegrate = dt * player.xvel; | |
let yIntegrate = dt * player.yvel; | |
player.x += xIntegrate; | |
player.y += yIntegrate; | |
//player movement | |
if (Key.isDown(Key.d) || Key.isDown(Key.RIGHT)) { | |
player.xvel = player.xspeed; | |
} | |
if (Key.isDown(Key.a) || Key.isDown(Key.LEFT)){ | |
player.xvel = - player.xspeed; | |
} | |
if(Key.isDown(Key.w) || Key.isDown(Key.UP)){ | |
player.yvel = -player.yspeed; | |
} | |
if(Key.isDown(Key.s) || Key.isDown(Key.DOWN)) { | |
player.yvel = player.yspeed; | |
} | |
if(Key.isDown(Key.SPACE || Key.isDown(Key.z))){ | |
//player.bullet.xvel = E.player.xvel; | |
player.bullet.yvel = -350; | |
bulletPool.get(player.bullet); | |
} | |
//world wrap for player | |
if(player.x > WIDTH){ | |
player.x = 0; | |
} | |
if(player.x < 0){ | |
player.x = WIDTH; | |
} | |
if(player.y > HEIGHT){ | |
player.y = 0; | |
} | |
if(player.y < 0){ | |
state = 'gameover'; | |
player.y = HEIGHT; | |
} | |
//end world wrap for player | |
}, | |
draw (dt) { | |
// let degrees = (360/256) * E.player.x * 0.0174533; | |
// let radius = (E.player.y / 2); | |
// let playerDrawPoint = E.util.toPolarScreen({x:E.player.x, y:E.player.y}); | |
// | |
// let distFromCenter = E.util.dist(playerDrawPoint.x+128, playerDrawPoint.y+128, 128,128); | |
// | |
// let playerSizeFactor = E.util.norm(distFromCenter, 0, 128); | |
//E.renderTarget = E.screen; | |
//E.gfx.fillCircle(playerDrawPoint.x+128, playerDrawPoint.y+128, E.player.radius * playerSizeFactor, 21); | |
fillCircle(this.x, this.y, this.radius, 21); | |
}, | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment