I'm back! Spent some time with family and taking a rest from all that study stuff. But now I'm back, though I don't have much time to work on the game, so I'll work on some things that I really need to implement which may not be really that interesting.
*
Multiple tile maps on the same level. Useful for creating indoor maps which won't require any loading. Much easier to use and implement than having them on the same tile map just far-far away.
*
Better collision detection. First of all, I need to use some space partitioning and I'll probably go with the simplest approach: uniform grid. I'll implement quad tree if there's a need for it (probably won't need it, as there's probably won't be lots of entities on the screen at the same time).
I also want to implement diagonal tiles but I don't have any idea how to do them at the moment, so any suggestions are welcome!
*
Making entity descriptions pure data. I've talked a bit previously about this, but now it's clearer to me why moving functions out of entity descriptions is awesome.
1) I can easily reuse them. Most functions inside entity description scripts are collision responses and different triggers. Some collision responses may be the same, for example, entities saying "watch where you're going". Copying even one line of the same behavior can be dangerous and lead to some hard to fix bugs (DRY!)
2) Serialization. I want to make entity descriptions serializable so I can edit them inside some Entity Editor (kinda like Animation Editor). I can't save Lua functions, I can only save data.
So, what is the alternative to storing collision response in script and having
CollisionSystem call that function on collision? Easy, I use events.
CollisionSystem sends
OnCollisionEvent and then state machine of the entity catches it and the current state reacts to that event.
This is cooler than I thought at first. Imagine if I want to implement some guy which can carry some precious item and drop it on collision with another entity if it was moving faster than SOME_BIG_SPEED. If he doesn't carry anything, he just swears.
Here's how old approach looks:
some_guy = {
...
CollisionComponent = {
onCollision = function(this, second)
local currentState = stateManager.getCurrentState(this)
if currentState == State.IdleState then
this:swear()
elseif currentState == States.CarryingItemState then
if Vector2f.normalize(second:getVelocity()) > SOME_BIG_SPEED then
this:dropItem()
end
end
end
}
}
This is bad, because if/else branches may become pretty big this way. Here's how it will look with my state machine system:
local SomeGuyStates = {
IdleState = {
[EventType.CollisionEvent] = {
callback = function(this, event)
this:swear()
end
}
},
CarryingItemState = {
[EventType.CollisionEvent] = {
callback = function(this, event)
if Vector2f.normalize(second:getVelocity()) > SOME_BIG_SPEED then
this:dropItem()
end
end
}
}
}
Okay, that may not look as straightforward as the first approach, but it's much more scalable and let's me easily add intended behavior which varies depending entity's current state.
*
Input. I've made some progress in this area. Now I have InputManager in Lua which has stuff like this (some things are simplified:
local playerCallbacks = {
UseItem = {
type = InputType.Player,
callback = function()
local player = getPlayer()
player:usePrimaryItem()
end
},
...
}
function InputManager:initialize()
self.onPressCallbacks = {}
self.oneReleaseCallbacks = {}
...
end
And then I set input like this.
inputManager.setPressedCallback(Button.PrimaryAction, playerCallbacks.UsePrimaryItem)
*
Reloading changes in scripts. Previously I could reload entities by changing their scripts and then typing "reload <ENTITY_NAME>" in in-game console. But this wasn't very efficient, because most changes are local to one component. So now I want to implement something like "reload <ENTITY_NAME>.<COMPONENT_NAME>" (e.g. "reload hero.CollisionComponent")
I can even take it further sometime and make some systems watch over currently used script files and reload them automatically if they detect any changes. Determining the change will be the hardest thing and I just plan to compare component tables inside entity description scripts. If some things changed, reloading system will just re-make the component in each entity of this type and give them copies of new one. Trying to detect changes INSIDE the component is much harder and I won't spend time on that. Though it would be pretty awesome to be able to change one thing inside the script, hit CTRL+S and have it changed in C++ without creating any new objects.
But that's pretty hard to make! Having "reload <ENTITY_NAME>.<COMPONENT_NAME>" will probably be enough for me for now.
*
Unbreaking stuff. There are some things that I break with system changes and then don't have time to fix them. For example: some actions lists and complete levels are broken and need to be rewritten. That's what I'm going to do in the next weeks.
*
Some refactoring and improving code. One thing that I dislike about my code base is that I use raw pointers quite a lot in some places. For example,
Entity::get<ComponentType> returns a raw pointer to component. This is not bad, because the component can not be present and then I'll just return
nullptr, but I hardly check for that anywhere, so references are the way to go. If I'm really want to know if the component is present, I can call
Entity::has<ComponentType> anyway.
There are some small changes that I have to make and I'll write them there if I find them good enough.
*
Lua. In recent days I've ported all my Lua/C++ code to sol2 and now LuaBridge is not used anywhere. This feels really good. I also really want to keep Lua/C++ stuff in one place, it's pretty hard to do now (it keeps getting better with events and moving some C++ stuff to action lists though). I wish there was some good example on how to keep Lua/C++ stuff in one place, but I haven't seen this anywhere, so I'll see what works for me.
*
Combat. Okay, that one is the coolest. I'll just work on combat, draw some battle animation and see what works and what doesn't. The combat won't be complex, but I want it to be cooler than ALttP. The player won't have a shield in his undead body, so he'll only be able to dodge attacks. Let's see how it works, there aren't many top down action adventure games which use this system.