新增画布类,三联,九宫格控件
This commit is contained in:
20
.vscode/launch.json
vendored
Normal file
20
.vscode/launch.json
vendored
Normal file
@@ -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
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
enum.nut
|
enum.nut
|
||||||
Tool/Math.nut
|
Tool/Math.nut
|
||||||
|
Tool/Json.nut
|
||||||
|
Tool/Common.nut
|
||||||
|
|
||||||
|
|
||||||
Game/StateMachine/StateMachine.nut
|
Game/StateMachine/StateMachine.nut
|
||||||
@@ -19,11 +21,14 @@ UI/ObjectClass/WindowNode.nut
|
|||||||
UI/ObjectClass/GameWindow.nut
|
UI/ObjectClass/GameWindow.nut
|
||||||
UI/ObjectClass/GameWidget.nut
|
UI/ObjectClass/GameWidget.nut
|
||||||
UI/ObjectClass/Sprite.nut
|
UI/ObjectClass/Sprite.nut
|
||||||
|
UI/ObjectClass/Canvas.nut
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
UI/Windows/Widget/BaseWidget.nut
|
UI/Windows/Widget/BaseWidget.nut
|
||||||
|
UI/Windows/Widget/TripleCav.nut
|
||||||
|
UI/Windows/Widget/NineGridCav.nut
|
||||||
|
|
||||||
|
|
||||||
UI/Windows/System/Cursor.nut
|
UI/Windows/System/Cursor.nut
|
||||||
|
|||||||
24
Tool/Common.nut
Normal file
24
Tool/Common.nut
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
702
Tool/Json.nut
Normal file
702
Tool/Json.nut
Normal file
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,11 +4,11 @@
|
|||||||
创建日期:2025-10-11 11:21
|
创建日期:2025-10-11 11:21
|
||||||
文件用途:主界面UI
|
文件用途:主界面UI
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
Actora <- null;
|
||||||
//主界面UI初始化回调
|
//主界面UI初始化回调
|
||||||
function _MainUI_Enter_(UI_Scene) {
|
function _MainUI_Enter_(UI_Scene) {
|
||||||
if (!_SYS_UI_SCENE_Instance_) _SYS_UI_SCENE_Instance_ = Actor(UI_Scene);
|
if (!_SYS_UI_SCENE_Instance_) _SYS_UI_SCENE_Instance_ = Actor(UI_Scene);
|
||||||
//初始化随机数种子
|
|
||||||
srand(time());
|
|
||||||
|
|
||||||
//初始化鼠标
|
//初始化鼠标
|
||||||
Game_Cursor.GetInstance();
|
Game_Cursor.GetInstance();
|
||||||
@@ -16,13 +16,36 @@ function _MainUI_Enter_(UI_Scene) {
|
|||||||
local TestWindow = sq_CreaterWindowInstance("HUD窗口", Window_hud, 0, 0, 1280, 720, 0);
|
local TestWindow = sq_CreaterWindowInstance("HUD窗口", Window_hud, 0, 0, 1280, 720, 0);
|
||||||
TestWindow.ResetFoucus();
|
TestWindow.ResetFoucus();
|
||||||
|
|
||||||
local Test1 = sq_CreaterWindowInstance("测试窗口", Window_NotiBox, 150, 150, 364, 356, 20);
|
// local Tc = GameWidget_TripleCav("sprite/interface/lenheartwindowcommon.img",175,300);
|
||||||
Test1.ResetFoucus();
|
// _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事件回调
|
//主界面UI事件回调
|
||||||
function _MainUI_HandleEvents_(EventType, EventData) {
|
function _MainUI_HandleEvents_(EventType, EventData) {
|
||||||
_Global_Windows_Events_(EventType, EventData);
|
_Global_Windows_Events_(EventType, EventData);
|
||||||
|
if (EventType == UI_EVENT.MOUSEBUTTONDOWN) {
|
||||||
|
if (Actora) {
|
||||||
|
_SYS_UI_SCENE_Instance_.RemoveChild(Actora);
|
||||||
|
Actora = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
//主界面UI更新回调
|
//主界面UI更新回调
|
||||||
function _MainUI_Update_(deltaTime) {
|
function _MainUI_Update_(deltaTime) {
|
||||||
|
|||||||
@@ -56,4 +56,8 @@ class Actor extends BaseNode {
|
|||||||
function GetWorldPos(){
|
function GetWorldPos(){
|
||||||
return sq_GetWorldPos(this.C_Object);
|
return sq_GetWorldPos(this.C_Object);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function SetName(Name) {
|
||||||
|
sq_SetName(this.C_Object, Name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,4 +13,5 @@ class BaseNode {
|
|||||||
//析构对象
|
//析构对象
|
||||||
if (DestructFlag) sq_RegisterDestruction(C_Object, this)
|
if (DestructFlag) sq_RegisterDestruction(C_Object, this)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
24
UI/ObjectClass/Canvas.nut
Normal file
24
UI/ObjectClass/Canvas.nut
Normal file
@@ -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});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,6 +10,7 @@ class Sprite extends Actor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
constructor(ImgPath, Idx) {
|
constructor(ImgPath, Idx) {
|
||||||
base.constructor(sq_CreateSprite(ImgPath, Idx))
|
C_Object = sq_CreateSprite(ImgPath, Idx);
|
||||||
|
sq_RegisterDestruction(C_Object,this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,4 +17,18 @@ class Window_hud extends GameWindow {
|
|||||||
Sp.SetPos((1280 - 403) / 2, 720 - 75);
|
Sp.SetPos((1280 - 403) / 2, 720 - 75);
|
||||||
AddChild(Sp);
|
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) {
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,9 +12,9 @@ class Game_Cursor extends GameWindow {
|
|||||||
CurrentMouseTaskId = 0;
|
CurrentMouseTaskId = 0;
|
||||||
|
|
||||||
//鼠标X坐标
|
//鼠标X坐标
|
||||||
MouseX = 0;
|
MouseX = -100;
|
||||||
//鼠标Y坐标
|
//鼠标Y坐标
|
||||||
MouseY = 0;
|
MouseY = -100;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
if (getroottable().rawin("__Game_Cursor__")) {
|
if (getroottable().rawin("__Game_Cursor__")) {
|
||||||
@@ -64,7 +64,13 @@ class Game_Cursor extends GameWindow {
|
|||||||
MouseSprite[CurrentMouseTaskId].SetPos(MouseX, MouseY);
|
MouseSprite[CurrentMouseTaskId].SetPos(MouseX, MouseY);
|
||||||
}
|
}
|
||||||
|
|
||||||
//事件
|
/**
|
||||||
|
* 鼠标窗口是独立的事件函数
|
||||||
|
* @function
|
||||||
|
* @param {any} EventType
|
||||||
|
* @param {any} EventData
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
function Event(EventType, EventData) {
|
function Event(EventType, EventData) {
|
||||||
if (EventType == UI_EVENT.MOUSEMOTION) {
|
if (EventType == UI_EVENT.MOUSEMOTION) {
|
||||||
MouseX = EventData[0];
|
MouseX = EventData[0];
|
||||||
|
|||||||
63
UI/Windows/Widget/NineGridCav.nut
Normal file
63
UI/Windows/Widget/NineGridCav.nut
Normal file
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
30
UI/Windows/Widget/TripleCav.nut
Normal file
30
UI/Windows/Widget/TripleCav.nut
Normal file
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -70,5 +70,20 @@
|
|||||||
},
|
},
|
||||||
"UI/Windows/Widget/BaseWidget.nut": {
|
"UI/Windows/Widget/BaseWidget.nut": {
|
||||||
"description": "基础控件"
|
"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": "九宫格画布"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -94,6 +94,7 @@ function sq_SetDirection(C_Object, Dir) {}
|
|||||||
function sq_CreateActor() {}
|
function sq_CreateActor() {}
|
||||||
function sq_RegisterDestruction(a,b) {}
|
function sq_RegisterDestruction(a,b) {}
|
||||||
function sq_CreateSprite(a,b) {}
|
function sq_CreateSprite(a,b) {}
|
||||||
|
function sq_CreateCanvas(a,b) {}
|
||||||
function sq_AddChild(a,b){}
|
function sq_AddChild(a,b){}
|
||||||
function sq_RemoveChild(a,b){}
|
function sq_RemoveChild(a,b){}
|
||||||
function sq_SetZOrder(a,b){}
|
function sq_SetZOrder(a,b){}
|
||||||
@@ -113,3 +114,10 @@ function pow(a,b){}
|
|||||||
|
|
||||||
function sq_GetWorldPos(a){}
|
function sq_GetWorldPos(a){}
|
||||||
function sq_SetVisible(a,b){}
|
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(...){}
|
||||||
|
|||||||
Reference in New Issue
Block a user