diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..60ecc82 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +lib +node_modules +.merlin diff --git a/README.md b/README.md new file mode 100644 index 0000000..c1b1c29 --- /dev/null +++ b/README.md @@ -0,0 +1,31 @@ +Reprocessing example project +--- + +This is a starter example project. Just clone to get started! + +## How to +``` +git clone https://github.com/bsansouci/reprocessing-example.git +``` + +### Install +_warning_: this doesn't work with npm5 yet. Use npm4 or use yarn. To downgrade to npm4 you can `npm install -g npm@latest-4` +``` +yarn +``` + +### Build +``` +npm run build +``` + +### Start +``` +npm start +``` + +To build to JS run `npm run build:web` and then run a static server, like `python -m SimpleHTTPServer` and go to `localhost:8000`. If you're using safari you can simply open the `index.html` and tick `Develop > Disable Cross-Origin Restrictions`. + +To build to native run `npm run build:native` and run `npm run start:native` + +The build system used is [bsb-native](https://github.com/bsansouci/bsb-native). diff --git a/assets/font/font.fnt b/assets/font/font.fnt new file mode 100755 index 0000000..90c08a3 --- /dev/null +++ b/assets/font/font.fnt @@ -0,0 +1,194 @@ +info face=font size=32 bold=0 italic=0 charset= unicode= stretchH=100 smooth=1 aa=1 padding=3,3,3,3 spacing=0,0 outline=0 +common lineHeight=36 base=25 scaleW=256 scaleH=256 pages=1 packed=0 +page id=0 file="font.png" +chars count=91 +char id=97 x=3 y=3 width=16 height=18 xoffset=1 yoffset=8 xadvance=18 page=0 chnl=15 +char id=98 x=3 y=24 width=15 height=24 xoffset=2 yoffset=2 xadvance=18 page=0 chnl=15 +char id=99 x=3 y=51 width=15 height=18 xoffset=1 yoffset=8 xadvance=16 page=0 chnl=15 +char id=100 x=3 y=72 width=15 height=24 xoffset=1 yoffset=2 xadvance=18 page=0 chnl=15 +char id=101 x=3 y=99 width=16 height=18 xoffset=1 yoffset=8 xadvance=18 page=0 chnl=15 +char id=102 x=21 y=24 width=10 height=24 xoffset=0 yoffset=2 xadvance=9 page=0 chnl=15 +char id=103 x=21 y=51 width=15 height=24 xoffset=1 yoffset=8 xadvance=18 page=0 chnl=15 +char id=104 x=34 y=3 width=14 height=23 xoffset=2 yoffset=2 xadvance=18 page=0 chnl=15 +char id=105 x=3 y=120 width=3 height=23 xoffset=2 yoffset=2 xadvance=7 page=0 chnl=15 +char id=106 x=3 y=146 width=7 height=30 xoffset=-1 yoffset=2 xadvance=7 page=0 chnl=15 +char id=107 x=9 y=120 width=14 height=23 xoffset=2 yoffset=2 xadvance=16 page=0 chnl=15 +char id=108 x=22 y=78 width=3 height=23 xoffset=2 yoffset=2 xadvance=7 page=0 chnl=15 +char id=109 x=34 y=29 width=23 height=17 xoffset=2 yoffset=8 xadvance=27 page=0 chnl=15 +char id=110 x=51 y=3 width=14 height=17 xoffset=2 yoffset=8 xadvance=18 page=0 chnl=15 +char id=111 x=3 y=179 width=16 height=18 xoffset=1 yoffset=8 xadvance=18 page=0 chnl=15 +char id=112 x=13 y=146 width=15 height=24 xoffset=2 yoffset=8 xadvance=18 page=0 chnl=15 +char id=113 x=26 y=104 width=15 height=24 xoffset=1 yoffset=8 xadvance=18 page=0 chnl=15 +char id=114 x=22 y=3 width=9 height=17 xoffset=2 yoffset=8 xadvance=11 page=0 chnl=15 +char id=115 x=28 y=78 width=14 height=18 xoffset=1 yoffset=8 xadvance=16 page=0 chnl=15 +char id=116 x=39 y=49 width=8 height=23 xoffset=1 yoffset=3 xadvance=9 page=0 chnl=15 +char id=117 x=3 y=200 width=14 height=17 xoffset=2 yoffset=8 xadvance=18 page=0 chnl=15 +char id=118 x=3 y=220 width=16 height=17 xoffset=0 yoffset=8 xadvance=16 page=0 chnl=15 +char id=119 x=20 y=200 width=23 height=17 xoffset=0 yoffset=8 xadvance=23 page=0 chnl=15 +char id=120 x=22 y=173 width=16 height=17 xoffset=0 yoffset=8 xadvance=16 page=0 chnl=15 +char id=121 x=22 y=220 width=16 height=24 xoffset=1 yoffset=8 xadvance=16 page=0 chnl=15 +char id=122 x=41 y=220 width=15 height=17 xoffset=1 yoffset=8 xadvance=16 page=0 chnl=15 +char id=65 x=31 y=131 width=22 height=23 xoffset=0 yoffset=2 xadvance=21 page=0 chnl=15 +char id=66 x=44 y=99 width=18 height=23 xoffset=2 yoffset=2 xadvance=21 page=0 chnl=15 +char id=67 x=41 y=157 width=21 height=24 xoffset=2 yoffset=2 xadvance=23 page=0 chnl=15 +char id=68 x=56 y=125 width=19 height=23 xoffset=2 yoffset=2 xadvance=23 page=0 chnl=15 +char id=69 x=46 y=184 width=17 height=23 xoffset=3 yoffset=2 xadvance=21 page=0 chnl=15 +char id=70 x=65 y=151 width=16 height=23 xoffset=3 yoffset=2 xadvance=20 page=0 chnl=15 +char id=71 x=59 y=210 width=22 height=24 xoffset=2 yoffset=2 xadvance=25 page=0 chnl=15 +char id=72 x=66 y=177 width=18 height=23 xoffset=3 yoffset=2 xadvance=23 page=0 chnl=15 +char id=73 x=50 y=49 width=3 height=23 xoffset=3 yoffset=2 xadvance=9 page=0 chnl=15 +char id=74 x=56 y=49 width=13 height=24 xoffset=1 yoffset=2 xadvance=16 page=0 chnl=15 +char id=75 x=60 y=23 width=19 height=23 xoffset=2 yoffset=2 xadvance=21 page=0 chnl=15 +char id=76 x=65 y=76 width=15 height=23 xoffset=2 yoffset=2 xadvance=18 page=0 chnl=15 +char id=77 x=72 y=49 width=22 height=23 xoffset=2 yoffset=2 xadvance=27 page=0 chnl=15 +char id=78 x=82 y=3 width=18 height=23 xoffset=2 yoffset=2 xadvance=23 page=0 chnl=15 +char id=79 x=78 y=102 width=22 height=24 xoffset=2 yoffset=2 xadvance=25 page=0 chnl=15 +char id=80 x=83 y=75 width=18 height=23 xoffset=2 yoffset=2 xadvance=21 page=0 chnl=15 +char id=81 x=97 y=29 width=23 height=25 xoffset=1 yoffset=2 xadvance=25 page=0 chnl=15 +char id=82 x=103 y=3 width=20 height=23 xoffset=3 yoffset=2 xadvance=23 page=0 chnl=15 +char id=83 x=84 y=129 width=19 height=24 xoffset=1 yoffset=2 xadvance=21 page=0 chnl=15 +char id=84 x=103 y=101 width=19 height=23 xoffset=1 yoffset=2 xadvance=20 page=0 chnl=15 +char id=85 x=104 y=57 width=18 height=24 xoffset=3 yoffset=2 xadvance=23 page=0 chnl=15 +char id=86 x=123 y=29 width=21 height=23 xoffset=0 yoffset=2 xadvance=21 page=0 chnl=15 +char id=87 x=126 y=3 width=30 height=23 xoffset=0 yoffset=2 xadvance=30 page=0 chnl=15 +char id=88 x=84 y=203 width=21 height=23 xoffset=0 yoffset=2 xadvance=21 page=0 chnl=15 +char id=89 x=84 y=229 width=21 height=23 xoffset=0 yoffset=2 xadvance=21 page=0 chnl=15 +char id=90 x=87 y=156 width=18 height=23 xoffset=1 yoffset=2 xadvance=20 page=0 chnl=15 +char id=48 x=106 y=127 width=15 height=24 xoffset=1 yoffset=2 xadvance=18 page=0 chnl=15 +char id=49 x=108 y=154 width=9 height=23 xoffset=3 yoffset=2 xadvance=18 page=0 chnl=15 +char id=50 x=108 y=180 width=16 height=23 xoffset=1 yoffset=2 xadvance=18 page=0 chnl=15 +char id=51 x=108 y=206 width=15 height=24 xoffset=1 yoffset=2 xadvance=18 page=0 chnl=15 +char id=52 x=120 y=154 width=16 height=23 xoffset=0 yoffset=2 xadvance=18 page=0 chnl=15 +char id=53 x=124 y=127 width=16 height=23 xoffset=1 yoffset=2 xadvance=18 page=0 chnl=15 +char id=54 x=126 y=206 width=15 height=24 xoffset=1 yoffset=2 xadvance=18 page=0 chnl=15 +char id=55 x=127 y=180 width=15 height=23 xoffset=2 yoffset=2 xadvance=18 page=0 chnl=15 +char id=56 x=139 y=153 width=15 height=24 xoffset=1 yoffset=2 xadvance=18 page=0 chnl=15 +char id=57 x=144 y=206 width=15 height=24 xoffset=1 yoffset=2 xadvance=18 page=0 chnl=15 +char id=33 x=145 y=180 width=4 height=23 xoffset=3 yoffset=2 xadvance=9 page=0 chnl=15 +char id=8470 x=152 y=180 width=31 height=23 xoffset=3 yoffset=2 xadvance=34 page=0 chnl=15 +char id=59 x=45 y=75 width=4 height=21 xoffset=3 yoffset=8 xadvance=9 page=0 chnl=15 +char id=37 x=162 y=206 width=25 height=24 xoffset=2 yoffset=2 xadvance=28 page=0 chnl=15 +char id=58 x=68 y=3 width=4 height=17 xoffset=3 yoffset=8 xadvance=9 page=0 chnl=15 +char id=63 x=125 y=55 width=15 height=24 xoffset=1 yoffset=2 xadvance=18 page=0 chnl=15 +char id=42 x=82 y=29 width=11 height=10 xoffset=1 yoffset=2 xadvance=12 page=0 chnl=15 +char id=40 x=125 y=82 width=8 height=30 xoffset=2 yoffset=2 xadvance=11 page=0 chnl=15 +char id=41 x=136 y=82 width=8 height=30 xoffset=2 yoffset=2 xadvance=11 page=0 chnl=15 +char id=95 x=22 y=193 width=19 height=2 xoffset=0 yoffset=29 xadvance=18 page=0 chnl=15 +char id=43 x=59 y=237 width=15 height=15 xoffset=2 yoffset=6 xadvance=19 page=0 chnl=15 +char id=45 x=44 y=125 width=9 height=3 xoffset=1 yoffset=15 xadvance=11 page=0 chnl=15 +char id=61 x=41 y=240 width=15 height=10 xoffset=2 yoffset=9 xadvance=19 page=0 chnl=15 +char id=46 x=82 y=42 width=4 height=4 xoffset=3 yoffset=22 xadvance=9 page=0 chnl=15 +char id=44 x=97 y=57 width=4 height=8 xoffset=3 yoffset=22 xadvance=9 page=0 chnl=15 +char id=47 x=143 y=55 width=9 height=24 xoffset=0 yoffset=2 xadvance=9 page=0 chnl=15 +char id=124 x=143 y=115 width=3 height=30 xoffset=3 yoffset=2 xadvance=8 page=0 chnl=15 +char id=92 x=147 y=82 width=9 height=24 xoffset=0 yoffset=2 xadvance=9 page=0 chnl=15 +char id=34 x=125 y=115 width=9 height=8 xoffset=1 yoffset=2 xadvance=11 page=0 chnl=15 +char id=39 x=77 y=237 width=4 height=8 xoffset=1 yoffset=2 xadvance=6 page=0 chnl=15 +char id=64 x=149 y=109 width=30 height=30 xoffset=2 yoffset=2 xadvance=32 page=0 chnl=15 +char id=35 x=157 y=142 width=17 height=24 xoffset=0 yoffset=2 xadvance=18 page=0 chnl=15 +char id=36 x=177 y=142 width=16 height=29 xoffset=1 yoffset=0 xadvance=18 page=0 chnl=15 +char id=94 x=3 y=240 width=14 height=13 xoffset=1 yoffset=2 xadvance=15 page=0 chnl=15 +char id=38 x=186 y=174 width=20 height=24 xoffset=1 yoffset=2 xadvance=21 page=0 chnl=15 +char id=123 x=155 y=29 width=9 height=30 xoffset=1 yoffset=2 xadvance=11 page=0 chnl=15 +char id=125 x=159 y=62 width=9 height=30 xoffset=1 yoffset=2 xadvance=11 page=0 chnl=15 +char id=91 x=190 y=201 width=7 height=30 xoffset=2 yoffset=2 xadvance=9 page=0 chnl=15 +char id=93 x=200 y=201 width=7 height=30 xoffset=1 yoffset=2 xadvance=9 page=0 chnl=15 +char id=32 x=0 y=0 width=0 height=0 xoffset=1 yoffset=2 xadvance=9 page=0 chnl=15 +kernings count=97 +kerning first=32 second=65 amount=-2 +kerning first=32 second=84 amount=-1 +kerning first=32 second=89 amount=-1 +kerning first=49 second=49 amount=-2 +kerning first=65 second=32 amount=-2 +kerning first=65 second=84 amount=-2 +kerning first=65 second=86 amount=-2 +kerning first=65 second=87 amount=-1 +kerning first=65 second=89 amount=-2 +kerning first=65 second=118 amount=-1 +kerning first=65 second=119 amount=-1 +kerning first=65 second=121 amount=-1 +kerning first=70 second=44 amount=-4 +kerning first=70 second=46 amount=-4 +kerning first=70 second=65 amount=-2 +kerning first=76 second=32 amount=-1 +kerning first=76 second=84 amount=-2 +kerning first=76 second=86 amount=-2 +kerning first=76 second=87 amount=-2 +kerning first=76 second=89 amount=-2 +kerning first=76 second=121 amount=-1 +kerning first=80 second=32 amount=-1 +kerning first=80 second=44 amount=-4 +kerning first=80 second=46 amount=-4 +kerning first=80 second=65 amount=-2 +kerning first=82 second=84 amount=-1 +kerning first=82 second=86 amount=-1 +kerning first=82 second=87 amount=-1 +kerning first=82 second=89 amount=-1 +kerning first=84 second=32 amount=-1 +kerning first=84 second=44 amount=-4 +kerning first=84 second=45 amount=-2 +kerning first=84 second=46 amount=-4 +kerning first=84 second=58 amount=-4 +kerning first=84 second=59 amount=-4 +kerning first=84 second=65 amount=-2 +kerning first=84 second=79 amount=-1 +kerning first=84 second=97 amount=-4 +kerning first=84 second=99 amount=-4 +kerning first=84 second=101 amount=-4 +kerning first=84 second=105 amount=-1 +kerning first=84 second=111 amount=-4 +kerning first=84 second=114 amount=-1 +kerning first=84 second=115 amount=-4 +kerning first=84 second=117 amount=-1 +kerning first=84 second=119 amount=-2 +kerning first=84 second=121 amount=-2 +kerning first=86 second=44 amount=-3 +kerning first=86 second=45 amount=-2 +kerning first=86 second=46 amount=-3 +kerning first=86 second=58 amount=-1 +kerning first=86 second=59 amount=-1 +kerning first=86 second=65 amount=-2 +kerning first=86 second=97 amount=-2 +kerning first=86 second=101 amount=-2 +kerning first=86 second=105 amount=-1 +kerning first=86 second=111 amount=-2 +kerning first=86 second=114 amount=-1 +kerning first=86 second=117 amount=-1 +kerning first=86 second=121 amount=-1 +kerning first=87 second=44 amount=-2 +kerning first=87 second=45 amount=-1 +kerning first=87 second=46 amount=-2 +kerning first=87 second=58 amount=-1 +kerning first=87 second=59 amount=-1 +kerning first=87 second=65 amount=-1 +kerning first=87 second=97 amount=-1 +kerning first=87 second=101 amount=-1 +kerning first=87 second=105 amount=0 +kerning first=87 second=111 amount=-1 +kerning first=87 second=114 amount=-1 +kerning first=87 second=117 amount=-1 +kerning first=87 second=121 amount=0 +kerning first=89 second=32 amount=-1 +kerning first=89 second=44 amount=-4 +kerning first=89 second=45 amount=-3 +kerning first=89 second=46 amount=-4 +kerning first=89 second=58 amount=-2 +kerning first=89 second=59 amount=-2 +kerning first=89 second=65 amount=-2 +kerning first=89 second=97 amount=-2 +kerning first=89 second=101 amount=-3 +kerning first=89 second=105 amount=-1 +kerning first=89 second=111 amount=-3 +kerning first=89 second=112 amount=-2 +kerning first=89 second=113 amount=-3 +kerning first=89 second=117 amount=-2 +kerning first=89 second=118 amount=-2 +kerning first=102 second=102 amount=-1 +kerning first=114 second=44 amount=-2 +kerning first=114 second=46 amount=-2 +kerning first=118 second=44 amount=-2 +kerning first=118 second=46 amount=-2 +kerning first=119 second=44 amount=-2 +kerning first=119 second=46 amount=-2 +kerning first=121 second=44 amount=-2 +kerning first=121 second=46 amount=-2 \ No newline at end of file diff --git a/assets/font/font.png b/assets/font/font.png new file mode 100755 index 0000000..8b7758c Binary files /dev/null and b/assets/font/font.png differ diff --git a/assets/spritesheet.png b/assets/spritesheet.png new file mode 100644 index 0000000..7dd620f Binary files /dev/null and b/assets/spritesheet.png differ diff --git a/bsconfig.json b/bsconfig.json new file mode 100644 index 0000000..01602e3 --- /dev/null +++ b/bsconfig.json @@ -0,0 +1,16 @@ +{ + "name": "reprocessing-example", + "sources": "src", + "bs-dependencies": ["reprocessing"], + "entries": [{ + "backend": "bytecode", + "main-module": "IndexHot" + },{ + "backend": "native", + "main-module": "Index" + },{ + "backend": "js", + "main-module": "Index" + }], + "refmt": 3, +} diff --git a/index.html b/index.html new file mode 100644 index 0000000..115730d --- /dev/null +++ b/index.html @@ -0,0 +1,9 @@ + + + + Reprocessing Example + + + + + diff --git a/package.json b/package.json new file mode 100644 index 0000000..4fc60e1 --- /dev/null +++ b/package.json @@ -0,0 +1,17 @@ +{ + "name": "reprocessing-example", + "scripts": { + "start": "./lib/bs/bytecode/index.byte", + "start:native": "./lib/bs/native/index.native", + "build": "bsb -make-world", + "build:web": "bsb -make-world -backend js", + "build:native": "bsb -make-world -backend native", + "clean": "bsb -clean-world" + }, + "dependencies": { + "reprocessing": "schmavery/reprocessing" + }, + "devDependencies": { + "bs-platform": "bsansouci/bsb-native" + } +} diff --git a/require_polyfill.js b/require_polyfill.js new file mode 100644 index 0000000..519d0cd --- /dev/null +++ b/require_polyfill.js @@ -0,0 +1,129 @@ +function normalizeArray(parts, allowAboveRoot) { + // if the path tries to go above the root, `up` ends up > 0 + var up = 0; + for (var i = parts.length - 1; i >= 0; i--) { + var last = parts[i]; + if (last === '.') { + parts.splice(i, 1); + } else if (last === '..') { + parts.splice(i, 1); + up++; + } else if (up) { + parts.splice(i, 1); + up--; + } + } + + // if the path is allowed to go above the root, restore leading ..s + if (allowAboveRoot) { + for (; up--; up) { + parts.unshift('..'); + } + } + + return parts; +}; + +function pathNormalize(path) { + var isAbsolute = path.charAt(0) === '/'; + var trailingSlash = path.substr(-1) === '/'; + + // Normalize the path + path = normalizeArray(path.split('/').filter(function(p) { + return !!p; + }), !isAbsolute).join('/'); + + if (!path && !isAbsolute) { + path = '.'; + } + if (path && trailingSlash) { + path += '/'; + } + + return (isAbsolute ? '/' : '') + path; +}; + +var globalEval = eval; +var currentScript = document.currentScript; +var projectRoot = currentScript.dataset['project-root'] || currentScript.dataset['projectRoot']; +if (projectRoot == null) { + throw new Error('The attribute `data-project-root` isn\'t found in the script tag. You need to provide the root (in which node_modules reside).') +} +var nodeModulesDir = projectRoot + '/node_modules/'; + +var modulesCache = {}; +var packageJsonMainCache = {}; + +var ensureEndsWithJs = function(path) { + if (path.endsWith('.js')) { + return path; + } else { + return path + '.js'; + } +}; +function loadScript(scriptPath) { + var request = new XMLHttpRequest(); + + request.open("GET", scriptPath, false); // sync + request.send(); + var dirSeparatorIndex = scriptPath.lastIndexOf('/'); + var dir = dirSeparatorIndex === -1 ? '.' : scriptPath.slice(0, dirSeparatorIndex); + + var moduleText = ` +(function(module, exports, modulesCache, packageJsonMainCache, nodeModulesDir) { + function require(path) { + var __dirname = "${dir}/"; + var resolvedPath; + if (path.startsWith('.')) { + // require('./foo/bar') + resolvedPath = ensureEndsWithJs(__dirname + path); + } else if (path.indexOf('/') === -1) { + // require('react') + var packageJson = pathNormalize(nodeModulesDir + path + '/package.json'); + if (packageJsonMainCache[packageJson] == null) { + var jsonRequest = new XMLHttpRequest(); + jsonRequest.open("GET", packageJson, false); + jsonRequest.send(); + var main; + if (jsonRequest.responseText != null) { + main = JSON.parse(jsonRequest.responseText).main; + }; + if (main == null) { + main = 'index.js'; + } else if (!main.endsWith('.js')) { + main = main + '.js'; + } + packageJsonMainCache[packageJson] = nodeModulesDir + path + '/' + main; + } + resolvedPath = packageJsonMainCache[packageJson]; + } else { + // require('react/bar') + resolvedPath = ensureEndsWithJs(nodeModulesDir + path); + }; + resolvedPath = pathNormalize(resolvedPath); + if (modulesCache[resolvedPath] != null) { + return modulesCache[resolvedPath]; + }; + var result = loadScript(resolvedPath); + modulesCache[resolvedPath] = result; + return result; + }; + var process = {env: {}, argv: []}; + var global = {}; + + +// -------Begin Require Polyfilled Module Loaded From Disk------------------------------ +// file: ${scriptPath} +// root: ${projectRoot} +// ---------------------------------------------------------------------- +${request.responseText} +// -------End Polyfill Loaded From Disk------------------------------ +// file: ${scriptPath} +// root: ${projectRoot} +// ---------------------------------------------------------------------- +return module.exports})\n//@ sourceURL=${scriptPath}`; + var module = {exports: {}}; + return globalEval(moduleText)(module, module.exports, modulesCache, packageJsonMainCache, nodeModulesDir); +}; + +loadScript(currentScript.dataset.main) diff --git a/src/IndexHot.re b/src/IndexHot.re new file mode 100644 index 0000000..e2e15e3 --- /dev/null +++ b/src/IndexHot.re @@ -0,0 +1 @@ +Reprocessing.hotreload("src/index.re"); diff --git a/src/index.re b/src/index.re new file mode 100644 index 0000000..5259a86 --- /dev/null +++ b/src/index.re @@ -0,0 +1,357 @@ +open Reprocessing; + +let playerSpeed = 4.; + +let bulletSpeed = 6.; + +type vec2T = { + x: float, + y: float +}; + +type bulletT = { + pos: vec2T, + direction: vec2T, + time: float, + moveBullet: bulletT => vec2T +}; + +type achievementStateT = + | Locked + | Unlocked; + +type gunT = { + amunition: int, + color: colorT, + keyToggle: Reprocessing_Common.KeySet.elt, + fire: (stateT, Reprocessing_Common.KeySet.elt) => stateT +} +and achievementT = { + gun: gunT, + state: achievementStateT, + condition: (stateT, glEnvT) => bool +} +and stateT = { + pos: vec2T, + guns: list(gunT), + equippedGun: int, + playerBullets: list(bulletT), + achievements: list(achievementT), + mainFont: fontT +}; + +let add = (v1, v2) => {x: v1.x +. v2.x, y: v1.y +. v2.y}; + +let defaultGun = { + amunition: 10, + color: Utils.color(155, 155, 0, 255), + keyToggle: Num_1, + fire: (state, direction) => { + let dir = + switch direction { + | Up => {x: 0., y: -. bulletSpeed} + | Down => {x: 0., y: bulletSpeed} + | Left => {x: -. bulletSpeed, y: 0.} + | Right => {x: bulletSpeed, y: 0.} + | _ => assert false + }; + let moveBullet = (bullet: bulletT) => add(bullet.pos, bullet.direction); + { + ...state, + guns: + List.mapi( + (i, gun) => + if (i === state.equippedGun) { + {...gun, amunition: max(gun.amunition - 1, 0)} + } else { + gun + }, + state.guns + ), + playerBullets: + List.nth(state.guns, state.equippedGun).amunition > 0 ? + [ + {pos: {x: state.pos.x, y: state.pos.y}, direction: dir, moveBullet, time: 0.}, + ...state.playerBullets + ] : + state.playerBullets + } + } +}; + +let gunWithSpread = { + amunition: 10, + color: Utils.color(0, 255, 0, 255), + keyToggle: Num_2, + fire: (state, direction) => { + let otherSpeed = 2.; + let dir1 = + switch direction { + | Up => {x: -. otherSpeed, y: -. bulletSpeed} + | Down => {x: otherSpeed, y: bulletSpeed} + | Left => {x: -. bulletSpeed, y: otherSpeed} + | Right => {x: bulletSpeed, y: -. otherSpeed} + | _ => assert false + }; + let dir2 = + switch direction { + | Up => {x: 0., y: -. bulletSpeed} + | Down => {x: 0., y: bulletSpeed} + | Left => {x: -. bulletSpeed, y: 0.} + | Right => {x: bulletSpeed, y: 0.} + | _ => assert false + }; + let dir3 = + switch direction { + | Up => {x: otherSpeed, y: -. bulletSpeed} + | Down => {x: -. otherSpeed, y: bulletSpeed} + | Left => {x: -. bulletSpeed, y: -. otherSpeed} + | Right => {x: bulletSpeed, y: otherSpeed} + | _ => assert false + }; + let moveBullet = (bullet: bulletT) => add(bullet.pos, bullet.direction); + { + ...state, + guns: + List.mapi( + (i, gun) => + if (i === state.equippedGun) { + {...gun, amunition: max(gun.amunition - 1, 0)} + } else { + gun + }, + state.guns + ), + playerBullets: + List.nth(state.guns, state.equippedGun).amunition > 0 ? + [ + {pos: {x: state.pos.x, y: state.pos.y}, direction: dir1, moveBullet, time: 0.}, + {pos: {x: state.pos.x, y: state.pos.y}, direction: dir2, moveBullet, time: 0.}, + {pos: {x: state.pos.x, y: state.pos.y}, direction: dir3, moveBullet, time: 0.}, + ...state.playerBullets + ] : + state.playerBullets + } + } +}; + +let gunWithSine = { + amunition: 10, + color: Utils.color(0, 155, 155, 255), + keyToggle: Num_3, + fire: (state, direction) => { + let otherSpeed = 2.; + let dir1 = + switch direction { + | Up => {x: -. otherSpeed, y: -. bulletSpeed} + | Down => {x: otherSpeed, y: bulletSpeed} + | Left => {x: -. bulletSpeed, y: otherSpeed} + | Right => {x: bulletSpeed, y: -. otherSpeed} + | _ => assert false + }; + let dir2 = + switch direction { + | Up => {x: 0., y: -. bulletSpeed} + | Down => {x: 0., y: bulletSpeed} + | Left => {x: -. bulletSpeed, y: 0.} + | Right => {x: bulletSpeed, y: 0.} + | _ => assert false + }; + let dir3 = + switch direction { + | Up => {x: otherSpeed, y: -. bulletSpeed} + | Down => {x: -. otherSpeed, y: bulletSpeed} + | Left => {x: -. bulletSpeed, y: -. otherSpeed} + | Right => {x: bulletSpeed, y: otherSpeed} + | _ => assert false + }; + let moveBullet = (bullet: bulletT) => { + let pos = add(bullet.pos, bullet.direction); + let perpendicular = {x: -. bullet.direction.y, y: bullet.direction.x}; + /*let perpendicular = bullet.direction;*/ + let perpendicularSize = + sqrt(perpendicular.x *. perpendicular.x +. perpendicular.y *. perpendicular.y); + let perpendicular = { + x: perpendicular.x /. perpendicularSize, + y: perpendicular.y /. perpendicularSize + }; + let norm = cos(bullet.time /. 5.); + let offset = {x: perpendicular.x *. norm *. 3., y: perpendicular.y *. norm *. 3.}; + add(pos, offset) + }; + { + ...state, + guns: + List.mapi( + (i, gun) => + if (i === state.equippedGun) { + {...gun, amunition: max(gun.amunition - 1, 0)} + } else { + gun + }, + state.guns + ), + playerBullets: + List.nth(state.guns, state.equippedGun).amunition > 0 ? + [ + {pos: {x: state.pos.x, y: state.pos.y}, direction: dir1, moveBullet, time: 0.}, + {pos: {x: state.pos.x, y: state.pos.y}, direction: dir2, moveBullet, time: 0.}, + {pos: {x: state.pos.x, y: state.pos.y}, direction: dir3, moveBullet, time: 0.}, + ...state.playerBullets + ] : + state.playerBullets + } + } +}; + +let gunWithTrail = { + amunition: 10, + color: Utils.color(0, 100, 100, 255), + keyToggle: Num_4, + fire: (state, direction) => { + let dir2 = + switch direction { + | Up => {x: 0., y: -. bulletSpeed} + | Down => {x: 0., y: bulletSpeed} + | Left => {x: -. bulletSpeed, y: 0.} + | Right => {x: bulletSpeed, y: 0.} + | _ => assert false + }; + let moveBullet = (bullet: bulletT) => add(bullet.pos, bullet.direction); + { + ...state, + guns: + List.mapi( + (i, gun) => + if (i === state.equippedGun) { + {...gun, amunition: max(gun.amunition - 1, 0)} + } else { + gun + }, + state.guns + ), + playerBullets: + List.nth(state.guns, state.equippedGun).amunition > 0 ? + [ + {pos: {x: state.pos.x, y: state.pos.y}, direction: dir2, moveBullet, time: 0.}, + { + pos: add(add({x: state.pos.x, y: state.pos.y}, dir2), dir2), + direction: dir2, + moveBullet, + time: 0. + }, + { + pos: add(add(add(add({x: state.pos.x, y: state.pos.y}, dir2), dir2), dir2), dir2), + direction: dir2, + moveBullet, + time: 0. + }, + ...state.playerBullets + ] : + state.playerBullets + } + } +}; + +let achievement1 = { + gun: gunWithSpread, + state: Locked, + condition: (state, env) => Env.keyPressed(B, env) +}; + +let drawKey = (x, y, gun, state, env) => { + let body = + switch gun.keyToggle { + | Num_1 => "1" + | Num_2 => "2" + | Num_3 => "3" + | Num_4 => "4" + | Num_5 => "5" + | Num_6 => "6" + | _ => assert false + }; + Draw.text(state.mainFont, body, (int_of_float(x), int_of_float(y) + 10), env) +}; + +let setup = (env) => { + Env.size(~width=1280, ~height=720, env); + { + pos: {x: 50., y: 50.}, + equippedGun: 0, + guns: [defaultGun], + playerBullets: [], + achievements: [achievement1], + mainFont: Draw.loadFont(~filename="assets/font/font.fnt", ~isPixel=true, env) + } +}; + +let draw = (state, env) => { + Draw.background(Utils.color(~r=199, ~g=217, ~b=229, ~a=255), env); + Draw.fill(Utils.color(~r=41, ~g=166, ~b=244, ~a=255), env); + Draw.rectMode(Corner, env); + let state = { + ...state, + playerBullets: + List.map( + (bullet) => {...bullet, pos: bullet.moveBullet(bullet), time: bullet.time +. 1.}, + state.playerBullets + ) + }; + let state = + Env.key(A, env) ? {...state, pos: {x: state.pos.x -. playerSpeed, y: state.pos.y}} : state; + let state = + Env.key(D, env) ? {...state, pos: {x: state.pos.x +. playerSpeed, y: state.pos.y}} : state; + let state = + Env.key(W, env) ? {...state, pos: {x: state.pos.x, y: state.pos.y -. playerSpeed}} : state; + let state = + Env.key(S, env) ? {...state, pos: {x: state.pos.x, y: state.pos.y +. playerSpeed}} : state; + let rec foldOverGuns = (state, guns, i) => + switch guns { + | [] => state + | [gun] => Env.keyPressed(gun.keyToggle, env) ? {...state, equippedGun: i} : state + | [gun, ...guns] => + foldOverGuns( + Env.keyPressed(gun.keyToggle, env) ? {...state, equippedGun: i} : state, + guns, + i + 1 + ) + }; + let state = foldOverGuns(state, state.guns, 0); + let curGun = List.nth(state.guns, state.equippedGun); + let state = Env.keyPressed(Up, env) ? curGun.fire(state, Up) : state; + let state = Env.keyPressed(Down, env) ? curGun.fire(state, Down) : state; + let state = Env.keyPressed(Left, env) ? curGun.fire(state, Left) : state; + let state = Env.keyPressed(Right, env) ? curGun.fire(state, Right) : state; + Draw.rectf(~pos=(state.pos.x, state.pos.y), ~width=30., ~height=30., env); + List.iter( + ({pos, direction: _}) => { + Draw.fill(Utils.color(~r=41, ~g=166, ~b=244, ~a=255), env); + Draw.rectf(~pos=(pos.x, pos.y), ~width=5., ~height=5., env) + }, + state.playerBullets + ); + ignore @@ + List.fold_left( + ((x, y, i), gun) => { + Draw.fill(gun.color, env); + Draw.rectf(~pos=(x +. 25., y +. 5.), ~width=40., ~height=40., env); + if (i === state.equippedGun) { + Draw.fill(Utils.color(255, 0, 0, 255), env); + Draw.rectf(~pos=(x +. 35., y +. 15.), ~width=20., ~height=20., env) + }; + Draw.text( + state.mainFont, + string_of_int(gun.amunition), + (int_of_float(x) + 70, int_of_float(y) + 10), + env + ); + drawKey(x, y, gun, state, env); + (x, y +. 50., i + 1) + }, + (10., 20., 0), + state.guns + ); + state +}; + +run(~setup, ~draw, ());