Not logged inGosu Forums
Forum back to libgosu.org Help Search Register Login
Up Topic Gosu / Gosu Showcase / Cptn. Ruby MAP EDITOR
- By AmIMeYet Date 2009-02-16 21:10
What?
           A map editor for Cptn. Ruby.

Why?
          Because.

No, seriously, why?
          Because I needed to have a starting project.

Current version?
          Version 1.0

Screenshots?
Sure:


Should we credit you if we use this?
Yeah! It's not much, but I've made this script; and no-one should get credit where it's not due..
So, just credit me, AmIMeYet, if you use this..

Requirements?
Ruby
Gosu
The Cptn. Ruby example (comes with gosu, in the 'example' directory)

How do I install it?
Put the script inside the folder you've got the Cptn. Ruby example in, and run it.

How do I use it?
Use buttons 1-4 to select the Earth, Grass, Gem and Erase tiles.
The current selection will be placed in the title bar, along with the tile currently hovering over.
Click with the left mouse button to apply the currently selected tile to the map.
Press S to save, and overwrite the default map file (so back that one up!)

Any bugs?
If you launch the editor, and then go do something else on your computer, it crashes.. so always SAVE.

And the code?
Here you go:
http://amimeyet.890m.com/misc/editor.txt

Or if that's down:
=begin
  An editor for the oh so popular game 'Cptn. Ruby'!
  Made by AmIMeYet
  Version 1.0
  Buttons:
    Left Mouse Button: Add Tile
    1: Select Earth (#)
    2: Select Grass (")
    3: Select Gem   (x)
    4: Erase
    S: Save map (overwrite)
=end
#media/Editor Tileset.png -> CptnRuby Tileset.png
# -> CptnRuby.png
# Editor Gem -> CptnRuby Gem.png

begin
  # In case you use Gosu via rubygems.
  require 'rubygems'
rescue LoadError
  # In case you don't.
end

require 'gosu'
include Gosu

# Module tiles defines the types of tile
module Tiles
  Grass = 0
  Earth = 1
end

# CollectibleGem is a class to show gems
class CollectibleGem
  attr_reader :x, :y

  def initialize(image, x, y)
    @image = image
    @x, @y = x, y
  end
 
  def draw(screen_x, screen_y)
    @image.draw(@x - screen_x - 5, @y - screen_y -5, 0, 0.5, 0.5)
    #-5 == offset#
  end
end

# MousePointer class adds a nice little cursor to the window
class MousePointer
  attr_reader :x, :y

  def initialize(window, image)
    @image = Image.new(window, image, false)
    @x = window.mouse_x
    @y = window.mouse_y
  end

  def draw(window)
    @image.draw($edwin.mouse_x, $edwin.mouse_y, 0)
  end

end

# Map class holds and draws tiles and gems.
class Map
  attr_reader :width, :height, :gems, :tiles
 
  def initialize(window, filename)
    # Load 60x60 tiles, 5px overlap in all four directions.
    @tileset = Image.load_tiles(window, "media/CptnRuby Tileset.png", 60, 60, true)
    @sky = Image.new(window, "media/Space.png", true)

    gem_img = Image.new(window, "media/CptnRuby Gem.png", false)
    @gems = []

    $lines = File.readlines(filename).map { |line| line.chop }
    @height = $lines.size
    @width = $lines[0].size
   
    @tiles = Array.new(@width) do |x|
      Array.new(@height) do |y|
        case $lines[y][x, 1]
        when '"'
          Tiles::Grass
        when '#'
          Tiles::Earth
        when 'x'
          @gems.push(CollectibleGem.new(gem_img, x * 20 + 5, y * 20 + 5)) # 5 > 25
          nil
        else
          nil
        end
      end
    end
  end
 
  def reload
    @height = $lines.size
    @width = $lines[0].size
    gem_img = Image.new($edwin, "media/CptnRuby Gem.png", false)
    @gems = []
   
    @tiles = Array.new(@width) do |x|
      Array.new(@height) do |y|
        case $lines[y][x, 1]
        when '"'
          Tiles::Grass
        when '#'
          Tiles::Earth
        when 'x'
          @gems.push(CollectibleGem.new(gem_img, x * 20 + 5, y * 20 + 5)) # 5 > 25
          nil
        else
          nil
        end
      end
    end
  end
 
  def draw(screen_x, screen_y)
    # Sigh, stars!
    @sky.draw(0, 0, 0)
    # Very primitive drawing function:
    # Draws all the tiles, some off-screen, some on-screen.
    @height.times do |y|
      @width.times do |x|
        tile = @tiles[x][y]
        if tile
          # Draw the tile with an offset (tile images have some overlap)
          # Scrolling is implemented here just as in the game objects.
          @tileset[tile].draw(x * 20 - screen_x - 5, y * 20 - screen_y - 5, 0, 0.5, 0.5)
        end
      end
    end
    @gems.each { |c| c.draw(screen_x, screen_y) }
  end
 
  # Solid at a given pixel position?
  def solid?(x, y)
    y < 0 || @tiles[x / 20][y / 20]
  end
end

# Ted class handles editing functions
class Ted
  attr_reader :type
 
  def initialize
    @type = "#"
  end
 
  def save
     file = File.new("media/CptnRuby Map.txt", "w+")
     file.puts($lines)
     file.close
  end
 
  def load
      $edwin.map.reload
  end
   
  def set_type(btn)
      case btn
       when "1"
        @type = "#"
       when "2"
        @type = "\""
       when "3"
        @type = "x"
      else
        @type = "."
     end
  end
 
  def clicked(sx, sy)
    mx = $edwin.mouse_x
    my = $edwin.mouse_y
    ry = ((sy + my) / 20).floor
    rx = ((sx + mx) / 20).floor    
    $lines[ry][rx] = @type
    load
  end
 
end

# The Game class is the main window
class Game < Window
  attr_reader :map
  attr_reader :mouse
 
  WIDTH = 640
  HEIGHT = 480

  def initialize   
    super(WIDTH , HEIGHT, false)
    self.caption = "Cptn. Ruby"
    @map = Map.new(self, "media/CptnRuby Map.txt")
    @mouse = MousePointer.new(self, "media/cursor.png")
    @ted = Ted.new
    # Scrolling is stored as the position of the top left corner of the screen.
    @screen_x = @screen_y = 0
    @font = Gosu::Font.new(self, Gosu::default_font_name, 20)
  end
  def update
    move_x = 0
    move_x -= 5 if atedge?("left")
    move_x += 5 if atedge?("right")
    move_y = 0
    move_y -= 5 if atedge?("up")
    move_y += 5 if atedge?("down")
   
    tempscreen_x = @screen_x + move_x
    tempscreen_y = @screen_y + move_y
    if tempscreen_x <= 0
      tempscreen_x = 0
    elsif tempscreen_x >= @map.width * 20 - WIDTH
     tempscreen_x = @map.width * 20 - WIDTH
    end
    if tempscreen_y <= 0
      tempscreen_y = 0
    elsif tempscreen_y >= @map.height * 20 - HEIGHT
     tempscreen_y = @map.height * 20 - HEIGHT
    end
    @screen_x = tempscreen_x
    @screen_y = tempscreen_y
   
    cx = ((@screen_x + mouse_x) / 20).floor
    cy = ((@screen_y+ mouse_y) / 20).floor
    case @ted.type
      when '#'
        ct = "Earth"
      when '"'
        ct = "Grass"
      when 'x'
        ct = "Diamond"
      when '.'
        ct = "Erase"
      end
    self.caption = "Capt. Ruby - Editor (#{cx}; #{cy}; #{ct})"
  end
  def draw
    @map.draw @screen_x, @screen_y
    @mouse.draw self
    @font.draw(@message, 10, 10, 999, 1.0, 1.0, 0xffffff00)
  end
  def button_down(id)
    if id == Button::KbEscape then close end
    if id == Button::Kb1 then @ted.set_type("1") end
    if id == Button::Kb2 then @ted.set_type("2") end
    if id == Button::Kb3 then @ted.set_type("3") end
    if id == Button::Kb4 then @ted.set_type("4") end
    if id == Button::MsLeft then @ted.clicked(@screen_x, @screen_y) end
    if id == Button::KbS then @ted.save end
  end
  def atedge?(dir)
    val = false
    case dir
      when "left"
        if mouse_x.between?(0, 20)
        val = true
        end
      when "right"
        if mouse_x.between?(620, 6405)
        val = true
        end
      when "up"
        if mouse_y.between?(0, 20)
        val = true
        end
      when "down"
        if mouse_y.between?(460, 480)
        val = true
        end
      end
      return val
  end
end

# Set window as new window and show it (edwin == Editor Window)
$edwin = Game.new
$edwin.show
- By banister Date 2009-02-26 14:32
nice work :) and a cool first project
- By AmIMeYet Date 2009-02-26 19:49
Thanks!
- By Shinobi Chef Date 2009-05-14 14:14
Hey AmiMeYet

Great work with the map editor for Cptn Ruby

though when I ran it the sprites(gems) where not placed where they should have been
they where a bit lower than where they should have been (compared to where they are when you play Cptn Ruby)

so I edited the source code and now it works fine(for me at lease)

please try out the changes Ive made and see what you think

I plan to use the new version of your map editor for my game Arthur's Adventures,hope you don't mind,I will give you full credit of course

Here is the source code for the new version I made

=begin
Originaly an Level Editor for the oh so popular game 'Cptn. Ruby'!
  Made by AmIMeYet
  Modifyed by Shinobi Chef
  Now the Level Editor for Arthur's Adventure
  Version 1.1
  Buttons:
    Left Mouse Button: Add Tile
    1: Select Earth (#)
    2: Select Grass (")
    3: Select Gold   (x)
    4: Erase
    5: Select Blue Shield (s)
    S: Save map (overwrite)
=end
#media/Editor Tileset.png -> CptnRuby Tileset.png
# -> CptnRuby.png
# Editor Gold -> CptnRuby Gold.png

begin
  # In case you use Gosu via rubygolds.
  require 'rubygolds'
rescue LoadError
  # In case you don't.
end

require 'gosu'
include Gosu

# Module tiles defines the types of tile
module Tiles
  Grass = 0
  Earth = 1
end

# CollectibleGold is a class to show golds
class CollectibleGold
  attr_reader :x, :y

  def initialize(image, x, y)
    @image = image
    @x, @y = x, y
  end
 
  def draw(screen_x, screen_y)
    @image.draw(@x - screen_x - 5, @y - screen_y -5, 0, 0.5, 0.5)
    #-5 == offset#
  end
end

class CollectibleBlueshield
  attr_reader :x, :y

  def initialize(image, x, y)
    @image = image
    @x, @y = x, y
  end
 
  def draw(screen_x, screen_y)
    @image.draw(@x - screen_x - 5, @y - screen_y -5, 0, 0.5, 0.5)
    #-5 == offset#
  end
end

# MousePointer class adds a nice little cursor to the window
class MousePointer
  attr_reader :x, :y

  def initialize(window, image)
    @image = Image.new(window, image, false)
    @x = window.mouse_x
    @y = window.mouse_y
  end

  def draw(window)
    @image.draw($edwin.mouse_x, $edwin.mouse_y, 0)
  end

end

# Map class holds and draws tiles and golds.
class Map
  attr_reader :width, :height, :golds, :tiles, :blueshields
 
  def initialize(window, filename)
    # Load 60x60 tiles, 5px overlap in all four directions.
    @tileset = Image.load_tiles(window, "media/CptnRuby Tileset.png", 60, 60, true)
    @sky = Image.new(window, "media/skybackground.png", true)

    gold_img = Image.new(window, "media/gold.png", false)
    @golds = []

     blueshield_img = Image.new(window, "media/blueshield.png", false)
    @blueshields = []

    $lines = File.readlines(filename).map { |line| line.chop }
    @height = $lines.size
    @width = $lines[0].size
   
    @tiles = Array.new(@width) do |x|
      Array.new(@height) do |y|
        case $lines[y][x, 1]
        when '"'
          Tiles::Grass
        when '#'
          Tiles::Earth
        when 's'
          @blueshields.push(CollectibleBlueshield.new(blueshield_img, x * 25 + 2, y * 25 + 2))
          nil
        when 'x'
          @golds.push(CollectibleGold.new(gold_img, x * 25 + 2 , y * 25 + 2)) # 5 > 25
          nil
        else
          nil
        end
      end
    end
  end
 
  def reload
    @height = $lines.size
    @width = $lines[0].size
    gold_img = Image.new($edwin, "media/gold.png", false)
    @golds = []
   
    blueshield_img = Image.new($edwin, "media/blueshield.png", false)
    @blueshields = []
   
    @tiles = Array.new(@width) do |x|
      Array.new(@height) do |y|
        case $lines[y][x, 1]
        when '"'
          Tiles::Grass
        when '#'
          Tiles::Earth
          when 's'
          @blueshields.push(CollectibleBlueshield.new(blueshield_img, x * 25 + 2, y * 25 + 2))
          nil         
        when 'x'
          @golds.push(CollectibleGold.new(gold_img, x * 25 + 2, y * 25+ 2)) # 5 > 25
          nil
        else
          nil
        end
      end
    end
  end
 
  def draw(screen_x, screen_y)
    # Sigh, stars!
    @sky.draw(0, 0, 0)
    # Very primitive drawing function:
    # Draws all the tiles, some off-screen, some on-screen.
    @height.times do |y|
      @width.times do |x|
        tile = @tiles[x][y]
        if tile
          # Draw the tile with an offset (tile images have some overlap)
          # Scrolling is implemented here just as in the game objects.
          @tileset[tile].draw(x * 25 - screen_x - 5, y * 25 - screen_y - 5, 0, 0.5, 0.5)
        end
      end
    end
    @golds.each { |c| c.draw(screen_x, screen_y) }
    @blueshields.each { |c| c.draw(screen_x, screen_y) }
  end
 
  # Solid at a given pixel position?
  def solid?(x, y)
    y < 0 || @tiles[x / 25][y / 25]
  end
end

# Ted class handles editing functions
class Ted
  attr_reader :type
 
  def initialize
    @type = "#"
  end
 
  def save
     file = File.new("maps/level1.txt", "w+")
     file.puts($lines)
     file.close
  end
 
  def load
      $edwin.map.reload
  end
   
  def set_type(btn)
      case btn
       when "1"
        @type = "#"
       when "2"
        @type = "\""
        when "5"
        @type = "s"
       when "3"
        @type = "x"
      else
        @type = "."
     end
  end
 
  def clicked(sx, sy)
    mx = $edwin.mouse_x
    my = $edwin.mouse_y
    ry = ((sy + my) / 25).floor
    rx = ((sx + mx) / 25).floor    
    $lines[ry][rx] = @type
    load
  end
 
end

# The Game class is the main window
class Game < Window
  attr_reader :map
  attr_reader :mouse
 
  WIDTH = 640
  HEIGHT = 480

  def initialize   
    super(WIDTH , HEIGHT, false)
    self.caption = "Arthur's Adventures - Level Editor"
    @map = Map.new(self, "maps/level1.txt")
    @mouse = MousePointer.new(self, "media/cursor.png")
    @ted = Ted.new
    # Scrolling is stored as the position of the top left corner of the screen.
    @screen_x = @screen_y = 0
    @font = Gosu::Font.new(self, Gosu::default_font_name, 25)
  end
  def update
    move_x = 0
    move_x -= 5 if atedge?("left")
    move_x += 5 if atedge?("right")
    move_y = 0
    move_y -= 5 if atedge?("up")
    move_y += 5 if atedge?("down")
   
    tempscreen_x = @screen_x + move_x
    tempscreen_y = @screen_y + move_y
    if tempscreen_x <= 0
      tempscreen_x = 0
    elsif tempscreen_x >= @map.width * 25 - WIDTH
     tempscreen_x = @map.width * 25 - WIDTH
    end
    if tempscreen_y <= 0
      tempscreen_y = 0
    elsif tempscreen_y >= @map.height * 25 - HEIGHT
     tempscreen_y = @map.height * 25 - HEIGHT
    end
    @screen_x = tempscreen_x
    @screen_y = tempscreen_y
   
    cx = ((@screen_x + mouse_x) / 25).floor
    cy = ((@screen_y+ mouse_y) / 25).floor
    case @ted.type
      when '#'
        ct = "Earth"
      when '"'
        ct = "Grass"
      when 's'
        ct = "Blue Shield"
      when 'x'
        ct = "Gold"
      when '.'
        ct = "Erase"
      end
    self.caption = "Arthur's Adventures - Level Editor (#{cx}; #{cy}; #{ct})"
  end
  def draw
    @map.draw @screen_x, @screen_y
    @mouse.draw self
    @font.draw(@message, 10, 10, 999, 1.0, 1.0, 0xffffff00)
  end
  def button_down(id)
    if id == Button::KbEscape then close end
    if id == Button::Kb1 then @ted.set_type("1") end
    if id == Button::Kb2 then @ted.set_type("2") end
    if id == Button::Kb3 then @ted.set_type("3") end
    if id == Button::Kb4 then @ted.set_type("4") end
    if id == Button::Kb5 then @ted.set_type("5") end
    if id == Button::MsLeft then @ted.clicked(@screen_x, @screen_y) end
    if id == Button::KbS then @ted.save end
  end
  def atedge?(dir)
    val = false
    case dir
      when "left"
        if mouse_x.between?(0, 25)
        val = true
        end
      when "right"
        if mouse_x.between?(620, 6405)
        val = true
        end
      when "up"
        if mouse_y.between?(0, 25)
        val = true
        end
      when "down"
        if mouse_y.between?(460, 480)
        val = true
        end
      end
      return val
  end
end

# Set window as new window and show it (edwin == Editor Window)
$edwin = Game.new
$edwin.show
- By AmIMeYet Date 2009-05-14 16:42
I'd be honored!

Though, I'm afraid I can't test your source.. I don't have blueshield's and gold. .. ..  Have you posted the right version? (as Gold should be Gems for cpt. Ruby)

Also, I'm working on a game of my own (a small, simple thing to show my teacher I'm already familliar with OO-programming, so I don't have to use some dumb point-and-click game program), and I'm thinking about making a small editor thingy on the side..
So I'm thinking on improving it too... making it more user-friendly, etc.
Like pressing UI-buttons in the editor, instead of pressing 1,2,3 and 4 on your keyboard.
- By Shinobi Chef Date 2009-05-15 07:53
Hey AmiMeYet

whats your email address ,ill send you the other files u need if you want,like blueshield.png and gold.png

or you can make a copy of original gem file and rename it to blueshield.png same goes for gold.png

as far as gems not being in the source code any more,its because I am using gold now in place of gems so I though it would be best to rename it in the code too

run your map editor(v1.0) look at where the gems are placed that are the position above ground or grass tiles,the gem is partly inside the ground or grass tile,that how it appears for me any way

Talk to you soon
Shinobi Chef
- By Shinobi Chef Date 2009-05-15 08:12
Hey AmiMeYet
Your idea of using UI buttons in an improved version of your editor sounds great

Would you like to make a similar version of your editor but for my game "Arthur's Adventures"?
as they are almost the same except my game will have more tiles and objects that you can place

What is this game you are working on? what type of game is it?

Bye for now
Shinobi Chef
- By AmIMeYet Date 2009-05-15 09:33 Edited 2009-05-15 10:50
Merely a small and simple rpg (without the roleplay part :p) thingy..
But all there is is 1 or 2 players, a map built of '#'s and other characters saying stuff.
It's really low-tech.

Also.. I haven't even started on the map editor!
I'm a little too busy with the game right now.

Also, about the email.. I hate spam.. so I'll give you one of my spam-accounts.. (security layer #1).
It's in the attachment (security layer #2)

Edit: Do you have msn? If so, mail your msn address to me.
Up Topic Gosu / Gosu Showcase / Cptn. Ruby MAP EDITOR

Powered by mwForum 2.29.7 © 1999-2015 Markus Wichitill