diff --git a/ZSharp/Main.cpp b/ZSharp/Main.cpp index eddb7f9..24b673d 100644 --- a/ZSharp/Main.cpp +++ b/ZSharp/Main.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #if UNIX #include @@ -139,31 +140,36 @@ boost::any EvalExpression(const string& ex, unordered_map& v // If no operations are applied, then return self if ((countOutsideParenthesis(expression, '+') == 0 && countOutsideParenthesis(expression, '-') == 0 && countOutsideParenthesis(expression, '*') == 0 && countOutsideParenthesis(expression, '/') == 0 && countOutsideParenthesis(expression, '^') == 0) || split(expression, '.')[0] == "ZS") { - bool isFunc = IsFunction(split(expression, '(')[0]); + //bool isFunc = IsFunction(split(expression, '(')[0]); if (isFunc && !inQuotes) { - //cout << split(expression, '(')[0] << endl; - string argContents = ""; - int y = indexInStr(expression, '(') + 1; - while (y < expression.size() && expression[y] != ')') - { - argContents += expression[y]; - - y++; - } - return ExecuteFunction(split(expression, '(')[0], VarValues(split(argContents, ','), variableValues)); + // start -> FuncCall(0, x, OtherFunc(a)) + // changeto -> 0, x, OtherFunc(a) + string insideFunArgs = betweenChars(expression, '(', ')'); +#if DEVELOPER_MESSAGES == true + cout << insideFunArgs << endl; +#endif + vector argList = splitNoOverlap(insideFunArgs, ',', '(', ')'); +#if DEVELOPER_MESSAGES == true + cout << "[" << unWrapVec(argList) << "]" << endl; +#endif + vector funcArgs = VarValues(argList, variableValues); + return ExecuteFunction(trim(split(expression, '(')[0]), funcArgs); } - else if (split(expression, '.')[0] == "ZS" && !inQuotes) + else if (isZS && !inQuotes) { - string argContents = ""; - int y = indexInStr(expression, '(') + 1; - while (y < expression.size() && expression[y] != ')') - { - argContents += expression[y]; - - y++; - } - return ZSFunction(split(expression, '(')[0], VarValues(split(argContents, ','), variableValues)); + // start -> FuncCall(0, x, OtherFunc(a)) + // changeto -> 0, x, OtherFunc(a) + string insideFunArgs = betweenChars(expression, '(', ')'); +#if DEVELOPER_MESSAGES == true + cout << insideFunArgs << endl; +#endif + vector argList = splitNoOverlap(insideFunArgs, ',', '(', ')'); +#if DEVELOPER_MESSAGES == true + cout << "[" << unWrapVec(argList) << "]" << endl; +#endif + vector funcArgs = VarValues(argList, variableValues); + return ZSFunction(trim(split(expression, '(')[0]), funcArgs); } else return GetVariableValue(expression, variableValues); @@ -177,11 +183,11 @@ boost::any EvalExpression(const string& ex, unordered_map& v if (expression[i] == '\"' && !isEscaped(newExpression, i)) inQuotes = !inQuotes; - if (isalpha(expression[i])) + if (isalpha(expression[i]) || expression[i] == '_') { string name = ""; - while (i < expression.size() && (isalpha(expression[i]) || expression[i] == '.')) + while (i < expression.size() && (isalpha(expression[i]) || expression[i] == '.' || expression[i] == '_')) { name += expression[i]; i++; @@ -191,29 +197,34 @@ boost::any EvalExpression(const string& ex, unordered_map& v bool isFunc = IsFunction(name); if (isFunc && !inQuotes) { - string argContents = ""; - i++; - while (i < expression.size() && expression[i] != ')') - { - argContents += expression[i]; - - i++; - } - string returnVal = AnyAsString(ExecuteFunction(name, VarValues(split(argContents, ','), variableValues))); + // start -> FuncCall(0, x, OtherFunc(a)) + // changeto -> 0, x, OtherFunc(a) + string insideFunArgs = betweenChars(expression, '(', ')'); +#if DEVELOPER_MESSAGES == true + cout << insideFunArgs << endl; +#endif + vector argList = splitNoOverlap(insideFunArgs, ',', '(', ')'); +#if DEVELOPER_MESSAGES == true + cout << unWrapVec(argList) << endl; +#endif + vector funcArgs = VarValues(argList, variableValues); + string returnVal = AnyAsString(ExecuteFunction(trim(split(expression, '(')[0]), funcArgs)); newExpression += returnVal; } else if (split(name, '.')[0] == "ZS" && !inQuotes) { - string argContents = ""; - int y = indexInStr(expression, '(') + 1; - while (y < expression.size() && expression[y] != ')') - { - argContents += expression[y]; - - y++; - } - //cout << split(expression, '(')[0] << " " << argContents << endl; - string returnVal = AnyAsString(ZSFunction(split(name, '(')[0], VarValues(split(argContents, ','), variableValues))); + // start -> FuncCall(0, x, OtherFunc(a)) + // changeto -> 0, x, OtherFunc(a) + string insideFunArgs = betweenChars(expression, '(', ')'); +#if DEVELOPER_MESSAGES == true + cout << insideFunArgs << endl; +#endif + vector argList = splitNoOverlap(insideFunArgs, ',', '(', ')'); +#if DEVELOPER_MESSAGES == true + cout << unWrapVec(argList) << endl; +#endif + vector funcArgs = VarValues(argList, variableValues); + string returnVal = AnyAsString(ExecuteFunction(trim(split(expression, '(')[0]), funcArgs)); newExpression += returnVal; } else @@ -371,7 +382,7 @@ int varOperation(const vector& str, unordered_map& v return 1; } -boost::any ProcessLine(const vector>& words, int lineNum, unordered_map& variableValues) +boost::any ProcessLine(const vector>& words, int& lineNum, unordered_map& variableValues) { // Check if the first two chars are '//', which would make it a comment if (words.at(lineNum).at(0)[0] == '/' && words.at(lineNum).at(0)[1] == '/') @@ -395,10 +406,34 @@ boost::any ProcessLine(const vector>& words, int lineNum, unorder // Check if it is function else if (IsFunction(trim(split(words.at(lineNum).at(0), '(')[0]))) { + // No args provided if (count(words.at(lineNum).at(0), '(') > 0 && count(words.at(lineNum).at(0), ')') > 0) ExecuteFunction(trim(split(words.at(lineNum).at(0), '(')[0]), vector()); else - ExecuteFunction(trim(split(words.at(lineNum).at(0), '(')[0]), VarValues(split(RMParenthesis("(" + split(unWrapVec(rangeInVec(words.at(lineNum), 0, (int)words.at(lineNum).size() - 1)), '(')[1]), ','), variableValues)); + { // Args provided, parse them first + // start -> FuncCall(0, x, OtherFunc(a)) + // changeto -> 0, x, OtherFunc(a) + string insideFunArgs = betweenChars(unWrapVec(words.at(lineNum)), '(', ')'); + vector argList = splitNoOverlap(insideFunArgs, ',', '(', ')'); + vector funcArgs = VarValues(argList, variableValues); + ExecuteFunction(trim(split(words.at(lineNum).at(0), '(')[0]), funcArgs); + } + return nullType; + } + + // Check if it is a SplitThread call + else if (startsWith(words.at(lineNum).at(0), "SplitThread")) + { + vector lineContents = removeTabs(words.at(lineNum), 10); + cout << "New Thread: " << words.at(lineNum).at(0) << endl; + //lineContents.at(0) = betweenChars(lineContents.at(0), '(', ')'); + + //cout << "debug: " << lineContents.at(0) << endl; + + //if (betweenChars(lineContents.at(0), '(', ')') == "") + // std::thread thread_obj(ExecuteFunction, trim(split(lineContents.at(0), '(')[0]), vector()); + //else + // std::thread thread_obj(ExecuteFunction, trim(split(lineContents.at(0), '(')[0]), VarValues(split(RMParenthesis("(" + split(unWrapVec(rangeInVec(lineContents, 0, (int)lineContents.size() - 2)), '(')[1]), ','), variableValues)); return nullType; } @@ -413,6 +448,7 @@ boost::any ProcessLine(const vector>& words, int lineNum, unorder // re-inits a variable then store it with it's value else if (countInVector(types, trim(words.at(lineNum).at(0))) > 0) { + //cout << words.at(lineNum).at(1) << "=" << unWrapVec(slice(words.at(lineNum), 3, -1)) << "=" << AnyAsString(EvalExpression(unWrapVec(slice(words.at(lineNum), 3, -1)), variableValues)) << endl; variableValues[words.at(lineNum).at(1)] = EvalExpression(unWrapVec(slice(words.at(lineNum), 3, -1)), variableValues); return nullType; } @@ -426,7 +462,7 @@ boost::any ProcessLine(const vector>& words, int lineNum, unorder return nullType; } - // Check existing variables: To see if accessign class sub component + // Check existing variables: To see if accessing class sub component else if (count(words.at(lineNum).at(0), '.') > 0 && IsVar(split(words.at(lineNum).at(0), '.')[0], variableValues) || IsVar(split(words.at(lineNum).at(0), '.')[0], globalVariableValues)) { if (IsVar(split(words.at(lineNum).at(0), '.')[0], variableValues)) @@ -442,17 +478,28 @@ boost::any ProcessLine(const vector>& words, int lineNum, unorder vector> whileContents; vector whileParameters; - for (int w = 1; w < (int)words.at(lineNum).size(); w++) - whileParameters.push_back(words.at(lineNum)[w]); + int numOfBrackets = 0; + for (int w = 1; w < (int)words.at(lineNum).size(); w++) { + if (count(words.at(lineNum).at(w), '{') == 0) + whileParameters.push_back(words.at(lineNum)[w]); + else + { + whileParameters.push_back(replace(words.at(lineNum)[w], "{", "")); + numOfBrackets = 1; + break; + } + } - int numOfBrackets = 1; - for (int p = lineNum + 2; p < (int)words.size(); p++) + lineNum += 1; + while (lineNum < (int)words.size()) { - numOfBrackets += countInVector(words.at(p), "{") - countInVector(words.at(p), "}"); + numOfBrackets += countInVector(words.at(lineNum), "{") - countInVector(words.at(lineNum), "}"); if (numOfBrackets == 0) break; - whileContents.push_back(words.at(p)); + whileContents.push_back(words.at(lineNum)); + lineNum++; } + whileContents = removeTabsWdArry(whileContents, 1); while (BooleanLogic(whileParameters.at(0), whileParameters.at(1), whileParameters.at(2), variableValues)) @@ -474,11 +521,19 @@ boost::any ProcessLine(const vector>& words, int lineNum, unorder vector> ifContents; vector ifParameters; - for (int w = 1; w < (int)words.at(lineNum).size(); w++) - ifParameters.push_back(words.at(lineNum).at(w)); + int numOfBrackets = 0; + for (int w = 1; w < (int)words.at(lineNum).size(); w++) { + if (count(words.at(lineNum).at(w), '{') == 0) + ifParameters.push_back(words.at(lineNum)[w]); + else + { + ifParameters.push_back(replace(words.at(lineNum)[w], "{", "")); + numOfBrackets = 1; + break; + } + } - int numOfBrackets = 1; - lineNum += 2; + lineNum++; while (lineNum < (int)words.size()) { numOfBrackets += countInVector(words.at(lineNum), "{") - countInVector(words.at(lineNum), "}"); @@ -487,6 +542,7 @@ boost::any ProcessLine(const vector>& words, int lineNum, unorder ifContents.push_back(words.at(lineNum)); lineNum++; } + ifContents = removeTabsWdArry(ifContents, 1); if (BooleanLogic(ifParameters.at(0), ifParameters.at(1), ifParameters.at(2), variableValues)) @@ -499,39 +555,44 @@ boost::any ProcessLine(const vector>& words, int lineNum, unorder return returnVal; } } - //else if (words.size() > lineNum + 1) - // if (words[lineNum + 1][0] == "else") - // { - // lineNum += 1; + else if (words.size() > lineNum + 1) + { + if (words[lineNum + 1].at(0) == "else") + { + vector> elseContents; + vector elseParameters; - // vector elseContents; + int numOfBrackets = 0; + for (int w = 1; w < (int)words.at(lineNum).size(); w++) { + if (count(words.at(lineNum).at(w), '{') != 0) + { + numOfBrackets = 1; + break; + } + } - // int numOfBrackets = 1; - // while (lineNum < (int)words.size()) - // { - // numOfBrackets += countInVector(words[lineNum], "{") - countInVector(words[lineNum], "}"); - // if (numOfBrackets == 0) - // break; - // elseContents.push_back(""); - // for (int w = 0; w < (int)words[lineNum].size(); w++) - // { - // elseContents[(int)elseContents.size() - 1] += words[lineNum][w] + " "; - // } - // lineNum++; - // } - // elseContents = removeTabs(elseContents, 2); + lineNum++; + while (lineNum < (int)words.size()) + { + numOfBrackets += countInVector(words.at(lineNum), "{") - countInVector(words.at(lineNum), "}"); + if (numOfBrackets == 0) + break; + elseContents.push_back(words.at(lineNum)); + lineNum++; + } - // vector> innerWords; - // for (int i = 0; i < (int)elseContents.size(); i++) - // innerWords.push_back(split(elseContents[i], ' ')); + elseContents = removeTabsWdArry(elseContents, 1); - // //Iterate through all lines in else statement - // for (int lineNum = 0; lineNum < (int)elseContents.size(); lineNum++) - // { - // ProcessLine(innerWords, lineNum, variableValues); - // } - // return nullType; - // } + //Iterate through all lines in if statement + for (int l = 0; l < (int)elseContents.size(); l++) + { + boost::any returnVal = ProcessLine(elseContents, l, variableValues); + if (!returnVal.empty()) + return returnVal; + } + + } + } return nullType; } //// Gathers else statement contents @@ -582,7 +643,7 @@ boost::any ExecuteFunction(const string& functionName, const vector& int parseZSharp(string script) { script = replace(script, " ", "\t"); // Replace spaces with tabs (not really required, and will break purposefull whitespace in strings etc.) - #if DEVELOPER_MESSAGES +#if DEVELOPER_MESSAGES InterpreterLog("Contents:\n" + script); #endif @@ -613,14 +674,22 @@ int parseZSharp(string script) if (indexInStr(unWrapVec(words.at(lineNum)), ')') - indexInStr(unWrapVec(words.at(lineNum)), '(') > 1) for (int w = 1; w < (int)words.at(lineNum).size(); w++) // Get all words from the instantiation line: these are the args { - args += replace(replace(words.at(lineNum).at(w), "(", " "), ")", ""); + if (count(words.at(lineNum).at(w), '{') == 0) + args += replace(replace(words.at(lineNum).at(w), "(", " "), ")", ""); } args = trim(replace(args, functName + " ", "")); functionContents.push_back(split(args, ',')); - int numOfBrackets = 1; - for (int p = lineNum + 2; p < (int)words.size(); p++) + int numOfBrackets = 0; + for (int w = 1; w < (int)words.at(lineNum).size(); w++) { + if (count(words.at(lineNum).at(w), '{') != 0) { + numOfBrackets = 1; + break; + } + } + + for (int p = lineNum + 1; p < (int)words.size(); p++) { numOfBrackets += countInVector(words.at(p), "{") - countInVector(words.at(p), "}"); if (numOfBrackets == 0) @@ -631,7 +700,37 @@ int parseZSharp(string script) } else { - if (words.at(lineNum).at(0) == "string") { + if (words.at(lineNum).at(0) == "include") + { + string scriptPath = StringRaw(words.at(lineNum).at(1)); + string scriptTextContents; +#if DEVELOPER_MESSAGES == true + InterpreterLog("Including from " + words.at(lineNum).at(1) + "..."); +#endif +#if UNIX + // Get script contents as single string + auto ss = ostringstream{}; + ifstream input_file(scriptPath); + ss << input_file.rdbuf(); + scriptTextContents = ss.str(); +#if DEVELOPER_MESSAGES + InterpreterLog("Gather script contents..."); +#endif +#elif WINDOWS + // Get script contents as single string + ifstream script(scriptPath); + stringstream scriptString; + scriptString << script.rdbuf(); + scriptTextContents = scriptString.str(); +#if DEVELOPER_MESSAGES + InterpreterLog("Gather script contents..."); +#endif +#endif + parseZSharp(scriptTextContents); + } + + + else if (words.at(lineNum).at(0) == "string") { globalVariableValues[words.at(lineNum).at(1)] = StringRaw(words.at(lineNum).at(3)); #if DEVELOPER_MESSAGES == true InterpreterLog("Load script variable " + words.at(lineNum).at(1) + "..."); @@ -660,12 +759,6 @@ int parseZSharp(string script) } } -#if DEVELOPER_MESSAGES - InterpreterLog("Start Main()"); - #endif - // Executes main, which is the entry point function - ExecuteFunction("Main", vector {}); - return 0; } @@ -693,6 +786,8 @@ int main(int argc, char* argv[]) #if DEVELOPER_MESSAGES cout << scriptPath << endl; #endif + if (!fileExists(scriptPath)) + LogCriticalError("Failed to load script from path: \"" + scriptPath + "\""); std::string projectDirectory = scriptPath.substr(0, scriptPath.find_last_of("/\\")); #if UNIX @@ -703,16 +798,17 @@ int main(int argc, char* argv[]) scriptTextContents = ss.str(); #if DEVELOPER_MESSAGES InterpreterLog("Gather script contents..."); - #endif - +#endif + // Change the current working directory to that of the script - chdir(projectDirectory.c_str()); + int chErr = chdir(projectDirectory.c_str()); + if (chErr < 0) + LogCriticalError("Failed to change directory to: \"" + projectDirectory.c_str() + "\", error num: " + chErr); #if DEVELOPER_MESSAGES - InterpreterLog("Change directory to " + projectDirectory + "..."); + InterpreterLog("Changed directory to " + projectDirectory + "..."); #endif #if DEVELOPER_MESSAGES string newPath = filesystem::current_path(); - InterpreterLog("Current working directory is " + newPath); #endif #elif WINDOWS // Get script contents as single string @@ -722,15 +818,15 @@ int main(int argc, char* argv[]) scriptTextContents = scriptString.str(); #if DEVELOPER_MESSAGES InterpreterLog("Gather script contents..."); - #endif - +#endif + // Change the current working directory to that of the script std::wstring_convert> converter; std::wstring wide = converter.from_bytes(projectDirectory); LPCWSTR s = wide.c_str(); SetCurrentDirectory(s); #if DEVELOPER_MESSAGES - InterpreterLog("Change directory to " + projectDirectory + "..."); + InterpreterLog("Changed directory to " + projectDirectory + "..."); #endif #endif } @@ -742,30 +838,41 @@ int main(int argc, char* argv[]) exit(1); } - #if DEVELOPER_MESSAGES +#if DEVELOPER_MESSAGES InterpreterLog("Parsing..."); - #endif - // Start running the script +#endif + // Parse the script parseZSharp(scriptTextContents); - +#if DEVELOPER_MESSAGES + InterpreterLog("Start Main()"); +#endif + try + { + // Executes main, which is the entry point function + ExecuteFunction("Main", vector {}); + } + catch (const std::exception&) + { + //Failed with error + } + // Entire script has been run, exit. - #if DEVELOPER_MESSAGES // If built with developer messages, then verify exit cout << "Press Enter to Continue"; cin.ignore(); exit(1); #else - if(argc > 2) + if (argc > 2) { string a = argv[2]; std::transform(a.begin(), a.end(), a.begin(), - [](unsigned char c){ return std::tolower(c); }); - - if(a == "-ve") // If the '-ve' (verify exit) option is used, ask for verification on exit + [](unsigned char c) { return std::tolower(c); }); + + if (a == "-ve") // If the '-ve' (verify exit) option is used, ask for verification on exit { cout << "Press Enter to Continue"; cin.ignore(); - exit(1); + exit(1); } } #endif // Else exit automatically diff --git a/ZSharp/ZS.h b/ZSharp/ZS.h index dd6ccde..175beef 100644 --- a/ZSharp/ZS.h +++ b/ZSharp/ZS.h @@ -137,5 +137,10 @@ func GetKey(keyName) bool b = ZS.Input.GetKey(keyName) return b } + +//func SplitThread(function) +//{ +// ZS.System.SplitThread(function) +//} )" ; \ No newline at end of file diff --git a/ZSharp/builtin.h b/ZSharp/builtin.h index 5a181fb..c7e65ca 100644 --- a/ZSharp/builtin.h +++ b/ZSharp/builtin.h @@ -12,6 +12,7 @@ #include #include #include +#include #include "strops.h" #include "graphics.h" @@ -86,6 +87,10 @@ float lerp(float a, float b, float f) return a + f * (b - a); } +inline bool fileExists(const std::string& name) { + struct stat buffer; + return (stat(name.c_str(), &buffer) == 0); +} void PrintColored(std::string text, std::string fgColor, std::string bgColor, bool isError) { @@ -197,8 +202,11 @@ int LogCriticalError(const string& errorText) PrintColored("ZSharp: ", yellowFGColor, "", true); PrintColored(errorText, redFGColor, "", true); cerr << std::endl; + cout << "Press Enter to Continue"; + cin.ignore(); + exit(1); //cerr << "\x1B[34m[" + to_string(Hour) + ":" + to_string(Min) + ":" + to_string(Sec) + "] \x1B[33mZSharp: \x1B[31mERROR: " << errorText << "\033[0m\t\t" << endl; - exit(EXIT_FAILURE); + //exit(EXIT_FAILURE); return 2; } @@ -314,7 +322,7 @@ int GetBuiltins(std::string s) } builtinFunctionValues[functName] = functionContents; //cout << functName << " is \n" << Vec2Str(functionContents) << endl << endl; - } + } else { if (words.at(lineNum).at(0) == "string") @@ -351,7 +359,7 @@ int GetBuiltins(std::string s) } return 0; - } +} // Executes boost::any ZSFunction(const string& name, const vector& args) @@ -373,10 +381,16 @@ boost::any ZSFunction(const string& name, const vector& args) #if DEVELOPER_MESSAGES == true InterpreterLog("Init graphics"); #endif - initGraphics(StringRaw(AnyAsString(args.at(0))), AnyAsInt(args.at(1)), AnyAsInt(args.at(2))); + if (args.size() <= 3) + initGraphics(StringRaw(AnyAsString(args.at(0))), AnyAsInt(args.at(1)), AnyAsInt(args.at(2)), 1); + else + initGraphics(StringRaw(AnyAsString(args.at(0))), AnyAsInt(args.at(1)), AnyAsInt(args.at(2)), AnyAsInt(args.at(3))); } else if (name == "ZS.Graphics.Sprite") { + if (!fileExists(StringRaw(AnyAsString(args.at(0))))) + LogCriticalError("Failed to create 'Sprite' object: \"" + StringRaw(AnyAsString(args.at(0))) + "\""); + Sprite s(StringRaw(AnyAsString(args.at(0))), any_cast(args.at(1)), any_cast(args.at(2)), AnyAsFloat(args.at(3))); return s; } @@ -386,6 +400,9 @@ boost::any ZSFunction(const string& name, const vector& args) any_cast(args.at(0)).Load(); else if (name == "ZS.Graphics.Text") { + if (!fileExists(StringRaw(AnyAsString(args.at(1))))) + LogCriticalError("Failed to create 'Text' object: \"" + StringRaw(AnyAsString(args.at(1))) + "\""); + Text t(StringRaw(AnyAsString(args.at(0))), StringRaw(AnyAsString(args.at(1))), any_cast(args.at(2)), AnyAsFloat(args.at(3)), AnyAsFloat(args.at(4)), (Uint8)AnyAsFloat(args.at(5)), (Uint8)AnyAsFloat(args.at(6)), (Uint8)AnyAsFloat(args.at(7))); return t; } diff --git a/ZSharp/graphics.h b/ZSharp/graphics.h index e32ebba..a1a650c 100644 --- a/ZSharp/graphics.h +++ b/ZSharp/graphics.h @@ -26,6 +26,7 @@ using namespace boost; int WINDOW_WIDTH = 1280; int WINDOW_HEIGHT = 720; +int PIXEL_SCALE = 1; unordered_map KEYS = { @@ -191,7 +192,7 @@ public: { x *= rhs; y *= rhs; - + return *this; } @@ -391,6 +392,8 @@ public: { SDL_RenderCopy(gRenderer, texture, NULL, &rect); // Centers + rect.w = scale.x; + rect.h = scale.y; rect.x = position.x - (rect.w / 2); rect.y = position.y - (rect.h / 2); return 0; @@ -501,6 +504,8 @@ public: scale.y /= AnyAsFloat(otherVal); } // Centers + rect.w = scale.x; + rect.h = scale.y; rect.x = position.x - (rect.w / 2); rect.y = position.y - (rect.h / 2); return *this; @@ -523,7 +528,7 @@ public: { rect.x = position.x; rect.y = position.y; - + font = TTF_OpenFont(pathToFont.c_str(), fontSize); Load(); @@ -1017,17 +1022,21 @@ int updateLoop() return 0; } -int initGraphics(std::string windowTitle, int width, int height) +int initGraphics(std::string windowTitle, int width, int height, int pixelScale) { WINDOW_WIDTH = width; WINDOW_HEIGHT = height; + PIXEL_SCALE = pixelScale; // Initialize SDL components SDL_Init(SDL_INIT_VIDEO); TTF_Init(); - gWindow = SDL_CreateWindow(windowTitle.c_str(), 40, 40, WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_SHOWN | SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); + gWindow = SDL_CreateWindow(windowTitle.c_str(), 40, 40, WINDOW_WIDTH * PIXEL_SCALE, WINDOW_HEIGHT * PIXEL_SCALE, SDL_WINDOW_SHOWN | SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); gRenderer = SDL_CreateRenderer(gWindow, -1, 0); + SDL_RenderSetLogicalSize(gRenderer, WINDOW_WIDTH * PIXEL_SCALE, WINDOW_HEIGHT * PIXEL_SCALE); + SDL_RenderSetScale(gRenderer, PIXEL_SCALE, PIXEL_SCALE); + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, 0); //Get window surface gScreenSurface = SDL_GetWindowSurface(gWindow); diff --git a/ZSharp/strops.cpp b/ZSharp/strops.cpp index be2fa03..f3ae7ad 100644 --- a/ZSharp/strops.cpp +++ b/ZSharp/strops.cpp @@ -150,6 +150,76 @@ int countNoOverlap(const string& str, const char& searchFor, const char& ch1, co return cnt; } +vector splitNoOverlap(const string& str, const char& splitBy, const char& openChar, const char& closeChar) +{ + vector newStr; + + int openCount = 0; + + string tmpStr = ""; + for (int i = 0; i < (int)str.size(); i++) + { + if (i == (int)str.size() - 1) + { + newStr.push_back(trim(tmpStr + str[i])); + break; + } + + if (str[i] == splitBy && openCount == 0) + { + newStr.push_back(trim(tmpStr)); + tmpStr = ""; + continue; + } + else if (str[i] == openChar) { + tmpStr += str[i]; + openCount += 1; + } + else if (str[i] == closeChar) { + tmpStr += str[i]; + openCount -= 1; + } + else + tmpStr += str[i]; + } + + return newStr; +} + +string betweenChars(const string& str, const char& openChar, const char& closeChar) +{ + string content = ""; + + int waitingForClose = 0; + + for (int i = 0; i < (int)str.size(); i++) + { + if (waitingForClose > 0 && !(str[i] == closeChar && waitingForClose == 1)) + content += str[i]; + + if (str[i] == openChar) + waitingForClose++; + else if (str[i] == closeChar) + waitingForClose--; + } + + return content; +} + +bool startsWith(const string& str, const string& lookFor) +{ + if (str.empty() || lookFor.size() > str.size()) + return false; + + for (int i = 0; i < (int)lookFor.size(); i++) + { + if (str[i] != lookFor[i]) + return false; + } + + return true; +} + int countOutsideParenthesis(const string& str, const char& searchFor) { int cnt = 0; @@ -350,4 +420,4 @@ bool isEscaped(const string& str, int curChar) return true; return false; -} \ No newline at end of file +} diff --git a/ZSharp/strops.h b/ZSharp/strops.h index f709655..59dd899 100644 --- a/ZSharp/strops.h +++ b/ZSharp/strops.h @@ -34,6 +34,8 @@ int count(const string& str, const char& ch); int countNoOverlap(const string& str, const char& searchFor, const char& ch1, const char& ch2); +string betweenChars(const string& str, const char& openChar, const char& closeChar); + int countOutsideParenthesis(const string& str, const char& searchFor); int indexInStr(const string& str, const char& ch); @@ -62,4 +64,8 @@ string replace(const string& str, const string& strToReplace, const string& repl bool isEscaped(const string& str, int curChar); +bool startsWith(const string& str, const string& lookFor); + +vector splitNoOverlap(const string& str, const char& splitBy, const char& openChar, const char& closeChar); + #endif diff --git a/examples/Platformer/arial.ttf b/examples/Platformer/arial.ttf new file mode 100644 index 0000000..ff0815c Binary files /dev/null and b/examples/Platformer/arial.ttf differ diff --git a/examples/Platformer/extra-include.zs b/examples/Platformer/extra-include.zs new file mode 100644 index 0000000..29ef010 --- /dev/null +++ b/examples/Platformer/extra-include.zs @@ -0,0 +1,5 @@ + +func TestInclude() +{ + print "Hello World!" +} \ No newline at end of file diff --git a/examples/Platformer/mariostill.png b/examples/Platformer/mariostill.png new file mode 100644 index 0000000..ceabf77 Binary files /dev/null and b/examples/Platformer/mariostill.png differ diff --git a/examples/Platformer/script.zs b/examples/Platformer/script.zs new file mode 100644 index 0000000..34cbbb6 --- /dev/null +++ b/examples/Platformer/script.zs @@ -0,0 +1,109 @@ +int g_screenw = 256 +int g_screenh = 224 +int g_resolutionScale = 3 + +float g_playerWalkSpeed = 400 +float g_playerRunSpeed = 700 +float g_jumpHeight = 20 +float g_currPlayerSpeed = 400 + +bool g_running = false + +float g_gravitySpeed = -86 + +include "./extra-include.zs" + +func Main() +{ + //SplitThread(ThreadedFunction()) + + // Immediately creates the window, then Start(), then the game loop. The game loop calls Update() every frame + ZS.Graphics.Init("Platformer game", g_screenw, g_screenh, g_resolutionScale) +} + +func ThreadedFunction() +{ + print "threaded:" +} + +func Start() +{ + float centerX = g_screenw / 2 + float centerY = g_screenh / 2 + global Vec2 g_screencenter = NVec2(centerX, centerY) + + Vec2 playerPos = g_screencenter + Vec2 playerScale = NVec2(16, 16) + global Sprite g_playerSprite = ZS.Graphics.Sprite("./mariostill.png", playerPos, playerScale, 0) + + Vec2 groundPos = NVec2(g_screencenter.x, 192) + Vec2 groundScale = NVec2(256, 16) + global Sprite g_groundSprite = ZS.Graphics.Sprite("./square.png", groundPos, groundScale, 0) + + Vec2 instructionsPos = NVec2(centerOfScreen.x, centerOfScreen.y) + global Text g_instructionsText = ZS.Graphics.Text("Use Arrow Keys or WASD to Move, and Spacebar to Jump", "./arial.ttf", instructionsPos, 20, 0, 255, 255, 255) + + global Vec2 g_playerTargetPosition = playerPos + + int i = 0 + while i < 10 { + i += 1 + print "while iter : " + i + } +} + +func Update(deltaTime) { + float fps = 1 / deltaTime + print "FPS: " + fps + //TestInclude() + + //// Test automatic conversion from bool to int + //int c = GetKey("A") + //print "Test: " + c + + // Shift key lets you sprint + g_running = GetKey("SHIFT_L") + + if g_running == true{ + g_currPlayerSpeed = g_playerRunSpeed + } + if g_running == false + { + g_currPlayerSpeed = g_playerWalkSpeed + } + + // Move Left And Right + if GetKey("A") == true + { + float newY = g_playerSprite.position.y + + float newX = g_playerTargetPosition.x - g_currPlayerSpeed * deltaTime + g_playerTargetPosition = NVec2(newX, newY) + } + if GetKey("D") == true + { + float newY = g_playerSprite.position.y + + float newX = g_playerTargetPosition.x + g_currPlayerSpeed * deltaTime + g_playerTargetPosition = NVec2(newX, newY) + } + // Lerps from old position to destination smoothly + float oldX = g_playerSprite.position.x + float newX = g_playerTargetPosition.x + float stopSpeed = deltaTime * 7 + float lerpedX = Lerp(oldX, newX, stopSpeed) + g_playerSprite.position = NVec2(lerpedX, newY) + + + // Finally draws all of the sprites + ZS.Graphics.Draw(g_playerSprite) + ZS.Graphics.Draw(g_groundSprite) + + ZS.Graphics.DrawText(g_instructionsText) +} + +func Colliding(a, b) +{ + bool b = ZS.Physics.AxisAlignedCollision(a, b) + return b +} diff --git a/examples/Platformer/square.png b/examples/Platformer/square.png new file mode 100644 index 0000000..89d23b0 Binary files /dev/null and b/examples/Platformer/square.png differ