Envision, Create, Share

Welcome to HBGames, a leading amateur game development forum and Discord server. All are welcome, and amongst our ranks you will find experts in their field from all aspects of video game design and development.

rxdata help/ data structure issue

ok so ive been working on my interactive map script. and ive been trying really hard to get the game to properly store and recover my map data so i can make a simple editor so people who cant script can use the mouse to make thier map. anyways here is what the data currently looks like
Map_Items::Town.new(80,130,1,8,4,2,"town3","Saar",1)
and here is my data structure if u need it
Code:
#==============================================================================

# ** Data::Object, Map_Items::Town, Sub::Town

#------------------------------------------------------------------------------

#  These classes were created by SephirothSpawn

#==============================================================================

module Map_Items

  Towns = {}

end

module Sub

  Towns = {}

end

class Data::Object

  @@ids = {}

  @@containers = {}

  attr_accessor :id

  def initialize

    @@ids[self.class] = 0 unless @@ids.has_key?(self.class)

    @@ids[self.class] += 1

    @id = @@ids[self.class]

    if @@containers.has_key?(self.class)

      @@containers[self.class][@id] = self

    end

  end

  def self.add_container(class_name, container)

    @@containers[class_name] = container

  end

end

class Map_Items::Town < Data::Object

  Data::Object.add_container(self, Map_Items::Towns)

  attr_reader :screen_x

  attr_reader :screen_y

  attr_reader :map_id

  attr_reader :map_x

  attr_reader :map_y

  attr_reader :direction

  attr_reader :icon

  attr_reader :town_name

  attr_reader :switch

  def initialize(screen_x, screen_y, map_id, map_x, map_y, direction, icon, town_name, switch)

   super()

    @screen_x = screen_x

    @screen_y = screen_y

    @map_id = map_id

    @map_x = map_x

    @map_y = map_y

    @direction = direction

    @icon = icon

    @town_name = town_name

    @switch = switch

  end

end

 

class Sub::Town < Data::Object

  Data::Object.add_container(self, Sub::Towns)

  attr_reader :screen_x

  attr_reader :screen_y

  attr_reader :map_id

  attr_reader :map_x

  attr_reader :map_y

  attr_reader :direction

  attr_reader :icon

  attr_reader :town_name

  attr_reader :switch

  attr_reader :upper_level

  def initialize(screen_x, screen_y, map_id, map_x, map_y, direction, icon, town_name, switch, upper_level)

   super()

    @screen_x = screen_x

    @screen_y = screen_y

    @map_id = map_id

    @map_x = map_x

    @map_y = map_y

    @direction = direction

    @icon = icon

    @town_name = town_name

    @switch = switch

    @upper_level = upper_level

  end

end

#==============================================================================

# ** Sprite_Cursor

#------------------------------------------------------------------------------

#  This sprite is used to display the cursor for World_Map.

#==============================================================================

 

class Sprite_Cursor < Sprite

 def initialize(viewport = Viewport.new(0, 0, 0, 0))

    super(viewport)

    update

  end

  #--------------------------------------------------------------------------

  # * Dispose

  #--------------------------------------------------------------------------

  def dispose

    if self.bitmap != nil

      self.bitmap.dispose

    end

    super

  end

  #--------------------------------------------------------------------------

  # * Frame Update

  #--------------------------------------------------------------------------

  def update

    super

  end

end

#==============================================================================

# ** Window_Map

#------------------------------------------------------------------------------

#  This window displays the name box for World_Map

#==============================================================================

 

class Window_Map < Window_Base

  #--------------------------------------------------------------------------

  # * Object Initialization

  #--------------------------------------------------------------------------

  def initialize

    super(0, 0, 640, 64)

    self.contents = Bitmap.new(width - 32, height - 32)

    self.z = 2010

    @text = ""

  end

  def text=(text)

    if @text != text

      @text = text

      self.contents.clear

      self.contents.draw_text(0, 0, contents.width, 32, @text, 1)

    end

  end

end

 

 

ive managed to get the game to store the data into a rxdata file, and when i open it in notepad it looks right. but i cant seem to get the data back out properly. so i was wondering if some one could show me a simple example of storeing data and recovering it.

p.s. btw the reason im asking for rxdata is so people can copy and paste from editor to game with no issues
p.s.s. its really late sorry if i forgot anything you need to know
 
all ready tried that, didnt work. was deleating multipule items when i passed just 2. i am trying to find a way to delete just the object in index 2, not everything with a specific value. i tried everything that was in the help help and none of it seemed to do what i needed
 
Well the problem is that Towns is a hash and not an array, and therefore doesn't provide indexes...
You could convert the hash into 2 arrays ( one for the keys and one for the values) and then you could delete that index "2"...

Problem, hash aren't sorted by order of entry... so the resulting array of value would be quite unpredictable and deleting that index 2 could be not what you want.

Also be careful, cause you're mixing indexes ( a position in an array ) with keys ( an id linked to a value )... deleting the 3rd item and deleting the item called "2" isn't the same at all.

The way things are created with that class is fairly simple: Each item is attributed an id at the creation, starting at 0, to make it act like an array :).
So weirdly enough you shouldn't get several items with the same id... when you said that it deleted several items.

With hash you can't have multiple values with the same key. So you must do something wrong... could you show us the code where you want to delete stuff so we have some context to see what's happening.?
 
allrighty, so here are some related methods so you can see whats going on. im making an editor for my Interactive world map script, it works perfect except for when i try to delete a town. which i guess is an object in my hash(i thought it was an array :( thats what i get for being self taught)
Code:
 

def draw_all_towns

    for i in 1...Map_Items::Towns.size+1

      if i != @dont_draw

        if Map_Items::Towns[i] != nil

          bitmap = RPG::Cache.icon(Map_Items::Towns[i].icon)

self.contents.blt(Map_Items::Towns[i].screen_x-(bitmap.width/2),Map_Items::Towns[i].screen_y-(bitmap.height/2), bitmap, Rect.new(0,0,bitmap.width,bitmap.height))

        end  

      end

    end

  end 

 

def select_town

      for i in 1...Map_Items::Towns.size+1

        if @cursor.x > Map_Items::Towns[i].screen_x-Map_Settings.pixel_offset && @cursor.x < Map_Items::Towns[i].screen_x + RPG::Cache.icon(Map_Items::Towns[i].icon).width + Map_Settings.pixel_offset

          if @cursor.y > Map_Items::Towns[i].screen_y-Map_Settings.pixel_offset && @cursor.y < Map_Items::Towns[i].screen_y + RPG::Cache.icon(Map_Items::Towns[i].icon).height + Map_Settings.pixel_offset

            @dont_draw = i

          end

        end 

      end 

    end  

 

def draw_town_under_cursor

      bitmap = RPG::Cache.icon(Map_Items::Towns[@dont_draw].icon)

      self.contents.blt(@cursor.x-(bitmap.width/2), @cursor.y-(bitmap.height/2), bitmap, Rect.new(0,0,bitmap.width,bitmap.height))

    end 

 

def place_town

      if @dont_draw != nil

        Map_Items::Towns[@dont_draw].screen_x = @cursor.x

        Map_Items::Towns[@dont_draw].screen_y = @cursor.y

        @dont_draw = nil

      end

end  

 

 
and here is the method in question:
Code:
def del_selection

      num = @dont_draw #store because i need to set dont draw to nil

      @dont_draw = nil # set to nil so draw_all_towns doesnt crash when i delete

      #and this would be where i need to delete the Map_Items::Town object inside of Map_Items::Towns

      refresh

end

hope i gave you enough info, there is tons of code to my script and since i changed up my whole data structure(to remove constants and some bugs) there is alot of dirty code. but if u need anything else im more then willing to suply it
 
ok, well I don't really see what's wrong with the way of doing "hash.delete(num)"

ANyway, I see really bad coding here :p
If you parse an array or a hash, with "for"

You better do this in you case, where the index isn't that important, you could directly use the current item being parsed :
Code:
for item in my_array

that saves you writing calculus for specific indexes, and makes sure going through each item.
You could pass the item to delete in the end.

or as we're working with a hash, you could use "each_pair"
[rgss]my_hash.each_pair do |key, value|
 # do stuff with the key, or the value or both
 if key == something
    p value
 end
end
[/rgss]

It would be easier to read :) ^^ and understand

If you want to go to the next object in the loop , for whatever reason, ( invalid value for example )
rather than doing a "if" for the valid code,
you can use "next"


like in :
Code:
 

for i in 0..9

 p "before next"

 next if i % 2 == 0 # skips even number values 

 p i

end

 


You can also for an hash, work independently with either the values or the keys, as arrays :

my_hash.values

or

my_hash.keys

will return an array containing those.

Hope that helps :) !!^^

ALso read this:
http://www.ruby-doc.org/core/classes/Hash.html
 
i in the end did get delete to work, i just passed it town_name, because that is unique to each town, just as index would be. i know there is some bad code, i type it so i can read it first, then clean it up before i release. thanks aton for your guys input.
 
Why to you make Map_Items::Towns and Sub::Towns constants?
If you want those to be options which can be easily changed by the player it's a good choice. But you shouldn't save and load constants.
If you want those to be lists which change during the game you should include them in some other class, preferably $game_system/Game_System. There you don't need to care about saving and loading as this is already done with $game_system and you can still access you variables easily.
 
they are not constants here is the classes they are from:
Code:
#==============================================================================

# ** Data::Object, Map_Items::Town, Sub::Town

#------------------------------------------------------------------------------

#  These classes were created by SephirothSpawn

#==============================================================================

module Map_Items

  Towns = {}

end

module Sub

  Towns = {}

end

class Data::Object

  @@ids = {}

  @@containers = {}

  attr_accessor :id

  def initialize

    @@ids[self.class] = 0 unless @@ids.has_key?(self.class)

    @@ids[self.class] += 1

    @id = @@ids[self.class]

    if @@containers.has_key?(self.class)

      @@containers[self.class][@id] = self

    end

  end

  def self.add_container(class_name, container)

    @@containers[class_name] = container

  end

end

class Map_Items::Town < Data::Object

  Data::Object.add_container(self, Map_Items::Towns)

  attr_accessor :screen_x

  attr_accessor :screen_y

  attr_accessor :map_id

  attr_accessor :map_x

  attr_accessor :map_y

  attr_accessor :direction

  attr_accessor :icon

  attr_accessor :town_name

  attr_accessor :switch

  def initialize(screen_x, screen_y, map_id, map_x, map_y, direction, icon, town_name, switch)

   super()

    @screen_x = screen_x

    @screen_y = screen_y

    @map_id = map_id

    @map_x = map_x

    @map_y = map_y

    @direction = direction

    @icon = icon

    @town_name = town_name

    @switch = switch

  end 

end

 

class Sub::Town < Data::Object

  Data::Object.add_container(self, Sub::Towns)

  attr_accessor :screen_x

  attr_accessor :screen_y

  attr_accessor :map_id

  attr_accessor :map_x

  attr_accessor :map_y

  attr_accessor :direction

  attr_accessor :icon

  attr_accessor :town_name

  attr_accessor :switch

  attr_accessor :upper_level

  def initialize(screen_x, screen_y, map_id, map_x, map_y, direction, icon, town_name, switch, upper_level)

   super()

    @screen_x = screen_x

    @screen_y = screen_y

    @map_id = map_id

    @map_x = map_x

    @map_y = map_y

    @direction = direction

    @icon = icon

    @town_name = town_name

    @switch = switch

    @upper_level = upper_level

  end

end
 
But you shouldn't save and load constants.
He isn't actually. He declares an empty constant and then merge it with the one saved in the save game data. Since the constant is an actual Hash (or works just like one) and not just a Constant, that's OK, it's just one way of many ones you can pick up to make some good use of Hashes.

Don't get fool by Enterbrain weird anti-rubyish ways of abusing of the creation of several extra $global variables for no good reason. Just take a look at all the $data_ variables they included in Scene_Title, they could have been Constants or Module methods instead.
 
@ Infamous Z: Yes, I see:
Code:
module Map_Items

  Towns = {}

end

module Sub

  Towns = {}

end
They are constants :O

@ kyonides: You're mixing up variables and objects.
It's a constant variable which is pointing to a Hash instance.
And that's not what constant should be used for. As the name says, constants are constant. They should be declared once and after that only used for reading data from them.
 
well its what seph originally suggested to me and the script is complete(unless more bugs appear) so unless you have a really good reason for me to rewrite my whole script(again) im not gonna change it, as it is working quite well atm
 
No, it's just another style, not necessarily a bad style and this isn't the first place I find such things and it's better than using a global variable for such a simple task. Believe me in Ruby Constants don't work in the same way they would in C or C++. If they did, we wouldn't be able to even reopen an existing RGSS default class. He could also used some @@variable, but since that Town or Towns hash, because that's what it is, won't ever change its class condition, a hash, we're not changing its nature. It's a bad idea to use a Constant if you set it as a String at first and then you change it to become an Array. Since that never happened here, it's still a Hash, only its hash keys and values changed, it's acting more like a class or module name does. So, it's correct and useful.
 
but since that Town or Towns hash, because that's what it is, won't ever change its class condition, a hash, we're not changing its nature.
But he is changing its content and in my opinion that shouldn't be done with constants. I think if a constant is used "good", you can always add a
constant.freeze
after its declaration and still nothing should cause errors.
 

Thank you for viewing

HBGames is a leading amateur video game development forum and Discord server open to all ability levels. Feel free to have a nosey around!

Discord

Join our growing and active Discord server to discuss all aspects of game making in a relaxed environment. Join Us

Content

  • Our Games
  • Games in Development
  • Emoji by Twemoji.
    Top