Jump to content
New account registrations are disabed. This website is now an archive. Read more here.
  • 0
Sign in to follow this  
Heretic86

[XP] Delete Element found in $game_party.actors

Question

I am messing with a screwy custom battle script. Short and simple, elements of $game_party.actors are moved to a new array. I compare the new array with $game_party.actors to find changes in the party, such as a Battler being Added or Removed during combat. Im trying to use this:

 

@count_battlers.delete(watched_party - $game_party.actors)

 

"watched_party" is a copy of the array I am comparing to because $game_party.actors changes when Characters are Added or Removed, but this doesnt work. @count_battlers is another copied array of all Battlers and Enemies (used for Progress Bar Gauge thing). This part of my script is trying to handle Removed Battlers, Added Battlers is super simple, uses actors.push(actor).

 

More of a Ruby in general question. How do I get this to work?

Share this post


Link to post
Share on other sites

11 answers to this question

Recommended Posts

  • 0

I'm not 100% sure I fully understand what you need to do...

 

I think (correct me if I am wrong) that in this battle system, you add or remove actors from $game_party.actors; then, you need to figure out which actors were removed and remove the same actors from @count_battlers?

 

If yes, then I think what you are trying to do is more like this:

# $game_party has actors removed
# find removed elements (actors)
removed_actors = watched_party - $game_party.actors
# delete removed actors from @count_battlers
@count_battlers.delete_if do |battler|
removed_actors.include?(battler)
end

 

First, you need the "removed" elements, assuming $game_party.actors has elements removed, and watched_party is the same except still contains the "removed" elements, then you need to capture a new array containing those elements:

removed_actors = watched_party - $game_party.actors

array - other_ary returns a copy of array, with any common elements from other_ary removed...thus leaving you with the removed elements.

 

Then, array#delete_if { |item| block } will iterate over each element in array, and removes each element that block returns true for...

i.e. removed_actors.include?(battler) will return true, if removed_actors contains the current battler in the array.

 

The only problem with your code, is that array#delete(obj) will delete obj from array if it is contained within that array. If you try to delete(array) from an array, it will ONLY remove an element that is an array, equal to that array.

 

Hope that made sense, hope that helps. I need some sleep xD

Share this post


Link to post
Share on other sites
  • 0

It does make some sense. I suck with ruby, but do much better on PHP and MySql. What if I were to get an Index, then delete the index, would that remove the sub_array from the larger containing array?

 

More a less stuck figuring out ruby syntax...

Share this post


Link to post
Share on other sites
  • 0

Nevermind, I got it.

 

@watched_party = @watched_party - (@watched_party - $game_party.actors)

 

Simplified version, finds the removed actor, then removes from @watched_party. Boy do I feel dumb.

Share this post


Link to post
Share on other sites
  • 0

Hmm, I think I worded that funny. array - array will return an array, then other_array.delete(array) will try to delete the array from the other_array, which would not exist within that other_array

Hmm... maybe that was more confusing xD, Let me demonstrate the issue with that solution:

(pretend the number values represent battler objects)

 

count_battlers = [1, 2, 3, 4]
game_party = [1, 2, 3, 4]
watched_party = [1, 2, 3, 4]
# Remove last actor from party:
game_party.delete_at(3) # last index == 3
# Get removed actors
new_ary = watched_party - game_party
# new_ary == [4]
count_battler.delete(new_ary)
# count_battler == [1, 2, 3, 4] as no element within count_battler == [4]

So, technically, there are no sub arrays. And since you are trying to remove an array from another array (which would/should never have a sub array)

 

However, perhaps I could re-explain my original solution:

If you have used ruby enumerators before, this should be easy..if not, hopefully I can clear it up.

The 2 most common enumerators/iterator on an array are array#each and array#each_index. For example, array#each { |item| block } will loop through each element of array, and on each iteration passes that element to the local variable `item`. `block` is any block of code, which will be executed on each iteration/loop.

 

Really, you can think of an enumerator as a fancier (and technically much more efficient) version of a `for` loop.

 

array = [1, 2, 3]
# For loop:
for i in array
 puts i
end
# array#each
# NOTE: { |i| block } is the same as 
# do |i|
#   block
# end
# Generally, ruby programmers use do...end for multi-line blocks and { ... } for single line blocks
array.each do |i|
 puts i
end
# OUTPUT (will be the same for either method):
# 1
# 2
# 3

 

Now, array#delete_if { |item| block } is also an enumerator. On each iteration, the element of the array is passed into `item`, and then, if `block` evaluates to `true`, that element will be removed from array....

So:

array = [1, 2, 3]
array.delete_if { |i| i == 2 }
# array is now:
# [1, 3]
# when 2 (element index 1) is passed into i on the second iteration,
# i == 2 evaluates to `true` and thus 2 is removed from array.

Therefore, in my solution, on each iteration the current element (an actor/battler) will be passed to `battler`. Then, when removed_actors.include?(battler) is `true`, meaning the current battler from @count_battler is contained within removed_actors. Therefore, if a removed actor exists within @count_battler, it will be deleted.

 

And here's another solution I just thought of...which is ultimately simpler/less confusing.... (I left the explanations in case you wanted to know anyways)

 

# Get the removed actors:
removed_actors = watched_party - $game_party.actors
# removed_actors is now an array containing ALL `missing` actors
@count_battler = @count_battler - removed_actors
# @count_battler is now an array, WITHOUT the actors contained within `removed_actors`

 

xD I told you I needed some sleep.

 

note: of course, if you like simplifying things...you can do this all in one line:

@count_battler -= watched_party - $game_party.actors

 

And, to come full circle, here's a demonstration:

irb(main):035:0> game_party = [1, 2, 3, 4]
=> [1, 2, 3, 4]
irb(main):036:0> wacthed_party = game_party.dup
=> [1, 2, 3, 4]
irb(main):037:0> count_battlers = game_party.dup
=> [1, 2, 3, 4]
irb(main):038:0> game_party.delete_at(3)
=> 4
irb(main):039:0> count_battlers -= watched_party - game_party
=> [1, 2, 3]

 

*ahem* now, with that all said and done, is there a reason why you can't just manage all this in 1 or 2 arrays? I mean, maybe it would be pretty hard to manage with just ONE array, but IMO, I think it would me much easier to use $game_party.actors (for player's party) and another array for ALL battlers in battler (ie. @count_battlers) then, just manage both at same time?

 

EDIT: LOL, you JUST beat me to it. *props*

Share this post


Link to post
Share on other sites
  • 0

Grr, ran into a problem.

 

It probably is easier, but the way ruby handles arrays seems to be very strange for me. And yeah, they have sub arrays, thus, making things much more difficult for be to wrap my head around. Im pretty much stuck using that @count_battlers (no clue why author called it that), used it, and didnt assign properties to teh $game_party.actors class instead. But that is essencially what is happening in the script.

 

There is another property in there called ".cp" which is a numeric value from 0 to 65535, when at 65535, player can input a command. Like a counter for a Progress Bar.

 

The properties dont seem to be included when using array comparison (&, |, -) so although I can go "print $game_party.actors.name" I am not able to "print @count_battlers.battler.name" or in @watched_party. @watched_party is new, comparing that to $game_party.actors but not @count_battlers because once it is initialized (using $game_party.actors), it doesnt get updated, which is what Im trying to do.

 

The problem I have is when an actor is added during the battle, since they arent in that initial array (which is all over the place in the script), their "CP" (Progress Bar) thing doesnt update. When removing them, then adding again later in the same battle, Im trying to reset their "CP", but I cant figure out how to access those methods or properties (I suck at OOP) or even get an Index by iterating and comparing each value. Even when I do something like "if added_actor == @count_battlers.battler" and they are the same, it doesnt return true for me.

 

Get some sleep, I dont wanna rack your brain that hard.

Share this post


Link to post
Share on other sites
  • 0

Hmm, would you be able to post the scripts? I might be able to get a better view of what's going on exactly.

 

Which array has sub arrays? I know the *default* $game_party.actors is a 1 dimensional array...though I dunno about the other ones (or if the scripter changed that).

 

In the meantime, perhaps I can give you a bit of advice (I hope you don't mind my long tangents....I REALLY can't help myself lol)

*you probably know some of this already, but I'll try to clarify some things, in this context*

 

First off -- Arrays in Ruby:

Arrays are very similar in all languages. In ruby arrays are ...

 

1. 0-based

-> this is true for most languages, this means that the index of the first element of an array is 0, and the index of the last element of an array is always (number of elements - 1). In ruby you can call array.size to get the number of elements in the array

array = [1, 2, 3]
puts "First element: #{array[0]}"
puts "Last element: #{array[array.size-1]}"
# Output:
# First element: 1
# Last element: 3

 

2. Dynamically Sized

-> This is one of the most convenient bits about ruby arrays. They will shrink/grow as elements are added or removed (i.e. array.push(obj) array.pop etc.) The other nice thing about this, is you can refer to an index of an array that is out of bounds without causing errors -- if out of bounds, ruby returns `nil`

array = [1]
puts array.size
array.push(1)
puts array.size
array.pop
puts array.size
puts array[50]
# Output:
# 1
# 2
# 1
# nil

 

3. Negative indices

-> If a negative index is referred to of an array, ruby grabs the element relative to the last element.

array = [1, 2, 3]
puts array[-1]
puts array[-2]
puts array[-3]
# Output:
# 3
# 2
# 1

 

4. Mixed types

-> This can be convenient, and potentially dangerous if one is not careful...but it's a feature that can be REALLY useful. A ruby array can contain any type of object, and various types as well.

array = [1, "string", 4.5, [1, "string"], nil, Time.now, 0..4]

 

There are probably more features, but these are the more important ones to keep in mind (well, also being able to enumerate/iterate over an array...but I already mentioned this)

 

Next important thing (I think *this* might be messing with you most)

In most programming languages (especially OOP languages), there are 2 main "data types" -- value types and reference types. A value type is usually what most people would call "primitive" data types (i.e. Integer, Float, Char, etc) where as a reference type is usually what people would refer to as an instance of a class.

 

The most important thing to know about these "types" are:

Value Types:

- passed by value, meaning the actual value is "copied" when passed to a method/variable

Reference Types:

- passed by reference (memory address), meaning the reference to the object is passed to a method/variable (object IS NOT copied)

 

In ruby, everything is an instance of an object (I do literally mean EVERYTHING), HOWEVER, it is EXTREMELY important to note: ALL OBJECTS ARE PASSED BY REFERENCE, EXCEPT FOR NUMERIC OBJECTS (i.e Fixnum/Integer or Floats)

This is especially important for arrays, as arrays are reference types.

Hmm...That seems confusing a bit. Perhaps an example could help:

a = [1, 2, 3] # Array is loaded into memory, then Array.new is called
# Memory address of newly created array is stored in variable `a`
b = a # a's value (memory address of [1, 2, 3]) is copied to b
b.push(4) # push 4 into array stored at address referred to by b
puts "Array A: #{a.to_s}"
puts "Array B: #{b.to_s}"
# Output:
# Array A: [1, 2, 3, 4]
# Array B: [1, 2, 3, 4]

# Notice array a.push(4) was not called, but a/b refer to the same array in memory
puts a.object_id
puts b.object_id
# Output:
# 22209828
# 22209828

 

Therefore, you should be careful when calling "Destructive" methods upon arrays. Destructive methods are methods that modify the object in place, rather than returning a modified copy:

# Array.delete is destructive
a = [1, 2, 3]
a.delete(1)
puts a
# output
# 2
# 3
# Array.reverse is not destructive
puts "a#reverse"
puts a.reverse
puts "a"
puts a
# output
# a#reverse
# 3
# 2
# a
# 2
# 3
# Array.reverse! is destructive
puts "a#reverse!"
puts a.reverse!
puts "a"
puts a
# output
# a#reverse!
# 3
# 2
# a
# 3
# 2

 

If you ever need to pass a copy of an object rather than the reference to the object, use

object#clone or object#dup

puts a.object_id
puts a.dup.object_id
puts a.clone.object_id
# output
# 23857056
# 23060688
# 22197900

 

Now, as you know (and mentioned yourself) objects have properties/methods. The really important thing here is to understand how referencing these things work.

 

Most (as far as I know) Object-Oriented languages use dot notation or the dot operator `.`

What you need to know about this, is that anything to the LEFT of the dot is an object, and anything to the RIGHT is a method/property of that object. Also, the dot operator works from left to right

 

So, in this context, `actors` is a property of $game_party (which is an instance of the Game_Party class)

$game_party . actors
object <      > property

in Game_Party, actors is an array object containing all the current actors in the hero's party.

(note: each element of $game_party.actors is an instance of the Game_Actor class, which has it's own properties and methods)

After $game_party.actors is invoked, the actors array is returned (as an object) to the calling statement...i.e, if you wrote this:

a = $game_party.actors

a will be a reference to the $game_party.actors object

 

Or a more detailed example:

a = $game_party.actors.dup

$game_party -> object

actors -> property of Game_Party

dup -> method of Object (in this case the object is the actors array)

 

finally, dup returns to this statement, putting a reference to a copy of $game_party.actors into `a`

 

So, a property of any object can be called from an instance of that object.

Note:

print $game_party.actors.name

works because $game_party has a property called actors, that is an array, which has an element which has a property called name

print @count_battlers.battler.name

does not work, because (as far as I understand), @count_battlers is an array. Array objects do NOT have a property called battler. If you wanted to print the contents of @count_battlers, you would be better off doing:

print @count_battlers[i].inspect
# If @count_battlers is an array of battlers,
print @count_battlers[i].name # will work
# My favourite however, for printing array contents:
print @count_battlers.inspect # no loop required, and displays ALL elements at once

 

In regards to array comparisons, you seem to be a *bit* mixed up:

<, <=, ==, >=, >, != are comparison operators, where as

&, |, - are special array operators (with other objects, these operators have other meanings)

 

array & other_ary

-> array intersection, returns a new array containing only elements common to array and other_ary, with duplicates omitted:

irb(main):044:0> [1, 2, 3] & [1, 2, 3, 4]
=> [1, 2, 3]

 

array | other_ary

-> array join, returns a new array containing all elements of array and other_ary, with duplicates omitted:

irb(main):046:0> [1, 2, 3] | [1, 2, 3, 4]
=> [1, 2, 3, 4]

 

array - other_ary

-> array difference, returns a copy of array with any items that appear in other_ary removed:

irb(main):047:0> [1, 2, 3, 4] - [1, 2, 3]
=> [4]

 

 

As for the last bit, I'd have to look at the script in question to help you there. Although, perhaps I may be able to shed some light on "if added_actor == @count_battlers.battler"

 

Unless the == method has been defined for an object, object == other_object will compare references, rather than the object itself. So, even if added_actor is "the same" as @count_battlers.battler, if either one of those objects are a COPY of the original, that statement will ALWAYS return false.

 

*Ahem* ANYWAYS, you don't need to read through all that, just thought I'd ramble again. Hopefully it makes sense, if you need further clarification, just ask.

 

Though, if you'd like to post the script, I could look over it for you. It would be easier to explain if I knew EXACTLY what each variable was. Right now, I'm just kinda taking stabs in the dark at finding you a solution.

Share this post


Link to post
Share on other sites
  • 0

I'll reply again in a sec, but as requested, here is the script. It is HUGE. Section I am working on starts about line 500. Gah! Overloaded the Forum, posting as link...

 

http://www.775.net/~heretic/downloads/ATBWIP.txt

(NON DEVS DO NOT USE - NOT STABLE)

 

Huh? Post Too Short error from the FOrum? Hope this fixes...

Share this post


Link to post
Share on other sites
  • 0

This actually clears a LOT up for me. For one, I didnt know that Ruby handled everything by Reference instead of by Value. It would seem to imply that creating a new array as a temporary placeholder and making attempts to modify that would modify the original objects properties.

 

I found the "inspect" method earlier, but didnt think to try to use print object.inspect, that pumped out some very useful data.

 

As for the script itself, it is so hard to work with, all of the Comments in it are foreign language characters that no longer translate, and I cant seem to find a translatable copy. Failing isnt bothering me either because I am learning a great deal more from my Failures, and the explanations of how and why it is failing. I know damn well it took some time to write that, so your efforts are not wasted at all, and very very appreciated. This thread seems to be turning into my Ruby Bible until I have a solid understanding of everything mentioned here. Very very different from PHP.

Share this post


Link to post
Share on other sites
  • 0

I had to put this down for a few days. Cooked my brain pan! Kel, had any chance to take a look and figure out why this script is not able to directly modify those arrays?

Share this post


Link to post
Share on other sites
  • 0

Just create a clone of the array when you sets its value, then use that. Since they no longer are pointing to the same reference, changes to one will not effect the other.

 

old_party = $game_party.actors.clone

Share this post


Link to post
Share on other sites
  • 0

Then I wont be able to compare values in the cloned array to the other if not by reference. Probably a Ruby thing that I am definitely not used to, but using that, trying to do this:

 

old_party.actor[1] == $game_party.actor[1]

 

Always returns false if not by reference.

 

Suggestions?

Share this post


Link to post
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
Sign in to follow this  

  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...