initial commit
This commit is contained in:
commit
3df59353e6
28 changed files with 1818 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
.vscode
|
||||
10
intersecting-circles-manual/.gitignore
vendored
Normal file
10
intersecting-circles-manual/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
*/.DS_Store
|
||||
.DS_Store
|
||||
.DS_Store?
|
||||
*/thumbs.db
|
||||
thumbs.db
|
||||
.thumbs.db?
|
||||
.luxe/
|
||||
_luxe.data/
|
||||
_luxe.deploy/
|
||||
log.txt
|
||||
1
intersecting-circles-manual/.luxeignore
Normal file
1
intersecting-circles-manual/.luxeignore
Normal file
|
|
@ -0,0 +1 @@
|
|||
preview.png
|
||||
113
intersecting-circles-manual/circle_manager.wren
Normal file
113
intersecting-circles-manual/circle_manager.wren
Normal file
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
47
intersecting-circles-manual/game.wren
Normal file
47
intersecting-circles-manual/game.wren
Normal file
|
|
@ -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
|
||||
74
intersecting-circles-manual/outline/app.wren
Normal file
74
intersecting-circles-manual/outline/app.wren
Normal file
|
|
@ -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
|
||||
|
||||
} //
|
||||
23
intersecting-circles-manual/outline/inputs.input.lx
Normal file
23
intersecting-circles-manual/outline/inputs.input.lx
Normal file
|
|
@ -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"]
|
||||
}
|
||||
}
|
||||
}
|
||||
51
intersecting-circles-manual/outline/renderer.wren
Normal file
51
intersecting-circles-manual/outline/renderer.wren
Normal file
|
|
@ -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
|
||||
17
intersecting-circles-manual/outline/settings.settings.lx
Normal file
17
intersecting-circles-manual/outline/settings.settings.lx
Normal file
|
|
@ -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
|
||||
}
|
||||
}
|
||||
14
intersecting-circles-manual/project.luxe
Normal file
14
intersecting-circles-manual/project.luxe
Normal file
|
|
@ -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
|
||||
3
intersecting-circles-manual/project.modules.lx
Normal file
3
intersecting-circles-manual/project.modules.lx
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
modules = {
|
||||
luxe = "2021.0.10"
|
||||
} //modules
|
||||
32
intersecting-circles-manual/util.wren
Normal file
32
intersecting-circles-manual/util.wren
Normal file
|
|
@ -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]
|
||||
}
|
||||
}
|
||||
10
intersecting-circles-modifiers/.gitignore
vendored
Normal file
10
intersecting-circles-modifiers/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
*/.DS_Store
|
||||
.DS_Store
|
||||
.DS_Store?
|
||||
*/thumbs.db
|
||||
thumbs.db
|
||||
.thumbs.db?
|
||||
.luxe/
|
||||
_luxe.data/
|
||||
_luxe.deploy/
|
||||
log.txt
|
||||
1
intersecting-circles-modifiers/.luxeignore
Normal file
1
intersecting-circles-modifiers/.luxeignore
Normal file
|
|
@ -0,0 +1 @@
|
|||
preview.png
|
||||
64
intersecting-circles-modifiers/game.wren
Normal file
64
intersecting-circles-modifiers/game.wren
Normal file
|
|
@ -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
|
||||
|
|
@ -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 }
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
||||
113
intersecting-circles-modifiers/modifiers/circle/circle.wren
Normal file
113
intersecting-circles-modifiers/modifiers/circle/circle.wren
Normal file
|
|
@ -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
|
||||
|
|
@ -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] }
|
||||
]
|
||||
}
|
||||
}
|
||||
468
intersecting-circles-modifiers/modifiers/move/move.modifier.wren
Normal file
468
intersecting-circles-modifiers/modifiers/move/move.modifier.wren
Normal file
|
|
@ -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
|
||||
|
||||
72
intersecting-circles-modifiers/modifiers/move/move.wren
Normal file
72
intersecting-circles-modifiers/modifiers/move/move.wren
Normal file
|
|
@ -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
|
||||
74
intersecting-circles-modifiers/outline/app.wren
Normal file
74
intersecting-circles-modifiers/outline/app.wren
Normal file
|
|
@ -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
|
||||
|
||||
} //
|
||||
23
intersecting-circles-modifiers/outline/inputs.input.lx
Normal file
23
intersecting-circles-modifiers/outline/inputs.input.lx
Normal file
|
|
@ -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"]
|
||||
}
|
||||
}
|
||||
}
|
||||
51
intersecting-circles-modifiers/outline/renderer.wren
Normal file
51
intersecting-circles-modifiers/outline/renderer.wren
Normal file
|
|
@ -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
|
||||
17
intersecting-circles-modifiers/outline/settings.settings.lx
Normal file
17
intersecting-circles-modifiers/outline/settings.settings.lx
Normal file
|
|
@ -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
|
||||
}
|
||||
}
|
||||
14
intersecting-circles-modifiers/project.luxe
Normal file
14
intersecting-circles-modifiers/project.luxe
Normal file
|
|
@ -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
|
||||
3
intersecting-circles-modifiers/project.modules.lx
Normal file
3
intersecting-circles-modifiers/project.modules.lx
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
modules = {
|
||||
luxe = "2021.0.10"
|
||||
} //modules
|
||||
32
intersecting-circles-modifiers/util.wren
Normal file
32
intersecting-circles-modifiers/util.wren
Normal file
|
|
@ -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]
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue