thehankinator Posted June 10, 2015 Share Posted June 10, 2015 This is a short tutorial to add a battery to the default FPSPlayer.lua script. I am going to assume you are familiar with lua script and Leadwerks 3.5 so I wont be spending much time explaining how to place entities on a map etc. The code samples below will have the new code surrounded by comments, the rest is there just to give you reference to what section of the code we are working in. I broke this problem down into 3 separate aspects. Flashlight logic Battery level indication (HUD) Battery pickup Initial Setup Open your project or create a new one. In the asset tab, navigate to the FPSPlayer.lua script. Make a copy of it, call it FPSPlayerBattery.lua. Next at the top of FPSPlayerBattery.lua, we need to add the variables that we will need to make this happen. Script.mouseDifference = Vec2(0,0) Script.playerMovement = Vec3(0,0,0) Script.tempJumpForce = 0 --+++BATTERY VARIABLES BEGIN+++ Script.battery_level = 100 --float "Battery level" Script.battery_max_level = 100 --float "Battery max level" Script.battery_discharge_rate = 0.5 --float "Battery discharge rate" --+++BATTERY VARIABLES END+++ function Script:CycleWeapon(direction) local n,weapon local foundindex=false Script.battery_level The current level. In this example I made 100 the current. If you wanted the player to start with no battery power, you could change this to 0. Script.battery_max_level The max level of the battery. If the player doesn't have a battery, you could set this to 0 or if they got an upgraded battery bump this value up. Script.battery_discharge_rate The speed which the battery will die while the light is on. Flashlight logic This will occur in the UpdatePhysics function of FPSPlayerBattery.lua. --Update the footstep sounds when walking self:UpdateFootsteps() --+++BATTERY LOGIC BEGIN+++ --Toggle the flash light on and off if window:KeyHit(Key.F) then if self.flashlight:Hidden() then --check if the flashlight is off if self.battery_level > 0 then --check if we battery power self.sound.flashlight:Play() --play the sound self.flashlight:Show() -- turn on the light end else --light is already on self.sound.flashlight:Play() --play the sound self.flashlight:Hide() --turn off the light end end if not self.flashlight:Hidden() then --check if the light is on self.battery_level = self.battery_level - self.battery_discharge_rate * Time:GetSpeed() --light is on, reduce the battery level. if self.battery_level <= 0 then --check if the battery died self.battery_level = 0 --just incase the battery level went below 0, reset it to 0 self.sound.flashlight:Play() --play the usual sound self.flashlight:Hide() --turn off the light end end --+++BATTERY LOGIC END+++ --Apply forces to make the carried object move the way we want if self.carryingEntity then Battery level indication (HUD) This will be a bar that will have a green color if you have power, red if you get low. We need to look in the PostRender function of FPSPlayerBattery.lua. context:SetBlendMode(1) context:SetColor(0,0,0,0.5) local indent=8 local w = 180 local h = 40 --+++BATTERY INDICATOR BEGIN+++ local battery_percent = self.battery_level / self.battery_max_level --calculate the percentage of battery power remaining context:SetColor( 1 - battery_percent, battery_percent, 0, 1) --as the battery dies the red component increases while the green decreases context:DrawRect( 50, 50, 100 * battery_percent, 20) --rectangle width is dependent on the percentage of battery remaining. Wider with more power. --+++BATTERY INDICATOR END+++ end Battery pickup In the assets tab, navigate to Scripts/Objects/Items. Create a new script called PickupBattery.lua. Open that sucker up and delete the contents. Script.battery_power = 50 --int "Battery power" function Script:Collision(entity, position, normal, speed) local p = entity.script --for convenience if p.battery_level ~= nil and p.battery_max_level ~= nil then --make sure what collided has the required battery variables if p.battery_level < p.battery_max_level then --make sure that the battery isn't already full p.battery_level = p.battery_level + self.battery_power --add the power to the battery if p.battery_level > p.battery_max_level then --check to see if we over filled the battery p.battery_level = p.battery_max_level --set the battery to max value end self.entity:Release() --get rid of the pickup now that the power was added end end end Script.battery_power How much power this pickup will give the player Wrap up That is all the parts needed. Set your player entity to use FPSPlayerBattery.lua. Set the script on the pickups in your level to PickupBattery.lua. I've not decided if I will upload the completed scripts, I don't want spoil the fun of doing it yourself . Feedback welcome. 4 Quote Link to comment Share on other sites More sharing options...
Thirsty Panther Posted June 10, 2015 Share Posted June 10, 2015 Thanks for the tutorial Hank. Nice work. Quote Link to comment Share on other sites More sharing options...
lxFirebal69xl Posted June 10, 2015 Share Posted June 10, 2015 Awesome tutorial, got everything working but the Battery Pickup script, I don't get how it works Quote Link to comment Share on other sites More sharing options...
thehankinator Posted June 10, 2015 Author Share Posted June 10, 2015 What part of it is throwing you off? Quote Link to comment Share on other sites More sharing options...
lxFirebal69xl Posted June 10, 2015 Share Posted June 10, 2015 What part of it is throwing you off? I went ahead and changed the battery pickup script to this: Script.battery_power = 50 --int "Battery power" function Script:Use(person) if person.script.battery_level ~= nil and person.script.battery_max_level ~=nil then if person.script.battery_level < person.script.battery_max_level then person.script.battery_level = person.script.battery_level + self.battery_power if person.script.battery_level > person.script.battery_max_level then person.script.battery_level = person.script.battery_max_level end self.entity:Release() end end end And I also changed something in my FPSPlayer script this is around line 445 if usableentity~=nil then --Use the object, whatever it may be usableentity.script:Use(self.entity) I changed the "Use(self)" to "Use(self.entity)" and this makes it so that the flashlight pickup has to be actually picked up, aka, pressing E on it. Quote Link to comment Share on other sites More sharing options...
Rick Posted June 10, 2015 Share Posted June 10, 2015 I think some of these features would be best to be broken out into their own classes. Flashlight seems like a prime candidate for this. The FPS player script is already a big mess. Plus integration/distribution/understanding/modification will be much easier. I think a great deal of things in the FPS player script could benefit from this and be much easier to manage and read. 1 Quote Link to comment Share on other sites More sharing options...
thehankinator Posted June 10, 2015 Author Share Posted June 10, 2015 I went ahead and changed the battery pickup script to this: Script.battery_power = 50 --int "Battery power" function Script:Use(person) if person.script.battery_level ~= nil and person.script.battery_max_level ~=nil then if person.script.battery_level < person.script.battery_max_level then person.script.battery_level = person.script.battery_level + self.battery_power if person.script.battery_level > person.script.battery_max_level then person.script.battery_level = person.script.battery_max_level end self.entity:Release() end end end And I also changed something in my FPSPlayer script this is around line 445 if usableentity~=nil then --Use the object, whatever it may be usableentity.script:Use(self.entity) I changed the "Use(self)" to "Use(self.entity)" and this makes it so that the flashlight pickup has to be actually picked up, aka, pressing E on it. That works for this pickup but I would refrain from making that sort of change to the FPSPlayer script. It could break some other item's Use function because they would be expecting the script object rather than an entity object. I would change FPSPlayer script back to if usableentity~=nil then --Use the object, whatever it may be usableentity.script:Use(self) Then change the pickup script to Script.battery_power = 50 --int "Battery power" function Script:Use(person) if person.battery_level ~= nil and person.battery_max_level ~=nil then if person.battery_level < person.battery_max_level then person.battery_level = person.battery_level + self.battery_power if person.battery_level > person.battery_max_level then person.battery_level = person.battery_max_level end self.entity:Release() end end end Quote Link to comment Share on other sites More sharing options...
lxFirebal69xl Posted June 10, 2015 Share Posted June 10, 2015 That works for this pickup but I would refrain from making that sort of change to the FPSPlayer script. It could break some other item's Use function because they would be expecting the script object rather than an entity object. I would change FPSPlayer script back to if usableentity~=nil then --Use the object, whatever it may be usableentity.script:Use(self) Then change the pickup script to Script.battery_power = 50 --int "Battery power" function Script:Use(person) if person.battery_level ~= nil and person.battery_max_level ~=nil then if person.battery_level < person.battery_max_level then person.battery_level = person.battery_level + self.battery_power if person.battery_level > person.battery_max_level then person.battery_level = person.battery_max_level end self.entity:Release() end end end Allright that works as well, thanks hankinator! I think some of these features would be best to be broken out into their own classes. Flashlight seems like a prime candidate for this. The FPS player script is already a big mess. Plus integration/distribution/understanding/modification will be much easier. I think a great deal of things in the FPS player script could benefit from this and be much easier to manage and read. I completely agree with you here, it's such a pain to change code in the FPSPlayer script sometimes, maybe it's time for an FPSPlayer script overhaul. Quote Link to comment Share on other sites More sharing options...
Josh Posted June 10, 2015 Share Posted June 10, 2015 In my experience this will result in a lot of brittle pieces that frequently stop working together. One object, one script, zero ambiguity. Quote My job is to make tools you love, with the features you want, and performance you can't live without. Link to comment Share on other sites More sharing options...
Rick Posted June 10, 2015 Share Posted June 10, 2015 One object, one script, zero ambiguity. Yeah, we've had this convo many times and don't agree My time is short but would be interesting to see a clearly broken out fps script to see the difference in readability/maintainability/extensibility. I'm not talking component design to an insane level here, just classes that you manually include into the script to break out logical functionality. Movement & animation still makes sense for FPS script. Flashlight and all that goes with it seems to make sense to break out. Firebal could have taken the small and easy flightlight.lua file and adapted it easily enough to add his functionality I think. At least the task wouldn't seem so large and overwhelming as it does when he looks at the fps script today. Quote Link to comment Share on other sites More sharing options...
Josh Posted June 10, 2015 Share Posted June 10, 2015 Extensibility in most cases is really just indecisiveness. My $0.02. Quote My job is to make tools you love, with the features you want, and performance you can't live without. Link to comment Share on other sites More sharing options...
Rick Posted June 10, 2015 Share Posted June 10, 2015 Extensibility in most cases is really just indecisiveness. My $0.02. Not in this specific case of a flashlight. You provided a basic flashlight. It wasn't indecisiveness on your part it was just providing basic functionality. You provided a basic template and he wants to extend it, but you didn't give a very good environment for extending it. Even so though, indecisiveness is a human trait. We don't know everything. You've changed many things over time. We aren't perfect so making this process easier seems like a good idea. That's part of the idea. We aren't perfect and we may want to try many different things. This would also make people like the OP's job easier to provide such functionality if the environment promoted this. Right now he's following in the footsteps of your idea and that script just got bigger and messier (but it was kind of him to help for sure). If your template broke these things out, he'd be more inclined to follow that design pattern. This isn't all life or death stuff obviously, but it makes script writing better in my experience. Quote Link to comment Share on other sites More sharing options...
josk Posted June 10, 2015 Share Posted June 10, 2015 Those big scripts can look complicated. I have started doing more smaller scripts that can be used between projects. Adding to the script panel so properties dont need changing in code between projects. Quote Elite Cobra Squad Link to comment Share on other sites More sharing options...
thehankinator Posted June 10, 2015 Author Share Posted June 10, 2015 Not in this specific case of a flashlight. You provided a basic flashlight. It wasn't indecisiveness on your part it was just providing basic functionality. You provided a basic template and he wants to extend it, but you didn't give a very good environment for extending it. Even so though, indecisiveness is a human trait. We don't know everything. You've changed many things over time. We aren't perfect so making this process easier seems like a good idea. That's part of the idea. We aren't perfect and we may want to try many different things. This would also make people like the OP's job easier to provide such functionality if the environment promoted this. Right now he's following in the footsteps of your idea and that script just got bigger and messier (but it was kind of him to help for sure). If your template broke these things out, he'd be more inclined to follow that design pattern. This isn't all life or death stuff obviously, but it makes script writing better in my experience. The purpose of this post was intended to show a basic concept. Most of the logic to achieve this battery would look pretty similar if it was developed utilizing a different design pattern. I expect that most people would take the concept and implement it in their scripts the way they see fit. This is part of the reason I didn't post the whole script, just the parts that matter. Besides, it's a moving target to satisfy everyone's code structure. Do you have have a prototype of your ideal FPSPlayer script? Quote Link to comment Share on other sites More sharing options...
Rick Posted June 10, 2015 Share Posted June 10, 2015 I understand the purpose of this post and I don't have an issue with it and think it's great you provided your time to help but it highlighted the overall script design philosophy that Josh holds that I don't agree with (completely) and the fps script is a prime example as to why I don't agree with it and how we see users follow in that idea even if it's to just get the basic idea of something. If Josh took a more modular approach and broke that script out more you would have been less likely to go "inline" with your example and instead follow the pattern. The flashlight would have already had it's own script so you would have just modified that script and it would have been much easier to get the idea across and for Firebal to implement and potentially understand and play around with modifying it without worrying about screwing up the rest of the fps script. So really this was less of an issue with what you did and more with the "One object, one script, zero ambiguity" idea when scripts start getting rather large which is very common in all games. Do you have have a prototype of your ideal FPSPlayer script? I generally avoid that script for anything but a quick test, but I might take another look given this recent topic and split it out. Don't want to get too sidetracked from Dead Anyway (saying that in case tj is reading this ) but shouldn't take that long as an exercise. The flashlight is an interesting and perfect example of all of this though. The idea of a flashlight can be pretty broad as we've seen in recent games. Cameras, cell phones, lamps, etc have acted as "flashlights" in games. Given a common interface for a "flashlight" it can really help people implement their own and separate out their logic to it's own script for easy distribution/maintenance/extensibility/etc. Really it comes down to what josk alludes to. Big scripts end up more complicated and fragile when modified than breaking out logical parts into multiple scripts. 1 script is great when you give it to someone who just accepts it and plugs it into the game, but this ends at the very basic beginner level in users. They soon want to start customizing their game and I feel it's easier and more friendly to do that (for everyone) with smaller logically broken out scripts that do their specific job without bleeding responsibility into other areas. Quote Link to comment Share on other sites More sharing options...
Thirsty Panther Posted June 10, 2015 Share Posted June 10, 2015 Also if Josh updates the FPS script you will lose your modifications to it. Quote Link to comment Share on other sites More sharing options...
thehankinator Posted June 10, 2015 Author Share Posted June 10, 2015 Also if Josh updates the FPS script you will lose your modifications to it. This is an annoying problem. When I get a LE update I cringe because it is awkward to go through the log and find all the .bak files to do a diff on the current script then merge the two scripts. I made sure to specify what version of LE I used when developing the tutorial. I've taken to making a copy of every script I modify (as I did in the this tutorial), updates be damned. I like the idea of an improved FPSPlayer script(regardless of design pattern) but until it replaces the default LE scripts I think it is best to base a tutorial on the scripts that are known, working and available with the default installation. Quote Link to comment Share on other sites More sharing options...
Rick Posted June 10, 2015 Share Posted June 10, 2015 but until it replaces the default LE scripts I think it is best to base a tutorial on the scripts that are known, working and available with the default installation. I agree. My posts weren't to try and make people do otherwise but to just show the benefits so maybe more people put more pressure on Josh to officially change the style with that script and maybe other bigger ones like it Josh does listen to the community but if only 1 person is voicing his opinions it's harder to get any traction for change. I think the fps script is starting to get to a tipping point the more people want to add functionality around it. 721 lines. That's a lot of code in 1 file. I remember going through HL's code and was amazed at how small and modular it was in it's class design. Each function was 1 screen or less, often times less and from what I recall there weren't a ton of functions to a class. They separated things out nicely. 5 Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.