Closed Roguedeus closed 10 years ago
What would "all normal skill details" include?
Just basic skill data. I was making mental notes as I built the test code. I am assuming that any special scripts applied via note tags should also function normally this way.
I've already started building on it. I am exploring the possibilities of modifying the user(enemy) in the same way that would occur in battle, so if a party member has trap countermeasures, they are applied to the user and thus effect the skill triggered by the trap.
So far this looks really cool.
Basing the animation on the selected skill would be useful, since the trap itself could be arbitrary picked from a list of skills.
Playing the animation over the affected character would also be effective.
Agreed. :) The more I poke this the more possibilities appear.
I am also thinking of possibly allowing the player to 'disarm' the trap via some sort of dialogue tree built out of the enemy stats. (Though very simple) Assuming the player has a trap removal skill or passive state of some kind.
This is also making me wish that Yanlfy's Popups worked in the game map... :p
This is making me wonder if I might be able to tackle that older suggestion I made about Battler States. :)
I didn't realize animations where so easy to call.
def battler_trap_animation(skill_id, wait = false)
item = $data_skills[skill_id]
character = $game_player
character.animation_id = item.animation_id
Fiber.yield while character.animation_id > 0 if wait
end
Can you possibly be able to tell me why this scripts popup
method is super fast the first time its used, but then causes at least half a second of lag every time after?
I am looking it over and I am simply not familiar enough with RGSS/Ruby to determine.
http://galvs-scripts.com/galvs-event-pop-ups/
I am guessing its a simple oversight because otherwise why would it be so snappy on its first run, only to lag so badly after?
I can't reproduce it. I had a "hello" popup appear and it doesn't lag or anything even when I make it appear multiple times.
I then had a potion icon appear and it works fine as well.
Damn... Thanks for trying. Looks like I am going on a bug hunt, or yanking that particular part from the trap mechanic.
Can you think of any particular part of that script that might lag naturally?
The only thing I can think is the update_bitmap
call every frame, but if that where causing the lag it would lag the whole time the popup is visible rather than just at its creation.
Fixed it... It was not caching the @icon_sprite
and re-creating it every time was causing the IconSet.png to be re-loaded each time. My IconSet is HUGE so it was causing issues.
Its even faster than before in a blank protect now.
Well damn it... Wasn't that simple. Now it gets progressively slower and slower every time an attack animation occurs.
Issue with the actual popup lagging is gone. But a new lag has revealed itself.
Is it normal for the Interpreter called animation on the game map, not in battle, to begin lagging after about 20 or so calls?
The lag is gone after a map transition.
Does it happen in a new project?
If not, then no.
Found it too... Its Yanfly's Event Window. Once it gets larger then about 15 entries it begins to noticeably lag.
Go figure.
Clearing it every 10 entries clears up every bit of lag.
class Game_Temp
def add_event_window_data(text)
@event_window_data = [] if @event_window_data.nil?
clear_event_window_data if @event_window_data.length > 10
return if text == ""
@event_window_data.push(text)
end
end
After conceding that there is no way a core feature of the game could cause it, it took less then a few moments to realize I was also updating the event window with trap results, in case the player disables the popup.
Hmm...but then if you think about how the item scene works, you could possibly have dozens of items being drawn and that doesn't really cause a problem.
Do you have or plan to make a public script for this, Roguedeus? I would be very interested in it, although I'm unsure how it works.
Its not public at the moment. It is still very rough. Also it incorporates the use of several authors scripts (Galv, Yanfly, Hime) it is also more of an in house thing.
In the mean time the OP code can be used to completely event your traps normally. Just place the code as a stand alone script and call that method in a an event script command at the proper time.
The trap_level
parameter wont work unless you are using Hime's Enemy Levels though.
What does it do? Say I want to have it so that when an enemy uses a contact move against the battler of a given slot id, the trap will activate, unless the enemy has the Above Ground state, because that particular trap is a ground trap. Or you could have a floating magic mine trap that work against anything besides things like snakes or slime, which can slide under. {And the trap is a certain skill?} that can either continue even if the original placer is out of the party or dead. Or perhaps certain moves against that slot id will cause the trap to deactivate. Yay, ideas. Lol.
Its not a battle, its only a single shot attack against every active party member. The battler only exists as a means of processing the skills data, so any effects that are applied to the battler will only serve to change his stats before the attack is processed. After which the battler is destroyed in code.
The player never sees the battler, as it only exists as an instance object in code, in order to get data from it.
However, anything you choose to have the event do, before or after that process occurs, is totally up to you.
Again, I am not sure if this script will ever be released for public use in its complete form as it requires the use of several other scripts and its unreasonable to assume that people will be able to handle that without trouble. And then they would want me to walk them through it each time... Its easier to just not release it, or release little more than what you see in the OP.
Ok, it just occurred to me yesterday that I can expand this script to include a few concepts I've got milling around in my head.
First, I can expand the traps script via special skills that are limited to reference only, not usable in menu or battle, that apply ONLY to traps. Having the skill has them applied to a trap when the party 'acts' on the trap. The batter that's created for the trap is then, ATTACKED by all battler members that have those skills, and if the battler dies, the trap is deactivated.
Conversely, the system can be adapted to collectable items like ores and treasures.
The same process will occur, but with 'Gathering' skills that attack the collectible battler the same way, resulting in loot (the collectible items) if the battler dies.
I think turning events into battlers on the map would slowly lead to on-map battle systems lol
First the events simply use a skill. Now you can defeat them and they will drop items.
What's next? They move? lol
Yeah. I have begun using this script for several things, including effects based on the enemy assigned to them. It started as just a trap system, but has morphed to where traps are only half the function of it.
I've allowed for actors to have passive states that mitigate trap effects and passive skills that only trigger against battler traps as a mechanic for disabling.
I have not had a need to develop the battler state idea yet... But I might soon. ;)
Returning to this because the lag caused by Event Window is pretty significant... Its super noticeable now that I have managed to streamline much of the rest of the lag issues I had.
After staring at the code and poking at it, I have determined that adding text to the window is the BIGGEST culprit. However, NOTHING I can find would indicate why. I am left wondering if it has to do with the fact that yanfly chose Window_EventWindow < Window_Selectable
Window Selectable as the basis for the event window.
Something tells me that Window Select must not have the same disposal actions as other regularly updated windows, which is causing the lag to get worse and worse, every time a new string is added to the contents.
Of course, this is just a guess, as I am not very familiar with windows. I'm going to try and see what alternatives I can find, or other similar scripts and how they've avoided the lag... Or not.
Any feedback might help.
To be clear... Its not just the event window causing lag. But it's damn close to half of it. The other half I haven't quite gotten a handle on. But I am guessing its the animations & sounds...
Looks like I was mistaken... EventWindow isn't a significant part of the problem... /facepalm It just looked like the reasonable explanation until I isolated it.
This is sooo much fun.
Yes, isolating things reveals a whole new world. This is pretty much why I ask people to create a new project.
I swear... It feels like this game engine operates on the edge of acceptable performance at all times and the slightest nudge sends it off balance.
I just realized that I am doing way way way to much with states... If there are more than 2 active states on any actors, the game begins to lag... And a large part of the trap lag issue, was the fact that by the time the party had passed through a half dozen of them, there were a hand full of states active, as a result...
This wouldn't be a problem in the middle of battle, where lag is pretty hard to notice. But when the fluidity of the map scrolling begins to hitch, its SUPER noticeable.
So... I get to make a run through all the scripts that touch states and try to figure out how I can optimize them...
Lately, every time I think I have reached a point were I can begin to crunch out some real content, I either discover something I'd like to do, or have to do, to prevent it.
Its almost as if being really productive is a catch 22. The more productive I am, the more I find I need to do... :p
Sounds like your passive states working against you again.
You are right... At least now I know which script to re-write. I should probably just use yours to plug into instead.
The passive state plugin I made was a large part but not all of it. I will still have to once over every state script... /sigh
Holy crap... Nested while loops are nearly half the speed of nested FOR loops... But straight FOR loops are about 30% SLOWER than straight while loops?!?
for ... in 0.093000 0.000000 0.093000 ( 0.088005)
while 0.063000 0.000000 0.063000 ( 0.062003)
for for 0.062000 0.000000 0.062000 ( 0.074005)
while while 0.125000 0.000000 0.125000 ( 0.121006)
[Finished in 0.4s]
My mistake... There is ZERO performance difference.
for ... in 0.093000 0.000000 0.093000 ( 0.088005)
while 0.047000 0.000000 0.047000 ( 0.059003)
for for 0.078000 0.000000 0.078000 ( 0.075005)
while while 0.078000 0.000000 0.078000 ( 0.075004)
[Finished in 0.4s]
lol you should also show the code you're testing.
I made sure they created the same arrays...
(The first time used the wrong array in the while while test...)
TIMES = 10000
ARRAY2 = Array.new(5) { Array.new(2) {1} }
user system total real
for for 0.015000 0.000000 0.015000 ( 0.023002)
while while 0.032000 0.000000 0.032000 ( 0.025001)
[Finished in 0.1s]
b.report "for for" do
TIMES.times do |i|
@array_f = []
for obj in ARRAY2
next unless obj #States don't have passive states...
for id in obj
@array_f.push(id)
end
end
end
# puts(@array_f.to_s)
end
b.report "while while" do
TIMES.times do |i|
@array_w = []
sub_cnt = 0
sub_lim = 0
cnt = 0
lim = ARRAY2.size
while cnt < lim
sub_cnt = 0
sub_lim = ARRAY2[cnt].size
while sub_cnt < sub_lim
@array_w.push(ARRAY2[cnt][sub_cnt])
sub_cnt += 1
end
cnt += 1
end
end #TIMES
# puts(@array_w.to_s)
end
Over all I found some interesting things... Several built in loops are actually equal to their raw while loop counterparts. While at least one is actually faster. (will double check it later.)
[].select
and [].collect
are sgnificantly faster than a while loop replacement... At least, as I tested them. Its possible I did something wrong.
#-----------------------------------------------------------------------------
# user system total real
# collect 0.125000 0.000000 0.125000 ( 0.120007)
# while 0.156000 0.000000 0.156000 ( 0.156009)
# [Finished in 0.4s]
#-----------------------------------------------------------------------------
b.report "collect" do
TIMES.times do |i|
@a = []
@a = ARRAY3.collect {|x| x <= 0}
end
# print("#{a}")
end
b.report "while" do
TIMES.times do |i|
@a = []
cnt = 0
lim = ARRAY3.size
while cnt < lim
if ARRAY3[cnt] <= 0
@a.push(true)
else
@a.push(false)
end
cnt += 1
end
end
# print("#{@a}")
end
#-----------------------------------------------------------------------------
# user system total real
# select 0.110000 0.000000 0.110000 ( 0.116007)
# while 0.187000 0.000000 0.187000 ( 0.182010)
# [Finished in 0.4s]
#-----------------------------------------------------------------------------
b.report "select" do
TIMES.times do |i|
@a = []
@a = ARRAY3.select {|x| x > 0}
end
# print("#{a}")
end
b.report "while" do
TIMES.times do |i|
@a = []
cnt = 0
lim = ARRAY3.size
while cnt < lim
if ARRAY3[cnt] > 0
@a.push(ARRAY3[cnt])
end
cnt += 1
end
end
# print("#{@a}")
end
Another example... Please tell me if this is not an apples to apples comparison.
require "benchmark"
class State
attr_accessor :id
attr_accessor :duration_min
attr_accessor :duration_max
attr_accessor :incaps
def initialize(id)
@id = id
@duration_min = rand(3) + 1
@duration_max = rand(4) + @duration_min
@incaps = []
end
end
TIMES = 100_000
STATE_ARRAY = Array.new(100) {|i| State.new(i)}
STATE_IDS = (1..100).to_a
ARRAY10 = [91,71,8,41,5,3,6,21,0,11] #10
ARRAY20 = [1,4,5,73,5,3,63,5,13,4,53,7,5,3,6,99,43,5,2,0] #20
Benchmark.bm(30) do |b|
b.report "collect" do
TIMES.times do |i|
#----------------------------------
@result = ARRAY10.collect {|id| STATE_ARRAY[id]}
#----------------------------------
end
end
# puts(@result.to_s)
b.report "while" do
TIMES.times do |i|
#----------------------------------
@result = []
cnt = 0
lim = ARRAY10.size
while cnt < lim
@result.push(STATE_ARRAY[ARRAY10[cnt]])
cnt += 1
end
#----------------------------------
end
end
# puts(@result.to_s)
end
# user system total real
#collect 0.156000 0.000000 0.156000 ( 0.155009)
#while 0.172000 0.000000 0.172000 ( 0.173009)
#[Finished in 0.4s]
I've made sure I am running 1.9.2 so its applicable to RGSS3.
It seems that nearly every example of each
is slower than the while alternative. But sometimes, not by much more than about 10%. At most I've seen about 25 to 30%.
require "benchmark"
class State
attr_accessor :id
attr_accessor :duration_min
attr_accessor :duration_max
attr_accessor :incaps
def initialize(id)
@id = id
@duration_min = rand(3) + 1
@duration_max = rand(4) + @duration_min
@incaps = []
end
end
TIMES = 150_000
STATE_ARRAY = Array.new(100) {|i| State.new(i)}
STATE_IDS = (1..100).to_a
ARRAY10 = [91,71,8,41,5,3,6,21,0,11] #10
ARRAY20 = [1,4,5,73,5,3,63,5,13,4,53,7,5,3,6,99,43,5,2,0] #20
HASH10 = {1=>91,2=>71,3=>8,4=>41,5=>5,6=>3,7=>6,8=>21,9=>0,10=>11} #10
Benchmark.bm(30) do |b|
b.report "each" do
TIMES.times do |i|
#----------------------------------
@result = []
HASH10.each do |i, id|
@result[i] = State.new(id)
end
#----------------------------------
end
end
# puts(@result.to_s)
b.report "while" do
TIMES.times do |i|
#----------------------------------
@result = []
cnt = 0
lim = HASH10.size
while cnt < lim
cnt += 1
@result[cnt] = State.new(HASH10[cnt])
end
#----------------------------------
end
end
# puts(@result.to_s)
end
# user system total real
#each 1.732000 0.000000 1.732000 ( 1.741100)
#while 1.435000 0.000000 1.435000 ( 1.436082)
#[Finished in 3.3s]
I've also begun to cache method results, used in loops, that assemble arrays every time they are called. It seems silly not to do so and even more silly that the engine makers didn't use a name scheme that indicated that's what the method is doing.
I'm not mistaken am I?
y = method #This caches the value
i.times do |z|
y.include?(xxx) #This checks the cache every loop?
end
i.times do |z|
method.include?(xxx) #This assembles the array for checking every loop?
end
def make_array
puts("Make")
return [1,2] + [3]
end
y = make_array
3.times{puts(y.push(4).to_s)}
puts("-------------------")
3.times{puts(make_array.push(4).to_s)}
#Make
#[1, 2, 3, 4]
#[1, 2, 3, 4, 4]
#[1, 2, 3, 4, 4, 4]
#-------------------
#Make
#[1, 2, 3, 4]
#Make
#[1, 2, 3, 4]
#Make
#[1, 2, 3, 4]
#[Finished in 0.1s]
Yeah, I sometimes get myself mixed up over which assignments are pointers to a value and which are actual values... I never studied computer science and all that so pretty much 99% of my work is simply force of will, trial and error, and the many times I've managed to have someone like you humor me for a while... ;)
Well... I've managed to get a full 5 battle member party, each 25+ states, to RUN not walk smoothly around the map.
In doing so I managed to figure out that I no longer needed about 4 scripts (replacing yanfly's passive states with yours) and will instead use my new Passive Aura States script. Which doesn't appear to cause any lag at all even when every party member has an aura on top of their 25+ states.
I really... REALLY, don't want to have to do this again any time soon. Though on the bright side, I did learn new things about ruby that I likely wouldn't have otherwise.
I did notice that they do not cache their results locally. One reason for this is perhaps to account for real-time changes?
What I mean is, suppose you have 100 states. By the time you've checked half of them, one of the states in the other half have changed already, and the game needs to correctly account for this.
Or maybe they just didn't want to clutter their code.
One example I can think of is the way they call equips
everytime they want to check parameters...
This small bit of code is the basis for the idea I have for using custom enemies as traps and simply using the level system, along with Parameter Tables, to scale them to need.
I intend to expand this as needed to include selecting the enemies skills, but for now the skill used as the trap is manually provided.