├── .gitignore ├── LICENSE ├── README.md ├── bin └── steam_appid.txt ├── cbackend.go ├── docs ├── feature.png ├── go-inovation.wasm ├── index.html └── wasm_exec.js ├── go.mod ├── go.sum ├── ino ├── fielddata.go ├── game.go ├── gamedata.go ├── icon.go ├── internal │ ├── assets │ │ ├── assets.go │ │ ├── images │ │ │ ├── color │ │ │ │ ├── bg.png │ │ │ │ ├── ino.png │ │ │ │ ├── msg_en.png │ │ │ │ ├── msg_ja.png │ │ │ │ └── touch.png │ │ │ ├── icons │ │ │ │ ├── 16x16.png │ │ │ │ ├── 32x32.png │ │ │ │ └── 48x48.png │ │ │ └── mono │ │ │ │ ├── bg.png │ │ │ │ ├── ino.png │ │ │ │ └── msg.png │ │ └── sound │ │ │ ├── damage.wav │ │ │ ├── heal.wav │ │ │ ├── ino1.ogg │ │ │ ├── ino2.ogg │ │ │ ├── itemget.wav │ │ │ ├── itemget2.wav │ │ │ └── jump.wav │ ├── audio │ │ └── audio.go │ ├── draw │ │ └── draw.go │ ├── field │ │ └── field.go │ ├── fieldtype │ │ └── fieldtype.go │ ├── font │ │ ├── font.go │ │ └── scaled.go │ ├── input │ │ ├── input.go │ │ ├── touch_mobile.go │ │ └── touch_notmobile.go │ ├── lang │ │ ├── lang_default.go │ │ ├── lang_js.go │ │ └── lang_steam.go │ └── text │ │ └── text.go ├── main.go ├── player.go └── view.go ├── main.go ├── mobile ├── android │ ├── .gitignore │ ├── app │ │ ├── .gitignore │ │ ├── build.gradle │ │ ├── proguard-rules.pro │ │ └── src │ │ │ └── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── java │ │ │ └── com │ │ │ │ └── hajimehoshi │ │ │ │ └── goinovation │ │ │ │ ├── EbitenViewWithErrorHandling.java │ │ │ │ └── MainActivity.java │ │ │ └── res │ │ │ ├── layout │ │ │ └── activity_main.xml │ │ │ ├── mipmap-hdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-mdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxxhdpi │ │ │ └── ic_launcher.png │ │ │ ├── values-w820dp │ │ │ └── dimens.xml │ │ │ └── values │ │ │ ├── colors.xml │ │ │ ├── dimens.xml │ │ │ ├── strings.xml │ │ │ └── styles.xml │ ├── build.gradle │ ├── gradle.properties │ ├── gradle │ │ └── wrapper │ │ │ └── gradle-wrapper.properties │ ├── gradlew │ ├── gradlew.bat │ ├── inovation │ │ └── build.gradle │ ├── mobile │ │ └── build.gradle │ └── settings.gradle ├── ios │ ├── .gitignore │ ├── goinovation.xcodeproj │ │ ├── project.pbxproj │ │ └── project.xcworkspace │ │ │ └── contents.xcworkspacedata │ └── goinovation │ │ ├── AppDelegate.h │ │ ├── AppDelegate.m │ │ ├── Assets.xcassets │ │ └── AppIcon.appiconset │ │ │ ├── Contents.json │ │ │ ├── icon1024.png │ │ │ ├── icon120-1.png │ │ │ ├── icon120.png │ │ │ ├── icon180.png │ │ │ ├── icon58.png │ │ │ ├── icon80.png │ │ │ └── icon87.png │ │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ │ ├── Info.plist │ │ ├── MobileEbitenViewControllerWithErrorHandling.h │ │ ├── MobileEbitenViewControllerWithErrorHandling.m │ │ └── main.m └── mobile.go ├── notarize_app.sh ├── steam ├── community_capsule_184x69_english.png ├── community_capsule_184x69_japanese.png ├── icon │ ├── icon_128x128.png │ ├── icon_16x16.png │ ├── icon_256x256.png │ ├── icon_32x32.ico │ ├── icon_32x32.png │ ├── icon_512x512.icns │ ├── icon_512x512.png │ └── icon_64x64.png ├── library_capsule_600x900_english.png ├── library_capsule_600x900_japanese.png ├── library_hero_3840x1240_english.png ├── library_hero_3840x1240_japanese.png ├── library_logo_1280x720_english.png ├── library_logo_1280x720_japanese.png ├── msg_en.png ├── msg_ja.png ├── screenshot.png ├── screenshot │ ├── convert.go │ ├── screenshot3_1920x1080_english.png │ ├── screenshot3_1920x1080_japanese.png │ ├── screenshot3_english.png │ ├── screenshot3_japanese.png │ ├── screenshot4_1920x1080_english.png │ ├── screenshot4_1920x1080_japanese.png │ ├── screenshot4_english.png │ ├── screenshot4_japanese.png │ ├── screenshot5_1920x1080_english.png │ ├── screenshot5_1920x1080_japanese.png │ ├── screenshot5_english.png │ ├── screenshot5_japanese.png │ ├── screenshot6_1920x1080_english.png │ ├── screenshot6_1920x1080_japanese.png │ ├── screenshot6_english.png │ ├── screenshot6_japanese.png │ ├── screenshot7_1920x1080_english.png │ ├── screenshot7_1920x1080_japanese.png │ ├── screenshot7_english.png │ └── screenshot7_japanese.png ├── store_header_capsule_460x215_english.png ├── store_header_capsule_460x215_japanese.png ├── store_main_capsule_616x353_english.png ├── store_main_capsule_616x353_japanese.png ├── store_small_capsule_231x87_english.png ├── store_small_capsule_231x87_japanese.png ├── store_vertical_capsule_374x448_english.png ├── store_vertical_capsule_374x448_japanese.png ├── title_en.png └── title_ja.png ├── steambuild_darwin.sh ├── steambuild_linux.sh ├── steambuild_windows.sh ├── tools.go └── zip_steambuilds.sh /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | .DS_Store 3 | *.framework 4 | *.xcframework 5 | *.aar 6 | *.jar 7 | bin/* 8 | !bin/steam_appid.txt 9 | 10 | # mobiles 11 | .idea 12 | mobile/android/app/release/ 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2015 Omega (The original auther) 2 | Copyright 2015 Haneda3 (JavaScript port) 3 | Copyright 2015 Hajime Hoshi (Go port) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Go port of "Inovation 2007" by Omega 2 | 3 | ## Original Work 4 | 5 | http://o-mega.sakura.ne.jp/product/ino.html 6 | 7 | ## Releases 8 | 9 | ### Web Browsers 10 | 11 | http://hajimehoshi.github.io/go-inovation/ 12 | 13 | ### Android 14 | 15 | Get it on Google Play 16 | 17 | ### iOS 18 | 19 | Download on the App Store 20 | 21 | ### Privacy Policy 22 | 23 | We never collect any data from users in the above applications. 24 | 25 | ## How to install and run on desktops 26 | 27 | ``` 28 | mkdir go-inovation 29 | cd go-inovation 30 | go mod init examle.com/m 31 | go run github.com/hajimehoshi/go-inovation 32 | ``` 33 | 34 | ## How to build for Android 35 | 36 | ``` 37 | git clone https://github.com/hajimehoshi/go-inovation 38 | cd go-inovation 39 | go run github.com/hajimehoshi/ebiten/v2/cmd/ebitenmobile bind -target android -javapkg com.hajimehoshi.goinovation -o ./mobile/android/inovation/inovation.aar ./mobile 40 | # You might need to specify Android SDK version like `-androidapi=23` 41 | ``` 42 | 43 | and run the Android Studio project in `./mobile/android`. 44 | 45 | ## How to build for iOS 46 | 47 | ``` 48 | git clone https://github.com/hajimehoshi/go-inovation 49 | cd go-inovation 50 | go run github.com/hajimehoshi/ebiten/v2/cmd/ebitenmobile bind -target ios -o ./mobile/ios/Mobile.xcframework ./mobile 51 | ``` 52 | 53 | and run the Xcode project in `./mobile/ios`. 54 | -------------------------------------------------------------------------------- /bin/steam_appid.txt: -------------------------------------------------------------------------------- 1 | 480 2 | -------------------------------------------------------------------------------- /cbackend.go: -------------------------------------------------------------------------------- 1 | //go:build ebitencbackend 2 | 3 | package main 4 | 5 | import "C" 6 | 7 | //export GoMain 8 | func GoMain() { 9 | main() 10 | } 11 | -------------------------------------------------------------------------------- /docs/feature.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hajimehoshi/go-inovation/20ee4c8e276f04cf0ba715aa938f6afa10e334d9/docs/feature.png -------------------------------------------------------------------------------- /docs/go-inovation.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hajimehoshi/go-inovation/20ee4c8e276f04cf0ba715aa938f6afa10e334d9/docs/go-inovation.wasm -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 26 |

Loading...

27 | -------------------------------------------------------------------------------- /docs/wasm_exec.js: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | "use strict"; 6 | 7 | (() => { 8 | const enosys = () => { 9 | const err = new Error("not implemented"); 10 | err.code = "ENOSYS"; 11 | return err; 12 | }; 13 | 14 | if (!globalThis.fs) { 15 | let outputBuf = ""; 16 | globalThis.fs = { 17 | constants: { O_WRONLY: -1, O_RDWR: -1, O_CREAT: -1, O_TRUNC: -1, O_APPEND: -1, O_EXCL: -1 }, // unused 18 | writeSync(fd, buf) { 19 | outputBuf += decoder.decode(buf); 20 | const nl = outputBuf.lastIndexOf("\n"); 21 | if (nl != -1) { 22 | console.log(outputBuf.substr(0, nl)); 23 | outputBuf = outputBuf.substr(nl + 1); 24 | } 25 | return buf.length; 26 | }, 27 | write(fd, buf, offset, length, position, callback) { 28 | if (offset !== 0 || length !== buf.length || position !== null) { 29 | callback(enosys()); 30 | return; 31 | } 32 | const n = this.writeSync(fd, buf); 33 | callback(null, n); 34 | }, 35 | chmod(path, mode, callback) { callback(enosys()); }, 36 | chown(path, uid, gid, callback) { callback(enosys()); }, 37 | close(fd, callback) { callback(enosys()); }, 38 | fchmod(fd, mode, callback) { callback(enosys()); }, 39 | fchown(fd, uid, gid, callback) { callback(enosys()); }, 40 | fstat(fd, callback) { callback(enosys()); }, 41 | fsync(fd, callback) { callback(null); }, 42 | ftruncate(fd, length, callback) { callback(enosys()); }, 43 | lchown(path, uid, gid, callback) { callback(enosys()); }, 44 | link(path, link, callback) { callback(enosys()); }, 45 | lstat(path, callback) { callback(enosys()); }, 46 | mkdir(path, perm, callback) { callback(enosys()); }, 47 | open(path, flags, mode, callback) { callback(enosys()); }, 48 | read(fd, buffer, offset, length, position, callback) { callback(enosys()); }, 49 | readdir(path, callback) { callback(enosys()); }, 50 | readlink(path, callback) { callback(enosys()); }, 51 | rename(from, to, callback) { callback(enosys()); }, 52 | rmdir(path, callback) { callback(enosys()); }, 53 | stat(path, callback) { callback(enosys()); }, 54 | symlink(path, link, callback) { callback(enosys()); }, 55 | truncate(path, length, callback) { callback(enosys()); }, 56 | unlink(path, callback) { callback(enosys()); }, 57 | utimes(path, atime, mtime, callback) { callback(enosys()); }, 58 | }; 59 | } 60 | 61 | if (!globalThis.process) { 62 | globalThis.process = { 63 | getuid() { return -1; }, 64 | getgid() { return -1; }, 65 | geteuid() { return -1; }, 66 | getegid() { return -1; }, 67 | getgroups() { throw enosys(); }, 68 | pid: -1, 69 | ppid: -1, 70 | umask() { throw enosys(); }, 71 | cwd() { throw enosys(); }, 72 | chdir() { throw enosys(); }, 73 | } 74 | } 75 | 76 | if (!globalThis.crypto) { 77 | throw new Error("globalThis.crypto is not available, polyfill required (crypto.getRandomValues only)"); 78 | } 79 | 80 | if (!globalThis.performance) { 81 | throw new Error("globalThis.performance is not available, polyfill required (performance.now only)"); 82 | } 83 | 84 | if (!globalThis.TextEncoder) { 85 | throw new Error("globalThis.TextEncoder is not available, polyfill required"); 86 | } 87 | 88 | if (!globalThis.TextDecoder) { 89 | throw new Error("globalThis.TextDecoder is not available, polyfill required"); 90 | } 91 | 92 | const encoder = new TextEncoder("utf-8"); 93 | const decoder = new TextDecoder("utf-8"); 94 | 95 | globalThis.Go = class { 96 | constructor() { 97 | this.argv = ["js"]; 98 | this.env = {}; 99 | this.exit = (code) => { 100 | if (code !== 0) { 101 | console.warn("exit code:", code); 102 | } 103 | }; 104 | this._exitPromise = new Promise((resolve) => { 105 | this._resolveExitPromise = resolve; 106 | }); 107 | this._pendingEvent = null; 108 | this._scheduledTimeouts = new Map(); 109 | this._nextCallbackTimeoutID = 1; 110 | 111 | const setInt64 = (addr, v) => { 112 | this.mem.setUint32(addr + 0, v, true); 113 | this.mem.setUint32(addr + 4, Math.floor(v / 4294967296), true); 114 | } 115 | 116 | const getInt64 = (addr) => { 117 | const low = this.mem.getUint32(addr + 0, true); 118 | const high = this.mem.getInt32(addr + 4, true); 119 | return low + high * 4294967296; 120 | } 121 | 122 | const loadValue = (addr) => { 123 | const f = this.mem.getFloat64(addr, true); 124 | if (f === 0) { 125 | return undefined; 126 | } 127 | if (!isNaN(f)) { 128 | return f; 129 | } 130 | 131 | const id = this.mem.getUint32(addr, true); 132 | return this._values[id]; 133 | } 134 | 135 | const storeValue = (addr, v) => { 136 | const nanHead = 0x7FF80000; 137 | 138 | if (typeof v === "number" && v !== 0) { 139 | if (isNaN(v)) { 140 | this.mem.setUint32(addr + 4, nanHead, true); 141 | this.mem.setUint32(addr, 0, true); 142 | return; 143 | } 144 | this.mem.setFloat64(addr, v, true); 145 | return; 146 | } 147 | 148 | if (v === undefined) { 149 | this.mem.setFloat64(addr, 0, true); 150 | return; 151 | } 152 | 153 | let id = this._ids.get(v); 154 | if (id === undefined) { 155 | id = this._idPool.pop(); 156 | if (id === undefined) { 157 | id = this._values.length; 158 | } 159 | this._values[id] = v; 160 | this._goRefCounts[id] = 0; 161 | this._ids.set(v, id); 162 | } 163 | this._goRefCounts[id]++; 164 | let typeFlag = 0; 165 | switch (typeof v) { 166 | case "object": 167 | if (v !== null) { 168 | typeFlag = 1; 169 | } 170 | break; 171 | case "string": 172 | typeFlag = 2; 173 | break; 174 | case "symbol": 175 | typeFlag = 3; 176 | break; 177 | case "function": 178 | typeFlag = 4; 179 | break; 180 | } 181 | this.mem.setUint32(addr + 4, nanHead | typeFlag, true); 182 | this.mem.setUint32(addr, id, true); 183 | } 184 | 185 | const loadSlice = (addr) => { 186 | const array = getInt64(addr + 0); 187 | const len = getInt64(addr + 8); 188 | return new Uint8Array(this._inst.exports.mem.buffer, array, len); 189 | } 190 | 191 | const loadSliceOfValues = (addr) => { 192 | const array = getInt64(addr + 0); 193 | const len = getInt64(addr + 8); 194 | const a = new Array(len); 195 | for (let i = 0; i < len; i++) { 196 | a[i] = loadValue(array + i * 8); 197 | } 198 | return a; 199 | } 200 | 201 | const loadString = (addr) => { 202 | const saddr = getInt64(addr + 0); 203 | const len = getInt64(addr + 8); 204 | return decoder.decode(new DataView(this._inst.exports.mem.buffer, saddr, len)); 205 | } 206 | 207 | const timeOrigin = Date.now() - performance.now(); 208 | this.importObject = { 209 | go: { 210 | // Go's SP does not change as long as no Go code is running. Some operations (e.g. calls, getters and setters) 211 | // may synchronously trigger a Go event handler. This makes Go code get executed in the middle of the imported 212 | // function. A goroutine can switch to a new stack if the current stack is too small (see morestack function). 213 | // This changes the SP, thus we have to update the SP used by the imported function. 214 | 215 | // func wasmExit(code int32) 216 | "runtime.wasmExit": (sp) => { 217 | sp >>>= 0; 218 | const code = this.mem.getInt32(sp + 8, true); 219 | this.exited = true; 220 | delete this._inst; 221 | delete this._values; 222 | delete this._goRefCounts; 223 | delete this._ids; 224 | delete this._idPool; 225 | this.exit(code); 226 | }, 227 | 228 | // func wasmWrite(fd uintptr, p unsafe.Pointer, n int32) 229 | "runtime.wasmWrite": (sp) => { 230 | sp >>>= 0; 231 | const fd = getInt64(sp + 8); 232 | const p = getInt64(sp + 16); 233 | const n = this.mem.getInt32(sp + 24, true); 234 | fs.writeSync(fd, new Uint8Array(this._inst.exports.mem.buffer, p, n)); 235 | }, 236 | 237 | // func resetMemoryDataView() 238 | "runtime.resetMemoryDataView": (sp) => { 239 | sp >>>= 0; 240 | this.mem = new DataView(this._inst.exports.mem.buffer); 241 | }, 242 | 243 | // func nanotime1() int64 244 | "runtime.nanotime1": (sp) => { 245 | sp >>>= 0; 246 | setInt64(sp + 8, (timeOrigin + performance.now()) * 1000000); 247 | }, 248 | 249 | // func walltime() (sec int64, nsec int32) 250 | "runtime.walltime": (sp) => { 251 | sp >>>= 0; 252 | const msec = (new Date).getTime(); 253 | setInt64(sp + 8, msec / 1000); 254 | this.mem.setInt32(sp + 16, (msec % 1000) * 1000000, true); 255 | }, 256 | 257 | // func scheduleTimeoutEvent(delay int64) int32 258 | "runtime.scheduleTimeoutEvent": (sp) => { 259 | sp >>>= 0; 260 | const id = this._nextCallbackTimeoutID; 261 | this._nextCallbackTimeoutID++; 262 | this._scheduledTimeouts.set(id, setTimeout( 263 | () => { 264 | this._resume(); 265 | while (this._scheduledTimeouts.has(id)) { 266 | // for some reason Go failed to register the timeout event, log and try again 267 | // (temporary workaround for https://github.com/golang/go/issues/28975) 268 | console.warn("scheduleTimeoutEvent: missed timeout event"); 269 | this._resume(); 270 | } 271 | }, 272 | getInt64(sp + 8) + 1, // setTimeout has been seen to fire up to 1 millisecond early 273 | )); 274 | this.mem.setInt32(sp + 16, id, true); 275 | }, 276 | 277 | // func clearTimeoutEvent(id int32) 278 | "runtime.clearTimeoutEvent": (sp) => { 279 | sp >>>= 0; 280 | const id = this.mem.getInt32(sp + 8, true); 281 | clearTimeout(this._scheduledTimeouts.get(id)); 282 | this._scheduledTimeouts.delete(id); 283 | }, 284 | 285 | // func getRandomData(r []byte) 286 | "runtime.getRandomData": (sp) => { 287 | sp >>>= 0; 288 | crypto.getRandomValues(loadSlice(sp + 8)); 289 | }, 290 | 291 | // func finalizeRef(v ref) 292 | "syscall/js.finalizeRef": (sp) => { 293 | sp >>>= 0; 294 | const id = this.mem.getUint32(sp + 8, true); 295 | this._goRefCounts[id]--; 296 | if (this._goRefCounts[id] === 0) { 297 | const v = this._values[id]; 298 | this._values[id] = null; 299 | this._ids.delete(v); 300 | this._idPool.push(id); 301 | } 302 | }, 303 | 304 | // func stringVal(value string) ref 305 | "syscall/js.stringVal": (sp) => { 306 | sp >>>= 0; 307 | storeValue(sp + 24, loadString(sp + 8)); 308 | }, 309 | 310 | // func valueGet(v ref, p string) ref 311 | "syscall/js.valueGet": (sp) => { 312 | sp >>>= 0; 313 | const result = Reflect.get(loadValue(sp + 8), loadString(sp + 16)); 314 | sp = this._inst.exports.getsp() >>> 0; // see comment above 315 | storeValue(sp + 32, result); 316 | }, 317 | 318 | // func valueSet(v ref, p string, x ref) 319 | "syscall/js.valueSet": (sp) => { 320 | sp >>>= 0; 321 | Reflect.set(loadValue(sp + 8), loadString(sp + 16), loadValue(sp + 32)); 322 | }, 323 | 324 | // func valueDelete(v ref, p string) 325 | "syscall/js.valueDelete": (sp) => { 326 | sp >>>= 0; 327 | Reflect.deleteProperty(loadValue(sp + 8), loadString(sp + 16)); 328 | }, 329 | 330 | // func valueIndex(v ref, i int) ref 331 | "syscall/js.valueIndex": (sp) => { 332 | sp >>>= 0; 333 | storeValue(sp + 24, Reflect.get(loadValue(sp + 8), getInt64(sp + 16))); 334 | }, 335 | 336 | // valueSetIndex(v ref, i int, x ref) 337 | "syscall/js.valueSetIndex": (sp) => { 338 | sp >>>= 0; 339 | Reflect.set(loadValue(sp + 8), getInt64(sp + 16), loadValue(sp + 24)); 340 | }, 341 | 342 | // func valueCall(v ref, m string, args []ref) (ref, bool) 343 | "syscall/js.valueCall": (sp) => { 344 | sp >>>= 0; 345 | try { 346 | const v = loadValue(sp + 8); 347 | const m = Reflect.get(v, loadString(sp + 16)); 348 | const args = loadSliceOfValues(sp + 32); 349 | const result = Reflect.apply(m, v, args); 350 | sp = this._inst.exports.getsp() >>> 0; // see comment above 351 | storeValue(sp + 56, result); 352 | this.mem.setUint8(sp + 64, 1); 353 | } catch (err) { 354 | sp = this._inst.exports.getsp() >>> 0; // see comment above 355 | storeValue(sp + 56, err); 356 | this.mem.setUint8(sp + 64, 0); 357 | } 358 | }, 359 | 360 | // func valueInvoke(v ref, args []ref) (ref, bool) 361 | "syscall/js.valueInvoke": (sp) => { 362 | sp >>>= 0; 363 | try { 364 | const v = loadValue(sp + 8); 365 | const args = loadSliceOfValues(sp + 16); 366 | const result = Reflect.apply(v, undefined, args); 367 | sp = this._inst.exports.getsp() >>> 0; // see comment above 368 | storeValue(sp + 40, result); 369 | this.mem.setUint8(sp + 48, 1); 370 | } catch (err) { 371 | sp = this._inst.exports.getsp() >>> 0; // see comment above 372 | storeValue(sp + 40, err); 373 | this.mem.setUint8(sp + 48, 0); 374 | } 375 | }, 376 | 377 | // func valueNew(v ref, args []ref) (ref, bool) 378 | "syscall/js.valueNew": (sp) => { 379 | sp >>>= 0; 380 | try { 381 | const v = loadValue(sp + 8); 382 | const args = loadSliceOfValues(sp + 16); 383 | const result = Reflect.construct(v, args); 384 | sp = this._inst.exports.getsp() >>> 0; // see comment above 385 | storeValue(sp + 40, result); 386 | this.mem.setUint8(sp + 48, 1); 387 | } catch (err) { 388 | sp = this._inst.exports.getsp() >>> 0; // see comment above 389 | storeValue(sp + 40, err); 390 | this.mem.setUint8(sp + 48, 0); 391 | } 392 | }, 393 | 394 | // func valueLength(v ref) int 395 | "syscall/js.valueLength": (sp) => { 396 | sp >>>= 0; 397 | setInt64(sp + 16, parseInt(loadValue(sp + 8).length)); 398 | }, 399 | 400 | // valuePrepareString(v ref) (ref, int) 401 | "syscall/js.valuePrepareString": (sp) => { 402 | sp >>>= 0; 403 | const str = encoder.encode(String(loadValue(sp + 8))); 404 | storeValue(sp + 16, str); 405 | setInt64(sp + 24, str.length); 406 | }, 407 | 408 | // valueLoadString(v ref, b []byte) 409 | "syscall/js.valueLoadString": (sp) => { 410 | sp >>>= 0; 411 | const str = loadValue(sp + 8); 412 | loadSlice(sp + 16).set(str); 413 | }, 414 | 415 | // func valueInstanceOf(v ref, t ref) bool 416 | "syscall/js.valueInstanceOf": (sp) => { 417 | sp >>>= 0; 418 | this.mem.setUint8(sp + 24, (loadValue(sp + 8) instanceof loadValue(sp + 16)) ? 1 : 0); 419 | }, 420 | 421 | // func copyBytesToGo(dst []byte, src ref) (int, bool) 422 | "syscall/js.copyBytesToGo": (sp) => { 423 | sp >>>= 0; 424 | const dst = loadSlice(sp + 8); 425 | const src = loadValue(sp + 32); 426 | if (!(src instanceof Uint8Array || src instanceof Uint8ClampedArray)) { 427 | this.mem.setUint8(sp + 48, 0); 428 | return; 429 | } 430 | const toCopy = src.subarray(0, dst.length); 431 | dst.set(toCopy); 432 | setInt64(sp + 40, toCopy.length); 433 | this.mem.setUint8(sp + 48, 1); 434 | }, 435 | 436 | // func copyBytesToJS(dst ref, src []byte) (int, bool) 437 | "syscall/js.copyBytesToJS": (sp) => { 438 | sp >>>= 0; 439 | const dst = loadValue(sp + 8); 440 | const src = loadSlice(sp + 16); 441 | if (!(dst instanceof Uint8Array || dst instanceof Uint8ClampedArray)) { 442 | this.mem.setUint8(sp + 48, 0); 443 | return; 444 | } 445 | const toCopy = src.subarray(0, dst.length); 446 | dst.set(toCopy); 447 | setInt64(sp + 40, toCopy.length); 448 | this.mem.setUint8(sp + 48, 1); 449 | }, 450 | 451 | "debug": (value) => { 452 | console.log(value); 453 | }, 454 | } 455 | }; 456 | } 457 | 458 | async run(instance) { 459 | if (!(instance instanceof WebAssembly.Instance)) { 460 | throw new Error("Go.run: WebAssembly.Instance expected"); 461 | } 462 | this._inst = instance; 463 | this.mem = new DataView(this._inst.exports.mem.buffer); 464 | this._values = [ // JS values that Go currently has references to, indexed by reference id 465 | NaN, 466 | 0, 467 | null, 468 | true, 469 | false, 470 | globalThis, 471 | this, 472 | ]; 473 | this._goRefCounts = new Array(this._values.length).fill(Infinity); // number of references that Go has to a JS value, indexed by reference id 474 | this._ids = new Map([ // mapping from JS values to reference ids 475 | [0, 1], 476 | [null, 2], 477 | [true, 3], 478 | [false, 4], 479 | [globalThis, 5], 480 | [this, 6], 481 | ]); 482 | this._idPool = []; // unused ids that have been garbage collected 483 | this.exited = false; // whether the Go program has exited 484 | 485 | // Pass command line arguments and environment variables to WebAssembly by writing them to the linear memory. 486 | let offset = 4096; 487 | 488 | const strPtr = (str) => { 489 | const ptr = offset; 490 | const bytes = encoder.encode(str + "\0"); 491 | new Uint8Array(this.mem.buffer, offset, bytes.length).set(bytes); 492 | offset += bytes.length; 493 | if (offset % 8 !== 0) { 494 | offset += 8 - (offset % 8); 495 | } 496 | return ptr; 497 | }; 498 | 499 | const argc = this.argv.length; 500 | 501 | const argvPtrs = []; 502 | this.argv.forEach((arg) => { 503 | argvPtrs.push(strPtr(arg)); 504 | }); 505 | argvPtrs.push(0); 506 | 507 | const keys = Object.keys(this.env).sort(); 508 | keys.forEach((key) => { 509 | argvPtrs.push(strPtr(`${key}=${this.env[key]}`)); 510 | }); 511 | argvPtrs.push(0); 512 | 513 | const argv = offset; 514 | argvPtrs.forEach((ptr) => { 515 | this.mem.setUint32(offset, ptr, true); 516 | this.mem.setUint32(offset + 4, 0, true); 517 | offset += 8; 518 | }); 519 | 520 | // The linker guarantees global data starts from at least wasmMinDataAddr. 521 | // Keep in sync with cmd/link/internal/ld/data.go:wasmMinDataAddr. 522 | const wasmMinDataAddr = 4096 + 8192; 523 | if (offset >= wasmMinDataAddr) { 524 | throw new Error("total length of command line and environment variables exceeds limit"); 525 | } 526 | 527 | this._inst.exports.run(argc, argv); 528 | if (this.exited) { 529 | this._resolveExitPromise(); 530 | } 531 | await this._exitPromise; 532 | } 533 | 534 | _resume() { 535 | if (this.exited) { 536 | throw new Error("Go program has already exited"); 537 | } 538 | this._inst.exports.resume(); 539 | if (this.exited) { 540 | this._resolveExitPromise(); 541 | } 542 | } 543 | 544 | _makeFuncWrapper(id) { 545 | const go = this; 546 | return function () { 547 | const event = { id: id, this: this, args: arguments }; 548 | go._pendingEvent = event; 549 | go._resume(); 550 | return event.result; 551 | }; 552 | } 553 | } 554 | })(); 555 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/hajimehoshi/go-inovation 2 | 3 | go 1.23.0 4 | 5 | require ( 6 | github.com/hajimehoshi/bitmapfont/v3 v3.2.1 7 | github.com/hajimehoshi/ebiten/v2 v2.8.7 8 | github.com/hajimehoshi/go-steamworks v0.0.0-20241112125913-96b2a6baef69 9 | golang.org/x/image v0.26.0 10 | golang.org/x/text v0.24.0 11 | ) 12 | 13 | require ( 14 | github.com/ebitengine/gomobile v0.0.0-20250329061421-6d0a8e981e4c // indirect 15 | github.com/ebitengine/hideconsole v1.0.0 // indirect 16 | github.com/ebitengine/oto/v3 v3.4.0-alpha.7 // indirect 17 | github.com/ebitengine/purego v0.9.0-alpha.3 // indirect 18 | github.com/go-text/typesetting v0.3.0 // indirect 19 | github.com/jezek/xgb v1.1.1 // indirect 20 | github.com/jfreymuth/oggvorbis v1.0.5 // indirect 21 | github.com/jfreymuth/vorbis v1.0.2 // indirect 22 | github.com/pierrec/lz4/v4 v4.1.21 // indirect 23 | golang.org/x/mod v0.24.0 // indirect 24 | golang.org/x/sync v0.13.0 // indirect 25 | golang.org/x/sys v0.32.0 // indirect 26 | golang.org/x/tools v0.32.0 // indirect 27 | ) 28 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/ebitengine/gomobile v0.0.0-20250329061421-6d0a8e981e4c h1:Ccgks2VROTr6bIm1FFxG2jT6P1DaCBMj8g/O9xbOQ08= 2 | github.com/ebitengine/gomobile v0.0.0-20250329061421-6d0a8e981e4c/go.mod h1:M6DDA2RbegvWBVv4Dq482lwyFTtMczT1A7UNm1qOYzY= 3 | github.com/ebitengine/hideconsole v1.0.0 h1:5J4U0kXF+pv/DhiXt5/lTz0eO5ogJ1iXb8Yj1yReDqE= 4 | github.com/ebitengine/hideconsole v1.0.0/go.mod h1:hTTBTvVYWKBuxPr7peweneWdkUwEuHuB3C1R/ielR1A= 5 | github.com/ebitengine/oto/v3 v3.4.0-alpha.7 h1:0rd2hzmixykApKPnLn0x39UWV3+mu/iNzfZ8YJfJBW8= 6 | github.com/ebitengine/oto/v3 v3.4.0-alpha.7/go.mod h1:poYRm0BcahJ49XN646C6Yg7wMc0gcwQNiC5ASQDCNnU= 7 | github.com/ebitengine/purego v0.9.0-alpha.3 h1:5kv5zzhJYYLOYAdA/ZBMt+L89cG2B3cNyYWeDgFw73I= 8 | github.com/ebitengine/purego v0.9.0-alpha.3/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= 9 | github.com/go-text/typesetting v0.3.0 h1:OWCgYpp8njoxSRpwrdd1bQOxdjOXDj9Rqart9ML4iF4= 10 | github.com/go-text/typesetting v0.3.0/go.mod h1:qjZLkhRgOEYMhU9eHBr3AR4sfnGJvOXNLt8yRAySFuY= 11 | github.com/go-text/typesetting-utils v0.0.0-20241103174707-87a29e9e6066 h1:qCuYC+94v2xrb1PoS4NIDe7DGYtLnU2wWiQe9a1B1c0= 12 | github.com/go-text/typesetting-utils v0.0.0-20241103174707-87a29e9e6066/go.mod h1:DDxDdQEnB70R8owOx3LVpEFvpMK9eeH1o2r0yZhFI9o= 13 | github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= 14 | github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 15 | github.com/hajimehoshi/bitmapfont/v3 v3.2.1 h1:33Lw85DZolX3upouUqf6Qza8HYGIROvr7SYin7PzIZ8= 16 | github.com/hajimehoshi/bitmapfont/v3 v3.2.1/go.mod h1:8gLqGatKVu0pwcNCJguW3Igg9WQqVXF0zg/RvrGQWyg= 17 | github.com/hajimehoshi/ebiten/v2 v2.8.7 h1:DnvNZuB8RF0ffOUTuqaXHl9d51VAT9XYfEMQPYD37v4= 18 | github.com/hajimehoshi/ebiten/v2 v2.8.7/go.mod h1:durJ05+OYnio9b8q0sEtOgaNeBEQG7Yr7lRviAciYbs= 19 | github.com/hajimehoshi/go-steamworks v0.0.0-20241112125913-96b2a6baef69 h1:R5DmT3Ffuccaf3U7DiLYpro2avyBz7D112v9eqm8NvE= 20 | github.com/hajimehoshi/go-steamworks v0.0.0-20241112125913-96b2a6baef69/go.mod h1:xQbwn4VSK2CwjfAgpolFH8MYSu96NQZhiOuksu1vvdY= 21 | github.com/jezek/xgb v1.1.1 h1:bE/r8ZZtSv7l9gk6nU0mYx51aXrvnyb44892TwSaqS4= 22 | github.com/jezek/xgb v1.1.1/go.mod h1:nrhwO0FX/enq75I7Y7G8iN1ubpSGZEiA3v9e9GyRFlk= 23 | github.com/jfreymuth/oggvorbis v1.0.5 h1:u+Ck+R0eLSRhgq8WTmffYnrVtSztJcYrl588DM4e3kQ= 24 | github.com/jfreymuth/oggvorbis v1.0.5/go.mod h1:1U4pqWmghcoVsCJJ4fRBKv9peUJMBHixthRlBeD6uII= 25 | github.com/jfreymuth/vorbis v1.0.2 h1:m1xH6+ZI4thH927pgKD8JOH4eaGRm18rEE9/0WKjvNE= 26 | github.com/jfreymuth/vorbis v1.0.2/go.mod h1:DoftRo4AznKnShRl1GxiTFCseHr4zR9BN3TWXyuzrqQ= 27 | github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ= 28 | github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= 29 | github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= 30 | github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= 31 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 32 | golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 33 | golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= 34 | golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= 35 | golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= 36 | golang.org/x/image v0.20.0/go.mod h1:0a88To4CYVBAHp5FXJm8o7QbUl37Vd85ply1vyD8auM= 37 | golang.org/x/image v0.26.0 h1:4XjIFEZWQmCZi6Wv8BoxsDhRU3RVnLX04dToTDAEPlY= 38 | golang.org/x/image v0.26.0/go.mod h1:lcxbMFAovzpnJxzXS3nyL83K27tmqtKzIJpctK8YO5c= 39 | golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= 40 | golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= 41 | golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= 42 | golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= 43 | golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= 44 | golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU= 45 | golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= 46 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 47 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 48 | golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= 49 | golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= 50 | golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= 51 | golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= 52 | golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= 53 | golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= 54 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 55 | golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 56 | golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 57 | golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= 58 | golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 59 | golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 60 | golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 61 | golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610= 62 | golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= 63 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 64 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 65 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 66 | golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 67 | golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 68 | golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 69 | golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 70 | golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 71 | golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 72 | golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 73 | golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 74 | golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20= 75 | golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= 76 | golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= 77 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 78 | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= 79 | golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= 80 | golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= 81 | golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= 82 | golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= 83 | golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= 84 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 85 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 86 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 87 | golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= 88 | golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= 89 | golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= 90 | golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= 91 | golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= 92 | golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= 93 | golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0= 94 | golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU= 95 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 96 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 97 | golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= 98 | golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= 99 | golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= 100 | golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= 101 | golang.org/x/tools v0.32.0 h1:Q7N1vhpkQv7ybVzLFtTjvQya2ewbwNDZzUgfXGqtMWU= 102 | golang.org/x/tools v0.32.0/go.mod h1:ZxrU41P/wAbZD8EDa6dDCa6XfpkhJ7HFMjHJXfBDu8s= 103 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 104 | -------------------------------------------------------------------------------- /ino/fielddata.go: -------------------------------------------------------------------------------- 1 | package ino 2 | 3 | var field_data = ` 4 | UUUU UUUUUUUUUUUUUUUUUUUBBB 5 | UL U U B BBBBBBBB 6 | U U UUUUUUUUUUUBBBBBHH PB UUUUUUUUUUUUUUU B B 7 | U UUUUUUU BB H UUUUUUUUUUUUUUUBBB UU U B p B 8 | UU B lBUU UU UUUUUUB BBBB B 9 | UU BBBBBBBB BBBBBBBBBBBBBB UUUU BBBBBBBBB H B hB B 10 | UUUU BBBBHHBB BB UUUU Br BB UBUB B B 11 | U B H ~~~ B U BBU BBBBUUUU* B~~B * 12 | U UB B B U BB UU BB B B B B 13 | U UB B a ~~~~ B UU B UUUBBB B B~~B B 14 | U UUB BBBB BUUUUUUUUUUUUU BBB U BB B B B B BBBBBBBBBBBB 15 | U UUB ~~~~~ B BBB UU BBBB B B~~B B B B 16 | U UUUB ~~~~ H BBUUUU BBB * B B * B B 17 | UU B ~~~~ BBBBBBBBBBBBBBBBB U BB B B~~B B B B 18 | U Bz ~~~~ ~ g UUU dB B B B B B B B 19 | UU B~~~~ @ BBBBBBBBBBBBBB~ BBBBBB~~B B B B B 20 | U B B **B~BBBB B BBBBBBBBBBBB b B B 21 | UU BBBBBBBBBBBBBBBBBBBBBBHB**B U BBBBB~ ~~~~~~~~~ ~~~~~~~~~~~B~ BBB* * 22 | U U B U B BBBHHBBBBBBBBBBBBBBBBBBB~ B * * 23 | UUUUUUUBBBBBBBBBBBBBBBBBBBBBBBBHHBBBBBB BB BBB UUHU BB B * * 24 | U BB U U Bj BBBBB BBBBB U U BBB B * * 25 | UU HH fU U BBB BBBB B U U B B * * 26 | U UBUUUUU UUUUUUUUUUUUU BB U B BB * * 27 | U UB ~~ ~~ ~~ <<<<<< <<<<<<<<<<<<<<<<<<< U*UU B BBB * * 28 | U UUB~ ~~ ~~ B B B o B B * * 29 | UU B ~~ ~~ ~~ B >>>>>>> BB BBBBBBBBBBBBBBBBBBBBB BB B * * 30 | UU B~~~ ~~~ ~~~ B BBBBBBBBB BBHBBBBBBBBBBBBB BHBBBBBBBB B * L* 31 | UUU B ~~~ ~~~ ~~~ B B * e U B B * * 32 | UUU UB~~~i ~~~ ~~~ ~~~ B B IIIIIBBB U B BB * * 33 | UU UB* ~~~ ~~~ ~~~ ~~~ BBB IIIII B B BBB * * 34 | U UUBHHBBBB<<<<<>>>>>BBBBB >>>>>>>> B B B * * 35 | U U BBBBBBBBBB~ B B B nB<<<~B * * 36 | U UUU UU B ~~ BBB ~~ P B BBB B * * 37 | U~UUUUU B ~~B k B~~ BBB BBBB B~>>>B * * 38 | U UUU UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU B BBBBBBBBB BBB B B * * 39 | U~ U U B~ *** BBB~~~~B * * 40 | B UUUUU U H~~B~ c B~~B * * * 41 | B~~U UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUBBBBBBBBBBBBBBBB*BBBBBBBBBBBBBB~~BBBBBBBBB>>>>>>IIIIIIIIII * * 42 | B B BBB U B B * * 43 | B~~BB U B<<<<<<<<~B BBBBBBBBBB B 44 | B B* m U B B B B 45 | B~~BIIIII U B~>>>>>>>>B H B 46 | B B > U B B H BU 47 | B~~B < < BBBBB U B<<<<<<<<~B B HUUUUU 48 | B B <<<<<< BBBB~B B B B B H U 49 | B~~B BBB B B~>>>>>>>>BBHHHHHHHBB H U 50 | B B ~BBBBB B B q BU U 51 | B~~B B BBB BUUUUUUUUBBBIIIIIII IIIIIIII<<= fieldtype.FIELD_ITEM_BORDER && 77 | f.field[y*maxFieldX+x] != fieldtype.FIELD_ITEM_STARTPOINT 78 | } 79 | 80 | func (f *Field) IsItemGettable(x, y int, gameData GameData) bool { 81 | if !f.IsItem(x, y) { 82 | return false 83 | } 84 | if f.field[y*maxFieldX+x] == fieldtype.FIELD_ITEM_OMEGA && gameData.IsHiddenSecret() { 85 | return false 86 | } 87 | return true 88 | } 89 | 90 | func (f *Field) EraseField(x, y int) { 91 | f.field[y*maxFieldX+x] = fieldtype.FIELD_NONE 92 | } 93 | 94 | type GameData interface { 95 | IsHiddenSecret() bool 96 | } 97 | 98 | func (f *Field) Draw(screen *ebiten.Image, gameData GameData, viewPositionX, viewPositionY int) { 99 | const ( 100 | graphicOffsetX = -16 - 16*2 101 | graphicOffsetY = 8 - 16*2 102 | ) 103 | vx, vy := viewPositionX, viewPositionY 104 | ofs_x := CHAR_SIZE - vx%CHAR_SIZE 105 | ofs_y := CHAR_SIZE - vy%CHAR_SIZE 106 | for xx := -(draw.ScreenWidth/CHAR_SIZE/2 + 2); xx < (draw.ScreenWidth/CHAR_SIZE/2 + 2); xx++ { 107 | fx := xx + vx/CHAR_SIZE 108 | if fx < 0 || fx >= maxFieldX { 109 | continue 110 | } 111 | for yy := -(draw.ScreenHeight/CHAR_SIZE/2 + 2); yy < (draw.ScreenHeight/CHAR_SIZE/2 + 2); yy++ { 112 | fy := yy + vy/CHAR_SIZE 113 | if fy < 0 || fy >= maxFieldY { 114 | continue 115 | } 116 | 117 | gy := (f.timer / 10) % 4 118 | gx := int(f.field[fy*maxFieldX+fx]) 119 | 120 | if f.IsItem(fx, fy) { 121 | gx -= (int(fieldtype.FIELD_ITEM_BORDER) + 1) 122 | gy = 4 + gx/16 123 | gx = gx % 16 124 | } 125 | 126 | if gameData.IsHiddenSecret() && f.field[fy*maxFieldX+fx] == fieldtype.FIELD_ITEM_OMEGA { 127 | continue 128 | } 129 | 130 | draw.Draw(screen, "ino", 131 | (xx+12)*CHAR_SIZE+ofs_x+graphicOffsetX+(draw.ScreenWidth-320)/2, 132 | (yy+8)*CHAR_SIZE+ofs_y+graphicOffsetY+(draw.ScreenHeight-240)/2, 133 | gx*16, gy*16, 16, 16) 134 | } 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /ino/internal/fieldtype/fieldtype.go: -------------------------------------------------------------------------------- 1 | package fieldtype 2 | 3 | import ( 4 | "golang.org/x/text/language" 5 | 6 | "github.com/hajimehoshi/go-inovation/ino/internal/text" 7 | ) 8 | 9 | type FieldType int 10 | 11 | const ( 12 | FIELD_NONE FieldType = iota // なし 13 | FIELD_HIDEPATH // 隠しルート(見えるけど判定のないブロック) 14 | FIELD_UNVISIBLE // 不可視ブロック(見えないけど判定があるブロック) 15 | FIELD_BLOCK // 通常ブロック 16 | FIELD_BAR // 床。降りたり上ったりできる 17 | FIELD_SCROLL_L // ベルト床左 18 | FIELD_SCROLL_R // ベルト床右 19 | FIELD_SPIKE // トゲ 20 | FIELD_SLIP // すべる 21 | FIELD_ITEM_BORDER // アイテムチェック用 22 | FIELD_ITEM_POWERUP // パワーアップ 23 | // ふじ系 24 | FIELD_ITEM_FUJI 25 | FIELD_ITEM_BUSHI 26 | FIELD_ITEM_APPLE 27 | FIELD_ITEM_V 28 | // たか系 29 | FIELD_ITEM_TAKA 30 | FIELD_ITEM_SHUOLDER 31 | FIELD_ITEM_DAGGER 32 | FIELD_ITEM_KATAKATA 33 | // なす系 34 | FIELD_ITEM_NASU 35 | FIELD_ITEM_BONUS 36 | FIELD_ITEM_NURSE 37 | FIELD_ITEM_NAZUNA 38 | // くそげー系 39 | FIELD_ITEM_GAMEHELL 40 | FIELD_ITEM_GUNDAM 41 | FIELD_ITEM_POED 42 | FIELD_ITEM_MILESTONE 43 | FIELD_ITEM_1YEN 44 | FIELD_ITEM_TRIANGLE 45 | FIELD_ITEM_OMEGA // 隠し 46 | FIELD_ITEM_LIFE // ハート 47 | FIELD_ITEM_STARTPOINT // 開始地点 48 | FIELD_ITEM_MAX 49 | ) 50 | 51 | func (f FieldType) ItemMessage(lang language.Tag) string { 52 | return text.Get(lang, text.TextID(f-FIELD_ITEM_POWERUP)+text.TextIDItemPowerUp) 53 | } 54 | -------------------------------------------------------------------------------- /ino/internal/font/font.go: -------------------------------------------------------------------------------- 1 | package font 2 | 3 | import ( 4 | "image/color" 5 | "strings" 6 | 7 | "github.com/hajimehoshi/bitmapfont/v3" 8 | "github.com/hajimehoshi/ebiten/v2" 9 | "github.com/hajimehoshi/ebiten/v2/text/v2" 10 | "golang.org/x/image/font" 11 | "golang.org/x/image/math/fixed" 12 | ) 13 | 14 | const LineHeight = 16 15 | 16 | func tokens(str string) []string { 17 | tokens := []string{} 18 | for { 19 | var strs []string 20 | switch len(tokens) % 2 { 21 | case 0: 22 | strs = strings.SplitN(str, "", 2) 23 | case 1: 24 | strs = strings.SplitN(str, "", 2) 25 | } 26 | if len(strs) >= 1 { 27 | tokens = append(tokens, strs[0]) 28 | } 29 | if len(strs) == 2 { 30 | str = strs[1] 31 | } else { 32 | break 33 | } 34 | } 35 | return tokens 36 | } 37 | 38 | func Width(str string) int { 39 | w := fixed.I(0) 40 | for _, t := range tokens(str) { 41 | w += font.MeasureString(bitmapfont.Face, t) 42 | } 43 | return w.Round() 44 | } 45 | 46 | func Height(str string) int { 47 | return (strings.Count(str, "\n") + 1) * LineHeight 48 | } 49 | 50 | var red = color.RGBA{0xe4, 0x32, 0x60, 0xff} 51 | 52 | var face = text.NewGoXFace(bitmapfont.Face) 53 | 54 | func DrawText(target *ebiten.Image, str string, x, y int, clr color.Color) { 55 | xf := float64(x) 56 | yf := float64(y) 57 | for i, t := range tokens(str) { 58 | clr := clr 59 | if i%2 == 1 { 60 | clr = red 61 | } 62 | op := &text.DrawOptions{} 63 | op.GeoM.Translate(xf, yf) 64 | op.ColorScale.ScaleWithColor(clr) 65 | text.Draw(target, t, face, op) 66 | xf += text.Advance(t, face) 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /ino/internal/font/scaled.go: -------------------------------------------------------------------------------- 1 | package font 2 | 3 | import ( 4 | "image" 5 | "image/color" 6 | 7 | "golang.org/x/image/font" 8 | "golang.org/x/image/math/fixed" 9 | ) 10 | 11 | type scaledImage struct { 12 | image image.Image 13 | scale int 14 | } 15 | 16 | func (s *scaledImage) ColorModel() color.Model { 17 | return s.image.ColorModel() 18 | } 19 | 20 | func (s *scaledImage) Bounds() image.Rectangle { 21 | b := s.image.Bounds() 22 | b.Min = b.Min.Mul(s.scale) 23 | b.Max = b.Max.Mul(s.scale) 24 | return b 25 | } 26 | 27 | func euclidianDiv(x, y int) int { 28 | if x < 0 { 29 | x -= y - 1 30 | } 31 | return x / y 32 | } 33 | 34 | func (s *scaledImage) At(x, y int) color.Color { 35 | x = euclidianDiv(x, s.scale) 36 | y = euclidianDiv(y, s.scale) 37 | return s.image.At(x, y) 38 | } 39 | 40 | func scaleFont(f font.Face, scale int) font.Face { 41 | if scale == 1 { 42 | return f 43 | } 44 | return &scaled{f, scale} 45 | } 46 | 47 | type scaled struct { 48 | font font.Face 49 | scale int 50 | } 51 | 52 | func (s *scaled) Close() error { 53 | return s.font.Close() 54 | } 55 | 56 | func (s *scaled) Glyph(dot fixed.Point26_6, r rune) (dr image.Rectangle, mask image.Image, maskp image.Point, advance fixed.Int26_6, ok bool) { 57 | dr, mask, maskp, advance, ok = s.font.Glyph(dot, r) 58 | if !ok { 59 | return 60 | } 61 | d := image.Pt(dot.X.Floor(), dot.Y.Floor()) 62 | dr.Min = dr.Min.Sub(d).Mul(s.scale).Add(d) 63 | dr.Max = dr.Max.Sub(d).Mul(s.scale).Add(d) 64 | maskp = maskp.Mul(s.scale) 65 | advance *= fixed.Int26_6(s.scale) 66 | return dr, &scaledImage{mask, s.scale}, maskp, advance, ok 67 | } 68 | 69 | func (s *scaled) GlyphBounds(r rune) (bounds fixed.Rectangle26_6, advance fixed.Int26_6, ok bool) { 70 | bounds, advance, ok = s.font.GlyphBounds(r) 71 | if !ok { 72 | return 73 | } 74 | bounds.Min.X *= fixed.Int26_6(s.scale) 75 | bounds.Min.Y *= fixed.Int26_6(s.scale) 76 | bounds.Max.X *= fixed.Int26_6(s.scale) 77 | bounds.Max.Y *= fixed.Int26_6(s.scale) 78 | advance *= fixed.Int26_6(s.scale) 79 | return 80 | } 81 | 82 | func (s *scaled) GlyphAdvance(r rune) (advance fixed.Int26_6, ok bool) { 83 | advance, ok = s.font.GlyphAdvance(r) 84 | if !ok { 85 | return 86 | } 87 | advance *= fixed.Int26_6(s.scale) 88 | return 89 | } 90 | 91 | func (s *scaled) Kern(r0, r1 rune) fixed.Int26_6 { 92 | return s.font.Kern(r0, r1) * fixed.Int26_6(s.scale) 93 | } 94 | 95 | func (s *scaled) Metrics() font.Metrics { 96 | m := s.font.Metrics() 97 | return font.Metrics{ 98 | Height: m.Height * fixed.Int26_6(s.scale), 99 | Ascent: m.Ascent * fixed.Int26_6(s.scale), 100 | Descent: m.Descent * fixed.Int26_6(s.scale), 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /ino/internal/input/input.go: -------------------------------------------------------------------------------- 1 | package input 2 | 3 | import ( 4 | "github.com/hajimehoshi/ebiten/v2" 5 | "github.com/hajimehoshi/ebiten/v2/inpututil" 6 | ) 7 | 8 | const ( 9 | // TODO: This is duplicated with draw package's definitions. 10 | ScreenWidth = 320 11 | ScreenHeight = 240 12 | ) 13 | 14 | var theInput = &Input{ 15 | pressed: map[ebiten.Key]struct{}{}, 16 | prevPressed: map[ebiten.Key]struct{}{}, 17 | } 18 | 19 | func Current() *Input { 20 | return theInput 21 | } 22 | 23 | type Direction int 24 | 25 | const ( 26 | DirectionLeft Direction = iota 27 | DirectionRight 28 | DirectionDown 29 | ) 30 | 31 | var keys = []ebiten.Key{ 32 | ebiten.KeyEnter, 33 | ebiten.KeySpace, 34 | ebiten.KeyLeft, 35 | ebiten.KeyDown, 36 | ebiten.KeyRight, 37 | 38 | // Fullscreen 39 | ebiten.KeyF, 40 | 41 | // Profiling 42 | ebiten.KeyP, 43 | ebiten.KeyQ, 44 | } 45 | 46 | type Input struct { 47 | pressed map[ebiten.Key]struct{} 48 | prevPressed map[ebiten.Key]struct{} 49 | touchMode bool 50 | 51 | gamepadID ebiten.GamepadID 52 | gamepadEnabled bool 53 | } 54 | 55 | func (i *Input) IsTouchEnabled() bool { 56 | if isTouchPrimaryInput() { 57 | return true 58 | } 59 | return i.touchMode 60 | } 61 | 62 | func (i *Input) Update() { 63 | i.prevPressed = map[ebiten.Key]struct{}{} 64 | for k := range i.pressed { 65 | i.prevPressed[k] = struct{}{} 66 | } 67 | i.pressed = map[ebiten.Key]struct{}{} 68 | for _, k := range keys { 69 | if ebiten.IsKeyPressed(k) { 70 | i.pressed[k] = struct{}{} 71 | } 72 | } 73 | 74 | // Emulates the keys by gamepad pressing 75 | gamepadIDs := ebiten.GamepadIDs() 76 | if len(gamepadIDs) > 0 { 77 | if !i.gamepadEnabled { 78 | i.gamepadID = gamepadIDs[0] 79 | i.gamepadEnabled = true 80 | } else { 81 | var found bool 82 | for _, id := range gamepadIDs { 83 | if i.gamepadID == id { 84 | found = true 85 | break 86 | } 87 | } 88 | if !found { 89 | i.gamepadID = gamepadIDs[0] 90 | } 91 | } 92 | } else { 93 | i.gamepadEnabled = false 94 | } 95 | 96 | var gamepadUsed bool 97 | if i.gamepadEnabled { 98 | const threshold = 0.8 99 | var x, y float64 100 | std := ebiten.IsStandardGamepadLayoutAvailable(i.gamepadID) 101 | if std { 102 | x = ebiten.StandardGamepadAxisValue(i.gamepadID, ebiten.StandardGamepadAxisLeftStickHorizontal) 103 | y = ebiten.StandardGamepadAxisValue(i.gamepadID, ebiten.StandardGamepadAxisLeftStickVertical) 104 | 105 | switch { 106 | case ebiten.IsStandardGamepadButtonPressed(i.gamepadID, ebiten.StandardGamepadButtonLeftLeft): 107 | x = -1 108 | case ebiten.IsStandardGamepadButtonPressed(i.gamepadID, ebiten.StandardGamepadButtonLeftRight): 109 | x = 1 110 | case ebiten.IsStandardGamepadButtonPressed(i.gamepadID, ebiten.StandardGamepadButtonLeftBottom): 111 | y = 1 112 | } 113 | } else { 114 | x = ebiten.GamepadAxis(i.gamepadID, 0) 115 | y = ebiten.GamepadAxis(i.gamepadID, 1) 116 | } 117 | switch { 118 | case -threshold >= x: 119 | i.pressed[ebiten.KeyLeft] = struct{}{} 120 | gamepadUsed = true 121 | case threshold <= x: 122 | i.pressed[ebiten.KeyRight] = struct{}{} 123 | gamepadUsed = true 124 | } 125 | if y >= threshold { 126 | i.pressed[ebiten.KeyDown] = struct{}{} 127 | gamepadUsed = true 128 | } 129 | 130 | if std { 131 | if ebiten.IsStandardGamepadButtonPressed(i.gamepadID, ebiten.StandardGamepadButtonRightBottom) || 132 | ebiten.IsStandardGamepadButtonPressed(i.gamepadID, ebiten.StandardGamepadButtonRightRight) { 133 | i.pressed[ebiten.KeyEnter] = struct{}{} 134 | i.pressed[ebiten.KeySpace] = struct{}{} 135 | gamepadUsed = true 136 | } 137 | } else { 138 | for b := ebiten.GamepadButton0; b <= ebiten.GamepadButton3; b++ { 139 | if ebiten.IsGamepadButtonPressed(i.gamepadID, b) { 140 | i.pressed[ebiten.KeyEnter] = struct{}{} 141 | i.pressed[ebiten.KeySpace] = struct{}{} 142 | gamepadUsed = true 143 | break 144 | } 145 | } 146 | } 147 | } 148 | 149 | // Emulates the keys by touching 150 | touches := ebiten.TouchIDs() 151 | for _, t := range touches { 152 | x, y := ebiten.TouchPosition(t) 153 | // TODO(hajimehoshi): 64 are magic numbers 154 | if y < ScreenHeight-64 { 155 | continue 156 | } 157 | switch { 158 | case ScreenWidth <= x: 159 | case ScreenWidth*3/4 <= x: 160 | i.pressed[ebiten.KeyEnter] = struct{}{} 161 | i.pressed[ebiten.KeySpace] = struct{}{} 162 | case ScreenWidth*2/4 <= x: 163 | i.pressed[ebiten.KeyDown] = struct{}{} 164 | case ScreenWidth/4 <= x: 165 | i.pressed[ebiten.KeyRight] = struct{}{} 166 | default: 167 | i.pressed[ebiten.KeyLeft] = struct{}{} 168 | } 169 | } 170 | 171 | if 0 < len(touches) { 172 | i.touchMode = true 173 | } else if gamepadUsed { 174 | i.touchMode = false 175 | } 176 | } 177 | 178 | func inLanguageSwitcher(x, y int) bool { 179 | return ScreenWidth*3/4 <= x && y < ScreenHeight/4 180 | } 181 | 182 | func (i *Input) IsSpaceTouched() bool { 183 | for _, t := range ebiten.TouchIDs() { 184 | x, y := ebiten.TouchPosition(t) 185 | if !inLanguageSwitcher(x, y) && y < ScreenHeight-64 { 186 | return true 187 | } 188 | } 189 | return false 190 | } 191 | 192 | func (i *Input) IsSpaceJustTouched() bool { 193 | for _, t := range inpututil.JustPressedTouchIDs() { 194 | x, y := ebiten.TouchPosition(t) 195 | if !inLanguageSwitcher(x, y) && y < ScreenHeight-64 { 196 | return true 197 | } 198 | } 199 | return false 200 | } 201 | 202 | func (i *Input) IsKeyPressed(key ebiten.Key) bool { 203 | _, ok := i.pressed[key] 204 | return ok 205 | } 206 | 207 | func (i *Input) IsKeyJustPressed(key ebiten.Key) bool { 208 | _, ok := i.pressed[key] 209 | if !ok { 210 | return false 211 | } 212 | _, ok = i.prevPressed[key] 213 | return !ok 214 | } 215 | 216 | func (i *Input) IsActionKeyPressed() bool { 217 | return i.IsKeyPressed(ebiten.KeyEnter) || i.IsKeyPressed(ebiten.KeySpace) 218 | } 219 | 220 | func (i *Input) IsActionKeyJustPressed() bool { 221 | return i.IsKeyJustPressed(ebiten.KeyEnter) || i.IsKeyJustPressed(ebiten.KeySpace) 222 | } 223 | 224 | func (i *Input) IsDirectionKeyPressed(dir Direction) bool { 225 | switch dir { 226 | case DirectionLeft: 227 | return i.IsKeyPressed(ebiten.KeyLeft) 228 | case DirectionRight: 229 | return i.IsKeyPressed(ebiten.KeyRight) 230 | case DirectionDown: 231 | return i.IsKeyPressed(ebiten.KeyDown) 232 | default: 233 | panic("not reach") 234 | } 235 | } 236 | 237 | func (i *Input) IsLanguageSwitcherPressed() bool { 238 | if inpututil.IsKeyJustPressed(ebiten.KeyL) { 239 | return true 240 | } 241 | if inpututil.IsMouseButtonJustPressed(ebiten.MouseButtonLeft) { 242 | if inLanguageSwitcher(ebiten.CursorPosition()) { 243 | return true 244 | } 245 | } 246 | for _, t := range inpututil.JustPressedTouchIDs() { 247 | if inLanguageSwitcher(ebiten.TouchPosition(t)) { 248 | return true 249 | } 250 | } 251 | return false 252 | } 253 | -------------------------------------------------------------------------------- /ino/internal/input/touch_mobile.go: -------------------------------------------------------------------------------- 1 | //go:build android || ios 2 | 3 | package input 4 | 5 | func isTouchPrimaryInput() bool { 6 | return true 7 | } 8 | -------------------------------------------------------------------------------- /ino/internal/input/touch_notmobile.go: -------------------------------------------------------------------------------- 1 | //go:build !android && !ios 2 | 3 | package input 4 | 5 | func isTouchPrimaryInput() bool { 6 | return false 7 | } 8 | -------------------------------------------------------------------------------- /ino/internal/lang/lang_default.go: -------------------------------------------------------------------------------- 1 | //go:build !js && !steam 2 | 3 | package lang 4 | 5 | import ( 6 | "golang.org/x/text/language" 7 | ) 8 | 9 | func SystemLang() language.Tag { 10 | // TODO: Implement this correctly 11 | return language.English 12 | } 13 | -------------------------------------------------------------------------------- /ino/internal/lang/lang_js.go: -------------------------------------------------------------------------------- 1 | package lang 2 | 3 | import ( 4 | "syscall/js" 5 | 6 | "golang.org/x/text/language" 7 | 8 | "github.com/hajimehoshi/go-inovation/ino/internal/text" 9 | ) 10 | 11 | func SystemLang() language.Tag { 12 | nav := js.Global().Get("navigator") 13 | if !nav.Truthy() { 14 | return language.Japanese 15 | } 16 | str := nav.Get("language").String() 17 | newLang, _ := language.Parse(str) 18 | base, _ := newLang.Base() 19 | newLang, _ = language.Compose(base) 20 | for _, l := range text.Languages() { 21 | if newLang == l { 22 | return newLang 23 | } 24 | } 25 | return language.English 26 | } 27 | -------------------------------------------------------------------------------- /ino/internal/lang/lang_steam.go: -------------------------------------------------------------------------------- 1 | //go:build !js && steam 2 | 3 | package lang 4 | 5 | import ( 6 | "os" 7 | 8 | "github.com/hajimehoshi/go-steamworks" 9 | "golang.org/x/text/language" 10 | ) 11 | 12 | const appID = 1710390 13 | 14 | func init() { 15 | if steamworks.RestartAppIfNecessary(appID) { 16 | os.Exit(1) 17 | } 18 | if !steamworks.Init() { 19 | panic("steamworks.Init failed") 20 | } 21 | } 22 | 23 | func SystemLang() language.Tag { 24 | switch steamworks.SteamApps().GetCurrentGameLanguage() { 25 | case "english": 26 | return language.English 27 | case "japanese": 28 | return language.Japanese 29 | } 30 | return language.English 31 | } 32 | -------------------------------------------------------------------------------- /ino/internal/text/text.go: -------------------------------------------------------------------------------- 1 | package text 2 | 3 | import ( 4 | "golang.org/x/text/language" 5 | ) 6 | 7 | type TextID int 8 | 9 | const ( 10 | TextIDStart TextID = iota 11 | TextIDStartLunker 12 | TextIDStartTouch 13 | TextIDOpening 14 | TextIDEnding 15 | TextIDEndingScore1 16 | TextIDEndingScore2 17 | TextIDEndingScore3 18 | TextIDSecretCommand 19 | TextIDSecretClear 20 | TextIDItemPowerUp 21 | TextIDItemFuji 22 | TextIDItemBushi 23 | TextIDItemApple 24 | TextIDItemV 25 | TextIDItemTaka 26 | TextIDItemShoulder 27 | TextIDItemDagger 28 | TextIDItemKatakata 29 | TextIDItemNasu 30 | TextIDItemBonus 31 | TextIDItemNurse 32 | TextIDItemNazuna 33 | TextIDItemGameHell 34 | TextIDItemGundam 35 | TextIDItemPoed 36 | TextIDItemMilestone 37 | TextIDItem1Yen 38 | TextIDItemTriangle 39 | TextIDItemOmega 40 | TextIDItemLife 41 | ) 42 | 43 | var texts = map[language.Tag]map[TextID]string{ 44 | language.Japanese: { 45 | TextIDStart: "すぺーす たたく はじまる!", 46 | TextIDStartLunker: "らんかー もーど はじまる!", 47 | TextIDStartTouch: "がめん たっち はじまる!", 48 | TextIDOpening: `めが さめたら 49 | いのししに なっていた。 50 | 51 | 52 | 53 | おちつけ おれ。 54 | ** ゆめの なかにいる ** 55 | 56 | 57 | 58 | ゆめの ちとゅう 59 | どるいどの よげんしゃが 60 | わたしに つげるのだった。 61 | 62 | 63 | 64 | 「さんしゅの じんぎを みつけだせるのは 65 | この ゆめの しゅじんこう… 66 | そう そなただけなのじゃ!」 67 | 68 | 69 | 70 | いかなる しょうがいをも のりこえ 71 | はつゆめ おやくそくの 72 | さんしゅの じんぎを さがしだすこと… 73 | それが わたしの 74 | はたすべき しめいなのだ! 75 | 76 | 77 | 78 | わたしの いのししとしての ちが さわぐ!`, 79 | TextIDEnding: `あつめた、じんぎたちが かがやきだす! 80 | 81 | 82 | 83 | うおーっ! 84 | 85 | わたしは さけびごえを あげ 86 | ひかりの なかへ… 87 | 88 | ほっぷ すてっぷ じゃんぷ 89 | かーるいす! 90 | 91 | 92 | 93 | やがて ひとつの いんしは 94 | その いしを もとの ばしょへ 95 | かいきさせ 96 | きおくの しんえんに きざまれた 97 | きげんの いしきを 98 | おもい おこさせる だろう… 99 | 100 | 101 | 102 | 103 | 104 | 2007 しんねん はじまる! 105 | あけましておめでとう! 106 | 107 | 108 | 109 | 110 | 111 | ―― ここから くれじっと ―― 112 | 113 | 114 | いのべーじょん2007 115 | ** くれじっとの なかに いる ** 116 | 117 | 118 | 119 | すーぱー ざつよう にんげん 120 | おめが / ( ゜ワ゜)ノ 121 | 122 | おんがく にんげん 123 | どん 124 | 125 | ふいーるど まっぷ にんげん 126 | おめが / ( ゜ワ゜)ノ 127 | げっく 128 | ずい 129 | 351 130 | 131 | たいとる めいめい にんげん 132 | わんきち 133 | 134 | てすとぷれい にんげん 135 | げーむへる2000 136 | げっく 137 | 351 138 | ずぃ 139 | あかじゃ 140 | 141 | すべさる さんくす にんげん 142 | げーむ せいさく ぎじゅつ いた 143 | どにちまでに げーむを つくる すれ 144 | 145 | HTML5 いしょく 146 | はねだ 147 | 148 | ごー げんご いしょく 149 | ほしはじめ 150 | 151 | 152 | ぷろどぅーすど ばい 153 | おめが 154 | 155 | 156 | 157 | ―― くれじっと ここまで ―― 158 | 159 | えんどう おふろに はいる`, 160 | TextIDEndingScore1: "せいせき はぴょう", 161 | TextIDEndingScore2: "かくとく あいてむ", 162 | TextIDEndingScore3: "くりあ たいむ", 163 | TextIDSecretCommand: `たいとるで 164 | 165 | ひだり ひだり ひだり 166 | みぎ みぎ みぎ 167 | ひだり みぎ`, 168 | TextIDSecretClear: `おめでとう。 169 | 170 | あなたは 171 | ぎじゅつ さる 172 | です。`, 173 | TextIDItemPowerUp: `「みずぐすり」を てに いれた。 174 | 「てーれってれー」 175 | 「じゃんぷりょくが あっぷ。 176 | くうちゅう じゃんぷが 1かい 177 | くわわる くわわる!`, 178 | TextIDItemFuji: `「ふじ」を てに いれた。 179 | じんぎの ひとつ。 180 | ふんかしない かざん。 181 | きゅうかざん って 182 | いうんだって。`, 183 | TextIDItemBushi: `「ぶし」を てに いれた。 184 | じゃぱにーず ないと。 185 | あめりか だいとうりょうも ぶしどー。 186 | さむらーい さむらーい ぶしどー。`, 187 | TextIDItemApple: `「ふじりんご」を てに いれた。 188 | あかい かじつ。 189 | あーかーい りんごーにー 190 | くちびーる よーせーてー。`, 191 | TextIDItemV: `「ぶい」を てに いれた。 192 | たたかいの さけび! 193 | 「しんかとは ひとと げーむの 194 | がったいだ!」`, 195 | TextIDItemTaka: `「たか」を てに いれた。 196 | じんぎの ひとつ。 197 | そらの はんたー。 198 | こだいあすてかでは 199 | かみの つかい なんだ。`, 200 | TextIDItemShoulder: `「かた」を てに いれた。 201 | どうたいの うえ、 202 | うでの つけね。 203 | かたが あかいと 204 | じかんに おくれる。`, 205 | TextIDItemDagger: `「だがー」を てに いれた。 206 | みじかい けん 207 | ひだりてたての かわりに。 208 | こがたなの かわりに。 209 | ぼうけんの おともに どうぞ。`, 210 | TextIDItemKatakata: `「かたかた」を てに いれた。 211 | かたかた… 212 | 「これは まるたーがいすと…」 213 | 「ちがう!ぷらずま だ!!」`, 214 | TextIDItemNasu: `「なす」を てに いれた。 215 | じんぎの ひとつ。 216 | むらさきに かがやく 217 | やさいの おうさま 218 | でも あまり たべたきが しない。`, 219 | TextIDItemBonus: `「ぼうなす」を てに いれた。 220 | あ ぼうなす! 221 | ふぇいたりてぃ ぼうなす! 222 | ぱしふぃすと ぼうなす! 223 | でぃす いず ざ ぼうなす!`, 224 | TextIDItemNurse: `「なーす」を てに いれた。 225 | 「かんごふでは ない! 226 | 『かんごし』と よべ! 227 | この ペいしえんと どもめ!」`, 228 | TextIDItemNazuna: `「なずな」を てに いれた。 229 | べつめい、ぺんぺんぐさ。 230 | なずなが とおったあとには 231 | ぺんぺんぐさすら のこらないという`, 232 | TextIDItemGameHell: `「げーむへる」を てに いれた。 233 | ようこそ。 234 | げーむ せいさくしゃと 235 | その しゅうへんの ための 236 | こみゅにていへ。`, 237 | TextIDItemGundam: `「じっしゃがんだむ」を てに いれた。 238 | 「そうさは かんたんだ。 239 | せんとう こんぴゅーたの 240 | すいっちを いれるだけで いい。」`, 241 | TextIDItemPoed: `「ほえど」を てに いれた。 242 | 「ふん。 243 | おもしろくなって 244 | きやがったぜ!」`, 245 | TextIDItemMilestone: `「まいるまーく」を てに いれた。 246 | さいしんさく「からす」 247 | ぜっさん かどうちゅう でしゅー`, 248 | TextIDItem1Yen: `「いちえんさつ」を てに いれた。 249 | 「くらくて よくみえないわ」 250 | 「ほうら あかるいだろう」 251 | 「『くらくて よくみえないわ』と 252 | かいてある」`, 253 | TextIDItemTriangle: `「とらいあんぐる」を てに いれた。 254 | すべって ころんで おおいたけん。 255 | しゃちょうは いま 256 | どうしているのか…`, 257 | TextIDItemOmega: `「おめがの くんしょう」を てに いれた。 258 | こんな げーむに 259 | まじに なって 260 | どうも ありがとう`, 261 | TextIDItemLife: `「はーとの うつわ」を てに いれた。 262 | でれででーん! 263 | らいふの じょうげんを 264 | 1ふやしてあげる 265 | ああ、なんて たくましいの…`, 266 | }, 267 | language.English: { 268 | TextIDStart: "PRESS SPACE BEGIN!", 269 | TextIDStartLunker: "LUNKER MODE BEGIN!", 270 | TextIDStartTouch: "TOUCH SCREEN BEGIN!", 271 | TextIDOpening: `when I wake up 272 | I become Wild bore 273 | calm down me 274 | ** stay in dream ** 275 | 276 | 277 | 278 | 279 | 280 | in a dream 281 | a Prophet Druid man 282 | He telling me 283 | can finding THE Three "GOT ICONs" 284 | this dream's HERO 285 | you. just only YOU! 286 | 287 | 288 | 289 | 290 | 291 | beat any traps 292 | Telling of 293 | "The first dream of the year of Japan" 294 | explor "Imperial Regalia of Japan" 295 | This is the FATE of me 296 | 297 | 298 | 299 | 300 | 301 | My WILD BORE's Heart get excited.`, 302 | TextIDEnding: `shining "Imperial Regalia of Japan" 303 | OOOMPF! 304 | 305 | 306 | 307 | Hop Step Jump 308 | carllouis! 309 | 310 | 311 | 312 | Before long A factor was 313 | her Intention had calling to original place 314 | Recurrence... 315 | Memoried to His Heart 316 | Recall it makes Mind of The Creation 317 | 318 | 319 | 2007 spring has come! 320 | 321 | 322 | a Happy New Year! 323 | 324 | 325 | 326 | 327 | 328 | INNOVATION 2007 329 | 330 | 331 | 332 | Super Trivial Works 333 | O-MEGA 334 | 335 | 336 | 337 | composer man 338 | dong 339 | 340 | 341 | 342 | Field Maps Design 343 | O-MEGA 344 | Gekku 345 | Zy 346 | 351 347 | 348 | 349 | 350 | Title naming 351 | wang-zhi 352 | 353 | 354 | 355 | Test Playing man 356 | Game-Hell 2000 357 | Gek 358 | 351 359 | Zi 360 | Akaja 361 | 362 | 363 | 364 | EngRish translation 365 | Eki 366 | Dong 367 | O-MEGA 368 | 369 | 370 | 371 | Special Thanks man 372 | Game Dev. BBS users 373 | www.2ch.net Thread "Game Deveropment" 374 | 375 | 376 | 377 | Porting to HTML5 378 | Haneda 379 | 380 | 381 | 382 | Porting to Go 383 | Hajime Hoshi 384 | 385 | 386 | 387 | Produced by 388 | O-MEGA 389 | 390 | 391 | 392 | EVZO-END get bath`, 393 | TextIDEndingScore1: "Results", 394 | TextIDEndingScore2: "You Got ICONS", 395 | TextIDEndingScore3: "Clear Time", 396 | TextIDSecretCommand: `at Title Screen 397 | 398 | L L L 399 | R R R 400 | L R`, 401 | TextIDSecretClear: `Congratulations! 402 | 403 | You are 404 | the 405 | technical monkey.`, 406 | TextIDItemPowerUp: `You Grab "Water Medicine" 407 | TA-RA-TERAH!! 408 | JUMP UP 409 | you got "M. Jordan's AIR NIKE" 410 | increase INCREASES!`, 411 | TextIDItemFuji: `You Grab a "FUJIYAMA" 412 | *An Imperial Regalia* 413 | Throw the One Ring Frodo!`, 414 | TextIDItemBushi: `You Feel "BUSHI-DO" 415 | Japanese SAMURAI Spilit 416 | USMC, Marines have BUSHI-DO 417 | SAMURAI SAMURAI BUSHI-DO`, 418 | TextIDItemApple: `You Grab Big Apple(fuji-ringo) 419 | Red Sweety 420 | Let it be lalala`, 421 | TextIDItemV: `You Grab "V of Victory" 422 | war cry! 423 | Me Humanbeing with a VIDEO GAME 424 | PILDER ON!`, 425 | TextIDItemTaka: `You catch a Hawk(Taka). 426 | *an Imperial Regalia* 427 | The President of Sky. 428 | In ancient Aztec 429 | A messenger of God`, 430 | TextIDItemShoulder: `You got a RED-SHOULDER(Kata) 431 | upper bodie The root of Arms 432 | Red-Shoulder`, 433 | TextIDItemDagger: `You Got a Dagger 434 | Short sword 435 | the only friend 436 | on your quest`, 437 | TextIDItemKatakata: `You Grab "Katakata" 438 | strange sound 439 | RATTLE-RATTLE... 440 | Poltergeist!? 441 | NO! ask to Mulder!`, 442 | TextIDItemNasu: `You Got Eggplant (Nasu) 443 | *An Imperial Regalia* 444 | Purple Shining 445 | King of Vegetable 446 | But I've never satisfied with this`, 447 | TextIDItemBonus: `You Got "Bonus" 448 | A Bonus! 449 | Fatality Bonus! 450 | Pacifist Bonus! 451 | This is the Bonus!`, 452 | TextIDItemNurse: `You Grab "Nurse" 453 | I'm not an angel in white 454 | I'm a goddess of hell 455 | You Patients!`, 456 | TextIDItemNazuna: `You got "Nazuna" 457 | It is called 458 | "Shepherd's-purse" 459 | in English 460 | Symbol of doom`, 461 | TextIDItemGameHell: `You Grab “GameHel12000" 462 | Helcome. 463 | We are an community of 464 | Japanese indie game developers.`, 465 | TextIDItemGundam: `You Grab "GUNDAM 0079" 466 | Control is easy 467 | All you have to do is 468 | switching on a battle computer`, 469 | TextIDItemPoed: `You Grab "Po'ed" 470 | Ha! 471 | It's getting more interesting!`, 472 | TextIDItemMilestone: `You got "Milestone Mark" 473 | All your wii are belong to 474 | our doomsday device KAROUS.`, 475 | TextIDItem1Yen: `You Got 1 Yen. 476 | In ancient Japan 477 | It was used as a 478 | substitute for light`, 479 | TextIDItemTriangle: `You Got "Triangle Service" 480 | Slip Trip Oita-Pref. 481 | Where is the Boss?`, 482 | TextIDItemOmega: `You Got "O-mega Medal" 483 | Thank you for playing 484 | such a masochistic game.`, 485 | TextIDItemLife: `You Got a Heart Container 486 | DeDeDe-Deng!! 487 | Increase your MAX LIFE. 488 | REAL MEN!!`, 489 | }, 490 | } 491 | 492 | func Get(lang language.Tag, id TextID) string { 493 | return texts[lang][id] 494 | } 495 | 496 | func Languages() []language.Tag { 497 | // TODO: Sort 498 | langs := []language.Tag{} 499 | for lang := range texts { 500 | langs = append(langs, lang) 501 | } 502 | return langs 503 | } 504 | -------------------------------------------------------------------------------- /ino/main.go: -------------------------------------------------------------------------------- 1 | package ino 2 | 3 | import ( 4 | "fmt" 5 | "image/color" 6 | "math/rand" 7 | "strconv" 8 | "strings" 9 | "time" 10 | 11 | "github.com/hajimehoshi/ebiten/v2" 12 | "golang.org/x/text/language" 13 | 14 | "github.com/hajimehoshi/go-inovation/ino/internal/audio" 15 | "github.com/hajimehoshi/go-inovation/ino/internal/draw" 16 | "github.com/hajimehoshi/go-inovation/ino/internal/font" 17 | "github.com/hajimehoshi/go-inovation/ino/internal/input" 18 | "github.com/hajimehoshi/go-inovation/ino/internal/text" 19 | ) 20 | 21 | const ( 22 | ScreenWidth = draw.ScreenWidth 23 | ScreenHeight = draw.ScreenHeight 24 | ) 25 | 26 | const ( 27 | ENDINGMAIN_STATE_STAFFROLL = iota 28 | ENDINGMAIN_STATE_RESULT 29 | ) 30 | 31 | type GameStateMsg int 32 | 33 | const ( 34 | GAMESTATE_MSG_NONE GameStateMsg = iota 35 | GAMESTATE_MSG_REQ_TITLE 36 | GAMESTATE_MSG_REQ_GAME 37 | GAMESTATE_MSG_REQ_OPENING 38 | GAMESTATE_MSG_REQ_ENDING 39 | GAMESTATE_MSG_REQ_SECRET_COMMAND 40 | GAMESTATE_MSG_REQ_SECRET_CLEAR 41 | ) 42 | 43 | type TitleScene struct { 44 | gameStateMsg GameStateMsg 45 | timer int 46 | offsetX int 47 | offsetY int 48 | lunkerMode bool 49 | lunkerCommand int 50 | } 51 | 52 | func init() { 53 | rand.Seed(time.Now().UnixNano()) 54 | } 55 | 56 | func (t *TitleScene) Update(game *Game) { 57 | t.timer++ 58 | if t.timer%5 == 0 { 59 | t.offsetX = rand.Intn(5) - 3 60 | t.offsetY = rand.Intn(5) - 3 61 | } 62 | 63 | if (input.Current().IsActionKeyJustPressed() || input.Current().IsSpaceJustTouched()) && t.timer > 5 { 64 | t.gameStateMsg = GAMESTATE_MSG_REQ_OPENING 65 | 66 | if t.lunkerMode { 67 | game.gameData = NewGameData(GAMEMODE_LUNKER) 68 | } else { 69 | game.gameData = NewGameData(GAMEMODE_NORMAL) 70 | } 71 | } 72 | 73 | // ランカー・モード・コマンド 74 | switch t.lunkerCommand { 75 | case 0, 1, 2, 6: 76 | if input.Current().IsKeyJustPressed(ebiten.KeyLeft) { 77 | t.lunkerCommand++ 78 | } else if input.Current().IsKeyJustPressed(ebiten.KeyRight) || input.Current().IsKeyJustPressed(ebiten.KeyUp) || input.Current().IsKeyJustPressed(ebiten.KeyDown) { 79 | t.lunkerCommand = 0 80 | } 81 | case 3, 4, 5, 7: 82 | if input.Current().IsKeyJustPressed(ebiten.KeyRight) { 83 | t.lunkerCommand++ 84 | } else if input.Current().IsKeyJustPressed(ebiten.KeyLeft) || input.Current().IsKeyJustPressed(ebiten.KeyUp) || input.Current().IsKeyJustPressed(ebiten.KeyDown) { 85 | t.lunkerCommand = 0 86 | } 87 | default: 88 | break 89 | } 90 | if t.lunkerCommand > 7 { 91 | t.lunkerCommand = 0 92 | t.lunkerMode = !t.lunkerMode 93 | } 94 | 95 | if input.Current().IsLanguageSwitcherPressed() { 96 | switch game.lang { 97 | case language.Japanese: 98 | game.lang = language.English 99 | case language.English: 100 | game.lang = language.Japanese 101 | } 102 | } 103 | 104 | switch game.lang { 105 | case language.English: 106 | ebiten.SetWindowTitle("INNO VATION! 2007") 107 | case language.Japanese: 108 | ebiten.SetWindowTitle("いの べーしょん! 2007") 109 | } 110 | } 111 | 112 | func (t *TitleScene) Draw(screen *ebiten.Image, game *Game) { 113 | textID := text.TextIDStart 114 | clr := color.Black 115 | if !game.transparent { 116 | if t.lunkerMode { 117 | draw.Draw(screen, "bg", 0, 0, 0, 240, draw.ScreenWidth, draw.ScreenHeight) 118 | textID = text.TextIDStartLunker 119 | clr = color.White 120 | } else { 121 | draw.Draw(screen, "bg", 0, 0, 0, 0, draw.ScreenWidth, draw.ScreenHeight) 122 | if input.Current().IsTouchEnabled() { 123 | textID = text.TextIDStartTouch 124 | } 125 | } 126 | } 127 | 128 | str := text.Get(game.lang, textID) 129 | x := (draw.ScreenWidth-font.Width(str))/2 + t.offsetX 130 | y := (draw.ScreenHeight-240)/2 + 160 + t.offsetY 131 | font.DrawText(screen, str, x, y, clr) 132 | 133 | // Draw the title. 134 | key := "msg_" + game.lang.String() 135 | draw.Draw(screen, key, (draw.ScreenWidth-256)/2, 32+(draw.ScreenHeight-240)/2, 0, 0, 256, 48) 136 | 137 | // Draw the language switcher. 138 | font.DrawText(screen, "Language", 320-48, 0, color.RGBA{0x80, 0x80, 0x80, 0xff}) 139 | } 140 | 141 | func (t *TitleScene) Msg() GameStateMsg { 142 | return t.gameStateMsg 143 | } 144 | 145 | type OpeningScene struct { 146 | gameStateMsg GameStateMsg 147 | timer int 148 | texts map[language.Tag][]string 149 | } 150 | 151 | const ( 152 | OPENING_SCROLL_SPEED = 3 153 | ) 154 | 155 | func (o *OpeningScene) Update(game *Game) { 156 | o.timer++ 157 | 158 | if input.Current().IsActionKeyPressed() || input.Current().IsSpaceTouched() { 159 | o.timer += 20 160 | } 161 | scrollLen := font.Height(text.Get(game.lang, text.TextIDOpening)) + draw.ScreenHeight 162 | if o.timer/OPENING_SCROLL_SPEED > scrollLen { 163 | o.gameStateMsg = GAMESTATE_MSG_REQ_GAME 164 | audio.PauseBGM() 165 | } 166 | } 167 | 168 | func (o *OpeningScene) Draw(screen *ebiten.Image, game *Game) { 169 | if !game.transparent { 170 | draw.Draw(screen, "bg", 0, 0, 0, 480, 320, 240) 171 | } 172 | 173 | if _, ok := o.texts[game.lang]; !ok { 174 | if o.texts == nil { 175 | o.texts = map[language.Tag][]string{} 176 | } 177 | o.texts[game.lang] = strings.Split(text.Get(game.lang, text.TextIDOpening), "\n") 178 | } 179 | for i, line := range o.texts[game.lang] { 180 | x := (draw.ScreenWidth - font.Width(line)) / 2 181 | y := draw.ScreenHeight - (o.timer / OPENING_SCROLL_SPEED) + i*font.LineHeight 182 | font.DrawText(screen, line, x, y, color.Black) 183 | } 184 | } 185 | 186 | func (o *OpeningScene) Msg() GameStateMsg { 187 | return o.gameStateMsg 188 | } 189 | 190 | type EndingScene struct { 191 | gameStateMsg GameStateMsg 192 | timer int 193 | bgmFadingTimer int 194 | state int 195 | texts map[language.Tag][]string 196 | } 197 | 198 | const ( 199 | ENDING_SCROLL_SPEED = 3 200 | ) 201 | 202 | func (e *EndingScene) Update(game *Game) { 203 | e.timer++ 204 | switch e.state { 205 | case ENDINGMAIN_STATE_STAFFROLL: 206 | if input.Current().IsActionKeyPressed() || input.Current().IsSpaceTouched() { 207 | e.timer += 20 208 | } 209 | scrollLen := font.Height(text.Get(game.lang, text.TextIDEnding)) + draw.ScreenHeight 210 | if e.timer/ENDING_SCROLL_SPEED > scrollLen { 211 | e.timer = 0 212 | e.state = ENDINGMAIN_STATE_RESULT 213 | } 214 | case ENDINGMAIN_STATE_RESULT: 215 | const max = 5 * 60 216 | e.bgmFadingTimer++ 217 | switch { 218 | case e.bgmFadingTimer == max: 219 | audio.PauseBGM() 220 | case e.bgmFadingTimer < max: 221 | vol := 1 - (float64(e.bgmFadingTimer) / max) 222 | audio.SetBGMVolume(vol) 223 | } 224 | if (input.Current().IsActionKeyJustPressed() || input.Current().IsSpaceJustTouched()) && e.timer > 5 { 225 | // 条件を満たしていると隠し画面へ 226 | if game.gameData.IsGetOmega() { 227 | if game.gameData.lunkerMode { 228 | e.gameStateMsg = GAMESTATE_MSG_REQ_SECRET_CLEAR 229 | } else { 230 | e.gameStateMsg = GAMESTATE_MSG_REQ_SECRET_COMMAND 231 | } 232 | return 233 | } 234 | e.gameStateMsg = GAMESTATE_MSG_REQ_TITLE 235 | audio.PauseBGM() 236 | } 237 | } 238 | } 239 | 240 | func (e *EndingScene) Draw(screen *ebiten.Image, game *Game) { 241 | if !game.transparent { 242 | draw.Draw(screen, "bg", 0, 0, 0, 480, 320, 240) 243 | } 244 | 245 | switch e.state { 246 | case ENDINGMAIN_STATE_STAFFROLL: 247 | if _, ok := e.texts[game.lang]; !ok { 248 | if e.texts == nil { 249 | e.texts = map[language.Tag][]string{} 250 | } 251 | e.texts[game.lang] = strings.Split(text.Get(game.lang, text.TextIDEnding), "\n") 252 | } 253 | for i, line := range e.texts[game.lang] { 254 | x := (draw.ScreenWidth - font.Width(line)) / 2 255 | y := draw.ScreenHeight - (e.timer / ENDING_SCROLL_SPEED) + i*font.LineHeight 256 | font.DrawText(screen, line, x, y, color.Black) 257 | } 258 | case ENDINGMAIN_STATE_RESULT: 259 | lines := []string{ 260 | text.Get(game.lang, text.TextIDEndingScore1), 261 | "", 262 | text.Get(game.lang, text.TextIDEndingScore2), 263 | strconv.Itoa(game.gameData.GetItemCount()), 264 | "", 265 | text.Get(game.lang, text.TextIDEndingScore3), 266 | fmt.Sprintf("%.2f", float64(game.gameData.TimeInFrame())/60), 267 | } 268 | for i, line := range lines { 269 | x := (draw.ScreenWidth - font.Width(line)) / 2 270 | font.DrawText(screen, line, x, (draw.ScreenHeight-160)/2+16*i, color.Black) 271 | } 272 | } 273 | } 274 | 275 | func (e *EndingScene) Msg() GameStateMsg { 276 | return e.gameStateMsg 277 | } 278 | 279 | type SecretType int 280 | 281 | const ( 282 | SecretTypeCommand SecretType = iota 283 | SecretTypeClear 284 | ) 285 | 286 | type SecretScene struct { 287 | gameStateMsg GameStateMsg 288 | timer int 289 | secretType SecretType 290 | } 291 | 292 | func NewSecretScene(secretType SecretType) *SecretScene { 293 | return &SecretScene{ 294 | secretType: secretType, 295 | } 296 | } 297 | 298 | func (s *SecretScene) Update(game *Game) { 299 | s.timer++ 300 | if (input.Current().IsActionKeyJustPressed() || input.Current().IsSpaceJustTouched()) && s.timer > 5 { 301 | s.gameStateMsg = GAMESTATE_MSG_REQ_TITLE 302 | } 303 | } 304 | 305 | func (s *SecretScene) Draw(screen *ebiten.Image, game *Game) { 306 | if !game.transparent { 307 | draw.Draw(screen, "bg", 0, 0, 0, 240, 320, 240) 308 | } 309 | var textID text.TextID 310 | switch s.secretType { 311 | case SecretTypeCommand: 312 | textID = text.TextIDSecretCommand 313 | case SecretTypeClear: 314 | textID = text.TextIDSecretClear 315 | default: 316 | panic("not reached") 317 | } 318 | str := text.Get(game.lang, textID) 319 | y := (draw.ScreenHeight - font.Height(str)) / 2 320 | for i, line := range strings.Split(str, "\n") { 321 | x := (draw.ScreenWidth - font.Width(line)) / 2 322 | font.DrawText(screen, line, x, y+i*font.LineHeight, color.White) 323 | } 324 | } 325 | 326 | func (s *SecretScene) Msg() GameStateMsg { 327 | return s.gameStateMsg 328 | } 329 | 330 | type GameScene struct { 331 | gameStateMsg GameStateMsg 332 | player *Player 333 | } 334 | 335 | func NewGameScene(game *Game) *GameScene { 336 | g := &GameScene{ 337 | player: NewPlayer(game.gameData), 338 | } 339 | return g 340 | } 341 | 342 | func (g *GameScene) Update(game *Game) { 343 | g.gameStateMsg = g.player.Update() 344 | } 345 | 346 | func (g *GameScene) Draw(screen *ebiten.Image, game *Game) { 347 | if !game.transparent { 348 | if game.gameData.lunkerMode { 349 | draw.Draw(screen, "bg", 0, 0, 0, 240, draw.ScreenWidth, draw.ScreenHeight) 350 | } else { 351 | draw.Draw(screen, "bg", 0, 0, 0, 0, draw.ScreenWidth, draw.ScreenHeight) 352 | } 353 | } 354 | g.player.Draw(screen, game) 355 | if input.Current().IsTouchEnabled() { 356 | draw.DrawTouchButtons(screen) 357 | } 358 | } 359 | 360 | func (g *GameScene) Msg() GameStateMsg { 361 | return g.gameStateMsg 362 | } 363 | 364 | type Scene interface { 365 | Update(g *Game) // TODO: Should return errors 366 | Draw(screen *ebiten.Image, g *Game) 367 | Msg() GameStateMsg 368 | } 369 | -------------------------------------------------------------------------------- /ino/player.go: -------------------------------------------------------------------------------- 1 | package ino 2 | 3 | import ( 4 | "math" 5 | 6 | "github.com/hajimehoshi/ebiten/v2" 7 | 8 | "github.com/hajimehoshi/go-inovation/ino/internal/audio" 9 | "github.com/hajimehoshi/go-inovation/ino/internal/draw" 10 | "github.com/hajimehoshi/go-inovation/ino/internal/field" 11 | "github.com/hajimehoshi/go-inovation/ino/internal/fieldtype" 12 | "github.com/hajimehoshi/go-inovation/ino/internal/input" 13 | ) 14 | 15 | type PlayerState int 16 | 17 | const ( 18 | PLAYERSTATE_START PlayerState = iota 19 | PLAYERSTATE_NORMAL 20 | PLAYERSTATE_ITEMGET 21 | PLAYERSTATE_MUTEKI 22 | PLAYERSTATE_DEAD 23 | ) 24 | 25 | const ( 26 | PLAYER_SPEED = 2.0 27 | PLAYER_GRD_ACCRATIO = 0.04 28 | PLAYER_AIR_ACCRATIO = 0.01 29 | PLAYER_JUMP = -4.0 30 | PLAYER_GRAVITY = 0.2 31 | PLAYER_FALL_SPEEDMAX = 4.0 32 | WAIT_TIMER_INTERVAL = 10 33 | LIFE_RATIO = 400 34 | MUTEKI_INTERVAL = 50 35 | START_WAIT_INTERVAL = 50 36 | SCROLLPANEL_SPEED = 2.0 37 | 38 | LUNKER_JUMP_DAMAGE1 = 40.0 39 | LUNKER_JUMP_DAMAGE2 = 96.0 40 | ) 41 | 42 | type Player struct { 43 | life int 44 | jumpCnt int 45 | timer int 46 | position PositionF 47 | speed PositionF 48 | direction int 49 | jumpedPoint PositionF 50 | state PlayerState 51 | itemGet fieldtype.FieldType 52 | waitTimer int 53 | gameData *GameData // TODO(hajimehoshi): Remove this? 54 | view *View 55 | field *field.Field 56 | } 57 | 58 | func NewPlayer(gameData *GameData) *Player { 59 | f := field.New(field_data) 60 | x, y := f.GetStartPoint() 61 | startPointF := PositionF{float64(x), float64(y)} 62 | audio.PlayBGM(audio.BGM0) 63 | return &Player{ 64 | gameData: gameData, 65 | field: f, 66 | life: gameData.lifeMax * LIFE_RATIO, 67 | position: startPointF, 68 | jumpedPoint: startPointF, 69 | view: NewView(startPointF), 70 | } 71 | } 72 | 73 | func (p *Player) onWall() bool { 74 | if p.toFieldOfsY() > field.CHAR_SIZE/4 { 75 | return false 76 | } 77 | if p.field.IsRidable(p.toFieldX(), p.toFieldY()+1) && p.toFieldOfsX() < field.CHAR_SIZE*7/8 { 78 | return true 79 | } 80 | if p.field.IsRidable(p.toFieldX()+1, p.toFieldY()+1) && p.toFieldOfsX() > field.CHAR_SIZE/8 { 81 | return true 82 | } 83 | return false 84 | } 85 | 86 | func (p *Player) isFallable() bool { 87 | if !p.onWall() { 88 | return false 89 | } 90 | if p.field.IsWall(p.toFieldX(), p.toFieldY()+1) && p.toFieldOfsX() < field.CHAR_SIZE*7/8 { 91 | return false 92 | } 93 | if p.field.IsWall(p.toFieldX()+1, p.toFieldY()+1) && p.toFieldOfsX() > field.CHAR_SIZE/8 { 94 | return false 95 | } 96 | return true 97 | } 98 | 99 | func (p *Player) isUpperWallBoth() bool { 100 | if p.toFieldOfsY() < field.CHAR_SIZE/2 { 101 | return false 102 | } 103 | if p.field.IsWall(p.toFieldX(), p.toFieldY()) && p.field.IsWall(p.toFieldX()+1, p.toFieldY()) { 104 | return true 105 | } 106 | return false 107 | } 108 | 109 | func (p *Player) isUpperWall() bool { 110 | if p.toFieldOfsY() < field.CHAR_SIZE/2 { 111 | return false 112 | } 113 | if p.field.IsWall(p.toFieldX(), p.toFieldY()) && p.toFieldOfsX() < field.CHAR_SIZE*7/8 { 114 | return true 115 | } 116 | if p.field.IsWall(p.toFieldX()+1, p.toFieldY()) && p.toFieldOfsX() > field.CHAR_SIZE/8 { 117 | return true 118 | } 119 | return false 120 | } 121 | 122 | func (p *Player) isLeftWall() bool { 123 | if p.field.IsWall(p.toFieldX(), p.toFieldY()) { 124 | return true 125 | } 126 | if p.field.IsWall(p.toFieldX(), p.toFieldY()+1) && p.toFieldOfsY() > field.CHAR_SIZE/8 { 127 | return true 128 | } 129 | return false 130 | } 131 | 132 | func (p *Player) isRightWall() bool { 133 | if p.field.IsWall(p.toFieldX()+1, p.toFieldY()) { 134 | return true 135 | } 136 | if p.field.IsWall(p.toFieldX()+1, p.toFieldY()+1) && p.toFieldOfsY() > field.CHAR_SIZE/8 { 137 | return true 138 | } 139 | return false 140 | } 141 | 142 | func (p *Player) normalizeToRight() { 143 | p.position.X = float64(p.toFieldX() * field.CHAR_SIZE) 144 | p.speed.X = 0 145 | } 146 | 147 | func (p *Player) normalizeToLeft() { 148 | p.position.X = float64((p.toFieldX() + 1) * field.CHAR_SIZE) 149 | p.speed.X = 0 150 | } 151 | 152 | func (p *Player) normalizeToUpper() { 153 | if p.speed.Y < 0 { 154 | p.speed.Y = 0 155 | } 156 | p.position.Y = float64(field.CHAR_SIZE * (p.toFieldY() + 1)) 157 | } 158 | 159 | func (p *Player) toFieldX() int { 160 | return int(p.position.X) / field.CHAR_SIZE 161 | } 162 | 163 | func (p *Player) toFieldY() int { 164 | return int(p.position.Y) / field.CHAR_SIZE 165 | } 166 | 167 | func (p *Player) toFieldOfsX() int { 168 | return int(p.position.X) % field.CHAR_SIZE 169 | } 170 | 171 | func (p *Player) toFieldOfsY() int { 172 | return int(p.position.Y) % field.CHAR_SIZE 173 | } 174 | 175 | func (p *Player) Update() GameStateMsg { 176 | msg := GAMESTATE_MSG_NONE 177 | p.field.Update() 178 | switch p.state { 179 | case PLAYERSTATE_START: 180 | p.waitTimer++ 181 | if p.waitTimer > START_WAIT_INTERVAL { 182 | p.state = PLAYERSTATE_NORMAL 183 | } 184 | 185 | case PLAYERSTATE_NORMAL: 186 | p.moveByInput() 187 | p.moveNormal() 188 | if p.life < p.gameData.lifeMax*LIFE_RATIO { 189 | o_life := p.life 190 | p.life++ 191 | if (p.life / LIFE_RATIO) != (o_life / LIFE_RATIO) { 192 | audio.PlaySE(audio.SE_HEAL) 193 | } 194 | } 195 | 196 | case PLAYERSTATE_ITEMGET: 197 | p.moveItemGet() 198 | if p.state != PLAYERSTATE_ITEMGET { 199 | if p.gameData.IsGameClear() { 200 | msg = GAMESTATE_MSG_REQ_ENDING 201 | } 202 | } 203 | 204 | case PLAYERSTATE_MUTEKI: 205 | p.moveByInput() 206 | p.moveNormal() 207 | p.waitTimer++ 208 | if p.waitTimer > MUTEKI_INTERVAL { 209 | p.state = PLAYERSTATE_NORMAL 210 | } 211 | 212 | case PLAYERSTATE_DEAD: 213 | p.moveNormal() 214 | audio.PauseBGM() 215 | if input.Current().IsActionKeyPressed() && p.waitTimer > 15 { 216 | msg = GAMESTATE_MSG_REQ_TITLE 217 | } 218 | } 219 | if p.life < LIFE_RATIO { 220 | if p.state != PLAYERSTATE_DEAD { 221 | p.waitTimer = 0 222 | } 223 | p.state = PLAYERSTATE_DEAD 224 | p.direction = 0 225 | p.waitTimer++ 226 | } 227 | return msg 228 | } 229 | 230 | func (p *Player) moveNormal() { 231 | p.timer++ 232 | p.gameData.Update() 233 | 234 | // 移動&落下 235 | p.speed.Y += PLAYER_GRAVITY 236 | p.position.X += p.speed.X 237 | p.position.Y += p.speed.Y 238 | 239 | if p.speed.Y > PLAYER_FALL_SPEEDMAX { 240 | p.speed.Y = PLAYER_FALL_SPEEDMAX 241 | } 242 | 243 | if p.state == PLAYERSTATE_NORMAL { 244 | p.checkCollision() 245 | } 246 | 247 | // ATARI判定 248 | hitLeft := false 249 | hitRight := false 250 | hitUpper := false 251 | if p.onWall() && p.speed.Y >= 0 { 252 | if p.gameData.lunkerMode { 253 | if p.position.Y-p.jumpedPoint.Y > LUNKER_JUMP_DAMAGE1 { 254 | p.state = PLAYERSTATE_MUTEKI 255 | p.waitTimer = 0 256 | p.life -= LIFE_RATIO 257 | audio.PlaySE(audio.SE_DAMAGE) 258 | } 259 | if p.position.Y-p.jumpedPoint.Y > LUNKER_JUMP_DAMAGE2 { 260 | p.state = PLAYERSTATE_MUTEKI 261 | p.waitTimer = 0 262 | p.life -= LIFE_RATIO * 99 263 | audio.PlaySE(audio.SE_DAMAGE) 264 | } 265 | } 266 | 267 | if !input.Current().IsActionKeyPressed() || !input.Current().IsDirectionKeyPressed(input.DirectionDown) || !p.isFallable() { 268 | if p.speed.Y > 0 { 269 | p.speed.Y = 0 270 | } 271 | p.position.Y = float64(field.CHAR_SIZE * p.toFieldY()) 272 | p.jumpCnt = 0 273 | } 274 | 275 | p.jumpedPoint = p.position 276 | } 277 | if p.isLeftWall() && p.speed.X < 0 { 278 | hitLeft = true 279 | } 280 | if p.isRightWall() && p.speed.X > 0 { 281 | hitRight = true 282 | } 283 | if p.isUpperWall() && p.speed.Y <= 0 { 284 | hitUpper = true 285 | } 286 | 287 | if hitUpper && !hitLeft && !hitRight { 288 | p.normalizeToUpper() 289 | } 290 | if !hitUpper && hitLeft { 291 | p.normalizeToLeft() 292 | } 293 | if !hitUpper && hitRight { 294 | p.normalizeToRight() 295 | } 296 | if hitUpper && hitRight { 297 | if p.isUpperWallBoth() { 298 | p.normalizeToUpper() 299 | } else { 300 | if p.toFieldOfsX() > p.toFieldOfsY() { 301 | p.normalizeToRight() 302 | } else { 303 | p.normalizeToUpper() 304 | } 305 | } 306 | } 307 | if hitUpper && hitLeft { 308 | if p.isUpperWallBoth() { 309 | p.normalizeToUpper() 310 | } else { 311 | if field.CHAR_SIZE-p.toFieldOfsX() > p.toFieldOfsY() { 312 | p.normalizeToLeft() 313 | } else { 314 | p.normalizeToUpper() 315 | } 316 | } 317 | } 318 | 319 | // 床特殊効果 320 | switch p.getOnField() { 321 | case fieldtype.FIELD_SCROLL_L: 322 | p.speed.X = p.speed.X*(1.0-PLAYER_GRD_ACCRATIO) + float64(p.direction*PLAYER_SPEED-SCROLLPANEL_SPEED)*PLAYER_GRD_ACCRATIO 323 | case fieldtype.FIELD_SCROLL_R: 324 | p.speed.X = p.speed.X*(1.0-PLAYER_GRD_ACCRATIO) + float64(p.direction*PLAYER_SPEED+SCROLLPANEL_SPEED)*PLAYER_GRD_ACCRATIO 325 | case fieldtype.FIELD_SLIP: 326 | // Do nothing 327 | case fieldtype.FIELD_NONE: 328 | p.speed.X = p.speed.X*(1.0-PLAYER_AIR_ACCRATIO) + float64(p.direction*PLAYER_SPEED)*PLAYER_AIR_ACCRATIO 329 | default: 330 | p.speed.X = p.speed.X*(1.0-PLAYER_GRD_ACCRATIO) + float64(p.direction*PLAYER_SPEED)*PLAYER_GRD_ACCRATIO 331 | } 332 | 333 | p.view.Update(p.position, p.speed) 334 | } 335 | 336 | func (p *Player) moveItemGet() { 337 | if p.waitTimer < WAIT_TIMER_INTERVAL { 338 | p.waitTimer++ 339 | return 340 | } 341 | if input.Current().IsActionKeyJustPressed() { 342 | p.state = PLAYERSTATE_NORMAL 343 | audio.ResumeBGM(audio.BGM0) 344 | } 345 | } 346 | 347 | func (p *Player) moveByInput() { 348 | if input.Current().IsDirectionKeyPressed(input.DirectionLeft) { 349 | p.direction = -1 350 | } 351 | if input.Current().IsDirectionKeyPressed(input.DirectionRight) { 352 | p.direction = 1 353 | } 354 | 355 | if input.Current().IsActionKeyJustPressed() { 356 | if ((p.gameData.jumpMax > p.jumpCnt) || p.onWall()) && !input.Current().IsDirectionKeyPressed(input.DirectionDown) { 357 | p.speed.Y = PLAYER_JUMP // ジャンプ 358 | if !p.onWall() { 359 | p.jumpCnt++ 360 | } 361 | 362 | if math.Abs(p.speed.X) < 0.1 { 363 | if p.speed.X < 0 { 364 | p.speed.X -= 0.02 365 | } 366 | if p.speed.X > 0 { 367 | p.speed.X += 0.02 368 | } 369 | } 370 | audio.PlaySE(audio.SE_JUMP) 371 | p.jumpedPoint = p.position 372 | } 373 | } 374 | } 375 | 376 | func (p *Player) checkCollision() { 377 | for xx := 0; xx < 2; xx++ { 378 | for yy := 0; yy < 2; yy++ { 379 | // アイテム獲得(STATE_ITEMGETへ遷移) 380 | if p.field.IsItem(p.toFieldX()+xx, p.toFieldY()+yy) { 381 | // 隠しアイテムは条件が必要 382 | if !p.field.IsItemGettable(p.toFieldX()+xx, p.toFieldY()+yy, p.gameData) { 383 | continue 384 | } 385 | 386 | p.state = PLAYERSTATE_ITEMGET 387 | 388 | // アイテム効果 389 | p.itemGet = p.field.GetField(p.toFieldX()+xx, p.toFieldY()+yy) 390 | switch p.field.GetField(p.toFieldX()+xx, p.toFieldY()+yy) { 391 | case fieldtype.FIELD_ITEM_POWERUP: 392 | p.gameData.jumpMax++ 393 | case fieldtype.FIELD_ITEM_LIFE: 394 | p.gameData.lifeMax++ 395 | p.life = p.gameData.lifeMax * LIFE_RATIO 396 | default: 397 | p.gameData.itemGetFlags[p.itemGet] = true 398 | } 399 | p.field.EraseField(p.toFieldX()+xx, p.toFieldY()+yy) 400 | p.waitTimer = 0 401 | 402 | audio.PauseBGM() 403 | if IsItemForClear(p.itemGet) || p.itemGet == fieldtype.FIELD_ITEM_POWERUP { 404 | audio.PlaySE(audio.SE_ITEMGET) 405 | } else { 406 | audio.PlaySE(audio.SE_ITEMGET2) 407 | } 408 | return 409 | } 410 | // トゲ(ダメージ) 411 | if p.field.IsSpike(p.toFieldX()+xx, p.toFieldY()+yy) { 412 | p.state = PLAYERSTATE_MUTEKI 413 | p.waitTimer = 0 414 | p.life -= LIFE_RATIO 415 | p.speed.Y = PLAYER_JUMP 416 | p.jumpCnt = -1 // ダメージ・エキストラジャンプ 417 | audio.PlaySE(audio.SE_DAMAGE) 418 | return 419 | } 420 | } 421 | } 422 | } 423 | 424 | func (p *Player) getOnField() fieldtype.FieldType { 425 | if !p.onWall() { 426 | return fieldtype.FIELD_NONE 427 | } 428 | x, y := p.toFieldX(), p.toFieldY() 429 | if p.toFieldOfsX() < field.CHAR_SIZE/2 { 430 | if p.field.IsRidable(x, y+1) { 431 | return p.field.GetField(x, y+1) 432 | } 433 | return p.field.GetField(x+1, y+1) 434 | } 435 | if p.field.IsRidable(x+1, y+1) { 436 | return p.field.GetField(x+1, y+1) 437 | } 438 | return p.field.GetField(x, y+1) 439 | } 440 | 441 | func (p *Player) drawPlayer(screen *ebiten.Image, game *Game) { 442 | v := p.view.ToScreenPosition(p.position) 443 | vx, vy := int(v.X), int(v.Y) 444 | if p.state == PLAYERSTATE_DEAD { // 死亡 445 | anime := (p.timer / 6) % 4 446 | if game.gameData.lunkerMode { 447 | draw.Draw(screen, "ino", vx, vy, field.CHAR_SIZE*(2+anime), 128+field.CHAR_SIZE*2, field.CHAR_SIZE, field.CHAR_SIZE) 448 | return 449 | } 450 | draw.Draw(screen, "ino", vx, vy, field.CHAR_SIZE*(2+anime), 128, field.CHAR_SIZE, field.CHAR_SIZE) 451 | return 452 | } 453 | if p.state != PLAYERSTATE_MUTEKI || p.timer%10 < 5 { 454 | anime := (p.timer / 6) % 2 455 | if !p.onWall() { 456 | anime = 0 457 | } 458 | if p.direction < 0 { 459 | if game.gameData.lunkerMode { 460 | draw.Draw(screen, "ino", vx, vy, field.CHAR_SIZE*anime, 128+field.CHAR_SIZE*2, field.CHAR_SIZE, field.CHAR_SIZE) 461 | return 462 | } 463 | draw.Draw(screen, "ino", vx, vy, field.CHAR_SIZE*anime, 128, field.CHAR_SIZE, field.CHAR_SIZE) 464 | return 465 | } 466 | if game.gameData.lunkerMode { 467 | draw.Draw(screen, "ino", vx, vy, field.CHAR_SIZE*anime, 128+field.CHAR_SIZE*3, field.CHAR_SIZE, field.CHAR_SIZE) 468 | return 469 | } 470 | draw.Draw(screen, "ino", vx, vy, field.CHAR_SIZE*anime, 128+field.CHAR_SIZE, field.CHAR_SIZE, field.CHAR_SIZE) 471 | return 472 | } 473 | } 474 | 475 | func (p *Player) drawLife(screen *ebiten.Image, game *Game) { 476 | for t := 0; t < game.gameData.lifeMax; t++ { 477 | if p.life < LIFE_RATIO*2 && p.timer%10 < 5 && game.gameData.lifeMax > 1 { 478 | continue 479 | } 480 | if p.life >= (t+1)*LIFE_RATIO { 481 | draw.Draw(screen, "ino", 482 | field.CHAR_SIZE*t, 0, field.CHAR_SIZE*3, 128+field.CHAR_SIZE*1, field.CHAR_SIZE, field.CHAR_SIZE) 483 | continue 484 | } 485 | draw.Draw(screen, "ino", 486 | field.CHAR_SIZE*t, 0, field.CHAR_SIZE*4, 128+field.CHAR_SIZE*1, field.CHAR_SIZE, field.CHAR_SIZE) 487 | } 488 | } 489 | 490 | func (p *Player) drawItems(screen *ebiten.Image, game *Game) { 491 | for t := fieldtype.FIELD_ITEM_FUJI; t < fieldtype.FIELD_ITEM_MAX; t++ { 492 | if !game.gameData.itemGetFlags[t] { 493 | draw.Draw(screen, "ino", 494 | draw.ScreenWidth-field.CHAR_SIZE/4*(int(fieldtype.FIELD_ITEM_MAX)-2-int(t)), 0, // 無 495 | field.CHAR_SIZE*5, 128+field.CHAR_SIZE, field.CHAR_SIZE/4, field.CHAR_SIZE/2) 496 | continue 497 | } 498 | // クリア条件アイテムは専用グラフィック 499 | if IsItemForClear(t) { 500 | for i, c := range clearFlagItems { 501 | if c != t { 502 | continue 503 | } 504 | draw.Draw(screen, "ino", 505 | draw.ScreenWidth-field.CHAR_SIZE/4*(int(fieldtype.FIELD_ITEM_MAX)-2-int(t)), 0, 506 | field.CHAR_SIZE*5+field.CHAR_SIZE/4*(i+2), 128+field.CHAR_SIZE, field.CHAR_SIZE/4, field.CHAR_SIZE/2) 507 | } 508 | continue 509 | } 510 | draw.Draw(screen, "ino", 511 | draw.ScreenWidth-field.CHAR_SIZE/4*(int(fieldtype.FIELD_ITEM_MAX)-2-int(t)), 0, // 有 512 | field.CHAR_SIZE*5+field.CHAR_SIZE/4, 128+field.CHAR_SIZE, field.CHAR_SIZE/4, field.CHAR_SIZE/2) 513 | } 514 | } 515 | 516 | func (p *Player) drawMessage(screen *ebiten.Image, game *Game) { 517 | switch p.state { 518 | case PLAYERSTATE_ITEMGET: 519 | t := WAIT_TIMER_INTERVAL - p.waitTimer 520 | draw.DrawItemMessage(screen, p.itemGet, (draw.ScreenHeight-96)/2+24-t*t, game.lang) 521 | draw.DrawItemFrame(screen, (draw.ScreenWidth-32)/2, (draw.ScreenHeight-96)/2-t*t-24) 522 | it := int(p.itemGet) - (int(fieldtype.FIELD_ITEM_BORDER) + 1) 523 | draw.Draw(screen, "ino", (draw.ScreenWidth-16)/2, (draw.ScreenHeight-96)/2-int(t)*int(t)-16, 524 | (it%16)*field.CHAR_SIZE, (it/16+4)*field.CHAR_SIZE, field.CHAR_SIZE, field.CHAR_SIZE) 525 | case PLAYERSTATE_START: 526 | key := "msg_" + game.lang.String() 527 | draw.Draw(screen, key, (draw.ScreenWidth-256)/2, 64+(draw.ScreenHeight-240)/2, 0, 96, 256, 32) 528 | case PLAYERSTATE_DEAD: 529 | key := "msg_" + game.lang.String() 530 | draw.Draw(screen, key, (draw.ScreenWidth-256)/2, 64+(draw.ScreenHeight-240)/2, 0, 128, 256, 32) 531 | } 532 | } 533 | 534 | func (p *Player) Draw(screen *ebiten.Image, game *Game) { 535 | po := p.view.GetPosition() 536 | p.field.Draw(screen, game.gameData, int(po.X), int(po.Y)) 537 | p.drawPlayer(screen, game) 538 | p.drawLife(screen, game) 539 | p.drawItems(screen, game) 540 | p.drawMessage(screen, game) 541 | } 542 | -------------------------------------------------------------------------------- /ino/view.go: -------------------------------------------------------------------------------- 1 | package ino 2 | 3 | import ( 4 | "github.com/hajimehoshi/go-inovation/ino/internal/draw" 5 | "github.com/hajimehoshi/go-inovation/ino/internal/input" 6 | ) 7 | 8 | type PositionF struct { 9 | X float64 10 | Y float64 11 | } 12 | 13 | type View struct { 14 | position PositionF 15 | } 16 | 17 | func NewView(position PositionF) *View { 18 | return &View{ 19 | position: position, 20 | } 21 | } 22 | 23 | func (v *View) ToScreenPosition(p PositionF) PositionF { 24 | x := p.X - v.GetPosition().X + draw.ScreenWidth/2 25 | y := p.Y - v.GetPosition().Y + draw.ScreenHeight/2 26 | return PositionF{x, y} 27 | } 28 | 29 | func (v *View) GetPosition() PositionF { 30 | p := v.position 31 | if input.Current().IsTouchEnabled() { 32 | p.Y += 16 33 | } 34 | return p 35 | } 36 | 37 | func (v *View) Update(position, speed PositionF) { 38 | const VIEW_DIRECTION_OFFSET = 30.0 39 | v.position.X = v.position.X*0.95 + (position.X+speed.X*VIEW_DIRECTION_OFFSET)*0.05 40 | v.position.Y = v.position.Y*0.95 + position.Y*0.05 41 | } 42 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "os" 7 | "runtime/pprof" 8 | "runtime/trace" 9 | 10 | "github.com/hajimehoshi/ebiten/v2" 11 | "github.com/hajimehoshi/go-inovation/ino" 12 | ) 13 | 14 | var ( 15 | memProfile = flag.String("memprofile", "", "write memory profile to file") 16 | traceOut = flag.String("trace", "", "write trace to file") 17 | transparent = flag.Bool("transparent", false, "background transparency") 18 | ) 19 | 20 | func main() { 21 | flag.Parse() 22 | 23 | if *traceOut != "" { 24 | f, err := os.Create(*traceOut) 25 | if err != nil { 26 | panic(err) 27 | } 28 | defer f.Close() 29 | 30 | trace.Start(f) 31 | defer trace.Stop() 32 | } 33 | 34 | game, err := ino.NewGame() 35 | if err != nil { 36 | panic(err) 37 | } 38 | 39 | if *transparent { 40 | ebiten.SetScreenTransparent(true) 41 | ebiten.SetWindowDecorated(false) 42 | game.SetTransparent() 43 | } 44 | 45 | const scale = 2 46 | ebiten.SetWindowSize(ino.ScreenWidth*scale, ino.ScreenHeight*scale) 47 | ebiten.SetWindowResizable(true) 48 | if err := ebiten.RunGame(game); err != nil { 49 | panic(err) 50 | } 51 | if *memProfile != "" { 52 | f, err := os.Create(*memProfile) 53 | if err != nil { 54 | panic(err) 55 | } 56 | defer f.Close() 57 | if err := pprof.WriteHeapProfile(f); err != nil { 58 | panic(fmt.Sprintf("could not write memory profile: %s", err)) 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /mobile/android/.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | *.apk 3 | *.ap_ 4 | *.aab 5 | 6 | # Files for the ART/Dalvik VM 7 | *.dex 8 | 9 | # Java class files 10 | *.class 11 | 12 | # Generated files 13 | bin/ 14 | gen/ 15 | out/ 16 | 17 | # Gradle files 18 | .gradle/ 19 | build/ 20 | 21 | # Local configuration file (sdk path, etc) 22 | local.properties 23 | 24 | # Proguard folder generated by Eclipse 25 | proguard/ 26 | 27 | # Log Files 28 | *.log 29 | 30 | # Android Studio Navigation editor temp files 31 | .navigation/ 32 | 33 | # Android Studio captures folder 34 | captures/ 35 | 36 | # IntelliJ 37 | *.iml 38 | .idea/workspace.xml 39 | .idea/tasks.xml 40 | .idea/gradle.xml 41 | .idea/assetWizardSettings.xml 42 | .idea/dictionaries 43 | .idea/libraries 44 | .idea/caches 45 | 46 | # Keystore files 47 | # Uncomment the following lines if you do not want to check your keystore files in. 48 | #*.jks 49 | #*.keystore 50 | 51 | # External native build folder generated in Android Studio 2.2 and later 52 | .externalNativeBuild 53 | 54 | # Google Services (e.g. APIs or Firebase) 55 | google-services.json 56 | 57 | # Freeline 58 | freeline.py 59 | freeline/ 60 | freeline_project_description.json 61 | 62 | # fastlane 63 | fastlane/report.xml 64 | fastlane/Preview.html 65 | fastlane/screenshots 66 | fastlane/test_output 67 | fastlane/readme.md 68 | -------------------------------------------------------------------------------- /mobile/android/app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /mobile/android/app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdk 34 5 | defaultConfig { 6 | applicationId "com.hajimehoshi.goinovation" 7 | minSdkVersion 23 8 | targetSdkVersion 34 9 | versionCode 8 10 | versionName '1.0.7' 11 | } 12 | buildTypes { 13 | release { 14 | minifyEnabled false 15 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 16 | } 17 | } 18 | productFlavors { 19 | } 20 | namespace 'com.hajimehoshi.goinovation' 21 | } 22 | 23 | dependencies { 24 | implementation fileTree(include: ['*.jar'], dir: 'libs') 25 | implementation 'androidx.appcompat:appcompat:1.7.0' 26 | implementation project(':inovation') 27 | 28 | // This line is needed to resolve a mysterious compilation error. 29 | // https://stackoverflow.com/questions/75263047/duplicate-class-in-kotlin-android 30 | implementation platform("org.jetbrains.kotlin:kotlin-bom:1.8.0") 31 | } 32 | -------------------------------------------------------------------------------- /mobile/android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/hajimehoshi/Library/Android/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /mobile/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /mobile/android/app/src/main/java/com/hajimehoshi/goinovation/EbitenViewWithErrorHandling.java: -------------------------------------------------------------------------------- 1 | package com.hajimehoshi.goinovation; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | 6 | import com.hajimehoshi.goinovation.mobile.EbitenView; 7 | 8 | class EbitenViewWithErrorHandling extends EbitenView { 9 | public EbitenViewWithErrorHandling(Context context) { 10 | super(context); 11 | } 12 | 13 | public EbitenViewWithErrorHandling(Context context, AttributeSet attributeSet) { 14 | super(context, attributeSet); 15 | } 16 | 17 | @Override 18 | protected void onErrorOnGameUpdate(Exception e) { 19 | // You can define your own error handling e.g., using Crashlytics. 20 | // e.g., Crashlytics.logException(e); 21 | super.onErrorOnGameUpdate(e); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /mobile/android/app/src/main/java/com/hajimehoshi/goinovation/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.hajimehoshi.goinovation; 2 | 3 | import androidx.appcompat.app.AppCompatActivity; 4 | 5 | import android.os.Bundle; 6 | 7 | import go.Seq; 8 | 9 | import com.hajimehoshi.goinovation.mobile.EbitenView; 10 | 11 | public class MainActivity extends AppCompatActivity { 12 | 13 | @Override 14 | protected void onCreate(Bundle savedInstanceState) { 15 | super.onCreate(savedInstanceState); 16 | setContentView(R.layout.activity_main); 17 | Seq.setContext(getApplicationContext()); 18 | } 19 | 20 | private EbitenView getEbitenView() { 21 | return (EbitenView)this.findViewById(R.id.ebitenview); 22 | } 23 | 24 | @Override 25 | protected void onPause() { 26 | super.onPause(); 27 | this.getEbitenView().suspendGame(); 28 | } 29 | 30 | @Override 31 | protected void onResume() { 32 | super.onResume(); 33 | this.getEbitenView().resumeGame(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /mobile/android/app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 15 | 16 | -------------------------------------------------------------------------------- /mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hajimehoshi/go-inovation/20ee4c8e276f04cf0ba715aa938f6afa10e334d9/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hajimehoshi/go-inovation/20ee4c8e276f04cf0ba715aa938f6afa10e334d9/mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hajimehoshi/go-inovation/20ee4c8e276f04cf0ba715aa938f6afa10e334d9/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hajimehoshi/go-inovation/20ee4c8e276f04cf0ba715aa938f6afa10e334d9/mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hajimehoshi/go-inovation/20ee4c8e276f04cf0ba715aa938f6afa10e334d9/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /mobile/android/app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /mobile/android/app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | 7 | -------------------------------------------------------------------------------- /mobile/android/app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 6 | -------------------------------------------------------------------------------- /mobile/android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | いのべーしょん 3 | 4 | -------------------------------------------------------------------------------- /mobile/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /mobile/android/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | mavenCentral() 6 | google() 7 | } 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:8.2.2' 10 | 11 | // NOTE: Do not place your application dependencies here; they belong 12 | // in the individual module build.gradle files 13 | } 14 | } 15 | 16 | allprojects { 17 | repositories { 18 | mavenCentral() 19 | google() 20 | } 21 | } 22 | 23 | tasks.register('clean', Delete) { 24 | delete rootProject.buildDir 25 | } 26 | -------------------------------------------------------------------------------- /mobile/android/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true 19 | android.enableJetifier=true 20 | android.nonFinalResIds=false 21 | android.nonTransitiveRClass=false 22 | android.useAndroidX=true -------------------------------------------------------------------------------- /mobile/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /mobile/android/gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | # 21 | # Gradle start up script for POSIX generated by Gradle. 22 | # 23 | # Important for running: 24 | # 25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 26 | # noncompliant, but you have some other compliant shell such as ksh or 27 | # bash, then to run this script, type that shell name before the whole 28 | # command line, like: 29 | # 30 | # ksh Gradle 31 | # 32 | # Busybox and similar reduced shells will NOT work, because this script 33 | # requires all of these POSIX shell features: 34 | # * functions; 35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 37 | # * compound commands having a testable exit status, especially «case»; 38 | # * various built-in commands including «command», «set», and «ulimit». 39 | # 40 | # Important for patching: 41 | # 42 | # (2) This script targets any POSIX shell, so it avoids extensions provided 43 | # by Bash, Ksh, etc; in particular arrays are avoided. 44 | # 45 | # The "traditional" practice of packing multiple parameters into a 46 | # space-separated string is a well documented source of bugs and security 47 | # problems, so this is (mostly) avoided, by progressively accumulating 48 | # options in "$@", and eventually passing that to Java. 49 | # 50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 52 | # see the in-line comments for details. 53 | # 54 | # There are tweaks for specific operating systems such as AIX, CygWin, 55 | # Darwin, MinGW, and NonStop. 56 | # 57 | # (3) This script is generated from the Groovy template 58 | # https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 59 | # within the Gradle project. 60 | # 61 | # You can find Gradle at https://github.com/gradle/gradle/. 62 | # 63 | ############################################################################## 64 | 65 | # Attempt to set APP_HOME 66 | 67 | # Resolve links: $0 may be a link 68 | app_path=$0 69 | 70 | # Need this for daisy-chained symlinks. 71 | while 72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 73 | [ -h "$app_path" ] 74 | do 75 | ls=$( ls -ld "$app_path" ) 76 | link=${ls#*' -> '} 77 | case $link in #( 78 | /*) app_path=$link ;; #( 79 | *) app_path=$APP_HOME$link ;; 80 | esac 81 | done 82 | 83 | APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit 84 | 85 | APP_NAME="Gradle" 86 | APP_BASE_NAME=${0##*/} 87 | 88 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 89 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 90 | 91 | # Use the maximum available, or set MAX_FD != -1 to use that value. 92 | MAX_FD=maximum 93 | 94 | warn () { 95 | echo "$*" 96 | } >&2 97 | 98 | die () { 99 | echo 100 | echo "$*" 101 | echo 102 | exit 1 103 | } >&2 104 | 105 | # OS specific support (must be 'true' or 'false'). 106 | cygwin=false 107 | msys=false 108 | darwin=false 109 | nonstop=false 110 | case "$( uname )" in #( 111 | CYGWIN* ) cygwin=true ;; #( 112 | Darwin* ) darwin=true ;; #( 113 | MSYS* | MINGW* ) msys=true ;; #( 114 | NONSTOP* ) nonstop=true ;; 115 | esac 116 | 117 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 118 | 119 | 120 | # Determine the Java command to use to start the JVM. 121 | if [ -n "$JAVA_HOME" ] ; then 122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 123 | # IBM's JDK on AIX uses strange locations for the executables 124 | JAVACMD=$JAVA_HOME/jre/sh/java 125 | else 126 | JAVACMD=$JAVA_HOME/bin/java 127 | fi 128 | if [ ! -x "$JAVACMD" ] ; then 129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 130 | 131 | Please set the JAVA_HOME variable in your environment to match the 132 | location of your Java installation." 133 | fi 134 | else 135 | JAVACMD=java 136 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 137 | 138 | Please set the JAVA_HOME variable in your environment to match the 139 | location of your Java installation." 140 | fi 141 | 142 | # Increase the maximum file descriptors if we can. 143 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 144 | case $MAX_FD in #( 145 | max*) 146 | MAX_FD=$( ulimit -H -n ) || 147 | warn "Could not query maximum file descriptor limit" 148 | esac 149 | case $MAX_FD in #( 150 | '' | soft) :;; #( 151 | *) 152 | ulimit -n "$MAX_FD" || 153 | warn "Could not set maximum file descriptor limit to $MAX_FD" 154 | esac 155 | fi 156 | 157 | # Collect all arguments for the java command, stacking in reverse order: 158 | # * args from the command line 159 | # * the main class name 160 | # * -classpath 161 | # * -D...appname settings 162 | # * --module-path (only if needed) 163 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 164 | 165 | # For Cygwin or MSYS, switch paths to Windows format before running java 166 | if "$cygwin" || "$msys" ; then 167 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 168 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 169 | 170 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 171 | 172 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 173 | for arg do 174 | if 175 | case $arg in #( 176 | -*) false ;; # don't mess with options #( 177 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 178 | [ -e "$t" ] ;; #( 179 | *) false ;; 180 | esac 181 | then 182 | arg=$( cygpath --path --ignore --mixed "$arg" ) 183 | fi 184 | # Roll the args list around exactly as many times as the number of 185 | # args, so each arg winds up back in the position where it started, but 186 | # possibly modified. 187 | # 188 | # NB: a `for` loop captures its iteration list before it begins, so 189 | # changing the positional parameters here affects neither the number of 190 | # iterations, nor the values presented in `arg`. 191 | shift # remove old arg 192 | set -- "$@" "$arg" # push replacement arg 193 | done 194 | fi 195 | 196 | # Collect all arguments for the java command; 197 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of 198 | # shell script including quotes and variable substitutions, so put them in 199 | # double quotes to make sure that they get re-expanded; and 200 | # * put everything else in single quotes, so that it's not re-expanded. 201 | 202 | set -- \ 203 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 204 | -classpath "$CLASSPATH" \ 205 | org.gradle.wrapper.GradleWrapperMain \ 206 | "$@" 207 | 208 | # Use "xargs" to parse quoted args. 209 | # 210 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 211 | # 212 | # In Bash we could simply go: 213 | # 214 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 215 | # set -- "${ARGS[@]}" "$@" 216 | # 217 | # but POSIX shell has neither arrays nor command substitution, so instead we 218 | # post-process each arg (as a line of input to sed) to backslash-escape any 219 | # character that might be a shell metacharacter, then use eval to reverse 220 | # that process (while maintaining the separation between arguments), and wrap 221 | # the whole thing up as a single "set" statement. 222 | # 223 | # This will of course break if any of these variables contains a newline or 224 | # an unmatched quote. 225 | # 226 | 227 | eval "set -- $( 228 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 229 | xargs -n1 | 230 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 231 | tr '\n' ' ' 232 | )" '"$@"' 233 | 234 | exec "$JAVACMD" "$@" 235 | -------------------------------------------------------------------------------- /mobile/android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /mobile/android/inovation/build.gradle: -------------------------------------------------------------------------------- 1 | configurations.maybeCreate("default") 2 | artifacts.add("default", file('inovation.aar')) 3 | -------------------------------------------------------------------------------- /mobile/android/mobile/build.gradle: -------------------------------------------------------------------------------- 1 | configurations.maybeCreate("default") 2 | artifacts.add("default", file('mobile.aar')) -------------------------------------------------------------------------------- /mobile/android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app', ':inovation' 2 | -------------------------------------------------------------------------------- /mobile/ios/.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | 20 | ## Other 21 | *.moved-aside 22 | *.xccheckout 23 | *.xcscmblueprint 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | *.ipa 28 | *.dSYM.zip 29 | *.dSYM 30 | 31 | # CocoaPods 32 | # 33 | # We recommend against adding the Pods directory to your .gitignore. However 34 | # you should judge for yourself, the pros and cons are mentioned at: 35 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 36 | # 37 | # Pods/ 38 | # 39 | # Add this line if you want to avoid checking in source code from the Xcode workspace 40 | *.xcworkspace 41 | 42 | # Carthage 43 | # 44 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 45 | # Carthage/Checkouts 46 | 47 | Carthage/Build 48 | 49 | # fastlane 50 | # 51 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 52 | # screenshots whenever they are needed. 53 | # For more information about the recommended setup visit: 54 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 55 | 56 | fastlane/report.xml 57 | fastlane/Preview.html 58 | fastlane/screenshots/**/*.png 59 | fastlane/test_output 60 | 61 | # Code Injection 62 | # 63 | # After new code Injection tools there's a generated folder /iOSInjectionProject 64 | # https://github.com/johnno1962/injectionforxcode 65 | 66 | iOSInjectionProject/ 67 | -------------------------------------------------------------------------------- /mobile/ios/goinovation.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 52; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 8C050D3F1D16B7E500F865C4 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8C050D3D1D16B7E500F865C4 /* LaunchScreen.storyboard */; }; 11 | 8C319FA3232D60A90051792B /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8C319FA2232D60A80051792B /* AudioToolbox.framework */; }; 12 | 8C341D9E22E3140400B5C749 /* OpenGLES.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8C341D9D22E3140400B5C749 /* OpenGLES.framework */; }; 13 | 8C341DA022E3141600B5C749 /* GLKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8C341D9922E313CD00B5C749 /* GLKit.framework */; }; 14 | 8C4C3321271B334200CB6E83 /* GameController.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8C4C3320271B334200CB6E83 /* GameController.framework */; }; 15 | 8C7185BE1D11C56C00F98056 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C7185BD1D11C56C00F98056 /* main.m */; }; 16 | 8C7185C11D11C56C00F98056 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C7185C01D11C56C00F98056 /* AppDelegate.m */; }; 17 | 8C7185C71D11C56C00F98056 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8C7185C51D11C56C00F98056 /* Main.storyboard */; settings = {ASSET_TAGS = (1, ); }; }; 18 | 8C7185C91D11C56C00F98056 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 8C7185C81D11C56C00F98056 /* Assets.xcassets */; }; 19 | 8CB110C1230972630064D8CE /* MobileEbitenViewControllerWithErrorHandling.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CB110C0230972630064D8CE /* MobileEbitenViewControllerWithErrorHandling.m */; }; 20 | 8CCA2ADB2784D87000F93EF7 /* Mobile.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8CCA2AD72784D18900F93EF7 /* Mobile.xcframework */; }; 21 | 8CCAFF0B22E3133E00FAEDC1 /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8CCAFF0A22E3133E00FAEDC1 /* AVFoundation.framework */; }; 22 | /* End PBXBuildFile section */ 23 | 24 | /* Begin PBXFileReference section */ 25 | 8C050D3E1D16B7E500F865C4 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = goinovation/Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 26 | 8C319FA2232D60A80051792B /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; }; 27 | 8C341D9922E313CD00B5C749 /* GLKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GLKit.framework; path = System/Library/Frameworks/GLKit.framework; sourceTree = SDKROOT; }; 28 | 8C341D9D22E3140400B5C749 /* OpenGLES.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGLES.framework; path = System/Library/Frameworks/OpenGLES.framework; sourceTree = SDKROOT; }; 29 | 8C4C3320271B334200CB6E83 /* GameController.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GameController.framework; path = System/Library/Frameworks/GameController.framework; sourceTree = SDKROOT; }; 30 | 8C7185B91D11C56C00F98056 /* goinovation.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = goinovation.app; sourceTree = BUILT_PRODUCTS_DIR; }; 31 | 8C7185BD1D11C56C00F98056 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 32 | 8C7185BF1D11C56C00F98056 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 33 | 8C7185C01D11C56C00F98056 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 34 | 8C7185C61D11C56C00F98056 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 35 | 8C7185C81D11C56C00F98056 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 36 | 8C7185CD1D11C56C00F98056 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 37 | 8CB110C0230972630064D8CE /* MobileEbitenViewControllerWithErrorHandling.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MobileEbitenViewControllerWithErrorHandling.m; sourceTree = ""; }; 38 | 8CB110C22309728C0064D8CE /* MobileEbitenViewControllerWithErrorHandling.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MobileEbitenViewControllerWithErrorHandling.h; sourceTree = ""; }; 39 | 8CCA2AD72784D18900F93EF7 /* Mobile.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = Mobile.xcframework; sourceTree = ""; }; 40 | 8CCAFF0A22E3133E00FAEDC1 /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; }; 41 | /* End PBXFileReference section */ 42 | 43 | /* Begin PBXFrameworksBuildPhase section */ 44 | 8C7185B61D11C56C00F98056 /* Frameworks */ = { 45 | isa = PBXFrameworksBuildPhase; 46 | buildActionMask = 2147483647; 47 | files = ( 48 | 8C319FA3232D60A90051792B /* AudioToolbox.framework in Frameworks */, 49 | 8C341DA022E3141600B5C749 /* GLKit.framework in Frameworks */, 50 | 8C4C3321271B334200CB6E83 /* GameController.framework in Frameworks */, 51 | 8C341D9E22E3140400B5C749 /* OpenGLES.framework in Frameworks */, 52 | 8CCAFF0B22E3133E00FAEDC1 /* AVFoundation.framework in Frameworks */, 53 | 8CCA2ADB2784D87000F93EF7 /* Mobile.xcframework in Frameworks */, 54 | ); 55 | runOnlyForDeploymentPostprocessing = 0; 56 | }; 57 | /* End PBXFrameworksBuildPhase section */ 58 | 59 | /* Begin PBXGroup section */ 60 | 8C7185B01D11C56C00F98056 = { 61 | isa = PBXGroup; 62 | children = ( 63 | 8C7185BB1D11C56C00F98056 /* goinovation */, 64 | 8C7185BA1D11C56C00F98056 /* Products */, 65 | 8CCAFF0922E3133E00FAEDC1 /* Frameworks */, 66 | ); 67 | sourceTree = ""; 68 | }; 69 | 8C7185BA1D11C56C00F98056 /* Products */ = { 70 | isa = PBXGroup; 71 | children = ( 72 | 8C7185B91D11C56C00F98056 /* goinovation.app */, 73 | ); 74 | name = Products; 75 | sourceTree = ""; 76 | }; 77 | 8C7185BB1D11C56C00F98056 /* goinovation */ = { 78 | isa = PBXGroup; 79 | children = ( 80 | 8C7185BF1D11C56C00F98056 /* AppDelegate.h */, 81 | 8C7185C01D11C56C00F98056 /* AppDelegate.m */, 82 | 8CB110C22309728C0064D8CE /* MobileEbitenViewControllerWithErrorHandling.h */, 83 | 8CB110C0230972630064D8CE /* MobileEbitenViewControllerWithErrorHandling.m */, 84 | 8C7185C51D11C56C00F98056 /* Main.storyboard */, 85 | 8C050D3D1D16B7E500F865C4 /* LaunchScreen.storyboard */, 86 | 8C7185C81D11C56C00F98056 /* Assets.xcassets */, 87 | 8C7185CD1D11C56C00F98056 /* Info.plist */, 88 | 8C7185BC1D11C56C00F98056 /* Supporting Files */, 89 | ); 90 | path = goinovation; 91 | sourceTree = ""; 92 | }; 93 | 8C7185BC1D11C56C00F98056 /* Supporting Files */ = { 94 | isa = PBXGroup; 95 | children = ( 96 | 8C7185BD1D11C56C00F98056 /* main.m */, 97 | ); 98 | name = "Supporting Files"; 99 | sourceTree = ""; 100 | }; 101 | 8CCAFF0922E3133E00FAEDC1 /* Frameworks */ = { 102 | isa = PBXGroup; 103 | children = ( 104 | 8CCA2AD72784D18900F93EF7 /* Mobile.xcframework */, 105 | 8C4C3320271B334200CB6E83 /* GameController.framework */, 106 | 8C319FA2232D60A80051792B /* AudioToolbox.framework */, 107 | 8C341D9D22E3140400B5C749 /* OpenGLES.framework */, 108 | 8C341D9922E313CD00B5C749 /* GLKit.framework */, 109 | 8CCAFF0A22E3133E00FAEDC1 /* AVFoundation.framework */, 110 | ); 111 | name = Frameworks; 112 | sourceTree = ""; 113 | }; 114 | /* End PBXGroup section */ 115 | 116 | /* Begin PBXNativeTarget section */ 117 | 8C7185B81D11C56C00F98056 /* goinovation */ = { 118 | isa = PBXNativeTarget; 119 | buildConfigurationList = 8C7185D01D11C56C00F98056 /* Build configuration list for PBXNativeTarget "goinovation" */; 120 | buildPhases = ( 121 | 8C7185B51D11C56C00F98056 /* Sources */, 122 | 8C7185B61D11C56C00F98056 /* Frameworks */, 123 | 8C7185B71D11C56C00F98056 /* Resources */, 124 | ); 125 | buildRules = ( 126 | ); 127 | dependencies = ( 128 | ); 129 | name = goinovation; 130 | productName = goinovation; 131 | productReference = 8C7185B91D11C56C00F98056 /* goinovation.app */; 132 | productType = "com.apple.product-type.application"; 133 | }; 134 | /* End PBXNativeTarget section */ 135 | 136 | /* Begin PBXProject section */ 137 | 8C7185B11D11C56C00F98056 /* Project object */ = { 138 | isa = PBXProject; 139 | attributes = { 140 | KnownAssetTags = ( 141 | 1, 142 | ); 143 | LastUpgradeCheck = 1320; 144 | ORGANIZATIONNAME = "Hajime Hoshi"; 145 | TargetAttributes = { 146 | 8C7185B81D11C56C00F98056 = { 147 | CreatedOnToolsVersion = 7.3.1; 148 | DevelopmentTeam = M89F6KFPW7; 149 | ProvisioningStyle = Automatic; 150 | }; 151 | }; 152 | }; 153 | buildConfigurationList = 8C7185B41D11C56C00F98056 /* Build configuration list for PBXProject "goinovation" */; 154 | compatibilityVersion = "Xcode 3.2"; 155 | developmentRegion = English; 156 | hasScannedForEncodings = 0; 157 | knownRegions = ( 158 | English, 159 | en, 160 | Base, 161 | ); 162 | mainGroup = 8C7185B01D11C56C00F98056; 163 | productRefGroup = 8C7185BA1D11C56C00F98056 /* Products */; 164 | projectDirPath = ""; 165 | projectRoot = ""; 166 | targets = ( 167 | 8C7185B81D11C56C00F98056 /* goinovation */, 168 | ); 169 | }; 170 | /* End PBXProject section */ 171 | 172 | /* Begin PBXResourcesBuildPhase section */ 173 | 8C7185B71D11C56C00F98056 /* Resources */ = { 174 | isa = PBXResourcesBuildPhase; 175 | buildActionMask = 2147483647; 176 | files = ( 177 | 8C050D3F1D16B7E500F865C4 /* LaunchScreen.storyboard in Resources */, 178 | 8C7185C91D11C56C00F98056 /* Assets.xcassets in Resources */, 179 | 8C7185C71D11C56C00F98056 /* Main.storyboard in Resources */, 180 | ); 181 | runOnlyForDeploymentPostprocessing = 0; 182 | }; 183 | /* End PBXResourcesBuildPhase section */ 184 | 185 | /* Begin PBXSourcesBuildPhase section */ 186 | 8C7185B51D11C56C00F98056 /* Sources */ = { 187 | isa = PBXSourcesBuildPhase; 188 | buildActionMask = 2147483647; 189 | files = ( 190 | 8CB110C1230972630064D8CE /* MobileEbitenViewControllerWithErrorHandling.m in Sources */, 191 | 8C7185C11D11C56C00F98056 /* AppDelegate.m in Sources */, 192 | 8C7185BE1D11C56C00F98056 /* main.m in Sources */, 193 | ); 194 | runOnlyForDeploymentPostprocessing = 0; 195 | }; 196 | /* End PBXSourcesBuildPhase section */ 197 | 198 | /* Begin PBXVariantGroup section */ 199 | 8C050D3D1D16B7E500F865C4 /* LaunchScreen.storyboard */ = { 200 | isa = PBXVariantGroup; 201 | children = ( 202 | 8C050D3E1D16B7E500F865C4 /* Base */, 203 | ); 204 | name = LaunchScreen.storyboard; 205 | path = ..; 206 | sourceTree = ""; 207 | }; 208 | 8C7185C51D11C56C00F98056 /* Main.storyboard */ = { 209 | isa = PBXVariantGroup; 210 | children = ( 211 | 8C7185C61D11C56C00F98056 /* Base */, 212 | ); 213 | name = Main.storyboard; 214 | sourceTree = ""; 215 | }; 216 | /* End PBXVariantGroup section */ 217 | 218 | /* Begin XCBuildConfiguration section */ 219 | 8C7185CE1D11C56C00F98056 /* Debug */ = { 220 | isa = XCBuildConfiguration; 221 | buildSettings = { 222 | ALWAYS_SEARCH_USER_PATHS = NO; 223 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 224 | CLANG_ANALYZER_NONNULL = YES; 225 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 226 | CLANG_CXX_LIBRARY = "libc++"; 227 | CLANG_ENABLE_MODULES = YES; 228 | CLANG_ENABLE_OBJC_ARC = YES; 229 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 230 | CLANG_WARN_BOOL_CONVERSION = YES; 231 | CLANG_WARN_COMMA = YES; 232 | CLANG_WARN_CONSTANT_CONVERSION = YES; 233 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 234 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 235 | CLANG_WARN_EMPTY_BODY = YES; 236 | CLANG_WARN_ENUM_CONVERSION = YES; 237 | CLANG_WARN_INFINITE_RECURSION = YES; 238 | CLANG_WARN_INT_CONVERSION = YES; 239 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 240 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 241 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 242 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 243 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 244 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 245 | CLANG_WARN_STRICT_PROTOTYPES = YES; 246 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 247 | CLANG_WARN_UNREACHABLE_CODE = YES; 248 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 249 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 250 | COPY_PHASE_STRIP = NO; 251 | DEBUG_INFORMATION_FORMAT = dwarf; 252 | ENABLE_STRICT_OBJC_MSGSEND = YES; 253 | ENABLE_TESTABILITY = YES; 254 | GCC_C_LANGUAGE_STANDARD = gnu99; 255 | GCC_DYNAMIC_NO_PIC = NO; 256 | GCC_NO_COMMON_BLOCKS = YES; 257 | GCC_OPTIMIZATION_LEVEL = 0; 258 | GCC_PREPROCESSOR_DEFINITIONS = ( 259 | "DEBUG=1", 260 | "$(inherited)", 261 | ); 262 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 263 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 264 | GCC_WARN_UNDECLARED_SELECTOR = YES; 265 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 266 | GCC_WARN_UNUSED_FUNCTION = YES; 267 | GCC_WARN_UNUSED_VARIABLE = YES; 268 | HEADER_SEARCH_PATHS = ""; 269 | IPHONEOS_DEPLOYMENT_TARGET = 12.0; 270 | MTL_ENABLE_DEBUG_INFO = YES; 271 | ONLY_ACTIVE_ARCH = YES; 272 | SDKROOT = iphoneos; 273 | }; 274 | name = Debug; 275 | }; 276 | 8C7185CF1D11C56C00F98056 /* Release */ = { 277 | isa = XCBuildConfiguration; 278 | buildSettings = { 279 | ALWAYS_SEARCH_USER_PATHS = NO; 280 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 281 | CLANG_ANALYZER_NONNULL = YES; 282 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 283 | CLANG_CXX_LIBRARY = "libc++"; 284 | CLANG_ENABLE_MODULES = YES; 285 | CLANG_ENABLE_OBJC_ARC = YES; 286 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 287 | CLANG_WARN_BOOL_CONVERSION = YES; 288 | CLANG_WARN_COMMA = YES; 289 | CLANG_WARN_CONSTANT_CONVERSION = YES; 290 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 291 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 292 | CLANG_WARN_EMPTY_BODY = YES; 293 | CLANG_WARN_ENUM_CONVERSION = YES; 294 | CLANG_WARN_INFINITE_RECURSION = YES; 295 | CLANG_WARN_INT_CONVERSION = YES; 296 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 297 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 298 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 299 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 300 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 301 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 302 | CLANG_WARN_STRICT_PROTOTYPES = YES; 303 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 304 | CLANG_WARN_UNREACHABLE_CODE = YES; 305 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 306 | CODE_SIGN_IDENTITY = "iPhone Distribution"; 307 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; 308 | COPY_PHASE_STRIP = NO; 309 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 310 | ENABLE_NS_ASSERTIONS = NO; 311 | ENABLE_STRICT_OBJC_MSGSEND = YES; 312 | GCC_C_LANGUAGE_STANDARD = gnu99; 313 | GCC_NO_COMMON_BLOCKS = YES; 314 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 315 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 316 | GCC_WARN_UNDECLARED_SELECTOR = YES; 317 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 318 | GCC_WARN_UNUSED_FUNCTION = YES; 319 | GCC_WARN_UNUSED_VARIABLE = YES; 320 | HEADER_SEARCH_PATHS = ""; 321 | IPHONEOS_DEPLOYMENT_TARGET = 12.0; 322 | MTL_ENABLE_DEBUG_INFO = NO; 323 | PROVISIONING_PROFILE = ""; 324 | SDKROOT = iphoneos; 325 | VALIDATE_PRODUCT = YES; 326 | }; 327 | name = Release; 328 | }; 329 | 8C7185D11D11C56C00F98056 /* Debug */ = { 330 | isa = XCBuildConfiguration; 331 | buildSettings = { 332 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 333 | CODE_SIGN_IDENTITY = "Apple Development"; 334 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 335 | CODE_SIGN_STYLE = Automatic; 336 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 337 | DEVELOPMENT_TEAM = M89F6KFPW7; 338 | ENABLE_BITCODE = NO; 339 | FRAMEWORK_SEARCH_PATHS = ( 340 | "$(inherited)", 341 | "$(PROJECT_DIR)", 342 | ); 343 | HEADER_SEARCH_PATHS = ""; 344 | INFOPLIST_FILE = goinovation/Info.plist; 345 | IPHONEOS_DEPLOYMENT_TARGET = 12.0; 346 | LD_RUNPATH_SEARCH_PATHS = ( 347 | "$(inherited)", 348 | "@executable_path/Frameworks", 349 | ); 350 | PRODUCT_BUNDLE_IDENTIFIER = com.hajimehoshi.goinovation; 351 | PRODUCT_NAME = "$(TARGET_NAME)"; 352 | PROVISIONING_PROFILE_SPECIFIER = ""; 353 | TARGETED_DEVICE_FAMILY = "1,2"; 354 | }; 355 | name = Debug; 356 | }; 357 | 8C7185D21D11C56C00F98056 /* Release */ = { 358 | isa = XCBuildConfiguration; 359 | buildSettings = { 360 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 361 | CODE_SIGN_IDENTITY = "iPhone Distribution: Hajime Hoshi (M89F6KFPW7)"; 362 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution: Hajime Hoshi (M89F6KFPW7)"; 363 | DEVELOPMENT_TEAM = M89F6KFPW7; 364 | ENABLE_BITCODE = NO; 365 | FRAMEWORK_SEARCH_PATHS = ( 366 | "$(inherited)", 367 | "$(PROJECT_DIR)", 368 | ); 369 | HEADER_SEARCH_PATHS = ""; 370 | INFOPLIST_FILE = goinovation/Info.plist; 371 | IPHONEOS_DEPLOYMENT_TARGET = 12.0; 372 | LD_RUNPATH_SEARCH_PATHS = ( 373 | "$(inherited)", 374 | "@executable_path/Frameworks", 375 | ); 376 | PRODUCT_BUNDLE_IDENTIFIER = com.hajimehoshi.goinovation; 377 | PRODUCT_NAME = "$(TARGET_NAME)"; 378 | PROVISIONING_PROFILE_SPECIFIER = "iOS Dev"; 379 | TARGETED_DEVICE_FAMILY = "1,2"; 380 | }; 381 | name = Release; 382 | }; 383 | /* End XCBuildConfiguration section */ 384 | 385 | /* Begin XCConfigurationList section */ 386 | 8C7185B41D11C56C00F98056 /* Build configuration list for PBXProject "goinovation" */ = { 387 | isa = XCConfigurationList; 388 | buildConfigurations = ( 389 | 8C7185CE1D11C56C00F98056 /* Debug */, 390 | 8C7185CF1D11C56C00F98056 /* Release */, 391 | ); 392 | defaultConfigurationIsVisible = 0; 393 | defaultConfigurationName = Release; 394 | }; 395 | 8C7185D01D11C56C00F98056 /* Build configuration list for PBXNativeTarget "goinovation" */ = { 396 | isa = XCConfigurationList; 397 | buildConfigurations = ( 398 | 8C7185D11D11C56C00F98056 /* Debug */, 399 | 8C7185D21D11C56C00F98056 /* Release */, 400 | ); 401 | defaultConfigurationIsVisible = 0; 402 | defaultConfigurationName = Release; 403 | }; 404 | /* End XCConfigurationList section */ 405 | }; 406 | rootObject = 8C7185B11D11C56C00F98056 /* Project object */; 407 | } 408 | -------------------------------------------------------------------------------- /mobile/ios/goinovation.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /mobile/ios/goinovation/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // goinovation 4 | // 5 | // Created by Hajime Hoshi on 6/16/16. 6 | // Copyright © 2016 Hajime Hoshi. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /mobile/ios/goinovation/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // goinovation 4 | // 5 | // Created by Hajime Hoshi on 6/16/16. 6 | // Copyright © 2016 Hajime Hoshi. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | #import "MobileEbitenViewControllerWithErrorHandling.h" 12 | 13 | @interface AppDelegate () 14 | 15 | @end 16 | 17 | @implementation AppDelegate 18 | 19 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 20 | // Override point for customization after application launch. 21 | return YES; 22 | } 23 | 24 | - (void)applicationWillResignActive:(UIApplication *)application { 25 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 26 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 27 | [[self ebitenViewContrller] suspendGame]; 28 | } 29 | 30 | - (void)applicationDidEnterBackground:(UIApplication *)application { 31 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 32 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 33 | } 34 | 35 | - (void)applicationWillEnterForeground:(UIApplication *)application { 36 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 37 | } 38 | 39 | - (void)applicationDidBecomeActive:(UIApplication *)application { 40 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 41 | [[self ebitenViewContrller] resumeGame]; 42 | } 43 | 44 | - (void)applicationWillTerminate:(UIApplication *)application { 45 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 46 | } 47 | 48 | - (MobileEbitenViewControllerWithErrorHandling*)ebitenViewContrller 49 | { 50 | return (MobileEbitenViewControllerWithErrorHandling*)([[self window] rootViewController]); 51 | } 52 | 53 | @end 54 | -------------------------------------------------------------------------------- /mobile/ios/goinovation/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "size" : "29x29", 15 | "idiom" : "iphone", 16 | "filename" : "icon58.png", 17 | "scale" : "2x" 18 | }, 19 | { 20 | "size" : "29x29", 21 | "idiom" : "iphone", 22 | "filename" : "icon87.png", 23 | "scale" : "3x" 24 | }, 25 | { 26 | "size" : "40x40", 27 | "idiom" : "iphone", 28 | "filename" : "icon80.png", 29 | "scale" : "2x" 30 | }, 31 | { 32 | "size" : "40x40", 33 | "idiom" : "iphone", 34 | "filename" : "icon120.png", 35 | "scale" : "3x" 36 | }, 37 | { 38 | "size" : "60x60", 39 | "idiom" : "iphone", 40 | "filename" : "icon120-1.png", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "size" : "60x60", 45 | "idiom" : "iphone", 46 | "filename" : "icon180.png", 47 | "scale" : "3x" 48 | }, 49 | { 50 | "size" : "1024x1024", 51 | "idiom" : "ios-marketing", 52 | "filename" : "icon1024.png", 53 | "scale" : "1x" 54 | } 55 | ], 56 | "info" : { 57 | "version" : 1, 58 | "author" : "xcode" 59 | } 60 | } -------------------------------------------------------------------------------- /mobile/ios/goinovation/Assets.xcassets/AppIcon.appiconset/icon1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hajimehoshi/go-inovation/20ee4c8e276f04cf0ba715aa938f6afa10e334d9/mobile/ios/goinovation/Assets.xcassets/AppIcon.appiconset/icon1024.png -------------------------------------------------------------------------------- /mobile/ios/goinovation/Assets.xcassets/AppIcon.appiconset/icon120-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hajimehoshi/go-inovation/20ee4c8e276f04cf0ba715aa938f6afa10e334d9/mobile/ios/goinovation/Assets.xcassets/AppIcon.appiconset/icon120-1.png -------------------------------------------------------------------------------- /mobile/ios/goinovation/Assets.xcassets/AppIcon.appiconset/icon120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hajimehoshi/go-inovation/20ee4c8e276f04cf0ba715aa938f6afa10e334d9/mobile/ios/goinovation/Assets.xcassets/AppIcon.appiconset/icon120.png -------------------------------------------------------------------------------- /mobile/ios/goinovation/Assets.xcassets/AppIcon.appiconset/icon180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hajimehoshi/go-inovation/20ee4c8e276f04cf0ba715aa938f6afa10e334d9/mobile/ios/goinovation/Assets.xcassets/AppIcon.appiconset/icon180.png -------------------------------------------------------------------------------- /mobile/ios/goinovation/Assets.xcassets/AppIcon.appiconset/icon58.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hajimehoshi/go-inovation/20ee4c8e276f04cf0ba715aa938f6afa10e334d9/mobile/ios/goinovation/Assets.xcassets/AppIcon.appiconset/icon58.png -------------------------------------------------------------------------------- /mobile/ios/goinovation/Assets.xcassets/AppIcon.appiconset/icon80.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hajimehoshi/go-inovation/20ee4c8e276f04cf0ba715aa938f6afa10e334d9/mobile/ios/goinovation/Assets.xcassets/AppIcon.appiconset/icon80.png -------------------------------------------------------------------------------- /mobile/ios/goinovation/Assets.xcassets/AppIcon.appiconset/icon87.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hajimehoshi/go-inovation/20ee4c8e276f04cf0ba715aa938f6afa10e334d9/mobile/ios/goinovation/Assets.xcassets/AppIcon.appiconset/icon87.png -------------------------------------------------------------------------------- /mobile/ios/goinovation/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 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 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /mobile/ios/goinovation/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /mobile/ios/goinovation/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | いのべーしょん 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0.5 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 6 25 | LSRequiresIPhoneOS 26 | 27 | UILaunchStoryboardName 28 | LaunchScreen 29 | UIMainStoryboardFile 30 | Main 31 | UIRequiredDeviceCapabilities 32 | 33 | armv7 34 | 35 | UISupportedInterfaceOrientations 36 | 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /mobile/ios/goinovation/MobileEbitenViewControllerWithErrorHandling.h: -------------------------------------------------------------------------------- 1 | // 2 | // MobileEbitenViewWithErrorHandling.h 3 | // goinovation 4 | // 5 | // Created by Hajime Hoshi on 2019/08/18. 6 | // Copyright © 2019 Hajime Hoshi. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface MobileEbitenViewControllerWithErrorHandling : MobileEbitenViewController 12 | @end 13 | -------------------------------------------------------------------------------- /mobile/ios/goinovation/MobileEbitenViewControllerWithErrorHandling.m: -------------------------------------------------------------------------------- 1 | // 2 | // MobileEbitenViewWithErrorHandling.m 3 | // goinovation 4 | // 5 | // Created by Hajime Hoshi on 2019/08/18. 6 | // Copyright © 2019 Hajime Hoshi. All rights reserved. 7 | // 8 | 9 | #import "MobileEbitenViewControllerWithErrorHandling.h" 10 | 11 | #import 12 | 13 | @implementation MobileEbitenViewControllerWithErrorHandling { 14 | } 15 | 16 | - (void)onErrorOnGameUpdate:(NSError*)err { 17 | // You can define your own error handling e.g., using Crashlytics. 18 | NSLog(@"Inovation Error!: %@", err); 19 | } 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /mobile/ios/goinovation/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // goinovation 4 | // 5 | // Created by Hajime Hoshi on 6/16/16. 6 | // Copyright © 2016 Hajime Hoshi. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /mobile/mobile.go: -------------------------------------------------------------------------------- 1 | package mobile 2 | 3 | import ( 4 | "github.com/hajimehoshi/ebiten/v2/mobile" 5 | 6 | "github.com/hajimehoshi/go-inovation/ino" 7 | ) 8 | 9 | func init() { 10 | inogame, err := ino.NewGame() 11 | if err != nil { 12 | panic(err) 13 | } 14 | mobile.SetGame(inogame) 15 | } 16 | 17 | // Dummy is a dummy exported function. 18 | // 19 | // gomobile doesn't compile a package that doesn't include any exported function. 20 | // Dummy forces gomobile to compile this package. 21 | func Dummy() {} 22 | -------------------------------------------------------------------------------- /notarize_app.sh: -------------------------------------------------------------------------------- 1 | set -e 2 | 3 | name=innovation2007 4 | app_name=Innovation2007.app 5 | bundle_id=com.hajimehoshi.innovation2007.macos 6 | email=hajimehoshi@gmail.com 7 | 8 | # Specify a 'Developer ID' (Developer ID Application) certificate. 9 | # See https://developer.apple.com/documentation/security/notarizing_macos_software_before_distribution/resolving_common_notarization_issues 10 | developer_name='Developer ID Application: Hajime Hoshi (M89F6KFPW7)' 11 | 12 | # To get the provider, run `xcrun altool --list-providers --username= --password=` and see the ProviderShortname. 13 | asc_provider=M89F6KFPW7 14 | 15 | # macOS: signing 16 | # See 17 | # * https://partner.steamgames.com/doc/store/application/platforms 18 | # * https://coldandold.com/posts/releasing-steam-game-on-mac/ 19 | 20 | cd bin 21 | mkdir -p .cache 22 | 23 | echo ' 24 | 25 | 26 | 27 | com.apple.security.cs.disable-library-validation 28 | 29 | com.apple.security.cs.allow-dyld-environment-variables 30 | 31 | 32 | ' > .cache/entitlements.plist 33 | 34 | codesign --display \ 35 | --verbose \ 36 | --verify \ 37 | --sign "${developer_name}" \ 38 | --timestamp \ 39 | --options runtime \ 40 | --force \ 41 | --entitlements .cache/entitlements.plist \ 42 | --deep \ 43 | ${app_name} 44 | 45 | ditto -c -k --keepParent ${app_name} ${app_name}.zip 46 | 47 | if [[ -z "${APP_PASSWORD}" ]]; then 48 | echo 'fail: set APP_PASSWORD. See https://support.apple.com/en-us/HT204397' 49 | exit 1 50 | fi 51 | 52 | xcrun altool --notarize-app \ 53 | --primary-bundle-id "${bundle_id}" \ 54 | --username "${email}" \ 55 | --password "${APP_PASSWORD}" \ 56 | --asc-provider "${asc_provider}" \ 57 | --file ${app_name}.zip 58 | rm ${app_name}.zip 59 | 60 | echo "Please wait for an email from Apple." 61 | echo "For the log, run this command: xcrun altool --notarization-info --username --password " 62 | echo "After the notarization succeeds, run this command: xcrun stapler staple bin/${app_name}" 63 | -------------------------------------------------------------------------------- /steam/community_capsule_184x69_english.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hajimehoshi/go-inovation/20ee4c8e276f04cf0ba715aa938f6afa10e334d9/steam/community_capsule_184x69_english.png -------------------------------------------------------------------------------- /steam/community_capsule_184x69_japanese.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hajimehoshi/go-inovation/20ee4c8e276f04cf0ba715aa938f6afa10e334d9/steam/community_capsule_184x69_japanese.png -------------------------------------------------------------------------------- /steam/icon/icon_128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hajimehoshi/go-inovation/20ee4c8e276f04cf0ba715aa938f6afa10e334d9/steam/icon/icon_128x128.png -------------------------------------------------------------------------------- /steam/icon/icon_16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hajimehoshi/go-inovation/20ee4c8e276f04cf0ba715aa938f6afa10e334d9/steam/icon/icon_16x16.png -------------------------------------------------------------------------------- /steam/icon/icon_256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hajimehoshi/go-inovation/20ee4c8e276f04cf0ba715aa938f6afa10e334d9/steam/icon/icon_256x256.png -------------------------------------------------------------------------------- /steam/icon/icon_32x32.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hajimehoshi/go-inovation/20ee4c8e276f04cf0ba715aa938f6afa10e334d9/steam/icon/icon_32x32.ico -------------------------------------------------------------------------------- /steam/icon/icon_32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hajimehoshi/go-inovation/20ee4c8e276f04cf0ba715aa938f6afa10e334d9/steam/icon/icon_32x32.png -------------------------------------------------------------------------------- /steam/icon/icon_512x512.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hajimehoshi/go-inovation/20ee4c8e276f04cf0ba715aa938f6afa10e334d9/steam/icon/icon_512x512.icns -------------------------------------------------------------------------------- /steam/icon/icon_512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hajimehoshi/go-inovation/20ee4c8e276f04cf0ba715aa938f6afa10e334d9/steam/icon/icon_512x512.png -------------------------------------------------------------------------------- /steam/icon/icon_64x64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hajimehoshi/go-inovation/20ee4c8e276f04cf0ba715aa938f6afa10e334d9/steam/icon/icon_64x64.png -------------------------------------------------------------------------------- /steam/library_capsule_600x900_english.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hajimehoshi/go-inovation/20ee4c8e276f04cf0ba715aa938f6afa10e334d9/steam/library_capsule_600x900_english.png -------------------------------------------------------------------------------- /steam/library_capsule_600x900_japanese.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hajimehoshi/go-inovation/20ee4c8e276f04cf0ba715aa938f6afa10e334d9/steam/library_capsule_600x900_japanese.png -------------------------------------------------------------------------------- /steam/library_hero_3840x1240_english.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hajimehoshi/go-inovation/20ee4c8e276f04cf0ba715aa938f6afa10e334d9/steam/library_hero_3840x1240_english.png -------------------------------------------------------------------------------- /steam/library_hero_3840x1240_japanese.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hajimehoshi/go-inovation/20ee4c8e276f04cf0ba715aa938f6afa10e334d9/steam/library_hero_3840x1240_japanese.png -------------------------------------------------------------------------------- /steam/library_logo_1280x720_english.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hajimehoshi/go-inovation/20ee4c8e276f04cf0ba715aa938f6afa10e334d9/steam/library_logo_1280x720_english.png -------------------------------------------------------------------------------- /steam/library_logo_1280x720_japanese.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hajimehoshi/go-inovation/20ee4c8e276f04cf0ba715aa938f6afa10e334d9/steam/library_logo_1280x720_japanese.png -------------------------------------------------------------------------------- /steam/msg_en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hajimehoshi/go-inovation/20ee4c8e276f04cf0ba715aa938f6afa10e334d9/steam/msg_en.png -------------------------------------------------------------------------------- /steam/msg_ja.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hajimehoshi/go-inovation/20ee4c8e276f04cf0ba715aa938f6afa10e334d9/steam/msg_ja.png -------------------------------------------------------------------------------- /steam/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hajimehoshi/go-inovation/20ee4c8e276f04cf0ba715aa938f6afa10e334d9/steam/screenshot.png -------------------------------------------------------------------------------- /steam/screenshot/convert.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "image/color" 7 | "image/png" 8 | "math" 9 | "os" 10 | "regexp" 11 | 12 | "github.com/hajimehoshi/ebiten/v2" 13 | "github.com/hajimehoshi/ebiten/v2/ebitenutil" 14 | ) 15 | 16 | var regularTermination = errors.New("regular termiination") 17 | 18 | var reFilename = regexp.MustCompile(`^screenshot([^_]+)_([a-z]+)\.png$`) 19 | 20 | type Game struct { 21 | tmpImage *ebiten.Image 22 | } 23 | 24 | func (g *Game) getTmpImage(width, height int) *ebiten.Image { 25 | if g.tmpImage != nil { 26 | if w, h := g.tmpImage.Size(); w == width && h == height { 27 | g.tmpImage.Clear() 28 | return g.tmpImage 29 | } 30 | } 31 | g.tmpImage = ebiten.NewImage(width, height) 32 | return g.tmpImage 33 | } 34 | 35 | func (g *Game) Update() error { 36 | ents, err := os.ReadDir(".") 37 | if err != nil { 38 | return err 39 | } 40 | 41 | const ( 42 | screenshotWidth = 1920 43 | screenshotHeight = 1080 44 | ) 45 | 46 | offscreen := ebiten.NewImage(screenshotWidth, screenshotHeight) 47 | for _, ent := range ents { 48 | if ent.IsDir() { 49 | continue 50 | } 51 | name := ent.Name() 52 | m := reFilename.FindStringSubmatch(name) 53 | if m == nil { 54 | continue 55 | } 56 | 57 | img, _, err := ebitenutil.NewImageFromFile(name) 58 | if err != nil { 59 | return err 60 | } 61 | 62 | w, h := img.Size() 63 | scale := screenshotHeight / float64(h) 64 | iscale := math.Ceil(scale) 65 | op := &ebiten.DrawImageOptions{} 66 | op.GeoM.Scale(iscale, iscale) 67 | tmpImg := g.getTmpImage(w * int(iscale), h * int(iscale)) 68 | tmpImg.DrawImage(img, op) 69 | 70 | op = &ebiten.DrawImageOptions{} 71 | op.GeoM.Scale(float64(scale) / float64(iscale), float64(scale) / float64(iscale)) 72 | op.GeoM.Translate((screenshotWidth - float64(w) * scale) / 2, 0) 73 | op.Filter = ebiten.FilterLinear 74 | offscreen.Clear() 75 | offscreen.Fill(color.Black) 76 | offscreen.DrawImage(tmpImg, op) 77 | 78 | newName := fmt.Sprintf("screenshot%s_%dx%d_%s.png", m[1], screenshotWidth, screenshotHeight, m[2]) 79 | f, err := os.Create(newName) 80 | if err != nil { 81 | return err 82 | } 83 | defer f.Close() 84 | if err := png.Encode(f, offscreen); err != nil { 85 | return err 86 | } 87 | } 88 | return regularTermination 89 | } 90 | 91 | func (*Game) Draw(screen *ebiten.Image) { 92 | } 93 | 94 | func (*Game) Layout(width, height int) (int, int) { 95 | return width, height 96 | } 97 | 98 | func main() { 99 | ebiten.SetWindowDecorated(false) 100 | ebiten.SetScreenTransparent(true) 101 | if err := ebiten.RunGame(&Game{}); err != nil && err != regularTermination { 102 | panic(err) 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /steam/screenshot/screenshot3_1920x1080_english.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hajimehoshi/go-inovation/20ee4c8e276f04cf0ba715aa938f6afa10e334d9/steam/screenshot/screenshot3_1920x1080_english.png -------------------------------------------------------------------------------- /steam/screenshot/screenshot3_1920x1080_japanese.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hajimehoshi/go-inovation/20ee4c8e276f04cf0ba715aa938f6afa10e334d9/steam/screenshot/screenshot3_1920x1080_japanese.png -------------------------------------------------------------------------------- /steam/screenshot/screenshot3_english.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hajimehoshi/go-inovation/20ee4c8e276f04cf0ba715aa938f6afa10e334d9/steam/screenshot/screenshot3_english.png -------------------------------------------------------------------------------- /steam/screenshot/screenshot3_japanese.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hajimehoshi/go-inovation/20ee4c8e276f04cf0ba715aa938f6afa10e334d9/steam/screenshot/screenshot3_japanese.png -------------------------------------------------------------------------------- /steam/screenshot/screenshot4_1920x1080_english.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hajimehoshi/go-inovation/20ee4c8e276f04cf0ba715aa938f6afa10e334d9/steam/screenshot/screenshot4_1920x1080_english.png -------------------------------------------------------------------------------- /steam/screenshot/screenshot4_1920x1080_japanese.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hajimehoshi/go-inovation/20ee4c8e276f04cf0ba715aa938f6afa10e334d9/steam/screenshot/screenshot4_1920x1080_japanese.png -------------------------------------------------------------------------------- /steam/screenshot/screenshot4_english.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hajimehoshi/go-inovation/20ee4c8e276f04cf0ba715aa938f6afa10e334d9/steam/screenshot/screenshot4_english.png -------------------------------------------------------------------------------- /steam/screenshot/screenshot4_japanese.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hajimehoshi/go-inovation/20ee4c8e276f04cf0ba715aa938f6afa10e334d9/steam/screenshot/screenshot4_japanese.png -------------------------------------------------------------------------------- /steam/screenshot/screenshot5_1920x1080_english.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hajimehoshi/go-inovation/20ee4c8e276f04cf0ba715aa938f6afa10e334d9/steam/screenshot/screenshot5_1920x1080_english.png -------------------------------------------------------------------------------- /steam/screenshot/screenshot5_1920x1080_japanese.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hajimehoshi/go-inovation/20ee4c8e276f04cf0ba715aa938f6afa10e334d9/steam/screenshot/screenshot5_1920x1080_japanese.png -------------------------------------------------------------------------------- /steam/screenshot/screenshot5_english.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hajimehoshi/go-inovation/20ee4c8e276f04cf0ba715aa938f6afa10e334d9/steam/screenshot/screenshot5_english.png -------------------------------------------------------------------------------- /steam/screenshot/screenshot5_japanese.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hajimehoshi/go-inovation/20ee4c8e276f04cf0ba715aa938f6afa10e334d9/steam/screenshot/screenshot5_japanese.png -------------------------------------------------------------------------------- /steam/screenshot/screenshot6_1920x1080_english.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hajimehoshi/go-inovation/20ee4c8e276f04cf0ba715aa938f6afa10e334d9/steam/screenshot/screenshot6_1920x1080_english.png -------------------------------------------------------------------------------- /steam/screenshot/screenshot6_1920x1080_japanese.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hajimehoshi/go-inovation/20ee4c8e276f04cf0ba715aa938f6afa10e334d9/steam/screenshot/screenshot6_1920x1080_japanese.png -------------------------------------------------------------------------------- /steam/screenshot/screenshot6_english.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hajimehoshi/go-inovation/20ee4c8e276f04cf0ba715aa938f6afa10e334d9/steam/screenshot/screenshot6_english.png -------------------------------------------------------------------------------- /steam/screenshot/screenshot6_japanese.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hajimehoshi/go-inovation/20ee4c8e276f04cf0ba715aa938f6afa10e334d9/steam/screenshot/screenshot6_japanese.png -------------------------------------------------------------------------------- /steam/screenshot/screenshot7_1920x1080_english.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hajimehoshi/go-inovation/20ee4c8e276f04cf0ba715aa938f6afa10e334d9/steam/screenshot/screenshot7_1920x1080_english.png -------------------------------------------------------------------------------- /steam/screenshot/screenshot7_1920x1080_japanese.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hajimehoshi/go-inovation/20ee4c8e276f04cf0ba715aa938f6afa10e334d9/steam/screenshot/screenshot7_1920x1080_japanese.png -------------------------------------------------------------------------------- /steam/screenshot/screenshot7_english.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hajimehoshi/go-inovation/20ee4c8e276f04cf0ba715aa938f6afa10e334d9/steam/screenshot/screenshot7_english.png -------------------------------------------------------------------------------- /steam/screenshot/screenshot7_japanese.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hajimehoshi/go-inovation/20ee4c8e276f04cf0ba715aa938f6afa10e334d9/steam/screenshot/screenshot7_japanese.png -------------------------------------------------------------------------------- /steam/store_header_capsule_460x215_english.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hajimehoshi/go-inovation/20ee4c8e276f04cf0ba715aa938f6afa10e334d9/steam/store_header_capsule_460x215_english.png -------------------------------------------------------------------------------- /steam/store_header_capsule_460x215_japanese.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hajimehoshi/go-inovation/20ee4c8e276f04cf0ba715aa938f6afa10e334d9/steam/store_header_capsule_460x215_japanese.png -------------------------------------------------------------------------------- /steam/store_main_capsule_616x353_english.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hajimehoshi/go-inovation/20ee4c8e276f04cf0ba715aa938f6afa10e334d9/steam/store_main_capsule_616x353_english.png -------------------------------------------------------------------------------- /steam/store_main_capsule_616x353_japanese.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hajimehoshi/go-inovation/20ee4c8e276f04cf0ba715aa938f6afa10e334d9/steam/store_main_capsule_616x353_japanese.png -------------------------------------------------------------------------------- /steam/store_small_capsule_231x87_english.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hajimehoshi/go-inovation/20ee4c8e276f04cf0ba715aa938f6afa10e334d9/steam/store_small_capsule_231x87_english.png -------------------------------------------------------------------------------- /steam/store_small_capsule_231x87_japanese.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hajimehoshi/go-inovation/20ee4c8e276f04cf0ba715aa938f6afa10e334d9/steam/store_small_capsule_231x87_japanese.png -------------------------------------------------------------------------------- /steam/store_vertical_capsule_374x448_english.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hajimehoshi/go-inovation/20ee4c8e276f04cf0ba715aa938f6afa10e334d9/steam/store_vertical_capsule_374x448_english.png -------------------------------------------------------------------------------- /steam/store_vertical_capsule_374x448_japanese.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hajimehoshi/go-inovation/20ee4c8e276f04cf0ba715aa938f6afa10e334d9/steam/store_vertical_capsule_374x448_japanese.png -------------------------------------------------------------------------------- /steam/title_en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hajimehoshi/go-inovation/20ee4c8e276f04cf0ba715aa938f6afa10e334d9/steam/title_en.png -------------------------------------------------------------------------------- /steam/title_ja.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hajimehoshi/go-inovation/20ee4c8e276f04cf0ba715aa938f6afa10e334d9/steam/title_ja.png -------------------------------------------------------------------------------- /steambuild_darwin.sh: -------------------------------------------------------------------------------- 1 | set -e 2 | 3 | name=innovation2007 4 | app_name=Innovation2007.app 5 | bundle_id=com.hajimehoshi.innovation2007.macos 6 | mkdir -p bin 7 | 8 | rm -rf bin/${app_name} 9 | mkdir -p bin/${app_name}/Contents/MacOS 10 | mkdir -p bin/${app_name}/Contents/Resources 11 | env CGO_ENABLED=1 CGO_CFLAGS=-mmacosx-version-min=10.12 CGO_LDFLAGS=-mmacosx-version-min=10.12 GOARCH=amd64 go build -tags=steam -o bin/${app_name}/Contents/MacOS/${name} . 12 | cp steam/icon/icon_512x512.icns bin/${app_name}/Contents/Resources/icon.icns 13 | echo ' 14 | 15 | 16 | 17 | CFBundlePackageType 18 | APPL 19 | CFBundleInfoDictionaryVersion 20 | 6.0 21 | CFBundleExecutable 22 | {{.Name}} 23 | CFBundleIdentifier 24 | {{.BundleID}} 25 | CFBundleIconFile 26 | icon.icns 27 | CFBundleVersion 28 | 0.0.0 29 | CFBundleShortVersionString 30 | 0.0.0 31 | NSHighResolutionCapable 32 | 33 | LSMinimumSystemVersion 34 | 10.12.0 35 | 36 | ' | 37 | sed -e "s/{{.Name}}/${name}/g" | 38 | sed -e "s/{{.BundleID}}/${bundle_id}/g" > bin/${app_name}/Contents/Info.plist 39 | # Note: In order to open the *.app, steam_appid.txt should be copied to *.app/Contents/Resources. 40 | # However, this file should not be copied when you submit the app. 41 | -------------------------------------------------------------------------------- /steambuild_linux.sh: -------------------------------------------------------------------------------- 1 | set -e 2 | 3 | name=innovation2007 4 | STEAM_RUNTIME_VERSION=0.20210817.0 5 | GO_VERSION=$(go env GOVERSION) 6 | 7 | cd bin 8 | 9 | mkdir -p .cache/${STEAM_RUNTIME_VERSION} 10 | 11 | # Download binaries for 386. 12 | if [[ ! -f .cache/${STEAM_RUNTIME_VERSION}/com.valvesoftware.SteamRuntime.Sdk-i386-scout-sysroot.Dockerfile ]]; then 13 | (cd .cache/${STEAM_RUNTIME_VERSION}; curl --location --remote-name https://repo.steampowered.com/steamrt-images-scout/snapshots/${STEAM_RUNTIME_VERSION}/com.valvesoftware.SteamRuntime.Sdk-i386-scout-sysroot.Dockerfile) 14 | fi 15 | if [[ ! -f .cache/${STEAM_RUNTIME_VERSION}/com.valvesoftware.SteamRuntime.Sdk-i386-scout-sysroot.tar.gz ]]; then 16 | (cd .cache/${STEAM_RUNTIME_VERSION}; curl --location --remote-name https://repo.steampowered.com/steamrt-images-scout/snapshots/${STEAM_RUNTIME_VERSION}/com.valvesoftware.SteamRuntime.Sdk-i386-scout-sysroot.tar.gz) 17 | fi 18 | if [[ ! -f .cache/${GO_VERSION}.linux-386.tar.gz ]]; then 19 | (cd .cache; curl --location --remote-name https://golang.org/dl/${GO_VERSION}.linux-386.tar.gz) 20 | fi 21 | 22 | # Download binaries for amd64. 23 | if [[ ! -f .cache/${STEAM_RUNTIME_VERSION}/com.valvesoftware.SteamRuntime.Sdk-amd64,i386-scout-sysroot.Dockerfile ]]; then 24 | (cd .cache/${STEAM_RUNTIME_VERSION}; curl --location --remote-name https://repo.steampowered.com/steamrt-images-scout/snapshots/${STEAM_RUNTIME_VERSION}/com.valvesoftware.SteamRuntime.Sdk-amd64,i386-scout-sysroot.Dockerfile) 25 | fi 26 | if [[ ! -f .cache/${STEAM_RUNTIME_VERSION}/com.valvesoftware.SteamRuntime.Sdk-amd64,i386-scout-sysroot.tar.gz ]]; then 27 | (cd .cache/${STEAM_RUNTIME_VERSION}; curl --location --remote-name https://repo.steampowered.com/steamrt-images-scout/snapshots/${STEAM_RUNTIME_VERSION}/com.valvesoftware.SteamRuntime.Sdk-amd64,i386-scout-sysroot.tar.gz) 28 | fi 29 | if [[ ! -f .cache/${GO_VERSION}.linux-amd64.tar.gz ]]; then 30 | (cd .cache; curl --location --remote-name https://golang.org/dl/${GO_VERSION}.linux-amd64.tar.gz) 31 | fi 32 | 33 | # Build for 386 34 | (cd .cache/${STEAM_RUNTIME_VERSION}; docker build -f com.valvesoftware.SteamRuntime.Sdk-i386-scout-sysroot.Dockerfile -t steamrt_scout_i386:latest .) 35 | docker run --rm --workdir=/work --volume $(pwd)/..:/work steamrt_scout_i386:latest /bin/sh -c " 36 | export PATH=\$PATH:/usr/local/go/bin 37 | export CGO_CFLAGS=-std=gnu99 38 | 39 | rm -rf /usr/local/go && tar -C /usr/local -xzf bin/.cache/${GO_VERSION}.linux-386.tar.gz 40 | 41 | go build -tags=steam -o bin/${name}_linux_386 . 42 | " 43 | 44 | # Build for amd64 45 | (cd .cache/${STEAM_RUNTIME_VERSION}; docker build -f com.valvesoftware.SteamRuntime.Sdk-amd64,i386-scout-sysroot.Dockerfile -t steamrt_scout_amd64:latest .) 46 | docker run --rm --workdir=/work --volume $(pwd)/..:/work steamrt_scout_amd64:latest /bin/sh -c " 47 | export PATH=\$PATH:/usr/local/go/bin 48 | export CGO_CFLAGS=-std=gnu99 49 | 50 | rm -rf /usr/local/go && tar -C /usr/local -xzf bin/.cache/${GO_VERSION}.linux-amd64.tar.gz 51 | 52 | go build -tags=steam -o bin/${name}_linux_amd64 . 53 | " 54 | -------------------------------------------------------------------------------- /steambuild_windows.sh: -------------------------------------------------------------------------------- 1 | set -e 2 | 3 | name=innovation2007 4 | mkdir -p bin 5 | 6 | # TODO: Should '-ldflags=-H=windowsgui' be added? 7 | GOOS=windows GOARCH=386 go build -tags=steam -o bin/${name}_windows_386.exe . 8 | GOOS=windows GOARCH=amd64 go build -tags=steam -o bin/${name}_windows_amd64.exe . 9 | -------------------------------------------------------------------------------- /tools.go: -------------------------------------------------------------------------------- 1 | //go:build tools 2 | 3 | package main 4 | 5 | import ( 6 | _ "github.com/hajimehoshi/ebiten/v2/cmd/ebitenmobile" 7 | ) 8 | -------------------------------------------------------------------------------- /zip_steambuilds.sh: -------------------------------------------------------------------------------- 1 | set -e 2 | 3 | name=innovation2007 4 | app_name=Innovation2007.app 5 | 6 | cd bin 7 | 8 | ditto -c -k --keepParent ${app_name} ${name}_darwin_amd64.zip # Use ditto instead of zip to keep metadata 9 | zip ${name}_linux_386.zip ${name}_linux_386 10 | zip ${name}_linux_amd64.zip ${name}_linux_amd64 11 | zip ${name}_windows_386.zip ${name}_windows_386.exe steam_api.dll 12 | zip ${name}_windows_amd64.zip ${name}_windows_amd64.exe steam_api64.dll 13 | --------------------------------------------------------------------------------