initial commit
This commit is contained in:
commit
12466b5d4e
16 changed files with 5640 additions and 0 deletions
10
.gitignore
vendored
Normal file
10
.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
.luxeignore
Normal file
1
.luxeignore
Normal file
|
|
@ -0,0 +1 @@
|
|||
preview.png
|
||||
17
.vscode/tasks.json
vendored
Normal file
17
.vscode/tasks.json
vendored
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"tasks": [
|
||||
{
|
||||
"type": "luxe",
|
||||
"script": "run",
|
||||
"problemMatcher": [
|
||||
"$luxe-absolute",
|
||||
"$luxe-relative"
|
||||
],
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
},
|
||||
"label": "luxe: run - Build & Run the project"
|
||||
}
|
||||
]
|
||||
}
|
||||
62
assets/down_the_mountain/snowplayers.atlas
Normal file
62
assets/down_the_mountain/snowplayers.atlas
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
|
||||
skeleton.png
|
||||
size: 1203,242
|
||||
format: RGBA8888
|
||||
filter: Linear,Linear
|
||||
repeat: none
|
||||
Untitled-1
|
||||
rotate: false
|
||||
xy: 1071, 122
|
||||
size: 130, 118
|
||||
orig: 130, 118
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Untitled-2
|
||||
rotate: true
|
||||
xy: 743, 29
|
||||
size: 133, 157
|
||||
orig: 133, 157
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Untitled-3
|
||||
rotate: false
|
||||
xy: 743, 164
|
||||
size: 326, 76
|
||||
orig: 327, 76
|
||||
offset: 1, 0
|
||||
index: -1
|
||||
Untitled-4
|
||||
rotate: true
|
||||
xy: 2, 6
|
||||
size: 234, 268
|
||||
orig: 236, 278
|
||||
offset: 2, 0
|
||||
index: -1
|
||||
Untitled-5
|
||||
rotate: false
|
||||
xy: 542, 6
|
||||
size: 199, 234
|
||||
orig: 199, 234
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
eye1
|
||||
rotate: false
|
||||
xy: 1061, 2
|
||||
size: 130, 118
|
||||
orig: 130, 118
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
eye2
|
||||
rotate: true
|
||||
xy: 902, 29
|
||||
size: 133, 157
|
||||
orig: 133, 157
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
eye3
|
||||
rotate: true
|
||||
xy: 272, 6
|
||||
size: 234, 268
|
||||
orig: 236, 278
|
||||
offset: 2, 0
|
||||
index: -1
|
||||
4
assets/down_the_mountain/snowplayers.image.lx
Normal file
4
assets/down_the_mountain/snowplayers.image.lx
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
image = {
|
||||
source = "assets/down_the_mountain/snowplayers.png"
|
||||
generate_mipmaps_at_load = false
|
||||
}
|
||||
4974
assets/down_the_mountain/snowplayers.json
Normal file
4974
assets/down_the_mountain/snowplayers.json
Normal file
File diff suppressed because it is too large
Load diff
BIN
assets/down_the_mountain/snowplayers.png
Normal file
BIN
assets/down_the_mountain/snowplayers.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 246 KiB |
4
assets/down_the_mountain/snowplayers.spine.lx
Normal file
4
assets/down_the_mountain/snowplayers.spine.lx
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
spine = {
|
||||
skeleton = "assets/down_the_mountain/snowplayers",
|
||||
atlas = "assets/down_the_mountain/snowplayers"
|
||||
}
|
||||
58
game.wren
Normal file
58
game.wren
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
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 "spine" for Spine
|
||||
|
||||
class Game is Ready {
|
||||
|
||||
construct ready() {
|
||||
|
||||
super("ready!")
|
||||
|
||||
app = App.new()
|
||||
|
||||
System.print("render size: %(app.width) x %(app.height) @ %(app.scale)x")
|
||||
|
||||
_logo = Entity.create(app.world, "sprite")
|
||||
Transform.create(_logo)
|
||||
Transform.set_pos(_logo, app.width/2, app.height/2, 0)
|
||||
Sprite.create(_logo, Assets.material("luxe: material/logo"), 128, 128)
|
||||
|
||||
|
||||
var spine_asset = Spine.parse("assets/down_the_mountain/snowplayers")
|
||||
_debug = Draw.create(World.render_set(app.world))
|
||||
spine_asset.draw_bones(_debug)
|
||||
spine_asset.draw_outlines(_debug)
|
||||
Draw.commit(_debug)
|
||||
} //ready
|
||||
|
||||
tick(delta) {
|
||||
|
||||
var pos = Camera.screen_point_to_world(app.camera, Input.mouse_x(), Input.mouse_y())
|
||||
Transform.set_pos(_logo, pos.x, pos.y, 0)
|
||||
|
||||
if(Input.key_state_released(Key.escape)) {
|
||||
IO.shutdown()
|
||||
}
|
||||
|
||||
app.color.r = app.color.g = app.color.b = (IO.timestamp()/20 % 1)
|
||||
|
||||
} //tick
|
||||
|
||||
destroy() {
|
||||
|
||||
System.print("unready!")
|
||||
app.destroy()
|
||||
|
||||
} //destroy
|
||||
|
||||
app { _app }
|
||||
app=(v) { _app=v }
|
||||
|
||||
} //Game
|
||||
74
outline/app.wren
Normal file
74
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
outline/inputs.input.lx
Normal file
23
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
outline/renderer.wren
Normal file
51
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
outline/settings.settings.lx
Normal file
17
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 = 2
|
||||
stencil = 8
|
||||
depth = 24
|
||||
}
|
||||
}
|
||||
14
project.luxe
Normal file
14
project.luxe
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
import "luxe: project" for Entry
|
||||
|
||||
class Project is Entry {
|
||||
|
||||
construct entry(target) {
|
||||
|
||||
name = "game"
|
||||
version = "0.0.0"
|
||||
renderer = "outline/renderer"
|
||||
settings = "outline/settings"
|
||||
|
||||
} //new
|
||||
|
||||
} //Project
|
||||
3
project.modules.lx
Normal file
3
project.modules.lx
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
modules = {
|
||||
luxe = "2021.0.3"
|
||||
} //modules
|
||||
328
spine.wren
Normal file
328
spine.wren
Normal file
|
|
@ -0,0 +1,328 @@
|
|||
import "luxe: assets" for Assets
|
||||
import "luxe: color" for Color
|
||||
import "luxe: string" for Str
|
||||
import "luxe: render" for Geometry
|
||||
import "luxe: draw" for Draw, PathStyle, LineJoin, LineCap
|
||||
import "luxe: math" for Math
|
||||
|
||||
|
||||
class Spine{
|
||||
bones_by_index{_bones_by_index}
|
||||
bones_by_name{_bones_by_name}
|
||||
|
||||
static parse(id: String) : Spine{
|
||||
var asset = Assets.lx(id + ".spine.lx")["spine"]
|
||||
var skeleton = Assets.lx(asset["skeleton"]+".json")
|
||||
var atlas = Assets.bytes(asset["atlas"]+".atlas")
|
||||
|
||||
var spine_asset = Spine.from_data(skeleton)
|
||||
return spine_asset
|
||||
}
|
||||
|
||||
construct from_data(jsonDict: Map){
|
||||
init()
|
||||
load_skeleton(jsonDict["skeleton"])
|
||||
load_bones(jsonDict["bones"])
|
||||
load_slots(jsonDict["slots"])
|
||||
load_skins(jsonDict["skins"])
|
||||
load_animations(jsonDict["animations"])
|
||||
//todo: constraints
|
||||
}
|
||||
|
||||
init(){
|
||||
_pos = [0, 0]
|
||||
_size = [0, 0]
|
||||
_fps = 30
|
||||
|
||||
_bones_by_name = {}
|
||||
_bones_by_index = []
|
||||
_slots_by_name = {}
|
||||
_slots_by_index = []
|
||||
_skins = {}
|
||||
_animations = {}
|
||||
_active_skins = ["default"]
|
||||
_active_attachments = []
|
||||
_active_animation = "" //todo: tie this into Anim system
|
||||
}
|
||||
|
||||
load_skeleton(skeleton_data: Map){
|
||||
_pos = [skeleton_data["x"], skeleton_data["y"]]
|
||||
_size = [skeleton_data["width"], skeleton_data["height"]]
|
||||
_fps = skeleton_data["fps"] || 30
|
||||
}
|
||||
|
||||
load_bones(bones_data: List){
|
||||
_bones_by_index.clear()
|
||||
for(bone_data in bones_data){
|
||||
var bone = SpineBone.from_data(bone_data, _bones_by_name)
|
||||
_bones_by_name[bone.name] = bone
|
||||
_bones_by_index.add(bone)
|
||||
}
|
||||
}
|
||||
|
||||
load_slots(slots_data: List){
|
||||
if(slots_data == null) return
|
||||
_slots_by_index.clear()
|
||||
for(slot_data in slots_data){
|
||||
var slot = SpineSlot.from_data(slot_data, _bones_by_name)
|
||||
_slots_by_name[slot.name] = slot
|
||||
_slots_by_index.add(slot)
|
||||
}
|
||||
}
|
||||
|
||||
load_skins(skins_data: List){
|
||||
if(skins_data == null) return
|
||||
for(skin_data in skins_data){
|
||||
var skin = SpineSkin.from_data(skin_data, this)
|
||||
_skins[skin.name] = skin
|
||||
}
|
||||
}
|
||||
|
||||
load_animations(animation_data: Map){
|
||||
//todo
|
||||
}
|
||||
|
||||
|
||||
draw_bones(context){draw_bones(context, [1, 0, 0, 1])}
|
||||
draw_bones(context, color){
|
||||
for(bone in _bones_by_index){
|
||||
var pos = bone.position()
|
||||
pos = [pos.x+200, pos.y+200]
|
||||
var length = bone.length
|
||||
var rotation = Math.radians(bone.rotation())
|
||||
|
||||
var direction = [rotation.cos, rotation.sin] //todo: use matrices - this approach might be lossy with nonuniform scaling
|
||||
var target = [pos.x + direction.x * length, pos.y + direction.y * length]
|
||||
|
||||
var style = PathStyle.new()
|
||||
style.color = color
|
||||
Draw.line(context, pos.x, pos.y, target.x, target.y, 0, style)
|
||||
}
|
||||
}
|
||||
|
||||
draw_outlines(context){draw_outlines(context, [0, 1, 0, 1])}
|
||||
draw_outlines(context, color){
|
||||
for(skin_id in _active_skins){ //todo: only draw "uppermost" attachments
|
||||
_skins[skin_id].draw_outlines(context, color)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SpineSkin{
|
||||
name{_name}
|
||||
|
||||
construct from_data(skin_data: Map, spine){
|
||||
_name = skin_data["name"]
|
||||
|
||||
_slots = {}
|
||||
for(slot in skin_data["attachments"]){
|
||||
var attachments = []
|
||||
for(attachment_data in slot.value){
|
||||
var attachment = SpineAttachment.from_data(attachment_data.value, attachment_data.key, spine)
|
||||
if(attachment) attachments.add(attachment)
|
||||
}
|
||||
_slots[slot.key] = attachments
|
||||
}
|
||||
|
||||
//todo: skins that are not the default skin can have bones/constraints/paths - handle that (http://esotericsoftware.com/spine-json-format/#Attachments)
|
||||
}
|
||||
|
||||
draw_outlines(context, color){
|
||||
for(slot in _slots.values){
|
||||
for(attachment in slot){
|
||||
attachment.draw_outlines(context, color)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SpineAttachment{
|
||||
type{_type}
|
||||
type=(value){_type=value}
|
||||
|
||||
name{_name}
|
||||
name=(value){_name=value}
|
||||
|
||||
static from_data(attachment_data: Map, map_name: String, spine): SpineAttachment{
|
||||
var type = attachment_data["type"] || "region"
|
||||
var name = attachment_data["name"] || map_name
|
||||
|
||||
var attachment
|
||||
if(type == "mesh"){
|
||||
var weighted = attachment_data["vertices"].count > attachment_data["uvs"].count
|
||||
if(weighted){
|
||||
attachment = SpineSkinnedMeshAttachment.from_data(attachment_data, spine)
|
||||
} else {
|
||||
attachment = SpineMeshAttachment.from_data(attachment_data)
|
||||
}
|
||||
} else {
|
||||
System.print("Unknown attachment type \"%(type)\"")
|
||||
return null
|
||||
}
|
||||
attachment.name = name
|
||||
attachment.type = type
|
||||
|
||||
return attachment
|
||||
}
|
||||
}
|
||||
|
||||
class SpineMeshAttachment is SpineAttachment{
|
||||
path{(_path != null) ? _path : name} //use path when set, otherwise fall back to name
|
||||
|
||||
construct from_data(attachment_data: Map){
|
||||
_hull = attachment_data["hull"] //amount of vertices that form the hull - always the first n vertices in the list
|
||||
_path = attachment_data["path"]
|
||||
//todo: parse tint (RGBA hex)
|
||||
|
||||
var triangles = attachment_data["triangles"]
|
||||
var vertices = attachment_data["vertices"]
|
||||
var uvs = attachment_data["uvs"]
|
||||
|
||||
_vertices = vertices
|
||||
_triangles = triangles
|
||||
_uvs = uvs
|
||||
}
|
||||
}
|
||||
|
||||
class SpineSkinnedMeshAttachment is SpineAttachment{
|
||||
path{(_path != null) ? _path : name} //use path when set, otherwise fall back to name
|
||||
|
||||
construct from_data(attachment_data: Map, spine: Spine){
|
||||
_hull = attachment_data["hull"] //amount of vertices that form the hull - always the first n vertices in the list
|
||||
_path = attachment_data["path"]
|
||||
//todo: parse tint (RGBA hex)
|
||||
|
||||
var triangles = attachment_data["triangles"]
|
||||
var vertices = attachment_data["vertices"]
|
||||
var uvs = attachment_data["uvs"]
|
||||
|
||||
_vertices = []
|
||||
var vert_index = 0
|
||||
//var uv_index = 0
|
||||
while(vert_index<vertices.count){
|
||||
var bone_count = vertices[vert_index]
|
||||
var bones = []
|
||||
vert_index = vert_index+1
|
||||
for(ii in 0...bone_count){
|
||||
var bone_index = vertices[vert_index]
|
||||
var bone = spine.bones_by_index[bone_index]
|
||||
var bind_x = vertices[vert_index+1]
|
||||
var bind_y = vertices[vert_index+2]
|
||||
var weight = vertices[vert_index+3]
|
||||
bones.add(SpineBoneWeight.new(bone, [bind_x, bind_y], weight))
|
||||
vert_index = vert_index+4
|
||||
}
|
||||
//var uv = [uvs[uv_index], uvs[uv_index+1]]
|
||||
//uv_index = uv_index+2
|
||||
_vertices.add(SpineSkinnedVertex.new(null, bones))
|
||||
}
|
||||
|
||||
_uvs = uvs
|
||||
_triangles = triangles
|
||||
}
|
||||
|
||||
|
||||
draw_outlines(context, color){
|
||||
var style = PathStyle.new()
|
||||
style.color = color
|
||||
var points = (0..._hull).map{|i| _vertices[i].position()}
|
||||
.map{|pos| [pos.x + 200, pos.y + 200]}.toList
|
||||
points.add(points[0])
|
||||
Draw.path(context, points, style, true)
|
||||
}
|
||||
}
|
||||
|
||||
class SpineSkinnedVertex{
|
||||
bone_weights{_bone_weights}
|
||||
//uv{_uv}
|
||||
|
||||
construct new(uv: List, bones:List){
|
||||
//_uv = uv
|
||||
_bone_weights = bones
|
||||
}
|
||||
|
||||
position(){
|
||||
return _bone_weights
|
||||
.map{|weight| [weight.bone.transform(weight.bind_position), weight.weight]}
|
||||
.map{|args| [args[0].x * args[1], args[0].y * args[1]]}
|
||||
.reduce([0, 0]){|acc, item| [acc.x+item.x, acc.y+item.y]}
|
||||
}
|
||||
}
|
||||
|
||||
class SpineBoneWeight{
|
||||
bind_position{_bind_position}
|
||||
weight{_weight}
|
||||
bone{_bone}
|
||||
|
||||
construct new(bone: SpineBone, bind_position: List, weight: Num){
|
||||
_bone = bone
|
||||
_bind_position = bind_position
|
||||
_weight = weight
|
||||
}
|
||||
}
|
||||
|
||||
class SpineBone{
|
||||
name{_name}
|
||||
|
||||
rotation{_rotation}
|
||||
position{_position}
|
||||
scale{_scale}
|
||||
parent{_parent}
|
||||
length{_length}
|
||||
|
||||
//todo: get good information out of bones
|
||||
|
||||
construct from_data(bone_data, existing_bones){
|
||||
_name = bone_data["name"]
|
||||
_parent = bone_data["parent"]
|
||||
_parent = _parent && existing_bones[_parent] //we can just take a reference to the parent because parent bones are guaranteed to be before their children
|
||||
_length = bone_data["length"] || 0
|
||||
_transform = bone_data["transform"] || "normal" //todo: use enum
|
||||
_skin = bone_data["skin"] || false
|
||||
//all transformation are relative to the parent
|
||||
_position = [bone_data["x"] || 0, bone_data["y"] || 0]
|
||||
_rotation = bone_data["rotation"] || 0
|
||||
_scale = [bone_data["scaleX"] || 1, bone_data["scaleY"] || 1]
|
||||
_shear = [bone_data["shearX"] || 0, bone_data["shearY"] || 0]
|
||||
//todo: tint of the bone
|
||||
}
|
||||
|
||||
transform(pos){
|
||||
var bone = this
|
||||
while(bone != null){
|
||||
pos = [pos.x * bone.scale.x, pos.y * bone.scale.y]
|
||||
Math.rotate(pos, 0, 0, bone.rotation)
|
||||
pos = [pos.x + bone.position.x, pos.y + bone.position.y]
|
||||
bone = bone.parent
|
||||
}
|
||||
return pos
|
||||
}
|
||||
|
||||
position(){
|
||||
return transform([0, 0])
|
||||
}
|
||||
|
||||
rotation(){
|
||||
var bone = this
|
||||
var rot = 0
|
||||
while(bone != null){
|
||||
rot = rot + bone.rotation
|
||||
bone = bone.parent
|
||||
}
|
||||
return rot
|
||||
}
|
||||
}
|
||||
|
||||
class SpineSlot{
|
||||
name{_name}
|
||||
|
||||
construct from_data(slot_data, bone_dict){
|
||||
_name = slot_data["name"]
|
||||
_bone = slot_data["bone"]
|
||||
_bone = _bone && bone_dict[_bone]
|
||||
//todo: parse color
|
||||
//todo: parse dark color
|
||||
//todo: consider looking at and understanding how "attachment" works
|
||||
_blend = slot_data["blend"] || "normal" //todo: enum
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue