Twinklebear / LPCGame

Working on a C++ tile based 'engine' using SDL
MIT License
18 stars 1 forks source link

Creating the Editor #14

Open Twinklebear opened 11 years ago

Twinklebear commented 11 years ago

Tile Maps

btstevens89 commented 11 years ago

I'm going try to tackle this next. Starting with beefing up the map editor.

Things I hope to add.

First Additons
  1. New button / Select # tiles.
  2. Save/Save As buttons.
  3. Open button.
  4. Clear button.
  5. Map Info (saved location, rows vs columns).
Additional Additions to Add
  1. Warp zones (to travel between maps).
  2. TileBar (with additions).

Not sure how to implement warp zones yet.

Question: How do I implement buttons that don't load another state, but rather call C++ code.

I've written two functions that run the default Windows OpenFileDialog and SaveFileDialog, I just need to find out how to bind them with buttons. I'd hope it'd just be through c++ but maybe lua?

Twinklebear commented 11 years ago

Unfortunately, the buttons are still very much a WIP, at the moment all the C++ ones can call is to setexit on the current scene and change to the next with the scene param set to whatever is described in json.

The Lua one can do the same thing but from Lua, and can do any other Lua operations currently supported.

Buttons and their interactions is actually where I'm actively working, so at the moment it's really got nothing. I was thinking in the future of having some sort of dispatch system for button function calls, where they can try to call some function and send some parameters, either a C++ function or Lua function, or get a function to cache for later through the lookup system (should be doable if the lookup system is lua_cfunctions(?))

I guess the only way to do the buttons for now would be to hardcode the call, or maybe detect the call to do based on some param. Ie. param = OpenFileDialog then instead of calling the default registered function, call the one you want. Once buttons and the function dispatcher are in place this will then be pushed entirely into Lua.

As far as warp zones, what you could do is have a non-rendered entity (this flag isn't implemented, ie. render toggle for entities), although you could just give it no image file. That when interacted with (OnClick/OnMouseDown/etc are the only options for now) will call the StateManager to change state to whatever it should warp to. You could take a look at the Lua button i've made and just change it to some entity to click.

What I would like to add are callback functions for OnCollision events (don't exist yet) which will call an OnCollision function on both colliding entities, passing the tag/name of what they collided with. So then you'd have the warpzone waiting for OnCollision where the name is player, and then trigger a state change.

I'm not sure how much you've been keeping up with the Lua Embedding issue , but there you'll find an explanation as to why buttons can't do this yet and what I plan to make them do in the future and can see the progress in making this stuff possible. The code for that work is found in Experiments/LuaCrossStateCallTest

Twinklebear commented 11 years ago

It may take me a bit to get this working in a form where it's ready to merge into the engine, as there's some wierdness occurring with luabind vs. lua C API where userdata that's usable and defined via luabind can't be recast back to a usable version in the lua C API.

I'd suggest going with some ugly hardcoding of the function pointers for now, and when I've got the C++/Lua function dispatch and buttons put together I'll let you know and we can get it put together.

Sounds pretty awesome though! Is it through the win32 api? Or is SDL able to do some cross platform stuff?

A nice thing for the editor would be the ability to place tiles anywhere starting from an empty map. Although it may be a bit tricky. Easier method is definitely to select # tiles for x y

btstevens89 commented 11 years ago

Several things...

I want to move everything out of the json files and into predefined code. TileBar and all of the editor's buttons should be hardcoded. What do you think?

As for warpzones. I'm going to add something that can define warpzone areas on the map. We can implement something for doing the actual changes later.

Twinklebear commented 11 years ago

Yep I'd agree with hardcoding the editor, we're the only ones who will need to be tweaking it ever, and it should be something that's not easy for a user to break on accident by fiddling with some json.

For anything game related i was planning to leave it up to the user to define entity/map/scene interactions, but since the Lua API and the Lua -> C++ and Lua -> Lua function dispatching isn't made, the warparea sounds fine for a temporary method.

It may be really hard to allow random placement of tiles of a map, having a pre-defined blank map would be fine, perhaps of a grid style blank editor tile. Then once the map is finished and saved simply ignore the editor's filler tiles to prune the map down to only what was made. Actually this may be really hard since a non-rectangular map will mess up the tile index calculations, it'd probably need to be re-written to some different method entirely. Pre-defined rectangles is fine, or requesting a rectangle size to generate.

As far as Lua goes, my goal is to hide as much of the lua specific functions as possible from the rest of the C++ code as I'm doing in the test project, so there won't be any changes on the C++ side of things and when/if you write some Lua code to work with entities, Lua itself is really easy to pick up, and the API will call/act almost identical to the C++ code it's wrapping, so it should be easy to use/familiar. You probably won't have to deal with Lua's C API but if you do end up needing to work with it, it's not too bad.

btstevens89 commented 11 years ago

Currently Map is drawn with Math::FromSceneSpace and Math::Centering. Is there an easy way to bypass this and specify exactly where I want the map to be drawn from? That would make it a lot easier to work with maps.

Some things I've got working...

The only issue i'm having with this is that when keeping the scene box at 20x20 I can't scroll the map past 20x20. When I change the scene box, the map is drawn out of view. Any ideas on that? Should I just overload Map::Draw in MapEditor?

Twinklebear commented 11 years ago

If you wanted to bypass the map tile draw positioning, you would want to adjust the x,y for the Rectf pos in these lines:

Rectf pos = Math::FromSceneSpace(cam, mTiles.at(i).Box());
Window::DrawTexture(mTileSet->Texture(mTiles.at(i).Name()), pos, 
    &(Recti)mTileSet->Clip(mTiles.at(i).Name()));

so here you can set pos to anything you want to change the tile's draw x/y/w/h. When specifying x/y keep in mind that the draw x/y are used as the window-space coordinates to draw too. ie. 0,0 is the top left corner of the window.

As far as the issue goes, I'm not sure. There could be some weirdness going on in the camera or the drawing or somewhere. Perhaps the tiles aren't being marked as colliding with the camera beyond some point? Then their index wouldn't show up in the list of tile indices to be drawn. A wild guess haha, I'm not really sure. You may want to see if the issue also occurs in the game state, the camera should be set to follow the player already, so you could generate a very big map and walk around on it and see what happens.

If it's exclusive to the map editor it may be best to just override the function, although it may be an issue in both classes.

btstevens89 commented 11 years ago

What is the difference between Box and SceneBox?

Twinklebear commented 11 years ago

So the scenBox is the size of the scene that's in the camera, so a 10x10 map is a 320x320 scene box. mBox is the size of the camera that we're looking through, so mBox should never be bigger than the sceneBox, but the sceneBox can be as big as it needs to be, and if it's bigger than the camera box, the camera will pan around the scene, following either a focus or pan instructions.

So centering is done to put mBox in the center of the window, and mBox x and y are clamped to be within the sceneBox and when setting either mBox or sceneBox a check is made to make sure mBox is <= the size of the sceneBox.

I probably should have a comment there haha, it is a bit confusing. Or maybe just clearer names.

btstevens89 commented 11 years ago

Then are scenebox.x and scenebox.y used for anything?

Twinklebear commented 11 years ago

Not in the camera at the moment, it's assumed that the sceneBox starts at 0, 0. You can see this in the clamp operations for the camera x & y, where the minimum x,y is set as 0, 0 instead of sceneBox.x, sceneBox.y.

I guess it would be possible to use the values if for some reason the scenebox was to be put at 10, 10 or something, but i don't think that makes much sense to do.

so short answer, no. They're assumed to be 0

btstevens89 commented 11 years ago

Sounds good.

Another question, was there a reason you reused the mBox.X() and Y() in this function. Was it intentional?

void Camera::SetBox(Rectf box){
    //The camera box can't be bigger than the scene box
    if (mSceneBox.w != 0 && mSceneBox.h != 0){
        mBox.Set(box.X(), box.Y(),                           //Was mBox.X(), mBox.Y()
            Math::Clamp(box.w, 0, mSceneBox.w),
            Math::Clamp(box.h, 0, mSceneBox.h));
    }
    //If no scene box is set yet, just allow the change, as we check again 
    //when setting a scene box
    else
        mBox = box;
}   
Twinklebear commented 11 years ago

Oh that looks like it was a mistake on my part, it doesn't make sense to set mBox to a new rect but keep the old position. That code is what it should be heh.

It may also make sense here to clamp the x & y to keep the camera from running outside of the scene, as is done in other areas of the code.

Edit: It looks like my intention may have been to make it resize the camera w & h, but that should be a different function than SetBox.

Twinklebear commented 11 years ago

As an aside for the editor ui elements (and any other ui elements you may have), you should take a look at the changes made in EntityManager vs. UIManager being closed when you're getting things ready to make a pull request (may not be a while, but a heads up on the changes)

Changing to the new method should be as simple as adding

"ui" : true,
"render" : true

to each of your ui elements and ui false to non-ui elements. The values are also switchable at runtime if you want to make some things disappear or move between ui and non-ui.