Update TiledCollisionEditor to OrginnProject implementation

master
Nic0Nic0Nii 8 months ago
parent d9107f3077
commit ffb28aa2fd
  1. 1806
      TiledCollisionEditor/Tiles/Basic Tileset - Copy - Copy - Copy - Copy - Copy.tsx
  2. 654
      TiledCollisionEditor/Tiles/Basic Tileset.tsx
  3. 250
      TiledCollisionEditor/Tiles/BasicGrass.tsx
  4. BIN
      TiledCollisionEditor/Tiles/tileset.png
  5. 363
      TiledCollisionEditor/main.cpp
  6. 43
      TiledCollisionEditor/olcPGEX_QuickGUI.h
  7. 73
      TiledCollisionEditor/pixelGameEngine.h
  8. BIN
      TiledCollisionEditor/redoButton.png
  9. BIN
      TiledCollisionEditor/undoButton.png

File diff suppressed because it is too large Load Diff

@ -0,0 +1,250 @@
<?xml version="1.0" encoding="UTF-8"?>
<tileset version="1.10" tiledversion="1.10.2" name="BasicGrass" tilewidth="32" tileheight="32" tilecount="576" columns="24">
<image source="tileset.png" width="768" height="768"/>
<tile id="53" type="Object">
<properties>
<property name="Name" value="Object0"/>
</properties>
<objectgroup draworder="index" id="1">
<object id="1" x="0" y="0">
<polygon points="184,24 48,32 48,72 184,80"/>
</object>
</objectgroup>
</tile>
<tile id="54" type="Object">
<properties>
<property name="Name" value="Object0"/>
</properties>
</tile>
<tile id="55" type="Object">
<properties>
<property name="Name" value="Object0"/>
</properties>
</tile>
<tile id="56" type="Object">
<properties>
<property name="Name" value="Object0"/>
</properties>
</tile>
<tile id="57" type="Object">
<properties>
<property name="Name" value="Object0"/>
</properties>
</tile>
<tile id="58" type="Object">
<properties>
<property name="Name" value="Object0"/>
</properties>
</tile>
<tile id="59" type="Object">
<properties>
<property name="Name" value="Object0"/>
</properties>
</tile>
<tile id="60" type="Object">
<properties>
<property name="Name" value="Object0"/>
</properties>
</tile>
<tile id="77" type="Object">
<properties>
<property name="Name" value="Object0"/>
</properties>
</tile>
<tile id="78" type="Object">
<properties>
<property name="Name" value="Object0"/>
</properties>
</tile>
<tile id="79" type="Object">
<properties>
<property name="Name" value="Object0"/>
</properties>
</tile>
<tile id="80" type="Object">
<properties>
<property name="Name" value="Object0"/>
</properties>
</tile>
<tile id="81" type="Object">
<properties>
<property name="Name" value="Object0"/>
</properties>
</tile>
<tile id="82" type="Object">
<properties>
<property name="Name" value="Object0"/>
</properties>
</tile>
<tile id="83" type="Object">
<properties>
<property name="Name" value="Object0"/>
</properties>
</tile>
<tile id="84" type="Object">
<properties>
<property name="Name" value="Object0"/>
</properties>
</tile>
<tile id="101" type="Object">
<properties>
<property name="Name" value="Object0"/>
</properties>
</tile>
<tile id="102" type="Object">
<properties>
<property name="Name" value="Object0"/>
</properties>
</tile>
<tile id="103" type="Object">
<properties>
<property name="Name" value="Object0"/>
</properties>
</tile>
<tile id="104" type="Object">
<properties>
<property name="Name" value="Object0"/>
</properties>
</tile>
<tile id="105" type="Object">
<properties>
<property name="Name" value="Object0"/>
</properties>
</tile>
<tile id="106" type="Object">
<properties>
<property name="Name" value="Object0"/>
</properties>
</tile>
<tile id="107" type="Object">
<properties>
<property name="Name" value="Object0"/>
</properties>
</tile>
<tile id="108" type="Object">
<properties>
<property name="Name" value="Object0"/>
</properties>
</tile>
<tile id="125" type="Object">
<properties>
<property name="Name" value="Object0"/>
</properties>
</tile>
<tile id="126" type="Object">
<properties>
<property name="Name" value="Object0"/>
</properties>
</tile>
<tile id="127" type="Object">
<properties>
<property name="Name" value="Object0"/>
</properties>
</tile>
<tile id="128" type="Object">
<properties>
<property name="Name" value="Object0"/>
</properties>
</tile>
<tile id="129" type="Object">
<properties>
<property name="Name" value="Object0"/>
</properties>
</tile>
<tile id="130" type="Object">
<properties>
<property name="Name" value="Object0"/>
</properties>
</tile>
<tile id="131" type="Object">
<properties>
<property name="Name" value="Object0"/>
</properties>
</tile>
<tile id="132" type="Object">
<properties>
<property name="Name" value="Object0"/>
</properties>
</tile>
<tile id="149" type="Object">
<properties>
<property name="Name" value="Object0"/>
</properties>
</tile>
<tile id="150" type="Object">
<properties>
<property name="Name" value="Object0"/>
</properties>
</tile>
<tile id="151" type="Object">
<properties>
<property name="Name" value="Object0"/>
</properties>
</tile>
<tile id="152" type="Object">
<properties>
<property name="Name" value="Object0"/>
</properties>
</tile>
<tile id="153" type="Object">
<properties>
<property name="Name" value="Object0"/>
</properties>
</tile>
<tile id="154" type="Object">
<properties>
<property name="Name" value="Object0"/>
</properties>
</tile>
<tile id="155" type="Object">
<properties>
<property name="Name" value="Object0"/>
</properties>
</tile>
<tile id="156" type="Object">
<properties>
<property name="Name" value="Object0"/>
</properties>
</tile>
</tileset>

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

@ -4,6 +4,7 @@
#include "olcUTIL_Camera2D.h"
#include "olcPGEX_QuickGUI.h"
#include <variant>
#include <deque>
using namespace olc;
using namespace olc::utils;
@ -13,8 +14,8 @@ const std::string TILESET_DIR="./Tiles/";
class TiledCollisionEditor : public olc::PixelGameEngine
{
std::unordered_map<std::string,Tileset>tilesets;
std::unordered_map<std::string,Renderable>images;
Tileset currentTileset;
Renderable mapImage;
std::string activeTileset;
Quadrilateral*editingQuad=nullptr;
Quadrilateral originalQuad;
@ -24,17 +25,32 @@ class TiledCollisionEditor : public olc::PixelGameEngine
bool dragTranslate=false;
vf2d upperLeftDragOffset{};
Quadrilateral*highlightedQuad=nullptr;
std::string nameEditObj="";
size_t lastSelectedItem=0;
bool dragNewObj=false;
vi2d upperLeftObjTile{};
vi2d lowerRightObjTile{};
bool selectingFile=false;
Renderable circle;
Renderable createNewButtonImg;
Renderable undoButtonImg;
Renderable redoButtonImg;
Renderable editButtonImg;
bool loadedFirstFile=false;
TransformedView view;
std::vector<std::string>tilesetList;
std::unordered_map<std::string,TilesetObject>previousObjState;
std::deque<std::unordered_map<std::string,TilesetObject>>redoList;
std::deque<std::unordered_map<std::string,TilesetObject>>undoList;
public:
TiledCollisionEditor()
{
@ -42,10 +58,17 @@ public:
}
Manager gui;
Manager selectionGui;
ImageCheckBox*createNewButton=nullptr;
ImageCheckBox*editButton=nullptr;
ImageButton*undoButton=nullptr;
ImageButton*redoButton=nullptr;
TextBox*nameBox=nullptr;
Button*openButton=nullptr;
ListBox*tilesetsList=nullptr;
TSXParser parsedMap{""};
Button*closeButton=nullptr;
public:
bool OnUserCreate() override
{
@ -60,38 +83,57 @@ public:
createNewButtonImg.Load("newCollisionButton.png");
editButtonImg.Load("EditButton.png");
std::string tilesetFilename=TILESET_DIR+"Basic Tileset.tsx";
parsedMap={tilesetFilename};
Tileset&tileset=tilesets[tilesetFilename]=parsedMap.GetData();
Renderable&tilesetImg=images[tilesetFilename];
tilesetImg.Load(TILESET_DIR+tileset.filename);
if(tilesets.size()==1)activeTileset=tilesetFilename;
undoButtonImg.Load("undoButton.png");
redoButtonImg.Load("redoButton.png");
createNewButton=new ImageCheckBox{gui,createNewButtonImg,false,vf2d{4.f,ScreenHeight()-36.f},{32.f,32.f},{4,1},{32,32}};
createNewButton->hotkey=Q;
editButton=new ImageCheckBox{gui,editButtonImg,true,vf2d{40.f,ScreenHeight()-36.f},{32.f,32.f},{4,4},{32,32}};
editButton->hotkey=E;
undoButton=new ImageButton{gui,undoButtonImg,vf2d{ScreenWidth()-72.f,ScreenHeight()-36.f},{32.f,32.f},{4,4},{32,32}};
redoButton=new ImageButton{gui,redoButtonImg,vf2d{ScreenWidth()-36.f,ScreenHeight()-36.f},{32.f,32.f},{4,4},{32,32}};
nameBox=new TextBox{gui,"",vf2d{76.f,ScreenHeight()-36.f+6.f},{128,20.f},{1,1}};
nameBox->bHasBackground=true;
openButton=new Button{gui,"Open",{ScreenWidth()-32.f,0.f},{32,12.f},{0.5f,0.5f}};
closeButton=new Button{selectionGui,"Close",{ScreenWidth()-32.f,0.f},{32,12.f},{0.5f,0.5f}};
std::filesystem::path dir{TILESET_DIR};
for(auto const&dir:std::filesystem::directory_iterator(dir)){
if(dir.path().string().ends_with(".tsx")){
tilesetList.push_back(dir.path().string());
}
}
tilesetsList=new ListBox{selectionGui,tilesetList,{ScreenWidth()/2-240.f,ScreenHeight()/2-60.f},{480.f,120.f},16.f};
previousObjState=currentTileset.objects;
return true;
}
void SaveFile(){
void SaveFile(bool ignoreUndoEntry=false){
if(!ignoreUndoEntry){
undoList.push_back(previousObjState);
previousObjState=currentTileset.objects;
redoList.clear();
if(undoList.size()>20)undoList.pop_front();
}
std::stringstream file;
if(file.good()){
const std::vector<XMLTag>originalData=parsedMap.originalData;
const std::vector<NonObject>nonObjects=parsedMap.nonObjects;
auto xmlTag=std::find_if(originalData.begin(),originalData.end(),[](const XMLTag tag){return tag.tag=="?xml";});
file<<"<?xml version=\"1.0\" encoding=\"UTF-8\"?>"<<std::endl;
if(xmlTag!=originalData.end())file<<"<?xml version=\"1.0\" encoding=\"UTF-8\"?>"<<std::endl;
const Tileset&activeSet=tilesets.at(activeTileset);
file<<std::format("<tileset name=\"{}\" tilewidth=\"{}\" tileheight=\"{}\" tilecount=\"{}\" columns=\"{}\">",
activeSet.name,activeSet.tilewidth,activeSet.tileheight,(activeSet.imagewidth/activeSet.tilewidth)*(activeSet.imageheight/activeSet.tileheight),activeSet.columns)<<std::endl;
const Tileset&activeSet=currentTileset;
file<<std::format("<tileset version=\"1.10\" tiledversion=\"1.10.2\" name=\"{}\" tilewidth=\"{}\" tileheight=\"{}\" tilecount=\"{}\" columns=\"{}\">",
activeSet.name,activeSet.tilewidth,activeSet.tileheight,activeSet.tilecount,activeSet.columns)<<std::endl;
auto transformationsTag=std::find_if(originalData.begin(),originalData.end(),[](const XMLTag tag){return tag.tag=="transformations";});
file<<(*transformationsTag).OutputTag("/>")<<std::endl;
if(transformationsTag!=originalData.end())file<<(*transformationsTag).OutputTag("/>")<<std::endl;
file<<std::format("<image source=\"{}\" width=\"{}\" height=\"{}\"/>",
activeSet.filename,activeSet.imagewidth,activeSet.imageheight)<<std::endl;
@ -123,28 +165,32 @@ public:
std::ofstream saveFile{activeTileset};
saveFile<<file.str()<<std::endl;
saveFile.close();
std::cout<<"Save Successful!"<<std::endl;
}
void ResetState(){
editingPoint=4;
dragging=false;
editingQuad=nullptr;
dragTranslate=false;
highlightedQuad=nullptr;
selectedObj="";
dragNewObj=false;
}
void Update(){
const Tileset&tileset=tilesets[activeTileset];
const Tileset&tileset=currentTileset;
if(selectedObj.length()>0){
if(GetKey(DEL).bPressed){
tilesets[activeTileset].objects.erase(selectedObj);
if(GetKey(DEL).bReleased){
currentTileset.objects.erase(selectedObj);
selectedObj="";
ResetState();
SaveFile();
return;
}
for(int y=0;y<tileset.tilecount/tileset.columns;y++){
for(int x=0;x<tileset.columns;x++){
if(!geom2d::contains(tileset.objects.at(selectedObj).bounds,vf2d{float(x*tileset.tilewidth)+tileset.tilewidth/2,float(y*tileset.tileheight)+tileset.tileheight/2})){
view.FillRectDecal(vf2d{float(x),float(y)}*tileset.tilewidth,vf2d{float(tileset.tilewidth),float(tileset.tileheight)},{0,0,0,128});
}
}
}
const TilesetObject&obj=tileset.objects.at(selectedObj);
const bool EditingQuad=(editingPoint<4||dragging)&&editingQuad!=nullptr;
@ -158,7 +204,12 @@ public:
};
if(EditingQuad&&!dragging){
(*editingQuad)[editingPoint]=GetSnapPoint();
vf2d newEditPoint=GetSnapPoint();
newEditPoint.x=std::clamp(newEditPoint.x,float(obj.bounds.left().start.x),float(obj.bounds.right().start.x));
newEditPoint.y=std::clamp(newEditPoint.y,float(obj.bounds.top().start.y),float(obj.bounds.bottom().start.y));
(*editingQuad)[editingPoint]=newEditPoint;
}else
if(EditingQuad&&dragging){
vf2d cursorPos=GetSnapPoint();
@ -180,7 +231,7 @@ public:
if(highlightedQuad!=nullptr){
#pragma region Select a point on a collision quad.
for(size_t pointInd=0;const vf2d&point:*highlightedQuad){
if(geom2d::line<float>(point,view.ScreenToWorld(GetMousePos())).length()<4){
if(geom2d::line<float>(point,view.ScreenToWorld(GetMousePos())).length()<4/view.GetWorldScale().x){
editingPoint=pointInd;
editingQuad=highlightedQuad;
originalQuad=*highlightedQuad;
@ -198,24 +249,25 @@ public:
}
exitCollisionCheck:
if(EditingQuad&&!dragging){
(*editingQuad)[editingPoint]=GetSnapPoint();
vf2d newEditPoint=GetSnapPoint();
newEditPoint.x=std::clamp(newEditPoint.x,float(obj.bounds.left().start.x),float(obj.bounds.right().start.x));
newEditPoint.y=std::clamp(newEditPoint.y,float(obj.bounds.top().start.y),float(obj.bounds.bottom().start.y));
(*editingQuad)[editingPoint]=newEditPoint;
editingPoint++;
}
}
if(GetMouse(Mouse::RIGHT).bPressed||GetKey(ESCAPE).bPressed){
if(GetMouse(Mouse::RIGHT).bPressed||GetKey(ESCAPE).bReleased){
if(EditingQuad||dragTranslate){
editingPoint=4;
dragging=false;
*editingQuad=originalQuad;
editingQuad=nullptr;
dragTranslate=false;
ResetState();
}
}
}else{
if(GetMouse(Mouse::LEFT).bPressed){
Quadrilateral newQuad{GetSnapPoint()};
tilesets[activeTileset].objects[selectedObj].collisionTiles.push_back(newQuad);
currentTileset.objects[selectedObj].collisionTiles.push_back(newQuad);
dragging=true;
editingQuad=const_cast<Quadrilateral*>(&obj.collisionTiles.back());
originalQuad=*editingQuad;
@ -224,11 +276,8 @@ public:
if(GetMouse(Mouse::RIGHT).bPressed&&!EditingQuad&&!dragTranslate){
if(highlightedQuad!=nullptr){
std::erase_if(tilesets[activeTileset].objects[selectedObj].collisionTiles,[&](Quadrilateral&q){return &q==highlightedQuad;});
editingPoint=4;
dragging=false;
editingQuad=nullptr;
dragTranslate=false;
std::erase_if(currentTileset.objects[selectedObj].collisionTiles,[&](Quadrilateral&q){return &q==highlightedQuad;});
ResetState();
SaveFile();
}
}
@ -240,12 +289,21 @@ public:
(*editingQuad)[1]=vf2d{cursorPos.x,initialPoint.y};
(*editingQuad)[2]=GetSnapPoint();
(*editingQuad)[3]=vf2d{initialPoint.x,cursorPos.y};
dragging=false;
ResetState();
SaveFile();
}else
if(EditingQuad&&!dragging){
(*editingQuad)[editingPoint]=GetSnapPoint();
vf2d newEditPoint=GetSnapPoint();
newEditPoint.x=std::clamp(newEditPoint.x,float(obj.bounds.left().start.x),float(obj.bounds.right().start.x));
newEditPoint.y=std::clamp(newEditPoint.y,float(obj.bounds.top().start.y),float(obj.bounds.bottom().start.y));
(*editingQuad)[editingPoint]=newEditPoint;
editingPoint=4;
dragging=false;
editingQuad=nullptr;
dragTranslate=false;
highlightedQuad=nullptr;
SaveFile();
}else
if(dragTranslate){
@ -258,7 +316,7 @@ public:
}
void NewObjectUpdate(){
const Tileset&tileset=tilesets[activeTileset];
const Tileset&tileset=currentTileset;
if(GetMouse(Mouse::LEFT).bReleased){
dragNewObj=false;
@ -280,7 +338,7 @@ public:
geom2d::rect<int>newObjRect{newUpperLeftTile,newLowerRightTile-newUpperLeftTile};
const Tileset&tileset=tilesets[activeTileset];
const Tileset&tileset=currentTileset;
//Check for intersection with other objects, if found then we deny creating this object this way.
bool intersectionFound=false;
for(auto&[name,obj]:tileset.objects){
@ -292,9 +350,9 @@ public:
}
if(!intersectionFound){
std::string objName=std::format("Object{}",tilesets[activeTileset].objects.size());
std::string objName=std::format("Object{}",currentTileset.objects.size());
TilesetObject&newObj=tilesets[activeTileset].objects[objName];
TilesetObject&newObj=currentTileset.objects[objName];
newObj.name=objName;
for(int y=0;y<newObjRect.size.y/tileset.tileheight;y++){
for(int x=0;x<newObjRect.size.x/tileset.tilewidth;x++){
@ -309,33 +367,70 @@ public:
}
}
bool OnUserUpdate(float fElapsedTime) override
{
Clear(VERY_DARK_BLUE);
void OnTextEntryComplete(const std::string&sText)override{
currentTileset.objects[nameEditObj].name=sText;
SaveFile();
}
void EditorUpdate(){
view.HandlePanAndZoom();
const float CAMERA_MOVESPD = 150.f;
if(GetKey(W).bHeld)view.MoveWorldOffset(vf2d{0.f,-CAMERA_MOVESPD}*fElapsedTime/view.GetWorldScale());
if(GetKey(S).bHeld)view.MoveWorldOffset(vf2d{0.f,CAMERA_MOVESPD}*fElapsedTime/view.GetWorldScale());
if(GetKey(A).bHeld)view.MoveWorldOffset(vf2d{-CAMERA_MOVESPD,0.f}*fElapsedTime/view.GetWorldScale());
if(GetKey(D).bHeld)view.MoveWorldOffset(vf2d{CAMERA_MOVESPD,0.f}*fElapsedTime/view.GetWorldScale());
const Tileset&tileset=tilesets[activeTileset];
const Tileset&tileset=currentTileset;
view.DrawDecal({0,0},images[activeTileset].Decal());
const float CAMERA_MOVESPD = 150.f;
for(int y=0;y<tileset.tilecount/tileset.columns;y++){
for(int x=0;x<tileset.columns;x++){
view.DrawRectDecal(vf2d{float(x),float(y)}*tileset.tilewidth,vf2d{float(tileset.tilewidth),float(tileset.tileheight)},GREY);
if(!nameBox->m_bTextEdit){
if(selectedObj.length()>0&&GetKey(R).bReleased){
TextEntryEnable(true, nameBox->sText);
nameBox->m_bTextEdit=true;
nameEditObj=currentTileset.objects[selectedObj].name;
}
if(GetKey(W).bHeld)view.MoveWorldOffset(vf2d{0.f,-CAMERA_MOVESPD}*GetElapsedTime()/view.GetWorldScale());
if(GetKey(S).bHeld)view.MoveWorldOffset(vf2d{0.f,CAMERA_MOVESPD}*GetElapsedTime()/view.GetWorldScale());
if(GetKey(A).bHeld)view.MoveWorldOffset(vf2d{-CAMERA_MOVESPD,0.f}*GetElapsedTime()/view.GetWorldScale());
if(GetKey(D).bHeld)view.MoveWorldOffset(vf2d{CAMERA_MOVESPD,0.f}*GetElapsedTime()/view.GetWorldScale());
if(((undoButton->bPressed||GetKey(CTRL).bHeld&&GetKey(Z).bReleased))&&
undoList.size()>0){
redoList.push_back(currentTileset.objects);
currentTileset.objects.clear();
currentTileset.objects=undoList.back();
undoList.pop_back();
previousObjState=currentTileset.objects;
std::cout<<"Undo List Size:"<<undoList.size()<<std::endl;
SaveFile(true);
ResetState();
gui.Update(this);
return; //Don't process the rest of this function because we clicked and so we skip input.
}
if(((redoButton->bPressed||GetKey(CTRL).bHeld&&GetKey(Y).bReleased||GetKey(CTRL).bHeld&&GetKey(SHIFT).bHeld&&GetKey(Z).bReleased))&&
redoList.size()>0){
undoList.push_back(currentTileset.objects);
currentTileset.objects.clear();
currentTileset.objects=redoList.back();
previousObjState=currentTileset.objects;
redoList.pop_back();
std::cout<<"Redo List Size:"<<redoList.size()<<std::endl;
SaveFile(true);
ResetState();
gui.Update(this);
return;
}
if(openButton->bReleased){
selectingFile=true;
openButton->Reset();
gui.Update(this);
return;
}
}
if(editingQuad==nullptr){
const bool EditingQuad=(editingPoint<4||dragging)&&editingQuad!=nullptr;
if(editingQuad==nullptr&&!EditingQuad){
selectedObj="";
for(auto&[objName,obj]:tileset.objects){
if(geom2d::contains(obj.bounds,view.ScreenToWorld(GetMousePos()))){
selectedObj=objName;
nameBox->sText=obj.name;
break;
}
}
@ -343,8 +438,19 @@ public:
if(createNewButton->bPressed)editButton->bChecked=false;
if(editButton->bPressed)createNewButton->bChecked=false;
undoButton->Enable(undoList.size()>0);
redoButton->Enable(redoList.size()>0);
if(GetMouseY()<ScreenHeight()-36||GetMouseX()>72){
gui.Update(this);
if((GetMouseY()<ScreenHeight()-36||GetMouseX()>204)&&
(GetMouseX()<ScreenWidth()-72||GetMouseY()<ScreenHeight()-36)&&
(GetMouseX()<ScreenWidth()-32||GetMouseY()>ScreenHeight()+12)&&
!nameBox->m_bTextEdit&&
tileset.columns>0&&
view.ScreenToWorld(GetMousePos()).x<tileset.columns*tileset.tilewidth&&
view.ScreenToWorld(GetMousePos()).y<tileset.tilecount/tileset.columns*tileset.tileheight&&
view.ScreenToWorld(GetMousePos()).x>=0&&view.ScreenToWorld(GetMousePos()).y>=0){
if(selectedObj.length()==0){
if(GetMouse(Mouse::LEFT).bPressed){
vf2d worldCoords=view.ScreenToWorld(GetMousePos());
@ -358,13 +464,77 @@ public:
NewObjectUpdate();
}
}
}
void SelectingFileUpdate(){
selectionGui.Update(this);
if(tilesetList.size()>0&&!loadedFirstFile){
loadedFirstFile=true;
tilesetsList->nSelectedItem=0;
goto loadFile;
}
if(tilesetsList->bSelectionChanged){
loadFile:
const std::string tilesetFilename{tilesetList[tilesetsList->nSelectedItem]};
parsedMap={tilesetFilename};
mapImage.Load(TILESET_DIR+parsedMap.GetData().filename);
currentTileset=parsedMap.GetData();
activeTileset=tilesetFilename;
undoList.clear();
redoList.clear();
previousObjState=currentTileset.objects;
ResetState();
}
if(GetKey(ESCAPE).bReleased){
selectingFile=false;
openButton->Reset();
gui.Update(this);
}
if(closeButton->bReleased){
closeButton->Reset();
selectingFile=false;
openButton->Reset();
gui.Update(this);
}
GradientFillRectDecal({0.f,0.f},GetScreenSize()/2.f,BLACK,BLACK,{0,0,0,0},BLACK);
GradientFillRectDecal({0.f,ScreenHeight()/2.f},GetScreenSize()/2.f,BLACK,BLACK,BLACK,{0,0,0,0});
GradientFillRectDecal(GetScreenSize()/2.f,GetScreenSize()/2.f,{0,0,0,0},BLACK,BLACK,BLACK);
GradientFillRectDecal({ScreenWidth()/2.f,0.f},GetScreenSize()/2.f,BLACK,{0,0,0,0},BLACK,BLACK);
selectionGui.DrawDecal(this);
}
void RenderTileset(){
const Tileset&tileset=currentTileset;
if(mapImage.Decal()!=nullptr){
view.DrawDecal({0,0},mapImage.Decal());
}
if(tileset.columns>0){
if(selectedObj.length()>0){
for(int y=0;y<tileset.tilecount/tileset.columns;y++){
for(int x=0;x<tileset.columns;x++){
if(!geom2d::contains(tileset.objects.at(selectedObj).bounds,vf2d{float(x*tileset.tilewidth)+tileset.tilewidth/2,float(y*tileset.tileheight)+tileset.tileheight/2})){
view.FillRectDecal(vf2d{float(x),float(y)}*tileset.tilewidth,vf2d{float(tileset.tilewidth),float(tileset.tileheight)},{0,0,0,128});
}
}
}
}
for(int y=0;y<tileset.tilecount/tileset.columns;y++){
for(int x=0;x<tileset.columns;x++){
view.DrawRectDecal(vf2d{float(x),float(y)}*tileset.tilewidth,vf2d{float(tileset.tilewidth),float(tileset.tileheight)},GREY);
}
}
}
//Font test.
/*DrawStringDecal({0,0},"the quick brown fox jumps over the lazy dog 1234567890 !@#$%^&*()-=_+[]{}\\;':\",./<>?~`",WHITE,{1.5f,1.5f});
DrawStringDecal({0,18},"THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG 1234567890 !@#$%^&*()-=_+[]{}\\;':\",./<>?~`",WHITE,{1.5f,1.5f});
DrawStringPropDecal({0,36},"the quick brown fox jumps over the lazy dog 1234567890 !@#$%^&*()-=_+[]{}\\;':\",./<>?~`",WHITE,{1.5f,1.5f});
DrawStringPropDecal({0,54},"THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG 1234567890 !@#$%^&*()-=_+[]{}\\;':\",./<>?~`",WHITE,{1.5f,1.5f});
*/
if(selectedObj.length()>0&&!dragNewObj){
const TilesetObject&obj=tileset.objects.at(selectedObj);
@ -405,14 +575,14 @@ public:
for(bool highlighted=false;const vf2d&point:quad){
if(highlightedQuad==&quad){
if(geom2d::line<float>(point,view.ScreenToWorld(GetMousePos())).length()<4&&!highlighted){
view.DrawRotatedDecal(point,circle.Decal(),0.f,circle.Sprite()->Size()/2,{1.f,1.f},YELLOW);
if(geom2d::line<float>(point,view.ScreenToWorld(GetMousePos())).length()<4/view.GetWorldScale().x&&!highlighted){
view.DrawRotatedDecal(point,circle.Decal(),0.f,circle.Sprite()->Size()/2,vf2d{1.f,1.f}/view.GetWorldScale(),YELLOW);
highlighted=true;
}else{
view.DrawRotatedDecal(point,circle.Decal(),0.f,circle.Sprite()->Size()/2,{1.f,1.f},RED);
view.DrawRotatedDecal(point,circle.Decal(),0.f,circle.Sprite()->Size()/2,vf2d{1.f,1.f}/view.GetWorldScale(),RED);
}
}else{
view.DrawRotatedDecal(point,circle.Decal(),0.f,circle.Sprite()->Size()/2,{0.25f,0.25f},DARK_GREY);
view.DrawRotatedDecal(point,circle.Decal(),0.f,circle.Sprite()->Size()/2,vf2d{0.25f,0.25f}/view.GetWorldScale(),DARK_GREY);
}
}
}
@ -457,21 +627,46 @@ public:
view.DrawLineDecal(obj.bounds.pos+obj.bounds.size,obj.bounds.pos+obj.bounds.size+vf2d{0.f,-float(obj.bounds.size.y)},YELLOW);
view.DrawLineDecal(obj.bounds.pos+obj.bounds.size,obj.bounds.pos+obj.bounds.size+vf2d{-float(obj.bounds.size.x),0.f},YELLOW);
vi2d nameTextSize=GetTextSizeProp(objName)*0.25f;
view.GradientFillRectDecal(obj.bounds.pos,nameTextSize+vf2d{2,2},RED,{255,0,0,64},{255,0,0,64},RED);
view.DrawStringPropDecal(obj.bounds.pos+vf2d{1.25f,1.25f},objName,BLACK,vf2d{0.25f,0.25f});
view.DrawStringPropDecal(obj.bounds.pos+vf2d{1,1},objName,WHITE,vf2d{0.25f,0.25f});
if(geom2d::contains(obj.bounds,view.ScreenToWorld(GetMousePos()))){
selectedObj=objName;
vi2d nameTextSize=GetTextSizeProp(obj.name)*0.25f;
if(!geom2d::overlaps(geom2d::rect<float>{obj.bounds.pos,nameTextSize+vf2d{2,2}},view.ScreenToWorld(GetMousePos()))){
view.GradientFillRectDecal(obj.bounds.pos,nameTextSize+vf2d{2,2},RED,{255,0,0,64},{255,0,0,64},RED);
view.DrawStringPropDecal(obj.bounds.pos+vf2d{1.25f,1.25f},obj.name,BLACK,vf2d{0.25f,0.25f});
view.DrawStringPropDecal(obj.bounds.pos+vf2d{1,1},obj.name,WHITE,vf2d{0.25f,0.25f});
}
}
gui.Update(this);
gui.DrawDecal(this);
if(!nameBox->m_bTextEdit){
createNewButton->Enable(true);
editButton->Enable(true);
FillRectDecal(nameBox->vPos,nameBox->vSize,{0,0,0,150});
if(selectedObj.length()>0){
DrawStringPropDecal(nameBox->vPos+vf2d{2.f,0.f},"R to Edit",WHITE,{0.6f,0.6f});
}
}else{
createNewButton->Enable(false);
editButton->Enable(false);
}
DrawStringDecal(createNewButton->vPos+vf2d{3,0},"Q");
DrawStringDecal(editButton->vPos+vf2d{3,0},"E");
}
bool OnUserUpdate(float fElapsedTime) override
{
Clear(VERY_DARK_BLUE);
const bool editingFile=!selectingFile;
if(IsFocused()&&editingFile){
EditorUpdate();
}
RenderTileset();
if(IsFocused()&&selectingFile){
SelectingFileUpdate();
}
return true;
}
@ -480,7 +675,7 @@ public:
int main()
{
TiledCollisionEditor demo;
if (demo.Construct(640, 180, 4, 4))
if (demo.Construct(640, 180, 4, 4, false, true))
demo.Start();
return 0;

@ -91,6 +91,8 @@ namespace olc::QuickGUI
public:
// Switches the control on/off
void Enable(const bool bEnable);
//Resets the state of a control such as when transitioning from a screen to another screen, we want to reset the state to normal.
void Reset();
// Sets whether or not the control is interactive/displayed
bool bVisible = true;
@ -447,6 +449,15 @@ namespace olc::QuickGUI
{
m_state = bEnable ? State::Normal : State::Disabled;
}
void BaseControl::Reset(){
m_state = State::Normal;
bPressed = false;
bHeld = false;
bReleased = false;
bHovered = false;
}
#pragma endregion
#pragma region Manager
@ -706,31 +717,31 @@ namespace olc::QuickGUI
void Button::Update(olc::PixelGameEngine* pge)
{
bPressed = false;
bReleased = false;
if (m_state == State::Disabled || !bVisible)
return;
bPressed = false;
bReleased = false;
float fElapsedTime = pge->GetElapsedTime();
olc::vf2d vMouse = pge->GetMousePos();
if (m_state != State::Click)
{
if (vMouse.x >= vPos.x && vMouse.x < vPos.x + vSize.x &&
if ((vMouse.x >= vPos.x && vMouse.x < vPos.x + vSize.x &&
vMouse.y >= vPos.y && vMouse.y < vPos.y + vSize.y
||pge->GetKey(hotkey).bPressed||pge->GetKey(hotkey).bHeld||pge->GetKey(hotkey).bReleased)
||(hotkey!=olc::Key::NONE&&(pge->GetKey(hotkey).bPressed||pge->GetKey(hotkey).bHeld))))
{
m_fTransition += fElapsedTime * m_manager.fHoverSpeedOn;
m_state = State::Hover;
bHovered = true;
bPressed = pge->GetMouse(olc::Mouse::LEFT).bPressed||pge->GetKey(hotkey).bPressed;
bPressed = pge->GetMouse(olc::Mouse::LEFT).bPressed||(hotkey!=olc::Key::NONE&&pge->GetKey(hotkey).bPressed);
if (bPressed)
{
m_state = State::Click;
}
bHeld = pge->GetMouse(olc::Mouse::LEFT).bHeld||pge->GetKey(hotkey).bHeld;
bHeld = pge->GetMouse(olc::Mouse::LEFT).bHeld||(hotkey!=olc::Key::NONE&&pge->GetKey(hotkey).bHeld);
}
else
{
@ -741,8 +752,8 @@ namespace olc::QuickGUI
}
else
{
bHeld = pge->GetMouse(olc::Mouse::LEFT).bHeld||pge->GetKey(hotkey).bHeld;
bReleased = pge->GetMouse(olc::Mouse::LEFT).bReleased||pge->GetKey(hotkey).bReleased;
bHeld = pge->GetMouse(olc::Mouse::LEFT).bHeld||(hotkey!=olc::Key::NONE&&pge->GetKey(hotkey).bHeld);
bReleased = pge->GetMouse(olc::Mouse::LEFT).bReleased||(hotkey!=olc::Key::NONE&&pge->GetKey(hotkey).bReleased);
if (bReleased) m_state = State::Normal;
}
@ -861,7 +872,7 @@ namespace olc::QuickGUI
return;
ImageButton::Update(pge);
if (bPressed) bChecked = !bChecked;
if (bPressed) bChecked = true;
}
void ImageCheckBox::Draw(olc::PixelGameEngine* pge)
@ -1031,7 +1042,7 @@ namespace olc::QuickGUI
if(fMax<fMin)std::swap(fMax,fMin);
fValue = std::clamp(fValue, fMin, fMax);
fValue = std::clamp(fValue, std::max(0.f,fMin), std::max(0.f,fMax));
m_fTransition = std::clamp(m_fTransition, 0.0f, 1.0f);
}
@ -1163,7 +1174,7 @@ namespace olc::QuickGUI
{
if (idx == nSelectedItem)
pge->FillRect(vTextPos - olc::vi2d(1,-1), {int32_t(vSize.x - m_group.fGrabRad * 2), int(fontSize)}, m_group.colHover);
pge->DrawStringProp(vTextPos + olc::vi2d(0,2), m_vList[idx],olc::WHITE,fontSize/10);
pge->DrawStringProp(vTextPos, m_vList[idx],olc::WHITE,fontSize/10);
vTextPos.y += fontSize;
}
@ -1176,7 +1187,7 @@ namespace olc::QuickGUI
return;
if (bHasBackground)
pge->FillRectDecal(vPos + olc::vf2d(1, 1), vSize - olc::vf2d(2, 2), m_manager.colNormal);
pge->FillRectDecal(vPos + olc::vf2d(1, -1), vSize - olc::vf2d(2, 2), m_manager.colNormal);
size_t idx0 = size_t(m_pSlider->fValue);
size_t idx1 = std::min(idx0 + size_t((vSize.y - 4) / fontSize), m_vList.size());
@ -1185,13 +1196,13 @@ namespace olc::QuickGUI
for (size_t idx = idx0; idx < idx1; idx++)
{
if (idx == nSelectedItem)
pge->FillRectDecal(vTextPos - olc::vi2d(1, -1), { vSize.x - m_group.fGrabRad * 2.0f, fontSize }, m_group.colHover);
pge->FillRectDecal(vTextPos - olc::vi2d(1, 1), { vSize.x - m_group.fGrabRad * 2.0f, fontSize }, m_group.colHover);
float width = pge->GetTextSizeProp(m_vList[idx]).x*fontSize/10;
if (width>vSize.x-m_manager.fGrabRad*2){
float scaleX = (vSize.x-m_manager.fGrabRad*2)/width;
pge->DrawStringPropDecal(vTextPos + olc::vi2d(0,2), m_vList[idx], olc::WHITE, olc::vf2d{scaleX,1}*fontSize/10);
pge->DrawStringPropDecal(vTextPos + olc::vi2d(0,-5), m_vList[idx], olc::WHITE, olc::vf2d{scaleX,1}*fontSize/10);
} else {
pge->DrawStringPropDecal(vTextPos + olc::vi2d(0,2), m_vList[idx], olc::WHITE, olc::vf2d{1,1}*fontSize/10);
pge->DrawStringPropDecal(vTextPos + olc::vi2d(0,-5), m_vList[idx], olc::WHITE, olc::vf2d{1,1}*fontSize/10);
}
vTextPos.y += fontSize;
}
@ -1199,7 +1210,7 @@ namespace olc::QuickGUI
if (bHasBorder)
{
pge->SetDecalMode(olc::DecalMode::WIREFRAME);
pge->FillRectDecal(vPos + olc::vf2d(1, 1), vSize - olc::vf2d(2, 2), m_manager.colBorder);
pge->FillRectDecal(vPos + olc::vf2d(1, -1), vSize - olc::vf2d(2, 2), m_manager.colBorder);
pge->SetDecalMode(olc::DecalMode::NORMAL);
}

@ -1025,6 +1025,10 @@ namespace olc
uint32_t GetFPS() const;
// Gets last update of elapsed time
float GetElapsedTime() const;
// Returns whether the mouse cursor exists inside the window or outside of it.
const bool IsMouseInsideWindow() const;
// Gets Actual Window pos
const olc::vi2d& GetWindowPos() const;
// Gets Actual Window size
const olc::vi2d& GetWindowSize() const;
// Gets pixel scale
@ -1227,6 +1231,7 @@ namespace olc
olc::vi2d vMouseWindowPos = { 0, 0 };
int32_t nMouseWheelDeltaCache = 0;
olc::vi2d vWindowSize = { 0, 0 };
olc::vi2d vWindowPos = { 0, 0 };
olc::vi2d vViewPos = { 0, 0 };
olc::vi2d vViewSize = { 0,0 };
bool bFullScreen = false;
@ -1296,6 +1301,7 @@ namespace olc
// "Break In" Functions
void olc_UpdateMouse(int32_t x, int32_t y);
void olc_UpdateMouseWheel(int32_t delta);
void olc_UpdateWindowPos(int32_t x, int32_t y);
void olc_UpdateWindowSize(int32_t x, int32_t y);
void olc_UpdateViewport();
void olc_ConstructFontSheet();
@ -2131,6 +2137,12 @@ namespace olc
float PixelGameEngine::GetElapsedTime() const
{ return fLastElapsed; }
const bool PixelGameEngine::IsMouseInsideWindow() const
{ return GetMouseX()>=0&&GetMouseY()>=0&&GetMouseX()<GetScreenSize().x&&GetMouseY()<GetScreenSize().y; }
const olc::vi2d& PixelGameEngine::GetWindowPos() const
{ return vWindowPos; }
const olc::vi2d& PixelGameEngine::GetWindowSize() const
{ return vWindowSize; }
@ -3724,7 +3736,7 @@ namespace olc
}
}
if (GetKey(olc::Key::ENTER).bPressed)
if (GetKey(olc::Key::ENTER).bPressed||GetKey(olc::Key::ESCAPE).bPressed)
{
if (bConsoleShow)
{
@ -3793,6 +3805,10 @@ namespace olc
vWindowSize = { x, y };
olc_UpdateViewport();
}
void PixelGameEngine::olc_UpdateWindowPos(int32_t x, int32_t y)
{
vWindowPos = { x, y };
}
void PixelGameEngine::olc_UpdateMouseWheel(int32_t delta)
{ nMouseWheelDeltaCache += delta; }
@ -3808,10 +3824,6 @@ namespace olc
y -= vViewPos.y;
vMousePosCache.x = (int32_t)(((float)x / (float)(vWindowSize.x - (vViewPos.x * 2)) * (float)vScreenSize.x));
vMousePosCache.y = (int32_t)(((float)y / (float)(vWindowSize.y - (vViewPos.y * 2)) * (float)vScreenSize.y));
if (vMousePosCache.x >= (int32_t)vScreenSize.x) vMousePosCache.x = vScreenSize.x - 1;
if (vMousePosCache.y >= (int32_t)vScreenSize.y) vMousePosCache.y = vScreenSize.y - 1;
if (vMousePosCache.x < 0) vMousePosCache.x = 0;
if (vMousePosCache.y < 0) vMousePosCache.y = 0;
}
void PixelGameEngine::olc_UpdateMouseState(int32_t button, bool state)
@ -5513,6 +5525,8 @@ namespace olc
olc_hWnd = CreateWindowEx(dwExStyle, olcT("OLC_PIXEL_GAME_ENGINE"), olcT(""), dwStyle,
vTopLeft.x, vTopLeft.y, width, height, NULL, NULL, GetModuleHandle(nullptr), this);
MoveWindow(olc_hWnd,vTopLeft.x,vTopLeft.y,width,height,false); //A hack to get the window's position updated in the correct spot (WM_MOVE reports the correct upper-left corner of the client area)
DragAcceptFiles(olc_hWnd, true);
// Create Keyboard Mapping
@ -5582,7 +5596,18 @@ namespace olc
return olc::OK;
}
virtual olc::rcode HandleSystemEvent() override { return olc::rcode::FAIL; }
virtual olc::rcode HandleSystemEvent() override {
struct tagPOINT p{0,0};
//Update mouse positions and states outside the window.
GetCursorPos(&p);
ptrPGE->olc_UpdateMouse(p.x-ptrPGE->GetWindowPos().x,p.y-ptrPGE->GetWindowPos().y);
ptrPGE->olc_UpdateMouseState(0,GetAsyncKeyState(VK_LBUTTON)>>7);
ptrPGE->olc_UpdateMouseState(1,GetAsyncKeyState(VK_RBUTTON)>>7);
ptrPGE->olc_UpdateMouseState(2,GetAsyncKeyState(VK_MBUTTON)>>7);
ptrPGE->olc_UpdateMouseState(3,GetAsyncKeyState(VK_XBUTTON1)>>7);
ptrPGE->olc_UpdateMouseState(4,GetAsyncKeyState(VK_XBUTTON2)>>7);
return olc::rcode::OK;
}
// Windows Event Handler - this is statically connected to the windows event system
static LRESULT CALLBACK olc_WindowEvent(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
@ -5597,6 +5622,13 @@ namespace olc
ptrPGE->olc_UpdateMouse(ix, iy);
return 0;
}
case WM_MOVE:
{
uint16_t x = lParam & 0xFFFF; uint16_t y = (lParam >> 16) & 0xFFFF;
int16_t ix = *(int16_t*)&x; int16_t iy = *(int16_t*)&y;
ptrPGE->olc_UpdateWindowPos(ix, iy);
return 0;
}
case WM_SIZE: ptrPGE->olc_UpdateWindowSize(lParam & 0xFFFF, (lParam >> 16) & 0xFFFF); return 0;
case WM_MOUSEWHEEL: ptrPGE->olc_UpdateMouseWheel(GET_WHEEL_DELTA_WPARAM(wParam)); return 0;
case WM_MOUSELEAVE: ptrPGE->olc_UpdateMouseFocus(false); return 0;
@ -5842,11 +5874,13 @@ namespace olc
{
XWindowAttributes gwa;
XGetWindowAttributes(olc_Display, olc_Window, &gwa);
ptrPGE->olc_UpdateWindowPos(gwa.x, gwa.y);
ptrPGE->olc_UpdateWindowSize(gwa.width, gwa.height);
}
else if (xev.type == ConfigureNotify)
{
XConfigureEvent xce = xev.xconfigure;
ptrPGE->olc_UpdateWindowPos(gwa.x, gwa.y);
ptrPGE->olc_UpdateWindowSize(xce.width, xce.height);
}
else if (xev.type == KeyPress)
@ -6325,19 +6359,19 @@ namespace olc
mapKeys[DOM_PK_QUOTE] = Key::OEM_7; mapKeys[DOM_PK_BACKSLASH] = Key::OEM_8;
// Keyboard Callbacks
emscripten_set_keydown_callback("#canvas", 0, 1, keyboard_callback);
emscripten_set_keyup_callback("#canvas", 0, 1, keyboard_callback);
emscripten_set_keydown_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, 0, 1, keyboard_callback);
emscripten_set_keyup_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, 0, 1, keyboard_callback);
// Mouse Callbacks
emscripten_set_wheel_callback("#canvas", 0, 1, wheel_callback);
emscripten_set_mousedown_callback("#canvas", 0, 1, mouse_callback);
emscripten_set_mouseup_callback("#canvas", 0, 1, mouse_callback);
emscripten_set_mousemove_callback("#canvas", 0, 1, mouse_callback);
emscripten_set_mousedown_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, 0, 1, mouse_callback);
emscripten_set_mouseup_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, 0, 1, mouse_callback);
emscripten_set_mousemove_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, 0, 1, mouse_callback);
// Touch Callbacks
emscripten_set_touchstart_callback("#canvas", 0, 1, touch_callback);
emscripten_set_touchmove_callback("#canvas", 0, 1, touch_callback);
emscripten_set_touchend_callback("#canvas", 0, 1, touch_callback);
emscripten_set_touchstart_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, 0, 1, touch_callback);
emscripten_set_touchmove_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, 0, 1, touch_callback);
emscripten_set_touchend_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, 0, 1, touch_callback);
// Canvas Focus Callbacks
emscripten_set_blur_callback("#canvas", 0, 1, focus_callback);
@ -6373,6 +6407,8 @@ namespace olc
// is using one of the default or minimal emscripten page layouts
Module.olc_AssumeDefaultShells = (document.querySelectorAll('.emscripten').length >= 3) ? true : false;
oncontextmenu=function(e){return false}; //Because we can click outside the window, we want to disable normal right-click context menu for the application.
// olc_ResizeHandler
//
// Used by olc_Init, and is called when a resize observer and fullscreenchange event is triggered.
@ -6511,7 +6547,7 @@ namespace olc
// Move
if (eventType == EMSCRIPTEN_EVENT_TOUCHMOVE)
{
ptrPGE->olc_UpdateMouse(e->touches->targetX, e->touches->targetY);
ptrPGE->olc_UpdateMouse(e->touches->targetX-ptrPGE->GetWindowPos().x-EM_ASM_INT({return window.scrollX}), e->touches->targetY-ptrPGE->GetWindowPos().y-EM_ASM_INT({return window.scrollY}));
}
// Start
@ -6535,7 +6571,7 @@ namespace olc
{
//Mouse Movement
if (eventType == EMSCRIPTEN_EVENT_MOUSEMOVE)
ptrPGE->olc_UpdateMouse(e->targetX, e->targetY);
ptrPGE->olc_UpdateMouse(e->targetX-ptrPGE->GetWindowPos().x-EM_ASM_INT({return window.scrollX}), e->targetY-ptrPGE->GetWindowPos().y-EM_ASM_INT({return window.scrollY}));
//Mouse button press
@ -6578,7 +6614,10 @@ namespace olc
{ return olc::OK; }
virtual olc::rcode HandleSystemEvent() override
{ return olc::OK; }
{
ptrPGE->olc_UpdateWindowPos(EM_ASM_INT({return Module.canvas.getBoundingClientRect().left}),EM_ASM_INT({return Module.canvas.getBoundingClientRect().top}));
return olc::OK;
}
static void MainLoop()
{

Binary file not shown.

After

Width:  |  Height:  |  Size: 704 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 708 B

Loading…
Cancel
Save