diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3dbb121 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,20 @@ +{ + // 使用 IntelliSense 了解相关属性。 + // 悬停以查看现有属性的描述。 + // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "squirrel", + "request": "attach", + "name": "Server", + "port": 2222 + }, + { + "type": "squirrel", + "request": "attach", + "name": "Client", + "port": 2222 + } + ] +} \ No newline at end of file diff --git a/SquirrelFileConfig.cfg b/SquirrelFileConfig.cfg index 3b0e61f..c7e795d 100644 --- a/SquirrelFileConfig.cfg +++ b/SquirrelFileConfig.cfg @@ -1,5 +1,7 @@ enum.nut Tool/Math.nut +Tool/Json.nut +Tool/Common.nut Game/StateMachine/StateMachine.nut @@ -19,11 +21,14 @@ UI/ObjectClass/WindowNode.nut UI/ObjectClass/GameWindow.nut UI/ObjectClass/GameWidget.nut UI/ObjectClass/Sprite.nut +UI/ObjectClass/Canvas.nut UI/Windows/Widget/BaseWidget.nut +UI/Windows/Widget/TripleCav.nut +UI/Windows/Widget/NineGridCav.nut UI/Windows/System/Cursor.nut diff --git a/Tool/Common.nut b/Tool/Common.nut new file mode 100644 index 0000000..777a7c9 --- /dev/null +++ b/Tool/Common.nut @@ -0,0 +1,24 @@ +/* +文件名:Common.nut +路径:Tool/Common.nut +创建日期:2025-10-25 00:05 +文件用途:工具类 +*/ +function print(Object) { + switch (typeof Object) { + case "table": + case "array": { + local str = Json.Encode(Object); + sq_OutPutTable(str); + break; + } + case "string": + case "integer": { + output(Object); + break; + } + default: + output(Object); + break; + } +} diff --git a/Tool/Json.nut b/Tool/Json.nut new file mode 100644 index 0000000..0755385 --- /dev/null +++ b/Tool/Json.nut @@ -0,0 +1,702 @@ + +/** + * JSON Parser + * @package JSONParser + */ +class JSONParser { + + // should be the same for all components within JSONParser package + static version = "1.0.1"; + + /** + * Parse JSON string into data structure + * + * @param {string} str + * @param {function({string} value[, "number"|"string"])|null} converter + * @return {*} + */ + function parse(str, converter = null) { + + local state; + local stack = [] + local container; + local key; + local value; + + // actions for string tokens + local string = { + go = function() { + state = "ok"; + }, + firstokey = function() { + key = value; + state = "colon"; + }, + okey = function() { + key = value; + state = "colon"; + }, + ovalue = function() { + value = this._convert(value, "string", converter); + state = "ocomma"; + }.bindenv(this), + firstavalue = function() { + value = this._convert(value, "string", converter); + state = "acomma"; + }.bindenv(this), + avalue = function() { + value = this._convert(value, "string", converter); + state = "acomma"; + }.bindenv(this) + }; + + // the actions for number tokens + local number = { + go = function() { + state = "ok"; + }, + ovalue = function() { + value = this._convert(value, "number", converter); + state = "ocomma"; + }.bindenv(this), + firstavalue = function() { + value = this._convert(value, "number", converter); + state = "acomma"; + }.bindenv(this), + avalue = function() { + value = this._convert(value, "number", converter); + state = "acomma"; + }.bindenv(this) + }; + + // action table + // describes where the state machine will go from each given state + local action = { + + "{": { + go = function() { + stack.push({ + state = "ok" + }); + container = {}; + state = "firstokey"; + }, + ovalue = function() { + stack.push({ + container = container, + state = "ocomma", + key = key + }); + container = {}; + state = "firstokey"; + }, + firstavalue = function() { + stack.push({ + container = container, + state = "acomma" + }); + container = {}; + state = "firstokey"; + }, + avalue = function() { + stack.push({ + container = container, + state = "acomma" + }); + container = {}; + state = "firstokey"; + } + }, + + "}": { + firstokey = function() { + local pop = stack.pop(); + value = container; + container = ("container" in pop) ? pop.container : null; + key = ("key" in pop) ? pop.key : null; + state = pop.state; + }, + ocomma = function() { + local pop = stack.pop(); + container[key] <- value; + value = container; + container = ("container" in pop) ? pop.container : null; + key = ("key" in pop) ? pop.key : null; + state = pop.state; + } + }, + + "[": { + go = function() { + stack.push({ + state = "ok" + }); + container = []; + state = "firstavalue"; + }, + ovalue = function() { + stack.push({ + container = container, + state = "ocomma", + key = key + }); + container = []; + state = "firstavalue"; + }, + firstavalue = function() { + stack.push({ + container = container, + state = "acomma" + }); + container = []; + state = "firstavalue"; + }, + avalue = function() { + stack.push({ + container = container, + state = "acomma" + }); + container = []; + state = "firstavalue"; + } + }, + + "]": { + firstavalue = function() { + local pop = stack.pop(); + value = container; + container = ("container" in pop) ? pop.container : null; + key = ("key" in pop) ? pop.key : null; + state = pop.state; + }, + acomma = function() { + local pop = stack.pop(); + container.push(value); + value = container; + container = ("container" in pop) ? pop.container : null; + key = ("key" in pop) ? pop.key : null; + state = pop.state; + } + }, + + ":": { + colon = function() { + // Check if the key already exists + // NOTE previous code used 'if (key in container)...' + // but this finds table ('container') member methods too + local err = false; + foreach(akey, avalue in container) { + if (akey == key) err = true; + break + } + if (err) throw "Duplicate key \"" + key + "\""; + state = "ovalue"; + } + }, + + ",": { + ocomma = function() { + container[key] <- value; + state = "okey"; + }, + acomma = function() { + container.push(value); + state = "avalue"; + } + }, + + "true": { + go = function() { + value = true; + state = "ok"; + }, + ovalue = function() { + value = true; + state = "ocomma"; + }, + firstavalue = function() { + value = true; + state = "acomma"; + }, + avalue = function() { + value = true; + state = "acomma"; + } + }, + + "false": { + go = function() { + value = false; + state = "ok"; + }, + ovalue = function() { + value = false; + state = "ocomma"; + }, + firstavalue = function() { + value = false; + state = "acomma"; + }, + avalue = function() { + value = false; + state = "acomma"; + } + }, + + "null": { + go = function() { + value = null; + state = "ok"; + }, + ovalue = function() { + value = null; + state = "ocomma"; + }, + firstavalue = function() { + value = null; + state = "acomma"; + }, + avalue = function() { + value = null; + state = "acomma"; + } + } + }; + + // + + state = "go"; + stack = []; + + // current tokenizeing position + local start = 0; + + try { + + local + result, + token, + tokenizer = _JSONTokenizer(); + + while (token = tokenizer.nextToken(str, start)) { + + if ("ptfn" == token.type) { + // punctuation/true/false/null + action[token.value][state](); + } else if ("number" == token.type) { + // number + value = token.value; + number[state](); + } else if ("string" == token.type) { + // string + value = tokenizer.unescape(token.value); + string[state](); + } + + start += token.length; + } + + } catch (e) { + state = e; + } + + // check is the final state is not ok + // or if there is somethign left in the str + if (state != "ok" || regexp("[^\\s]").capture(str, start)) { + local min = @(a, b) a< b ? a : b; + local near = str.slice(start, min(str.len(), start + 10)); + throw "JSON Syntax Error near `" + near + "`"; + } + + return value; + } + + /** + * Convert strings/numbers + * Uses custom converter function + * + * @param {string} value + * @param {string} type + * @param {function|null} converter + */ + function _convert(value, type, converter) { + if ("function" == typeof converter) { + + // # of params for converter function + + local parametercCount = 2; + + // .getinfos() is missing on ei platform + if ("getinfos" in converter) { + parametercCount = converter.getinfos().parameters.len() - + 1 /* "this" is also included */ ; + } + + if (parametercCount == 1) { + return converter(value); + } else if (parametercCount == 2) { + return converter(value, type); + } else { + throw "Error: converter function must take 1 or 2 parameters" + } + + } else if ("number" == type) { + return (value.find(".") == null && value.find("e") == null && value.find("E") == null) ? value.tointeger() : value.tofloat(); + } else { + return value; + } + } +} + +/** + * JSON Tokenizer + * @package JSONParser + */ +class _JSONTokenizer { + + _ptfnRegex = null; + _numberRegex = null; + _stringRegex = null; + _ltrimRegex = null; + _unescapeRegex = null; + + constructor() { + // punctuation/true/false/null + this._ptfnRegex = regexp("^(?:\\,|\\:|\\[|\\]|\\{|\\}|true|false|null)"); + + // numbers + this._numberRegex = regexp("^(?:\\-?\\d+(?:\\.\\d*)?(?:[eE][+\\-]?\\d+)?)"); + + // strings + this._stringRegex = regexp("^(?:\\\"((?:[^\\r\\n\\t\\\\\\\"]|\\\\(?:[\"\\\\\\/trnfb]|u[0-9a-fA-F]{4}))*)\\\")"); + + // ltrim pattern + this._ltrimRegex = regexp("^[\\s\\t\\n\\r]*"); + + // string unescaper tokenizer pattern + this._unescapeRegex = regexp("\\\\(?:(?:u\\d{4})|[\\\"\\\\/bfnrt])"); + } + + /** + * Get next available token + * @param {string} str + * @param {integer} start + * @return {{type,value,length}|null} + */ + function nextToken(str, start = 0) { + + local + m, + type, + token, + value, + length, + whitespaces; + + // count # of left-side whitespace chars + whitespaces = this._leadingWhitespaces(str, start); + start += whitespaces; + + if (m = this._ptfnRegex.capture(str, start)) { + // punctuation/true/false/null + value = str.slice(m[0].begin, m[0].end); + type = "ptfn"; + } else if (m = this._numberRegex.capture(str, start)) { + // number + value = str.slice(m[0].begin, m[0].end); + type = "number"; + } else if (m = this._stringRegex.capture(str, start)) { + // string + value = str.slice(m[1].begin, m[1].end); + type = "string"; + } else { + return null; + } + + token = { + type = type, + value = value, + length = m[0].end - m[0].begin + whitespaces + }; + + return token; + } + + /** + * Count # of left-side whitespace chars + * @param {string} str + * @param {integer} start + * @return {integer} number of leading spaces + */ + function _leadingWhitespaces(str, start) { + local r = this._ltrimRegex.capture(str, start); + + if (r) { + return r[0].end - r[0].begin; + } else { + return 0; + } + } + + // unesacape() replacements table + _unescapeReplacements = { + "b": "\b", + "f": "\f", + "n": "\n", + "r": "\r", + "t": "\t" + }; + + /** + * Unesacape string escaped per JSON standard + * @param {string} str + * @return {string} + */ + function unescape(str) { + + local start = 0; + local res = ""; + + while (start< str.len()) { + local m = this._unescapeRegex.capture(str, start); + + if (m) { + local token = str.slice(m[0].begin, m[0].end); + + // append chars before match + local pre = str.slice(start, m[0].begin); + res += pre; + + if (token.len() == 6) { + // unicode char in format \uhhhh, where hhhh is hex char code + // todo: convert \uhhhh chars + res += token; + } else { + // escaped char + // @see http://www.json.org/ + local char = token.slice(1); + + if (char in this._unescapeReplacements) { + res += this._unescapeReplacements[char]; + } else { + res += char; + } + } + + } else { + // append the rest of the source string + res += str.slice(start); + break; + } + + start = m[0].end; + } + + return res; + } +} + + +class JSONEncoder { + + static VERSION = "2.0.0"; + + // max structure depth + // anything above probably has a cyclic ref + static _maxDepth = 32; + + /** + * Encode value to JSON + * @param {table|array|*} value + * @returns {string} + */ + function encode(value) { + return this._encode(value); + } + + /** + * @param {table|array} val + * @param {integer=0} depth – current depth level + * @private + */ + function _encode(val, depth = 0) { + + // detect cyclic reference + if (depth > this._maxDepth) { + throw "Possible cyclic reference"; + } + + local + r = "", + s = "", + i = 0; + + switch (typeof val) { + + case "table": + case "class": + s = ""; + + // serialize properties, but not functions + foreach(k, v in val) { + if (typeof v != "function") { + s += ",\"" + k + "\":" + this._encode(v, depth + 1); + } + } + + s = s.len() > 0 ? s.slice(1) : s; + r += "{" + s + "}"; + break; + + case "array": + s = ""; + + for (i = 0; i< val.len(); i++) { + s += "," + this._encode(val[i], depth + 1); + } + + s = (i > 0) ? s.slice(1) : s; + r += "[" + s + "]"; + break; + + case "integer": + case "float": + case "bool": + r += val; + break; + + case "null": + r += "null"; + break; + + case "instance": + + if ("_serializeRaw" in val && typeof val._serializeRaw == "function") { + + // include value produced by _serializeRaw() + r += val._serializeRaw().tostring(); + + } else if ("_serialize" in val && typeof val._serialize == "function") { + + // serialize instances by calling _serialize method + r += this._encode(val._serialize(), depth + 1); + + } else { + + s = ""; + + try { + + // iterate through instances which implement _nexti meta-method + foreach(k, v in val) { + s += ",\"" + k + "\":" + this._encode(v, depth + 1); + } + + } catch (e) { + + // iterate through instances w/o _nexti + // serialize properties, but not functions + foreach(k, v in val.getclass()) { + if (typeof v != "function") { + s += ",\"" + k + "\":" + this._encode(val[k], depth + 1); + } + } + + } + + s = s.len() > 0 ? s.slice(1) : s; + r += "{" + s + "}"; + } + + break; + + case "blob": + // This is a workaround for a known bug: + // on device side Blob.tostring() returns null + // (instaead of an empty string) + r += "\"" + (val.len() ? this._escape(val.tostring()) : "") + "\""; + break; + + // strings and all other + default: + r += "\"" + this._escape(val.tostring()) + "\""; + break; + } + + return r; + } + + /** + * Escape strings according to http://www.json.org/ spec + * @param {string} str + */ + function _escape(str) { + local res = ""; + + for (local i = 0; i< str.len(); i++) { + + local ch1 = (str[i] & 0xFF); + + if ((ch1 & 0x80) == 0x00) { + // 7-bit Ascii + + ch1 = format("%c", ch1); + + if (ch1 == "\"") { + res += "\\\""; + } else if (ch1 == "\\") { + res += "\\\\"; + } else if (ch1 == "/") { + res += "\\/"; + } else if (ch1 == "\b") { + res += "\\b"; + } else if (ch1 == "\f") { + res += "\\f"; + } else if (ch1 == "\n") { + res += "\\n"; + } else if (ch1 == "\r") { + res += "\\r"; + } else if (ch1 == "\t") { + res += "\\t"; + } else if (ch1 == "\0") { + res += "\\u0000"; + } else { + res += ch1; + } + + } else { + + if ((ch1 & 0xE0) == 0xC0) { + // 110xxxxx = 2-byte unicode + local ch2 = (str[++i] & 0xFF); + res += format("%c%c", ch1, ch2); + } else if ((ch1 & 0xF0) == 0xE0) { + // 1110xxxx = 3-byte unicode + local ch2 = (str[++i] & 0xFF); + local ch3 = (str[++i] & 0xFF); + res += format("%c%c%c", ch1, ch2, ch3); + } else if ((ch1 & 0xF8) == 0xF0) { + // 11110xxx = 4 byte unicode + local ch2 = (str[++i] & 0xFF); + local ch3 = (str[++i] & 0xFF); + local ch4 = (str[++i] & 0xFF); + res += format("%c%c%c%c", ch1, ch2, ch3, ch4); + } + + } + } + + return res; + } +} + +class Json { + + function Encode(Table) { + return JSONEncoder.encode(Table); + } + + function Decode(Str) { + return JSONParser.parse(Str); + } +} \ No newline at end of file diff --git a/UI/MainUI.nut b/UI/MainUI.nut index 0bb45f0..a8f1875 100644 --- a/UI/MainUI.nut +++ b/UI/MainUI.nut @@ -4,11 +4,11 @@ 创建日期:2025-10-11 11:21 文件用途:主界面UI */ + +Actora <- null; //主界面UI初始化回调 function _MainUI_Enter_(UI_Scene) { if (!_SYS_UI_SCENE_Instance_) _SYS_UI_SCENE_Instance_ = Actor(UI_Scene); - //初始化随机数种子 - srand(time()); //初始化鼠标 Game_Cursor.GetInstance(); @@ -16,13 +16,36 @@ function _MainUI_Enter_(UI_Scene) { local TestWindow = sq_CreaterWindowInstance("HUD窗口", Window_hud, 0, 0, 1280, 720, 0); TestWindow.ResetFoucus(); - local Test1 = sq_CreaterWindowInstance("测试窗口", Window_NotiBox, 150, 150, 364, 356, 20); - Test1.ResetFoucus(); + // local Tc = GameWidget_TripleCav("sprite/interface/lenheartwindowcommon.img",175,300); + // _SYS_UI_SCENE_Instance_.AddChild(Tc); + // Tc.SetPos(400,300); + local NgC = GameWidget_NineGridCav("sprite/interface/lenheartwindowcommon.img", 97, 300, 300); + _SYS_UI_SCENE_Instance_.AddChild(NgC); + NgC.SetPos(400, 300); + + // local T = sq_GetPng("sprite/item/avatar/swordman/0sm_acap.img",0); + // print(T); + + // local Test1 = sq_CreaterWindowInstance("测试窗口", Window_NotiBox, 150, 150, 364, 356, 20); + // Test1.ResetFoucus(); + + // local Canv = Canvas(600, 600); + // _SYS_UI_SCENE_Instance_.AddChild(Canv); + + // for (local i = 0; i < 10000; i++) { + // Canv.DrawImg("sprite/item/avatar/swordman/0sm_acap.img", 0, i % 600, i / 600 * 28); + // } } //主界面UI事件回调 function _MainUI_HandleEvents_(EventType, EventData) { _Global_Windows_Events_(EventType, EventData); + if (EventType == UI_EVENT.MOUSEBUTTONDOWN) { + if (Actora) { + _SYS_UI_SCENE_Instance_.RemoveChild(Actora); + Actora = null; + } + } } //主界面UI更新回调 function _MainUI_Update_(deltaTime) { diff --git a/UI/ObjectClass/Actor.nut b/UI/ObjectClass/Actor.nut index 52a3e29..c2ccbe0 100644 --- a/UI/ObjectClass/Actor.nut +++ b/UI/ObjectClass/Actor.nut @@ -56,4 +56,8 @@ class Actor extends BaseNode { function GetWorldPos(){ return sq_GetWorldPos(this.C_Object); } + + function SetName(Name) { + sq_SetName(this.C_Object, Name); + } } diff --git a/UI/ObjectClass/BaseNode.nut b/UI/ObjectClass/BaseNode.nut index 24871ff..eb614ac 100644 --- a/UI/ObjectClass/BaseNode.nut +++ b/UI/ObjectClass/BaseNode.nut @@ -13,4 +13,5 @@ class BaseNode { //析构对象 if (DestructFlag) sq_RegisterDestruction(C_Object, this) } + } diff --git a/UI/ObjectClass/Canvas.nut b/UI/ObjectClass/Canvas.nut new file mode 100644 index 0000000..e783ba7 --- /dev/null +++ b/UI/ObjectClass/Canvas.nut @@ -0,0 +1,24 @@ +/* +文件名:Canvas.nut +路径:UI/ObjectClass/Canvas.nut +创建日期:2025-10-24 22:00 +文件用途:画布类 +*/ +class Canvas extends Actor { + function _typeof() { + return "Canvas"; + } + + constructor(Width, Height) { + C_Object = sq_CreateCanvas(Width, Height); + sq_RegisterDestruction(C_Object, this); + } + + function DrawImg(Img, Index, X, Y) { + sq_Canvas_DrawImg(C_Object, Img, Index, {x = X, y = Y}); + } + + function DrawImgRect(Img, Index, X, Y, Width, Height) { + sq_Canvas_DrawImgRect(C_Object, Img, Index, {x = X, y = Y,w = Width, h = Height}); + } +} diff --git a/UI/ObjectClass/Sprite.nut b/UI/ObjectClass/Sprite.nut index 205174d..769f96e 100644 --- a/UI/ObjectClass/Sprite.nut +++ b/UI/ObjectClass/Sprite.nut @@ -10,6 +10,7 @@ class Sprite extends Actor { } constructor(ImgPath, Idx) { - base.constructor(sq_CreateSprite(ImgPath, Idx)) + C_Object = sq_CreateSprite(ImgPath, Idx); + sq_RegisterDestruction(C_Object,this); } } diff --git a/UI/Windows/HUD/Window_hud.nut b/UI/Windows/HUD/Window_hud.nut index 6e812e7..3cc8815 100644 --- a/UI/Windows/HUD/Window_hud.nut +++ b/UI/Windows/HUD/Window_hud.nut @@ -17,4 +17,18 @@ class Window_hud extends GameWindow { Sp.SetPos((1280 - 403) / 2, 720 - 75); AddChild(Sp); } + + /** + * 鼠标事件重载函数 + * @function override + * @param {any} Type + * @param {any} Data + * @param {boolean} EventInteractiveFlag + * @returns {void} + */ + function OnMouseEvent(Type, Data, EventInteractiveFlag) { + base.OnMouseEvent(Type, Data, EventInteractiveFlag) + if(Type == UI_EVENT.MOUSEBUTTONDOWN) { + } + } } diff --git a/UI/Windows/System/Cursor.nut b/UI/Windows/System/Cursor.nut index f790da2..8476fa0 100644 --- a/UI/Windows/System/Cursor.nut +++ b/UI/Windows/System/Cursor.nut @@ -12,9 +12,9 @@ class Game_Cursor extends GameWindow { CurrentMouseTaskId = 0; //鼠标X坐标 - MouseX = 0; + MouseX = -100; //鼠标Y坐标 - MouseY = 0; + MouseY = -100; constructor() { if (getroottable().rawin("__Game_Cursor__")) { @@ -64,7 +64,13 @@ class Game_Cursor extends GameWindow { MouseSprite[CurrentMouseTaskId].SetPos(MouseX, MouseY); } - //事件 + /** + * 鼠标窗口是独立的事件函数 + * @function + * @param {any} EventType + * @param {any} EventData + * @returns {void} + */ function Event(EventType, EventData) { if (EventType == UI_EVENT.MOUSEMOTION) { MouseX = EventData[0]; diff --git a/UI/Windows/Widget/NineGridCav.nut b/UI/Windows/Widget/NineGridCav.nut new file mode 100644 index 0000000..8212467 --- /dev/null +++ b/UI/Windows/Widget/NineGridCav.nut @@ -0,0 +1,63 @@ +/* +文件名:NineGridCav.nut +路径:UI/Windows/Widget/NineGridCav.nut +创建日期:2025-10-25 00:35 +文件用途:九宫格画布 +*/ +class GameWidget_NineGridCav extends Canvas { + /** + * + * @function + * @param {string} ImgPath Img路径 + * @param {integer} ImgStart Img起始索引 + * @param {integer} Width 总宽度 + * @param {integer} Height 总高度 + * @returns {gamewidget_ninegridcav} + */ + constructor(ImgPath, ImgStart, Width, Height) { + //获取九宫格各部分原始尺寸 + local topLeft = sq_GetPng(ImgPath, ImgStart); + local topMid = sq_GetPng(ImgPath, ImgStart + 1); + local topRight = sq_GetPng(ImgPath, ImgStart + 2); + local midLeft = sq_GetPng(ImgPath, ImgStart + 3); + local midMid = sq_GetPng(ImgPath, ImgStart + 4); + local midRight = sq_GetPng(ImgPath, ImgStart + 5); + local bottomLeft = sq_GetPng(ImgPath, ImgStart + 6); + local bottomMid = sq_GetPng(ImgPath, ImgStart + 7); + local bottomRight = sq_GetPng(ImgPath, ImgStart + 8); + + //初始化画布尺寸 + base.constructor(Width, Height); + + //计算中间拉伸区域尺寸 + local midWidth = Width - topLeft.Width - topRight.Width; + local midHeight = Height - topLeft.Height - bottomLeft.Height; + + //绘制左上角 + DrawImg(ImgPath, ImgStart, 0, 0); + + //绘制上中(横向拉伸) + DrawImgRect(ImgPath, ImgStart + 1, topLeft.Width, 0, midWidth, topMid.Height); + + //绘制右上角 + DrawImg(ImgPath, ImgStart + 2, Width - topRight.Width, 0); + + //绘制左中(纵向拉伸) + DrawImgRect(ImgPath, ImgStart + 3, 0, topLeft.Height, midLeft.Width, midHeight); + + //绘制中间(双向拉伸) + DrawImgRect(ImgPath, ImgStart + 4, topLeft.Width, topLeft.Height, midWidth, midHeight); + + //绘制右中(纵向拉伸) + DrawImgRect(ImgPath, ImgStart + 5, Width - midRight.Width, topLeft.Height, midRight.Width, midHeight); + + //绘制左下角 + DrawImg(ImgPath, ImgStart + 6, 0, Height - bottomLeft.Height); + + //绘制下中(横向拉伸) + DrawImgRect(ImgPath, ImgStart + 7, topLeft.Width, Height - bottomMid.Height, midWidth, bottomMid.Height); + + //绘制右下角 + DrawImg(ImgPath, ImgStart + 8, Width - bottomRight.Width, Height - bottomRight.Height); + } +} diff --git a/UI/Windows/Widget/TripleCav.nut b/UI/Windows/Widget/TripleCav.nut new file mode 100644 index 0000000..f0ce4cd --- /dev/null +++ b/UI/Windows/Widget/TripleCav.nut @@ -0,0 +1,30 @@ +/* +文件名:TripleCav.nut +路径:UI/Windows/Widget/TripleCav.nut +创建日期:2025-10-24 23:15 +文件用途:三联画布 +*/ +class GameWidget_TripleCav extends Canvas { + /** + * 创建三联图画布 + * @function + * @param {string} ImgPath Img路径 + * @param {integer} ImgStart Img起始索引 + * @param {integer} Width 总宽度 + * @returns {gamewidget_triplecav} + */ + constructor(ImgPath, ImgStart, Width) { + local Left_Width = sq_GetPng(ImgPath, ImgStart).Width; + local Height = sq_GetPng(ImgPath, ImgStart).Height; + local Right_Width = sq_GetPng(ImgPath, ImgStart + 2).Width; + + base.constructor(Width, Height); + + //绘制左侧 + DrawImg(ImgPath, ImgStart, 0, 0); + //绘制中间 + DrawImgRect(ImgPath, ImgStart + 1, Left_Width, 0, Width - Left_Width - Right_Width, Height); + //绘制右侧 + DrawImg(ImgPath, ImgStart + 2, Width - Right_Width, 0); + } +} diff --git a/folder-alias.json b/folder-alias.json index 2453007..b36c879 100644 --- a/folder-alias.json +++ b/folder-alias.json @@ -70,5 +70,20 @@ }, "UI/Windows/Widget/BaseWidget.nut": { "description": "基础控件" + }, + "UI/ObjectClass/GameWidget.nut": { + "description": "游戏_控件类" + }, + "UI/ObjectClass/GameWindow.nut": { + "description": "游戏_窗口类" + }, + "UI/ObjectClass/Canvas.nut": { + "description": "画布类" + }, + "UI/Windows/Widget/TripleCav.nut": { + "description": "三联图画布" + }, + "UI/Windows/Widget/NineGridCav.nut": { + "description": "九宫格画布" } } \ No newline at end of file diff --git a/internalInterfaceDoc/func.nut b/internalInterfaceDoc/func.nut index e19c360..909c897 100644 --- a/internalInterfaceDoc/func.nut +++ b/internalInterfaceDoc/func.nut @@ -94,6 +94,7 @@ function sq_SetDirection(C_Object, Dir) {} function sq_CreateActor() {} function sq_RegisterDestruction(a,b) {} function sq_CreateSprite(a,b) {} +function sq_CreateCanvas(a,b) {} function sq_AddChild(a,b){} function sq_RemoveChild(a,b){} function sq_SetZOrder(a,b){} @@ -112,4 +113,11 @@ function pow(a,b){} function sq_GetWorldPos(a){} -function sq_SetVisible(a,b){} \ No newline at end of file +function sq_SetVisible(a,b){} +function sq_SetName(a,b){} +function sq_Canvas_DrawImg(a,b,c,d){} +function sq_Canvas_DrawImgRect(a,b,c,d){} +function sq_GetImg(a){} +function sq_GetPng(a,b){} +function sq_OutPutTable(...){} +function output(...){} diff --git a/main.nut b/main.nut index e566823..7e05ab9 100644 --- a/main.nut +++ b/main.nut @@ -1,5 +1,9 @@ function main() { + //初始化随机数种子 + srand(time()); + + local SM = StateMachine.GetInstance(); SM.RegisterState(CHARACTERJOB.SWORDMAN, "Character_Rest", 0);