├── .github ├── FUNDING.yml └── ISSUE_TEMPLATE │ ├── ask_question.md │ ├── bug_report.md │ ├── config.yml │ └── feature_request.md ├── License.md ├── OtherLicenses.md ├── README.md ├── Sources └── found │ ├── App.hx │ ├── Event.hx │ ├── Found.hx │ ├── Input.hx │ ├── Scene.hx │ ├── State.hx │ ├── Timer.hx │ ├── Trait.hx │ ├── Url.hx │ ├── anim │ ├── Animation.hx │ ├── Sprite.hx │ ├── Tile.hx │ └── Tilemap.hx │ ├── audio │ ├── Music.hx │ └── Sfx.hx │ ├── data │ ├── Creator.hx │ ├── Data.hx │ ├── DataLoader.hx │ ├── DataPatcher.hx │ ├── Project.hx │ ├── SceneFormat.hx │ ├── SpriteData.hx │ └── Wasm.hx │ ├── glsl │ └── Shader.hx │ ├── import.hx │ ├── math │ ├── Util.hx │ └── Vec2.hx │ ├── node │ ├── AddVec2Node.hx │ ├── ApplyForceToRigidbodyNode.hx │ ├── ApplyImpulseToRigidbodyNode.hx │ ├── BooleanNode.hx │ ├── BranchNode.hx │ ├── BulletMovementNode.hx │ ├── CooldownNode.hx │ ├── DegToRadNode.hx │ ├── DestroyObjectNode.hx │ ├── DestroyObjectOutsideViewNode.hx │ ├── EventListenNode.hx │ ├── EveryXNode.hx │ ├── FlipSpriteNode.hx │ ├── FloatNode.hx │ ├── FloatToIntNode.hx │ ├── GateNode.hx │ ├── GetCenterNode.hx │ ├── GetForwardNode.hx │ ├── GetObjectNode.hx │ ├── GetPositionNode.hx │ ├── GetPropNode.hx │ ├── GetRandomObjectNode.hx │ ├── GetRotationNode.hx │ ├── GetWidthHeightNode.hx │ ├── InitNode.hx │ ├── IntegerNode.hx │ ├── IsFalseNode.hx │ ├── IsObjectOutsideViewNode.hx │ ├── IsTrueNode.hx │ ├── JoinVec2Node.hx │ ├── Logic.hx │ ├── LogicNode.hx │ ├── LogicTree.hx │ ├── MathNode.hx │ ├── MouseCoordNode.hx │ ├── MultiEventNode.hx │ ├── MultiplyVec2Node.hx │ ├── MultiplyVec2sNode.hx │ ├── NullNode.hx │ ├── OnAddNode.hx │ ├── OnCollisionNode.hx │ ├── OnGamepadAxisInputNode.hx │ ├── OnGamepadButtonInputNode.hx │ ├── OnKeyboardNode.hx │ ├── OnMouseNode.hx │ ├── ParseFloatNode.hx │ ├── ParseIntNode.hx │ ├── Platformer2DControllerNode.hx │ ├── PlayAnimationNode.hx │ ├── PlayMusicNode.hx │ ├── PlaySfxNode.hx │ ├── PrintNode.hx │ ├── RadToDegNode.hx │ ├── RandFNode.hx │ ├── RandINode.hx │ ├── RotateTowardPositionNode.hx │ ├── SendEventNode.hx │ ├── SetCameraFollowTargetNode.hx │ ├── SetCameraTargetPositionNode.hx │ ├── SetObjectLocationNode.hx │ ├── SetPropNode.hx │ ├── SpawnObjectNode.hx │ ├── SplitVec2Node.hx │ ├── StringNode.hx │ ├── TopDownControllerNode.hx │ ├── TranslateObjectNode.hx │ ├── UpdateNode.hx │ ├── Vector2Node.hx │ ├── WhileNode.hx │ └── data │ │ ├── FoundryNode.hx │ │ ├── LogicNode.hx │ │ ├── MathNode.hx │ │ ├── NodeCreator.hx │ │ ├── StdNode.hx │ │ └── VariableNode.hx │ ├── object │ ├── Action.hx │ ├── Camera.hx │ ├── Collidable.hx │ ├── Executor.hx │ └── Object.hx │ ├── particle │ ├── Emitter.hx │ └── Particle.hx │ ├── tool │ ├── Follower.hx │ ├── Log.hx │ ├── Loop.hx │ ├── NodeEditor.hx │ ├── OneOf.hx │ ├── Pool.hx │ ├── Runner.hx │ ├── TileEditor.hx │ └── UUID.hx │ ├── trait │ ├── TestScript.hx │ └── internal │ │ ├── Arrows.hx │ │ ├── CameraMovement.hx │ │ ├── CanvasScript.hx │ │ └── LoadingScript.hx │ └── tween │ ├── Ease.hx │ └── Tween.hx ├── defaults ├── default.json ├── font_default.ttf ├── foundry_icon.png ├── loading.json ├── loading.png ├── platformerPack_character.png ├── temp.txt └── tilesheet.png └── khafile.js /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [foundry2D] 4 | custom: ['https://www.patreon.com/user?u=11154829'] 5 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/ask_question.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Ask a question 3 | about: Post a question about Foundry2D 4 | title: '' 5 | labels: question 6 | assignees: '' 7 | --- 8 | 9 | 12 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a bug report 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | 13 | 14 | **Foundry2D version:** 15 | 16 | 17 | 18 | **OS/device including version:** 19 | 20 | 21 | **Browser:** 22 | 23 | 24 | **Issue description:** 25 | 26 | 27 | 28 | **Steps to reproduce:** 29 | 30 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | # Disallow blank issues to make sure people follow one of the templates. 2 | blank_issues_enabled: false 3 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Create a feature request 4 | title: '' 5 | labels: feature request 6 | assignees: '' 7 | --- 8 | 9 | 12 | -------------------------------------------------------------------------------- /License.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2020 the Foundry2d Development Team 2 | 3 | This software is provided 'as-is', without any express or implied 4 | warranty. In no event will the authors be held liable for any damages 5 | arising from the use of this software. 6 | 7 | Permission is granted to anyone to use this software for any purpose, 8 | including commercial applications, and to alter it and redistribute it 9 | freely, subject to the following restrictions: 10 | 11 | 1. The origin of this software must not be misrepresented; you must not 12 | claim that you wrote the original software. If you use this software 13 | in a product, an acknowledgment in the product documentation would be 14 | appreciated but is not required. 15 | 16 | 2. Altered source versions must be plainly marked as such, and must not be 17 | misrepresented as being the original software. 18 | 19 | 3. This notice may not be removed or altered from any source distribution. 20 | -------------------------------------------------------------------------------- /OtherLicenses.md: -------------------------------------------------------------------------------- 1 | # Armory3D 2 | 3 | Used: 4 | * Modified Event 5 | * Modified CanvasScript 6 | 7 | ### The zlib/libpng License 8 | 9 | This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. 10 | Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 11 | The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 12 | Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 13 | This notice may not be removed or altered from any source distribution. 14 | 15 | # Iron 16 | 17 | Used: 18 | * Trait system from iron 19 | * Modified Input 20 | 21 | ### The zlib/libpng License 22 | 23 | This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. 24 | Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 25 | The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 26 | Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 27 | This notice may not be removed or altered from any source distribution. 28 | 29 | # Clay 30 | 31 | Used: 32 | * UUID generator 33 | 34 | ### The MIT License 35 | 36 | Copyright (c) 2020 Andrei Rudenko 37 | 38 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 39 | 40 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 41 | 42 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 43 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Foundry2D 2 | 3 | ![](https://d33wubrfki0l68.cloudfront.net/f1108f9b26116b1f0b6a2b2d1b4cd94c2a0cbf05/5d3be/data/logo_web_foundry.png) 4 | 5 | Foundry is a real-time and all in one game engine. The goal is performance, ease of use and portability. 6 | 7 | - [docs](https://github.com/foundry2D/foundry2d/wiki) 8 | - For building locally and engine developement have a look at the [Empty project repository](https://github.com/foundry2D/Empty). 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Sources/found/App.hx: -------------------------------------------------------------------------------- 1 | package found; 2 | 3 | import kha.Canvas; 4 | import kha.graphics2.ImageScaleQuality; 5 | import kha.Image; 6 | import kha.math.FastMatrix3; 7 | import kha.System; 8 | import kha.Scaler; 9 | 10 | class App { 11 | 12 | private var _imageQuality:ImageScaleQuality; 13 | static var onResets: ArrayVoid> = null; 14 | static var onEndFrames: ArrayVoid> = null; 15 | static var traitAwakes:ArrayVoid> = []; 16 | static var traitInits:ArrayVoid> = []; 17 | static var traitUpdates:ArrayVoid> = []; 18 | static var traitLateUpdates:ArrayVoid> = []; 19 | static var traitRenders:ArrayVoid> = []; 20 | static var traitRenders2D:ArrayVoid> = []; 21 | 22 | public static function init(_appReady:Void->Void) { 23 | new App(_appReady); 24 | } 25 | #if editor 26 | public static var editorui:EditorUi = null; 27 | #end 28 | #if tile_editor 29 | public static var frameCounter:FPS = new FPS(); 30 | #end 31 | public function new(_appReady:Void->Void){ 32 | _appReady(); 33 | Found.backbuffer = Image.createRenderTarget(Found.BUFFERWIDTH, Found.BUFFERHEIGHT); 34 | 35 | _imageQuality = Found.smooth ? ImageScaleQuality.High:ImageScaleQuality.Low; 36 | 37 | found.State.setup(); 38 | 39 | #if editor 40 | editorui = new EditorUi(); 41 | #end 42 | } 43 | @:access(found.object.Executor) 44 | public static function reset() { 45 | Scene.ready = false; 46 | traitInits = []; 47 | traitUpdates = []; 48 | traitLateUpdates = []; 49 | traitRenders = []; 50 | traitRenders2D = []; 51 | 52 | if (onResets != null) for (f in onResets) f(); 53 | 54 | for(exe in found.object.Executor.executors){ 55 | var modified:Array = Reflect.field(found.object.Object,exe.field); 56 | modified = []; 57 | } 58 | } 59 | 60 | public function update(dt:Float):Void { 61 | if (State.active != null){ 62 | State.active.update(dt); 63 | } 64 | #if editor 65 | editorui.update(dt); 66 | #end 67 | #if tile_editor 68 | Found.tileeditor.update(dt); 69 | frameCounter.update(); 70 | #end 71 | 72 | if (onEndFrames != null) for (f in onEndFrames) f(); 73 | } 74 | 75 | public function render(canvas:Canvas):Void { 76 | 77 | Found.backbuffer.g2.begin(); 78 | canvas.g2.color = Found.backgroundcolor; 79 | canvas.g2.fillRect(0, 0, Found.backbuffer.width, Found.backbuffer.height); 80 | if (State.active != null){ 81 | #if editor 82 | if(editorui.currentView == 0 && !editorui.isHidden()) 83 | { 84 | Found.backbuffer.g2.pushTransformation(FastMatrix3.translation(-State.active.cam.position.x,-State.active.cam.position.y)); 85 | EditorTools.drawGrid(Found.backbuffer.g2); 86 | Found.backbuffer.g2.popTransformation(); 87 | State.active.render(Found.backbuffer); 88 | } 89 | else{ 90 | #end 91 | State.active.render(Found.backbuffer); 92 | #if editor } #end 93 | } 94 | Found.backbuffer.g2.end(); 95 | #if editor 96 | frameCounter.render(Found.backbuffer); 97 | frameCounter.addFrame(); 98 | editorui.render(Found.backbuffer); 99 | if(editorui.currentView == 0 || !editorui.visible){//To avoid calling TileEditor when not in game view 100 | #end 101 | #if tile_editor 102 | #if editor if(editorui.currentView == 0 || editorui.isHidden())#end 103 | Found.tileeditor.render(Found.backbuffer); 104 | #end 105 | #if editor 106 | }//end 107 | if(zui.Popup.show) { 108 | zui.Popup.render(Found.backbuffer.g2); 109 | } 110 | #end 111 | 112 | canvas.g2.begin(); 113 | canvas.g2.imageScaleQuality = _imageQuality; 114 | Scaler.scale(Found.backbuffer, canvas, System.screenRotation); 115 | canvas.g2.end(); 116 | } 117 | 118 | // Hooks 119 | public static function notifyOnAwake(f:Void->Void) { 120 | for(func in traitAwakes){ 121 | if(Reflect.compareMethods(func,f)) return; 122 | } 123 | traitAwakes.push(f); 124 | } 125 | 126 | public static function removeAwake(f:Void->Void) { 127 | traitAwakes.remove(f); 128 | } 129 | 130 | public static function notifyOnInit(f:Void->Void) { 131 | for(func in traitInits){ 132 | if(Reflect.compareMethods(func,f)) return; 133 | } 134 | traitInits.push(f); 135 | } 136 | 137 | public static function removeInit(f:Void->Void) { 138 | traitInits.remove(f); 139 | } 140 | 141 | public static function notifyOnUpdate(f:Float->Void) { 142 | for(func in traitUpdates){ 143 | if(Reflect.compareMethods(func,f)) return; 144 | } 145 | traitUpdates.push(f); 146 | } 147 | 148 | public static function removeUpdate(f:Float->Void) { 149 | traitUpdates.remove(f); 150 | } 151 | 152 | public static function notifyOnLateUpdate(f:Void->Void) { 153 | for(func in traitLateUpdates){ 154 | if(Reflect.compareMethods(func,f)) return; 155 | } 156 | traitLateUpdates.push(f); 157 | } 158 | 159 | public static function removeLateUpdate(f:Void->Void) { 160 | traitLateUpdates.remove(f); 161 | } 162 | 163 | public static function notifyOnRender(f:kha.graphics4.Graphics->Void) { 164 | for(func in traitRenders){ 165 | if(Reflect.compareMethods(func,f)) return; 166 | } 167 | traitRenders.push(f); 168 | } 169 | 170 | public static function removeRender(f:kha.graphics4.Graphics->Void) { 171 | traitRenders.remove(f); 172 | } 173 | 174 | public static function notifyOnRender2D(f:kha.graphics2.Graphics->Void) { 175 | for(func in traitRenders2D){ 176 | if(Reflect.compareMethods(func,f)) return; 177 | } 178 | traitRenders2D.push(f); 179 | } 180 | 181 | public static function removeRender2D(f:kha.graphics2.Graphics->Void) { 182 | traitRenders2D.remove(f); 183 | } 184 | 185 | public static function notifyOnReset(f:Void->Void) { 186 | if (onResets == null) onResets = []; 187 | onResets.push(f); 188 | } 189 | 190 | public static function removeReset(f:Void->Void) { 191 | onResets.remove(f); 192 | } 193 | 194 | public static function notifyOnEndFrame(f:Void->Void) { 195 | if (onEndFrames == null) onEndFrames = []; 196 | onEndFrames.push(f); 197 | } 198 | 199 | public static function removeEndFrame(f:Void->Void) { 200 | onEndFrames.remove(f); 201 | } 202 | } 203 | 204 | private class FPS { 205 | 206 | public var fps(default, null) = 0; 207 | var frames = 0; 208 | var time = 0.0; 209 | var lastTime = 0.0; 210 | var ui:zui.Zui; 211 | public function new() { } 212 | 213 | public function update():Int { 214 | var deltaTime = kha.Scheduler.realTime() - lastTime; 215 | lastTime = kha.Scheduler.realTime(); 216 | time += deltaTime; 217 | 218 | if (time >= 1) { 219 | fps = frames; 220 | frames = 0; 221 | time = 0; 222 | } 223 | return fps; 224 | } 225 | var lastFps:Int = 0; 226 | var fpsHandle:zui.Zui.Handle = zui.Id.handle(); 227 | public function render(canvas:kha.Canvas,inEditor = true): Void { 228 | if(canvas.g2 == null || State.active == null || State.active.cam == null) return; 229 | if(ui == null)ui = new zui.Zui({font: kha.Assets.fonts.font_default}); 230 | 231 | canvas.g2.pushTranslation(State.active.cam.position.x,State.active.cam.position.y); 232 | var oldScale = ui.SCALE(); 233 | var width = 60; 234 | var height = 20; 235 | if(inEditor){ 236 | ui.setScale(2.0); 237 | width*=2; 238 | height*=2; 239 | } 240 | ui.begin(canvas.g2); 241 | var accentCol = ui.t.ACCENT_COL; 242 | var windowBgColor = ui.t.WINDOW_BG_COL; 243 | ui.t.ACCENT_COL =ui.t.WINDOW_BG_COL= kha.Color.Transparent; 244 | 245 | fpsHandle.redraws = lastFps != fps ? 2 : 0; 246 | if(ui.window(fpsHandle,0,0, width, height,false))ui.text('Fps: $fps'); 247 | canvas.g2.popTransformation(); 248 | ui.end(); 249 | ui.setScale(oldScale); 250 | ui.t.ACCENT_COL = accentCol; 251 | ui.t.WINDOW_BG_COL = windowBgColor; 252 | } 253 | 254 | public inline function addFrame():Void frames++; 255 | 256 | } -------------------------------------------------------------------------------- /Sources/found/Event.hx: -------------------------------------------------------------------------------- 1 | package found; 2 | 3 | import found.tool.OneOf; 4 | import haxe.ds.Either; 5 | 6 | class Event { 7 | 8 | static var events = new Map>(); 9 | 10 | public static function send(name: String, mask = -1) { 11 | var entries = get(name); 12 | if (entries != null) 13 | for (e in entries) 14 | if (mask == -1 || mask == e.mask ) 15 | switch(e.onEvent){ 16 | case Left(v): 17 | v(); 18 | case Right(v): 19 | v([name,mask]); 20 | } 21 | } 22 | 23 | public static function get(name: String): Array { 24 | return events.get(name); 25 | } 26 | 27 | public static function add(name: String, onEvent:OneOfVoid,Array->Void>, mask = -1): TEvent { 28 | var e: TEvent = { name: name, onEvent: onEvent, mask: mask }; 29 | var entries = events.get(name); 30 | if (entries != null) entries.push(e); 31 | else events.set(name, [e]); 32 | return e; 33 | } 34 | 35 | public static function remove(name: String) { 36 | events.remove(name); 37 | } 38 | 39 | public static function removeListener(event: TEvent) { 40 | var entries = events.get(event.name); 41 | if (entries != null) entries.remove(event); 42 | } 43 | } 44 | 45 | typedef TEvent = { 46 | var name: String; 47 | var onEvent:OneOfVoid,Array->Void>; 48 | var mask: Int; 49 | } 50 | -------------------------------------------------------------------------------- /Sources/found/Found.hx: -------------------------------------------------------------------------------- 1 | package found; 2 | 3 | import kha.Framebuffer; 4 | import kha.Scheduler; 5 | import kha.Assets; 6 | import kha.System; 7 | import kha.Color; 8 | import kha.Image; 9 | import kha.Display; 10 | 11 | #if (kha_html5 &&js) 12 | import js.html.CanvasElement; 13 | import js.Browser.document; 14 | import js.Browser.window; 15 | #end 16 | 17 | enum OS { 18 | None; 19 | Windows; 20 | Mac; 21 | Linux; 22 | Android; 23 | iOS; 24 | Switch; 25 | XboxOne; 26 | Ps4; 27 | } 28 | 29 | class Found { 30 | private static var _app:App; 31 | 32 | public static var WIDTH(default, null):Int; 33 | public static var HEIGHT(default, null):Int; 34 | 35 | public static var GRID:Int = 64; 36 | 37 | public static var backbuffer:Image; 38 | #if editor 39 | public static var BUFFERWIDTH(default, default):Int = WIDTH; 40 | public static var BUFFERHEIGHT(default, default):Int = HEIGHT; 41 | 42 | public static var sha = utilities.BuildMacros.sha().substr(1, 7); 43 | public static var date = utilities.BuildMacros.date().split(" ")[0]; 44 | 45 | #else 46 | public static var BUFFERWIDTH(default, null):Int = WIDTH; 47 | public static var BUFFERHEIGHT(default, null):Int = HEIGHT; 48 | #end 49 | 50 | #if tile_editor 51 | public static var tileeditor:found.tool.TileEditor; 52 | #end 53 | 54 | public static var popupZuiInstance:zui.Zui; 55 | 56 | #if debug 57 | public static var collisionsDraw:Bool = false; 58 | public static var drawGrid:Bool = false; 59 | #end 60 | 61 | public static var sceneX:Float=0.0; 62 | public static var sceneY:Float=0.0; 63 | public static var backgroundcolor:Color; 64 | 65 | public static var smooth:Bool; 66 | 67 | private static var _fps:Float; 68 | 69 | public static var os(get,null):OS; 70 | static function get_os(){ 71 | var plat:OS = None; 72 | #if kha_html5 73 | final agent = js.Browser.navigator.userAgent; 74 | if(agent.lastIndexOf("Mobi") != -1){ 75 | if(agent.lastIndexOf("Android") != -1){ 76 | plat = Android; 77 | } 78 | else if(agent.lastIndexOf("Mac") != -1){ 79 | plat = iOS; 80 | } 81 | } 82 | else { 83 | if(agent.lastIndexOf("Windows") != -1){ 84 | plat = Windows; 85 | } 86 | else if(agent.lastIndexOf("Linux") != -1){ 87 | plat = Linux; 88 | 89 | } 90 | else if(agent.lastIndexOf("Mac") != -1){ 91 | plat = Mac; 92 | } 93 | else if(agent.lastIndexOf("Xbox") != -1){ 94 | plat = XboxOne; 95 | } 96 | else if(agent.lastIndexOf("PlayStation 4") != -1 || agent.lastIndexOf("PLAYSTATION 4") != -1){ 97 | plat = Ps4; 98 | } 99 | } 100 | #else 101 | //@TODO: Add other systems 102 | switch(kha.System.systemId){ 103 | case "Windows": 104 | plat = Windows; 105 | case "MacOS": 106 | plat = Mac; 107 | case "Linux": 108 | plat = Linux; 109 | default: 110 | } 111 | #end 112 | return plat; 113 | } 114 | 115 | public static dynamic function loadScreen(g:kha.graphics2.Graphics){ 116 | var elemH = zui.Themes.dark.ELEMENT_H; 117 | g.begin(); 118 | var value = Assets.progress * (Found.WIDTH * 0.5); 119 | g.color = zui.Themes.dark.PANEL_BG_COL; 120 | g.fillRect(Found.WIDTH * 0.25,Found.HEIGHT * 0.5,Found.WIDTH * 0.5,elemH); 121 | g.color = kha.Color.Orange; 122 | g.fillRect(Found.WIDTH * 0.25,Found.HEIGHT * 0.5,value,elemH); 123 | g.end(); 124 | }; 125 | 126 | public static function setup(config:FoundConfig){ 127 | WIDTH = Display.primary.width; 128 | HEIGHT = Display.primary.height; 129 | var loadDraw = function(framebuffer:Array){ 130 | Found.loadScreen(framebuffer[0].g2); 131 | }; 132 | System.notifyOnFrames(loadDraw); 133 | 134 | if (config.width == null) config.width = WIDTH; 135 | if (config.height == null) config.height = HEIGHT; 136 | if (config.bufferwidth == null) config.bufferwidth = WIDTH; 137 | BUFFERWIDTH = config.bufferwidth; 138 | if (config.bufferheight == null) config.bufferheight = HEIGHT; 139 | BUFFERHEIGHT = config.bufferheight; 140 | 141 | if (config.fps == null) config.fps = 60; 142 | _fps = config.fps; 143 | 144 | if (config.backgroundcolor == null) config.backgroundcolor = Color.Black; 145 | backgroundcolor = config.backgroundcolor; 146 | 147 | if (config.smooth == null) config.smooth = true; 148 | smooth = config.smooth; 149 | 150 | #if kha_html5 151 | html(); 152 | #end 153 | System.start({ 154 | title:config.title, 155 | width:config.width, 156 | height:config.height 157 | }, 158 | function(_){ 159 | Assets.loadEverything(function(){ 160 | Scheduler.addTimeTask(update, 0, 1 / _fps); 161 | resize(System.windowWidth(),System.windowHeight()); 162 | var tBlob = config.defaultThemeFile != null ? kha.Assets.blobs.get(config.defaultThemeFile) :kha.Assets.blobs.get("_themes_json"); 163 | 164 | if (tBlob != null) { 165 | zui.Canvas.themes = haxe.Json.parse(tBlob.toString()); 166 | } 167 | else { 168 | warn("\"_themes.json\" is empty! Using default theme instead."); 169 | } 170 | if (zui.Canvas.themes.length == 0) { 171 | zui.Canvas.themes.push(zui.Themes.dark); 172 | } 173 | _app = Type.createInstance(config.app, []); 174 | kha.Window.get(0).notifyOnResize(resize); 175 | System.removeFramesListener(loadDraw); 176 | System.notifyOnFrames(function(framebuffer){ 177 | render(framebuffer[0]); 178 | }); 179 | #if tile_editor 180 | tileeditor = new found.tool.TileEditor(); 181 | #end 182 | popupZuiInstance = new zui.Zui({font: kha.Assets.fonts.font_default,theme: zui.Canvas.themes[0]}); 183 | }); 184 | }); 185 | } 186 | static function resize(width:Int,height:Int){ 187 | Reflect.setField(Found,"WIDTH",width); 188 | Reflect.setField(Found,"HEIGHT",height); 189 | BUFFERWIDTH = WIDTH; 190 | BUFFERHEIGHT = HEIGHT; 191 | } 192 | static function update(){ 193 | Timer.update(); 194 | _app.update(Timer.delta); 195 | } 196 | 197 | static function render(framebuffer:Framebuffer){ 198 | _app.render(framebuffer); 199 | } 200 | #if kha_html5 201 | static function html(){ 202 | 203 | document.documentElement.style.padding = '0'; 204 | document.documentElement.style.margin = '0'; 205 | document.body.style.padding = '0'; 206 | document.body.style.margin = '0'; 207 | 208 | var canvas = cast(document.getElementById('khanvas'), CanvasElement); 209 | canvas.style.display = 'block'; 210 | 211 | var resize = function(){ 212 | canvas.width = Std.int(window.innerWidth * window.devicePixelRatio); 213 | canvas.height = Std.int(window.innerHeight * window.devicePixelRatio); 214 | canvas.style.width = document.documentElement.clientWidth + 'px'; 215 | canvas.style.height = document.documentElement.clientHeight + 'px'; 216 | } 217 | window.onresize = resize; 218 | resize(); 219 | } 220 | #end 221 | } 222 | 223 | typedef FoundConfig = { 224 | app:Class, 225 | ?defaultThemeFile:String, 226 | ?timer:Timer, 227 | ?title:String, 228 | ?width:Int, 229 | ?height:Int, 230 | ?bufferwidth:Int, 231 | ?bufferheight:Int, 232 | ?backgroundcolor:Color, 233 | ?smooth:Bool, 234 | ?fps:Float 235 | } -------------------------------------------------------------------------------- /Sources/found/State.hx: -------------------------------------------------------------------------------- 1 | package found; 2 | 3 | import kha.Assets; 4 | import found.data.SceneFormat; 5 | import found.data.Data; 6 | 7 | class State extends Scene { 8 | public static var active:State; 9 | private static var loadingState:State; 10 | private static var _states:Map; 11 | 12 | public function new(raw:TSceneFormat){ 13 | super(raw); 14 | 15 | } 16 | 17 | public static function setup(?loadingPath:String = ""){ 18 | _states = new Map(); 19 | if(loadingPath != ""){ 20 | Data.getSceneRaw(loadingPath, function(raw:TSceneFormat){ 21 | loadingState = new State(raw); 22 | }); 23 | }else { 24 | var b:kha.Blob = Reflect.field(Assets.blobs, "loading_json"); 25 | loadingState = new State(haxe.Json.parse(b.toString())); 26 | } 27 | } 28 | 29 | public static function addState(name:String, state:String):String { 30 | if(_states == null)State.setup(); 31 | _states.set(name, state); 32 | return state; 33 | } 34 | 35 | public static function removeState(name:String){ 36 | _states.remove(name); 37 | } 38 | 39 | static var lastState:State; 40 | public static function set(name:String,onDone:Void->Void=null){ 41 | Scene.ready = false; 42 | var file = _states.get(name); 43 | lastState = active; 44 | active = loadingState; 45 | var loaded = onDone == null ? loadState : function(raw:TSceneFormat){ 46 | loadState(raw); 47 | onDone(); 48 | }; 49 | #if debug 50 | if(file == null){ 51 | active = lastState; 52 | error('State with name $name does not exist in State list. Use AddState to add it.'); 53 | } 54 | #end 55 | Data.getSceneRaw(file,loaded); 56 | 57 | 58 | } 59 | private static function loadState(raw:TSceneFormat){ 60 | App.reset(); 61 | //@TODO: Evaluate if we need a dispose function for the Scene class to dispose the last created Scene ? 62 | if(lastState != null && lastState.physics_world != null){ 63 | lastState.physicsUpdate = null; 64 | lastState.physics_world.dispose(); 65 | } 66 | active = new State(raw); 67 | } 68 | // Hooks 69 | public function notifyOnInit(f:Void->Void) { 70 | if (Scene.ready) f(); // Scene already running 71 | else traitInits.push(f); 72 | } 73 | 74 | public function removeInit(f:Void->Void) { 75 | traitInits.remove(f); 76 | } 77 | 78 | public function notifyOnRemove(f:Void->Void) { 79 | traitRemoves.push(f); 80 | } 81 | } -------------------------------------------------------------------------------- /Sources/found/Timer.hx: -------------------------------------------------------------------------------- 1 | package found; 2 | 3 | import kha.Scheduler; 4 | 5 | class Timer { 6 | public static var delta:Float; 7 | static var current:Float; 8 | 9 | public static function update() { 10 | delta = Scheduler.time() -current; 11 | current = Scheduler.time(); 12 | } 13 | } -------------------------------------------------------------------------------- /Sources/found/Trait.hx: -------------------------------------------------------------------------------- 1 | package found; 2 | 3 | import found.object.Object; 4 | 5 | enum abstract PropertyType(Int) from Int to Int 6 | { 7 | var int; 8 | var bool; 9 | var float; 10 | var string; 11 | var vector2i; 12 | var vector2b; 13 | var vector2; 14 | } 15 | #if editor 16 | @:autoBuild(ListTraits.build()) 17 | #end 18 | @:keepSub 19 | class Trait { 20 | 21 | public var name:String = ""; 22 | /** 23 | * Object this trait belongs to. 24 | */ 25 | public var object:Object; 26 | 27 | static var props:Map> = new Map>(); 28 | 29 | public static function hasTrait(classname:String) { 30 | return props.exists(classname); 31 | } 32 | public static function getProps(classname:String):Array { 33 | if(props.exists(classname)){ 34 | var temp:Array = props.get(classname); 35 | var out:Array = []; 36 | if(Std.isOfType(temp,Array)){ 37 | return out.concat(temp); 38 | } 39 | else{ 40 | for(f in Reflect.fields(temp)){ 41 | out.push(Reflect.field(temp,f)); 42 | } 43 | return out; 44 | } 45 | } 46 | else { 47 | return []; 48 | } 49 | } 50 | public static function addProps(classname:String,props:Array){ 51 | if(Trait.props.exists(classname)){ 52 | Trait.props.set(classname,Trait.getProps(classname).concat(props)); 53 | } 54 | else { 55 | Trait.props.set(classname,[for(i in 0...props.length)props[i]]); 56 | } 57 | } 58 | public static function removeProps(classname:String,props:Array){ 59 | if(Trait.props.exists(classname)){ 60 | for(p in props){ 61 | Trait.props.get(classname).remove(p); 62 | } 63 | } 64 | } 65 | 66 | var _add:ArrayVoid> = null; 67 | var _awake:ArrayVoid> = null; 68 | var _init:ArrayVoid> = null; 69 | var _remove:ArrayVoid> = null; 70 | var _update:ArrayVoid> = null; 71 | var _lateUpdate:ArrayVoid> = null; 72 | var _render:ArrayVoid> = null; 73 | var _render2D:ArrayVoid> = null; 74 | 75 | public function new() {} 76 | 77 | public function remove() { 78 | object.removeTrait(this); 79 | } 80 | 81 | public function notifyOnAdd(f:Void->Void) { 82 | if (_add == null) _add = []; 83 | _add.push(f); 84 | } 85 | 86 | public function notifyOnAwake(f:Void->Void) { 87 | if (_awake == null) _awake = []; 88 | _awake.push(f); 89 | } 90 | 91 | public function notifyOnInit(f:Void->Void) { 92 | if (_init == null) _init = []; 93 | _init.push(f); 94 | } 95 | 96 | public function notifyOnRemove(f:Void->Void) { 97 | if (_remove == null) _remove = []; 98 | _remove.push(f); 99 | } 100 | 101 | public function notifyOnUpdate(f:Float->Void) { 102 | if (_update == null) _update = []; 103 | _update.push(f); 104 | } 105 | 106 | public function removeUpdate(f:Float->Void) { 107 | _update.remove(f); 108 | } 109 | 110 | public function notifyOnLateUpdate(f:Void->Void) { 111 | if (_lateUpdate == null) _lateUpdate = []; 112 | _lateUpdate.push(f); 113 | } 114 | 115 | public function removeLateUpdate(f:Void->Void) { 116 | _lateUpdate.remove(f); 117 | } 118 | 119 | public function notifyOnRender(f:kha.graphics4.Graphics->Void) { 120 | if (_render == null) _render = []; 121 | _render.push(f); 122 | } 123 | 124 | public function removeRender(f:kha.graphics4.Graphics->Void) { 125 | _render.remove(f); 126 | } 127 | 128 | public function notifyOnRender2D(f:kha.graphics2.Graphics->Void) { 129 | if (_render2D == null) _render2D = []; 130 | _render2D.push(f); 131 | } 132 | 133 | public function removeRender2D(f:kha.graphics2.Graphics->Void) { 134 | _render2D.remove(f); 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /Sources/found/Url.hx: -------------------------------------------------------------------------------- 1 | package found; 2 | 3 | import haxe.io.Bytes; 4 | 5 | class Url { 6 | 7 | public static function explorer(url: String) { 8 | #if krom_windows 9 | Krom.sysCommand('explorer "' + url + '"'); 10 | #elseif krom_linux 11 | Krom.sysCommand('xdg-open "' + url + '"'); 12 | #elseif (krom_android || krom_ios) 13 | Krom.loadUrl(url); 14 | #elseif krom 15 | Krom.sysCommand('open "' + url + '"'); 16 | #else 17 | kha.System.loadUrl(url); 18 | #end 19 | } 20 | 21 | public static function download(url: String, dstPath: String) { 22 | #if krom_windows 23 | Krom.sysCommand('powershell -c "Invoke-WebRequest -Uri ' + url + " -OutFile '" + dstPath + "'"); 24 | #elseif krom 25 | Krom.sysCommand("curl " + url + " -o " + dstPath); 26 | #end 27 | } 28 | 29 | public static function downloadBytes(url: String): Bytes { 30 | #if krom 31 | var save = Path.data() + Path.sep + "download.bin"; 32 | download(url, save); 33 | try { 34 | return Bytes.ofData(Krom.loadBlob(save)); 35 | } 36 | catch (e: Dynamic) { 37 | return null; 38 | } 39 | #else 40 | return null; 41 | #end 42 | } 43 | } -------------------------------------------------------------------------------- /Sources/found/anim/Animation.hx: -------------------------------------------------------------------------------- 1 | package found.anim; 2 | 3 | 4 | import found.data.SceneFormat.TAnimation; 5 | import found.data.SceneFormat.TFrame; 6 | 7 | class Animation { 8 | public var name:String; 9 | private var _frames: Array; 10 | private var _speeddiv: Int; 11 | private var _count: Int; 12 | private var _index: Int; 13 | 14 | public static function create(frame: TFrame) { 15 | return new Animation([frame], 1); 16 | } 17 | 18 | public static function createFrames(width:Int,height:Int,maxindex: Int, speeddiv: Int,?step:Float = 1.0): Animation { 19 | var frames = new Array(); 20 | for (i in 0...maxindex) frames.push({id:i,start:step*i,tw:width,th:height}); 21 | return new Animation(frames, speeddiv); 22 | } 23 | 24 | public function new(frames:Array,speeddiv: Int) { 25 | this._frames = frames; 26 | _index = 0; 27 | this._speeddiv = speeddiv; 28 | } 29 | public static function fromDefinition(def:TAnimation){ 30 | var anim = new Animation(def.frames, def.fps); 31 | anim._index = 0; 32 | anim.name = def.name; 33 | return anim; 34 | } 35 | 36 | public function take(animation: Animation) { 37 | if (_frames == animation._frames) return; 38 | _frames = animation._frames; 39 | _speeddiv = animation._speeddiv; 40 | name = animation.name; 41 | reset(); 42 | } 43 | 44 | public function get(): TFrame { 45 | return _frames[_index]; 46 | } 47 | 48 | public function getIndex(): Int { 49 | return _index; 50 | } 51 | 52 | public function setIndex(index: Int): Void { 53 | if (index < _frames.length) this._index = index; 54 | } 55 | 56 | public function next(): Bool { 57 | ++_count; 58 | if (_count % _speeddiv == 0) { 59 | ++_index; 60 | if (_index >= _frames.length) { 61 | _index = 0; 62 | return false; 63 | } 64 | } 65 | return true; 66 | } 67 | 68 | public function reset(): Void { 69 | _count = 0; 70 | _index = 0; 71 | } 72 | } -------------------------------------------------------------------------------- /Sources/found/anim/Sprite.hx: -------------------------------------------------------------------------------- 1 | package found.anim; 2 | 3 | /* 4 | Originally coded & created by Robert Konrad 5 | http://robdangero.us 6 | https://github.com/Kha-Samples/Kha2D 7 | 8 | Edited for the Kha Tutorial Series by Lewis Lepton 9 | https://lewislepton.com 10 | https://github.com/lewislepton/kha-tutorial-series 11 | 12 | Edited for the Foundry Engine by Jean-Sébastien Nadeau 13 | https://github.com/foundry2D/foundry2d 14 | */ 15 | 16 | 17 | import kha.Canvas; 18 | import kha.Color; 19 | import kha.math.Vector2; 20 | import found.object.Object; 21 | import found.data.SpriteData; 22 | import found.data.SceneFormat; 23 | 24 | 25 | class Sprite extends Object { 26 | private var data:SpriteData; 27 | @:isVar private var _w(get,default): Float; 28 | function get__w(){ 29 | return _w * scale.x; 30 | } 31 | @:isVar private var _h(get,default): Float; 32 | function get__h(){ 33 | return _h * scale.y; 34 | } 35 | 36 | public var flip:Vector2; 37 | 38 | public function new(sprite:TSpriteData,?done:Sprite->Void){ 39 | super(sprite); 40 | this.active = sprite.active; 41 | this.flip = Reflect.hasField(sprite,"flip") ? sprite.flip:new Vector2(); 42 | new SpriteData(sprite,function(p_data){ 43 | this.data = p_data; 44 | this.raw = Reflect.copy(data.raw); 45 | if (this.width == 0 && data.image != null) this.width = data.image.width; 46 | if (this.height == 0 && data.image != null) this.height = data.image.height; 47 | 48 | if(Reflect.hasField(sprite,"scale") && sprite.scale != null){ 49 | this.resize(function(data:Vector2){ 50 | data.x = sprite.scale.x; 51 | data.y = sprite.scale.y; 52 | return data; 53 | }); 54 | } 55 | done(this); 56 | }); 57 | 58 | } 59 | 60 | override function set_raw(data:TObj):TObj { 61 | return this.data.raw = cast(super.set_raw(data)); 62 | } 63 | 64 | override function get_raw():TObj { 65 | return this.data.raw; 66 | } 67 | 68 | public function setAnimation(animation: Int): Void { 69 | data.curAnim = animation; 70 | } 71 | 72 | public function setAnimationByName(animationName: String): Void { 73 | data.setCurrentAnimationByName(animationName); 74 | } 75 | 76 | function animate(): Void { 77 | if(data == null)return; 78 | data.animation.next(); 79 | } 80 | 81 | override public function render(canvas: Canvas): Void { 82 | if(data == null)return; 83 | super.render(canvas); 84 | #if editor 85 | if(App.editorui.isPlayMode) 86 | #end 87 | animate(); 88 | if (data.image != null) { 89 | var frame = data.animation.get(); 90 | var tx = frame.tx != null ? frame.tx: Std.int(frame.id * _w) % data.image.width; 91 | var ty = frame.ty != null ? frame.ty: Math.floor(frame.id * _w / data.image.width) * _h; 92 | var w = width; 93 | var h = height; 94 | canvas.g2.color = Color.White; 95 | canvas.g2.drawScaledSubImage(data.image,tx , ty, frame.tw, frame.th, (flip.x > 0.0 ? w:0), (flip.y > 0.0 ? h:0), (flip.x > 0.0 ? -w:w), (flip.y > 0.0 ? -h:h)); 96 | } 97 | } 98 | 99 | // @:Incomplete we set this but we never change the animations... 100 | public function set(sprite:TSpriteData): Void { 101 | if(data.name != sprite.imagePath){ 102 | new SpriteData(sprite,function(p_data){ 103 | this.data = p_data; 104 | this.width = this.data.raw.width = p_data.image.width; 105 | this.height = this.data.raw.height= p_data.image.height; 106 | this.raw = this.data.raw; 107 | if(!this.data.animatable){ 108 | this.data.animation.get().tw = Std.int(width); 109 | this.data.animation.get().th = Std.int(height); 110 | } 111 | #if editor 112 | if(found.App.editorui.inspector != null) 113 | found.App.editorui.inspector.updateField(uid,"imagePath",this.raw); 114 | #end 115 | }); 116 | } 117 | } 118 | 119 | override function set_width(value: Float): Float { 120 | super.set_width(value); 121 | return _w = value; 122 | } 123 | 124 | override function set_height(value: Float): Float { 125 | super.set_height(value); 126 | return _h = value; 127 | } 128 | 129 | 130 | } 131 | -------------------------------------------------------------------------------- /Sources/found/anim/Tile.hx: -------------------------------------------------------------------------------- 1 | package found.anim; 2 | 3 | import kha.math.FastMatrix3; 4 | import kha.Canvas; 5 | import kha.math.Vector2; 6 | 7 | import found.math.Util; 8 | import found.data.SpriteData; 9 | import found.data.SceneFormat; 10 | 11 | class Tile { 12 | private var map:Tilemap; 13 | //Id in the tilesheet 14 | public var tileId(default,never):Int; 15 | private var dataId:Int; 16 | // This is the tilesheet 17 | private var data(get,never):SpriteData; 18 | function get_data() { 19 | return map.imageData[dataId]; 20 | } 21 | private var offsetx:Int = 0; 22 | private var offsety:Int = 0; 23 | 24 | private var _w: Float; 25 | private var _h: Float; 26 | 27 | public var animIndex(default,never):Int =0; 28 | 29 | public var flip:Vector2; 30 | 31 | public var raw:TTileData; 32 | 33 | @:access(found.anim.Tilemap) 34 | public function new(tilemap:Tilemap,sprite:TTileData,index:Int,isPivot:Bool,done:Tile->Void){ 35 | // super(sprite.position.x, sprite.position.y, sprite.width, sprite.height); 36 | this.map = tilemap; 37 | // this.active = sprite.active; 38 | this.flip = Reflect.hasField(sprite,"flip") ? sprite.flip:new Vector2(); 39 | _w = sprite.tileWidth; 40 | _h = sprite.tileHeight; 41 | this.raw = sprite; 42 | map.addData(sprite,function(dataId:Int){ 43 | this.dataId = dataId; 44 | //Every tilesheet will have the 0 tile be created 45 | if(index == 0 || isPivot){ 46 | Reflect.setField(this,"tileId",index); 47 | map.pivotTiles.push(this); 48 | done(this); 49 | for(i in 0...sprite.usedIds.length){ 50 | if(i ==0)continue; 51 | createTile(map,sprite,sprite.usedIds[i]); 52 | } 53 | } 54 | else{ 55 | Reflect.setField(this,"tileId",index); 56 | var value = data.addSubSprite(this.tileId-map.pivotTiles[dataId].tileId,sprite.tileWidth,sprite.tileHeight); 57 | Reflect.setField(this,"animIndex",value); 58 | done(this); 59 | } 60 | }); 61 | 62 | } 63 | //initialized in makeBodies of Tilemap 64 | public var bodies:Array = []; 65 | public var bodyCount:Int = -1; 66 | static var onStaticDone:Tilemap->Void = null; 67 | @:access(found.anim.Tilemap) 68 | public static function createTile(map:Tilemap,sprite:TTileData,index:Int,?isPivot=false,?done:Tilemap->Void){ 69 | if(done != null) 70 | onStaticDone = done; 71 | return new Tile(map,sprite,index,isPivot,function(tile:Tile){ 72 | map.tiles.set(tile.tileId,tile); 73 | if(tile.raw.usedIds[tile.raw.usedIds.length-1] == index && onStaticDone != null){ 74 | onStaticDone(map); 75 | onStaticDone = null; 76 | } 77 | 78 | }); 79 | } 80 | public function setAnimation(animation: Int): Void { 81 | data.curAnim = animation; 82 | } 83 | function updateBody(position:Vector2) { 84 | bodyCount++; 85 | if(bodyCount < bodies.length){ 86 | bodies[bodyCount].set_position(position.x,position.y); 87 | } 88 | } 89 | 90 | public function render(canvas: Canvas,position:Vector2,?color:kha.Color=null,?scale:kha.math.Vector2,?shouldZoom:Bool = true): Void { 91 | if(data == null)return; 92 | setAnimation(animIndex); 93 | if(data.animatable) 94 | data.animation.next(); 95 | 96 | if (data.image != null) { 97 | canvas.g2.color = color != null ? color:kha.Color.White; 98 | if(scale != null) 99 | canvas.g2.transformation = FastMatrix3.scale(scale.x,scale.y); 100 | var pos = shouldZoom ? new Vector2(position.x,position.y).mult(State.active.cam.zoom) : position; 101 | canvas.g2.pushTranslation(pos.x,pos.y); 102 | // canvas.g2.rotate(Util.degToRad(rotation), position.x + width/ 2,position.y + height/ 2); 103 | var grid = map.tw; 104 | var width = Util.snap(data.image.width,grid); 105 | var x = Std.int(data.animation.get().id * grid) % width; 106 | var y = Math.floor(data.animation.get().id * grid/width)*(map.th); 107 | canvas.g2.drawScaledSubImage(data.image,x ,y,_w, _h, (flip.x > 0.0 ? _w:0), (flip.y > 0.0 ? _h:0), (flip.x > 0.0 ? -_w:_w), (flip.y > 0.0 ? -_h:_h)); 108 | canvas.g2.popTransformation(); 109 | if(scale != null) 110 | canvas.g2.transformation = FastMatrix3.identity(); 111 | } 112 | } 113 | } -------------------------------------------------------------------------------- /Sources/found/anim/Tilemap.hx: -------------------------------------------------------------------------------- 1 | package found.anim; 2 | 3 | import found.tool.TileEditor; 4 | import kha.Canvas; 5 | import found.anim.Tile; 6 | import found.object.Object; 7 | import found.data.SpriteData; 8 | import found.data.SceneFormat; 9 | import kha.math.Vector2; 10 | 11 | @:access(found.anim.Tile) 12 | class Tilemap extends Object{ 13 | static function deserialize(data:Any):Map>{ 14 | var map = new Map>(); 15 | for(field in Reflect.fields(Reflect.getProperty(data,"h"))){ 16 | map.set(Std.parseInt(field),Reflect.getProperty(Reflect.getProperty(data,"h"),field)); 17 | } 18 | return map; 19 | 20 | } 21 | //@TODO: Set data array to new array 22 | //when changing the width or height of the tilemap 23 | public var w(default,set) : Int; 24 | function set_w(width:Int){ 25 | super.width = width; 26 | return w = width; 27 | } 28 | public var h(default,set) : Int; 29 | function set_h(height:Int){ 30 | super.height = height; 31 | return h = height; 32 | } 33 | public var tw : Int; 34 | public var th : Int; 35 | public var data : Array; 36 | var tiles:Map; 37 | var pivotTiles:Array; 38 | public var imageData:Array; 39 | 40 | public function new(data:TTilemapData,done:Tilemap->Void) { 41 | super(data); 42 | this.w = Std.int(data.width); 43 | this.h = Std.int(data.height); 44 | this.tw = data.tileWidth; 45 | this.th = data.tileHeight; 46 | this.data = [for (i in 0...w * h) -1]; 47 | this.imageData = []; 48 | this.tiles = []; 49 | this.pivotTiles = []; 50 | this.raw = data; 51 | data.map = Tilemap.deserialize(data.map); 52 | for(tileid in data.map.keys()){ 53 | for(pos in data.map.get(tileid)){ 54 | this.data[pos] = tileid; 55 | } 56 | } 57 | 58 | for(tile in data.images){ 59 | Tile.createTile(this,tile,tile.id,true,done); 60 | } 61 | if(data.images.length == 0){ 62 | done(this); 63 | } 64 | } 65 | 66 | override function set_body(b:echo.Body) { 67 | var out = super.set_body(b); 68 | if(b == null){ 69 | removeBodies(State.active); 70 | } 71 | return out; 72 | } 73 | 74 | public inline function x(id : Int) : Int { 75 | return id % w; 76 | } 77 | 78 | public inline function y(id : Int) : Int { 79 | return Std.int(id / w); 80 | } 81 | 82 | public inline function i(x : Int, y : Int) : Int { 83 | if (x < 0) return -1; 84 | else if (x >= w) return -1; 85 | else if (y < 0) return -1; 86 | else if (y >= h) return -1; 87 | else return y * w + x; 88 | } 89 | 90 | // tile -> pixel 91 | public inline function x2p(x : Float) : Float { 92 | return x * tw; 93 | } 94 | 95 | public inline function y2p(y : Float) : Float { 96 | return y * th; 97 | } 98 | 99 | // pixel -> tile 100 | public inline function p2x(p : Float) : Float { 101 | return p / tw; 102 | } 103 | 104 | public inline function p2y(p : Float) : Float { 105 | return p / th; 106 | } 107 | 108 | public inline function pos2Id(pos:Vector2) : Int { 109 | var tx = Std.int(pos.x / tw); 110 | var ty = Std.int(pos.y / th); 111 | return i(tx, ty); 112 | } 113 | 114 | public inline function posXY2Id(x : Float, y : Float) : Int { 115 | var tx = Std.int(x / tw); 116 | var ty = Std.int(y / th); 117 | return i(tx, ty); 118 | } 119 | public function addData(data:TSpriteData,onDone:Int->Void) { 120 | var id = -1; 121 | for(i in 0...imageData.length){ 122 | if(imageData[i].raw.imagePath == data.imagePath){ 123 | onDone(i); 124 | return; 125 | } 126 | } 127 | if(id == -1){ 128 | new SpriteData(data,function(p_data){ 129 | onDone(imageData.push(p_data)-1); 130 | }); 131 | } 132 | } 133 | #if tile_editor 134 | @:access(found.tool.TileEditor) 135 | #end 136 | override public function render(canvas:Canvas) { 137 | super.render(canvas); 138 | var x = 0; 139 | var y = 0; 140 | while(x < w){ 141 | var pos = posXY2Id(x,y); 142 | if(pos != -1){ 143 | var tileId = data[pos]; 144 | if(tileId != -1){ 145 | var tile = tiles[tileId]; 146 | if(tile != null){ 147 | var pos:Vector2 = new Vector2(x,y); 148 | tile.render(canvas,pos); 149 | tile.updateBody(pos.add(this.position)); 150 | } 151 | } 152 | } 153 | x+=tw; 154 | if(x>= w && y < h){ 155 | y+=th; 156 | x = 0; 157 | } 158 | } 159 | for(tile in tiles){ 160 | tile.bodyCount = -1; 161 | } 162 | #if tile_editor 163 | if(TileEditor.selectedTilemapIdIndex != -1 && TileEditor.tilemapIds[TileEditor.selectedTilemapIdIndex] == this.uid){ 164 | drawCountour(canvas); 165 | } 166 | #end 167 | } 168 | 169 | #if tile_editor 170 | function drawCountour(canvas:Canvas){ 171 | var g = canvas.g2; 172 | var stren = State.active.cam.zoom < 1.0 ? 9.0 * (1.0 - State.active.cam.zoom) : 0.0; 173 | g.drawRect(0,0,w,h,3.0+stren); 174 | 175 | } 176 | #end 177 | 178 | public function makeBodies(scene:Scene,?p_tileid:Int){ 179 | var data:TTilemapData = cast(this.raw); 180 | var addAllIds:()->Null = function(){ 181 | for(tileid in data.map.keys()) 182 | makeBodies(scene,tileid); 183 | return null; 184 | }; 185 | var tileId:Null = p_tileid != null ? p_tileid : addAllIds(); 186 | if(tileId != null && data.map.exists(tileId)){ 187 | for(index in data.map.get(tileId) ){ 188 | var tile = this.tiles[tileId]; 189 | if(tile != null && tile.raw.rigidBodies != null && tile.raw.rigidBodies.exists(tile.tileId)){ 190 | var body = tile.raw.rigidBodies.get(tile.tileId); 191 | body.x = this.x2p(this.x(index))+this.position.x; 192 | body.y = this.y2p(this.y(index))+this.position.y; 193 | var addBody:Bool = true; 194 | for(bod in tile.bodies){ 195 | if(bod.x == body.x && bod.y == body.y){ 196 | addBody = false; 197 | break; 198 | } 199 | } 200 | if(addBody){ 201 | var bod = new echo.Body(body); 202 | bod.object = this; 203 | tile.bodies.push(scene.physics_world.add(bod)); 204 | } 205 | 206 | } 207 | } 208 | } 209 | 210 | } 211 | 212 | public function removeBodies(scene:Scene,?p_tileid:Int){ 213 | var data:TTilemapData = cast(this.raw); 214 | var rmAllIds:()->Null = function(){ 215 | for(tileid in data.map.keys()) 216 | removeBodies(scene,tileid); 217 | return null; 218 | }; 219 | var tileId:Null = p_tileid != null ? p_tileid : rmAllIds(); 220 | if(tileId != null){ 221 | var tile = this.tiles[tileId]; 222 | for(body in tile.bodies){ 223 | scene.physics_world.remove(body); 224 | } 225 | tile.bodies.splice(0,tile.bodies.length); 226 | } 227 | } 228 | } -------------------------------------------------------------------------------- /Sources/found/audio/Music.hx: -------------------------------------------------------------------------------- 1 | package found.audio; 2 | 3 | import found.data.Data; 4 | 5 | import kha.audio2.AudioChannel; 6 | import kha.audio1.Audio; 7 | 8 | class Music { 9 | static var musicChannels:Map = new Map(); 10 | public static function play(name:String, ?volume:Float = 0.3, ?loop:Bool= false ) { 11 | Data.getSound(name,function(snd:kha.Sound){ 12 | var chan:AudioChannel = cast(Audio.stream(snd,loop)); 13 | chan.volume = volume; 14 | musicChannels.set(name,chan); 15 | 16 | }); 17 | } 18 | public static function setVolume(name:String,volume:Float){ 19 | var chan = musicChannels.get(name); 20 | if(chan != null && !chan.finished){ 21 | chan.volume = volume; 22 | } 23 | #if debug 24 | else if(chan == null){ 25 | warn('Can\'t set volume, no music with name $name exists'); 26 | } 27 | #end 28 | } 29 | 30 | public static function stopAll() { 31 | for(chan in musicChannels){ 32 | chan.stop(); 33 | } 34 | musicChannels.clear(); 35 | } 36 | } -------------------------------------------------------------------------------- /Sources/found/audio/Sfx.hx: -------------------------------------------------------------------------------- 1 | package found.audio; 2 | 3 | import kha.internal.BytesBlob; 4 | import kha.audio2.Buffer; 5 | import kha.Blob; 6 | import kha.arrays.Float32Array; 7 | import kha.audio2.AudioChannel; 8 | import found.data.SceneFormat.TAudioData; 9 | import found.data.Data; 10 | import found.math.Util; 11 | 12 | import kha.audio1.Audio; 13 | 14 | class Sfx { 15 | static var sfxChannels:Map = new Map(); 16 | static var inactiveChannels:Array = []; 17 | public static var allLoaded:Bool = false; 18 | public static function loadSounds(defs:Array){ 19 | var count = 0; 20 | var done = function(){ 21 | count--; 22 | if(count == 0){ 23 | allLoaded = true; 24 | } 25 | }; 26 | for(def in defs){ 27 | count++; 28 | Data.getSound(def.path,function(snd:kha.Sound){ 29 | if(StringTools.endsWith(def.path,".wav")){ 30 | var data = snd.compressedData; 31 | var arr:kha.arrays.Float32Array = new Float32Array(data.length); 32 | for(i in 0...data.length){ 33 | arr[i] = data.getFloat(i); 34 | } 35 | snd.uncompressedData = arr; 36 | } 37 | else { 38 | snd.uncompress(done); 39 | } 40 | },def.alias); 41 | } 42 | } 43 | public static function bytesToSingle(bytes:haxe.io.Bytes,position:Int) { 44 | var first = bytes.get(position + 0); 45 | var second = bytes.get(position + 1); 46 | var s:Float = (second << 8) | first; 47 | return (s/32768.0)-1.0; 48 | } 49 | public static function play(name:String, ?volume:Float = 0.3){ 50 | Data.getSound(name,function(snd:kha.Sound){ 51 | 52 | var done = function(){ 53 | var sound:Null = null; 54 | if(inactiveChannels.length > 0){ 55 | sound = inactiveChannels.pop(); 56 | sound.data = snd.uncompressedData; 57 | sound.play(); 58 | } 59 | else{ 60 | sound = cast(Audio.play(snd, false)); 61 | } 62 | sound.volume = volume; 63 | sfxChannels.set(name,sound); 64 | // sound.onFinishedCallback = function() { 65 | // var sound = sfxChannels.get(name); 66 | // if(sound != null) 67 | // sfxChannels.remove(name); 68 | // inactiveChannels.push(sound); 69 | // } 70 | }; 71 | if(snd.uncompressedData == null){ 72 | if(StringTools.endsWith(name,".wav")){ 73 | // var data = snd.compressedData; 74 | 75 | var data = Blob.fromBytes(snd.compressedData); 76 | var length = Std.int(data.length*0.5); 77 | var arr:kha.arrays.Float32Array = new Float32Array(length); 78 | var div:Float = 1.0/32768.0; 79 | for(i in 0...length){ 80 | arr.set(i,div * data.readS16LE(i)); 81 | } 82 | snd.uncompressedData = arr; 83 | done(); 84 | } 85 | else{ 86 | snd.uncompress(done); 87 | } 88 | } 89 | else{ 90 | done(); 91 | } 92 | }); 93 | } 94 | 95 | public static function random(name:String, ?amount:Int = 3, ?volume:Float = 0.3){ 96 | var choiceSound:Int = Util.randomInt(amount); 97 | Data.getSound(name+choiceSound,function(snd:kha.Sound){ 98 | var sound = Audio.play(snd, false); 99 | sound.volume = volume; 100 | }); 101 | } 102 | 103 | public static function setVolume(name:String,volume:Float){ 104 | var chan = sfxChannels.get(name); 105 | if(chan != null && !chan.finished){ 106 | chan.volume = volume; 107 | } 108 | #if debug 109 | else if(chan == null){ 110 | warn('Can\'t set volume, no sfx with name $name exists'); 111 | } 112 | #end 113 | } 114 | 115 | public static function isPlaying(name:String) { 116 | return sfxChannels.exists(name) && !sfxChannels.get(name).finished; 117 | } 118 | } -------------------------------------------------------------------------------- /Sources/found/data/Creator.hx: -------------------------------------------------------------------------------- 1 | package found.data; 2 | 3 | import kha.math.Vector2; 4 | import kha.math.Vector3; 5 | 6 | import found.data.SceneFormat; 7 | 8 | class Creator { 9 | public static function createType(name:String,type:String):Null{ 10 | var data:Null = null; 11 | switch(type){ 12 | case "object": 13 | data = { 14 | name: name, 15 | type: type, 16 | position: new Vector2(), 17 | rotation: new Vector3(), 18 | width: 0.0, 19 | height:0.0, 20 | scale: new Vector2(1.0,1.0), 21 | center: new Vector2(), 22 | layer: 0, 23 | depth: 0.0, 24 | active: true 25 | }; 26 | case "sprite_object": 27 | var sprite:TSpriteData = createType(name,"object"); 28 | sprite.width = 493.0; 29 | sprite.height = 512.0; 30 | sprite.imagePath = "foundry_icon"; 31 | sprite.shape = 0;//Rect 32 | sprite.points = [new Vector2(),new Vector2(sprite.width,0),new Vector2(sprite.width,sprite.height),new Vector2(0,sprite.height)]; 33 | sprite.anims = []; 34 | data = sprite; 35 | case "tilemap_object": 36 | var tilemap:TTilemapData = createType(name,"object"); 37 | tilemap.width = 1280.0; 38 | tilemap.height = 960.0; 39 | tilemap.tileWidth = 64; 40 | tilemap.tileHeight = 64; 41 | tilemap.map = new Map>(); 42 | var tile:TTileData = createType("Tile","sprite_object"); 43 | tile.id = 0; 44 | tile.width = 896.0; 45 | tile.height = 448.0; 46 | tile.tileWidth = 64; 47 | tile.tileHeight = 64; 48 | tile.points = [new Vector2(),new Vector2(64,0),new Vector2(64,64),new Vector2(0,64)]; 49 | tile.imagePath = "tilesheet"; 50 | tile.usedIds = [0]; 51 | tile.rigidBodies = new Map(); 52 | 53 | tilemap.images = [tile]; 54 | 55 | data = tilemap; 56 | } 57 | Reflect.setField(data,"type",type); 58 | return data; 59 | } 60 | } -------------------------------------------------------------------------------- /Sources/found/data/Data.hx: -------------------------------------------------------------------------------- 1 | package found.data; 2 | 3 | import found.tool.Log; 4 | import kha.Assets; 5 | import kha.arrays.Float32Array; 6 | import kha.Sound; 7 | import haxe.Json; 8 | import haxe.io.BytesInput; 9 | import found.data.SceneFormat; 10 | // import iron.system.ArmPack; 11 | using StringTools; 12 | 13 | // Global data list and asynchronous data loading 14 | class Data { 15 | 16 | public static var version = 0.1; 17 | public static var cachedSceneRaws:Map = new Map(); 18 | 19 | public static var cachedBlobs:Map = new Map(); 20 | public static var cachedImages:Map = new Map(); 21 | 22 | public static var cachedSounds:Map = new Map(); 23 | public static var cachedVideos:Map = new Map(); 24 | public static var cachedFonts:Map = new Map(); 25 | 26 | public static var assetsLoaded = 0; 27 | static var loadingSceneRaws:MapVoid>> = new Map(); 28 | 29 | static var loadingBlobs:MapVoid>> = new Map(); 30 | static var loadingImages:MapVoid>> = new Map(); 31 | 32 | static var loadingSounds:MapVoid>> = new Map(); 33 | static var loadingVideos:MapVoid>> = new Map(); 34 | static var loadingFonts:MapVoid>> = new Map(); 35 | 36 | #if data_dir 37 | public static var dataPath = './data/'; 38 | #else 39 | public static var dataPath = ''; 40 | #end 41 | 42 | public function new() {} 43 | 44 | public static function deleteAll() { 45 | cachedSceneRaws = new Map(); 46 | // cachedLights = new Map(); 47 | // cachedCameras = new Map(); 48 | 49 | 50 | for (c in cachedBlobs) c.unload(); 51 | cachedBlobs = new Map(); 52 | for (c in cachedImages) c.unload(); 53 | cachedImages = new Map(); 54 | #if arm_audio 55 | for (c in cachedSounds) c.unload(); 56 | cachedSounds = new Map(); 57 | #end 58 | for (c in cachedVideos) c.unload(); 59 | cachedVideos = new Map(); 60 | for (c in cachedFonts) c.unload(); 61 | cachedFonts = new Map(); 62 | } 63 | 64 | public static function getSceneRaw(file:String, done:TSceneFormat->Void) { 65 | var cached = cachedSceneRaws.get(file); 66 | if (cached != null) { done(cached); return; } 67 | 68 | var loading = loadingSceneRaws.get(file); 69 | if (loading != null) { loading.push(done); return; } 70 | 71 | loadingSceneRaws.set(file, [done]); 72 | 73 | // If no extension specified, set to .arm 74 | var compressed = file.endsWith('.lz4'); 75 | var isJson = file.endsWith('.json') || file.endsWith('_json'); 76 | var ext = (compressed || isJson || file.endsWith('.arm')) ? '' : '.arm'; 77 | 78 | getBlob(file,function(b:kha.Blob) { 79 | if (compressed) { 80 | #if arm_compress 81 | #end 82 | } 83 | var parsed:TSceneFormat = null; 84 | try{ 85 | parsed = /*s.charAt(0) == "{" ? */DataLoader.parse(b.toString()) /*: ArmPack.decode(b.toBytes())*/; 86 | } 87 | catch(e:Dynamic){ 88 | error(e); 89 | } 90 | returnSceneRaw(file, parsed); 91 | }); 92 | } 93 | 94 | static function returnSceneRaw(file:String, parsed:TSceneFormat) { 95 | var separated = file.split('/'); 96 | var name = separated[separated.length-1]; 97 | cachedSceneRaws.set(name, parsed); 98 | for (f in loadingSceneRaws.get(file)) f(parsed); 99 | loadingSceneRaws.remove(file); 100 | } 101 | 102 | static var getData = #if wasmfs khafs.Fs.getData#else kha.Assets.loadBlobFromPath#end; 103 | // Raw assets 104 | public static function getBlob(file:String, done:kha.Blob->Void, ?reload:Bool = false) { 105 | 106 | var cached = cachedBlobs.get(file); // Is already cached 107 | if (cached != null && !reload) { done(cached); return; } 108 | 109 | var loading = loadingBlobs.get(file); // Is already being loaded 110 | if (loading != null) { loading.push(done); return; } 111 | 112 | loadingBlobs.set(file, [done]); // Start loading 113 | 114 | var p = (file.charAt(0) == '/' || file.charAt(1) == ':') ? file : dataPath + file; 115 | 116 | if(Reflect.hasField(Assets.blobs,file)){ 117 | var onDone = function(b:kha.Blob) { 118 | cachedBlobs.set(file, b); 119 | for (f in loadingBlobs.get(file)) f(b); 120 | loadingBlobs.remove(file); 121 | assetsLoaded++; 122 | }; 123 | if(Assets.progress >= 1.0){ 124 | onDone(Assets.blobs.get(file)); 125 | }else { 126 | kha.Assets.loadBlob(file,onDone); 127 | } 128 | } 129 | else { 130 | getData(p, function(b:kha.Blob) { 131 | cachedBlobs.set(file, b); 132 | for (f in loadingBlobs.get(file)) f(b); 133 | loadingBlobs.remove(file); 134 | assetsLoaded++; 135 | },function(failed:kha.AssetError){ 136 | var error = failed.error; 137 | var path = failed.url; 138 | Log.error('Asset at path: $path failed to load because of $error'); 139 | }); 140 | } 141 | } 142 | 143 | public static function deleteBlob(handle:String) { 144 | var blob = cachedBlobs.get(handle); 145 | if (blob == null) return; 146 | blob.unload(); 147 | cachedBlobs.remove(handle); 148 | } 149 | 150 | #if wasmfs 151 | static function getImageFromPath(path:String, readable:Bool, done:kha.Image -> Void, ?failed:Null Void>, ?pos:Null){ 152 | var splitted = path.split('/'); 153 | var extension:String = splitted[splitted.length-1].split('.')[1]; 154 | getBlob(path,function(data:kha.Blob){ 155 | var bytes = data.toBytes(); 156 | kha.Image.fromEncodedBytes(bytes,extension,done,function(err:String){ 157 | if(failed != null){ 158 | var error:kha.AssetError = {url: path,error: err}; 159 | Log.error(err); 160 | failed(error); 161 | } 162 | },readable); 163 | }); 164 | } 165 | #else 166 | static var getImageFromPath = kha.Assets.loadImageFromPath; 167 | #end 168 | public static function getImage(file:String, done:kha.Image->Void, readable = false, format = 'RGBA32') { 169 | #if (cpp || hl) 170 | file = file.substring(0, file.length - 4) + '.k'; 171 | #end 172 | 173 | var cached = cachedImages.get(file); 174 | if (cached != null) { done(cached); return; } 175 | 176 | var loading = loadingImages.get(file); 177 | if (loading != null) { loading.push(done); return; } 178 | 179 | loadingImages.set(file, [done]); 180 | 181 | var p = (file.charAt(0) == '/' || file.charAt(1) == ':') ? file : dataPath + file; 182 | 183 | if(Reflect.hasField(kha.Assets.images,file)){ 184 | kha.Assets.loadImage(file,function(b:kha.Image) { 185 | cachedImages.set(file, b); 186 | for (f in loadingImages.get(file)) f(b); 187 | loadingImages.remove(file); 188 | assetsLoaded++; 189 | }); 190 | }else{ 191 | // @:Incomplete: process format in Kha 192 | getImageFromPath(p, readable, function(b:kha.Image) { 193 | cachedImages.set(file, b); 194 | for (f in loadingImages.get(file)) f(b); 195 | loadingImages.remove(file); 196 | assetsLoaded++; 197 | },function (e:kha.AssetError){ 198 | if(e.url == "")e.url = 'Null'; 199 | error("file " + e.url + " does not exist"); 200 | }); 201 | } 202 | } 203 | 204 | public static function deleteImage(handle:String) { 205 | var image = cachedImages.get(handle); 206 | if (image == null) return; 207 | image.unload(); 208 | cachedImages.remove(handle); 209 | } 210 | 211 | 212 | #if wasmfs 213 | static function getSoundFromPath(path:String, done:kha.Sound -> Void, ?failed:Null Void>, ?pos:Null){ 214 | getBlob(path,function(data:kha.Blob){ 215 | var bytes = data.toBytes(); 216 | var snd = new kha.Sound(); 217 | snd.compressedData = bytes; 218 | done(snd); 219 | }); 220 | } 221 | #else 222 | static var getSoundFromPath = kha.Assets.loadSoundFromPath; 223 | #end 224 | /** 225 | * Load sound file from disk into ram. 226 | * 227 | * @param file A String matching the file name of the sound file on disk. 228 | * @param done Completion handler function to do something after the sound is loaded. 229 | */ 230 | public static function getSound(file:String, done:kha.Sound->Void, ?alias:String) { 231 | #if soundcompress 232 | if (file.endsWith('.wav')) file = file.substring(0, file.length - 4) + '.ogg'; 233 | #end 234 | 235 | var cached = cachedSounds.get(file); 236 | if (cached != null) { done(cached); return; } 237 | 238 | var loading = loadingSounds.get(file); 239 | if (loading != null) { loading.push(done); return; } 240 | 241 | loadingSounds.set(file, [done]); 242 | 243 | var p = (file.charAt(0) == '/' || file.charAt(1) == ':') ? file : dataPath + file; 244 | 245 | getSoundFromPath(p, function(b:kha.Sound) { 246 | #if soundcompress 247 | b.uncompress(function () { 248 | #end 249 | var key = alias != null ? alias: file; 250 | cachedSounds.set(key, b); 251 | for (f in loadingSounds.get(file)) f(b); 252 | loadingSounds.remove(file); 253 | assetsLoaded++; 254 | #if soundcompress 255 | }); 256 | #end 257 | },function(error:kha.AssetError){ 258 | Log.error('Couldn\'t load $p because of $error'); 259 | }); 260 | } 261 | 262 | public static function deleteSound(handle:String) { 263 | var sound = cachedSounds.get(handle); 264 | if (sound == null) return; 265 | sound.unload(); 266 | cachedSounds.remove(handle); 267 | } 268 | 269 | public static function getVideo(file:String, done:kha.Video->Void) { 270 | #if (cpp || hl) 271 | file = file.substring(0, file.length - 4) + '.avi'; 272 | #elseif krom 273 | file = file.substring(0, file.length - 4) + '.webm'; 274 | #end 275 | var cached = cachedVideos.get(file); 276 | if (cached != null) { done(cached); return; } 277 | 278 | var loading = loadingVideos.get(file); 279 | if (loading != null) { loading.push(done); return; } 280 | 281 | loadingVideos.set(file, [done]); 282 | 283 | var p = (file.charAt(0) == '/' || file.charAt(1) == ':') ? file : dataPath + file; 284 | 285 | kha.Assets.loadVideoFromPath(p, function(b:kha.Video) { 286 | cachedVideos.set(file, b); 287 | for (f in loadingVideos.get(file)) f(b); 288 | loadingVideos.remove(file); 289 | assetsLoaded++; 290 | }); 291 | } 292 | 293 | public static function deleteVideo(handle:String) { 294 | var video = cachedVideos.get(handle); 295 | if (video == null) return; 296 | video.unload(); 297 | cachedVideos.remove(handle); 298 | } 299 | 300 | public static function getFont(file:String, done:kha.Font->Void) { 301 | var cached = cachedFonts.get(file); 302 | if (cached != null) { done(cached); return; } 303 | 304 | var loading = loadingFonts.get(file); 305 | if (loading != null) { loading.push(done); return; } 306 | 307 | loadingFonts.set(file, [done]); 308 | 309 | var p = (file.charAt(0) == '/' || file.charAt(1) == ':') ? file : dataPath + file; 310 | 311 | kha.Assets.loadFontFromPath(p, function(b:kha.Font) { 312 | cachedFonts.set(file, b); 313 | for (f in loadingFonts.get(file)) f(b); 314 | loadingFonts.remove(file); 315 | assetsLoaded++; 316 | }); 317 | } 318 | 319 | public static function deleteFont(handle:String) { 320 | var font = cachedFonts.get(handle); 321 | if (font == null) return; 322 | font.unload(); 323 | cachedFonts.remove(handle); 324 | } 325 | } -------------------------------------------------------------------------------- /Sources/found/data/DataLoader.hx: -------------------------------------------------------------------------------- 1 | package found.data; 2 | 3 | import haxe.Serializer; 4 | import haxe.Unserializer; 5 | import haxe.Json; 6 | import Type; 7 | 8 | 9 | class DataLoader { 10 | public static var version(default,null) : Float; 11 | 12 | var objVersion : Float; 13 | var obj : Null; 14 | var serialized : Null; 15 | 16 | 17 | public function new(?dataVersion:Null) { 18 | if(dataVersion != null) 19 | version = dataVersion; 20 | objVersion = -1.0; 21 | } 22 | 23 | 24 | public function serialize(o:Dynamic, ?pretty=false) : Void { 25 | var raw = Json.stringify(o/*, function(k:Dynamic, v:Dynamic) : Dynamic { 26 | switch( Type.typeof(v) ) { 27 | case TEnum(_) : 28 | return "__hser__" + Serializer.run(v); 29 | 30 | case TClass(List) : 31 | return "__hser__" + Serializer.run(v); 32 | 33 | case TClass(haxe.ds.StringMap), TClass(haxe.ds.IntMap), TClass(haxe.ds.EnumValueMap) : 34 | return "__hser__" + Serializer.run(v); 35 | case TClass(kha.math.Vector2) | TClass(kha.math.Vector3): 36 | return "__hser__" + Serializer.run(v); 37 | case TClass(String), TClass(Array) : 38 | return v; 39 | 40 | case TNull, TInt, TFloat, TBool, TObject : 41 | return v; 42 | 43 | default : 44 | throw k+" has an unsupported type ("+Type.typeof(v)+")"; 45 | } 46 | }*/); 47 | 48 | raw = '{"version":$version, "data":$raw}'; 49 | 50 | serialized = pretty ? prettify(raw) : raw; 51 | } 52 | 53 | public inline function getSerialized() : String { 54 | if( serialized==null ) 55 | throw 'serialize() must be called first'; 56 | 57 | return serialized; 58 | } 59 | 60 | 61 | //@TODO: We have issues with the data loader when saving scenes.... with new objects 62 | //it says cannot access read only field ???!! 63 | public function unserialize(raw:String) : Void { 64 | var o = Json.parse(raw); 65 | objVersion = Reflect.field(o, "version"); 66 | // parseRec(o, function(k:String, v:Dynamic) : Dynamic { 67 | 68 | // switch( Type.typeof(v) ) { 69 | 70 | // case TClass(String) : 71 | // // Rebuild special types 72 | // var s : String = cast v; 73 | 74 | // // Serialized field 75 | // if( s.indexOf("__hser__")==0 ) 76 | // return Unserializer.run( s.substr(8) ); 77 | 78 | // default : 79 | // } 80 | 81 | // return v; 82 | 83 | // }); 84 | 85 | o = Reflect.field(o, "data"); 86 | 87 | obj = o; 88 | } 89 | 90 | public function getCurrentUnserializedDataVersion() { 91 | return objVersion; 92 | } 93 | 94 | 95 | public function getUnserialized() : Dynamic { 96 | if(objVersion == -1 && obj != null) return obj; 97 | if( version>objVersion ) 98 | throw 'Unserialized object version mismatch, a patch is required (object version:$objVersion, current:$version)'; 99 | 100 | if( versionVoid) { 112 | if( objVersion==from ) { 113 | operation(obj); 114 | objVersion = to; 115 | } 116 | } 117 | 118 | 119 | 120 | static function parseRec(o:Dynamic, replacer:String->Dynamic->Dynamic) { 121 | for(k in Reflect.fields(o)) { 122 | 123 | var v = Reflect.field(o,k); 124 | 125 | Reflect.setField(o, k, replacer(k,v)); 126 | 127 | switch( Type.typeof(v) ) { 128 | 129 | case TObject : 130 | parseRec(v, replacer); 131 | 132 | case TClass(c) : 133 | switch(c) { 134 | 135 | case Array : 136 | // Parse sub array 137 | var arr : Array = cast v; 138 | for(e in arr) 139 | parseRec(e, replacer); 140 | 141 | } 142 | default : 143 | } 144 | 145 | } 146 | } 147 | 148 | 149 | public static function parse(raw:String) { 150 | var hj = new DataLoader(Data.version); 151 | hj.unserialize(raw); 152 | return hj.getUnserialized(); 153 | } 154 | 155 | public static function stringify(o:Dynamic,#if something ?pretty=true #else?pretty=false#end) { 156 | var hj = new DataLoader(Data.version); 157 | hj.serialize(o, pretty); 158 | return hj.getSerialized(); 159 | } 160 | 161 | 162 | public static function prettify(json:String) { 163 | var strBuff = new StringBuf(); 164 | var inString = false; 165 | var indent = 0; 166 | var jumpBefore : Bool; 167 | var jumpAfter : Bool; 168 | var cid : Int; 169 | 170 | for(c in json.split("")) { 171 | cid = c.charCodeAt(0); 172 | jumpBefore = jumpAfter = false; 173 | if( inString ) { 174 | if( c=="\"" ) 175 | inString = false; 176 | } 177 | else 178 | switch( c ) { 179 | case " " : 180 | c = ""; 181 | 182 | case "," : 183 | jumpAfter = true; 184 | 185 | case ":" : 186 | c = " : "; 187 | 188 | case "{" : 189 | if( !inString ) { 190 | jumpAfter = true; 191 | indent++; 192 | } 193 | 194 | case "}" : 195 | jumpBefore = true; 196 | indent--; 197 | 198 | case "[" : 199 | if( !inString ) { 200 | jumpAfter = true; 201 | indent++; 202 | } 203 | 204 | case "]" : 205 | jumpBefore = true; 206 | indent--; 207 | 208 | case "\"" : inString = true; 209 | } 210 | if( jumpBefore ) { 211 | strBuff.addChar(10); // new line 212 | for(i in 0...indent) 213 | strBuff.addChar(9); // tab 214 | } 215 | strBuff.addChar(cid); 216 | if( jumpAfter ) { 217 | strBuff.addChar(10); // new line 218 | for(i in 0...indent) 219 | strBuff.addChar(9); // tab 220 | } 221 | } 222 | return strBuff.toString(); 223 | } 224 | 225 | } -------------------------------------------------------------------------------- /Sources/found/data/DataPatcher.hx: -------------------------------------------------------------------------------- 1 | package found.data; 2 | 3 | class DataPatcher { 4 | 5 | } -------------------------------------------------------------------------------- /Sources/found/data/Project.hx: -------------------------------------------------------------------------------- 1 | package found.data; 2 | 3 | typedef TProject = { 4 | var name:String; 5 | var dataVersion:Float; 6 | var path:String; 7 | var scenes:Array;//path 8 | var type:Project.Type; 9 | } 10 | enum abstract Type(Int) from Int to Int { 11 | var twoD = 0; 12 | var threeD = 1; 13 | } -------------------------------------------------------------------------------- /Sources/found/data/SceneFormat.hx: -------------------------------------------------------------------------------- 1 | package found.data; 2 | 3 | import kha.FastFloat; 4 | import kha.math.Vector2; 5 | import kha.math.Vector3; 6 | import kha.arrays.Float32Array; 7 | import kha.arrays.Uint32Array; 8 | import kha.arrays.Int16Array; 9 | 10 | // Zui 11 | import zui.Nodes; 12 | import zui.Nodes.TNodeCanvas; 13 | 14 | class SceneFormat{ 15 | 16 | public static function getData(t:Dynamic):Dynamic{ 17 | var o= {}; 18 | for(f in Reflect.fields(t)){ 19 | Reflect.setField(o,f,Reflect.field(t,f)); 20 | } 21 | return o; 22 | } 23 | } 24 | 25 | #if js 26 | typedef TSceneFormat = { 27 | #else 28 | @:structInit class TSceneFormat { 29 | #end 30 | public var name:String; 31 | @:optional public var _entities:Null>; 32 | @:optional public var _depth:Null; 33 | @:optional public var _Zsort:Null; 34 | @:optional public var cullOffset:Null; 35 | @:optional public var traits:Null>; // Scene root traits 36 | @:optional public var layers:Null>; 37 | @:optional public var physicsWorld: Null; 38 | } 39 | 40 | #if js 41 | typedef TAudioData = { 42 | #else 43 | @:structInit class TAudioData { 44 | #end 45 | var type:Int; //types: Sfx = 0; Music = 1; 46 | var path:String; 47 | var volume:Float; 48 | @:optional var alias:Null; 49 | } 50 | 51 | #if js 52 | typedef TObj = { 53 | #else 54 | @:structInit class TObj { 55 | #end 56 | public var name:String; 57 | public var type:String; // object, sprite_object, light_object, camera_object, speaker_object, emitter_object,tilemap_object 58 | public var position:Vector2; 59 | public var rotation:Vector3; 60 | @:optional public var velocity:Vector2; 61 | public var width:FastFloat; 62 | public var height:FastFloat; 63 | @:optional public var scale:Null; 64 | public var center:Vector2; 65 | public var layer:Int; 66 | public var depth:Float; 67 | public var active:Bool; 68 | @:optional public var rigidBody: Null; 69 | @:optional public var children:Null>; 70 | @:optional public var traits:Null>; 71 | @:optional public var sounds:Null>; 72 | } 73 | 74 | #if js 75 | typedef TPool = { 76 | >TObj, 77 | #else 78 | @:structInit class TPool extends TObj { 79 | #end 80 | public var maxAmount:Int; 81 | } 82 | 83 | #if js 84 | typedef TCollisionData = { 85 | >TObj, 86 | #else 87 | @:structInit class TCollisionData extends TObj { 88 | #end 89 | public var shape:Int;// Rect = 0; Circle = 1; Polygon = 2; 90 | public var points:Array;// Center = 0; 91 | } 92 | 93 | #if js 94 | typedef TSpriteData = { 95 | >TCollisionData, 96 | #else 97 | @:structInit class TSpriteData extends TCollisionData{ 98 | #end 99 | 100 | public var imagePath: String; 101 | @:optional public var flip:Null; 102 | public var anims:Array; 103 | } 104 | #if js 105 | typedef TTileData = { 106 | >TSpriteData, 107 | #else 108 | @:structInit class TTileData extends TSpriteData{ 109 | #end 110 | public var id:Int; 111 | public var usedIds:Array; 112 | public var tileWidth: Int; 113 | public var tileHeight: Int; 114 | @:optional public var rigidBodies:Null>; 115 | @:optional public var tileAnims:Null>>; 116 | } 117 | #if js 118 | typedef TTilemapData = { 119 | >TObj, 120 | #else 121 | @:structInit class TTilemapData extends TObj{ 122 | #end 123 | public var tileWidth: Int; 124 | public var tileHeight: Int; 125 | // public var map:Array; 126 | // Tileid,posId 127 | public var map:Map>; 128 | public var images:Array; 129 | @:optional public var flip:Null; 130 | } 131 | #if js 132 | typedef TCameraData = { 133 | >TObj, 134 | #else 135 | @:structInit class TCameraData extends TObj { 136 | #end 137 | public var speedX:Float; 138 | public var speedY:Float; 139 | public var offsetX:Int; 140 | public var offsetY:Int; 141 | } 142 | #if js 143 | typedef TEmitterData = { 144 | >TObj, 145 | #else 146 | @:structInit class TEmitterData extends TObj { 147 | #end 148 | public var amount:Int; 149 | } 150 | 151 | #if js 152 | typedef TAnimation = { 153 | #else 154 | @:structInit class TAnimation { 155 | #end 156 | public var name:String; 157 | public var time:Float; 158 | public var fps:Int; 159 | public var frames:Array; 160 | } 161 | #if js 162 | typedef TFrame = { 163 | #else 164 | @:structInit class TFrame{ 165 | #end 166 | //If no tx and ty are specified, id is considered an index. 167 | //This is because of how animations work as of now. 168 | //@TODO: reevaluate these assumptions later 169 | public var id:Int; 170 | public var start:Float; 171 | @:optional public var end:Null; 172 | @:optional public var tx:Null; 173 | @:optional public var ty:Null; 174 | public var tw:Int; 175 | public var th:Int; 176 | @:optional public var movement:Null>; 177 | } 178 | #if js 179 | typedef TPos = { 180 | #else 181 | @:structInit class TPos{ 182 | #end 183 | public var position:Vector2; 184 | public var rotation:Float; 185 | } 186 | #if js 187 | typedef TTrait = { 188 | #else 189 | @:structInit class TTrait { 190 | #end 191 | public var type:String; 192 | public var classname:String; 193 | @:optional public var parameters:Null>; // constructor params 194 | @:optional public var props:Null>; // name : type : value 195 | } 196 | 197 | #if js 198 | typedef TLayer = { 199 | #else 200 | @:structInit class TLayer { 201 | #end 202 | public var name:String; 203 | public var zIndex:Int; 204 | public var speed:FastFloat; 205 | 206 | } 207 | 208 | #if js 209 | typedef LogicTreeData = { 210 | #else 211 | @:structInit class LogicTreeData { 212 | #end 213 | public var name: String; 214 | public var nodes: Nodes; 215 | public var nodeCanvas: TNodeCanvas; 216 | } -------------------------------------------------------------------------------- /Sources/found/data/SpriteData.hx: -------------------------------------------------------------------------------- 1 | package found.data; 2 | 3 | import kha.Image; 4 | import kha.Blob; 5 | 6 | import found.anim.Animation; 7 | import found.data.SceneFormat; 8 | 9 | class SpriteData { 10 | public var name:String; 11 | public var image:Image; 12 | public var animation(get,null):Animation; 13 | function get_animation(){ 14 | return anims[curAnim]; 15 | } 16 | private var anims:Array; 17 | public var animatable(get,never):Bool; 18 | @:access(found.anim.Animation) 19 | function get_animatable(){ 20 | if(anims == null)return false; 21 | return animation._frames.length >1; 22 | } 23 | public var curAnim(default,set):Int = 0; 24 | function set_curAnim(index:Int){ 25 | if(anims.length < index){ 26 | warn('Trying to set animation with index: $index but the number of animations is:'+anims.length); 27 | }else{ 28 | curAnim =index; 29 | } 30 | return curAnim; 31 | } 32 | public var raw:TSpriteData; 33 | 34 | public function new(raw:TSpriteData,done:SpriteData->Void){ 35 | this.raw = raw; 36 | Data.getImage(raw.imagePath,function (img:Image){ 37 | this.image = img; 38 | anims = []; 39 | name = this.raw.imagePath; 40 | if( raw.anims != null && raw.anims.length != 0){ 41 | for(a in raw.anims){ 42 | animLoad(a); 43 | } 44 | done(this); 45 | } 46 | else { 47 | addSubSprite(0); 48 | done(this); 49 | } 50 | }); 51 | } 52 | public function addSubSprite(index:Int,?width:Null,?height:Null){ 53 | var w = width != null ? width: Std.int(raw.width); 54 | var h = height != null ? height: Std.int(raw.height); 55 | var frame:TFrame = {id:index,start:0.0,tw:w,th:h}; 56 | return anims.push(Animation.create(frame))-1; 57 | } 58 | 59 | public function setCurrentAnimationByName(animationName:String) { 60 | for (i in 0...anims.length) { 61 | if (anims[i].name == animationName) { 62 | curAnim = i; 63 | return; 64 | } 65 | } 66 | 67 | error('Animation with name: $animationName does not exist'); 68 | } 69 | 70 | function animLoad(anim:TAnimation) { 71 | anims.push(Animation.fromDefinition(anim)); 72 | } 73 | } -------------------------------------------------------------------------------- /Sources/found/data/Wasm.hx: -------------------------------------------------------------------------------- 1 | package found.data; 2 | 3 | #if js 4 | 5 | class Wasm { 6 | public var exports:Dynamic; 7 | 8 | public static inline function instance(blob:kha.Blob, importObject:Dynamic = null):Wasm { 9 | return new Wasm(blob, importObject); 10 | } 11 | 12 | function new(blob:kha.Blob, importObject:Dynamic) { 13 | // Switch to WebAssembly.instantiateStreaming when available 14 | var data = blob.toBytes().getData(); 15 | untyped __js__('var module = new WebAssembly.Module({0});', data); 16 | if (importObject == null) { 17 | untyped __js__('{0} = new WebAssembly.Instance(module).exports;', exports); 18 | } 19 | else { 20 | untyped __js__('{0} = new WebAssembly.Instance(module, {1}).exports;', exports, importObject); 21 | } 22 | } 23 | 24 | public function getString(i:Int):String { // Retrieve string from memory pointer 25 | var mem = getMemory(i, 32); 26 | var s = ""; 27 | for (i in 0...32) mem[i] == 0 ? break : s += String.fromCharCode(mem[i]); 28 | return s; 29 | } 30 | 31 | public function getMemory(offset:Int, length:Int):js.lib.Uint8Array { 32 | return untyped __js__('new Uint8Array({0}.memory.buffer, {1}, {2});', exports, offset, length); 33 | } 34 | 35 | public function getMemoryF32(offset:Int, length:Int):kha.arrays.Float32Array { 36 | return untyped __js__('new Float32Array({0}.memory.buffer, {1}, {2});', exports, offset, length); 37 | } 38 | 39 | public function getMemoryU32(offset:Int, length:Int):kha.arrays.Uint32Array { 40 | return untyped __js__('new Uint32Array({0}.memory.buffer, {1}, {2});', exports, offset, length); 41 | } 42 | } 43 | 44 | #end 45 | -------------------------------------------------------------------------------- /Sources/found/glsl/Shader.hx: -------------------------------------------------------------------------------- 1 | package found.glsl; 2 | 3 | import kha.Canvas; 4 | import kha.Scheduler; 5 | import kha.Shaders; 6 | import kha.graphics4.BlendingFactor; 7 | import kha.graphics4.ConstantLocation; 8 | import kha.graphics4.VertexData; 9 | import kha.graphics4.VertexStructure; 10 | import kha.graphics4.PipelineState; 11 | import kha.graphics4.FragmentShader; 12 | 13 | import found.object.Object; 14 | 15 | class Shader extends Object { 16 | private var _pipeline:PipelineState; 17 | public var shader:FragmentShader; 18 | public var timeID:ConstantLocation; 19 | 20 | public function new(shader:FragmentShader, shadertype:Int = 0){ 21 | super(); 22 | this.shader = shader; 23 | 24 | _pipeline = new PipelineState(); 25 | _pipeline.fragmentShader = shader; 26 | 27 | var structure = new VertexStructure(); 28 | structure.add('vertexPosition', VertexData.Float3); 29 | 30 | switch (shadertype){ 31 | case 0: 32 | _pipeline.vertexShader = Shaders.painter_colored_vert; 33 | structure.add('vertexColor', VertexData.Float4); 34 | 35 | case 1: 36 | _pipeline.vertexShader = Shaders.painter_image_vert; 37 | structure.add('texPosition', VertexData.Float2); 38 | structure.add('vertexColor', VertexData.Float4); 39 | default: return; 40 | } 41 | 42 | _pipeline.inputLayout = [structure]; 43 | 44 | _pipeline.blendSource = BlendingFactor.SourceAlpha; 45 | _pipeline.blendDestination = BlendingFactor.InverseSourceAlpha; 46 | _pipeline.alphaBlendSource = BlendingFactor.SourceAlpha; 47 | _pipeline.alphaBlendDestination = BlendingFactor.InverseSourceAlpha; 48 | 49 | _pipeline.compile(); 50 | 51 | timeID = _pipeline.getConstantLocation('u_time'); 52 | } 53 | 54 | public function begin(canvas:Canvas){ 55 | canvas.g2.pipeline = _pipeline; 56 | _pipeline.set(); 57 | canvas.g4.setFloat(timeID, Scheduler.time()); 58 | } 59 | 60 | public function end(canvas:Canvas){ 61 | canvas.g2.pipeline = null; 62 | } 63 | } -------------------------------------------------------------------------------- /Sources/found/import.hx: -------------------------------------------------------------------------------- 1 | package found; 2 | // Global imports 3 | 4 | #if (!macro) 5 | import found.tool.Log.warn; 6 | import found.tool.Log.error; 7 | #end -------------------------------------------------------------------------------- /Sources/found/math/Util.hx: -------------------------------------------------------------------------------- 1 | package found.math; 2 | 3 | import haxe.Int32; 4 | import haxe.macro.Expr; 5 | 6 | /** 7 | * Some copy pasta from: https://github.com/deepnight/deepnightLibs/blob/master/src/dn/M.hx 8 | */ 9 | 10 | class Util { 11 | inline static var RAND_MAX = (1 << 31)-1; 12 | public static function random(seed:Int){ 13 | return (seed * 1103515245 + 12345) & RAND_MAX; 14 | } 15 | public static function randomInt(value:Int):Int { 16 | return Math.floor(Math.random() * value); 17 | } 18 | 19 | public static function randomFloat(value:Float):Float { 20 | return Math.random() * value; 21 | } 22 | 23 | public static function randomRangeInt(min:Int, max:Int):Int { 24 | return Math.floor(Math.random() * (1 + max - min)) + min; 25 | } 26 | 27 | public static function randomRangeFloat(min:Float, max:Float):Float { 28 | return Math.random() * (max - min) + min; 29 | } 30 | 31 | public static function lerp(min:Float, max:Float, value:Float):Float { 32 | return min + (max - min) * value; 33 | } 34 | 35 | inline public static var PI = 3.141592653589793; 36 | 37 | inline static var d2r = PI / 180 ; 38 | public static function degToRad(degrees:Float):Float { 39 | return degrees * d2r; 40 | } 41 | 42 | inline static var r2d = 180 / PI; 43 | public static function radToDeg(radians:Float):Float { 44 | return radians * r2d; 45 | } 46 | 47 | public static function fround( value : Float, precision : Int): Float { 48 | value = value * Math.pow(10, precision); 49 | value = Math.round( value ) / Math.pow(10, precision); 50 | return value; 51 | } 52 | 53 | inline public static function fclamp(x:Float, min:Float, max:Float):Float 54 | { 55 | return (x < min) ? min : (x > max) ? max : x; 56 | } 57 | 58 | /** 59 | * Default system epsilon. 60 | */ 61 | inline public static var EPS = 1e-6; 62 | 63 | inline public static function slerp(from:Float, to:Float, t:Float) 64 | { 65 | var m = Math; 66 | 67 | var c1 = m.sin(from * .5); 68 | var r1 = m.cos(from * .5); 69 | var c2 = m.sin(to * .5); 70 | var r2 = m.cos(to * .5); 71 | 72 | var c = r1 * r2 + c1 * c2; 73 | 74 | if( c < 0.) 75 | { 76 | if( (1. + c) > Util.EPS) 77 | { 78 | var o = m.acos(-c); 79 | var s = m.sin(o); 80 | var s0 = m.sin((1 - t) * o) / s; 81 | var s1 = m.sin(t * o) / s; 82 | return m.atan2(s0 * c1 - s1 * c2, s0 * r1 - s1 * r2) * 2.; 83 | } 84 | else 85 | { 86 | var s0 = 1 - t; 87 | var s1 = t; 88 | return m.atan2(s0 * c1 - s1 * c2, s0 * r1 - s1 * r2) * 2; 89 | } 90 | } 91 | else 92 | { 93 | if( (1 - c) > Util.EPS) 94 | { 95 | var o = m.acos(c); 96 | var s = m.sin(o); 97 | var s0 = m.sin((1 - t) * o) / s; 98 | var s1 = m.sin(t * o) / s; 99 | return m.atan2(s0 * c1 + s1 * c2, s0 * r1 + s1 * r2) * 2.; 100 | } 101 | else 102 | { 103 | var s0 = 1 - t; 104 | var s1 = t; 105 | return m.atan2(s0 * c1 + s1 * c2, s0 * r1 + s1 * r2) * 2; 106 | } 107 | } 108 | } 109 | 110 | /** 111 | * Replaces pow(v, 3) by v * v * v at compilation time (macro), 17x faster results 112 | * Limitations: "power" must be a constant Int [0-256], no variable allowed 113 | */ 114 | macro public static function pow(v:Expr, power:Expr) { 115 | var pos = haxe.macro.Context.currentPos(); 116 | var v = { expr:EParenthesis(v), pos:pos } 117 | 118 | var ipow = switch( power.expr ) { 119 | case EConst(CInt(v)) : Std.parseInt(v); 120 | default : haxe.macro.Context.error("You can only use a constant Int here", power.pos); 121 | } 122 | 123 | if( ipow<=0 || ipow>256 ) 124 | haxe.macro.Context.error("Only values between [0-256] are supported", power.pos); 125 | 126 | function recur(n:Int) : Expr { 127 | if( n>1 ) 128 | return {expr:EBinop(OpMult, v, recur(n-1)), pos:pos} 129 | else 130 | return v; 131 | } 132 | return recur(ipow); 133 | } 134 | 135 | /** 136 | * Snaps value to the grid. 137 | */ 138 | inline public static function snap(value:Float, grid:Float):Float 139 | { if(value % grid == 0) return value; 140 | return value += grid - Math.floor(value) % grid; 141 | } 142 | 143 | /** 144 | * Returns the sign of x. 145 | * sgn(0) = 0. 146 | */ 147 | inline public static function sign(x:Float):Int { 148 | return (x > 0) ? 1 : (x < 0 ? -1 : 0); 149 | } 150 | inline public static function signEq(x:Float,y:Float):Bool { 151 | return Util.sign(x)==Util.sign(y); 152 | } 153 | 154 | } 155 | 156 | /** 157 | * Cli util for coloring the console. Vars that start with b are BOLD. 158 | * Don't forget to use the reset after coloring to avoid coloring the whole string. 159 | */ 160 | class Cli{ 161 | public static final red = "\033[31m"; 162 | public static final green = "\033[32m"; 163 | public static final yellow = "\033[33m"; 164 | public static final bred = "\033[1m\033[31m"; 165 | public static final bgreen = "\033[1m\033[32m"; 166 | public static final byellow = "\033[1m\033[33m"; 167 | public static final reset = "\033[0m"; 168 | } 169 | /** the following are UBUNTU/LINUX, and MacOS ONLY terminal color codes. As of 2019 they should work in windows 10: https://stackoverflow.com/a/52063884 170 | #define RESET "\033[0m" 171 | #define BLACK "\033[30m" 172 | #define RED "\033[31m" 173 | #define GREEN "\033[32m" 174 | #define YELLOW "\033[33m" 175 | #define BLUE "\033[34m" 176 | #define MAGENTA "\033[35m" 177 | #define CYAN "\033[36m" 178 | #define WHITE "\033[37m" 179 | #define BOLDBLACK "\033[1m\033[30m" 180 | #define BOLDRED "\033[1m\033[31m" 181 | #define BOLDGREEN "\033[1m\033[32m" 182 | #define BOLDYELLOW "\033[1m\033[33m" 183 | #define BOLDBLUE "\033[1m\033[34m" 184 | #define BOLDMAGENTA "\033[1m\033[35m" 185 | #define BOLDCYAN "\033[1m\033[36m" 186 | #define BOLDWHITE "\033[1m\033[37m" 187 | **/ -------------------------------------------------------------------------------- /Sources/found/math/Vec2.hx: -------------------------------------------------------------------------------- 1 | package found.math; 2 | 3 | import kha.math.FastVector2; 4 | 5 | // @:TODO Investigate using import kha.simd.Float32x4; 6 | // We could store scale and or center vector; 7 | // We actually need to determine which of them will be used often for calculations 8 | 9 | @:forward(dot,normalized,angle,toString,x,y) 10 | abstract Vec2(FastVector2) from FastVector2 to FastVector2 { 11 | inline public function new(x= 0.0,y=0.0) { 12 | this = new FastVector2(x,y); 13 | } 14 | 15 | @:op(A + B) 16 | public function addition(other:Vec2):Vec2 { 17 | return inline this.add(other); 18 | } 19 | 20 | @:op(A - B) 21 | public function subtract(other:Vec2):Vec2 { 22 | return inline this.sub(other); 23 | } 24 | 25 | @:op(A * B) 26 | public function multiply(f:Float):Vec2 { 27 | return inline this.mult(f); 28 | } 29 | 30 | @:op(A / B) 31 | public function divide(f:Float):Vec2 { 32 | return inline this.div(f); 33 | } 34 | } -------------------------------------------------------------------------------- /Sources/found/node/AddVec2Node.hx: -------------------------------------------------------------------------------- 1 | package found.node; 2 | 3 | import kha.math.Vector2; 4 | 5 | class AddVec2Node extends LogicNode { 6 | 7 | public function new(tree:LogicTree) { 8 | super(tree); 9 | } 10 | 11 | override function get(from: Int): Dynamic { 12 | var one:Vector2 = inputs[0].get(); 13 | var two:Vector2 = inputs[1].get(); 14 | 15 | return one.add(two); 16 | } 17 | } -------------------------------------------------------------------------------- /Sources/found/node/ApplyForceToRigidbodyNode.hx: -------------------------------------------------------------------------------- 1 | package found.node; 2 | 3 | import found.object.Object; 4 | import kha.math.FastVector2; 5 | 6 | class ApplyForceToRigidbodyNode extends LogicNode { 7 | public function new(tree:LogicTree) { 8 | super(tree); 9 | } 10 | 11 | override function run(from:Int) { 12 | var force:FastVector2 = inputs[2].get(); 13 | 14 | if (inputs[1].node == null) { 15 | if (tree.object.body != null) { 16 | tree.object.body.push(force.x, force.y); 17 | } 18 | } else { 19 | var objectToApplyForceTo:Object = cast(inputs[1].get()); 20 | if (objectToApplyForceTo.body != null) { 21 | objectToApplyForceTo.body.push(force.x, force.y); 22 | } 23 | } 24 | 25 | runOutput(0); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Sources/found/node/ApplyImpulseToRigidbodyNode.hx: -------------------------------------------------------------------------------- 1 | package found.node; 2 | 3 | import found.object.Object; 4 | import kha.math.FastVector2; 5 | 6 | class ApplyImpulseToRigidbodyNode extends LogicNode { 7 | public function new(tree:LogicTree) { 8 | super(tree); 9 | } 10 | 11 | override function run(from:Int) { 12 | var force:FastVector2 = inputs[2].get(); 13 | 14 | if (inputs[1].node == null) { 15 | if (tree.object.body != null) { 16 | tree.object.body.velocity.x = force.x; 17 | tree.object.body.velocity.y = force.y; 18 | } 19 | } else { 20 | var objectToApplyImpulseTo:Object = cast(inputs[1].get()); 21 | if (objectToApplyImpulseTo.body != null) { 22 | objectToApplyImpulseTo.body.velocity.x = force.x; 23 | objectToApplyImpulseTo.body.velocity.y = force.y; 24 | } 25 | } 26 | 27 | runOutput(0); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Sources/found/node/BooleanNode.hx: -------------------------------------------------------------------------------- 1 | package found.node; 2 | 3 | @:keep 4 | class BooleanNode extends LogicNode { 5 | 6 | public var value: Bool; 7 | 8 | public function new(tree: LogicTree, value = false) { 9 | super(tree); 10 | this.value = value; 11 | } 12 | 13 | override function get(from: Int): Dynamic { 14 | if (inputs.length > 0) return inputs[0].get(); 15 | return value; 16 | } 17 | 18 | override function set(value: Dynamic) { 19 | if (inputs.length > 0) inputs[0].set(value); 20 | else this.value = value; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Sources/found/node/BranchNode.hx: -------------------------------------------------------------------------------- 1 | package found.node; 2 | 3 | class BranchNode extends LogicNode{ 4 | 5 | public function new(tree: LogicTree){ 6 | super(tree); 7 | } 8 | 9 | override function run(from: Int){ 10 | var bool: Bool = inputs[1].get(); 11 | bool ? runOutput(0) : runOutput(1); 12 | } 13 | 14 | } -------------------------------------------------------------------------------- /Sources/found/node/BulletMovementNode.hx: -------------------------------------------------------------------------------- 1 | package found.node; 2 | 3 | import found.math.Util; 4 | import kha.math.Vector2; 5 | 6 | class BulletMovementNode extends LogicNode { 7 | public function new(tree:LogicTree) { 8 | super(tree); 9 | 10 | tree.notifyOnInit(setVelocity); 11 | } 12 | function setVelocity() { 13 | if (tree.object.body != null) { 14 | var speed:Float = inputs[1].get(); 15 | var angle:Float = tree.object.rotation.z; 16 | 17 | var newVelocity:Vector2 = new Vector2(); 18 | var rotationInRadians:Float = Util.degToRad(angle); 19 | newVelocity.x = Math.cos(rotationInRadians) * speed; 20 | newVelocity.y = Math.sin(rotationInRadians) * speed; 21 | 22 | tree.object.body.velocity = newVelocity; 23 | } 24 | #if debug 25 | else { 26 | error("Bullet Movement node needs the object to have a Rigidbody"); 27 | } 28 | #end 29 | } 30 | override function run(from:Int) { 31 | setVelocity(); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Sources/found/node/CooldownNode.hx: -------------------------------------------------------------------------------- 1 | package found.node; 2 | 3 | import kha.Scheduler; 4 | 5 | class CooldownNode extends LogicNode { 6 | 7 | public function new(tree:LogicTree) { 8 | super(tree); 9 | tree.notifyOnInit(init); 10 | } 11 | function init(){ 12 | cooldown = inputs[1].get(); 13 | lastTime = Scheduler.time(); 14 | } 15 | var cooldown:Float; 16 | var lastTime:Float; 17 | override function run(from:Int) { 18 | var dif = Scheduler.time() - lastTime; 19 | if(dif >= cooldown){ 20 | lastTime = Scheduler.time(); 21 | runOutput(0); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Sources/found/node/DegToRadNode.hx: -------------------------------------------------------------------------------- 1 | package found.node; 2 | 3 | class DegToRadNode extends LogicNode { 4 | 5 | public function new(tree: LogicTree) { 6 | super(tree); 7 | } 8 | 9 | override function get(from: Int): Dynamic { 10 | 11 | var degree: Float = inputs[0].get(); 12 | 13 | return degree * Math.PI / 180; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Sources/found/node/DestroyObjectNode.hx: -------------------------------------------------------------------------------- 1 | package found.node; 2 | 3 | import found.object.Object; 4 | 5 | class DestroyObjectNode extends LogicNode { 6 | override function run(from:Int) { 7 | var objectToDestroy:Object; 8 | 9 | if (inputs[1].node != null) { 10 | objectToDestroy = cast(inputs[1].get()); 11 | } else { 12 | objectToDestroy = tree.object; 13 | } 14 | 15 | found.State.active.remove(objectToDestroy); 16 | 17 | runOutput(0); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Sources/found/node/DestroyObjectOutsideViewNode.hx: -------------------------------------------------------------------------------- 1 | package found.node; 2 | 3 | import found.object.Object; 4 | 5 | class DestroyObjectOutsideViewNode extends LogicNode { 6 | public function new(tree:LogicTree) { 7 | super(tree); 8 | 9 | tree.notifyOnUpdate(update); 10 | } 11 | 12 | function update(dt:Float) { 13 | var objectToDestroy:Object; 14 | var viewOffsetToDestroyAt:Int = inputs[1].get(); 15 | 16 | if (inputs[0].node != null) { 17 | objectToDestroy = cast(inputs[0].get()); 18 | } else { 19 | objectToDestroy = tree.object; 20 | } 21 | 22 | if (!objectToDestroy.isVisible(viewOffsetToDestroyAt, found.State.active.getCameraView())) { 23 | found.State.active.remove(objectToDestroy); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Sources/found/node/EventListenNode.hx: -------------------------------------------------------------------------------- 1 | package found.node; 2 | 3 | @:keep 4 | @:access(found.Trait) 5 | class EventListenNode extends LogicNode { 6 | 7 | public function new(tree:LogicTree) { 8 | super(tree); 9 | tree.notifyOnRemove(removeEvent); 10 | } 11 | override function run(from:Int) { 12 | addEvent(); 13 | } 14 | var eventName:String; 15 | function addEvent() { 16 | eventName = inputs[1].get(); 17 | if(eventName != "" && eventName != null){ 18 | Event.add(eventName,onEvent,tree.object.uid); 19 | } 20 | } 21 | function removeEvent(){ 22 | if(eventName != null) 23 | Event.remove(eventName); 24 | } 25 | function onEvent(){ 26 | runOutput(0); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Sources/found/node/EveryXNode.hx: -------------------------------------------------------------------------------- 1 | package found.node; 2 | 3 | import kha.Scheduler; 4 | 5 | class EveryXNode extends LogicNode { 6 | 7 | public function new(tree:LogicTree) { 8 | super(tree); 9 | tree.notifyOnInit(init); 10 | tree.notifyOnUpdate(update); 11 | } 12 | function init(){ 13 | everyX = inputs[0].get(); 14 | } 15 | var everyX:Float; 16 | var lastTime:Float; 17 | function update(dt:Float) { 18 | var dif = Scheduler.time() - lastTime; 19 | if(dif >= everyX){ 20 | lastTime = Scheduler.time(); 21 | runOutput(0); 22 | } 23 | 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Sources/found/node/FlipSpriteNode.hx: -------------------------------------------------------------------------------- 1 | package found.node; 2 | 3 | import found.anim.Sprite; 4 | import found.object.Object; 5 | 6 | @:keep 7 | class FlipSpriteNode extends LogicNode { 8 | public var selectedSpriteName:String = ""; 9 | 10 | public var value: Bool; 11 | var lastselectedSpriteName:String = ""; 12 | var selectedSprite:Sprite = null; 13 | 14 | public function new(tree:LogicTree) { 15 | super(tree); 16 | } 17 | 18 | override function run(from:Int) { 19 | var sprite:Null = inputs[1].get(); 20 | if(sprite != null && sprite.raw.type == "sprite_object"){ 21 | selectedSprite = cast(sprite); 22 | } 23 | else { 24 | selectedSprite = get(0); 25 | } 26 | var flipX = inputs[2].get(); 27 | var flipY = inputs[3].get(); 28 | if(selectedSprite != null){ 29 | selectedSprite.flip.x = flipX ? 1.0 : -1.0; 30 | selectedSprite.flip.y = flipY ? 1.0 : -1.0; 31 | } 32 | #if debug 33 | else{ 34 | var x = flipX != null; 35 | var y = flipY != null; 36 | error('The boolean value for flipX/Y: $x : $y and the sprite was $selectedSprite'); 37 | } 38 | #end 39 | } 40 | 41 | override function get(from:Int):Dynamic { 42 | if (selectedSprite == null || lastselectedSpriteName != selectedSpriteName) { 43 | lastselectedSpriteName = selectedSpriteName; 44 | selectedSprite = cast(State.active.getObject(selectedSpriteName),Sprite); 45 | } 46 | return selectedSprite; 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /Sources/found/node/FloatNode.hx: -------------------------------------------------------------------------------- 1 | package found.node; 2 | 3 | @:keep 4 | class FloatNode extends LogicNode { 5 | 6 | public var value: Float; 7 | 8 | public function new(tree: LogicTree, value = 0.0) { 9 | super(tree); 10 | this.value = value; 11 | } 12 | 13 | override function get(from: Int): Dynamic { 14 | if (inputs.length > 0) return inputs[0].get(); 15 | return value; 16 | } 17 | 18 | override function set(value: Dynamic) { 19 | if (inputs.length > 0) inputs[0].set(value); 20 | else this.value = value; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Sources/found/node/FloatToIntNode.hx: -------------------------------------------------------------------------------- 1 | package found.node; 2 | 3 | class FloatToIntNode extends LogicNode { 4 | 5 | public function new(tree: LogicTree) { 6 | super(tree); 7 | } 8 | 9 | override function get(from: Int): Dynamic { 10 | 11 | var float: Float = inputs[0].get(); 12 | 13 | return Math.round(float); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Sources/found/node/GateNode.hx: -------------------------------------------------------------------------------- 1 | package found.node; 2 | 3 | class GateNode extends LogicNode { 4 | 5 | public var operations: String; 6 | 7 | public function new(tree: LogicTree) { 8 | super(tree); 9 | } 10 | static var operationsNames:Array = ["Or","And","Equal","Less", "Less Equal","Greater", "Greater Equal"]; 11 | public static function getOperationsNames() { 12 | return operationsNames; 13 | } 14 | override function get(from:Int):Dynamic { 15 | var v1: Dynamic = inputs[0].get(); 16 | var v2: Dynamic = inputs[1].get(); 17 | var cond = false; 18 | 19 | switch (operations) { 20 | case "Equal": 21 | cond = v1 == v2; 22 | case "Greater": 23 | cond = v1 > v2; 24 | case "Greater Equal": 25 | cond = v1 >= v2; 26 | case "Less": 27 | cond = v1 < v2; 28 | case "Less Equal": 29 | cond = v1 <= v2; 30 | case "Or": 31 | for (i in 0...inputs.length) { 32 | if (inputs[i].get()) { 33 | cond = true; 34 | break; 35 | } 36 | } 37 | case "And": 38 | cond = true; 39 | for (i in 0...inputs.length) { 40 | if (!inputs[i].get()) { 41 | cond = false; 42 | break; 43 | } 44 | } 45 | } 46 | 47 | return cond; 48 | } 49 | } -------------------------------------------------------------------------------- /Sources/found/node/GetCenterNode.hx: -------------------------------------------------------------------------------- 1 | package found.node; 2 | 3 | import found.object.Object; 4 | 5 | class GetCenterNode extends LogicNode { 6 | override function get(from:Int):Dynamic { 7 | if (inputs[0].node == null) { 8 | return tree.object.center; 9 | } else { 10 | var object:Object = cast(inputs[0].get()); 11 | return object.center; 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Sources/found/node/GetForwardNode.hx: -------------------------------------------------------------------------------- 1 | package found.node; 2 | 3 | import found.math.Util; 4 | import kha.math.Vector2; 5 | import found.object.Object; 6 | 7 | class GetForwardNode extends LogicNode { 8 | #if debug_nodes 9 | public function new(tree:LogicTree) { 10 | super(tree); 11 | tree.notifyOnRender2D(debugDraw); 12 | } 13 | function debugDraw(g2:kha.graphics2.Graphics){ 14 | var pos:Vector2 = tree.object.center; 15 | var forward:Vector2 = this.get(0); 16 | forward = forward.mult(50); 17 | g2.color = 0xaa0000ff; 18 | g2.fillRect(pos.x + forward.x,pos.y + forward.y,10,10); 19 | g2.color = 0xffffffff; 20 | } 21 | #end 22 | override function get(from:Int):Dynamic { 23 | 24 | var angle = Util.degToRad(inputs[0].node == null ? 25 | tree.object.rotation.z: 26 | cast(inputs[0].get(),Object).rotation.z); 27 | return new Vector2(Math.cos(angle),Math.sin(angle)); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Sources/found/node/GetObjectNode.hx: -------------------------------------------------------------------------------- 1 | package found.node; 2 | 3 | import found.object.Object; 4 | 5 | @:keep 6 | class GetObjectNode extends LogicNode { 7 | public var selectedObjectName:String = ""; 8 | 9 | var lastSelectedObjectName:String = ""; 10 | var selectedObject:Object = null; 11 | 12 | public function new(tree:LogicTree) { 13 | super(tree); 14 | } 15 | 16 | override function run(from:Int) { 17 | get(0); 18 | runOutput(0); 19 | } 20 | 21 | override function get(from:Int):Dynamic { 22 | if (selectedObject == null || lastSelectedObjectName != selectedObjectName) { 23 | lastSelectedObjectName = selectedObjectName; 24 | selectedObject = State.active.getObject(selectedObjectName); 25 | } 26 | return selectedObject; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Sources/found/node/GetPositionNode.hx: -------------------------------------------------------------------------------- 1 | package found.node; 2 | 3 | import kha.math.Vector2; 4 | import found.object.Object; 5 | 6 | class GetPositionNode extends LogicNode { 7 | override function get(from:Int):Dynamic { 8 | 9 | if (inputs[0].node == null) { 10 | return new Vector2(tree.object.position.x,tree.object.position.y); 11 | } else { 12 | var object:Object = cast(inputs[0].get()); 13 | return new Vector2(object.position.x,object.position.y); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Sources/found/node/GetPropNode.hx: -------------------------------------------------------------------------------- 1 | package found.node; 2 | 3 | import kha.math.Vector2i; 4 | 5 | class GetPropNode extends LogicNode { 6 | public var classname:String; 7 | public var propertyName:String; 8 | override function get(from:Int):Dynamic { 9 | var value:Null = null; 10 | for(t in tree.object.raw.traits){ 11 | if(t.classname == classname && t.props != null){ 12 | var props = Trait.getProps(classname+tree.object.uid); 13 | for(p in props){ 14 | if(StringTools.contains(p,propertyName)){ 15 | var prop = p.split("~"); 16 | var type = Std.parseInt(prop[1]); 17 | value = toType(type,prop[2]); 18 | break; 19 | } 20 | } 21 | } 22 | } 23 | return value; 24 | } 25 | function toType(type:Trait.PropertyType,text:String){ 26 | var value:Any; 27 | switch(type){ 28 | case int: 29 | value = Std.parseInt(text); 30 | case bool: 31 | value = text == "1" ? true : false; 32 | case float: 33 | value = Std.parseFloat(text); 34 | case string: 35 | value = text; 36 | case vector2i: 37 | var values:Array = text.split("|"); 38 | value = new Vector2i(toType(int,values[0]),toType(int,values[1])); 39 | case vector2b: 40 | var values:Array = text.split("|"); 41 | value = new Vector2i(toType(int,values[0]),toType(int,values[1])); 42 | case vector2: 43 | var values:Array = text.split("|"); 44 | value = new Vector2i(toType(float,values[0]),toType(float,values[1])); 45 | } 46 | return value; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Sources/found/node/GetRandomObjectNode.hx: -------------------------------------------------------------------------------- 1 | package found.node; 2 | 3 | import found.math.Util; 4 | 5 | @:keep 6 | class GetRandomObjectNode extends LogicNode { 7 | public var listOfObjects:Array; 8 | 9 | 10 | public function new(tree:LogicTree) { 11 | super(tree); 12 | } 13 | 14 | override function get(from:Int):Dynamic { 15 | var names:Array = State.active.getObjectNames(); 16 | var choice:Int = listOfObjects[Util.randomInt(listOfObjects.length)]; 17 | return State.active.getObject(names[choice]); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Sources/found/node/GetRotationNode.hx: -------------------------------------------------------------------------------- 1 | package found.node; 2 | 3 | import found.object.Object; 4 | 5 | class GetRotationNode extends LogicNode { 6 | override function get(from:Int):Dynamic { 7 | if (inputs[0].node == null) { 8 | return tree.object.rotation.z; 9 | } else { 10 | var object:Object = cast(inputs[0].get()); 11 | return object.rotation.z; 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Sources/found/node/GetWidthHeightNode.hx: -------------------------------------------------------------------------------- 1 | package found.node; 2 | 3 | import kha.math.Vector2; 4 | import found.object.Object; 5 | 6 | class GetWidthHeightNode extends LogicNode { 7 | override function get(from:Int):Dynamic { 8 | 9 | if (inputs[0].node == null) { 10 | return new Vector2(tree.object.width,tree.object.height); 11 | } else { 12 | var object:Object = cast(inputs[0].get()); 13 | return new Vector2(object.width,object.height); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Sources/found/node/InitNode.hx: -------------------------------------------------------------------------------- 1 | package found.node; 2 | 3 | @:keep 4 | @:access(found.Trait) 5 | class InitNode extends LogicNode { 6 | 7 | public function new(tree:LogicTree) { 8 | super(tree); 9 | tree.notifyOnInit(init); 10 | } 11 | 12 | function init() { 13 | runOutput(0); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Sources/found/node/IntegerNode.hx: -------------------------------------------------------------------------------- 1 | package found.node; 2 | 3 | @:keep 4 | class IntegerNode extends LogicNode { 5 | 6 | public var value: Int; 7 | 8 | public function new(tree: LogicTree, value = 0) { 9 | super(tree); 10 | this.value = value; 11 | } 12 | 13 | override function get(from: Int): Dynamic { 14 | if (inputs.length > 0) return inputs[0].get(); 15 | return value; 16 | } 17 | 18 | override function set(value: Dynamic) { 19 | if (inputs.length > 0) inputs[0].set(value); 20 | else this.value = value; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Sources/found/node/IsFalseNode.hx: -------------------------------------------------------------------------------- 1 | package found.node; 2 | 3 | class IsFalseNode extends LogicNode{ 4 | 5 | public function new(tree: LogicTree){ 6 | super(tree); 7 | } 8 | 9 | override function run(from: Int){ 10 | var bool: Bool = inputs[1].get(); 11 | if(!bool) runOutput(0); 12 | } 13 | } -------------------------------------------------------------------------------- /Sources/found/node/IsObjectOutsideViewNode.hx: -------------------------------------------------------------------------------- 1 | package found.node; 2 | 3 | import found.object.Object; 4 | 5 | class IsObjectOutsideViewNode extends LogicNode { 6 | public function new(tree:LogicTree) { 7 | super(tree); 8 | 9 | tree.notifyOnUpdate(update); 10 | } 11 | 12 | function update(dt:Float) { 13 | var object:Object; 14 | var maxViewOffset:Int = inputs[1].get(); 15 | 16 | if (inputs[0].node != null) { 17 | object = cast(inputs[0].get()); 18 | } else { 19 | object = tree.object; 20 | } 21 | 22 | if (!object.isVisible(maxViewOffset, found.State.active.getCameraView())) { 23 | runOutput(0); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Sources/found/node/IsTrueNode.hx: -------------------------------------------------------------------------------- 1 | package found.node; 2 | 3 | class IsTrueNode extends LogicNode{ 4 | 5 | public function new(tree: LogicTree){ 6 | super(tree); 7 | } 8 | 9 | override function run(from: Int){ 10 | var bool: Bool = inputs[1].get(); 11 | if(bool) runOutput(0); 12 | } 13 | } -------------------------------------------------------------------------------- /Sources/found/node/JoinVec2Node.hx: -------------------------------------------------------------------------------- 1 | package found.node; 2 | 3 | class JoinVec2Node extends LogicNode { 4 | 5 | public function new(tree:LogicTree) { 6 | super(tree); 7 | } 8 | 9 | override function get(from: Int): Dynamic { 10 | var x:Float = inputs[0].get(); 11 | var y:Float = inputs[1].get(); 12 | 13 | return new kha.math.FastVector2(x, y); 14 | } 15 | } -------------------------------------------------------------------------------- /Sources/found/node/Logic.hx: -------------------------------------------------------------------------------- 1 | package found.node; 2 | 3 | import found.data.SceneFormat.LogicTreeData; 4 | 5 | @:keep 6 | class Logic { 7 | 8 | static var nodes:Array; 9 | static var links:Array; 10 | 11 | static var parsed_nodes:Array = null; 12 | static var parsed_labels:Map = null; 13 | static var nodeMap:Map; 14 | 15 | public static var enumTexts: String->Array = null; 16 | 17 | public static var packageNames:Array = ["found.node","gameplay"]; 18 | 19 | public static function getNode(id: Int): TNode { 20 | for (n in nodes) if (n.id == id) return n; 21 | return null; 22 | } 23 | 24 | public static function getLink(id: Int): TNodeLink { 25 | for (l in links) if (l.id == id) return l; 26 | return null; 27 | } 28 | 29 | public static function getInputLink(inp: TNodeSocket): TNodeLink { 30 | for (l in links) { 31 | if (l.to_id == inp.node_id) { 32 | var node = getNode(inp.node_id); 33 | if (node.inputs.length <= l.to_socket) return null; 34 | if (node.inputs[l.to_socket] == inp) return l; 35 | } 36 | } 37 | return null; 38 | } 39 | 40 | public static function getOutputLinks(out: TNodeSocket): Array { 41 | var res: Array = []; 42 | for (l in links) { 43 | if (l.from_id == out.node_id) { 44 | var node = getNode(out.node_id); 45 | if (node.outputs.length <= l.from_socket) continue; 46 | if (node.outputs[l.from_socket] == out) res.push(l); 47 | } 48 | } 49 | return res; 50 | } 51 | 52 | static function safesrc(s:String):String { 53 | return StringTools.replace(s, ' ', ''); 54 | } 55 | 56 | static function node_name(node:TNode):String { 57 | var s = safesrc(node.name) + node.id; 58 | return s; 59 | } 60 | 61 | static var tree: LogicTree; 62 | public static function parse(logicTree:LogicTreeData, onAdd = true): LogicTree { 63 | 64 | nodes = logicTree.nodeCanvas.nodes; 65 | links = logicTree.nodeCanvas.links; 66 | 67 | parsed_nodes = []; 68 | parsed_labels = new Map(); 69 | nodeMap = new Map(); 70 | var root_nodes = get_root_nodes(logicTree.nodeCanvas); 71 | 72 | tree = new LogicTree(); 73 | if (onAdd) { 74 | // tree.notifyOnAdd(function() { 75 | for (node in root_nodes) build_node(node); 76 | // }); 77 | } 78 | else { 79 | for (node in root_nodes) build_node(node); 80 | } 81 | return tree; 82 | } 83 | 84 | static function build_node(node: TNode): String { 85 | 86 | // Get node name 87 | var name = node_name(node); 88 | 89 | // Check if node already exists 90 | if (parsed_nodes.indexOf(name) != -1) { 91 | return name; 92 | } 93 | 94 | parsed_nodes.push(name); 95 | 96 | // Create node 97 | var v = createClassInstance(node.type, [tree]); 98 | nodeMap.set(name, v); 99 | 100 | // Expose button values in node class 101 | for (b in node.buttons) { 102 | if (b.type == "ENUM") { 103 | var arrayData = Std.is(b.data, Array); 104 | var texts = arrayData ? b.data : enumTexts(node.type); 105 | Reflect.setProperty(v, b.name, texts[b.default_value]); 106 | } 107 | else { 108 | Reflect.setProperty(v, b.name, b.default_value); 109 | } 110 | } 111 | 112 | // Create inputs 113 | var inp_node: LogicNode = null; 114 | var inp_from = 0; 115 | for (i in 0...node.inputs.length) { 116 | var inp = node.inputs[i]; 117 | // Is linked - find node 118 | var l = getInputLink(inp); 119 | if (l != null) { 120 | var n = getNode(l.from_id); 121 | var socket = n.outputs[l.from_socket]; 122 | inp_node = nodeMap.get(build_node(n)); 123 | for (i in 0...n.outputs.length) { 124 | if (n.outputs[i] == socket) { 125 | inp_from = i; 126 | break; 127 | } 128 | } 129 | } 130 | // Not linked - create node with default values 131 | else { 132 | inp_node = build_default_node(inp); 133 | inp_from = 0; 134 | } 135 | // Add input 136 | v.addInput(inp_node, inp_from); 137 | } 138 | 139 | // Create outputs 140 | for (out in node.outputs) { 141 | var outNodes:Array = []; 142 | var ls = getOutputLinks(out); 143 | if (ls != null && ls.length > 0) { 144 | for (l in ls) { 145 | var n = getNode(l.to_id); 146 | var out_name = build_node(n); 147 | outNodes.push(nodeMap.get(out_name)); 148 | } 149 | } 150 | // Not linked - create node with default values 151 | else { 152 | outNodes.push(build_default_node(out)); 153 | } 154 | // Add outputs 155 | v.addOutputs(outNodes); 156 | } 157 | 158 | return name; 159 | } 160 | 161 | static function get_root_nodes(node_group:TNodeCanvas):Array { 162 | var roots:Array = []; 163 | for (node in node_group.nodes) { 164 | // if (node.bl_idname == 'NodeUndefined') { 165 | // arm.log.warn('Undefined logic nodes in ' + node_group.name) 166 | // return [] 167 | // } 168 | var linked = false; 169 | 170 | for (out in node.outputs) { 171 | var ls = getOutputLinks(out); 172 | if (ls != null && ls.length > 0) { 173 | linked = true; 174 | break; 175 | } 176 | } 177 | if (!linked) { // Assume node with no connected outputs as roots 178 | roots.push(node); 179 | } 180 | } 181 | return roots; 182 | } 183 | 184 | static function build_default_node(inp:TNodeSocket): LogicNode { 185 | 186 | var v: LogicNode = null; 187 | 188 | if (inp.type == 'OBJECT') { 189 | v = createClassInstance('ObjectNode', [tree, inp.default_value]); 190 | } 191 | else if (inp.type == 'ANIMACTION') { 192 | v = createClassInstance('StringNode', [tree, inp.default_value]); 193 | } 194 | else if (inp.type == 'VECTOR2') { 195 | if (inp.default_value == null) inp.default_value = [0, 0]; // TODO 196 | v = createClassInstance('Vector2Node', [tree, inp.default_value[0], inp.default_value[1]]); 197 | } 198 | else if (inp.type == 'RGBA') { 199 | if (inp.default_value == null) inp.default_value = [0, 0, 0]; // TODO 200 | v = createClassInstance('ColorNode', [tree, inp.default_value[0], inp.default_value[1], inp.default_value[2], inp.default_value[3]]); 201 | } 202 | else if (inp.type == 'RGB') { 203 | if (inp.default_value == null) inp.default_value = [0, 0, 0]; // TODO 204 | v = createClassInstance('ColorNode', [tree, inp.default_value[0], inp.default_value[1], inp.default_value[2]]); 205 | } 206 | else if (inp.type == 'VALUE') { 207 | v = createClassInstance('FloatNode', [tree, inp.default_value]); 208 | } 209 | else if (inp.type == 'INT') { 210 | v = createClassInstance('IntegerNode', [tree, inp.default_value]); 211 | } 212 | else if (inp.type == 'BOOLEAN') { 213 | v = createClassInstance('BooleanNode', [tree, inp.default_value]); 214 | } 215 | else if (inp.type == 'STRING') { 216 | v = createClassInstance('StringNode', [tree, inp.default_value]); 217 | } 218 | else { // ACTION, ARRAY 219 | v = createClassInstance('NullNode', [tree]); 220 | } 221 | return v; 222 | } 223 | 224 | static function createClassInstance(className:String, args:Array):Dynamic { 225 | for(pname in packageNames){ 226 | var cname = Type.resolveClass(pname + '.' + className); 227 | if (cname == null) continue; 228 | return Type.createInstance(cname, args); 229 | } 230 | return null; 231 | } 232 | } 233 | 234 | typedef TNodeCanvas = { 235 | var name: String; 236 | var nodes: Array; 237 | var links: Array; 238 | } 239 | 240 | typedef TNode = { 241 | var id: Int; 242 | var name: String; 243 | var type: String; 244 | var x: Float; 245 | var y: Float; 246 | var inputs: Array; 247 | var outputs: Array; 248 | var buttons: Array; 249 | var color: Int; 250 | } 251 | 252 | typedef TNodeSocket = { 253 | var id: Int; 254 | var node_id: Int; 255 | var name: String; 256 | var type: String; 257 | var color: Int; 258 | var default_value: Dynamic; 259 | @:optional var min: Null; 260 | @:optional var max: Null; 261 | } 262 | 263 | typedef TNodeLink = { 264 | var id: Int; 265 | var from_id: Int; 266 | var from_socket: Int; 267 | var to_id: Int; 268 | var to_socket: Int; 269 | } 270 | 271 | typedef TNodeButton = { 272 | var name: String; 273 | var type: String; 274 | @:optional var output: Null; 275 | @:optional var default_value: Dynamic; 276 | @:optional var data: Dynamic; 277 | @:optional var min: Null; 278 | @:optional var max: Null; 279 | } 280 | -------------------------------------------------------------------------------- /Sources/found/node/LogicNode.hx: -------------------------------------------------------------------------------- 1 | package found.node; 2 | 3 | @:keep 4 | class LogicNode { 5 | 6 | var tree:LogicTree; 7 | var inputs:Array = []; 8 | var outputs:Array> = []; 9 | 10 | public function new(tree:LogicTree) { 11 | this.tree = tree; 12 | } 13 | 14 | public function addInput(node:LogicNode, from:Int) { 15 | inputs.push(new LogicNodeInput(node, from)); 16 | } 17 | 18 | public function addOutputs(nodes:Array) { 19 | outputs.push(nodes); 20 | } 21 | 22 | /** 23 | * Called when this node is activated. 24 | * @param from impulse index 25 | */ 26 | function run(from:Int) {} 27 | 28 | /** 29 | * Call to activate node connected to the output. 30 | * @param i output index 31 | */ 32 | function runOutput(i:Int) { 33 | if (i >= outputs.length) return; 34 | for (o in outputs[i]) { 35 | // Check which input activated the node 36 | for (j in 0...o.inputs.length) { 37 | if (o.inputs[j].node == this) { 38 | o.run(j); 39 | break; 40 | } 41 | } 42 | } 43 | } 44 | 45 | @:allow(found.node.LogicNodeInput) 46 | function get(from:Int):Dynamic { return this; } 47 | 48 | @:allow(found.node.LogicNodeInput) 49 | function set(value:Dynamic) { } 50 | } 51 | 52 | class LogicNodeInput { 53 | 54 | @:allow(found.node.LogicNode) 55 | var node:LogicNode; 56 | var from:Int; // Socket index 57 | 58 | public function new(node:LogicNode, from:Int) { 59 | this.node = node; 60 | this.from = from; 61 | } 62 | 63 | @:allow(found.node.LogicNode) 64 | function get():Dynamic { 65 | return node != null ? node.get(from):null; 66 | } 67 | 68 | @:allow(found.node.LogicNode) 69 | function set(value:Dynamic) { 70 | node.set(value); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /Sources/found/node/LogicTree.hx: -------------------------------------------------------------------------------- 1 | package found.node; 2 | 3 | @:keep 4 | class LogicTree extends found.Trait { 5 | 6 | public var loopBreak = false; // Trigger break from loop nodes 7 | 8 | public function new() { 9 | super(); 10 | } 11 | 12 | public function add() {} 13 | 14 | var paused = false; 15 | 16 | public function pause() { 17 | if (paused) return; 18 | paused = true; 19 | 20 | if (_update != null) for (f in _update) found.App.removeUpdate(f); 21 | } 22 | 23 | public function resume() { 24 | if (!paused) return; 25 | paused = false; 26 | 27 | if (_update != null) for (f in _update) found.App.notifyOnUpdate(f); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Sources/found/node/MathNode.hx: -------------------------------------------------------------------------------- 1 | package found.node; 2 | 3 | @:keep 4 | class MathNode extends LogicNode { 5 | 6 | public var operations: String; 7 | 8 | public function new(tree: LogicTree) { 9 | super(tree); 10 | } 11 | 12 | override function get(from: Int): Dynamic { 13 | 14 | var v1: Float = inputs[0].get(); 15 | var v2: Float = inputs[1].get(); 16 | var f = 0.0; 17 | 18 | switch (operations) { 19 | case "Add": f = v1 + v2; 20 | case "Subtract": f = v1 - v2; 21 | case "Multiply": f = v1 * v2; 22 | case "Divide": f = v1 / v2; 23 | } 24 | 25 | return f; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Sources/found/node/MouseCoordNode.hx: -------------------------------------------------------------------------------- 1 | package found.node; 2 | 3 | class MouseCoordNode extends LogicNode { 4 | var coords = new kha.math.FastVector2(); 5 | var move = new kha.math.FastVector2(); 6 | 7 | public function new(tree:LogicTree) { 8 | super(tree); 9 | } 10 | 11 | override function get(from:Int):Dynamic { 12 | var mouse = Input.getMouse(); 13 | 14 | if (from == 0) { 15 | coords.x = mouse.x+State.active.cam.position.x; 16 | coords.y = mouse.y+State.active.cam.position.y; 17 | return coords; 18 | } else if (from == 1) { 19 | move.x = mouse.movementX; 20 | move.y = mouse.movementY; 21 | return move; 22 | } else { 23 | return mouse.wheelDelta; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Sources/found/node/MultiEventNode.hx: -------------------------------------------------------------------------------- 1 | package found.node; 2 | 3 | 4 | 5 | class MultiEventNode extends LogicNode { 6 | 7 | public function new(tree:LogicTree) { 8 | super(tree); 9 | } 10 | 11 | override function run(from:Int) { 12 | runOutput(0); 13 | } 14 | } -------------------------------------------------------------------------------- /Sources/found/node/MultiplyVec2Node.hx: -------------------------------------------------------------------------------- 1 | package found.node; 2 | 3 | import kha.math.Vector2; 4 | 5 | class MultiplyVec2Node extends LogicNode { 6 | 7 | public function new(tree:LogicTree) { 8 | super(tree); 9 | } 10 | 11 | override function get(from: Int): Dynamic { 12 | var one:Vector2 = inputs[0].get(); 13 | var two:Float = inputs[1].get(); 14 | 15 | return one.mult(two); 16 | } 17 | } -------------------------------------------------------------------------------- /Sources/found/node/MultiplyVec2sNode.hx: -------------------------------------------------------------------------------- 1 | package found.node; 2 | 3 | import kha.math.Vector2; 4 | 5 | class MultiplyVec2sNode extends LogicNode { 6 | 7 | public function new(tree:LogicTree) { 8 | super(tree); 9 | } 10 | 11 | override function get(from: Int): Dynamic { 12 | var one:Vector2 = inputs[0].get(); 13 | var two:Vector2 = inputs[1].get(); 14 | 15 | return new Vector2(one.x * two.x, two.y * one.y); 16 | } 17 | } -------------------------------------------------------------------------------- /Sources/found/node/NullNode.hx: -------------------------------------------------------------------------------- 1 | package found.node; 2 | 3 | @:keep 4 | class NullNode extends LogicNode { 5 | 6 | public function new(tree: LogicTree) { 7 | super(tree); 8 | } 9 | 10 | override function get(from: Int): Dynamic { return null; } 11 | } 12 | -------------------------------------------------------------------------------- /Sources/found/node/OnAddNode.hx: -------------------------------------------------------------------------------- 1 | package found.node; 2 | 3 | @:keep 4 | @:access(found.Trait) 5 | class OnAddNode extends LogicNode { 6 | 7 | public function new(tree:LogicTree) { 8 | super(tree); 9 | tree.notifyOnAdd(add); 10 | } 11 | 12 | function add() { 13 | runOutput(0); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Sources/found/node/OnCollisionNode.hx: -------------------------------------------------------------------------------- 1 | package found.node; 2 | 3 | import found.object.Object; 4 | 5 | class OnCollisionNode extends LogicNode { 6 | var collisionListeners:Array; 7 | 8 | public function new(tree:LogicTree) { 9 | super(tree); 10 | 11 | collisionListeners = []; 12 | 13 | tree.notifyOnRemove(function() { 14 | tree.object.removeCollisionListeners(collisionListeners); 15 | }); 16 | } 17 | 18 | override function run(from:Int) { 19 | if (inputs[1].node != null) { 20 | var selectedCollidingObject:Object = cast(inputs[1].get()); 21 | var tileid:Null = inputs[2].get(); 22 | 23 | var collisionDef:CollisionDef = { 24 | objectName: selectedCollidingObject.raw.name, 25 | onEnter: onCollisionEnterEvent, 26 | onStay: onCollisionStayEvent, 27 | onExit: onCollisionExitEvent, 28 | tileId: tileid 29 | }; 30 | 31 | collisionListeners = collisionListeners.concat(tree.object.onCollision(collisionDef)); 32 | } 33 | #if debug 34 | else { 35 | error("On Collision node needs an object to check collisions with"); 36 | } 37 | #end 38 | } 39 | var lastBody:echo.Body; 40 | function onCollisionEnterEvent(body:echo.Body, otherBody:echo.Body, data:Array) { 41 | lastBody = otherBody; 42 | runOutput(0); 43 | } 44 | 45 | function onCollisionStayEvent(body:echo.Body, otherBody:echo.Body, data:Array) { 46 | lastBody = otherBody; 47 | runOutput(1); 48 | } 49 | 50 | function onCollisionExitEvent(body:echo.Body, otherBody:echo.Body) { 51 | lastBody = otherBody; 52 | runOutput(2); 53 | } 54 | 55 | @:access(found.anim.Tilemap) 56 | override function get(from:Int):Dynamic { 57 | return lastBody.object; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Sources/found/node/OnGamepadAxisInputNode.hx: -------------------------------------------------------------------------------- 1 | package found.node; 2 | 3 | import found.Input.Gamepad; 4 | 5 | class OnGamepadAxisInputNode extends LogicNode { 6 | public var selectedAxisName:String; 7 | 8 | var deadZone = 0.1; 9 | var selectedAxisValue:Float = 0; 10 | 11 | public function new(tree:LogicTree) { 12 | super(tree); 13 | 14 | tree.notifyOnUpdate(update); 15 | } 16 | 17 | function update(dt:Float) { 18 | var gamepadIndex:Int = inputs[0].get(); 19 | var gamepad:Gamepad = Input.getGamepad(gamepadIndex); 20 | 21 | if (gamepad == null) 22 | return; 23 | 24 | selectedAxisValue = gamepad.getAxisInformation(selectedAxisName).value; 25 | if (selectedAxisValue < deadZone && selectedAxisValue > -deadZone) { 26 | selectedAxisValue = 0; 27 | } 28 | 29 | if (gamepad.getAxisInformation(selectedAxisName).moved) { 30 | runOutput(0); 31 | } 32 | } 33 | 34 | override function get(from:Int):Dynamic { 35 | return selectedAxisValue; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Sources/found/node/OnGamepadButtonInputNode.hx: -------------------------------------------------------------------------------- 1 | package found.node; 2 | 3 | import found.Input.Gamepad; 4 | 5 | class OnGamepadButtonInputNode extends LogicNode { 6 | static var buttonEventTypes:Array = ["Pressed", "Down", "Released"]; 7 | 8 | public var selectedButtonEventType:String; 9 | public var selectedButtonName:String; 10 | 11 | var selectedButtonValue:Int = 0; 12 | 13 | public static function getButtonEventTypes() { 14 | return buttonEventTypes; 15 | } 16 | 17 | public function new(tree:LogicTree) { 18 | super(tree); 19 | 20 | tree.notifyOnUpdate(update); 21 | } 22 | 23 | function update(dt:Float) { 24 | var gamepadIndex:Int = inputs[0].get(); 25 | var gamepad:Gamepad = Input.getGamepad(gamepadIndex); 26 | var gamepadEventOccured:Bool = false; 27 | 28 | if (gamepad == null) 29 | return; 30 | 31 | switch (selectedButtonEventType) { 32 | case "Pressed": 33 | gamepadEventOccured = gamepad.started(selectedButtonName); 34 | case "Down": 35 | gamepadEventOccured = gamepad.down(selectedButtonName) > 0.0; 36 | case "Released": 37 | gamepadEventOccured = gamepad.released(selectedButtonName); 38 | } 39 | 40 | if (gamepadEventOccured) { 41 | selectedButtonValue = 1; 42 | runOutput(0); 43 | } else { 44 | selectedButtonValue = 0; 45 | } 46 | } 47 | 48 | override function get(from:Int):Dynamic { 49 | return selectedButtonValue; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Sources/found/node/OnKeyboardNode.hx: -------------------------------------------------------------------------------- 1 | package found.node; 2 | 3 | import kha.input.KeyCode; 4 | import found.Input.Keyboard; 5 | 6 | class OnKeyboardNode extends LogicNode { 7 | public var keyboardEventType:String; 8 | public var keyCode:KeyCode; 9 | 10 | static var keyboardEventTypes:Array = ["Pressed", "Down", "Released"]; 11 | var isDown:Bool = false; 12 | public static function getKeyboardEventTypes() { 13 | return keyboardEventTypes; 14 | } 15 | 16 | public function new(tree:LogicTree) { 17 | super(tree); 18 | 19 | tree.notifyOnUpdate(update); 20 | } 21 | var lastKey:KeyCode; 22 | var keyName:String; 23 | function update(dt:Float) { 24 | var keyboard:Keyboard = Input.getKeyboard(); 25 | var keyboardEventOccured:Bool = false; 26 | 27 | if(lastKey != keyCode){ 28 | keyName = Input.Keyboard.keyCode(keyCode); 29 | lastKey = keyCode; 30 | } 31 | 32 | switch (keyboardEventType) { 33 | case "Pressed": 34 | keyboardEventOccured = keyboard.started(keyName); 35 | case "Down": 36 | keyboardEventOccured = keyboard.down(keyName); 37 | case "Released": 38 | keyboardEventOccured = keyboard.released(keyName); 39 | } 40 | 41 | isDown = keyboardEventOccured; 42 | 43 | if (keyboardEventOccured) 44 | runOutput(0); 45 | } 46 | override function get(from:Int):Dynamic { 47 | return isDown; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Sources/found/node/OnMouseNode.hx: -------------------------------------------------------------------------------- 1 | package found.node; 2 | 3 | class OnMouseNode extends LogicNode { 4 | public var mouseEventType:String; 5 | public var mouseButton:String; 6 | 7 | static var mouseEventTypes:Array = ["Pressed", "Down", "Released", "Moved"]; 8 | 9 | public static function getMouseButtonEventTypes() { 10 | return mouseEventTypes; 11 | } 12 | 13 | public function new(tree:LogicTree) { 14 | super(tree); 15 | 16 | tree.notifyOnUpdate(update); 17 | } 18 | 19 | function update(dt:Float) { 20 | var mouse = Input.getMouse(); 21 | var mouseEventOccured:Bool = false; 22 | 23 | switch (mouseEventType) { 24 | case "Pressed": 25 | mouseEventOccured = mouse.started(mouseButton); 26 | case "Down": 27 | mouseEventOccured = mouse.down(mouseButton); 28 | case "Released": 29 | mouseEventOccured = mouse.released(mouseButton); 30 | case "Moved": 31 | mouseEventOccured = mouse.moved; 32 | } 33 | 34 | if (mouseEventOccured) runOutput(0); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Sources/found/node/ParseFloatNode.hx: -------------------------------------------------------------------------------- 1 | package found.node; 2 | 3 | class ParseFloatNode extends LogicNode { 4 | 5 | public function new(tree: LogicTree) { 6 | super(tree); 7 | } 8 | 9 | override function get(from: Int): Dynamic { 10 | 11 | var string: String = inputs[0].get(); 12 | 13 | return Std.parseFloat(string); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Sources/found/node/ParseIntNode.hx: -------------------------------------------------------------------------------- 1 | package found.node; 2 | 3 | class ParseIntNode extends LogicNode { 4 | 5 | public function new(tree: LogicTree) { 6 | super(tree); 7 | } 8 | 9 | override function get(from: Int): Dynamic { 10 | 11 | var string: String = inputs[0].get(); 12 | 13 | return Std.parseInt(string); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Sources/found/node/Platformer2DControllerNode.hx: -------------------------------------------------------------------------------- 1 | package found.node; 2 | 3 | import kha.input.KeyCode; 4 | import found.Input.Keyboard; 5 | import kha.math.Vector2; 6 | 7 | class Platformer2DControllerNode extends LogicNode { 8 | public var inputType:String; 9 | public var defaultLeftKeyCode:KeyCode; 10 | public var defaultRightKeyCode:KeyCode; 11 | public var defaultJumpKeyCode:KeyCode; 12 | 13 | public function new(tree:LogicTree) { 14 | super(tree); 15 | #if debug 16 | tree.notifyOnInit(function(){ 17 | if(tree.object.body == null){ 18 | warn("Platformer2DController needs a rigibody to work, on "+tree.object.name); 19 | } 20 | }); 21 | #end 22 | tree.notifyOnUpdate(update); 23 | } 24 | 25 | function update(dt:Float) { 26 | var keyboard:Keyboard = Input.getKeyboard(); 27 | var speed:Float = inputs[1].get(); 28 | var jumpForce:Float = inputs[2].get(); 29 | 30 | if (tree.object.body != null) { 31 | var movementInput:Vector2 = new Vector2(0, 0); 32 | 33 | if (inputType == "Use default input") { 34 | if (keyboard.down(Input.Keyboard.keyCode(defaultLeftKeyCode))) { 35 | movementInput.x += -1; 36 | } 37 | if (keyboard.down(Input.Keyboard.keyCode(defaultRightKeyCode))) { 38 | movementInput.x += 1; 39 | } 40 | } else { 41 | var move:Null = inputs[0].get(); 42 | if(move != null){ 43 | movementInput.x = move.x; 44 | } 45 | } 46 | 47 | tree.object.body.velocity.x = movementInput.x * speed; 48 | 49 | if (keyboard.started(Input.Keyboard.keyCode(defaultJumpKeyCode))) { 50 | tree.object.body.velocity.y = -jumpForce; 51 | } 52 | } 53 | 54 | runOutput(0); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Sources/found/node/PlayAnimationNode.hx: -------------------------------------------------------------------------------- 1 | package found.node; 2 | 3 | import found.object.Object; 4 | 5 | @:keep 6 | class PlayAnimationNode extends LogicNode { 7 | override function run(from:Int) { 8 | var selectedObject:Object = null; 9 | if (inputs[2].node == null) { 10 | selectedObject = tree.object; 11 | } else { 12 | selectedObject = cast(inputs[2].get()); 13 | } 14 | 15 | if (selectedObject.raw.type == "sprite_object" && inputs[1].get() != "") { 16 | var curSprite:found.anim.Sprite = cast(selectedObject); 17 | curSprite.setAnimationByName(inputs[1].get()); 18 | } else { 19 | if (selectedObject.raw.type != "sprite_object") { 20 | error("\"Play Animation\" node needs to be associated to a sprite_object"); 21 | } 22 | } 23 | 24 | runOutput(0); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Sources/found/node/PlayMusicNode.hx: -------------------------------------------------------------------------------- 1 | package found.node; 2 | 3 | import found.audio.Music; 4 | 5 | @:keep 6 | class PlayMusicNode extends LogicNode { 7 | public var loop:Bool = false; 8 | public var volume:Float = 1.0; 9 | 10 | override function run(from:Int) { 11 | var name:String = inputs[1].get(); 12 | Music.play(name,volume,loop); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Sources/found/node/PlaySfxNode.hx: -------------------------------------------------------------------------------- 1 | package found.node; 2 | 3 | import found.audio.Sfx; 4 | 5 | @:keep 6 | class PlaySfxNode extends LogicNode { 7 | public var volume:Float; 8 | 9 | override function run(from:Int) { 10 | var name:String = inputs[1].get(); 11 | Sfx.play(name,volume); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Sources/found/node/PrintNode.hx: -------------------------------------------------------------------------------- 1 | package found.node; 2 | 3 | @:keep 4 | class PrintNode extends LogicNode { 5 | 6 | public function new(tree:LogicTree) { 7 | super(tree); 8 | } 9 | 10 | override function run(from:Int) { 11 | var value:Dynamic = inputs[1].get(); 12 | 13 | trace(value); 14 | 15 | runOutput(0); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Sources/found/node/RadToDegNode.hx: -------------------------------------------------------------------------------- 1 | package found.node; 2 | 3 | class RadToDegNode extends LogicNode { 4 | 5 | public function new(tree: LogicTree) { 6 | super(tree); 7 | } 8 | 9 | override function get(from: Int): Dynamic { 10 | 11 | var radian: Float = inputs[0].get(); 12 | 13 | return radian * 180 / Math.PI; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Sources/found/node/RandFNode.hx: -------------------------------------------------------------------------------- 1 | package found.node; 2 | 3 | @:keep 4 | class RandFNode extends LogicNode { 5 | 6 | public function new(tree: LogicTree) { 7 | super(tree); 8 | } 9 | 10 | override function get(from: Int): Dynamic { 11 | var min: Float = inputs[0].get(); 12 | var max: Float = inputs[1].get(); 13 | return Math.random() * (max - min) + min; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Sources/found/node/RandINode.hx: -------------------------------------------------------------------------------- 1 | package found.node; 2 | 3 | @:keep 4 | class RandINode extends LogicNode { 5 | 6 | public function new(tree: LogicTree) { 7 | super(tree); 8 | } 9 | 10 | override function get(from: Int): Dynamic { 11 | var min: Int = inputs[0].get(); 12 | var max: Int = inputs[1].get(); 13 | return Math.round( Math.random() * (max - min) + min); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Sources/found/node/RotateTowardPositionNode.hx: -------------------------------------------------------------------------------- 1 | package found.node; 2 | 3 | import kha.math.Vector2; 4 | import kha.math.FastVector2; 5 | import found.object.Object; 6 | 7 | class RotateTowardPositionNode extends LogicNode { 8 | override function run(from:Int) { 9 | var fastTargetPosition:FastVector2 = inputs[2].get(); 10 | var targetPosition:Vector2 = new Vector2(fastTargetPosition.x, fastTargetPosition.y); 11 | 12 | var objectToRotate:Object; 13 | if (inputs[1].node == null) { 14 | objectToRotate = tree.object; 15 | } else { 16 | objectToRotate = cast(inputs[1].get()); 17 | } 18 | 19 | objectToRotate.rotateTowardPosition(targetPosition); 20 | 21 | runOutput(0); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Sources/found/node/SendEventNode.hx: -------------------------------------------------------------------------------- 1 | package found.node; 2 | 3 | import found.object.Object; 4 | 5 | @:keep 6 | @:access(found.Trait) 7 | class SendEventNode extends LogicNode { 8 | 9 | public function new(tree:LogicTree) { 10 | super(tree); 11 | 12 | } 13 | override function run(from:Int) { 14 | var eventName:String = inputs[1].get(); 15 | var object:Object = inputs[2].get(); 16 | var mask = object != null ? object.uid: -1; 17 | Event.send(eventName,mask); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Sources/found/node/SetCameraFollowTargetNode.hx: -------------------------------------------------------------------------------- 1 | package found.node; 2 | 3 | import found.object.Object; 4 | 5 | class SetCameraFollowTargetNode extends LogicNode { 6 | public function new(tree:LogicTree) { 7 | super(tree); 8 | } 9 | 10 | override function run(from:Int) { 11 | if (inputs[1].node == null) { 12 | State.active.cam.setCameraFollowTarget(tree.object); 13 | } else { 14 | var objectToFollow:Object = cast(inputs[1].get()); 15 | State.active.cam.setCameraFollowTarget(objectToFollow); 16 | } 17 | 18 | runOutput(0); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Sources/found/node/SetCameraTargetPositionNode.hx: -------------------------------------------------------------------------------- 1 | package found.node; 2 | 3 | import kha.math.Vector2; 4 | 5 | class SetCameraTargetPositionNode extends LogicNode { 6 | public function new(tree:LogicTree) { 7 | super(tree); 8 | } 9 | //@TODO: We should test this; I doubt it works. 10 | override function run(from:Int) { 11 | var position:Vector2 = inputs[1].get(); 12 | var camPos = State.active.cam.position; 13 | var direction = position.sub(camPos).normalized(); 14 | var move= new Vector2(); 15 | if(direction.x > 0) 16 | { 17 | move.x = position.x - camPos.x; 18 | } 19 | else 20 | { 21 | move.x = camPos.x - position.x; 22 | } 23 | if(direction.y > 0) 24 | { 25 | move.y = position.y - camPos.y; 26 | } 27 | else 28 | { 29 | move.y = camPos.y - position.y; 30 | } 31 | State.active.cam.move(move); 32 | 33 | runOutput(0); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Sources/found/node/SetObjectLocationNode.hx: -------------------------------------------------------------------------------- 1 | package found.node; 2 | 3 | import found.object.Object; 4 | import found.object.Object.MoveData; 5 | import kha.math.FastVector2; 6 | 7 | class SetObjectLocationNode extends LogicNode { 8 | var newPositionVector:FastVector2 = new FastVector2(); 9 | 10 | public function new(tree:LogicTree) { 11 | super(tree); 12 | } 13 | 14 | override function run(from:Int) { 15 | newPositionVector = inputs[2].get(); 16 | 17 | if (inputs[1].node == null) { 18 | tree.object.translate(setObjectLocation); 19 | } else { 20 | var objectToSetLocation:Object = cast(inputs[1].get()); 21 | objectToSetLocation.translate(setObjectLocation); 22 | } 23 | 24 | runOutput(0); 25 | } 26 | 27 | function setObjectLocation(data:MoveData) { 28 | data._positions.x = newPositionVector.x; 29 | data._positions.y = newPositionVector.y; 30 | return data; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Sources/found/node/SetPropNode.hx: -------------------------------------------------------------------------------- 1 | package found.node; 2 | 3 | import found.data.SceneFormat.TTrait; 4 | 5 | class SetPropNode extends LogicNode { 6 | 7 | public var classname:String; 8 | public var propertyName:String; 9 | 10 | public function new(tree: LogicTree) { 11 | super(tree); 12 | tree.notifyOnRemove(reset); 13 | } 14 | @:access(found.Trait) 15 | function reset(){ 16 | for(t in tree.object.raw.traits){ 17 | if(t.classname == classname && t.props != null){ 18 | Trait.props.set(classname+tree.object.uid,t.props); 19 | } 20 | } 21 | } 22 | @:access(found.Trait) 23 | override function run(from:Int) { 24 | var props = Trait.getProps(classname+tree.object.uid); 25 | var i = 0; 26 | for(p in props){ 27 | if(StringTools.contains(p,propertyName)){ 28 | var prop = p.split("~"); 29 | prop.pop(); 30 | var newValue = inputs[1].get(); 31 | prop.push('$newValue'); 32 | props[i] = prop.join('~'); 33 | Trait.props.set(classname+tree.object.uid,props); 34 | break; 35 | } 36 | i++; 37 | } 38 | 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Sources/found/node/SpawnObjectNode.hx: -------------------------------------------------------------------------------- 1 | package found.node; 2 | 3 | import found.object.Object; 4 | import kha.math.FastVector2; 5 | 6 | class SpawnObjectNode extends LogicNode { 7 | var selectedObjectToSpawn:Object; 8 | var spawnPosition:FastVector2 = new FastVector2(); 9 | var spawnRotation:Float = 0; 10 | var spawnedObjects:Array = new Array(); 11 | 12 | public function new(tree:LogicTree) { 13 | super(tree); 14 | 15 | tree.notifyOnRemove(function() { 16 | while (spawnedObjects.length > 0) 17 | found.State.active.remove(spawnedObjects.pop()); 18 | }); 19 | } 20 | 21 | override function run(from:Int) { 22 | spawnPosition = inputs[2].get(); 23 | spawnRotation = inputs[3].get(); 24 | 25 | if (inputs[1].node != null) { 26 | selectedObjectToSpawn = cast(inputs[1].get()); 27 | found.State.active.spawn(selectedObjectToSpawn.raw,function(spawnedObject:Object){ 28 | spawnedObjects.push(spawnedObject); 29 | 30 | spawnedObject.activate(); 31 | spawnedObject.translate(moveObjectToSpawnPoint); 32 | spawnedObject.rotate(rotateObjectToSpawnRotation); 33 | }); 34 | } 35 | #if debug 36 | else { 37 | error("Spawn Object node needs an object to spawn"); 38 | } 39 | #end 40 | 41 | runOutput(0);//@TODO: Should we only call this when we actually spawn an object ? 42 | } 43 | 44 | function moveObjectToSpawnPoint(data:MoveData) { 45 | data._positions.x = spawnPosition.x - selectedObjectToSpawn.width * 0.5; 46 | data._positions.y = spawnPosition.y - selectedObjectToSpawn.height * 0.5; 47 | return data; 48 | } 49 | 50 | function rotateObjectToSpawnRotation(data:RotateData) { 51 | data._rotations.z = spawnRotation; 52 | return data; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Sources/found/node/SplitVec2Node.hx: -------------------------------------------------------------------------------- 1 | package found.node; 2 | 3 | import kha.math.FastVector2; 4 | 5 | class SplitVec2Node extends LogicNode { 6 | 7 | public function new(tree:LogicTree) { 8 | super(tree); 9 | } 10 | 11 | override function get(from: Int): Dynamic { 12 | var vec2:FastVector2 = inputs[0].get(); 13 | 14 | if(from == 0){ 15 | return vec2.x; 16 | }else{ 17 | return vec2.y; 18 | } 19 | } 20 | 21 | } -------------------------------------------------------------------------------- /Sources/found/node/StringNode.hx: -------------------------------------------------------------------------------- 1 | package found.node; 2 | 3 | @:keep 4 | class StringNode extends LogicNode { 5 | 6 | public var value:String; 7 | 8 | public function new(tree:LogicTree, value = "") { 9 | super(tree); 10 | this.value = value; 11 | } 12 | 13 | override function get(from:Int):Dynamic { 14 | if (inputs.length > 0) return inputs[0].get(); 15 | return value; 16 | } 17 | 18 | override function set(value:Dynamic) { 19 | if (inputs.length > 0) inputs[0].set(value); 20 | else this.value = value; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Sources/found/node/TopDownControllerNode.hx: -------------------------------------------------------------------------------- 1 | package found.node; 2 | 3 | import kha.input.KeyCode; 4 | import found.Input.Keyboard; 5 | import hxmath.math.Vector2; 6 | 7 | class TopDownControllerNode extends LogicNode { 8 | public var inputType:String; 9 | public var defaultUpKeyCode:KeyCode; 10 | public var defaultDownKeyCode:KeyCode; 11 | public var defaultLeftKeyCode:KeyCode; 12 | public var defaultRightKeyCode:KeyCode; 13 | 14 | public function new(tree:LogicTree) { 15 | super(tree); 16 | 17 | #if debug 18 | tree.notifyOnInit(function(){ 19 | if (tree.object.body == null){ 20 | error("Top-down controller needs the object to have a Rigidbody"); 21 | } 22 | }); 23 | #end 24 | tree.notifyOnUpdate(update); 25 | } 26 | 27 | function update(dt:Float) { 28 | var keyboard:Keyboard = Input.getKeyboard(); 29 | var speed:Float = inputs[1].get(); 30 | 31 | if (tree.object.body != null) { 32 | var movementInput:Vector2 = new Vector2(0, 0); 33 | 34 | if (inputType == "Use default input") { 35 | if (keyboard.down(Input.Keyboard.keyCode(defaultUpKeyCode))) { 36 | movementInput.y += -1; 37 | } 38 | if (keyboard.down(Input.Keyboard.keyCode(defaultDownKeyCode))) { 39 | movementInput.y += 1; 40 | } 41 | if (keyboard.down(Input.Keyboard.keyCode(defaultLeftKeyCode))) { 42 | movementInput.x += -1; 43 | } 44 | if (keyboard.down(Input.Keyboard.keyCode(defaultRightKeyCode))) { 45 | movementInput.x += 1; 46 | } 47 | } else { 48 | movementInput.x = inputs[0].get().x; 49 | movementInput.y = inputs[0].get().y; 50 | } 51 | 52 | var normalizedMovementInput:Vector2 = movementInput.normalize(); 53 | tree.object.body.velocity = normalizedMovementInput * speed; 54 | } 55 | 56 | runOutput(0); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Sources/found/node/TranslateObjectNode.hx: -------------------------------------------------------------------------------- 1 | package found.node; 2 | 3 | import found.object.Object; 4 | import kha.math.FastVector2; 5 | 6 | class TranslateObjectNode extends LogicNode { 7 | var direction:FastVector2 = new FastVector2(); 8 | var speed:Float = 0; 9 | 10 | override function run(from:Int) { 11 | direction = inputs[2].get(); 12 | speed = inputs[3].get(); 13 | 14 | if (inputs[1].node == null) { 15 | tree.object.translate(translateObject); 16 | } else { 17 | var objectToTranslate:Object = cast(inputs[1].get()); 18 | objectToTranslate.translate(translateObject); 19 | } 20 | 21 | runOutput(0); 22 | } 23 | 24 | function translateObject(data:MoveData) { 25 | data._positions.x += direction.x * speed; 26 | data._positions.y += direction.y * speed; 27 | return data; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Sources/found/node/UpdateNode.hx: -------------------------------------------------------------------------------- 1 | package found.node; 2 | 3 | @:keep 4 | @:access(found.Trait) 5 | class UpdateNode extends LogicNode { 6 | 7 | public function new(tree:LogicTree) { 8 | super(tree); 9 | tree.notifyOnUpdate(update); 10 | } 11 | 12 | function update(dt:Float) { 13 | runOutput(0); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Sources/found/node/Vector2Node.hx: -------------------------------------------------------------------------------- 1 | package found.node; 2 | 3 | class Vector2Node extends LogicNode { 4 | var value = new kha.math.FastVector2(); 5 | 6 | public function new(tree:LogicTree, x:Null = null, y:Null = null) { 7 | super(tree); 8 | } 9 | 10 | override function get(from:Int):Dynamic { 11 | if(inputs[0] != null && inputs[1] != null){ 12 | value.x = inputs[0].get(); 13 | value.y = inputs[1].get(); 14 | 15 | if (from == 0) { 16 | return value; 17 | } 18 | 19 | return value.normalized(); 20 | } 21 | else { 22 | return null; 23 | } 24 | 25 | } 26 | 27 | override function set(value:Dynamic) { 28 | inputs[0].set(value.x); 29 | inputs[1].set(value.y); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Sources/found/node/WhileNode.hx: -------------------------------------------------------------------------------- 1 | package found.node; 2 | 3 | class WhileNode extends LogicNode{ 4 | 5 | public function new(tree: LogicTree){ 6 | super(tree); 7 | } 8 | 9 | override function run(from: Int){ 10 | var bool: Bool = inputs[1].get(); 11 | 12 | while(bool){ 13 | runOutput(0); 14 | 15 | if(tree.loopBreak){ 16 | tree.loopBreak = false; 17 | break; 18 | } 19 | } 20 | 21 | runOutput(1); 22 | } 23 | } -------------------------------------------------------------------------------- /Sources/found/node/data/LogicNode.hx: -------------------------------------------------------------------------------- 1 | package found.node.data; 2 | 3 | import kha.Color; 4 | import zui.Nodes.TNode; 5 | 6 | class LogicNode { 7 | public static inline function _tr(s: String) { return s; } 8 | public static var gate: TNode = { 9 | id: 0, 10 | name:_tr("Gate"), 11 | type: "GateNode", 12 | x: 200, 13 | y: 200, 14 | color: -4962746, 15 | inputs: [ 16 | { 17 | id: 1, 18 | node_id: 0, 19 | name:_tr("Dynamic"), 20 | type: "BOOLEAN", 21 | color: 0xff99FFDB, 22 | default_value: null 23 | }, 24 | { 25 | id: 2, 26 | node_id: 0, 27 | name:_tr("Dynamic"), 28 | type: "BOOLEAN", 29 | color: 0xff99FFDB, 30 | default_value: null 31 | } 32 | ], 33 | outputs: [ 34 | { 35 | id: 0, 36 | node_id: 0, 37 | name:_tr("Bool"), 38 | type: "BOOLEAN", 39 | color: -10822566, 40 | default_value: 0.0 41 | } 42 | ], 43 | buttons: [ 44 | { 45 | name:_tr("operations"), 46 | type: "ENUM", 47 | data: GateNode.getOperationsNames(), 48 | default_value: 0 49 | } 50 | ] 51 | } 52 | public static var branch: TNode = { 53 | id: 0, 54 | name:_tr("Branch"), 55 | type: "BranchNode", 56 | x: 200, 57 | y: 200, 58 | color: -4962746, 59 | inputs: [ 60 | { 61 | id: 0, 62 | node_id: 0, 63 | name:_tr("In"), 64 | type: "ACTION", 65 | color: 0xffaa4444, 66 | default_value: 0.0 67 | }, 68 | { 69 | id: 1, 70 | node_id: 0, 71 | name:_tr("Bool"), 72 | type: "BOOLEAN", 73 | color: -10822566, 74 | default_value: 0.0 75 | } 76 | ], 77 | outputs: [ 78 | { 79 | id: 0, 80 | node_id: 0, 81 | name:_tr("True"), 82 | type: "BOOL", 83 | color: -10822566, 84 | default_value: 0.0 85 | }, 86 | { 87 | id: 1, 88 | node_id: 0, 89 | name:_tr("False"), 90 | type: "BOOL", 91 | color: -10822566, 92 | default_value: 0.0 93 | } 94 | ], 95 | buttons: [] 96 | } 97 | public static var isFalse: TNode = { 98 | id: 0, 99 | name:_tr("Is False"), 100 | type: "IsFalseNode", 101 | x: 200, 102 | y: 200, 103 | color: -4962746, 104 | inputs: [ 105 | { 106 | id: 0, 107 | node_id: 0, 108 | name:_tr("In"), 109 | type: "ACTION", 110 | color: 0xffaa4444, 111 | default_value: 0.0 112 | }, 113 | { 114 | id: 1, 115 | node_id: 0, 116 | name:_tr("Bool"), 117 | type: "BOOLEAN", 118 | color: -10822566, 119 | default_value: 0.0 120 | } 121 | ], 122 | outputs: [ 123 | { 124 | id: 0, 125 | node_id: 0, 126 | name:_tr("Out"), 127 | type: "ACTION", 128 | color: 0xffaa4444, 129 | default_value: 0.0 130 | } 131 | ], 132 | buttons: [] 133 | } 134 | public static var isTrue: TNode = { 135 | id: 0, 136 | name:_tr("Is True"), 137 | type: "IsTrueNode", 138 | x: 200, 139 | y: 200, 140 | color: -4962746, 141 | inputs: [ 142 | { 143 | id: 0, 144 | node_id: 0, 145 | name:_tr("In"), 146 | type: "ACTION", 147 | color: 0xffaa4444, 148 | default_value: 0.0 149 | }, 150 | { 151 | id: 1, 152 | node_id: 0, 153 | name:_tr("Bool"), 154 | type: "BOOLEAN", 155 | color: -10822566, 156 | default_value: 0.0 157 | } 158 | ], 159 | outputs: [ 160 | { 161 | id: 0, 162 | node_id: 0, 163 | name:_tr("Out"), 164 | type: "ACTION", 165 | color: 0xffaa4444, 166 | default_value: 0.0 167 | } 168 | ], 169 | buttons: [] 170 | } 171 | public static var whileN: TNode = { 172 | id: 0, 173 | name:_tr("While"), 174 | type: "WhileNode", 175 | x: 200, 176 | y: 200, 177 | color: -4962746, 178 | inputs: [ 179 | { 180 | id: 0, 181 | node_id: 0, 182 | name:_tr("In"), 183 | type: "ACTION", 184 | color: 0xffaa4444, 185 | default_value: 0.0 186 | }, 187 | { 188 | id: 1, 189 | node_id: 0, 190 | name:_tr("Condition"), 191 | type: "BOOLEAN", 192 | color: -10822566, 193 | default_value: 0.0 194 | } 195 | ], 196 | outputs: [ 197 | { 198 | id: 0, 199 | node_id: 0, 200 | name:_tr("Loop"), 201 | type: "ACTION", 202 | color: 0xffaa4444, 203 | default_value: 0.0 204 | }, 205 | { 206 | id: 0, 207 | node_id: 0, 208 | name:_tr("Done"), 209 | type: "ACTION", 210 | color: 0xffaa4444, 211 | default_value: 0.0 212 | } 213 | ], 214 | buttons: [] 215 | } 216 | } 217 | -------------------------------------------------------------------------------- /Sources/found/node/data/MathNode.hx: -------------------------------------------------------------------------------- 1 | package found.node.data; 2 | 3 | import kha.Color; 4 | import zui.Nodes.TNode; 5 | 6 | class MathNode { 7 | public static inline function _tr(s: String) { return s; } 8 | public static var maths: TNode = { 9 | id: 0, 10 | name:_tr("Maths"), 11 | type: "MathNode", 12 | x: 200, 13 | y: 200, 14 | color: -4962746, 15 | inputs: [ 16 | { 17 | id: 0, 18 | node_id: 0, 19 | name:_tr("Value"), 20 | type: "VALUE", 21 | color: -10183681, 22 | default_value: 0.0, 23 | max: 100.0 24 | }, 25 | { 26 | id: 1, 27 | node_id: 0, 28 | name:_tr("Value"), 29 | type: "VALUE", 30 | color: -10183681, 31 | default_value: 0.0, 32 | max: 100.0 33 | } 34 | ], 35 | outputs: [ 36 | { 37 | id: 0, 38 | node_id: 0, 39 | name:_tr("value"), 40 | type: "Value", 41 | color: -10183681, 42 | default_value: 0.0 43 | } 44 | ], 45 | buttons: [ 46 | { 47 | name:_tr("operations"), 48 | type: "ENUM", 49 | data: ["Add", "Subtract", "Multiply", "Divide"], 50 | output: 0, 51 | default_value: 0 52 | } 53 | ] 54 | } 55 | 56 | public static var radtodeg: TNode = { 57 | id: 0, 58 | name:_tr("Radian to Degre"), 59 | type: "RadToDegNode", 60 | x: 200, 61 | y: 200, 62 | color: -4962746, 63 | inputs: [ 64 | { 65 | id: 0, 66 | node_id: 0, 67 | name:_tr("Rad"), 68 | type: "VALUE", 69 | color: -10183681, 70 | default_value: 0.0, 71 | max: 6.28 72 | } 73 | ], 74 | outputs: [ 75 | { 76 | id: 0, 77 | node_id: 0, 78 | name:_tr("Deg"), 79 | type: "Value", 80 | color: -10183681, 81 | default_value: 0.0 82 | } 83 | ], 84 | buttons: [] 85 | } 86 | 87 | public static var degtorad: TNode = { 88 | id: 0, 89 | name:_tr("Degree to Radian"), 90 | type: "DegToRadNode", 91 | x: 200, 92 | y: 200, 93 | color: -4962746, 94 | inputs: [ 95 | { 96 | id: 0, 97 | node_id: 0, 98 | name:_tr("Deg"), 99 | type: "VALUE", 100 | color: -10183681, 101 | default_value: 0.0, 102 | max: 360.0 103 | } 104 | ], 105 | outputs: [ 106 | { 107 | id: 0, 108 | node_id: 0, 109 | name:_tr("Rad"), 110 | type: "Value", 111 | color: -10183681, 112 | default_value: 0.0 113 | } 114 | ], 115 | buttons: [] 116 | } 117 | 118 | public static var randf: TNode = { 119 | id: 0, 120 | name:_tr("Random (Float)"), 121 | type: "RandFNode", 122 | x: 200, 123 | y: 200, 124 | color: -4962746, 125 | inputs: [ 126 | { 127 | id: 0, 128 | node_id: 0, 129 | name:_tr("Float"), 130 | type: "VALUE", 131 | color: -10183681, 132 | default_value: 0.0, 133 | max: 100.0 134 | }, 135 | { 136 | id: 1, 137 | node_id: 0, 138 | name:_tr("Float"), 139 | type: "VALUE", 140 | color: -10183681, 141 | default_value: 0.0, 142 | max: 100.0 143 | } 144 | ], 145 | outputs: [ 146 | { 147 | id: 0, 148 | node_id: 0, 149 | name:_tr("Float"), 150 | type: "Value", 151 | color: -10183681, 152 | default_value: 0.0 153 | } 154 | ], 155 | buttons: [] 156 | } 157 | 158 | public static var randi: TNode = { 159 | id: 0, 160 | name:_tr("Random (Int)"), 161 | type: "RandINode", 162 | x: 200, 163 | y: 200, 164 | color: -4962746, 165 | inputs: [ 166 | { 167 | id: 0, 168 | node_id: 0, 169 | name:_tr("Int"), 170 | type: "VALUE", 171 | color: -10183681, 172 | default_value: 0, 173 | max: 100, 174 | // precision: 1 175 | }, 176 | { 177 | id: 1, 178 | node_id: 0, 179 | name:_tr("Int"), 180 | type: "VALUE", 181 | color: -10183681, 182 | default_value: 0, 183 | max: 100, 184 | // precision: 1 185 | } 186 | ], 187 | outputs: [ 188 | { 189 | id: 0, 190 | node_id: 0, 191 | name:_tr("Int"), 192 | type: "Value", 193 | color: -10183681, 194 | default_value: 0 195 | } 196 | ], 197 | buttons: [] 198 | } 199 | } 200 | -------------------------------------------------------------------------------- /Sources/found/node/data/NodeCreator.hx: -------------------------------------------------------------------------------- 1 | package found.node.data; 2 | 3 | import haxe.Json; 4 | import zui.Nodes; 5 | import zui.Nodes.TNode; 6 | 7 | class NodeCreator { 8 | 9 | public static function createNode(node: TNode, nodes: Nodes, nodeCanvas: TNodeCanvas):TNode { 10 | var node:TNode = Json.parse(Json.stringify(node)); 11 | node.id = nodes.getNodeId(nodeCanvas.nodes); 12 | for (soc in node.inputs) { 13 | soc.id = nodes.getSocketId(nodeCanvas.nodes); 14 | soc.node_id = node.id; 15 | } 16 | for (soc in node.outputs) { 17 | soc.id = nodes.getSocketId(nodeCanvas.nodes); 18 | soc.node_id = node.id; 19 | } 20 | return node; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Sources/found/node/data/StdNode.hx: -------------------------------------------------------------------------------- 1 | package found.node.data; 2 | 3 | import kha.Color; 4 | import zui.Nodes.TNode; 5 | 6 | class StdNode { 7 | public static inline function _tr(s: String) { return s; } 8 | public static var parseInt: TNode = { 9 | id: 0, 10 | name:_tr("Parse Int"), 11 | type: "ParseIntNode", 12 | x: 200, 13 | y: 200, 14 | color: -4962746, 15 | inputs: [ 16 | { 17 | id: 0, 18 | node_id: 0, 19 | name:_tr("String"), 20 | type: "STRING", 21 | color: -4934476, 22 | default_value: "" 23 | } 24 | ], 25 | outputs: [ 26 | { 27 | id: 0, 28 | node_id: 0, 29 | name:_tr("Int"), 30 | type: "VALUE", 31 | color: -10183681, 32 | default_value: "" 33 | } 34 | ], 35 | buttons: [] 36 | } 37 | 38 | public static var parseFloat: TNode = { 39 | id: 0, 40 | name:_tr("Parse Float"), 41 | type: "ParseFloatNode", 42 | x: 200, 43 | y: 200, 44 | color: -4962746, 45 | inputs: [ 46 | { 47 | id: 0, 48 | node_id: 0, 49 | name:_tr("String"), 50 | type: "STRING", 51 | color: -4934476, 52 | default_value: "" 53 | } 54 | ], 55 | outputs: [ 56 | { 57 | id: 0, 58 | node_id: 0, 59 | name:_tr("Float"), 60 | type: "VALUE", 61 | color: -10183681, 62 | default_value: "" 63 | } 64 | ], 65 | buttons: [] 66 | } 67 | 68 | public static var floatToInt: TNode = { 69 | id: 0, 70 | name:_tr("Float to Int"), 71 | type: "FloatToIntNode", 72 | x: 200, 73 | y: 200, 74 | color: -4962746, 75 | inputs: [ 76 | { 77 | id: 0, 78 | node_id: 0, 79 | name:_tr("Float"), 80 | type: "VALUE", 81 | color: -10183681, 82 | default_value: "" 83 | } 84 | ], 85 | outputs: [ 86 | { 87 | id: 0, 88 | node_id: 0, 89 | name:_tr("Int"), 90 | type: "VALUE", 91 | color: -10183681, 92 | default_value: "" 93 | } 94 | ], 95 | buttons: [] 96 | } 97 | 98 | public static var print: TNode = { 99 | id: 0, 100 | name:_tr("Print"), 101 | type: "PrintNode", 102 | x: 200, 103 | y: 200, 104 | color: -4962746, 105 | inputs: [ 106 | { 107 | id: 0, 108 | node_id: 0, 109 | name:_tr("In"), 110 | type: "ACTION", 111 | color: 0xffaa4444, 112 | default_value: "" 113 | }, 114 | { 115 | id: 1, 116 | node_id: 0, 117 | name:_tr("Value"), 118 | type: "STRING", 119 | color: -4934476, 120 | default_value: "" 121 | } 122 | ], 123 | outputs: [ 124 | { 125 | id: 0, 126 | node_id: 0, 127 | name:_tr("Out"), 128 | type: "ACTION", 129 | color: 0xffaa4444, 130 | default_value: "" 131 | } 132 | ], 133 | buttons: [] 134 | } 135 | 136 | } 137 | -------------------------------------------------------------------------------- /Sources/found/node/data/VariableNode.hx: -------------------------------------------------------------------------------- 1 | package found.node.data; 2 | 3 | import kha.Color; 4 | import zui.Nodes.TNode; 5 | 6 | class VariableNode { 7 | public static inline function _tr(s: String) { return s; } 8 | public static var string:TNode = { 9 | id: 0, 10 | name:_tr("String"), 11 | type: "StringNode", 12 | x: 200, 13 | y: 200, 14 | color: -16067936, 15 | inputs: [ 16 | { 17 | id: 0, 18 | node_id: 0, 19 | name:_tr("String"), 20 | type: "STRING", 21 | color: -4934476, 22 | default_value: "" 23 | } 24 | ], 25 | outputs: [ 26 | { 27 | id: 0, 28 | node_id: 0, 29 | name:_tr("String"), 30 | type: "STRING", 31 | color: -4934476, 32 | default_value: "" 33 | } 34 | ], 35 | buttons: [] 36 | } 37 | 38 | public static var float:TNode = { 39 | id: 0, 40 | name:_tr("Float"), 41 | type: "FloatNode", 42 | x: 200, 43 | y: 200, 44 | color: -16067936, 45 | inputs: [ 46 | { 47 | id: 0, 48 | node_id: 0, 49 | name:_tr("Float"), 50 | type: "VALUE", 51 | color: -10183681, 52 | default_value: 0.0, 53 | max: 100.0 54 | } 55 | ], 56 | outputs: [ 57 | { 58 | id: 0, 59 | node_id: 0, 60 | name:_tr("Float"), 61 | type: "VALUE", 62 | color: -10183681, 63 | default_value: 0.0 64 | } 65 | ], 66 | buttons: [] 67 | } 68 | 69 | public static var int:TNode = { 70 | id: 0, 71 | name:_tr("Int"), 72 | type: "IntegerNode", 73 | x: 200, 74 | y: 200, 75 | color: -16067936, 76 | inputs: [ 77 | { 78 | id: 0, 79 | node_id: 0, 80 | name:_tr("Int"), 81 | type: "VALUE", 82 | color: -10183681, 83 | default_value: 0, 84 | max: 100, 85 | // precision: 1 86 | } 87 | ], 88 | outputs: [ 89 | { 90 | id: 0, 91 | node_id: 0, 92 | name:_tr("Int"), 93 | type: "VALUE", 94 | color: -10183681, 95 | default_value: 0 96 | } 97 | ], 98 | buttons: [] 99 | } 100 | 101 | public static var boolean:TNode = { 102 | id: 0, 103 | name:_tr("Boolean"), 104 | type: "BoolNode", 105 | x: 200, 106 | y: 200, 107 | color: -16067936, 108 | inputs: [ 109 | { 110 | id: 0, 111 | node_id: 0, 112 | name:_tr("Bool"), 113 | type: "BOOLEAN", 114 | color: -10822566, 115 | default_value: "" 116 | } 117 | ], 118 | outputs: [ 119 | { 120 | id: 0, 121 | node_id: 0, 122 | name:_tr("Bool"), 123 | type: "BOOLEAN", 124 | color: -10822566, 125 | default_value: "" 126 | } 127 | ], 128 | buttons: [] 129 | } 130 | 131 | public static var vector2:TNode = { 132 | id: 0, 133 | name:_tr("Vector2"), 134 | type: "Vector2Node", 135 | x: 200, 136 | y: 200, 137 | color: -16067936, 138 | inputs: [ 139 | { 140 | id: 0, 141 | node_id: 0, 142 | name:_tr("X"), 143 | type: "VALUE", 144 | color: -10183681, 145 | default_value: 0.0, 146 | max: 100.0 147 | }, 148 | { 149 | id: 1, 150 | node_id: 0, 151 | name:_tr("Y"), 152 | type: "VALUE", 153 | color: -10183681, 154 | default_value: 0.0, 155 | max: 100.0 156 | } 157 | ], 158 | outputs: [ 159 | { 160 | id: 0, 161 | node_id: 0, 162 | name:_tr("Vec2"), 163 | type: "VECTOR2", 164 | color: -7929601, 165 | default_value: [0.0, 0.0] 166 | }, 167 | { 168 | id: 1, 169 | node_id: 0, 170 | name:_tr("Normalised Vec2"), 171 | type: "VECTOR2", 172 | color: -7929601, 173 | default_value: [0.0, 0.0] 174 | } 175 | ], 176 | buttons: [] 177 | } 178 | public static var getProp:TNode = { 179 | id: 0, 180 | name:_tr("Get Property"), 181 | type: "GetPropNode", 182 | x: 200, 183 | y: 200, 184 | color: -16067936, 185 | inputs: [ 186 | ], 187 | outputs: [ 188 | { 189 | id: 0, 190 | node_id: 0, 191 | name:_tr("Prop"), 192 | type: "VALUE", 193 | color: -10183681, 194 | default_value: null 195 | } 196 | ], 197 | buttons: [ 198 | { 199 | name:_tr("classname"), 200 | type: "ENUM", 201 | data: [], 202 | output:0, 203 | default_value: 0 204 | }, 205 | { 206 | name:_tr("propertyName"), 207 | type: "ENUM", 208 | data: [], 209 | output: 0, 210 | default_value: 0 211 | } 212 | ] 213 | } 214 | public static var setProp:TNode = { 215 | id: 0, 216 | name:_tr("Set Property"), 217 | type: "SetPropNode", 218 | x: 200, 219 | y: 200, 220 | color: -16067936, 221 | inputs: [ 222 | { 223 | id: 0, 224 | node_id: 0, 225 | name:_tr("In"), 226 | type: "ACTION", 227 | color: 0xffaa4444, 228 | default_value: "" 229 | }, 230 | { 231 | id: 0, 232 | node_id: 0, 233 | name:_tr("Value"), 234 | type: "VALUE", 235 | color: -10183681, 236 | default_value: null 237 | } 238 | ], 239 | outputs: [ 240 | 241 | ], 242 | buttons: [ 243 | { 244 | name:_tr("classname"), 245 | type: "ENUM", 246 | data: [], 247 | output:0, 248 | default_value: 0 249 | }, 250 | { 251 | name:_tr("propertyName"), 252 | type: "ENUM", 253 | data: [], 254 | output: 0, 255 | default_value: 0 256 | } 257 | ] 258 | } 259 | } 260 | -------------------------------------------------------------------------------- /Sources/found/object/Action.hx: -------------------------------------------------------------------------------- 1 | package found.object; 2 | 3 | import kha.Worker; 4 | 5 | class Action { 6 | public static function main():Void { 7 | #if kha_kore 8 | kha.Worker.notifyWorker(function(message:Dynamic){ 9 | var actions:Array = message.actions; 10 | for(i in 0...actions.length){ 11 | kha.Worker.postFromWorker({out: message.actions[i](message.datas[i]), uid: message.uids[i],set: message.sets[i]}); 12 | } 13 | }); 14 | #end 15 | } 16 | } -------------------------------------------------------------------------------- /Sources/found/object/Camera.hx: -------------------------------------------------------------------------------- 1 | package found.object; 2 | 3 | 4 | import found.math.Util; 5 | import kha.math.FastMatrix3; 6 | import kha.Canvas; 7 | import kha.math.Vector2; 8 | import found.data.SceneFormat.TCameraData; 9 | 10 | class Camera extends Object { 11 | public var origin(get,null):Vector2 = new Vector2(); 12 | function get_origin(){ 13 | origin.x = width * 0.5; 14 | origin.y = height * 0.5; 15 | return origin; 16 | } 17 | 18 | var camSpeedX:Float = 3; 19 | var camSpeedY:Float = 5; 20 | 21 | public var offsetX:Float = 15; 22 | public var offsetY:Float = 25; 23 | 24 | public var zoom:Float = 1.0; 25 | var lastParallax = 1.0; 26 | public function getTransformation(parallax:Float) { 27 | lastParallax = parallax; 28 | var center = origin; 29 | var transformation = FastMatrix3.identity(); 30 | transformation.setFrom(FastMatrix3.scale(zoom,zoom).multmat(transformation)); 31 | transformation.setFrom(FastMatrix3.translation(center.x, center.y).multmat(FastMatrix3.rotation(-Util.degToRad(rotation.z))).multmat(FastMatrix3.translation(-center.x, -center.y)).multmat(transformation)); 32 | transformation.setFrom(FastMatrix3.translation(center.x, center.y).multmat(transformation)); 33 | transformation.setFrom(FastMatrix3.translation(-position.x*parallax, -position.y*parallax).multmat(transformation)); 34 | return transformation; 35 | } 36 | 37 | var target:Null = null; 38 | public function new(data:TCameraData) { 39 | super(data); 40 | if (data.offsetX != null) 41 | offsetX = data.offsetX; 42 | if (data.offsetY != null) 43 | offsetY = data.offsetY; 44 | if (data.speedX != null) 45 | camSpeedX = data.speedX; 46 | if (data.speedY != null) 47 | camSpeedY = data.speedY; 48 | this.width = data.width < 1.0 ? Found.WIDTH : data.width; 49 | this.height = data.height < 1.0 ? Found.HEIGHT : data.height; 50 | } 51 | 52 | public function move(movement:Vector2,considerRotation = false) { 53 | if (considerRotation) 54 | { 55 | movement = cast(FastMatrix3.rotation(Util.degToRad(rotation.z)).multvec(cast(movement))); 56 | } 57 | this.position.x += movement.x; 58 | this.position.y += movement.y; 59 | 60 | 61 | } 62 | 63 | public function lookAt(obj:Object){ 64 | this.position.x = (obj.position.x + obj.width * 0.5) * zoom; 65 | this.position.y = (obj.position.y + obj.height * 0.5) * zoom; 66 | } 67 | public override function moveTowards(target:Vector2, step:Float) { 68 | warn("Use the move function instead for the camera."); 69 | } 70 | 71 | public function setCameraFollowTarget(p:Object) { 72 | target = p; 73 | } 74 | 75 | public function worldToScreen( worldPosition:Vector2, ?parallaxSpeed:Float = null ):Vector2 76 | { 77 | var speed = parallaxSpeed != null ? parallaxSpeed : lastParallax; 78 | return cast(getTransformation(speed).multvec(cast(worldPosition))); 79 | } 80 | 81 | public function screenToWorld(screenPosition:Vector2, ?parallaxSpeed:Float = null):Vector2 82 | { 83 | var speed = parallaxSpeed != null ? parallaxSpeed : lastParallax; 84 | return cast(getTransformation(speed).inverse().multvec(cast(screenPosition))); 85 | } 86 | 87 | public override function render(canvas:Canvas) { 88 | if (!Scene.ready) 89 | return; 90 | super.render(canvas); 91 | #if debug 92 | canvas.g2.color = kha.Color.Red; 93 | var center = origin; 94 | canvas.g2.drawRect(center.x, center.y, offsetX, offsetX); 95 | canvas.g2.color = kha.Color.White; 96 | #end 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /Sources/found/object/Collidable.hx: -------------------------------------------------------------------------------- 1 | package found.object; 2 | 3 | import echo.data.Data.CollisionData; 4 | import echo.Body; 5 | 6 | interface Collidable { 7 | private function onEnter(me:Body,other:Body, data:Array):Void; 8 | private function onStay(me:Body,other:Body, data:Array):Void; 9 | private function onExit(me:Body,other:Body):Void; 10 | } -------------------------------------------------------------------------------- /Sources/found/object/Executor.hx: -------------------------------------------------------------------------------- 1 | package found.object; 2 | 3 | import kha.Scheduler; 4 | #if !kha_krom 5 | import kha.Worker; 6 | #end 7 | class Executor { 8 | public static var executors:Array> = []; 9 | public var threads:Int = 2; 10 | var field:String = ""; 11 | var actions:ArrayT> = []; 12 | var datas:Array = []; 13 | var uids:Array = []; 14 | var sets:ArrayVoid> = []; 15 | #if (!kha_krom && !android) 16 | var workers:Array = []; 17 | var rest:Worker; 18 | #end 19 | public function new(p_field:String){ 20 | #if debug 21 | if(Scheduler.time() == 0) warn("You cant create Executors before the Scheduler has been created.Solution: Create your executor in the new function of your class."); 22 | #end 23 | field = p_field; 24 | #if kha_kore 25 | for(i in 0...threads){ 26 | var worker = Worker.create(found.object.Action); 27 | worker.notify(function(d:Dynamic){ 28 | set(d); 29 | }); 30 | workers.push(worker); 31 | } 32 | rest = Worker.create(found.object.Action); 33 | rest.notify(function(d:Dynamic){ 34 | set(d); 35 | }); 36 | #end 37 | executors.push(this); 38 | 39 | } 40 | function set(data:Dynamic) { 41 | //@:Incomplete: we should test that the condition after the || is needed 42 | // It was added to potentially avoid threaded calls trying to set the 43 | //data after the scene has changed 44 | if(!found.Scene.ready || State.active._entities.length == 0) return; 45 | 46 | var modified:Array = Reflect.field(Object,field); 47 | if(Reflect.hasField(data.out,field)){ 48 | modified[data.uid] = Reflect.field(data.out,field); 49 | } 50 | else{ 51 | modified[data.uid] = data.out; 52 | } 53 | data.set(data.out); 54 | #if editor 55 | if(found.App.editorui.inspector != null) 56 | found.App.editorui.inspector.updateField(data.uid,field,modified[data.uid]); 57 | #end 58 | } 59 | public function add(func:T->T,data:T,uid:Int,set:T->Void){ 60 | actions.push(func); 61 | datas.push(data); 62 | uids.push(uid); 63 | sets.push(set); 64 | } 65 | // @:Incomplete. We should use webworkers in the futur for html5(fixing khamake creation of workers) 66 | // And look at adding multithreading in Krom. As of now this would take too much time 67 | // So we will just have it singlethreaded on these targets since they are not the 68 | // final targets anyways 69 | public function execute(){ 70 | if(!found.Scene.ready || State.active._entities.length == 0) return; 71 | #if (kha_html5 || kha_krom || android) 72 | for(i in 0...actions.length){ 73 | set({out: actions[i](datas[i]),uid: uids[i], set: sets[i]}); 74 | } 75 | actions = []; 76 | datas= []; 77 | uids = []; 78 | sets = []; 79 | #else 80 | if(actions.length % threads == 0){ 81 | var len:Int = Std.int(actions.length/threads); 82 | for(i in 0...threads){ 83 | workers[i].post({actions: actions.splice(0,len),datas: datas.splice(0,len), uids: uids.splice(0,len), sets: sets.splice(0,len)}); 84 | } 85 | } 86 | else{ 87 | var len:Int = Math.ceil(actions.length/threads); 88 | var rlen = actions.length % threads; 89 | for(i in 0...threads){ 90 | if(actions.length < len)continue; 91 | workers[i].post({actions: actions.splice(0,len),datas: datas.splice(0,len), uids: uids.splice(0,len), sets: sets.splice(0,len)}); 92 | } 93 | if(len > 1) 94 | rest.post({actions: actions.splice(0,rlen),datas: datas.splice(0,rlen), uids: uids.splice(0,rlen), sets: sets.splice(0,rlen)}); 95 | } 96 | #end 97 | } 98 | } -------------------------------------------------------------------------------- /Sources/found/particle/Emitter.hx: -------------------------------------------------------------------------------- 1 | package found.particle; 2 | 3 | import kha.Canvas; 4 | using kha.graphics2.GraphicsExtension; 5 | import kha.Color; 6 | import kha.Assets; 7 | 8 | import found.Found; 9 | import found.object.Object; 10 | import found.math.Util; 11 | 12 | class Emitter extends Object { 13 | public var arParticle:Array; 14 | public var amount:Int; 15 | public var power = 3.0; 16 | 17 | public function new(?amount:Int = 3, ?power:Float = 3.0){ 18 | super(0, 0, 0, 0); 19 | this.amount = amount; 20 | this.power = power; 21 | 22 | arParticle = []; 23 | } 24 | 25 | override public function update(dt:Float){ 26 | super.update(dt); 27 | var p = arParticle.length; 28 | while (p --> 0){ 29 | arParticle[p].update(dt); 30 | if (arParticle[p].position.x <= 0 || arParticle[p].position.x >= Found.BUFFERWIDTH || arParticle[p].position.y <= 0 || arParticle[p].position.y >= Found.BUFFERHEIGHT){ 31 | arParticle.splice(p, 1); 32 | } 33 | } 34 | } 35 | 36 | override public function render(canvas:Canvas){ 37 | super.render(canvas); 38 | for (particle in arParticle){ 39 | particle.render(canvas); 40 | } 41 | } 42 | 43 | public function spawn(?x:Float, ?y:Float, ?width:Float = 2.0, ?height:Float = 2.0){ 44 | for (i in 0 ... amount){ 45 | var particle = new Particle(x, y, width, height); 46 | // particle.acceleration = -0.5; 47 | // particle.velocity.x = Util.randomRangeFloat(-power, power); 48 | // particle.velocity.y = Util.randomRangeFloat(-power, power); 49 | arParticle.push(particle); 50 | } 51 | } 52 | 53 | public function empty(){ 54 | arParticle = []; 55 | } 56 | } -------------------------------------------------------------------------------- /Sources/found/particle/Particle.hx: -------------------------------------------------------------------------------- 1 | package found.particle; 2 | 3 | 4 | import kha.Canvas; 5 | import kha.Color; 6 | 7 | import found.object.Object; 8 | 9 | class Particle extends Object { 10 | 11 | public function new(?x:Float, ?y:Float, ?width:Float, ?height:Float){ 12 | super(x, y, width, height); 13 | } 14 | 15 | override public function update(dt:Float){ 16 | super.update(dt); 17 | 18 | // velocity.y -= acceleration; 19 | } 20 | 21 | override public function render(canvas:Canvas){ 22 | super.render(canvas); 23 | canvas.g2.color = Color.White; 24 | canvas.g2.fillRect(position.x, position.y, width, height); 25 | } 26 | } -------------------------------------------------------------------------------- /Sources/found/tool/Follower.hx: -------------------------------------------------------------------------------- 1 | package found.tool; 2 | 3 | import found.object.Entity; 4 | 5 | class Follower { 6 | public var speed = 0.6; 7 | public var range = 200.00; 8 | private var _rate = 1.0; 9 | private var _x:Float = 0; 10 | private var _y:Float = 0; 11 | 12 | public function new(){} 13 | 14 | public function update(entity01:Entity, entity02:Entity){ 15 | var distanceX:Float = entity01.position.x - entity02.position.x; 16 | var distanceY:Float = entity01.position.y - entity02.position.y; 17 | 18 | var total = Math.sqrt(distanceX * distanceX + distanceY * distanceY); 19 | 20 | if (total <= range){ 21 | distanceX = _rate * distanceX / total; 22 | distanceY = _rate * distanceY / total; 23 | 24 | _x += distanceX; 25 | _y += distanceY; 26 | 27 | var totalDistance = Math.sqrt(_x * _x + _y * _y); 28 | 29 | _x = speed * _x / totalDistance; 30 | _y = speed * _y / totalDistance; 31 | 32 | entity02.position.x += _x; 33 | entity02.position.y += _y; 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /Sources/found/tool/Log.hx: -------------------------------------------------------------------------------- 1 | package found.tool; 2 | 3 | import found.math.Util.Cli; 4 | 5 | class Log { 6 | static var oldTrace:Dynamic->Null->Void; 7 | static var customLogs:ArrayNull->Void> = []; 8 | public static function warn(v:Dynamic, ?infos:Null) { 9 | if(oldTrace == null) 10 | initialize(); 11 | if(infos != null){ 12 | log(Cli.byellow+"WARNING: "+Cli.reset+v,infos); 13 | if(infos.customParams == null) 14 | infos.customParams = []; 15 | infos.customParams.push("Warn"); 16 | for(logger in customLogs){ 17 | logger(v,infos); 18 | } 19 | } 20 | else { 21 | log(Cli.byellow+"WARNING: "+Cli.reset+v); 22 | } 23 | } 24 | public static function error(v:Dynamic, ?infos:Null) { 25 | if(oldTrace == null) 26 | initialize(); 27 | if(infos != null){ 28 | log(Cli.bred+"ERROR: "+Cli.reset+v,infos); 29 | if(infos.customParams == null) 30 | infos.customParams = []; 31 | infos.customParams.push("Error"); 32 | for(logger in customLogs){ 33 | logger(v,infos); 34 | } 35 | } 36 | else { 37 | log(Cli.bred+"ERROR: "+Cli.reset+v); 38 | } 39 | 40 | } 41 | static function log(v:Dynamic, ?infos:Null){ 42 | oldTrace(v,infos); 43 | var t:String = v; 44 | if(!Std.isOfType(v,String) || (!StringTools.contains(t,"ERROR") && !StringTools.contains(t,"WARNING"))){ 45 | for(logger in customLogs){ 46 | logger(v,infos); 47 | } 48 | } 49 | } 50 | static function initialize() { 51 | oldTrace = haxe.Log.trace; 52 | haxe.Log.trace = log; 53 | 54 | } 55 | public static function addCustomLogging(logger:Dynamic->Null->Void){ 56 | if(oldTrace == null) 57 | initialize(); 58 | customLogs.push(logger); 59 | } 60 | } -------------------------------------------------------------------------------- /Sources/found/tool/Loop.hx: -------------------------------------------------------------------------------- 1 | package found.tool; 2 | 3 | class Loop { 4 | private var _start:Int; 5 | private var _end:Int; 6 | private var _step:Int; 7 | 8 | public function new(start:Int, end:Int, step:Int){ 9 | this._start = start; 10 | this._end = end; 11 | this._step = step; 12 | } 13 | 14 | public inline function hasNext() return _start < _end; 15 | public inline function next() return (_start += _step) - _step; 16 | } -------------------------------------------------------------------------------- /Sources/found/tool/OneOf.hx: -------------------------------------------------------------------------------- 1 | package found.tool; 2 | 3 | import haxe.ds.Either; 4 | 5 | abstract OneOf(Either) from Either to Either { 6 | @:from inline static function fromA(a:A):OneOf { 7 | return Left(a); 8 | } 9 | @:from inline static function fromB(b:B):OneOf { 10 | return Right(b); 11 | } 12 | 13 | @:to inline function toA():Null return switch(this) { 14 | case Left(a): a; 15 | default: null; 16 | } 17 | @:to inline function toB():Null return switch(this) { 18 | case Right(b): b; 19 | default: null; 20 | } 21 | } -------------------------------------------------------------------------------- /Sources/found/tool/Pool.hx: -------------------------------------------------------------------------------- 1 | package found.tool; 2 | 3 | import haxe.Constraints.Constructible; 4 | import kha.Canvas; 5 | import found.object.Object; 6 | import found.data.SceneFormat; 7 | 8 | @:generic 9 | class PoolVoid> & Object)> extends Object { 10 | public var entity:Array; 11 | public var max:Int; 12 | 13 | private var objectData:TObj; 14 | private var _count:Int = 0; 15 | 16 | public function new(data:TPool, objectData:TObj) { 17 | super(data); 18 | 19 | this.max = data.maxAmount; 20 | this.objectData = objectData; 21 | entity = []; 22 | } 23 | 24 | override public function update(dt:Float) { 25 | var i:Int = 0; 26 | while (i < entity.length) { 27 | var member = entity[i]; 28 | if (member != null) { 29 | if (member.active) { 30 | member.update(dt); 31 | if (!member.active) { 32 | if (i < _count) { 33 | _count = i; 34 | } 35 | } 36 | } 37 | } 38 | i++; 39 | } 40 | super.update(dt); 41 | } 42 | 43 | override public function render(canvas:Canvas) { 44 | for (member in entity) { 45 | if (member != null && member.active) { 46 | member.render(canvas); 47 | } 48 | } 49 | } 50 | 51 | private function first():Int { 52 | var i = _count; 53 | while (i < entity.length + _count) { 54 | var h = i % entity.length; 55 | if (entity[h] == null || !entity[h].active) { 56 | if (i < entity.length) { 57 | _count++; 58 | } 59 | } 60 | i++; 61 | } 62 | return -1; 63 | } 64 | 65 | public function add():O { 66 | var object:O = new O(objectData); 67 | var full:Bool = entity.length >= max; 68 | 69 | if (!full) { 70 | entity.push(object); 71 | } else { 72 | var index = first(); 73 | entity[index] = object; 74 | } 75 | 76 | return object; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /Sources/found/tool/Runner.hx: -------------------------------------------------------------------------------- 1 | package found.tool; 2 | 3 | import found.object.Entity; 4 | 5 | class Runner { 6 | public var speed = 0.6; 7 | public var range = 200.00; 8 | private var _rate = 1.0; 9 | private var _x:Float = 0; 10 | private var _y:Float = 0; 11 | 12 | public function new(){} 13 | 14 | public function update(entity01:Entity, entity02:Entity){ 15 | var distanceX:Float = entity01.position.x - entity02.position.x; 16 | var distanceY:Float = entity01.position.y - entity02.position.y; 17 | 18 | var total = Math.sqrt(distanceX * distanceX + distanceY * distanceY); 19 | 20 | if (total <= range){ 21 | distanceX = _rate * distanceX / total; 22 | distanceY = _rate * distanceY / total; 23 | 24 | _x -= distanceX; 25 | _y -= distanceY; 26 | 27 | var totalDistance = Math.sqrt(_x * _x + _y * _y); 28 | 29 | _x = speed * _x / totalDistance; 30 | _y = speed * _y / totalDistance; 31 | 32 | entity02.position.x += _x; 33 | entity02.position.y += _y; 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /Sources/found/tool/UUID.hx: -------------------------------------------------------------------------------- 1 | package found.tool; 2 | 3 | class UUID { 4 | 5 | static public function get(?val:Null):String { 6 | // https://web.archive.org/web/20190318040344/http://www.anotherchris.net/csharp/friendly-unique-id-generation-part-2/#base62 7 | 8 | if(val == null) val = Std.random(0x7fffffff); 9 | 10 | function toChar(value:Int):String { 11 | if (value > 9) { 12 | var ascii = (65 + (value - 10)); 13 | if (ascii > 90) { ascii += 6; } 14 | return String.fromCharCode(ascii); 15 | } else { 16 | return Std.string(value).charAt(0); 17 | } 18 | } 19 | 20 | var r = Std.int(val % 62); 21 | var q = Std.int(val / 62); 22 | return q > 0 ? get(q) + toChar(r) : Std.string(toChar(r)); 23 | } 24 | 25 | } -------------------------------------------------------------------------------- /Sources/found/trait/TestScript.hx: -------------------------------------------------------------------------------- 1 | package found.trait; 2 | 3 | import found.object.Object.RotateData; 4 | import found.object.Object.MoveData; 5 | 6 | class TestScript extends found.Trait { 7 | public function new(){ 8 | super(); 9 | notifyOnInit(function(){ 10 | this.object.onCollision({tileId: 70,objectName: "Tilemap",onEnter:onCollisionEnter }); 11 | }); 12 | } 13 | function onCollisionEnter(body:echo.Body,otherBody:echo.Body,data:Array){ 14 | if(body == this.object.body){ 15 | trace(body.x +" "+body.y+ "x Y from current Object"); 16 | } 17 | trace("Collided on spikes"); 18 | } 19 | } -------------------------------------------------------------------------------- /Sources/found/trait/internal/Arrows.hx: -------------------------------------------------------------------------------- 1 | package found.trait.internal; 2 | 3 | import kha.math.Vector2; 4 | import found.Input.Mouse; 5 | import kha.graphics2.Graphics; 6 | 7 | class Arrows extends Trait { 8 | public static var instance(get,null):Arrows; 9 | public var visible:Bool =false; 10 | var mouse:Mouse; 11 | static function get_instance() { 12 | if(instance == null) instance = new Arrows(); 13 | return instance; 14 | } 15 | public function new() { 16 | super(); 17 | mouse = Input.getMouse(); 18 | notifyOnRender2D(render); 19 | } 20 | var rectSize:Float; 21 | var height:Float; 22 | var width:Float; 23 | var rectPos:Vector2 = new Vector2(); 24 | var hPos:Vector2 = new Vector2(); 25 | var vPos:Vector2 = new Vector2(); 26 | function update(){ 27 | if(!visible || this.object == State.active.cam #if editor || found.App.editorui.currentView != 0#end)return; 28 | var pos = new Vector2(this.object.position.x,this.object.position.y); 29 | var mpos = State.active.cam.screenToWorld(new Vector2(mouse.x,mouse.y)); 30 | 31 | var hpos = pos.add(hPos); 32 | var isDown = mouse.down("left"); 33 | if(isDown && mpos.x > hpos.x && mpos.x < hpos.x + width && mpos.y > hpos.y && mpos.y < hpos.y + rectSize){ 34 | #if editor 35 | if(EditorUi.arrow == -1) 36 | EditorUi.arrow = 0; 37 | #end 38 | } 39 | var vpos = pos.add(vPos); 40 | if( isDown && mpos.x > vpos.x && mpos.x < vpos.x + rectSize && mpos.y > vpos.y && mpos.y < vpos.y + width){ 41 | #if editor 42 | if(EditorUi.arrow == -1) 43 | EditorUi.arrow = 1; 44 | #end 45 | } 46 | var rpos = pos.add(rectPos); 47 | if(isDown && mpos.x > rpos.x && mpos.x < rpos.x + rectSize && mpos.y > rpos.y && mpos.y < rpos.y + rectSize){ 48 | #if editor 49 | if(EditorUi.arrow == -1) 50 | EditorUi.arrow = 2; 51 | #end 52 | } 53 | } 54 | function render(g:Graphics){ 55 | if(!visible || this.object == State.active.cam #if editor || found.App.editorui.currentView != 0#end)return; 56 | height = rectSize = Found.popupZuiInstance.ELEMENT_H() * 0.5; 57 | width = Found.popupZuiInstance.ELEMENT_W(); 58 | rectPos.x = 0; 59 | rectPos.y = -rectSize; 60 | hPos.x = rectSize; 61 | hPos.y = -rectSize; 62 | vPos.x = 0; 63 | vPos.y = -rectSize - width; 64 | 65 | var size = rectSize * 0.33; 66 | g.color = kha.Color.Yellow; 67 | g.fillRect(rectPos.x,rectPos.y,rectSize,rectSize); 68 | g.color = kha.Color.Green; 69 | var w = width-rectSize; 70 | g.fillRect(hPos.x,hPos.y + rectSize * 0.5 - size *0.5,w,size); 71 | g.fillTriangle(hPos.x+w,hPos.y,hPos.x+width,hPos.y + rectSize * 0.5,hPos.x + w,hPos.y+rectSize); 72 | g.color = kha.Color.Red; 73 | g.fillRect(vPos.x + rectSize * 0.5 -size *0.5,vPos.y+rectSize,size,w); 74 | g.fillTriangle(vPos.x,vPos.y+rectSize,vPos.x+rectSize,vPos.y+rectSize,vPos.x+rectSize * 0.5,vPos.y); 75 | } 76 | } -------------------------------------------------------------------------------- /Sources/found/trait/internal/CameraMovement.hx: -------------------------------------------------------------------------------- 1 | package found.trait.internal; 2 | 3 | import kha.math.Vector2; 4 | import found.object.Camera; 5 | import found.math.Util; 6 | 7 | @:access(found.object.Camera) 8 | class CameraMovement extends found.Trait { 9 | var camera:Camera; 10 | public var considerRotation:Bool = false; 11 | public function new(){ 12 | super(); 13 | this.notifyOnInit(function(){ 14 | this.camera = cast(this.object,Camera); 15 | }); 16 | notifyOnUpdate(update); 17 | } 18 | function update(dt:Float){ 19 | if (camera.target != null){ 20 | var pos = camera.target.center.mult(camera.zoom); 21 | var center = camera.origin; 22 | var lpos = new Vector2(camera.position.x,camera.position.y); 23 | if (camera.offsetX < Math.abs(Math.abs(camera.position.x - center.x) - pos.x)) { 24 | lpos.x = Util.lerp(camera.position.x, pos.x - center.x, camera.camSpeedX * Timer.delta); 25 | } 26 | if (camera.offsetY < Math.abs(Math.abs(camera.position.y - center.y) - pos.y)) { 27 | lpos.y = Util.lerp(camera.position.y, pos.y - center.y, camera.camSpeedY * Timer.delta); 28 | } 29 | camera.move(lpos.sub(camera.position),considerRotation); 30 | 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /Sources/found/trait/internal/CanvasScript.hx: -------------------------------------------------------------------------------- 1 | package found.trait.internal; 2 | 3 | import kha.math.FastMatrix3; 4 | import haxe.ds.Either; 5 | import found.Trait; 6 | import zui.Zui; 7 | import zui.Canvas; 8 | 9 | class CanvasScript extends Trait { 10 | 11 | 12 | var cui: Zui; 13 | var canvas: TCanvas = null; 14 | var baseWidth:Int; 15 | var baseHeight:Int; 16 | 17 | var customDraw:MapTElement->Void>; 18 | 19 | public var ready(get, null): Bool; 20 | function get_ready(): Bool { return canvas != null; } 21 | 22 | public var visible(default,set):Bool = true; 23 | function set_visible(visible: Bool){ 24 | this.visible = visible; 25 | for (e in canvas.elements) e.visible = visible; 26 | return this.visible; 27 | } 28 | 29 | 30 | /** 31 | * Create new CanvasScript from canvas 32 | * @param canvasName Name of the canvas 33 | * @param font font file (Optional) 34 | */ 35 | public function new(canvasName: String, font: String = "font_default.ttf",b_canvas:kha.Blob=null) { 36 | super(); 37 | 38 | customDraw = new MapTElement->Void>(); 39 | var done = function(blob: kha.Blob) { 40 | 41 | var onFontDone = function(f: kha.Font) { 42 | var c: TCanvas = haxe.Json.parse(blob.toString()); 43 | if (c.theme == null) c.theme = Canvas.themes[0].NAME; 44 | cui = new Zui({font: f, theme: Canvas.getTheme(c.theme)}); 45 | 46 | if (c.assets == null || c.assets.length == 0) canvas = c; 47 | else { // Load canvas assets 48 | var loaded = 0; 49 | for (asset in c.assets) { 50 | var file = asset.file; 51 | found.data.Data.getImage(file, function(image: kha.Image) { 52 | Canvas.assetMap.set(asset.id, image); 53 | if (++loaded >= c.assets.length) canvas = c; 54 | }); 55 | } 56 | } 57 | } 58 | if(font == "font_default.ttf"){ 59 | onFontDone(kha.Assets.fonts.font_default); 60 | } 61 | else { 62 | found.data.Data.getFont(font,onFontDone); 63 | } 64 | }; 65 | 66 | if(b_canvas != null){ 67 | done(b_canvas); 68 | } 69 | else{ 70 | found.data.Data.getBlob(canvasName + ".json",done); 71 | } 72 | 73 | notifyOnReady(function(){ 74 | baseWidth = canvas.width; 75 | baseHeight = canvas.height; 76 | }); 77 | 78 | notifyOnRender2D(function(g: kha.graphics2.Graphics) { 79 | if (canvas == null || !visible) return; 80 | 81 | if (onReady != null) { onReady(); onReady = null; } 82 | var hasPos:Bool = this.object != null; 83 | 84 | var identity = FastMatrix3.identity(); 85 | var objectTrans = identity; 86 | var rotTrans = identity; 87 | if(hasPos){ 88 | if(object.rotation.z>0){ 89 | rotTrans = g.popTransformation(); 90 | } 91 | objectTrans = g.popTransformation(); 92 | } 93 | var lastTrans = g.popTransformation(); 94 | 95 | var isEmpty = g.transformation == null; 96 | if(isEmpty)g.pushTransformation(lastTrans); 97 | 98 | setCanvasDimensions(kha.System.windowWidth(), kha.System.windowHeight()); 99 | var events = Canvas.draw(cui, canvas, g); 100 | 101 | g.end(); 102 | for(key in customDraw.keys()){ 103 | var element = getElement(key); 104 | if(element != null){ 105 | customDraw.get(key)(g,element); 106 | } 107 | } 108 | 109 | if(!isEmpty) 110 | g.pushTransformation(lastTrans); 111 | 112 | if(hasPos){ 113 | g.pushTransformation(objectTrans); 114 | if(object.rotation.z>0) 115 | g.pushTransformation(rotTrans); 116 | } 117 | 118 | g.begin(false); 119 | 120 | for (e in events) { 121 | var all = found.Event.get(e); 122 | if (all != null){ 123 | for (entry in all){ 124 | switch(entry.onEvent){ 125 | case Either.Left(v): 126 | v(); 127 | case Either.Right(v): 128 | v([entry.name,entry.mask]); 129 | } 130 | } 131 | } 132 | 133 | } 134 | }); 135 | } 136 | 137 | var onReady: Void->Void = null; 138 | public function notifyOnReady(f: Void->Void) { 139 | onReady = f; 140 | } 141 | 142 | /** 143 | * Returns an element of the canvas. 144 | * @param name The name of the element 145 | * @return TElement 146 | */ 147 | public function getElement(name: String): TElement { 148 | for (e in canvas.elements) if (e.name == name) return e; 149 | return null; 150 | } 151 | 152 | /** 153 | * Returns an array of the elements of the canvas. 154 | * @return Array 155 | */ 156 | public function getElements(): Array { 157 | return canvas.elements; 158 | } 159 | 160 | /** 161 | * Returns the canvas object of this trait. 162 | * @return TCanvas 163 | */ 164 | public function getCanvas(): Null { 165 | return canvas; 166 | } 167 | 168 | /** 169 | * Set UI scale factor. 170 | * @param factor Scale factor. 171 | */ 172 | public function setUiScale(factor:Float) { 173 | cui.setScale(factor); 174 | } 175 | 176 | 177 | 178 | /** 179 | * Set dimensions of canvas 180 | * @param x Width 181 | * @param y Height 182 | */ 183 | public function setCanvasDimensions(x: Int, y: Int){ 184 | if(canvas.width != x || canvas.height != y){ 185 | canvas.width = x; 186 | canvas.height = y; 187 | for (i in 0...canvas.elements.length){ 188 | canvas.elements[i] = getScaledElement(canvas.elements[i]); 189 | } 190 | } 191 | 192 | } 193 | /** 194 | * Set font size of the canvas 195 | * @param fontSize Size of font to be setted 196 | */ 197 | public function setCanvasFontSize(fontSize: Int) { 198 | cui.t.FONT_SIZE = fontSize; 199 | } 200 | 201 | // Contains data 202 | @:access(zui.Canvas) 203 | @:access(zui.Handle) 204 | public function getHandle(name: String): Handle { 205 | // Consider this a temporary solution 206 | return Canvas.h.children[getElement(name).id]; 207 | } 208 | 209 | @:access(zui.Canvas) 210 | function getScaledElement(elem:TElement):TElement{ 211 | //@TODO: add anchor code to position elements based the anchors set. 212 | var element = Reflect.copy(elem); 213 | element.x = Math.floor((elem.x/baseWidth)*canvas.width); 214 | element.y = Math.floor((elem.y/baseHeight)*canvas.height); 215 | element.width = Math.floor((elem.width/baseWidth)*canvas.width); 216 | element.height = Math.floor((elem.height/baseHeight)*canvas.height); 217 | return element; 218 | } 219 | 220 | public function addCustomDraw(name:String, func:kha.graphics2.Graphics->TElement->Void){ 221 | customDraw.set(name,func); 222 | } 223 | public function removeCustomDraw(name:String){ 224 | customDraw.remove(name); 225 | } 226 | } 227 | -------------------------------------------------------------------------------- /Sources/found/trait/internal/LoadingScript.hx: -------------------------------------------------------------------------------- 1 | package found.trait.internal; 2 | 3 | import found.object.Object.RotateData; 4 | import found.object.Object.MoveData; 5 | 6 | class LoadingScript extends found.Trait { 7 | public function new(){ 8 | super(); 9 | notifyOnInit(doStuff); 10 | notifyOnInit(function (){ 11 | this.object.translate(center); 12 | // this.object.rotate(function (data:RotateData){ 13 | // data._rotations.z+= 10*data.dt; 14 | // return data; 15 | // },1.0); 16 | }); 17 | notifyOnUpdate(function(dt:Float){ 18 | // this.object.rotate(function (data:RotateData){ 19 | // data._rotations.z+= 10*data.dt; 20 | // return data; 21 | // },dt); 22 | // State.active.cam.x-=1.0; 23 | // this.object.translate(move,dt); 24 | // this.object.rotation+= 10*dt; 25 | }); 26 | } 27 | function doStuff(){ 28 | trace("Hello World !"); 29 | } 30 | function center(data:MoveData){ 31 | data._positions.x = (Found.WIDTH*0.5-(this.object.width)*0.5); 32 | data._positions.y = (Found.HEIGHT*0.5-(this.object.height)*0.5); 33 | return data; 34 | } 35 | function move(data:MoveData){ 36 | var speed = 25.0; 37 | data._positions.x += speed*data.dt; 38 | return data; 39 | } 40 | } -------------------------------------------------------------------------------- /Sources/found/tween/Ease.hx: -------------------------------------------------------------------------------- 1 | package found.tween; 2 | 3 | class Back { 4 | // Modeled after the overshooting cubic y = x^3-x*sin(x*pi) 5 | public static function easeIn(p:Float):Float { 6 | return p * p * p - p * Math.sin(p * Math.PI); 7 | } 8 | 9 | // Modeled after overshooting cubic y = 1-((1-x)^3-(1-x)*sin((1-x)*pi)) 10 | public static function easeOut(p:Float):Float { 11 | var f = (1 - p); 12 | return 1 - (f * f * f - f * Math.sin(f * Math.PI)); 13 | } 14 | 15 | // Modeled after the piecewise overshooting cubic function: 16 | // y = (1/2)*((2x)^3-(2x)*sin(2*x*pi)) ; [0, 0.5) 17 | // y = (1/2)*(1-((1-x)^3-(1-x)*sin((1-x)*pi))+1) ; [0.5, 1] 18 | public static function easeInOut(p:Float):Float { 19 | if (p < 0.5) { 20 | var f = 2 * p; 21 | return 0.5 * (f * f * f - f * Math.sin(f * Math.PI)); 22 | } else { 23 | var f = (1 - (2 * p - 1)); 24 | return 0.5 * (1 - (f * f * f - f * Math.sin(f * Math.PI))) + 0.5; 25 | } 26 | } 27 | } 28 | 29 | class Bounce { 30 | public static function easeIn(p:Float):Float { 31 | return 1 - easeOut(1 - p); 32 | } 33 | 34 | public static function easeOut(p:Float):Float { 35 | if (p < 4 / 11) 36 | return (121 * p * p) / 16; 37 | else if (p < 8 / 11) 38 | return (363 / 40 * p * p) - (99 / 10 * p) + 17 / 5; 39 | else if (p < 9 / 10) 40 | return (4356 / 361 * p * p) - (35442 / 1805 * p) + 16061 / 1805; 41 | else 42 | return (54 / 5 * p * p) - (513 / 25 * p) + 268 / 25; 43 | } 44 | 45 | public static function easeInOut(p:Float):Float { 46 | if (p < 0.5) 47 | return 0.5 * easeIn(p * 2); 48 | else 49 | return 0.5 * easeOut(p * 2 - 1) + 0.5; 50 | } 51 | } 52 | 53 | class Circle { 54 | // Modeled after shifted quadrant IV of unit circle 55 | public static function easeIn(p:Float):Float { 56 | return 1 - Math.sqrt(1 - (p * p)); 57 | } 58 | 59 | // Modeled after shifted quadrant II of unit circle 60 | public static function easeOut(p:Float):Float { 61 | return Math.sqrt((2 - p) * p); 62 | } 63 | 64 | // Modeled after the piecewise circular function 65 | // y = (1/2)(1 - sqrt(1 - 4x^2)) ; [0, 0.5) 66 | // y = (1/2)(sqrt(-(2x - 3)*(2x - 1)) + 1) ; [0.5, 1] 67 | public static function easeInOut(p:Float):Float { 68 | if (p < 0.5) 69 | return 0.5 * (1 - Math.sqrt(1 - 4 * (p * p))); 70 | else 71 | return 0.5 * (Math.sqrt(-((2 * p) - 3) * ((2 * p) - 1)) + 1); 72 | } 73 | } 74 | 75 | class Cube { 76 | // Modeled after the cubic y = x^3 77 | public static function easeIn(p:Float):Float { 78 | return p * p * p; 79 | } 80 | 81 | // Modeled after the cubic y = (x - 1)^3 + 1 82 | public static function easeOut(p:Float):Float { 83 | var f = (p - 1); 84 | return f * f * f + 1; 85 | } 86 | 87 | // Modeled after the piecewise cubic 88 | // y = (1/2)((2x)^3) ; [0, 0.5) 89 | // y = (1/2)((2x-2)^3 + 2) ; [0.5, 1] 90 | public static function easeInOut(p:Float):Float { 91 | if (p < 0.5) { 92 | return 4 * p * p * p; 93 | } else { 94 | var f = ((2 * p) - 2); 95 | return 0.5 * f * f * f + 1; 96 | } 97 | } 98 | } 99 | 100 | class Elastic { 101 | // Modeled after the damped sine wave y = sin(13pi/2*x)*pow(2, 10 * (x - 1)) 102 | public static function easeIn(p:Float):Float { 103 | return Math.sin(13 * (Math.PI / 2) * p) * Math.pow(2, 10 * (p - 1)); 104 | } 105 | 106 | // Modeled after the damped sine wave y = sin(-13pi/2*(x + 1))*pow(2, -10x) + 1 107 | public static function easeOut(p:Float):Float { 108 | return Math.sin(-13 * (Math.PI / 2) * (p + 1)) * Math.pow(2, -10 * p) + 1; 109 | } 110 | 111 | // Modeled after the piecewise exponentially-damped sine wave: 112 | // y = (1/2)*sin(13pi/2*(2*x))*pow(2, 10 * ((2*x) - 1)) ; [0,0.5) 113 | // y = (1/2)*(sin(-13pi/2*((2x-1)+1))*pow(2,-10(2*x-1)) + 2) ; [0.5, 1] 114 | public static function easeInOut(p:Float):Float { 115 | if (p < 0.5) 116 | return 0.5 * Math.sin(13 * (Math.PI / 2) * (2 * p)) * Math.pow(2, 10 * ((2 * p) - 1)); 117 | else 118 | return 0.5 * (Math.sin(-13 * (Math.PI / 2) * ((2 * p - 1) + 1)) * Math.pow(2, -10 * (2 * p - 1)) + 2); 119 | } 120 | } 121 | 122 | class Expo { 123 | // Modeled after the exponential function y = 2^(10(x - 1)) 124 | public static function easeIn(p:Float):Float { 125 | return (p == 0.0) ? p : Math.pow(2, 10 * (p - 1)); 126 | } 127 | 128 | // Modeled after the exponential function y = -2^(-10x) + 1 129 | public static function easeOut(p:Float):Float { 130 | return (p == 1.0) ? p : 1 - Math.pow(2, -10 * p); 131 | } 132 | 133 | // Modeled after the piecewise exponential 134 | // y = (1/2)2^(10(2x - 1)) ; [0,0.5) 135 | // y = -(1/2)*2^(-10(2x - 1))) + 1 ; [0.5,1] 136 | public static function easeInOut(p:Float):Float { 137 | if (p == 0.0 || p == 1.0) 138 | return p; 139 | 140 | if (p < 0.5) 141 | return 0.5 * Math.pow(2, (20 * p) - 10); 142 | else 143 | return -0.5 * Math.pow(2, (-20 * p) + 10) + 1; 144 | } 145 | } 146 | 147 | class Linear { 148 | public static function none(p:Float):Float { 149 | return p; 150 | } 151 | } 152 | 153 | class Quad { 154 | // Modeled after the parabola y = x^2 155 | public static function easeIn(p:Float):Float { 156 | return p * p; 157 | } 158 | 159 | // Modeled after the parabola y = -x^2 + 2x 160 | public static function easeOut(p:Float):Float { 161 | return -(p * (p - 2)); 162 | } 163 | 164 | // Modeled after the piecewise quadratic 165 | // y = (1/2)((2x)^2) ; [0, 0.5) 166 | // y = -(1/2)((2x-1)*(2x-3) - 1) ; [0.5, 1] 167 | public static function easeInOut(p:Float):Float { 168 | if (p < 0.5) 169 | return 2 * p * p; 170 | else 171 | return (-2 * p * p) + (4 * p) - 1; 172 | } 173 | } 174 | 175 | class Quart { 176 | // Modeled after the quartic x^4 177 | public static function easeIn(p:Float):Float { 178 | return p * p * p * p; 179 | } 180 | 181 | // Modeled after the quartic y = 1 - (x - 1)^4 182 | public static function easeOut(p:Float):Float { 183 | var f = (p - 1); 184 | return f * f * f * (1 - p) + 1; 185 | } 186 | 187 | // Modeled after the piecewise quartic 188 | // y = (1/2)((2x)^4) ; [0, 0.5) 189 | // y = -(1/2)((2x-2)^4 - 2) ; [0.5, 1] 190 | public static function easeInOut(p:Float):Float { 191 | if (p < 0.5) { 192 | return 8 * p * p * p * p; 193 | } else { 194 | var f = (p - 1); 195 | return -8 * f * f * f * f + 1; 196 | } 197 | } 198 | } 199 | 200 | class Quint { 201 | // Modeled after the quintic y = x^5 202 | public static function easeIn(p:Float):Float { 203 | return p * p * p * p * p; 204 | } 205 | 206 | // Modeled after the quintic y = (x - 1)^5 + 1 207 | public static function easeOut(p:Float):Float { 208 | var f = (p - 1); 209 | return f * f * f * f * f + 1; 210 | } 211 | 212 | // Modeled after the piecewise quintic 213 | // y = (1/2)((2x)^5) ; [0, 0.5) 214 | // y = (1/2)((2x-2)^5 + 2) ; [0.5, 1] 215 | public static function easeInOut(p:Float):Float { 216 | if (p < 0.5) { 217 | return 16 * p * p * p * p * p; 218 | } else { 219 | var f = ((2 * p) - 2); 220 | return 0.5 * f * f * f * f * f + 1; 221 | } 222 | } 223 | } 224 | 225 | class Sine { 226 | // Modeled after quarter-cycle of sine wave 227 | public static function easeIn(p:Float):Float { 228 | return Math.sin((p - 1) * (Math.PI / 2)) + 1; 229 | } 230 | 231 | // Modeled after quarter-cycle of sine wave (different phase) 232 | public static function easeOut(p:Float):Float { 233 | return Math.sin(p * (Math.PI / 2)); 234 | } 235 | 236 | // Modeled after half sine wave 237 | public static function easeInOut(p:Float):Float { 238 | return 0.5 * (1 - Math.cos(p * Math.PI)); 239 | } 240 | } -------------------------------------------------------------------------------- /Sources/found/tween/Tween.hx: -------------------------------------------------------------------------------- 1 | package found.tween; 2 | 3 | class Tween { 4 | private var _from:Float; 5 | private var _to:Float; 6 | private var _time:Float; 7 | private var _duration:Float; 8 | private var _set:Float->Float->Void; 9 | private var _ease:Float->Float; 10 | private var _finished:Bool; 11 | private var _onCompleteFunc:NullVoid>; 12 | 13 | public function new(from:Float, to:Float, duration:Float, ease:Float->Float, set:Float->Float->Void){ 14 | this._from = from; 15 | this._to = to - from; 16 | this._duration = duration; 17 | this._set = set; 18 | this._ease = ease; 19 | _time = 0; 20 | _finished = false; 21 | } 22 | 23 | public function update(){ 24 | if (_finished) return; 25 | 26 | _time += 1 / 60; 27 | if (_time >= _duration){ 28 | _set(1, _from + _to); 29 | _finished = true; 30 | finish(); 31 | } else { 32 | var t = _time / _duration; 33 | _set(t, _from + _ease(t) * _to); 34 | } 35 | } 36 | 37 | function finish(){ 38 | if (_onCompleteFunc!= null) _onCompleteFunc(); 39 | } 40 | 41 | public function onComplete(func:Void->Void){ 42 | _onCompleteFunc = func; 43 | return this; 44 | } 45 | } -------------------------------------------------------------------------------- /defaults/default.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": -1.0, 3 | "data": 4 | { 5 | "name":"default", 6 | "_depth": true, 7 | "_Zsort": true, 8 | "_entities": 9 | [ 10 | { 11 | "name":"camera", 12 | "type":"camera_object", 13 | "position":{"x":0.0,"y":0.0}, 14 | "rotation":{"x":0.0,"y":0.0,"z":0.0}, 15 | "width":0, 16 | "height":0, 17 | "center":{"x":0,"y":0}, 18 | "scale":{"x":1.0,"y":1.0}, 19 | "layer": 0, 20 | "depth":0, 21 | "active":true, 22 | "traits": 23 | [ 24 | { 25 | "type":"Script", 26 | "classname":"found.trait.internal.CameraMovement" 27 | } 28 | ] 29 | }, 30 | { 31 | "name":"default", 32 | "type":"sprite_object", 33 | "position":{"x":100.0,"y":100.0}, 34 | "rotation":{"x":0.0,"y":0.0,"z":0.0}, 35 | "width":493, 36 | "height":512, 37 | "center":{"x":0,"y":0}, 38 | "scale":{"x":1.0,"y":1.0}, 39 | "layer": 0, 40 | "depth":0, 41 | "active":true, 42 | "imagePath":"foundry_icon", 43 | "anims": [], 44 | "traits": 45 | [ 46 | ] 47 | } 48 | ] 49 | } 50 | 51 | } -------------------------------------------------------------------------------- /defaults/font_default.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Foundry3D/foundry2d/6d05b5289bb5d1d1f845af0540074a828ab596f1/defaults/font_default.ttf -------------------------------------------------------------------------------- /defaults/foundry_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Foundry3D/foundry2d/6d05b5289bb5d1d1f845af0540074a828ab596f1/defaults/foundry_icon.png -------------------------------------------------------------------------------- /defaults/loading.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "loading", 3 | "_entities":[ 4 | { 5 | "name": "load-icon", 6 | "type": "sprite_object", 7 | "position":{ "x": 0.0, "y": 0.0}, 8 | "rotation": { "x": 0.0, "y": 0.0,"z": 0.0}, 9 | "width": 666.0, 10 | "height": 555.0, 11 | "center":{ "x": 0.0, "y": 0.0}, 12 | "scale":{ "x": 0.5, "y": 0.5}, 13 | "depth": 0.0, 14 | "active": true, 15 | "imagePath": "loading", 16 | "anims": [], 17 | "traits":[ 18 | { 19 | "type": "Script", 20 | "classname": "found.trait.internal.LoadingScript" 21 | } 22 | ], 23 | "rigidBody":{ 24 | "kinematic": true, 25 | "mass": 9.8, 26 | "shapes": [ { 27 | "type": 0, 28 | "solid":true, 29 | "width": 333.0, 30 | "height": 277.5 31 | }] 32 | } 33 | } 34 | ], 35 | "physicsWorld": { 36 | "width": 1280.0, 37 | "height": 720.0, 38 | "x": 0.0, 39 | "y": 0.0, 40 | "gravity_y": 20.0, 41 | "iterations": 5 42 | } 43 | } -------------------------------------------------------------------------------- /defaults/loading.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Foundry3D/foundry2d/6d05b5289bb5d1d1f845af0540074a828ab596f1/defaults/loading.png -------------------------------------------------------------------------------- /defaults/platformerPack_character.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Foundry3D/foundry2d/6d05b5289bb5d1d1f845af0540074a828ab596f1/defaults/platformerPack_character.png -------------------------------------------------------------------------------- /defaults/temp.txt: -------------------------------------------------------------------------------- 1 | https://www.flaticon.com/free-icon/loading_189792#term=loading&page=1&position=7 2 | 3 | -------------------------------------------------------------------------------- /defaults/tilesheet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Foundry3D/foundry2d/6d05b5289bb5d1d1f845af0540074a828ab596f1/defaults/tilesheet.png -------------------------------------------------------------------------------- /khafile.js: -------------------------------------------------------------------------------- 1 | let project = new Project('found'); 2 | project.addAssets('defaults/**'); 3 | project.addSources('Sources'); 4 | project.addDefine("found"); 5 | project.addDefine("zui_translate"); 6 | project.addParameter('found.trait'); 7 | project.addParameter("--macro keep('found.trait')"); 8 | project.addParameter('found.node'); 9 | project.addParameter("--macro keep('found.node')"); 10 | project.addParameter('--macro echo.Macros.add_data("object", "found.object.Object")'); 11 | // @TODO: Fix strict null safety issues by enabling this and fixing the compile issues 12 | // project.addParameter('--macro nullSafety("found", Strict)'); 13 | 14 | // To enable debug code for nodes: 15 | // project.addDefine("debug_nodes"); 16 | 17 | project.addLibrary('Libraries/foundsdk/hxmath'); 18 | project.addLibrary('Libraries/foundsdk/echo'); 19 | project.addLibrary('Libraries/foundsdk/zui'); 20 | resolve(project); --------------------------------------------------------------------------------