diff --git a/Source/Node/DragonBone.cpp b/Source/Node/DragonBone.cpp index 54432e825..21e899ed1 100644 --- a/Source/Node/DragonBone.cpp +++ b/Source/Node/DragonBone.cpp @@ -422,6 +422,9 @@ void DragonBone::DBArmatureProxy::dispatchDBEvent(const std::string& type, db::E const std::string& animationName = value->animationState->getName(); _parent->emit("AnimationEnd"_slice, animationName, s_cast(_parent)); _parent->_lastCompletedAnimationName = animationName; + if (_parent->_currentAnimationName == animationName) { + _parent->_currentAnimationName.clear(); + } } else if (type == db::EventObject::LOOP_COMPLETE) { auto animationName = value->animationState->getName(); _parent->emit("AnimationEnd"_slice, animationName, s_cast(_parent)); diff --git a/Source/Node/Spine.cpp b/Source/Node/Spine.cpp index 76e982947..e793421d4 100644 --- a/Source/Node/Spine.cpp +++ b/Source/Node/Spine.cpp @@ -57,9 +57,15 @@ void Spine::SpineListener::callback(spine::AnimationState* state, spine::EventTy case spine::EventType_Complete: _owner->emit("AnimationEnd"_slice, animationName.toString(), s_cast(_owner)); _owner->_lastCompletedAnimationName = animationName.toString(); + if (_owner->_currentAnimationName == animationName) { + _owner->_currentAnimationName.clear(); + } break; case spine::EventType_Interrupt: _owner->_lastCompletedAnimationName.clear(); + if (_owner->_currentAnimationName == animationName) { + _owner->_currentAnimationName.clear(); + } break; case spine::EventType_Start: case spine::EventType_Dispose: diff --git a/Source/Wasm/WasmRuntime.cpp b/Source/Wasm/WasmRuntime.cpp index 1f65eed3d..ea220b0b1 100644 --- a/Source/Wasm/WasmRuntime.cpp +++ b/Source/Wasm/WasmRuntime.cpp @@ -243,6 +243,7 @@ static Own Value_To(const dora_val_t& v) { } static int64_t Value_From(Value* v) { + if (!v) return 0; switch (v->getType()) { case ValueType::Integral: return r_cast(new dora_val_t(v->toVal())); diff --git a/Tools/dora-wa/src/body.wa b/Tools/dora-wa/src/body.wa index 3dd9a9390..898135ade 100644 --- a/Tools/dora-wa/src/body.wa +++ b/Tools/dora-wa/src/body.wa @@ -1,7 +1,7 @@ import "dora" func test_body() { - gravity := dora.Vec2{X: 0.0, Y: -10.0} + gravity := dora.NewVec2(0.0, -10.0) const ( group_zero = 0 group_one = 1 @@ -16,12 +16,12 @@ func test_body() { polygon_def.SetType(dora.BodyTypeDynamic) polygon_def.SetLinearAcceleration(gravity) polygon_def.AttachPolygonWithVertices(&[]dora.Vec2{ - dora.Vec2{X: 60.0, Y: 0.0}, - dora.Vec2{X: 30.0, Y: -30.0}, - dora.Vec2{X: -30.0, Y: -30.0}, - dora.Vec2{X: -60.0, Y: 0.0}, - dora.Vec2{X: -30.0, Y: 30.0}, - dora.Vec2{X: 30.0, Y: 30.0}, + dora.NewVec2(60.0, 0.0), + dora.NewVec2(30.0, -30.0), + dora.NewVec2(-30.0, -30.0), + dora.NewVec2(-60.0, 0.0), + dora.NewVec2(-30.0, 30.0), + dora.NewVec2(30.0, 30.0), }, 1.0, 0.4, 0.4) disk_def := dora.NewBodyDef() @@ -36,15 +36,15 @@ func test_body() { world.SetShouldContact(group_one, group_two, true) world.SetShowDebug(true) - body := dora.NewBody(terrain_def, world, dora.Vec2{X: 0.0, Y: 0.0}, 0.0) + body := dora.NewBody(terrain_def, world, dora.Vec2Zero, 0.0) body.SetGroup(group_two) world.AddChild(body.Node) - body_p := dora.NewBody(polygon_def, world, dora.Vec2{X: 0.0, Y: 500.0}, 15.0) + body_p := dora.NewBody(polygon_def, world, dora.NewVec2(0.0, 500.0), 15.0) body_p.SetGroup(group_one) world.AddChild(body_p.Node) - body_d := dora.NewBody(disk_def, world, dora.Vec2{X: 50.0, Y: 800.0}, 0.0) + body_d := dora.NewBody(disk_def, world, dora.NewVec2(50.0, 800.0), 0.0) body_d.SetGroup(group_zero) body_d.SetAngularRate(90.0) world.AddChild(body_d.Node) @@ -61,12 +61,12 @@ func test_body() { width := dora.App.GetVisualSize().Width dora.ImGui.SetNextWindowBgAlpha(0.35) dora.ImGui.SetNextWindowPosOpts( - dora.Vec2{X: width - 10.0, Y: 10.0}, + dora.NewVec2(width-10.0, 10.0), dora.ImGuiCondAlways, - dora.Vec2{X: 1.0, Y: 0.0}, + dora.NewVec2(1.0, 0.0), ) dora.ImGui.SetNextWindowSizeOpts( - dora.Vec2{X: 240.0, Y: 0.0}, + dora.NewVec2(240.0, 0.0), dora.ImGuiCondFirstUseEver, ) dora.ImGui.BeginOpts("Body", window_flags, func() { diff --git a/Tools/dora-wa/src/contact.wa b/Tools/dora-wa/src/contact.wa index 043b4cd49..a59973edc 100644 --- a/Tools/dora-wa/src/contact.wa +++ b/Tools/dora-wa/src/contact.wa @@ -2,7 +2,7 @@ import "dora" import "strconv" func test_contact() { - gravity := dora.Vec2{X: 0.0, Y: -10.0} + gravity := dora.NewVec2(0.0, -10.0) world := dora.NewPhysicsWorld() world.SetShouldContact(0, 0, true) world.SetShowDebug(true) @@ -16,27 +16,27 @@ func test_contact() { vertices := []dora.Vec2{} for i := 0; i <= count; i++ { angle := 2.0 * dora.Math.Pi * f32(i) / f32(count) - vertices = append(vertices, dora.Vec2{X: radius * dora.Math.Cos(angle), Y: radius * dora.Math.Sin(angle)}) + vertices = append(vertices, dora.NewVec2(radius*dora.Math.Cos(angle), radius*dora.Math.Sin(angle))) } terrain_def.AttachChain(&vertices, 0.4, 0.0) - terrain_def.AttachDiskWithCenter(dora.Vec2{X: 0.0, Y: -270.0}, 30.0, 1.0, 0.0, 1.0) - terrain := dora.NewBody(terrain_def, world, dora.Vec2{X: 0.0, Y: 0.0}, 0.0) + terrain_def.AttachDiskWithCenter(dora.NewVec2(0.0, -270.0), 30.0, 1.0, 0.0, 1.0) + terrain := dora.NewBody(terrain_def, world, dora.NewVec2(0.0, 0.0), 0.0) terrain.AddTo(world.Node) platform_def := dora.NewBodyDef() - platform_def.AttachPolygonWithCenter(dora.Vec2{X: 0.0, Y: -80.0}, 120.0, 30.0, 0.0, 1.0, 0.0, 1.0) - platform := dora.NewBody(platform_def, world, dora.Vec2{X: 0.0, Y: 0.0}, 0.0) + platform_def.AttachPolygonWithCenter(dora.NewVec2(0.0, -80.0), 120.0, 30.0, 0.0, 1.0, 0.0, 1.0) + platform := dora.NewBody(platform_def, world, dora.NewVec2(0.0, 0.0), 0.0) platform.OnContactFilter(func(other: dora.Body) => bool { return other.GetVelocityY() < 0.0 }) platform.AddTo(world.Node) draw_node := dora.NewLineWithVecColor(&[]dora.Vec2{ - dora.Vec2{X: -20.0, Y: 0.0}, - dora.Vec2{X: 20.0, Y: 0.0}, + dora.NewVec2(-20.0, 0.0), + dora.NewVec2(20.0, 0.0), dora.Vec2Zero, - dora.Vec2{X: 0.0, Y: -20.0}, - dora.Vec2{X: 0.0, Y: 20.0}, + dora.NewVec2(0.0, -20.0), + dora.NewVec2(0.0, 20.0), }, dora.App.GetThemeColor()) draw_node.AddTo(world.Node) @@ -44,7 +44,7 @@ func test_contact() { disk_def.SetType(dora.BodyTypeDynamic) disk_def.SetLinearAcceleration(gravity) disk_def.AttachDisk(20.0, 5.0, 0.8, 1.0) - disk := dora.NewBody(disk_def, world, dora.Vec2{X: 100.0, Y: 200.0}, 0.0) + disk := dora.NewBody(disk_def, world, dora.NewVec2(100.0, 200.0), 0.0) disk.AddTo(world.Node) disk.SetAngularRate(-1800.0) disk.OnContactStart(func(other: dora.Body, point: dora.Vec2, normal: dora.Vec2, enabled: bool) { @@ -67,12 +67,12 @@ func test_contact() { width := dora.App.GetVisualSize().Width dora.ImGui.SetNextWindowBgAlpha(0.35) dora.ImGui.SetNextWindowPosOpts( - dora.Vec2{X: width - 10.0, Y: 10.0}, + dora.NewVec2(width-10.0, 10.0), dora.ImGuiCondAlways, - dora.Vec2{X: 1.0, Y: 0.0}, + dora.NewVec2(1.0, 0.0), ) dora.ImGui.SetNextWindowSizeOpts( - dora.Vec2{X: 240.0, Y: 0.0}, + dora.NewVec2(240.0, 0.0), dora.ImGuiCondFirstUseEver, ) dora.ImGui.BeginOpts("Contact", window_flags, func() { diff --git a/Tools/dora-wa/src/entity_move.wa b/Tools/dora-wa/src/entity_move.wa index 968af94c5..b185ad24c 100644 --- a/Tools/dora-wa/src/entity_move.wa +++ b/Tools/dora-wa/src/entity_move.wa @@ -1,58 +1,6 @@ import "dora" func test_entity_move() { - /* - let window_flags = - ImGuiWindowFlag::NO_DECORATION | - ImGuiWindowFlag::AlwaysAutoResize | - ImGuiWindowFlag::NoSavedSettings | - ImGuiWindowFlag::NoFocusOnAppearing | - ImGuiWindowFlag::NO_NAV | - ImGuiWindowFlag::NoMove; - let mut imgui_node = Node::new(); - imgui_node.schedule(Box::new(move |_| { - let width = App::get_visual_size().width; - ImGui::set_next_window_bg_alpha(0.35); - ImGui::set_next_window_pos_opts(&Vec2::new(width - 10.0, 10.0), ImGuiCond::Always, &Vec2::new(1.0, 0.0)); - ImGui::set_next_window_size_opts(&Vec2::new(240.0, 0.0), ImGuiCond::FirstUseEver); - ImGui::begin_opts("ECS System", window_flags, || { - ImGui::text("ECS System (Rust)"); - ImGui::separator(); - ImGui::text_wrapped("Tap any place to move entities."); - if ImGui::button("Create Random Entity", &Vec2::zero()) { - let mut entity = Entity::new(); - entity.set("image", "Image/logo.png"); - entity.set("position", Vec2::new( - 6.0 * (App::get_rand() % 100) as f32, - 6.0 * (App::get_rand() % 100) as f32)); - entity.set("direction", 1.0 * (App::get_rand() % 360) as f32); - let speed = 1.0 * (App::get_rand() % 20 + 1) as f32; - entity.set("speed", speed); - } - if ImGui::button("Destroy An Entity", &Vec2::zero()) { - let group = Group::new(&vec!["sprite", "position"]); - group.each(Box::new(|entity| { - let mut entity = entity.clone(); - entity.remove("position"); - let get_sprite = |e: &Entity| e.get("sprite")?.cast::(); - if let Some(mut sprite) = get_sprite(&entity) { - sprite.run_action_def( - ActionDef::sequence(&vec![ - ActionDef::scale(0.5, 0.5, 0.0, EaseType::InBack), - ActionDef::event("Destroy", "") - ]), false); - sprite.slot("Destroy", Box::new(move |_| { - entity.destroy(); - })); - } - true - })); - } - }); - false - })); - */ - scene_group := dora.NewGroup(&[]string{"scene"}) position_group := dora.NewGroup(&[]string{"position"}) { @@ -154,14 +102,14 @@ func test_entity_move() { { entity := dora.NewEntity() entity.Set("image", "Image/logo.png") - entity.Set("position", dora.Vec2{X: 0.0, Y: 0.0}) + entity.Set("position", dora.Vec2Zero) entity.Set("direction", 45.0) entity.Set("speed", 4.0) } { entity := dora.NewEntity() entity.Set("image", "Image/logo.png") - entity.Set("position", dora.Vec2{X: -100.0, Y: 200.0}) + entity.Set("position", dora.NewVec2(-100.0, 200.0)) entity.Set("direction", 90.0) entity.Set("speed", 10.0) } @@ -179,26 +127,26 @@ func test_entity_move() { width := dora.App.GetVisualSize().Width dora.ImGui.SetNextWindowBgAlpha(0.35) dora.ImGui.SetNextWindowPosOpts( - dora.Vec2{X: width - 10.0, Y: 10.0}, + dora.NewVec2(width-10.0, 10.0), dora.ImGuiCondAlways, - dora.Vec2{X: 1.0, Y: 0.0}, + dora.NewVec2(1.0, 0.0), ) dora.ImGui.SetNextWindowSizeOpts( - dora.Vec2{X: 240.0, Y: 0.0}, + dora.NewVec2(240.0, 0.0), dora.ImGuiCondFirstUseEver, ) dora.ImGui.BeginOpts("ECS System", window_flags, func() { dora.ImGui.Text("ECS System (Wa)") dora.ImGui.Separator() dora.ImGui.TextWrapped("Tap any place to move entities.") - if dora.ImGui.Button("Create Random Entity", dora.Vec2{X: 0.0, Y: 0.0}) { + if dora.ImGui.Button("Create Random Entity", dora.Vec2Zero) { entity := dora.NewEntity() entity.Set("image", "Image/logo.png") - entity.Set("position", dora.Vec2{X: 6.0 * f32(dora.App.GetRand()%100), Y: 6.0 * f32(dora.App.GetRand()%100)}) + entity.Set("position", dora.NewVec2(6.0*f32(dora.App.GetRand()%100), 6.0*f32(dora.App.GetRand()%100))) entity.Set("direction", 1.0*f32(dora.App.GetRand()%360)) entity.Set("speed", 1.0*f32(dora.App.GetRand()%20+1)) } - if dora.ImGui.Button("Destroy An Entity", dora.Vec2{X: 0.0, Y: 0.0}) { + if dora.ImGui.Button("Destroy An Entity", dora.Vec2Zero) { group := dora.NewGroup(&[]string{"sprite", "position"}) group.Each(func(entity: dora.Entity) => bool { entity.Remove("position") diff --git a/Tools/dora-wa/src/exceltest.wa b/Tools/dora-wa/src/exceltest.wa new file mode 100644 index 000000000..014933eab --- /dev/null +++ b/Tools/dora-wa/src/exceltest.wa @@ -0,0 +1,571 @@ +import "dora" +import "math" +import "strconv" + +func test_excel_test() { + const ( + TERRAIN_LAYER = 0 + PLAYER_LAYER = 1 + ITEM_LAYER = 2 + ) + + player_group := dora.PlatformerData.GetGroupFirstPlayer() + item_group := player_group + 1 + terrain_group := dora.PlatformerData.GetGroupTerrain() + + dora.PlatformerData.SetShouldContact(player_group, item_group, true) + + theme_color := dora.App.GetThemeColor() + fill_color := dora.NewColor( + theme_color.R, + theme_color.G, + theme_color.B, + 0x66, + ) + border_color := theme_color + const DESIGN_WIDTH = 1000.0 + + world := dora.NewPlatformerPlatformWorld() + camera := world.GetCamera() + camera.SetBoundary( + dora.NewRect( + dora.NewVec2(-1250.0, -500.0), + dora.NewSize(2500.0, 1000.0), + ), + ) + camera.SetFollowRatio(dora.NewVec2(0.02, 0.02)) + camera.SetZoom(dora.App.GetVisualSize().Width / DESIGN_WIDTH) + world.OnAppChange(func(setting_name: string) { + if setting_name == "Size" { + camera.SetZoom( + dora.App.GetVisualSize().Width / DESIGN_WIDTH, + ) + } + }) + + terrain_def := dora.NewBodyDef() + terrain_def.SetType(dora.BodyTypeStatic) + terrain_def.AttachPolygonWithCenter( + dora.NewVec2(0.0, -500.0), 2500.0, 10.0, + 0.0, 1.0, 1.0, 0.0, + ) + terrain_def.AttachPolygonWithCenter( + dora.NewVec2(0.0, 500.0), 2500.0, 10.0, + 0.0, 1.0, 1.0, 0.0, + ) + terrain_def.AttachPolygonWithCenter( + dora.NewVec2(1250.0, 0.0), 10.0, 1000.0, + 0.0, 1.0, 1.0, 0.0, + ) + terrain_def.AttachPolygonWithCenter( + dora.NewVec2(-1250.0, 0.0), 10.0, 1000.0, + 0.0, 1.0, 1.0, 0.0, + ) + + terrain := dora.NewBody(terrain_def, world.PhysicsWorld, dora.Vec2Zero, 0.0) + terrain.SetOrder(TERRAIN_LAYER) + terrain.SetGroup(terrain_group) + + new_rectangle := func(x: f32, y: f32, width: f32, height: f32, fill_color: dora.Color, border_color: dora.Color) => dora.Node { + hh := height / 2.0 + hw := width / 2.0 + draw_node := dora.NewDrawNode() + draw_node.DrawPolygon( + &[]dora.Vec2{ + dora.NewVec2(x-hw, y-hh), + dora.NewVec2(x-hw, y+hh), + dora.NewVec2(x+hw, y+hh), + dora.NewVec2(x+hw, y-hh), + }, + fill_color, 1.0, border_color, + ) + return draw_node.Node + } + + terrain.AddChild(new_rectangle( + 0.0, -500.0, 2500.0, 10.0, + fill_color, border_color, + )) + terrain.AddChild(new_rectangle( + 1250.0, 0.0, 10.0, 1000.0, + fill_color, border_color, + )) + terrain.AddChild(new_rectangle( + -1250.0, 0.0, 10.0, 1000.0, + fill_color, border_color, + )) + world.AddChild(terrain.Node) + + dora.PlatformerUnitActionAdd("idle", + 1, + 2.0, + 0.2, + false, + func( + unit: dora.PlatformerUnit, + action: dora.PlatformerUnitAction, + ) => bool { + return unit.IsOnSurface() + }, + func( + unit: dora.PlatformerUnit, + action: dora.PlatformerUnitAction, + ) => dora.PlatformerActionUpdate { + playable := unit.GetPlayable() + playable.SetSpeed(1.0) + playable.Play("idle", true) + total_time: f32 = 0.0 + idle1_count_down: f32 = 0.0 + return dora.NewPlatformerActionUpdate( + func( + unit: dora.PlatformerUnit, + action: dora.PlatformerUnitAction, + delta_time: f32, + ) => bool { + if idle1_count_down <= 0.0 { + total_time += delta_time + if total_time > 3.0 { + total_time = 0.0 + idle1_count_down = playable.Play("idle1", false) + } + } else { + idle1_count_down -= delta_time + if idle1_count_down <= 0.0 { + playable.Play("idle", true) + } + } + return !unit.IsOnSurface() + }) + }, + func( + unit: dora.PlatformerUnit, + action: dora.PlatformerUnitAction, + ) { + }, + ) + + dora.PlatformerUnitActionAdd("move", + 1, + 2.0, + 0.2, + false, + func( + unit: dora.PlatformerUnit, + action: dora.PlatformerUnitAction, + ) => bool { + return unit.IsOnSurface() + }, + func( + unit: dora.PlatformerUnit, + action: dora.PlatformerUnitAction, + ) => dora.PlatformerActionUpdate { + playable := unit.GetPlayable() + playable.SetSpeed(1.0) + playable.Play("fmove", true) + return dora.NewPlatformerActionUpdate( + func( + unit: dora.PlatformerUnit, + action: dora.PlatformerUnitAction, + delta_time: f32, + ) => bool { + elapsed_time := action.GetElapsedTime() + recovery := action.GetRecovery() * 2.0 + unit_def := unit.GetUnitDef() + movement, _ := unit_def.Get("move").GetF32() + move_speed: f32 = 1.0 + if elapsed_time < recovery { + move_speed = elapsed_time / recovery + move_speed = f32(math.Min(f64(move_speed), 1.0)) + } + if unit.IsFaceRight() { + move_speed *= movement + } else { + move_speed *= -movement + } + unit.SetVelocityX(move_speed) + return !unit.IsOnSurface() + }) + }, + func( + unit: dora.PlatformerUnit, + action: dora.PlatformerUnitAction, + ) { + }, + ) + + dora.PlatformerUnitActionAdd("jump", + 3, + 2.0, + 0.1, + true, + func( + unit: dora.PlatformerUnit, + action: dora.PlatformerUnitAction, + ) => bool { + return unit.IsOnSurface() + }, + func( + unit: dora.PlatformerUnit, + action: dora.PlatformerUnitAction, + ) => dora.PlatformerActionUpdate { + playable := unit.GetPlayable() + playable.SetSpeed(1.0) + playable.Play("jump", false) + unit_def := unit.GetUnitDef() + jump, _ := unit_def.Get("jump").GetF32() + unit.SetVelocityY(jump) + return dora.NewPlatformerActionUpdate( + func( + unit: dora.PlatformerUnit, + action: dora.PlatformerUnitAction, + delta_time: f32, + ) => bool { + return playable.GetCurrent() != "jump" + }) + }, + func( + unit: dora.PlatformerUnit, + action: dora.PlatformerUnitAction, + ) { + }, + ) + + dora.PlatformerUnitActionAdd("fallOff", + 2, + -1.0, + 0.3, + false, + func( + unit: dora.PlatformerUnit, + action: dora.PlatformerUnitAction, + ) => bool { + return !unit.IsOnSurface() + }, + func( + unit: dora.PlatformerUnit, + action: dora.PlatformerUnitAction, + ) => dora.PlatformerActionUpdate { + playable := unit.GetPlayable() + if playable.GetCurrent() != "jumping" { + playable.SetSpeed(1.0) + playable.Play("jumping", true) + } + count_down: f32 = 0.0 + landing := false + return dora.NewPlatformerActionUpdate( + func( + unit: dora.PlatformerUnit, + action: dora.PlatformerUnitAction, + delta_time: f32, + ) => bool { + if !landing { + if unit.IsOnSurface() { + landing = true + count_down = playable.Play("landing", false) + } + } else { + count_down -= delta_time + if count_down <= 0.0 { + return true + } + } + return false + }) + }, + func( + unit: dora.PlatformerUnit, + action: dora.PlatformerUnitAction, + ) { + }, + ) + + sel := dora.PlatformerDecisionTreeSel + seq := dora.PlatformerDecisionTreeSeq + con := dora.PlatformerDecisionTreeCon + act := dora.PlatformerDecisionTreeAct + + tree := sel(&[]dora.PlatformerDecisionTree{ + seq(&[]dora.PlatformerDecisionTree{ + con("fmove key down", func(unit: dora.PlatformerUnit) => bool { + entity := unit.GetEntity() + key_left_val := entity.Get("keyLeft") + if key_left_val == nil { + return false + } + key_left, _ := key_left_val.GetBool() + key_right_val := entity.Get("keyRight") + if key_right_val == nil { + return false + } + key_right, _ := key_right_val.GetBool() + return key_left != key_right && ((key_left && unit.IsFaceRight()) || (key_right && !unit.IsFaceRight())) + }), + act("turn"), + }), + seq(&[]dora.PlatformerDecisionTree{ + con("is falling", func(unit: dora.PlatformerUnit) => bool { + return !unit.IsOnSurface() + }), + act("fallOff"), + }), + seq(&[]dora.PlatformerDecisionTree{ + con("jump key down", func(unit: dora.PlatformerUnit) => bool { + entity := unit.GetEntity() + key_jump_val := entity.Get("keyJump") + if key_jump_val == nil { + return false + } + key_jump, _ := key_jump_val.GetBool() + return key_jump + }), + act("jump"), + }), + seq(&[]dora.PlatformerDecisionTree{ + con("fmove key down", func(unit: dora.PlatformerUnit) => bool { + entity := unit.GetEntity() + key_left_val := entity.Get("keyLeft") + if key_left_val == nil { + return false + } + key_left, _ := key_left_val.GetBool() + key_right_val := entity.Get("keyRight") + if key_right_val == nil { + return false + } + key_right, _ := key_right_val.GetBool() + return key_left || key_right + }), + act("move"), + }), + act("idle"), + }) + store := dora.PlatformerData.GetStore() + store.Set("AI:playerControl", tree.Object) + + unit_def := dora.NewDictionary() + unit_def.Set("linearAcceleration", dora.NewVec2(0.0, -15.0)) + unit_def.Set("bodyType", "Dynamic") + unit_def.Set("scale", 1.0) + unit_def.Set("density", 1.0) + unit_def.Set("friction", 1.0) + unit_def.Set("restitution", 0.0) + unit_def.Set("playable", "spine:Spine/moling") + unit_def.Set("defaultFaceRight", true) + unit_def.Set("size", dora.NewSize(60.0, 300.0)) + unit_def.Set("sensity", 0) + unit_def.Set("move", 300.0) + unit_def.Set("jump", 1000.0) + unit_def.Set("detectDistance", 350.0) + unit_def.Set("hp", 5.0) + unit_def.Set("tag", "player") + unit_def.Set("decisionTree", "AI:playerControl") + unit_def.Set("usePreciseHit", false) + arr := dora.NewArray() + arr.Add("idle").Add("turn") + arr.Add("move").Add("jump") + arr.Add("fallOff").Add("cancel") + unit_def.Set("actions", arr.Object) + + { + observer := dora.NewObserver(dora.EntityEventAdd, &[]string{"player"}) + observer.Watch(func(stack: dora.CallStack) => bool { + entity := *dora.ObjectAsEntity(*stack.PopObject()) + unit := dora.NewPlatformerUnit(unit_def, world.PhysicsWorld, entity, dora.NewVec2(300.0, -350.0), 0.0) + unit.SetOrder(PLAYER_LAYER) + unit.SetGroup(player_group) + playable := unit.GetPlayable() + playable.SetPosition(dora.NewVec2(0.0, -150.0)) + playable.Play("idle", true) + world.AddChild(unit.Node) + camera := world.GetCamera() + camera.SetFollowTarget(unit.Node) + return false + }) + } + + { + observer := dora.NewObserver(dora.EntityEventRemove, &[]string{"body"}) + observer.Watch(func(stack: dora.CallStack) => bool { + entity := *dora.ObjectAsEntity(*stack.PopObject()) + body_val := entity.Get("body") + if body_val == nil { + return false + } + body := *dora.ObjectAsBody(*body_val.GetObject()) + body.RemoveFromParent(true) + return false + }) + } + + players := dora.NewGroup(&[]string{"player"}) + update_player_control := func(key: string, flag: bool) { + players.Each(func(entity: dora.Entity) => bool { + entity.Set(key, flag) + return false + }) + } + + node := dora.NewNode() + node.Schedule(func(delta_time: f64) => bool { + update_player_control("keyLeft", dora.Keyboard.IsKeyPressed(dora.KeyA)) + update_player_control("keyRight", dora.Keyboard.IsKeyPressed(dora.KeyD)) + update_player_control("keyJump", dora.Keyboard.IsKeyPressed(dora.KeyJ)) + return false + }) + + entity := dora.NewEntity() + entity.Set("player", true) + + { + observer := dora.NewObserver(dora.EntityEventAdd, &[]string{"x", "icon"}) + observer.Watch(func(stack: dora.CallStack) => bool { + entity := *dora.ObjectAsEntity(*stack.PopObject()) + x, _ := stack.PopF32() + icon, _ := stack.PopStr() + sprite := dora.NewSpriteWithFile(icon) + sprite.RunActionDef(dora.ActionDefSpawn(&[]dora.ActionDef{ + dora.ActionDefProp(5.0, 0.0, 360.0, dora.PropertyAngleY, dora.EaseLinear), + dora.ActionDefSequence(&[]dora.ActionDef{ + dora.ActionDefProp(2.5, 0.0, 40.0, dora.PropertyY, dora.EaseOutQuad), + dora.ActionDefProp(2.5, 40.0, 0.0, dora.PropertyY, dora.EaseInQuad), + }), + }), true) + body_def := dora.NewBodyDef() + body_def.SetType(dora.BodyTypeDynamic) + body_def.SetLinearAcceleration(dora.NewVec2(0.0, -10.0)) + body_def.AttachPolygon(sprite.GetWidth()*0.5, sprite.GetHeight(), 1.0, 1.0, 0.0) + body_def.AttachPolygonSensor(0, sprite.GetWidth(), sprite.GetHeight()) + body := dora.NewBody(body_def, world.PhysicsWorld, dora.NewVec2(x, 0.0), 0.0) + body.SetOrder(ITEM_LAYER) + body.SetGroup(item_group) + body.AddChild(sprite.Node) + + body.OnBodyEnter(func(other: dora.Body, sensor_tag: i32) { + if other.GetGroup() == player_group { + body.SetGroup(dora.PlatformerData.GetGroupHide()) + entity.Set("picked", true) + sprite.RunActionDef(dora.ActionDefSpawn(&[]dora.ActionDef{ + dora.ActionDefScale(0.2, 1.0, 1.3, dora.EaseOutBack), + dora.ActionDefProp(0.2, 1.0, 0.0, dora.PropertyOpacity, dora.EaseLinear), + }), false) + } + }) + world.AddChild(body.Node) + entity.Set("body", body.Object) + return false + }) + } + + load_excel := func() { + item_group := dora.NewGroup(&[]string{"item"}) + item_group.Each(func(entity: dora.Entity) => bool { + entity.Destroy() + return false + }) + work_book := dora.Content.LoadExcel("Data/items.xlsx") + work_sheet := work_book.GetSheet("items") + arr := dora.NewArray() + get_str := func(index: i32) => string { + value := arr.Get(index) + str, _ := value.GetStr() + return str + } + get_f64 := func(index: i32) => f64 { + value := arr.Get(index) + num, _ := value.GetF64() + return num + } + work_sheet.Read(arr) + work_sheet.Read(arr) + for work_sheet.Read(arr) { + entity := dora.NewEntity() + entity.Set("item", true) + if arr.GetCount() >= 7 { + entity.Set("no", get_f64(1)) + entity.Set("name", get_str(2)) + entity.Set("x", get_f64(3)) + entity.Set("num", get_f64(4)) + entity.Set("icon", get_str(5)) + entity.Set("desc", get_str(6)) + } + } + } + + load_excel() + + picked_item_group := dora.NewGroup(&[]string{"picked"}) + window_flags := dora.ImGuiWindowFlags( + dora.ImGuiWindowNoDecoration, + dora.ImGuiWindowAlwaysAutoResize, + dora.ImGuiWindowNoSavedSettings, + dora.ImGuiWindowNoFocusOnAppearing, + dora.ImGuiWindowNoNav, + dora.ImGuiWindowNoMove, + ) + imgui_node := dora.NewNode() + imgui_node.Schedule(func(delta_time: f64) => bool { + dora.ImGui.SetNextWindowBgAlpha(0.35) + dora.ImGui.SetNextWindowPosOpts(dora.NewVec2(dora.App.GetVisualSize().Width-10.0, 10.0), dora.ImGuiCondAlways, dora.NewVec2(1.0, 0.0)) + dora.ImGui.SetNextWindowSizeOpts(dora.NewVec2(100.0, 300.0), dora.ImGuiCondFirstUseEver) + dora.ImGui.BeginOpts("BackPack", window_flags, func() { + if dora.ImGui.Button("重新加载Excel", dora.Vec2Zero) { + load_excel() + } + dora.ImGui.Separator() + dora.ImGui.Text("背包 (Wa)") + dora.ImGui.Text("左(A) 右(D) 跳(J)") + dora.ImGui.Separator() + dora.ImGui.ColumnsOpts(3, false, "BackPackColumns") + picked_item_group.Each(func(entity: dora.Entity) => bool { + get_str := func(key: string) => string { + value := entity.Get(key) + str, _ := value.GetStr() + return str + } + get_f64 := func(key: string) => f64 { + value := entity.Get(key) + num, _ := value.GetF64() + return num + } + no := get_f64("no") + icon := get_str("icon") + num := get_f64("num") + name := get_str("name") + desc := get_str("desc") + if num > 0.0 { + if dora.ImGui.ImageButton("item "+strconv.Itoa(int(no)), icon, dora.NewVec2(50.0, 50.0)) { + entity.Set("num", num-1.0) + player := players.GetFirst() + unit_val := player.Get("unit") + unit := *dora.ObjectAsPlatformerUnit(*unit_val.GetObject()) + sprite := dora.NewSpriteWithFile(icon) + sprite.SetScaleX(0.5) + sprite.SetScaleY(0.5) + sprite.PerformDef(dora.ActionDefSpawn(&[]dora.ActionDef{ + dora.ActionDefProp(1.0, 1.0, 0.0, dora.PropertyOpacity, dora.EaseLinear), + dora.ActionDefProp(1.0, 150.0, 250.0, dora.PropertyY, dora.EaseLinear), + }), false) + sprite.OnActionEnd(func(action: dora.Action, node: dora.Node) { + sprite.RemoveFromParent(true) + }) + unit.AddChild(sprite.Node) + } + if dora.ImGui.IsItemHovered() { + dora.ImGui.BeginTooltip(func() { + dora.ImGui.Text(name) + dora.ImGui.Text("数量:") + dora.ImGui.SameLine(0.0, 10.0) + dora.ImGui.Text(strconv.Itoa(int(num))) + dora.ImGui.Text("描述:") + dora.ImGui.SameLine(0.0, 10.0) + dora.ImGui.Text(desc) + }) + } + dora.ImGui.NextColumn() + } + return false + }) + }) + return false + }) +} diff --git a/Tools/dora-wa/src/hello_world.wa b/Tools/dora-wa/src/hello_world.wa index ccc5b14dd..e6934d3f6 100644 --- a/Tools/dora-wa/src/hello_world.wa +++ b/Tools/dora-wa/src/hello_world.wa @@ -35,12 +35,12 @@ func test_hello_world() { width := dora.App.GetVisualSize().Width dora.ImGui.SetNextWindowBgAlpha(0.35) dora.ImGui.SetNextWindowPosOpts( - dora.Vec2{X: width - 10.0, Y: 10.0}, + dora.NewVec2(width-10.0, 10.0), dora.ImGuiCondAlways, - dora.Vec2{X: 1.0, Y: 0.0}, + dora.NewVec2(1.0, 0.0), ) dora.ImGui.SetNextWindowSizeOpts( - dora.Vec2{X: 240.0, Y: 0.0}, + dora.NewVec2(240.0, 0.0), dora.ImGuiCondFirstUseEver, ) dora.ImGui.BeginOpts("Hello World", diff --git a/Tools/dora-wa/src/main.wa b/Tools/dora-wa/src/main.wa index ab6fb4dac..e71234239 100644 --- a/Tools/dora-wa/src/main.wa +++ b/Tools/dora-wa/src/main.wa @@ -12,18 +12,18 @@ func init { dora.Director.SchedulePosted(func(_: f64) => bool { size := dora.App.GetVisualSize() dora.ImGui.SetNextWindowSizeOpts( - dora.Vec2{X: 260, Y: 300}, + dora.NewVec2(260, 300), dora.ImGuiCondFirstUseEver, ) dora.ImGui.SetNextWindowPosOpts( - dora.Vec2{X: size.Width / 2.0, Y: size.Height / 2.0}, + dora.NewVec2(size.Width/2.0, size.Height/2.0), dora.ImGuiCondFirstUseEver, - dora.Vec2{X: 0.5, Y: 0.5}, + dora.NewVec2(0.5, 0.5), ) dora.ImGui.BeginOpts("Wa Tests", dora.ImGuiWindowFlags(dora.ImGuiWindowNoSavedSettings), func() { - button_size := dora.Vec2{X: 200, Y: 0} + button_size := dora.NewVec2(200, 0) if dora.ImGui.Button("Hello World", button_size) { all_clear() test_hello_world() @@ -68,11 +68,10 @@ func init { all_clear() test_layout() } - /* - if dora.ImGui.Button("Excel Test", button_size) { - all_clear() - } - */ + if dora.ImGui.Button("Excel Test", button_size) { + all_clear() + test_excel_test() + } }) return false }) diff --git a/Tools/dora-wa/src/vg_button.wa b/Tools/dora-wa/src/vg_button.wa index ac4409aca..003ff166c 100644 --- a/Tools/dora-wa/src/vg_button.wa +++ b/Tools/dora-wa/src/vg_button.wa @@ -2,7 +2,7 @@ import "dora" func test_vg_button() { node := dora.NewNode() - node.SetSize(dora.Size{Width: 100.0, Height: 100.0}) + node.SetSize(dora.NewSize(100.0, 100.0)) font_id := dora.Nvg.CreateFont("sarasa-mono-sc-regular") light := dora.Nvg.LinearGradient(0.0, 60.0, 0.0, 0.0, dora.NewColor(0xffffffff), dora.NewColor(0xff00ffff)) dark := dora.Nvg.LinearGradient(0.0, 60.0, 0.0, 0.0, dora.NewColor(0xffffffff), dora.NewColor(0xfffbc400)) diff --git a/Tools/dora-wa/vendor/dora/dora.wa b/Tools/dora-wa/vendor/dora/dora.wa index d6c7aa6e1..f777125c9 100644 --- a/Tools/dora-wa/vendor/dora/dora.wa +++ b/Tools/dora-wa/vendor/dora/dora.wa @@ -765,14 +765,14 @@ func CallStack.PopObject() => *Object { func CallStack.PopVec2() => (Vec2, bool) { if call_stack_front_vec2(*this.raw) == 0 { - return Vec2{X: 0, Y: 0}, false + return Vec2Zero, false } return Vec2FromValue(call_stack_pop_vec2(*this.raw)), true } func CallStack.PopSize() => (Size, bool) { if call_stack_front_size(*this.raw) == 0 { - return Size{Width: 0, Height: 0}, false + return SizeZero, false } return SizeFromValue(call_stack_pop_size(*this.raw)), true } @@ -937,6 +937,10 @@ type Vec2 :struct { global Vec2Zero = Vec2{X: 0, Y: 0} +func NewVec2(x: f32, y: f32) => Vec2 { + return Vec2{X: x, Y: y} +} + func Vec2Add(a: Vec2, b: Vec2) => Vec2 { return Vec2FromValue(vec2_add(a.ToValue(), b.ToValue())) } @@ -1015,6 +1019,10 @@ type Size :struct { global SizeZero = Size{Width: 0, Height: 0} +func NewSize(width: f32, height: f32) => Size { + return Size{Width: width, Height: height} +} + func Size.ToValue() => i64 { width := math.Float32bits(this.Width) height := math.Float32bits(this.Height) @@ -1416,13 +1424,13 @@ func Dictionary.SetSize(key: string, value: Size) { dictionary_set(*this.raw, ToDoraString(key), *NewValue(value).raw) } -func Dictionary.Get(key: string) => (*Value, bool) { +func Dictionary.Get(key: string) => *Value { value := dictionary_get(*this.raw, ToDoraString(key)) if value == 0 { - return nil, false + return nil } result := ValueFrom(value) - return &result, true + return &result } /* Content */ @@ -2003,7 +2011,7 @@ func EffekNode.OnEffekEnd(callback: func(handle: i32)) { } func Node.OnAppEvent(callback: func(event_type: string)) { - this.Slot("AppEvent", func(stack: CallStack) { + this.Gslot("AppEvent", func(stack: CallStack) { event_type, ok := stack.PopStr() if !ok { panic("invalid app event") @@ -2013,7 +2021,7 @@ func Node.OnAppEvent(callback: func(event_type: string)) { } func Node.OnAppChange(callback: func(setting_name: string)) { - this.Slot("AppChange", func(stack: CallStack) { + this.Gslot("AppChange", func(stack: CallStack) { setting_name, ok := stack.PopStr() if !ok { panic("invalid app change event") @@ -2023,7 +2031,7 @@ func Node.OnAppChange(callback: func(setting_name: string)) { } func Node.OnAppWs(callback: func(event_type: string, msg: string)) { - this.Slot("AppWs", func(stack: CallStack) { + this.Gslot("AppWS", func(stack: CallStack) { event_type, ok := stack.PopStr() if !ok { panic("invalid app ws event")