Jump to content

Rick

Members
  • Posts

    7,936
  • Joined

  • Last visited

Everything posted by Rick

  1. Close. You don't load cameras separately, just the models really. So let's say you have 10 different models in your game. In a loop just for clarity: LoadModel1 Update, Progress bar to 10% LoadModel2 Update Progress bar to 20% *repeat until you loaded all models Load Map (this will be fast now because you already loaded the models and when this goes to load those models it'll use the instances in memory vs going to disk). Note that you wouldn't manually set the % like this. You'd want to figure out how many models you need to load per map and calculate the % as you're looping over them all. Note this is a "hack" though. We shouldn't have to do something like this and hopefully Turbo handles this better.
  2. Yue, what gamecreator is saying is that the biggest time to load an entire map is loading all the models that are in the map. The LE map doesn't actually have the mdl files inside it. The map file just has information about what mdl files to load (mostly). In LE if a model is already loaded the next load call on it will just be creating another instance of the model (this means it doesn't have to go to disk to do this. it just looks at the already loaded model in memory and copies it.). Creating instances are fast. So if BEFORE you load your map you manually call load on all the mdl files you need then calling the map load will be faster. Since you're manually calling the mdl files to load you can loop over that process and make the progress bar, then at the end call your map load. Yes, there will be a slightly below still when you load the map but it'll be MUCH smaller and probably not noticeable by the user. So it sort of simulates map loading progress bar. This does have the side effect of needing to manually know which models to load for each map. Ideally one wouldn't load every model in the game if it's not used in a map. This is really why the map file should just be json so we can easily open and manipulate it ourselves. Even add fields to it.
  3. The loading bar idea should be noted for the new engine. Make the map format json or something so the information about what should be loaded can be loaded first then it's easy to see how many models there are and then the engine could expose a callback after each resource is loaded from the map and let a full iteration of the engine happen after each one so we can display our own progress bar.
  4. Rick

    Coroutine Sequences

    You are starting to get into the idea of behavior trees a little there (which you should totally implement as well into Turbo as they are amazing for AI). I did implement a general behavior tree with Lua. I found a lua implementation and converted it to work with LE. I implemented that into that dinosaur game me, Tim, and Shad did (which I can't find in the games section for some reason). https://github.com/tanema/behaviourtree.lua If you start reading up on behavior trees you see they have the idea of sequences. So the actual task or doing is the thing you originally were talking about with coroutines, but the structuring of all these tasks is what the behavior tree handles. A nice UI to manage the trees is handy as well. I think I used this https://github.com/behavior3/behavior3editor which exported to json and then the library I modified I created a function that loaded the json result of this editor into the behavior tree structure. It was pretty slick actually. Behavior trees have the idea of interrupts that you can put on any branch that would look for things that should take the AI off the current task and rerun the entire behavior tree again. When behavior trees are being ran through they run through your sequences in order so you always put the highest priority sequence first like getting shot at, or starving. Some sort of self preservation. When you're in a lower priority sequence the interrupt would say check your hunger level and if < 10 it would bail out of the current sequence and rerun the tree, which then the highest priority sequence would see you're hunger and then run it's sub sequences like find food, or cook food, whatever. You can play around with the editor online: https://www.behaviortrees.com/#/editor So if you hover over the Nodes header section on the right a New link comes up and that's where you'd make your new node actions like WalkToPoint or condition like IsHungry. It's actually really cool, very powerful, and fun to play with! You can even dynamically expand an actors "knowledge" by adding entire behavior trees as sub sequences! Imagine you creates a behavior tree that just has the sequence of "How to start a fire when cold". Then let's say you have 5 AI around your map. You start them with a basic behavior tree that has sequences like Find Food, Hunt, etc but you give 1 of them the "How to start a fire when cold" sequence. Then you code the game that when 2 actors bump into each other they share sequences in their behavior tree they have so you then give the other actor the "How to start a fire when cold" sequence and now you have AI teaching each other sequences they know. One might be able to expand this to make a more "real" AI that tries to randomly mix and match actions (you'd just have to code a bunch of actions that are available) to create their own sequences and if those sequences help their stats (hunger, thirst, etc) in any way they keep them and if they don't help they remove them! How cool would that be!
  5. Rick

    Coroutine Sequences

    Yes with coroutines. These things are amazingly powerful. So I'd say while this does work for some situations it's not as flexible. Sometimes you want to run multiple coroutine enabled functions at the same time and not continue until both are done. In a cut scene let's say you want to move from point A to B but also kick off some audio (the bad guy is talking as he's moving). He will reach his destination point before his speech is finished. The next step is to move again, but you want his speech and his first movement to be completed before you continue on. In my cut scene library I had my coroutine enabled methods return ID's of the coroutine itself, then made a method that would check if that coroutine was completed or not. So I could start both coroutine enabled functions and then do a loop checking if both were in a 'dead' state before continuing. local moveId = MoveToPoint(...) local speechId = StartAudio(...) -- don't recall lua syntax for looping atm while(IsCompleted(moveId) == false && IsCompleted(speechId) == false) loop -- continue with something else I would think at a minimum what you could do is make each script function a coroutine, or maybe let us somehow define that a script function should be coroutine enabled. This is what I did in my state manager library. In the scripts Update() I call my state manager Update() function. You change states by just calling stateMgr:ChanageState("StateName"). You added the script 'self' when creating the state manager because when you changed states it would look for functions of that state in that script by concatenating the state name to _Enter(), _Exit(), or _Update() and since you can search for functions by string name in Lua if the StateName_Enter() or StateName_Exit() function existed it would make a coroutine from them. The Update() was a normal function that looped while in that state, but I found myself using _Enter() more because coroutines rock. It might be nice to just have state type stuff built into these LE scripts honestly. States usually have an enter, exit, update. You don't need an update as you can get the same behavior by looping in enter and yielding out though. Exit is nice in case there are any cleanup stuff for that state. Wherever you are in that script you can change the state by calling some kind of ChangeState() function. Since you're dealing with coroutines you sort of need that because it tells the underlying system to stop calling that coroutine. If you're curious on how this works I have the library uploaded to the workshop. It's FSM (Finite State Machine). I think it's easy to use and gets the point across with states that have their enter/exit functions coroutine enabled.
  6. "The program will just silently close with no error message." Look at the definition of coroutine.resume() because it returns 2 values and 1 of them is if there is an error. I noticed the debugger doesn't show these so if there is an error I write it out to console so at least I can see the error.
  7. I think user events are very useful in this kind of subscribe/publish style because it allows for other scripts to know about whatever gameplay event you want without the script needing a reference to another script or entity. Cross script communication via events in my view is the best way to communicate. Allow the EmitEvent() to take a second parameter which is the value that will be passed to the subscribed functions. Since it's lua you only need 1 parameter and it can be a table that the person emitting the event fills out and if you are catching an event you have to just know the structure of said event parameter (a reasonable request). This would make using 3rd party scripts that emit events easier I think. Let's think about when we create enemy instances on the fly (not via the editor) and we need them to know about certain things the player is doing. How do we do that today? The enemy script either needs to get a hold of an instance of the player or the player get a hold of instances of the enemies so they can communicate. How they do that isn't very efficient or wise because it either means you're storing a global variable of the player so the enemies can get it (globals bad and error prone) or the player script is looping over every enemy to get a reference of them but enemies could be loading all the time so this doesn't work well. With the event system you can screw all that noise and just have the enemy script bind to a certain event that the player will emit. This way neither need a reference to each other to talk. So in summary user events gives us a way to have cross script communication without needing references of scripts/entities. I agree with this. Events work well for cross script communication and UI stuff, but gameplay stuff like picking objects work best with these inline procedural functions. Both are needed.
  8. The way you bind those events, in my opinion, is how the GUI events should work as well. self.btnExit:BindEvent(ON_CLICK, self, self.btnExit_OnClick) or self.btnExit.onClick:Bind(self, self.btnExit) Normally you have to pass the script itself as well so you can pass it as the first parameter tot he function so we can define it like function Script:btnExit_OnClick() end and use self inside of the function to refer to the script itself as 'self' is hidden 1st parameter to the function
  9. I will say good job at moving the core logic part out of PostRender
  10. My FSM is free. I would be willing to help yes. You for sure want to go with text vs images but yes that does mean you'll want some kind of generic code (library) to deal with all the issues that come with that (resolutions, line breaks etc). This can get sticky because it's all about font size and in LE you have to load fonts to get different sizes which is a pain. I have a UI library (it's sort of complicated now) where I have a label control where you size the rectangle where the text should fit and on load of the game it loops through a bunch of font sizes and loads them and tries to figure out what size fits best inside the rectangle and the rectangle itself is resolution independent (the size of it is relative to the screen resolution so it always looks the same on any resolution). You'll have the same issue with your images though because the size of them aren't resolution independent and you've had to account for that if you want that way too. I can release my UI library. It's pretty powerful as it handles all this stuff for you but that comes at a cost of complexity and I don't have any tutorials on it. I have some time tomorrow so I'll upload it then and make a youtube video on it.
  11. Just off the top of my head, having anything bug draw logic in PostRender() would be not ideal. Have your logic in UpdateWorld() and use PostRender() to just draw 2d images or text of the results. This means don't have window:KeyDown() in PostRender(). The second thing is using window:KeyDown(). The code is fairly messy to read but remember that KeyDown() will register true each frame if it's held down and it's hard for a person to press a key and have KeyDown() see it for only 1 frame. Try using KeyHit() instead maybe because that only registers the key press for 1 frame no matter if they hold it down. So that might help solve your issue of the question getting answered the same when they press a key. As far as structure goes, this is clearly, I think you know this, a mess of code which isn't very flexible and hard to debug. There is so much code duplication as well which will lead to hard to find bugs as soon as you start changing anything. You should probably go back to the drawing board with how to approach the requirements. Anytime you find yourself using just a **** load of boolean flags it's a good indication there is a better way. A bunch of boolean flags generally means you're trying to control state. So something to possibly look into is a state machine. The practical idea of state machines is that it allows you to change states and each state can be nicely isolated. In the case of a Lua library I made for LE this means each state has functions. Enter/Exit/Update(). When you change from 1 state to another the state you were in calls the Exit() function you defined for that state, then calls the Enter() function for the new state you changed to, then continuly calls Update() for the new state until you change state in which the same thing happens. Exit the old state, enter the new state, then Update() on the new state over and over again where you are looking for the user input or something to change to another state. To look into this go to the Workshop from the LE editor and search on state machine and you'll see my FSM. Download it. In the description I have links to videos explaining how it works. Something else to look at is the structure of your data. In this case it seems like you have questions that can lead to other questions and each question can have 3 answers. So think about how you could structure your data for that. This would be a table that holds question and answers and nested tables under as well to any level you want.
  12. If the headbob is at different speeds based on the speed of your app I'd say you aren't taking into account AppSpeed() in your calculation of it.
  13. I mostly work in Lua so I do a lot of System:Print() statements.
  14. I don't know exactly what it is about debug mode but don't ever run it and expect good results. It's really bad for that. In VS there should be a dropdown in the toolbar that says Debug and you can change it to Release I think.
  15. From the little text I see in your editor you're in debug mode? Debug mode is horrible.
  16. Do you think the indie person messing around (the main client base of LE) really cares this much about speed? I can get all the speed in the world but if I have to jump through all these hoops to get gameplay then it doesn't matter to me. I care more about less effort on my part to get something good up and running than I do speed. It doesn't matter how fast my game runs if I don't really even have a game because it takes so long to do certain things or the things aren't easy to use or flexible enough for my use case. The below isn't to slam your creations it's to show my opinion on the state of LE. Let's look at in game UI. The flexibility of the current UI comes at the cost of learning a proprietary library that really isn't easily flexible for all sorts of needs. Why? html/css is becoming the norm for game UI and for good reason. Everyone under the sun knows some html/css and it's the most discussed technology topic on the internet so if you don't know how to do something it's sure that you can easily find a stackoverflow post on how to do it. It's the ultimate in flexibility at pretty low cost. There are already tons of libraries out there (bootstrap) that help make it even easier and it's easier to get dynamic interesting UI vs gray buttons. You can defend your system all you want but in the world of game engines this UI is very low on that list. Why reinvent the UI wheel when html/css/javascript has done such a great job with it and has a massive history to draw from for knowledge. There is no question you like doing gfx programming. This is clearly your favorite part about a game engine and it shows in your blogs and posts. You can just see the excitement coming off those pages. You view this as the most important part and to a large extent it is, but you can't piece mail these other systems just to get a bullet point on a list of what the product can do and expect this to become any sort of massively successful product. Those other systems require just as much attention you give to the gfx programming side of things, but it seems like it's not your strongest skillset since you don't have as strong a passion for them. From my perspective understanding that and addressing that in some way will go a long way for LE.
  17. While more languages can attract more users it also adds overhead for the creators of the engine. It becomes just another thing to spend time on and Josh would have to determine if it's worth it. If it doesn't drive enough customers to makeup for the time spent on it is it really worth it? Someone who knows C# inside and out might already know C++ or willing to learn it since today they are getting more and more similar given C++'s advancements. So it might not scare those people away to not have C#.
  18. Anytime man. Feel free to ask anything anytime and I'll do my best to answer
  19. Remember this is being called on ALL the monsters. So hurtMonsterPosition is the monster that got hit, but when it fires for the other monsters self.entity is that other monster checking it's position against the one monster that got hit. A good thing you can do is set these values to a variable and System:Print() the value out so you can see what it is and if it's something that you aren't expecting.
  20. So when you're testing this stuff you can put a bunch of System:Print() commands in places to see if it goes into if statements and such. SO place a System:Print("A") inside the if data.hurtMonsterPosition blah blah to see if it goes inside that. If it does then you need to figure out how to set the player as this monsters target. I'm not 100% sure yet how to do it. I assumed it was just setting self.target but maybe not.
  21. OK figured it out. My loop in RaiseEvent() was wrong. Use this RaiseEvent() function and it works: function RaiseEvent(eventName, data) -- if someone tried to raise an event that doesn't have an entry in our events table do nothing if events[eventName] == null then return end -- loop through all the subscriptions for this event (there may be many game entities who want to know about this event) for k, v in pairs(events[eventName]) do System:Print("Raising event "..eventName) local scriptFunc = v.scriptFunction local script = v.scriptObject -- insert the functions into the eventCoroutines table. this will be iterated over in the main game loop below and resumed into table.insert(eventCoroutines, { co = coroutine.create(scriptFunc), args = data, script = script }) end end The difference is the table of callbacks within a function doesn't go from 1 to x like how I was iterating over it. This loop will loop over all sub tables of the event no matter what eventId is there. My bad.
  22. I just use the old animation lua script Josh had because I built this idea into it and working with callbacks in Lua is just easier. Still wish by default this LE PlayAnimation function gave us that capability, or he added a RegisterAnimationEvent() function to link the timing to a function.
  23. I still very much wish we could add any number of callbacks on the timing of the animation instead of just getting an end callback.
  24. I'll take a look at this tomorrow with the monster script you have.
×
×
  • Create New...