Jump to content

Rick

Members
  • Posts

    7,936
  • Joined

  • Last visited

Everything posted by Rick

  1. This is probably my not understanding your game. To get a better idea: 1. Is the overall dungeon the same for all 32 players? 2. Are you sort of building the dungeon in code at match startup from all these separate rooms? I believe you can generate the navmesh from code. So if each room is a prefab instead of it's own map, then load the prefab and gen the navmesh? I don't have a great understanding of how your game is working though. If you're thinking about the server and it's storing 32 different rooms I wonder what the performance would be if each room was it's own prefab and the navmesh was loaded on each new room for the rooms that exist in the 1 map. If you place the rooms apart from each other in the 3D space they won't ever touch but building the navmesh could still work. It would most likely take a few seconds though which would pause the server from processing anything else I think. Just talking it out
  2. I assume moving from room to room in the dungeon is a loading screen situation? Otherwise, why not just load the entire dungeon scene on the server and the client assuming the player can run to any other area in the dungeon and that you want those 32 players to share the same dungeon.
  3. Adding the value Math:DeltaAngle() returned did the trick thanks. For future reference and others who may wish to know: -- determine the model rotation based on direction we are going if move > 0 then if strafe > 0 then self.targetRot = self.targetRot + Math:DeltaAngle(self.targetRot, 225) elseif strafe < 0 then self.targetRot = self.targetRot + Math:DeltaAngle(self.targetRot, 135) else self.targetRot = self.targetRot + Math:DeltaAngle(self.targetRot, 180) end elseif move < 0 then if strafe > 0 then self.targetRot = self.targetRot + Math:DeltaAngle(self.targetRot, 315) elseif strafe < 0 then self.targetRot = self.targetRot + Math:DeltaAngle(self.targetRot, 45) else self.targetRot = self.targetRot + Math:DeltaAngle(self.targetRot, 0) end elseif strafe > 0 then self.targetRot = self.targetRot + Math:DeltaAngle(self.targetRot, 270) elseif strafe < 0 then self.targetRot = self.targetRot + Math:DeltaAngle(self.targetRot, 90) end self.rot = Math:Curve(self.targetRot, self.rot, self.damping) self.model:SetRotation(Vec3(0, self.rot, 0), true)
  4. Just testing something. Imagine you had a top down camera view and you moved the character controller with WASD. No rotation just forward/backward strafe left/right. However, the player avatar isn't the controller. It's separate but it's position is set to the controllers. However if you rotate the model to face the direction the controller is going then if the controller is strafing left the model rotates left, if going forward the model faces forward, etc (includes diagonals). So I have a check on the move and strafe variables that get passed to SetInput() that determines what the angle is to rotate the model. Values 0 - 315 increasing by 45 degrees. They are hardcoded though. If press 'S' then the angle is 0, if 'W' then the angle is 180, if 'A' then the angle is 90 and if 'D' then the angle is 270. If the current angle is > 180 and you press 'S' key to move it back to 0, it will take the long way around to get back to 0 (I use Math:Curve to smooth the current/target values). So the question is how can I get this rotation so it doesn't take the long way around. function Script:Start() self.window = Window:GetCurrent() self.model = Model:Load("Models/Knight/Knight Arthur Mecanim.mdl") self.model:SetScale(Vec3(0.01, 0.01, 0.01)) self.model:SetPosition(self.entity:GetPosition(true), true) self.damping = 5 self.rot = 0 self.targetRot = 0 self.pos = self.entity:GetPosition(true) end function Script:CalcShortestRot(current, target) local dist = target - current + 180 dist = dist - math.floor(dist / 2 / 180) * 2 * 180 - 180 if dist < 0 then return current - dist elseif dist > 0 then return current + dist else return target end end function Script:UpdateWorld() local move = ((window:KeyDown(Key.W) and 1 or 0) - (window:KeyDown(Key.S) and 1 or 0))*4 local strafe = ((window:KeyDown(Key.D)and 1 or 0) - (window:KeyDown(Key.A) and 1 or 0))*4 local jump = (window:KeyHit(Key.Space) and 1 or 0)*8 self.entity:SetInput(0,move,strafe,jump,false) -- position the model at the character controllers position local pos = self.entity:GetPosition(true) self.pos.x = Math:Curve(pos.x, self.pos.x, self.damping) self.pos.y = Math:Curve(pos.y, self.pos.y, self.damping) self.pos.z = Math:Curve(pos.z, self.pos.z, self.damping) self.model:SetPosition(self.pos) -- determine the model rotation based on direction we are going if move > 0 then if strafe > 0 then self.targetRot = self:CalcShortestRot(self.targetRot, 225) --self.targetRot = 225 elseif strafe < 0 then --self.targetRot = 135 self.targetRot = self:CalcShortestRot(self.targetRot, 135) else --self.targetRot = 180 self.targetRot = self:CalcShortestRot(self.targetRot, 180) end elseif move < 0 then if strafe > 0 then --self.targetRot = 315 self.targetRot = self:CalcShortestRot(self.targetRot, 315) elseif strafe < 0 then --self.targetRot = 45 self.targetRot = self:CalcShortestRot(self.targetRot, 45) else --self.targetRot = 360 self.targetRot = self:CalcShortestRot(self.targetRot, 360) end elseif strafe > 0 then --self.targetRot = 270 self.targetRot = self:CalcShortestRot(self.targetRot, 270) elseif strafe < 0 then --self.targetRot = 90 self.targetRot = self:CalcShortestRot(self.targetRot, 90) end self.rot = Math:Curve(self.targetRot, self.rot, self.damping) self.model:SetRotation(Vec3(0, self.rot, 0), true) end
  5. foreach(auto e in world->entities) { if(e->GetKeyValue("name") == "player") { } } It's been awhile since I've worked on the C++ side of things, or in LE really. Above I believe is the way to loop over entities in the world after the map is loaded. Sorry, no GetChild() needed I guess. Might be more like the below. Sorry, like I said been awhile for(auto e : world->entities) { }
  6. Yeah, I'm saying you would loop over world->entities once and add them to the map of lists with the name as the key and then you can get it via name which isn't a straight loop again, but the idea is today you just need the pivot but tomorrow you need another pivot, then the lights, then etc etc.
  7. One way to do this ourselves (but still would be nice if this was part of the engine), is to loop over all the world->entities and get their names and store them in a map<string, vector<Entity*>>. Now we have a dictionary where the key is the name and each entity is in the list for the key that matches it's name (since entities can have the same name). Then we can just access the entities by name like: entiites["MyPivot"][0] if you know there is only 1 with that name. What was the case statement for? It's been awhile so I don't recall. Was it for each different type and you cast or something?
  8. I believe you have to loop over the world->entities and call ent = world:GetChild(index) and look for the name (ent:GetEntityValue("name") ?) and then you have the entity in which you can call GetPosition() on. Honestly, it would be nice if there was a handy dandy function(s) for this kind of stuff. The function would return a list (since names can be the same). Maybe even be able to tag entities with some kind of value in the editor and find all entities with that tag.
  9. I would probably use a bounding box around each actor. You can get all coins that are within the box and tell them to move towards you. https://www.leadwerks.com/learn?page=API-Reference_Object_World_ForEachEntityInAABBDo Call this every so often in each Actors UpdateWorld() and for each coin entity that is in the bounding box tell it to move towards you. Maybe check that if it's already moving towards another actor to ignore moving towards another but maybe not, maybe that's part of the game. Each actor should have an AABB object and you define it by setting it's center point to be the players position in the UpdateWorld() so it moves, and give it a radius of however big you want. https://www.leadwerks.com/learn?page=API-Reference_Object_Math_AABB This will probably be faster than GetDistance() checks on all coins by all actors.
  10. The editor can save maps yes. I believe the editor is written in BMax still? So I don't believe there a map:save() that you can do in game.
  11. .map files are binary. You'd have to know the binary format to do this. Nobody has done this, to my knowledge, to date. In general this is beyond what is normally done and Josh hasn't really officially ever supported doing it although he may give you the format he's using if you ask, but be careful with updates Josh may do on the map format as you'd need to know the changes for your editor.
  12. Why the use of CreateXXX() vs newing up an instance of the class in question? ie. why CreateWindow() vs new Window().
  13. It means you can't have 2 or more people work on the same map at the same time and then merge them together like you can source files. So be careful if working in a team.
  14. @z3roram The idea with the script Thirsty pointed out that I created, a long time ago, is that in each of your entity scripts you would have a SaveData() function and LoadData(data) function. Inside each entity scripts SaveData() you return a lua table of what you want that entity to save and in the LoadData(data) that same table is passed in as the data parameter for you to use. So it's a generic way of loading and saving data for entities that have scripts because as Josh said each game varies on it's needs. So this is just a framework that is flexible enough for the needs of most all games in Leadwerks. SaveData() and LoadData() can be called from the flowgraph as they are exposed to the flowgraph because they have the --in after their names. So you could have a trigger somewhere that fires an onEnter output from the flowgraph (for example) that hooks up to the SaveData() of this script to save the data. Note that entities are identified by their name so each one you want to be saved should be unique. Note that if an entity is dynamic (it's not found in the map but exists in the saved file) it's expected that when you saved the data you set a property of the lua table named Prefab to the string of where the prefab exists and this will dynamically load that prefab and then call it's scripts LoadData(data) for you to set it's position/rotation/whatever variable you want. To use this add the SaveGame.lua script to a pivot in each scene so that you can call it's SaveData()/LoadData() functions whenever you want to.
  15. It ends up being more about your time. Eventually your time is limited due to other commitments and you want to be as productive as you can. Switching engines all the time limits your productivity while increasing your knowledge. It's a trade-off.
  16. EU has made you frisky lol.
  17. When I did UE4 I would simply get one month to get the software and then I was able to cancel and just not get updates but still use that version. I think they eventually stopped the monthly fee and I would think for that reason. They would pump out smaller updates and fixes weekly which I think they thought would be why people would keep thier monthly they subscription, but I don't think it worked out that way. I would renew about every 6 months just for that one mo th to get caught up on all the updates/fixes. What is is your plan for making this subscription work? Will we not be able to use the app without an active subscription or will we not be able to get updates only without an active subscription? If we can still use the app but not get updates then I can't see people keeping an active monthly subscription. They'll just renew when they want an upgrade or a fix. This, however, means to incentivize people you have to be pumping out fixes and advancements every month to make it worth it for people. If you make it so we can't use the app then that only refers to the editor. People could still code in LE without issue. The editor isn't really required it's just a convience thing. They could easily build most of thier levels and such in a modeling package. I don't see how a subscription base works in today's world which is why I think you see engines dropping that idea now. Your pricing models are always about 2-3 years behind the big engine leaders. Learn from thier mistakes. People come to Le because it's easy and it has no royalties. I think they also liked just putting up a reasonable amount of money every year or so and forgetting it. If people can still use the software and just not get updates you'll end up with probably $5-$-10 a year from a person. Probably just best to charge $25 per major update which should be yearly. You'll get more money and people won't have to screw around with the monthly game of subscribing and unsubscribing based on what and when they want to update to current. Most people probably see $25 a year for updates as very fair.
  18. Rick

    Design Question

    To me he wasn't asking if this behaviour of being able to play the same source on top of each other with one reference should change. That will stay. He's simply asking if a source's reference goes out of scope but it's playing should it be deleted and therefore stop playing. To me I think that makes sense and it's what people do today anyway. That way you can play your audio over and over again via this reference. To let it keep playing while the variable is out of scope now means you have no means to play it again, unless you add the functionality that you're talking about. I'm not really sure what the point of the engine storing these pointers though. The use case listed in the original post is a situation that should pretty much never happen. It doesn't seem to be what people are really doing today. From memory it's not what Josh does in his FPScript and at most it saves a person from having to make a variable at the correct scope for the rare instance they only want to play a sound once in the entire app. Doesn't seem worth the effort on Josh's side to me but I will say that it allows for both styles to work so it's no biggie if he wants to spend the time to manage them internally as well. I just don't see the benefit.
  19. Rick

    Design Question

    I'm pretty sure sources can play on top of each other. That is I can have one reference to a source that uses a sound and call play on that source while it's still playing from another play call and it works to give that rapid fire audio. Maybe I'm missing something around that? I'm sure I've done that before. So not sure what you mean keeping a list of sources.
  20. Rick

    Design Question

    You wouldn't have to check if the sound is playing in your case. You'd just have to be more careful with your scoping. The example presented in this thread should almost never happen in my view. Load your assets in a loading area, then play them via thier reference. That's a common design. Who isnt doing this already today? In Lua people are making class/script variables to hold thier sources because you almost always need to play your sound more than once.
  21. Rick

    Design Question

    Shell's way is convienent, the way I mentioned is reasonable (keep your references in scope for things you need), your way would require a lookup in a global storage container from some kind of key. The global list and lookup feels like it promotes some messy coding. It seems very GameCreators which I always thought was a strange way to mange resources and man did I see some horrible structures in some projects I joined because of it. When everything is available everywhere things get unruly quickly.
  22. Rick

    Design Question

    Yeah I can see how one would get the best of both world there. At first it seems strange to be thst when a variable seems to goes out of scope it's still technically in scope, but I could see people liking that feature.
  23. Rick

    Design Question

    Is there a 95% use case for a specific type of pointer? Like are shared the majority of what a person would use? If there is then make that use case the default and easy vs the minority use case. ie if 95% of the time sources should use shared pointers then just make SourcePtr a typedef for shared_pointer<Source> to make things easier. You're starting to see why languages like C# as loved so much. Don't have to deal with pointer **** directly and still get the feel of normal looking class.
  24. Rick

    Design Question

    As a side note, if we are meant to use these kinds of pointers all over the place you could typedef them with a common naming convention to market less typing for us. I can see that getting tedious. Also what are you doing for Lua? Automatically making all of these shared pointers? If shared pointers is the default then heck you could rename the classes themselves with and underscore and use the now class name as the typedef itself so nothing really changes on our side from today. If you wanted you could probably even extend shared pointer to have addref and release functions that do nothing so current code would work. Making it backward compatible. Gives people a chance to clean up code slowly over time when they upgrade perhaps? Just a quick thought on that.
  25. Rick

    Design Question

    I think it's reasonable for the user to have to keep the pointer around. Most people will be using classes and so this pointer would be a class member variable so it would exist as long as the class exists and classes generally exist longer than functions so it's reasonable. So yes, when it goes out of scope having it clean itself up then opsould be nice.
×
×
  • Create New...