From 3df59353e69166729562cbc565913d7222c4f943 Mon Sep 17 00:00:00 2001 From: Ronja Date: Tue, 14 Dec 2021 12:52:41 +0100 Subject: [PATCH] initial commit --- .gitignore | 1 + intersecting-circles-manual/.gitignore | 10 + intersecting-circles-manual/.luxeignore | 1 + .../circle_manager.wren | 113 +++++ intersecting-circles-manual/game.wren | 47 ++ intersecting-circles-manual/outline/app.wren | 74 +++ .../outline/inputs.input.lx | 23 + .../outline/renderer.wren | 51 ++ .../outline/settings.settings.lx | 17 + intersecting-circles-manual/project.luxe | 14 + .../project.modules.lx | 3 + intersecting-circles-manual/util.wren | 32 ++ intersecting-circles-modifiers/.gitignore | 10 + intersecting-circles-modifiers/.luxeignore | 1 + intersecting-circles-modifiers/game.wren | 64 +++ .../modifiers/circle/circle.modifier.lx | 12 + .../modifiers/circle/circle.modifier.wren | 466 +++++++++++++++++ .../modifiers/circle/circle.wren | 113 +++++ .../modifiers/move/move.modifier.lx | 12 + .../modifiers/move/move.modifier.wren | 468 ++++++++++++++++++ .../modifiers/move/move.wren | 72 +++ .../outline/app.wren | 74 +++ .../outline/inputs.input.lx | 23 + .../outline/renderer.wren | 51 ++ .../outline/settings.settings.lx | 17 + intersecting-circles-modifiers/project.luxe | 14 + .../project.modules.lx | 3 + intersecting-circles-modifiers/util.wren | 32 ++ 28 files changed, 1818 insertions(+) create mode 100644 .gitignore create mode 100644 intersecting-circles-manual/.gitignore create mode 100644 intersecting-circles-manual/.luxeignore create mode 100644 intersecting-circles-manual/circle_manager.wren create mode 100644 intersecting-circles-manual/game.wren create mode 100644 intersecting-circles-manual/outline/app.wren create mode 100644 intersecting-circles-manual/outline/inputs.input.lx create mode 100644 intersecting-circles-manual/outline/renderer.wren create mode 100644 intersecting-circles-manual/outline/settings.settings.lx create mode 100644 intersecting-circles-manual/project.luxe create mode 100644 intersecting-circles-manual/project.modules.lx create mode 100644 intersecting-circles-manual/util.wren create mode 100644 intersecting-circles-modifiers/.gitignore create mode 100644 intersecting-circles-modifiers/.luxeignore create mode 100644 intersecting-circles-modifiers/game.wren create mode 100644 intersecting-circles-modifiers/modifiers/circle/circle.modifier.lx create mode 100644 intersecting-circles-modifiers/modifiers/circle/circle.modifier.wren create mode 100644 intersecting-circles-modifiers/modifiers/circle/circle.wren create mode 100644 intersecting-circles-modifiers/modifiers/move/move.modifier.lx create mode 100644 intersecting-circles-modifiers/modifiers/move/move.modifier.wren create mode 100644 intersecting-circles-modifiers/modifiers/move/move.wren create mode 100644 intersecting-circles-modifiers/outline/app.wren create mode 100644 intersecting-circles-modifiers/outline/inputs.input.lx create mode 100644 intersecting-circles-modifiers/outline/renderer.wren create mode 100644 intersecting-circles-modifiers/outline/settings.settings.lx create mode 100644 intersecting-circles-modifiers/project.luxe create mode 100644 intersecting-circles-modifiers/project.modules.lx create mode 100644 intersecting-circles-modifiers/util.wren diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b4fa2c9 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.vscode diff --git a/intersecting-circles-manual/.gitignore b/intersecting-circles-manual/.gitignore new file mode 100644 index 0000000..d9dc9db --- /dev/null +++ b/intersecting-circles-manual/.gitignore @@ -0,0 +1,10 @@ +*/.DS_Store +.DS_Store +.DS_Store? +*/thumbs.db +thumbs.db +.thumbs.db? +.luxe/ +_luxe.data/ +_luxe.deploy/ +log.txt \ No newline at end of file diff --git a/intersecting-circles-manual/.luxeignore b/intersecting-circles-manual/.luxeignore new file mode 100644 index 0000000..a3de5ef --- /dev/null +++ b/intersecting-circles-manual/.luxeignore @@ -0,0 +1 @@ +preview.png \ No newline at end of file diff --git a/intersecting-circles-manual/circle_manager.wren b/intersecting-circles-manual/circle_manager.wren new file mode 100644 index 0000000..865570e --- /dev/null +++ b/intersecting-circles-manual/circle_manager.wren @@ -0,0 +1,113 @@ +import "luxe: world" for Entity, Transform, World +import "luxe: draw" for Draw, PathStyle +import "random" for Random +import "luxe: math" for Math +import "luxe: color" for Color +import "luxe: render" for Render +import "util" for Util + + +class CircleData{ + construct new(entity: Entity, velocity: List, radius: Num){ + _entity = entity + _radius = radius + _velocity = velocity + } + + entity{_entity} + velocity{_velocity} + radius{_radius} +} + +class CircleManager{ + construct new(world: World){ + _world = world + _circles = [] + _rng = Random.new() + _draw = Draw.create(World.render_set(world)) + + //setup draw styles + _circle_style = PathStyle.new() + _circle_style.color = Color.white + _circle_style.thickness = 1 + + _intersection_style = PathStyle.new() + _intersection_style.color = Color.hex(0xFFFF99) + _intersection_style.thickness = 2 + } + + spawn_circles(count: Num){ + for(i in 0...count){ + //entity/transform setup + var circle_ent = Entity.create(_world) + Transform.create(circle_ent) + var width = Render.window_w() + var height = Render.window_h() + Transform.set_pos(circle_ent, _rng.float(0, width), _rng.float(0, height), 0) + + //external wren class setup + var velocity = [_rng.float(-20, 20), _rng.float(-20, 20)] + var radius = _rng.float(20, 100) + var data = CircleData.new(circle_ent, velocity, radius) + + _circles.add(data) + } + } + + update(delta: Num){ + var width = Render.window_w() + var height = Render.window_h() + + //move and basic draw + _circles.each{|circle: CircleData| + //get pos + var pos = Transform.get_pos(circle.entity) + //update pos + pos.x = pos.x + circle.velocity.x * delta + pos.y = pos.y + circle.velocity.y * delta + if(pos.x < -circle.radius) pos.x = pos.x + width + circle.radius*2 + if(pos.x > width + circle.radius) pos.x = pos.x - width - circle.radius*2 + if(pos.y < -circle.radius) pos.y = pos.y + height + circle.radius*2 + if(pos.y > height + circle.radius) pos.y = pos.y - height - circle.radius*2 + //set pos + Transform.set_pos(circle.entity, pos.x, pos.y, pos.z) + + //per-ring drawing + Draw.ring(_draw, pos.x, pos.y, pos.z, circle.radius, circle.radius, 0, 360, 8, _circle_style) + } + + //intersections + //iterate all circle indices + for(i in 0..._circles.count){ + //and then also all again, up to the current one (that way we have all combinations) + for(ii in 0...i){ + //get needed data + var one = _circles[i] + var other = _circles[ii] + var one_pos = Transform.get_pos(one.entity) + var other_pos = Transform.get_pos(other.entity) + //get intersections + var intersections = Util.circle_intersect_circle(one_pos, one.radius, other_pos, other.radius) + if(intersections){ //and if we found any, draw them + Draw.line(_draw, intersections[0].x, intersections[0].y, intersections[1].x, intersections[1].y, 0, _intersection_style) + + Draw.circle(_draw, intersections[0].x, intersections[0].y, 0, 8, 8, [1, 1, 1, 0.2]) + Draw.circle(_draw, intersections[1].x, intersections[1].y, 0, 8, 8, [1, 1, 1, 0.2]) + + Draw.circle(_draw, intersections[0].x, intersections[0].y, 0, 3, 3, [1, 1, 1, 1]) + Draw.circle(_draw, intersections[1].x, intersections[1].y, 0, 3, 3, [1, 1, 1, 1]) + } + } + } + + Draw.commit(_draw) + } + + dispose(){ + //clean up entities and draw context + Draw.destroy(_draw) + _circles.each{|circle| + Entity.destroy(circle.entity) + } + } +} \ No newline at end of file diff --git a/intersecting-circles-manual/game.wren b/intersecting-circles-manual/game.wren new file mode 100644 index 0000000..97841a0 --- /dev/null +++ b/intersecting-circles-manual/game.wren @@ -0,0 +1,47 @@ +import "luxe: game" for Ready +import "luxe: assets" for Assets +import "luxe: input" for Input, Key +import "luxe: world" for World, Entity, Transform, Sprite, Values, Tags, Camera +import "luxe: math" for Math +import "luxe: draw" for Draw +import "luxe: io" for IO + +import "outline/app" for App +import "circle_manager" for CircleManager + +class Game is Ready { + + construct ready() { + + super("ready!") + + app = App.new() + app.color = [0,0,0,1] + + System.print("render size: %(app.width) x %(app.height) @ %(app.scale)x") + + _circles = CircleManager.new(app.world) + _circles.spawn_circles(20) + + } //ready + + tick(delta) { + _circles.update(delta) + + if(Input.key_state_released(Key.escape)) { + IO.shutdown() + } + } //tick + + destroy() { + + System.print("unready!") + app.destroy() + _circles.dispose() + + } //destroy + + app { _app } + app=(v) { _app=v } + +} //Game diff --git a/intersecting-circles-manual/outline/app.wren b/intersecting-circles-manual/outline/app.wren new file mode 100644 index 0000000..a0f1768 --- /dev/null +++ b/intersecting-circles-manual/outline/app.wren @@ -0,0 +1,74 @@ +import "luxe: world" for World, Camera, Entity, Transform +import "luxe: render" for Render +import "luxe: game" for Frame + +class App { + + world { _world } + ui { _ui_world } + + camera { _camera } + ui_camera { _ui_camera } + + color { _color } + color=(v) { _color = v } + + width { Render.window_w() } + height { Render.window_h() } + scale { Render.drawable_ratio() } + + construct new() { + + _color = [1,1,1,1] + + //create worlds + + _world = World.create("game") + _ui_world = World.create("ui") + + //create cameras + + _camera = Entity.create(_world, "app.camera") + Transform.create(_camera) + Camera.create(_camera) + Camera.set_default(_world, _camera) + + _ui_camera = Entity.create(_ui_world, "app.ui_camera") + Transform.create(_ui_camera) + Camera.create(_ui_camera) + Camera.set_default(_ui_world, _ui_camera) + + //update our worlds + + Frame.on(Frame.sim) {|delta| + World.tick(_world, delta) + World.tick(_ui_world, delta) + } + + //render our worlds + + Frame.on(Frame.visual) {|delta| + World.render(_world, _camera, "game", {"clear_color":_color}) + World.render(_ui_world, _ui_camera, "ui") + } + + } //new + + destroy() { + + //destroy cameras + + Camera.destroy(_camera) + Camera.destroy(_ui_camera) + + Entity.destroy(_camera) + Entity.destroy(_ui_camera) + + //destroy worlds + + World.destroy(_ui_world) + World.destroy(_world) + + } //destroy + +} // diff --git a/intersecting-circles-manual/outline/inputs.input.lx b/intersecting-circles-manual/outline/inputs.input.lx new file mode 100644 index 0000000..dc45459 --- /dev/null +++ b/intersecting-circles-manual/outline/inputs.input.lx @@ -0,0 +1,23 @@ +input = { + nodes = [ + { name = "ui" where = "front" channels = ["c01"] } + { name = "game" where = "after: ui" channels = ["c02"] } + ] + + map = { + left = { keys = ["key_a", "left"] } + right = { keys = ["key_d", "right"] } + up = { keys = ["key_w", "up"] } + down = { keys = ["key_s", "down"] } + jump = { + keys = ["key_x", "up", "key_w", "space"] + mouse = ["left"] + gamepad = [0] + } + + next = { + keys = ["key_x", "up", "key_w", "space", "enter", "escape"] + mouse = ["left", "right"] + } + } +} diff --git a/intersecting-circles-manual/outline/renderer.wren b/intersecting-circles-manual/outline/renderer.wren new file mode 100644 index 0000000..8c00ab4 --- /dev/null +++ b/intersecting-circles-manual/outline/renderer.wren @@ -0,0 +1,51 @@ +import "luxe: render" for Render, RenderLayerDesc, PassLayerDesc, LoadAction +import "luxe: render" for SortType, ImageDesc, ImageType, PixelFormat + +class Renderer { + + construct new() { + + System.print("game / render / init / ok") + + } //new + + ready() { + + } + + tick(delta) { + + } + + render_path(ctx) { + + if(ctx.path == "game") { + game_render_path(ctx) + } else if(ctx.path == "ui") { + ui_render_path(ctx) + } + + } //render_path + + game_render_path(ctx) { + + var layer = RenderLayerDesc.new() + layer.dest.color[0].clear_color = ctx.get("clear_color", [1,1,1,1]) + layer.dest.color[0].load_action = LoadAction.clear + layer.dest.depth.load_action = LoadAction.clear + + ctx.layer_render("default", layer) + + } //game_render_path + + ui_render_path(ctx) { + + var layer = RenderLayerDesc.new() + layer.dest.color[0].load_action = LoadAction.dont_care + layer.dest.depth.load_action = LoadAction.clear + + ctx.layer_render("default", layer) + + } //ui_render_path + +} //Renderer diff --git a/intersecting-circles-manual/outline/settings.settings.lx b/intersecting-circles-manual/outline/settings.settings.lx new file mode 100644 index 0000000..9d1ad01 --- /dev/null +++ b/intersecting-circles-manual/outline/settings.settings.lx @@ -0,0 +1,17 @@ +engine = { + input.entry = "outline/inputs" + runtime = { + window = { + width = 960 + height = 640 + resizable = false + fullscreen = false + } + } + + render = { + antialiasing = 8 + stencil = 8 + depth = 24 + } +} \ No newline at end of file diff --git a/intersecting-circles-manual/project.luxe b/intersecting-circles-manual/project.luxe new file mode 100644 index 0000000..3205c85 --- /dev/null +++ b/intersecting-circles-manual/project.luxe @@ -0,0 +1,14 @@ +import "luxe: project" for Entry + +class Project is Entry { + + construct entry(target) { + + name = "Intersecting Circles (manual)" + version = "1.0.0" + renderer = "outline/renderer" + settings = "outline/settings" + + } //new + +} //Project \ No newline at end of file diff --git a/intersecting-circles-manual/project.modules.lx b/intersecting-circles-manual/project.modules.lx new file mode 100644 index 0000000..50dd33d --- /dev/null +++ b/intersecting-circles-manual/project.modules.lx @@ -0,0 +1,3 @@ +modules = { + luxe = "2021.0.10" +} //modules diff --git a/intersecting-circles-manual/util.wren b/intersecting-circles-manual/util.wren new file mode 100644 index 0000000..d26effd --- /dev/null +++ b/intersecting-circles-manual/util.wren @@ -0,0 +1,32 @@ +import "luxe: math" for Math + +class Util{ + //cirle circle intersections, largely taken from http://paulbourke.net/geometry/circlesphere/ + static circle_intersect_circle(o1, r1, o2, r2){ + var diff_x = o2.x - o1.x + var diff_y = o2.y - o1.y + + var distance = Math.length(diff_x, diff_y) + if(distance > r1 + r2) return //too far away + if(distance < (r1 - r2).abs) return //contain each other + if(distance <= Num.smallest) return //infinite solutions + + var a = (r1*r1 - r2*r2 + distance*distance) / (2 * distance) //adjacient length of triangle between o1, midpoint and intersection + var h = (r1*r1 - a*a).sqrt //hypotenuse length of triangle between o1, midpoint and intersection + + var mid_x = o1.x + a * (o2.x - o1.x) / distance + var mid_y = o1.y + a * (o2.y - o1.y) / distance + + var inter1 = [ + mid_x + h * diff_y / distance, + mid_y - h * diff_x / distance + ] + + var inter2 = [ + mid_x - h * diff_y / distance, + mid_y + h * diff_x / distance + ] + + return [inter1, inter2] + } +} \ No newline at end of file diff --git a/intersecting-circles-modifiers/.gitignore b/intersecting-circles-modifiers/.gitignore new file mode 100644 index 0000000..d9dc9db --- /dev/null +++ b/intersecting-circles-modifiers/.gitignore @@ -0,0 +1,10 @@ +*/.DS_Store +.DS_Store +.DS_Store? +*/thumbs.db +thumbs.db +.thumbs.db? +.luxe/ +_luxe.data/ +_luxe.deploy/ +log.txt \ No newline at end of file diff --git a/intersecting-circles-modifiers/.luxeignore b/intersecting-circles-modifiers/.luxeignore new file mode 100644 index 0000000..a3de5ef --- /dev/null +++ b/intersecting-circles-modifiers/.luxeignore @@ -0,0 +1 @@ +preview.png \ No newline at end of file diff --git a/intersecting-circles-modifiers/game.wren b/intersecting-circles-modifiers/game.wren new file mode 100644 index 0000000..b144e8b --- /dev/null +++ b/intersecting-circles-modifiers/game.wren @@ -0,0 +1,64 @@ +import "luxe: game" for Ready +import "luxe: assets" for Assets +import "luxe: input" for Input, Key +import "luxe: world" for World, Entity, Transform, Sprite, Values, Tags, Camera +import "luxe: math" for Math +import "luxe: draw" for Draw +import "luxe: io" for IO +import "luxe: render" for Render + +import "random" for Random + +import "outline/app" for App +import "modifiers/circle/circle" for Circle +import "modifiers/move/move" for Move + +class Game is Ready { + + construct ready() { + + super("ready!") + + app = App.new() + app.color = [0,0,0,1] + + System.print("render size: %(app.width) x %(app.height) @ %(app.scale)x") + + spawn_circles(20) + } //ready + + spawn_circles(count: Num){ + var rng = Random.new() + for(i in 0...count){ + //entity/transform setup + var circle_ent = Entity.create(app.world) + Transform.create(circle_ent) + var width = Render.window_w() + var height = Render.window_h() + Transform.set_pos(circle_ent, rng.float(0, width), rng.float(0, height), 0) + + Circle.create(circle_ent) + Circle.set_radius(circle_ent, rng.float(20, 100)) + + Move.create(circle_ent) + Move.set_velocity(circle_ent, [rng.float(-20, 20), rng.float(-20, 20)]) + } + } + + tick(delta) { + if(Input.key_state_released(Key.escape)) { + IO.shutdown() + } + } //tick + + destroy() { + + System.print("unready!") + app.destroy() + + } //destroy + + app { _app } + app=(v) { _app=v } + +} //Game diff --git a/intersecting-circles-modifiers/modifiers/circle/circle.modifier.lx b/intersecting-circles-modifiers/modifiers/circle/circle.modifier.lx new file mode 100644 index 0000000..8d94a3c --- /dev/null +++ b/intersecting-circles-modifiers/modifiers/circle/circle.modifier.lx @@ -0,0 +1,12 @@ +modifier = { + script = "modifiers/cirle/circle" + description = "Intersecting circle modifier." + field = "circle" + display = "Circle" //the display in the editor + class = "Circle" //The code generated name for the modifier API + block = { //The data for the modifier + fields = [ + { name="radius" type="number" default=10 } + ] + } +} \ No newline at end of file diff --git a/intersecting-circles-modifiers/modifiers/circle/circle.modifier.wren b/intersecting-circles-modifiers/modifiers/circle/circle.modifier.wren new file mode 100644 index 0000000..d319bfc --- /dev/null +++ b/intersecting-circles-modifiers/modifiers/circle/circle.modifier.wren @@ -0,0 +1,466 @@ + +//-- this file is generated! don't try editing it. + +import "luxe: io" for IO +import "luxe: bytes" for Byter, Bytes +import "luxe: world" for Block + +//`modifiers/circle/circle > runtime` types + + class ModifierRuntime { + + construct new() { + } //new + + } //ModifierRuntime + +//`modifiers/circle/circle > runtime` compilers + + class ModifierRuntimeCompiler { + + construct new() { + } + + bytes_count(instance) { + + var size = 4 //version + + size = size + 0 + + return size + + } //bytes_count + + validate(from_source_id, elements) { + + var fields = { + "type": false, //:luxe:internal + "uuid": false, //:luxe:internal + "luxe.self.modifier": false, //:luxe:internal + } + for(element in elements) { + var instance = element.value + for(field in instance) { + if(fields[field.key] == null) { + Fiber.abort("node `%(element.key)` in `%(from_source_id)` has extra field `%(field.key)`") + } //if not found + } //each field + for(field in fields) { + var required = field.value + if(required && instance[field.key] == null) { + Fiber.abort("node `%(element.key)` in `%(from_source_id)` is missing a required field `%(field.key)` (and the field has no default value)") + } + } //each field + } //each element + + } //validate + + write(compiler, instance, out) { + + //version + out.write_int32(0) + + return out + + } //write + + bytes_count_block() { + + return 8 + + } //bytes_count_block + + write_block(compiler, out) { + + //source id + out.write_uint32(compiler.string.hash("modifiers/circle/circle > runtime")) + + //fields count + out.write_int32(0) + + } //write_block + + write(instance) { + + var size = bytes_count(instance) + var out = Byter.new(size+8) + + out.write_string("LUXEMRTM") + + write(instance, out) + + return out + + } //write + + } //ModifierRuntimeCompiler + +//`modifiers/circle/circle > runtime` block types + + class BlockModifierRuntime { + + field { "circle" } + source { "modifiers/circle/circle > runtime" } + + construct new(block) { + _block = block + _inst_type = instance_type + _inst = _inst_type.new(_block, 0) + } + + construct new() { + _block = Block.create() + _inst_type = instance_type + _inst = _inst_type.new(_block, 0) + Block.set_type(_block, "modifiers/circle/circle > runtime") + } //new + + instance_type { + + class BlockInstModifierRuntime { + slot { _slot } + entity { Block.get_handle(_block, _slot) } + block_set_slot(value) { + _slot=value + return this + } + construct new(block, slot) { + _block = block + _slot = slot + } //new + block { _block } + } //BlockInstModifierRuntime + + return BlockInstModifierRuntime + + } //instance_type + + block { _block } + count { Block.get_count(_block) } + add() { Block.add(_block) } + append(other_block) { Block.append(_block, other_block) } + each(c, fn) { + for(i in 0 ... c) { + fn.call(0, _inst.block_set_slot(i)) + } + } //each + + [slot, inst] { _inst.block_set_slot(slot) } + + [slot] { _inst_type.new(_block, slot) } + } //BlockModifierRuntime + + +//`modifiers/circle/circle > data` types + + class ModifierData { + + construct new() { + _radius = 10 + } //new + + radius { _radius } + radius=(vvv) { _radius = vvv } + + } //ModifierData + +//`modifiers/circle/circle > data` compilers + + class ModifierDataCompiler { + + construct new() { + } + + bytes_count(instance) { + + var size = 4 //version + + size = size + 8 // radius + + size = size + 0 + + return size + + } //bytes_count + + validate(from_source_id, elements) { + + var fields = { + "type": false, //:luxe:internal + "uuid": false, //:luxe:internal + "luxe.self.modifier": false, //:luxe:internal + "radius": false, + } + for(element in elements) { + var instance = element.value + for(field in instance) { + if(fields[field.key] == null) { + Fiber.abort("node `%(element.key)` in `%(from_source_id)` has extra field `%(field.key)`") + } //if not found + } //each field + for(field in fields) { + var required = field.value + if(required && instance[field.key] == null) { + Fiber.abort("node `%(element.key)` in `%(from_source_id)` is missing a required field `%(field.key)` (and the field has no default value)") + } + } //each field + } //each element + + } //validate + + write(compiler, instance, out) { + + //version + out.write_int32(0) + + var radius = instance["radius"] + if(radius == null) radius = 10 + out.write_float64(radius) + + + return out + + } //write + + bytes_count_block() { + + return 24 + + } //bytes_count_block + + write_block(compiler, out) { + + //source id + out.write_uint32(compiler.string.hash("modifiers/circle/circle > data")) + + //fields count + out.write_int32(1) + + // radius + out.write_uint32(compiler.string.hash("radius")) + out.write_uint32(467038368) //type number + var radius_default = 10 + out.write_float64(radius_default) + + + } //write_block + + write(instance) { + + var size = bytes_count(instance) + var out = Byter.new(size+8) + + out.write_string("LUXEMDTA") + + write(instance, out) + + return out + + } //write + + } //ModifierDataCompiler + +//`modifiers/circle/circle > data` block types + + class BlockModifierData { + + field { "circle" } + source { "modifiers/circle/circle > data" } + + construct new(block) { + _block = block + _inst_type = instance_type + _inst = _inst_type.new(_block, 0) + } + + construct new() { + _block = Block.create() + _inst_type = instance_type + _inst = _inst_type.new(_block, 0) + Block.add(_block, "radius", "number", 10) + Block.set_type(_block, "modifiers/circle/circle > data") + } //new + + instance_type { + + class BlockInstModifierData { + radius { Block.get(_block, "radius", _slot) } + radius=(v) { Block.set(_block, "radius", _slot, v) } + slot { _slot } + entity { Block.get_handle(_block, _slot) } + block_set_slot(value) { + _slot=value + return this + } + construct new(block, slot) { + _block = block + _slot = slot + } //new + block { _block } + } //BlockInstModifierData + + return BlockInstModifierData + + } //instance_type + + block { _block } + count { Block.get_count(_block) } + add() { Block.add(_block) } + append(other_block) { Block.append(_block, other_block) } + each(c, fn) { + for(i in 0 ... c) { + fn.call(0, _inst.block_set_slot(i)) + } + } //each + + [slot, inst] { _inst.block_set_slot(slot) } + + [slot] { _inst_type.new(_block, slot) } + } //BlockModifierData + + +//`modifiers/circle/circle > world` types + + class ModifierWorld { + + construct new() { + } //new + + } //ModifierWorld + +//`modifiers/circle/circle > world` compilers + + class ModifierWorldCompiler { + + construct new() { + } + + bytes_count(instance) { + + var size = 4 //version + + size = size + 0 + + return size + + } //bytes_count + + validate(from_source_id, elements) { + + var fields = { + "type": false, //:luxe:internal + "uuid": false, //:luxe:internal + "luxe.self.modifier": false, //:luxe:internal + } + for(element in elements) { + var instance = element.value + for(field in instance) { + if(fields[field.key] == null) { + Fiber.abort("node `%(element.key)` in `%(from_source_id)` has extra field `%(field.key)`") + } //if not found + } //each field + for(field in fields) { + var required = field.value + if(required && instance[field.key] == null) { + Fiber.abort("node `%(element.key)` in `%(from_source_id)` is missing a required field `%(field.key)` (and the field has no default value)") + } + } //each field + } //each element + + } //validate + + write(compiler, instance, out) { + + //version + out.write_int32(0) + + return out + + } //write + + bytes_count_block() { + + return 8 + + } //bytes_count_block + + write_block(compiler, out) { + + //source id + out.write_uint32(compiler.string.hash("modifiers/circle/circle > world")) + + //fields count + out.write_int32(0) + + } //write_block + + write(instance) { + + var size = bytes_count(instance) + var out = Byter.new(size+8) + + out.write_string("LUXEMWLD") + + write(instance, out) + + return out + + } //write + + } //ModifierWorldCompiler + +//`modifiers/circle/circle > world` block types + + class BlockModifierWorld { + + field { "circle" } + source { "modifiers/circle/circle > world" } + + construct new(block) { + _block = block + _inst_type = instance_type + _inst = _inst_type.new(_block, 0) + } + + construct new() { + _block = Block.create() + _inst_type = instance_type + _inst = _inst_type.new(_block, 0) + Block.set_type(_block, "modifiers/circle/circle > world") + } //new + + instance_type { + + class BlockInstModifierWorld { + slot { _slot } + entity { Block.get_handle(_block, _slot) } + block_set_slot(value) { + _slot=value + return this + } + construct new(block, slot) { + _block = block + _slot = slot + } //new + block { _block } + } //BlockInstModifierWorld + + return BlockInstModifierWorld + + } //instance_type + + block { _block } + count { Block.get_count(_block) } + add() { Block.add(_block) } + append(other_block) { Block.append(_block, other_block) } + each(c, fn) { + for(i in 0 ... c) { + fn.call(0, _inst.block_set_slot(i)) + } + } //each + + [slot, inst] { _inst.block_set_slot(slot) } + + [slot] { _inst_type.new(_block, slot) } + } //BlockModifierWorld + diff --git a/intersecting-circles-modifiers/modifiers/circle/circle.wren b/intersecting-circles-modifiers/modifiers/circle/circle.wren new file mode 100644 index 0000000..4bb5536 --- /dev/null +++ b/intersecting-circles-modifiers/modifiers/circle/circle.wren @@ -0,0 +1,113 @@ +import "luxe: io" for IO +import "luxe: world" for World, Entity, Modifiers, ModifierSystem, Transform +import "random" for Random +import "luxe: draw" for Draw, PathStyle +import "luxe: math" for Math +import "luxe: color" for Color +import "luxe: render" for Render +import "util" for Util +import "modifiers/circle/circle.modifier" for ModifierData as CircleData +import "luxe: world" for Block + +//User facing API +//This is what the user of your modifier will interact with +class Circle { + + static create(entity) { Modifiers.create(This, entity) } + static destroy(entity) { Modifiers.destroy(This, entity) } + static has(entity) { Modifiers.has(This, entity) } + + static set_radius(entity, radius) { + var data = Modifiers.get(This, entity) + data.radius = radius + } + + static get_radius(entity) { + var data = Modifiers.get(This, entity) + return data.radius + } + +} //Circle + +//Your modifier system implementation. +//This speaks to the engine and your user facing API +//to do the actual work. You'll get notified when things change +//in the world and respond to them here. +class CircleSystem is ModifierSystem { + + construct new() { + _rng = Random.new() + + //setup draw styles + _circle_style = PathStyle.new() + _circle_style.color = Color.white + _circle_style.thickness = 1 + + _intersection_style = PathStyle.new() + _intersection_style.color = Color.hex(0xFFFF99) + _intersection_style.thickness = 2 + } + + init(world) { + _world = world + _draw = Draw.create(World.render_set(world)) + } + + destroy() { + Draw.destroy(_draw) + } + + attach(entity, data) { + //called when attached to an entity + } + + detach(entity, data) { + //called when detached from an entity, like on destroy + } + + tick(delta) { + //called usually once every frame. + //called when the world that this modifier lives in, is ticked + + //draw each circle + each{|entity: Entity, data: CircleData| + var pos = Transform.get_pos(entity) + Draw.ring(_draw, pos.x, pos.y, pos.z, data.radius, data.radius, 0, 360, 8, _circle_style) + } + + //then do intersections between all circle pairs + for(i in 0...count){ + //get data of 1st entity + var slot_1 = Block.get_slot_at(data.block, i) + var entity_1 = Block.get_handle(data.block, slot_1) + var radius_1 = data[slot_1, true].radius //its important to get out the radius here because data always gives out the same reference + if(!Entity.valid(entity_1)) continue + var pos_1 = Transform.get_pos(entity_1) + + for(ii in 0...i){ + //get data of second entity + var slot_2 = Block.get_slot_at(data.block, ii) + var entity_2 = Block.get_handle(data.block, slot_2) + var radius_2 = data[slot_2, true].radius + if(!Entity.valid(entity_2)) continue + var pos_2 = Transform.get_pos(entity_2) + + var intersections = Util.circle_intersect_circle(pos_1, radius_1, pos_2, radius_2) + if(intersections){ //and if we found any, draw them + Draw.line(_draw, intersections[0].x, intersections[0].y, intersections[1].x, intersections[1].y, 0, _intersection_style) + + Draw.circle(_draw, intersections[0].x, intersections[0].y, 0, 8, 8, [1, 1, 1, 0.2]) + Draw.circle(_draw, intersections[1].x, intersections[1].y, 0, 8, 8, [1, 1, 1, 0.2]) + + Draw.circle(_draw, intersections[0].x, intersections[0].y, 0, 3, 3, [1, 1, 1, 1]) + Draw.circle(_draw, intersections[1].x, intersections[1].y, 0, 3, 3, [1, 1, 1, 1]) + } + } + } + + Draw.commit(_draw) + } //tick + +} //CircleSystem + +var Modifier = CircleSystem //required diff --git a/intersecting-circles-modifiers/modifiers/move/move.modifier.lx b/intersecting-circles-modifiers/modifiers/move/move.modifier.lx new file mode 100644 index 0000000..8b72963 --- /dev/null +++ b/intersecting-circles-modifiers/modifiers/move/move.modifier.lx @@ -0,0 +1,12 @@ +modifier = { + script = "modifiers/move/move" + description = "Constant movement." + field = "move" + display = "Move" //the display in the editor + class = "Move" //The code generated name for the modifier API + block = { //The data for the modifier + fields = [ + { name="velocity" type="float2" default=[0, 0] } + ] + } +} \ No newline at end of file diff --git a/intersecting-circles-modifiers/modifiers/move/move.modifier.wren b/intersecting-circles-modifiers/modifiers/move/move.modifier.wren new file mode 100644 index 0000000..4c14e60 --- /dev/null +++ b/intersecting-circles-modifiers/modifiers/move/move.modifier.wren @@ -0,0 +1,468 @@ + +//-- this file is generated! don't try editing it. + +import "luxe: io" for IO +import "luxe: bytes" for Byter, Bytes +import "luxe: world" for Block + +//`modifiers/move/move > runtime` types + + class ModifierRuntime { + + construct new() { + } //new + + } //ModifierRuntime + +//`modifiers/move/move > runtime` compilers + + class ModifierRuntimeCompiler { + + construct new() { + } + + bytes_count(instance) { + + var size = 4 //version + + size = size + 0 + + return size + + } //bytes_count + + validate(from_source_id, elements) { + + var fields = { + "type": false, //:luxe:internal + "uuid": false, //:luxe:internal + "luxe.self.modifier": false, //:luxe:internal + } + for(element in elements) { + var instance = element.value + for(field in instance) { + if(fields[field.key] == null) { + Fiber.abort("node `%(element.key)` in `%(from_source_id)` has extra field `%(field.key)`") + } //if not found + } //each field + for(field in fields) { + var required = field.value + if(required && instance[field.key] == null) { + Fiber.abort("node `%(element.key)` in `%(from_source_id)` is missing a required field `%(field.key)` (and the field has no default value)") + } + } //each field + } //each element + + } //validate + + write(compiler, instance, out) { + + //version + out.write_int32(0) + + return out + + } //write + + bytes_count_block() { + + return 8 + + } //bytes_count_block + + write_block(compiler, out) { + + //source id + out.write_uint32(compiler.string.hash("modifiers/move/move > runtime")) + + //fields count + out.write_int32(0) + + } //write_block + + write(instance) { + + var size = bytes_count(instance) + var out = Byter.new(size+8) + + out.write_string("LUXEMRTM") + + write(instance, out) + + return out + + } //write + + } //ModifierRuntimeCompiler + +//`modifiers/move/move > runtime` block types + + class BlockModifierRuntime { + + field { "move" } + source { "modifiers/move/move > runtime" } + + construct new(block) { + _block = block + _inst_type = instance_type + _inst = _inst_type.new(_block, 0) + } + + construct new() { + _block = Block.create() + _inst_type = instance_type + _inst = _inst_type.new(_block, 0) + Block.set_type(_block, "modifiers/move/move > runtime") + } //new + + instance_type { + + class BlockInstModifierRuntime { + slot { _slot } + entity { Block.get_handle(_block, _slot) } + block_set_slot(value) { + _slot=value + return this + } + construct new(block, slot) { + _block = block + _slot = slot + } //new + block { _block } + } //BlockInstModifierRuntime + + return BlockInstModifierRuntime + + } //instance_type + + block { _block } + count { Block.get_count(_block) } + add() { Block.add(_block) } + append(other_block) { Block.append(_block, other_block) } + each(c, fn) { + for(i in 0 ... c) { + fn.call(0, _inst.block_set_slot(i)) + } + } //each + + [slot, inst] { _inst.block_set_slot(slot) } + + [slot] { _inst_type.new(_block, slot) } + } //BlockModifierRuntime + + +//`modifiers/move/move > data` types + + class ModifierData { + + construct new() { + _velocity = [0, 0] + } //new + + velocity { _velocity } + velocity=(vvv) { _velocity = vvv } + + } //ModifierData + +//`modifiers/move/move > data` compilers + + class ModifierDataCompiler { + + construct new() { + } + + bytes_count(instance) { + + var size = 4 //version + + size = size + 8 // velocity + + size = size + 0 + + return size + + } //bytes_count + + validate(from_source_id, elements) { + + var fields = { + "type": false, //:luxe:internal + "uuid": false, //:luxe:internal + "luxe.self.modifier": false, //:luxe:internal + "velocity": false, + } + for(element in elements) { + var instance = element.value + for(field in instance) { + if(fields[field.key] == null) { + Fiber.abort("node `%(element.key)` in `%(from_source_id)` has extra field `%(field.key)`") + } //if not found + } //each field + for(field in fields) { + var required = field.value + if(required && instance[field.key] == null) { + Fiber.abort("node `%(element.key)` in `%(from_source_id)` is missing a required field `%(field.key)` (and the field has no default value)") + } + } //each field + } //each element + + } //validate + + write(compiler, instance, out) { + + //version + out.write_int32(0) + + var velocity = instance["velocity"] + if(velocity == null) velocity = [0, 0] + out.write_float32(velocity[0]) + out.write_float32(velocity[1]) + + + return out + + } //write + + bytes_count_block() { + + return 24 + + } //bytes_count_block + + write_block(compiler, out) { + + //source id + out.write_uint32(compiler.string.hash("modifiers/move/move > data")) + + //fields count + out.write_int32(1) + + // velocity + out.write_uint32(compiler.string.hash("velocity")) + out.write_uint32(1042253589) //type float2 + var velocity_default = [0, 0] + out.write_float32(velocity_default[0]) + out.write_float32(velocity_default[1]) + + + } //write_block + + write(instance) { + + var size = bytes_count(instance) + var out = Byter.new(size+8) + + out.write_string("LUXEMDTA") + + write(instance, out) + + return out + + } //write + + } //ModifierDataCompiler + +//`modifiers/move/move > data` block types + + class BlockModifierData { + + field { "move" } + source { "modifiers/move/move > data" } + + construct new(block) { + _block = block + _inst_type = instance_type + _inst = _inst_type.new(_block, 0) + } + + construct new() { + _block = Block.create() + _inst_type = instance_type + _inst = _inst_type.new(_block, 0) + Block.add(_block, "velocity", "float2", [0, 0]) + Block.set_type(_block, "modifiers/move/move > data") + } //new + + instance_type { + + class BlockInstModifierData { + velocity { Block.get(_block, "velocity", _slot) } + velocity=(v) { Block.set(_block, "velocity", _slot, v) } + slot { _slot } + entity { Block.get_handle(_block, _slot) } + block_set_slot(value) { + _slot=value + return this + } + construct new(block, slot) { + _block = block + _slot = slot + } //new + block { _block } + } //BlockInstModifierData + + return BlockInstModifierData + + } //instance_type + + block { _block } + count { Block.get_count(_block) } + add() { Block.add(_block) } + append(other_block) { Block.append(_block, other_block) } + each(c, fn) { + for(i in 0 ... c) { + fn.call(0, _inst.block_set_slot(i)) + } + } //each + + [slot, inst] { _inst.block_set_slot(slot) } + + [slot] { _inst_type.new(_block, slot) } + } //BlockModifierData + + +//`modifiers/move/move > world` types + + class ModifierWorld { + + construct new() { + } //new + + } //ModifierWorld + +//`modifiers/move/move > world` compilers + + class ModifierWorldCompiler { + + construct new() { + } + + bytes_count(instance) { + + var size = 4 //version + + size = size + 0 + + return size + + } //bytes_count + + validate(from_source_id, elements) { + + var fields = { + "type": false, //:luxe:internal + "uuid": false, //:luxe:internal + "luxe.self.modifier": false, //:luxe:internal + } + for(element in elements) { + var instance = element.value + for(field in instance) { + if(fields[field.key] == null) { + Fiber.abort("node `%(element.key)` in `%(from_source_id)` has extra field `%(field.key)`") + } //if not found + } //each field + for(field in fields) { + var required = field.value + if(required && instance[field.key] == null) { + Fiber.abort("node `%(element.key)` in `%(from_source_id)` is missing a required field `%(field.key)` (and the field has no default value)") + } + } //each field + } //each element + + } //validate + + write(compiler, instance, out) { + + //version + out.write_int32(0) + + return out + + } //write + + bytes_count_block() { + + return 8 + + } //bytes_count_block + + write_block(compiler, out) { + + //source id + out.write_uint32(compiler.string.hash("modifiers/move/move > world")) + + //fields count + out.write_int32(0) + + } //write_block + + write(instance) { + + var size = bytes_count(instance) + var out = Byter.new(size+8) + + out.write_string("LUXEMWLD") + + write(instance, out) + + return out + + } //write + + } //ModifierWorldCompiler + +//`modifiers/move/move > world` block types + + class BlockModifierWorld { + + field { "move" } + source { "modifiers/move/move > world" } + + construct new(block) { + _block = block + _inst_type = instance_type + _inst = _inst_type.new(_block, 0) + } + + construct new() { + _block = Block.create() + _inst_type = instance_type + _inst = _inst_type.new(_block, 0) + Block.set_type(_block, "modifiers/move/move > world") + } //new + + instance_type { + + class BlockInstModifierWorld { + slot { _slot } + entity { Block.get_handle(_block, _slot) } + block_set_slot(value) { + _slot=value + return this + } + construct new(block, slot) { + _block = block + _slot = slot + } //new + block { _block } + } //BlockInstModifierWorld + + return BlockInstModifierWorld + + } //instance_type + + block { _block } + count { Block.get_count(_block) } + add() { Block.add(_block) } + append(other_block) { Block.append(_block, other_block) } + each(c, fn) { + for(i in 0 ... c) { + fn.call(0, _inst.block_set_slot(i)) + } + } //each + + [slot, inst] { _inst.block_set_slot(slot) } + + [slot] { _inst_type.new(_block, slot) } + } //BlockModifierWorld + diff --git a/intersecting-circles-modifiers/modifiers/move/move.wren b/intersecting-circles-modifiers/modifiers/move/move.wren new file mode 100644 index 0000000..e8b8b2a --- /dev/null +++ b/intersecting-circles-modifiers/modifiers/move/move.wren @@ -0,0 +1,72 @@ +import "luxe: io" for IO +import "luxe: world" for World, Entity, Modifiers, ModifierSystem, Transform +import "luxe: render" for Render +import "modifiers/circle/circle" for Circle + +//User facing API +//This is what the user of your modifier will interact with +class Move { + + static create(entity) { Modifiers.create(This, entity) } + static destroy(entity) { Modifiers.destroy(This, entity) } + static has(entity) { Modifiers.has(This, entity) } + + static set_velocity(entity, velocity) { + var data = Modifiers.get(This, entity) + data.velocity = velocity + } + +} //Move + +//Your modifier system implementation. +//This speaks to the engine and your user facing API +//to do the actual work. You'll get notified when things change +//in the world and respond to them here. +class MoveSystem is ModifierSystem { + + construct new() { + //called when your system is first created. + } + + init(world) { + _world = world + //called when your modifier is created in a world + } + + destroy() { + //called when your modifier is removed from a world + } + + attach(entity, data) { + //called when attached to an entity + } + + detach(entity, data) { + //called when detached from an entity, like on destroy + } + + tick(delta) { + //called usually once every frame. + //called when the world that this modifier lives in, is ticked + + var width = Render.window_w() + var height = Render.window_h() + + each {|entity, data| + var pos = Transform.get_pos(entity) + var radius = Circle.get_radius(entity) + //update pos + pos.x = pos.x + data.velocity.x * delta + pos.y = pos.y + data.velocity.y * delta + if(pos.x < -radius) pos.x = pos.x + width + radius*2 + if(pos.x > width + radius) pos.x = pos.x - width - radius*2 + if(pos.y < -radius) pos.y = pos.y + height + radius*2 + if(pos.y > height + radius) pos.y = pos.y - height - radius*2 + //set pos + Transform.set_pos(entity, pos.x, pos.y, pos.z) + } + } //tick + +} //MoveSystem + +var Modifier = MoveSystem //required diff --git a/intersecting-circles-modifiers/outline/app.wren b/intersecting-circles-modifiers/outline/app.wren new file mode 100644 index 0000000..a0f1768 --- /dev/null +++ b/intersecting-circles-modifiers/outline/app.wren @@ -0,0 +1,74 @@ +import "luxe: world" for World, Camera, Entity, Transform +import "luxe: render" for Render +import "luxe: game" for Frame + +class App { + + world { _world } + ui { _ui_world } + + camera { _camera } + ui_camera { _ui_camera } + + color { _color } + color=(v) { _color = v } + + width { Render.window_w() } + height { Render.window_h() } + scale { Render.drawable_ratio() } + + construct new() { + + _color = [1,1,1,1] + + //create worlds + + _world = World.create("game") + _ui_world = World.create("ui") + + //create cameras + + _camera = Entity.create(_world, "app.camera") + Transform.create(_camera) + Camera.create(_camera) + Camera.set_default(_world, _camera) + + _ui_camera = Entity.create(_ui_world, "app.ui_camera") + Transform.create(_ui_camera) + Camera.create(_ui_camera) + Camera.set_default(_ui_world, _ui_camera) + + //update our worlds + + Frame.on(Frame.sim) {|delta| + World.tick(_world, delta) + World.tick(_ui_world, delta) + } + + //render our worlds + + Frame.on(Frame.visual) {|delta| + World.render(_world, _camera, "game", {"clear_color":_color}) + World.render(_ui_world, _ui_camera, "ui") + } + + } //new + + destroy() { + + //destroy cameras + + Camera.destroy(_camera) + Camera.destroy(_ui_camera) + + Entity.destroy(_camera) + Entity.destroy(_ui_camera) + + //destroy worlds + + World.destroy(_ui_world) + World.destroy(_world) + + } //destroy + +} // diff --git a/intersecting-circles-modifiers/outline/inputs.input.lx b/intersecting-circles-modifiers/outline/inputs.input.lx new file mode 100644 index 0000000..dc45459 --- /dev/null +++ b/intersecting-circles-modifiers/outline/inputs.input.lx @@ -0,0 +1,23 @@ +input = { + nodes = [ + { name = "ui" where = "front" channels = ["c01"] } + { name = "game" where = "after: ui" channels = ["c02"] } + ] + + map = { + left = { keys = ["key_a", "left"] } + right = { keys = ["key_d", "right"] } + up = { keys = ["key_w", "up"] } + down = { keys = ["key_s", "down"] } + jump = { + keys = ["key_x", "up", "key_w", "space"] + mouse = ["left"] + gamepad = [0] + } + + next = { + keys = ["key_x", "up", "key_w", "space", "enter", "escape"] + mouse = ["left", "right"] + } + } +} diff --git a/intersecting-circles-modifiers/outline/renderer.wren b/intersecting-circles-modifiers/outline/renderer.wren new file mode 100644 index 0000000..8c00ab4 --- /dev/null +++ b/intersecting-circles-modifiers/outline/renderer.wren @@ -0,0 +1,51 @@ +import "luxe: render" for Render, RenderLayerDesc, PassLayerDesc, LoadAction +import "luxe: render" for SortType, ImageDesc, ImageType, PixelFormat + +class Renderer { + + construct new() { + + System.print("game / render / init / ok") + + } //new + + ready() { + + } + + tick(delta) { + + } + + render_path(ctx) { + + if(ctx.path == "game") { + game_render_path(ctx) + } else if(ctx.path == "ui") { + ui_render_path(ctx) + } + + } //render_path + + game_render_path(ctx) { + + var layer = RenderLayerDesc.new() + layer.dest.color[0].clear_color = ctx.get("clear_color", [1,1,1,1]) + layer.dest.color[0].load_action = LoadAction.clear + layer.dest.depth.load_action = LoadAction.clear + + ctx.layer_render("default", layer) + + } //game_render_path + + ui_render_path(ctx) { + + var layer = RenderLayerDesc.new() + layer.dest.color[0].load_action = LoadAction.dont_care + layer.dest.depth.load_action = LoadAction.clear + + ctx.layer_render("default", layer) + + } //ui_render_path + +} //Renderer diff --git a/intersecting-circles-modifiers/outline/settings.settings.lx b/intersecting-circles-modifiers/outline/settings.settings.lx new file mode 100644 index 0000000..9d1ad01 --- /dev/null +++ b/intersecting-circles-modifiers/outline/settings.settings.lx @@ -0,0 +1,17 @@ +engine = { + input.entry = "outline/inputs" + runtime = { + window = { + width = 960 + height = 640 + resizable = false + fullscreen = false + } + } + + render = { + antialiasing = 8 + stencil = 8 + depth = 24 + } +} \ No newline at end of file diff --git a/intersecting-circles-modifiers/project.luxe b/intersecting-circles-modifiers/project.luxe new file mode 100644 index 0000000..856a7c1 --- /dev/null +++ b/intersecting-circles-modifiers/project.luxe @@ -0,0 +1,14 @@ +import "luxe: project" for Entry + +class Project is Entry { + + construct entry(target) { + + name = "Intersecting Circles (modifiers)" + version = "1.0.0" + renderer = "outline/renderer" + settings = "outline/settings" + + } //new + +} //Project \ No newline at end of file diff --git a/intersecting-circles-modifiers/project.modules.lx b/intersecting-circles-modifiers/project.modules.lx new file mode 100644 index 0000000..50dd33d --- /dev/null +++ b/intersecting-circles-modifiers/project.modules.lx @@ -0,0 +1,3 @@ +modules = { + luxe = "2021.0.10" +} //modules diff --git a/intersecting-circles-modifiers/util.wren b/intersecting-circles-modifiers/util.wren new file mode 100644 index 0000000..d26effd --- /dev/null +++ b/intersecting-circles-modifiers/util.wren @@ -0,0 +1,32 @@ +import "luxe: math" for Math + +class Util{ + //cirle circle intersections, largely taken from http://paulbourke.net/geometry/circlesphere/ + static circle_intersect_circle(o1, r1, o2, r2){ + var diff_x = o2.x - o1.x + var diff_y = o2.y - o1.y + + var distance = Math.length(diff_x, diff_y) + if(distance > r1 + r2) return //too far away + if(distance < (r1 - r2).abs) return //contain each other + if(distance <= Num.smallest) return //infinite solutions + + var a = (r1*r1 - r2*r2 + distance*distance) / (2 * distance) //adjacient length of triangle between o1, midpoint and intersection + var h = (r1*r1 - a*a).sqrt //hypotenuse length of triangle between o1, midpoint and intersection + + var mid_x = o1.x + a * (o2.x - o1.x) / distance + var mid_y = o1.y + a * (o2.y - o1.y) / distance + + var inter1 = [ + mid_x + h * diff_y / distance, + mid_y - h * diff_x / distance + ] + + var inter2 = [ + mid_x - h * diff_y / distance, + mid_y + h * diff_x / distance + ] + + return [inter1, inter2] + } +} \ No newline at end of file