From cca768b48d4cf8dfba559d77599f9d8b47baafaf Mon Sep 17 00:00:00 2001 From: Ronja Date: Sun, 23 May 2021 19:43:54 +0200 Subject: [PATCH] add slot modifier with snapping --- field.wren | 13 +- game.wren | 4 +- material/card.material.lx | 7 + material/hexagon.material.lx | 7 +- modifiers/slot/slot.modifier.lx | 16 + modifiers/slot/slot.modifier.wren | 470 ++++++++++++++++++++++++++++++ modifiers/slot/slot.wren | 59 ++++ outline/settings.settings.lx | 4 +- prototype/card.prototype.lx | 24 +- prototype/layout_7x5.prototype.lx | 76 +++++ utils/hex.wren | 63 ++++ 11 files changed, 713 insertions(+), 30 deletions(-) create mode 100644 material/card.material.lx create mode 100644 modifiers/slot/slot.modifier.lx create mode 100644 modifiers/slot/slot.modifier.wren create mode 100644 modifiers/slot/slot.wren create mode 100644 prototype/layout_7x5.prototype.lx create mode 100644 utils/hex.wren diff --git a/field.wren b/field.wren index 13160c7..c966d7b 100644 --- a/field.wren +++ b/field.wren @@ -1,5 +1,6 @@ import "luxe: world" for Prototype, Entity, Transform import "utils/vec" for Vec +import "utils/hex" for Hex var Slots = [ @@ -15,13 +16,6 @@ var Hand = [ [-2, 2, 0], [-1, 1, 0], [ 0, 0, 0], [ 1, -1, 0], [ 2, -2, 0] ] -var x_angle = 1 * Num.tau / 12 -var y_angle = 5 * Num.tau / 12 -var z_angle = 9 * Num.tau / 12 -var X_Dir = [x_angle.cos, x_angle.sin, 0] -var Y_Dir = [y_angle.cos, y_angle.sin, 0] -var Z_Dir = [z_angle.cos, z_angle.sin, 0] - class Field{ root{_root} @@ -34,9 +28,8 @@ class Field{ } add_slot(slot: List /*of Num*/){ - var pos = Vec.add(Vec.add(Vec.mul(slot.x, X_Dir), Vec.mul(slot.y, Y_Dir)), Vec.mul(slot.z, Z_Dir)) - pos = Vec.mul(pos, 66) - var new_instance = Prototype.create(_world, "prototype/card", "card(%(slot.x), %(slot.y), %(slot.z))", pos, [0,0,0], [2,2,2]) + var pos = Hex.coord_to_pos(slot, 66) + var new_instance = Prototype.create(_world, "prototype/card", "slot(%(slot.x), %(slot.y), %(slot.z))", pos, [0,0,0], [2,2,2]) Transform.link(new_instance, _root) } diff --git a/game.wren b/game.wren index b2f4181..56fa1aa 100644 --- a/game.wren +++ b/game.wren @@ -6,8 +6,9 @@ import "luxe: math" for Math import "luxe: draw" for Draw import "luxe: io" for IO import "luxe: lx" for LX -import "field" for Field, Slots, Hand +import "field" for Field, Slots, Hand +import "utils/hex" for Hex import "outline/app" for App class Game is Ready { @@ -41,6 +42,7 @@ class Game is Ready { tick(delta) { var pos = Camera.screen_point_to_world(app.camera, Input.mouse_x(), Input.mouse_y()) + pos = Hex.coord_to_pos(Hex.pos_to_coord(pos, 50), 50) Transform.set_pos(_logo, pos.x, pos.y, 100) if(Input.key_state_released(Key.escape)) { diff --git a/material/card.material.lx b/material/card.material.lx new file mode 100644 index 0000000..eba4fb4 --- /dev/null +++ b/material/card.material.lx @@ -0,0 +1,7 @@ +material = { + basis = "shaders/sprite_masked" + inputs = { + sprite.image = "assets/prototype/SharkCard" + sprite.mask = "assets/prototype/Hexagon" + } +} diff --git a/material/hexagon.material.lx b/material/hexagon.material.lx index eba4fb4..aeed6ce 100644 --- a/material/hexagon.material.lx +++ b/material/hexagon.material.lx @@ -1,7 +1,4 @@ material = { - basis = "shaders/sprite_masked" - inputs = { - sprite.image = "assets/prototype/SharkCard" - sprite.mask = "assets/prototype/Hexagon" - } + basis = "luxe: material_basis/sprite" + inputs = { sprite.image = "assets/prototype/Hexagon" } } diff --git a/modifiers/slot/slot.modifier.lx b/modifiers/slot/slot.modifier.lx new file mode 100644 index 0000000..cad68d6 --- /dev/null +++ b/modifiers/slot/slot.modifier.lx @@ -0,0 +1,16 @@ +modifier = { + description = "A slot on the playing field" + field = "slot" + display = "Slot" + class = "Slot" + dependency = [] + + blocks = { + data = { + fields = [ + { name="coord" type="float3" default=[0, 0, 0] } + ] + } + } +} + diff --git a/modifiers/slot/slot.modifier.wren b/modifiers/slot/slot.modifier.wren new file mode 100644 index 0000000..8ef57d2 --- /dev/null +++ b/modifiers/slot/slot.modifier.wren @@ -0,0 +1,470 @@ + +//-- 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/slot/slot > runtime` types + + class ModifierRuntime { + + construct new() { + } //new + + } //ModifierRuntime + +//`modifiers/slot/slot > 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/slot/slot > 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/slot/slot > runtime` block types + + class BlockModifierRuntime { + + field { "slot" } + source { "modifiers/slot/slot > 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/slot/slot > 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/slot/slot > data` types + + class ModifierData { + + construct new() { + _coord = [0, 0, 0] + } //new + + coord { _coord } + coord=(vvv) { _coord = vvv } + + } //ModifierData + +//`modifiers/slot/slot > data` compilers + + class ModifierDataCompiler { + + construct new() { + } + + bytes_count(instance) { + + var size = 4 //version + + size = size + 12 // coord + + 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 + "coord": 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 coord = instance["coord"] + if(coord == null) coord = [0, 0, 0] + out.write_float32(coord[0]) + out.write_float32(coord[1]) + out.write_float32(coord[2]) + + + return out + + } //write + + bytes_count_block() { + + return 28 + + } //bytes_count_block + + write_block(compiler, out) { + + //source id + out.write_uint32(compiler.string.hash("modifiers/slot/slot > data")) + + //fields count + out.write_int32(1) + + // coord + out.write_uint32(compiler.string.hash("coord")) + out.write_uint32(1025475970) //type float3 + var coord_default = [0, 0, 0] + out.write_float32(coord_default[0]) + out.write_float32(coord_default[1]) + out.write_float32(coord_default[2]) + + + } //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/slot/slot > data` block types + + class BlockModifierData { + + field { "slot" } + source { "modifiers/slot/slot > 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, "coord", "float3", [0, 0, 0]) + Block.set_type(_block, "modifiers/slot/slot > data") + } //new + + instance_type { + + class BlockInstModifierData { + coord { Block.get(_block, "coord", _slot) } + coord=(v) { Block.set(_block, "coord", _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/slot/slot > world` types + + class ModifierWorld { + + construct new() { + } //new + + } //ModifierWorld + +//`modifiers/slot/slot > 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/slot/slot > 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/slot/slot > world` block types + + class BlockModifierWorld { + + field { "slot" } + source { "modifiers/slot/slot > 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/slot/slot > 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/modifiers/slot/slot.wren b/modifiers/slot/slot.wren new file mode 100644 index 0000000..556bd74 --- /dev/null +++ b/modifiers/slot/slot.wren @@ -0,0 +1,59 @@ +import "luxe: io" for IO +import "luxe: world" for World, Entity, Modifiers, ModifierSystem, Transform +import "utils/hex" for Hex + +//User facing API +//This is what the user of your modifier will interact with +class Slot { + + static create(entity) { Modifiers.create(This, entity) } + static destroy(entity) { Modifiers.destroy(This, entity) } + static has(entity) { Modifiers.has(This, entity) } + +} //Slot + +//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 SlotSystem 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) { + if(!World.tag_has(_world, "edit")) return //only in editor pls + + //called usually once every frame. + //called when the world that this modifier lives in, is ticked + each {|entity, data| + var pos = Transform.get_pos(entity) + var coord = Hex.pos_to_coord(pos, 50) //todo: get scale from field + coord = Hex.round(coord) + pos = Hex.coord_to_pos(coord, 50) + Transform.set_pos(entity, pos.x, pos.y) + data.coord = coord + } + } //tick + +} //SlotSystem + +var Modifier = SlotSystem //required diff --git a/outline/settings.settings.lx b/outline/settings.settings.lx index fe39e7e..bb1f1a7 100644 --- a/outline/settings.settings.lx +++ b/outline/settings.settings.lx @@ -2,8 +2,8 @@ engine = { input.entry = "outline/inputs" runtime = { window = { - width = 960 - height = 640 + width = 1280 + height = 720 resizable = false fullscreen = false } diff --git a/prototype/card.prototype.lx b/prototype/card.prototype.lx index 0d1689a..b2f5e48 100644 --- a/prototype/card.prototype.lx +++ b/prototype/card.prototype.lx @@ -13,7 +13,7 @@ prototype = { link = "f873fe05-6771-496f-b56a-713d7f5fc622" pos = [0 0 1] //pos type = "luxe: modifier/transform" - rotation = [0 0 60.00000166965211] //rotation + rotation = [0 0 60.000002] //rotation } //transform } //modifiers uuid = "6f4e045a-52e2-41e9-a80b-f05eb95b6b41" @@ -31,7 +31,7 @@ prototype = { link = "f873fe05-6771-496f-b56a-713d7f5fc622" pos = [0 0 1] //pos type = "luxe: modifier/transform" - rotation = [0 0 -60.00000849984128] //rotation + rotation = [0 0 -60.000008] //rotation } //transform } //modifiers uuid = "dda3e025-14d8-452a-af4c-c27fdc4c1776" @@ -56,7 +56,7 @@ prototype = { bg = { modifiers = { sprite = { - material = "material/hexagon" + material = "material/card" height = 64 uv = [0 0 1 1] //uv color = [1 1 1 1] //color @@ -73,14 +73,14 @@ prototype = { modifiers = { sprite = { material = "material/border" - color = [0.341176 0.203922 0.0588235 1] //color + color = [0.341176 0.203922 0.058824 1] //color height = 64 type = "luxe: modifier/sprite" width = 64 } //sprite transform = { link = "86fc6726-97dd-4b77-8ded-a5da1aabe698" - scale = [1.049999952316284 1.049999952316284 1] //scale + scale = [1.05 1.05 1] //scale pos = [0 0 1] //pos type = "luxe: modifier/transform" } //transform @@ -100,7 +100,7 @@ prototype = { link = "f873fe05-6771-496f-b56a-713d7f5fc622" pos = [0 0 1] //pos type = "luxe: modifier/transform" - rotation = [0 0 120.0000033393042] //rotation + rotation = [0 0 120.000003] //rotation } //transform } //modifiers uuid = "8d6b1d9f-0a29-4c02-961a-1274fb140101" @@ -112,11 +112,11 @@ prototype = { align_vertical = "center" size = 6 type = "luxe: modifier/text" - text = "Shork" align = "center" + text = "Shork" } //text transform = { - pos = [0 -12.85531902313232 1] //pos + pos = [0 -12.855319 1] //pos type = "luxe: modifier/transform" } //transform } //modifiers @@ -135,7 +135,7 @@ prototype = { link = "f873fe05-6771-496f-b56a-713d7f5fc622" pos = [0 0 1] //pos type = "luxe: modifier/transform" - rotation = [0 0 -179.999991348578] //rotation + rotation = [0 0 -179.999991] //rotation } //transform } //modifiers uuid = "c1531b18-f282-4311-801f-86015db22546" @@ -153,7 +153,7 @@ prototype = { link = "f873fe05-6771-496f-b56a-713d7f5fc622" pos = [0 0 1] //pos type = "luxe: modifier/transform" - rotation = [0 0 -119.9999896789259] //rotation + rotation = [0 0 -119.99999] //rotation } //transform } //modifiers uuid = "3bacb0d2-03ac-4c3d-91e7-ccab18e1cc52" @@ -168,7 +168,7 @@ prototype = { width = 40 } //sprite transform = { - pos = [0 -13.08282947540283 0.1000000014901161] //pos + pos = [0 -13.082829 0.1] //pos type = "luxe: modifier/transform" } //transform } //modifiers @@ -184,7 +184,7 @@ prototype = { width = 64 } //sprite transform = { - scale = [0.9900000095367432 0.9900000095367432 0.9900000095367432] //scale + scale = [0.99 0.99 0.99] //scale link = "86fc6726-97dd-4b77-8ded-a5da1aabe698" type = "luxe: modifier/transform" } //transform diff --git a/prototype/layout_7x5.prototype.lx b/prototype/layout_7x5.prototype.lx new file mode 100644 index 0000000..faac696 --- /dev/null +++ b/prototype/layout_7x5.prototype.lx @@ -0,0 +1,76 @@ +prototype = { + elements = { + slot_1,-1,0 = { + modifiers = { + sprite = { + material = "material/hexagon" + height = 64 + type = "luxe: modifier/sprite" + width = 64 + } //sprite + slot = { + type = "modifiers/slot/slot" + } //slot + transform = { + scale = [1.5 1.5 1] //scale + pos = [86.602539 0 0] //pos + link = "455ce044-0613-47f3-83b7-cc962dd417d4" + type = "luxe: modifier/transform" + rotation = [0 -0 0] //rotation + } //transform + } //modifiers + uuid = "81cb28ce-7f4d-4a8a-bbf2-b681ead0955a" + } //slot_1,-1,0 + slot_1,0,-1 = { + modifiers = { + sprite = { + material = "material/hexagon" + height = 64 + type = "luxe: modifier/sprite" + width = 64 + } //sprite + slot = { + type = "modifiers/slot/slot" + } //slot + transform = { + scale = [1.5 1.5 1] //scale + pos = [43.30127 75 0] //pos + link = "455ce044-0613-47f3-83b7-cc962dd417d4" + type = "luxe: modifier/transform" + rotation = [0 -0 0] //rotation + } //transform + } //modifiers + uuid = "44930a60-0581-4703-aebc-5a633b88de3a" + } //slot_1,0,-1 + slot_0,0,0 = { + modifiers = { + sprite = { + material = "material/hexagon" + height = 64 + type = "luxe: modifier/sprite" + width = 64 + } //sprite + slot = { + type = "modifiers/slot/slot" + } //slot + transform = { + scale = [1.5 1.5 1] //scale + pos = [0 -0 0] //pos + link = "455ce044-0613-47f3-83b7-cc962dd417d4" + type = "luxe: modifier/transform" + rotation = [0 -0 0] //rotation + } //transform + } //modifiers + uuid = "63febcbe-b95f-4f6f-ad64-e8360383e9a4" + } //slot_0,0,0 + field = { + modifiers = { + transform = { + pos = [0 0 0] //pos + type = "luxe: modifier/transform" + } //transform + } //modifiers + uuid = "455ce044-0613-47f3-83b7-cc962dd417d4" + } //field + } //elements +} //prototype diff --git a/utils/hex.wren b/utils/hex.wren new file mode 100644 index 0000000..deb05fe --- /dev/null +++ b/utils/hex.wren @@ -0,0 +1,63 @@ +import "utils/vec" for Vec +import "luxe: math" for Math + +var x_angle = 1 * Num.tau / 12 +var y_angle = 5 * Num.tau / 12 +var z_angle = 9 * Num.tau / 12 +var X_Dir = [x_angle.cos, x_angle.sin, 0] +var Y_Dir = [y_angle.cos, y_angle.sin, 0] +var Z_Dir = [z_angle.cos, z_angle.sin, 0] + +class Hex{ + + //cheaper calculation might be possible? + //but I dont understand it so it doesnt count :V + static pos_to_coord(pos, scale){ + var coords = [0, 0, 0] + + scale = scale * 1.5 + coords.x = Math.dot(X_Dir, pos) / scale + coords.y = Math.dot(Y_Dir, pos) / scale + coords.z = Math.dot(Z_Dir, pos) / scale + return coords + } + + static pos_to_coord(pos){ pos_to_coord(pos, 1) } + + static coord_to_pos(coord, scale){ + var x_pos = Vec.mul(X_Dir, coord.x * scale) + var y_pos = Vec.mul(Y_Dir, coord.y * scale) + var z_pos = Vec.mul(Z_Dir, coord.z * scale) + return Vec.add(x_pos, Vec.add(y_pos, z_pos)) + } + + static coord_to_pos(coord){ coord_to_pos(coord, 1) } + + static round(coords){ + var result = [ + coords.x.round, + coords.y.round, + coords.z.round + ] + + //if all is good, all is good + if(result.x + result.y + result.z == 0) return result + + //otherwise calculate the difference rounding made + var x_diff = result.x - coords.x + var y_diff = result.y - coords.y + var z_diff = result.z - coords.z + + //and recalculate the coordinate that made the biggest jump + //so the 0 sum constraint is enforced again + if(x_diff > y_diff && y_diff > z_diff) { + result.x = -result.y - result.z + } else if(y_diff > z_diff) { + result.y = -result.z - result.x + } else { + result.z = -result.x-result.y + } + + return result + } +} \ No newline at end of file