initial commit

This commit is contained in:
Ronja 2021-12-14 12:52:41 +01:00
commit 3df59353e6
28 changed files with 1818 additions and 0 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
.vscode

10
intersecting-circles-manual/.gitignore vendored Normal file
View file

@ -0,0 +1,10 @@
*/.DS_Store
.DS_Store
.DS_Store?
*/thumbs.db
thumbs.db
.thumbs.db?
.luxe/
_luxe.data/
_luxe.deploy/
log.txt

View file

@ -0,0 +1 @@
preview.png

View 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)
}
}
}

View 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

View 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
} //

View 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"]
}
}
}

View 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

View 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
}
}

View 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

View file

@ -0,0 +1,3 @@
modules = {
luxe = "2021.0.10"
} //modules

View 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]
}
}

View file

@ -0,0 +1,10 @@
*/.DS_Store
.DS_Store
.DS_Store?
*/thumbs.db
thumbs.db
.thumbs.db?
.luxe/
_luxe.data/
_luxe.deploy/
log.txt

View file

@ -0,0 +1 @@
preview.png

View 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

View file

@ -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 }
]
}
}

View file

@ -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

View 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

View file

@ -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] }
]
}
}

View 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

View 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

View 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
} //

View 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"]
}
}
}

View 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

View 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
}
}

View 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

View file

@ -0,0 +1,3 @@
modules = {
luxe = "2021.0.10"
} //modules

View 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]
}
}