How do I update some methods for a specific map only without adding code to all the other maps to save performance? I know that 1 single if-statement won't make the difference but it will with more complex code like .each statements or when the amount of if-statements rises due to the larger amount of scripts combined with older pc's.
class Game_Map alias test update def update test my_stuff.update if my_stuff # I don't want this line to execute in all other maps. Not even the if-check. endendI thought about making a new Game_Map_Test class. That way the other maps are not affected:
class Game_Map_Test < Game_MapBut that won't work. Unless I replace the $game_map variable and for my custom maps (just before the transfer forth & back) call:
$game_map = Game_Map_Test.new # To the test map$game_map = Game_Map.new # From the test mapAm I doing it wrong?
Have code only placed for specific maps
● ARCHIVED · READ-ONLY
-
-
What about using map ID to determine whether you should execute that code?
Edit: misread the question.
Will it really affect the performance by that much that you'd need to worry about it? -
perhaps you're thinking to complex.
In your case, I would simply place an if on your part of the update - but make that if conditioned on a game switch.
And then instead of checking for specific maps, you'll have an control switch before each transfer command that leads to the maps with the extra update.
That is not as "clean" as a direct scripted solution would be, but you would have to find a way to give the map identification for update or not to the script anyway, and this way you can change it during playtests without modifying the script. -
That I do not know for sure. I did test that a 140 relatively simple if-checks per frame take 0.001 second (on a super fast pc). So about a 0.06 FPS drain in worst case and perhaps an estimated 0.2 FPS drain for a much older PC. 0.2 isn't much but it's still a huge waste for a bunch of inactive scripts :/. And I did not even alias.Will it really affect the performance by that much that you'd need to worry about it?
I already have that (sorry wasn't clear I typed the sample wrong):In your case, I would simply place an if on your part of the update - but make that if conditioned on a game switch.
Only if my_stuff is not nil, only then is it updated. "my_stuff" could be anything in this sample.my_stuff.update if my_stuff # update_my_stuff if update_my_stuff
But sometimes you can't resort to a simple if-statement and you have to check several variables/states to check if the script should be active. This can often be optimized though.
But it seems that everyone just goes with the if-check instead of using a different parent class or something. But it just isn't too great for large projects. -
no clue if it's work... or the speeds on it. But I've seen some code where they if the whole method like
Code:class Game_Map if my_stuff alias test update def update test my_stuff.update end endend -
'if-fing' the whole method is no good. That enables/disables it for the entire executable-run. Because those if-statement are only executed once when the game starts. This can not be used when transferring between maps.
-
You could try metaprogramming, every time you transfer you could delete your aliased update method and make a new alias which contains the update for the new map. This is just theory but I think that it could be possible...
-
Anything you do to try and code it out will wind up more performance breaking than a simple "if" statement like you have in your first post. Especially aliasing or having multiple map classes. I'd just stick with the if.
-
Yeah, I do suggest just sticking with your original method...
-
Wait, what?That I do not know for sure. I did test that a 140 relatively simple if-checks per frame take 0.001 second (on a super fast pc). So about a 0.06 FPS drain in worst case and perhaps an estimated 0.2 FPS drain for a much older PC. 0.2 isn't much but it's still a huge waste for a bunch of inactive scripts :/. And I did not even alias.
I already have that (sorry wasn't clear I typed the sample wrong):
Only if my_stuff is not nil, only then is it updated. "my_stuff" could be anything in this sample.
But sometimes you can't resort to a simple if-statement and you have to check several variables/states to check if the script should be active. This can often be optimized though.
But it seems that everyone just goes with the if-check instead of using a different parent class or something. But it just isn't too great for large projects.
I'm not quite sure your numbers are accurate. I ran a benchmark over ten million iterations using a simple check from a local variable:
require 'benchmark'i = 10000000t = truef = falsen = nil other = "purple"Benchmark.bmbm do |x| x.report { i.times { n if t } } # true test x.report { i.times { n if f } } # false test x.report { i.times { n if other } } # implicit true test x.report { i.times { } } # empty blockendWith the following results:
Rehearsal ------------------------------------ 0.749000 0.000000 0.749000 ( 0.736042) 0.733000 0.000000 0.733000 ( 0.735043) 0.733000 0.000000 0.733000 ( 0.738042) 0.656000 0.000000 0.656000 ( 0.649037)--------------------------- total: 2.871000sec user system total real 0.733000 0.000000 0.733000 ( 0.732042) 0.686000 0.031000 0.717000 ( 0.721041) 0.733000 0.000000 0.733000 ( 0.731042) 0.656000 0.000000 0.656000 ( 0.658038)My computer is pretty fast, but that is several orders of magnitude off your estimates. And as you can see, the bulk of that benchmark time is just from iterating the block used to test even the empty block, the 'if' test itself is a further order of magnitude off from that. The 'if' check itself will have very little bearing at all. If you use a single comparative, you'll get similar results, even if it has to go through a couple accessors to get there. This is not likely to become your bottleneck, especially if it is the update method for Game_Map, which is only run once every frame, considering everything else that goes in in a frame update.
Your main concern with branching, rather than performance, is that it reduces readability of your code and therefore makes it harder to trace and debug. So multiple 'if' statements that have two branches that do drastically different things are generally not a good idea for this reason, though this is usually fine if you separate the two branches into different methods.
Ideally, if you wanted to do such a thing, you would use a separate class here, or singleton methods, but it just isn't feasible in this case. Other classes are reliant on the global instance $game_map to do what they need to do, so subclassing and replacing the variable may cause you issues elsewhere. The logical point to perform the switch between the two classes is also the setup method of Game_Map - or every single method that calls it. You would then have to copy over any instance variables that have a persistent state between the two objects (ie., the interpreter and screen). This would then make your code less intuitive from an outside perspective because it would then be unclear which class $game_map was at any given time, and which one ends up getting serialized when the game is saved.
Basically, if you wanted to do either of these with a Scene at point of call, it would be perfectly fine, because only the Scene itself really cares what is going on. But I would avoid doing this for any of the global instances.
Since I don't really see how you would Game_Map (which basically a persistent container for a bunch of variables with a few internal calculations) enough that its function would no longer be clear, you should probably just branch inside the method(s) like normal. If you just need to branch inside the update method to do some additional stuff, it will be perfectly fine both performance wise and readability wise. It only becomes bad if you need to conditionally branch multiple methods and make them do different stuff within these same methods, at which point you should rethink your implementation.
I've seen my fair share of scripts with performance issues. Excessive sprite use or bitmap operations, redrawing window contents every frame, repeatedly performing string matches instead from notes instead of caching the results, greatly increasing the length of a method that is called hundreds of times per frame, and/or excessive iteration (usually combined with one or more of the others) are all things that can cause performance issues. An 'if' statement or two and a couple comparatives with method calls that return a variable called one time per frame is not going to hurt you. -
Meta-programming is indeed an option. But very error prone and hard to debug.
I might be better off improving performance elsewhere and stick with the if-statements instead, as mentioned a few times.
EDIT: Got ninja-ed.
Maybe my 0.001 performance test was rounded. I was also slightly surprised that it actually took that much time to run them. In C# the numbers are also more closely to your benchmark. But you never know, It's RGSS so internally there could be something else going on without my knowledge so I assumed it to be plausible. I tested it with an if-statement that went up to 3 boolean conditionals per if-statement for a total of about ~400 boolean if-checks per frame. Like if true && (false || true). But that difference shouldn't be noticeable so I presume that my benchmark was wrong.
But that concludes that there is only one good solution: stick to if-statements. -
Yes, all your tests rely on Time from within Ruby, which is not only has a very low precision, but is the precision is also system dependent. My old computer, for example, would not give me any precision for anything lower than 1/64 of a second, which is terrible. The precision available can appear to be greater than it actually is because of the way time difference is calculated, but it looks like you have a max precision of 1 ms. In order to get a semi-accurate benchmark the test need to be run enough that you are getting at least a couple significant digits (enough operations that they are taking at least 10 times the precision you have available). The more significant digits you have, the more accuracy (obviously). And always try to cut out as many other operations as possible to isolate what you are trying to test for, but also remember that the operations you are testing rarely take place in a vacuum and performing micro-optimizations to conform with benchmark results is generally not worth it.