dxopal 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +5 -0
- data/.ignore +5 -0
- data/.nojekyll +4 -0
- data/CHANGELOG.md +90 -0
- data/DEVELOPMENT.md +57 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +39 -0
- data/README.md +22 -0
- data/Rakefile +66 -0
- data/TODO.md +278 -0
- data/build/dxopal.js +46590 -0
- data/build/dxopal.min.js +1 -0
- data/config.ru +39 -0
- data/doc/api/DXOpal.html +129 -0
- data/doc/api/DXOpal/Font.html +485 -0
- data/doc/api/DXOpal/Image.html +2533 -0
- data/doc/api/DXOpal/Input.html +1086 -0
- data/doc/api/DXOpal/Input/MouseCodes.html +146 -0
- data/doc/api/DXOpal/RemoteResource.html +641 -0
- data/doc/api/DXOpal/Sound.html +568 -0
- data/doc/api/DXOpal/SoundEffect.html +444 -0
- data/doc/api/DXOpal/SoundEffect/WaveTypes.html +130 -0
- data/doc/api/DXOpal/Sprite.html +1419 -0
- data/doc/api/DXOpal/Window.html +1915 -0
- data/doc/api/_index.html +228 -0
- data/doc/api/class_list.html +51 -0
- data/doc/api/css/common.css +1 -0
- data/doc/api/css/full_list.css +58 -0
- data/doc/api/css/style.css +492 -0
- data/doc/api/file.CHANGELOG.html +162 -0
- data/doc/api/file.README.html +124 -0
- data/doc/api/file_list.html +61 -0
- data/doc/api/frames.html +17 -0
- data/doc/api/index.html +124 -0
- data/doc/api/js/app.js +248 -0
- data/doc/api/js/full_list.js +216 -0
- data/doc/api/js/jquery.js +4 -0
- data/doc/api/method_list.html +939 -0
- data/doc/api/top-level-namespace.html +110 -0
- data/doc/en/index.html +93 -0
- data/doc/ja/index.html +92 -0
- data/dxopal.gemspec +29 -0
- data/exe/dxopal +44 -0
- data/index.html +56 -0
- data/opal/dxopal.rb +54 -0
- data/opal/dxopal/constants/colors.rb +16 -0
- data/opal/dxopal/font.rb +20 -0
- data/opal/dxopal/image.rb +301 -0
- data/opal/dxopal/input.rb +170 -0
- data/opal/dxopal/input/key_codes.rb +168 -0
- data/opal/dxopal/remote_resource.rb +65 -0
- data/opal/dxopal/sound.rb +53 -0
- data/opal/dxopal/sound_effect.rb +84 -0
- data/opal/dxopal/sprite.rb +94 -0
- data/opal/dxopal/sprite/collision_area.rb +288 -0
- data/opal/dxopal/sprite/collision_check.rb +106 -0
- data/opal/dxopal/sprite/collision_checker.rb +169 -0
- data/opal/dxopal/sprite/physics.rb +82 -0
- data/opal/dxopal/version.rb +3 -0
- data/opal/dxopal/window.rb +173 -0
- data/template/index.html +13 -0
- data/template/main.rb +9 -0
- metadata +191 -0
| @@ -0,0 +1,16 @@ | |
| 1 | 
            +
            module DXOpal
         | 
| 2 | 
            +
              module Constants
         | 
| 3 | 
            +
                # Pre-defined ARGB colors
         | 
| 4 | 
            +
                module Colors
         | 
| 5 | 
            +
                  C_BLACK   = [255, 0, 0, 0]
         | 
| 6 | 
            +
                  C_RED     = [255, 255, 0, 0]
         | 
| 7 | 
            +
                  C_GREEN   = [255, 0, 255, 0]
         | 
| 8 | 
            +
                  C_BLUE    = [255, 0, 0, 255]
         | 
| 9 | 
            +
                  C_YELLOW  = [255, 255, 255, 0]
         | 
| 10 | 
            +
                  C_CYAN    = [255, 0, 255, 255]
         | 
| 11 | 
            +
                  C_MAGENTA = [255, 255, 0, 255]
         | 
| 12 | 
            +
                  C_WHITE   = [255, 255, 255, 255]
         | 
| 13 | 
            +
                  C_DEFAULT = [0, 0, 0, 0]
         | 
| 14 | 
            +
                end
         | 
| 15 | 
            +
              end
         | 
| 16 | 
            +
            end
         | 
    
        data/opal/dxopal/font.rb
    ADDED
    
    | @@ -0,0 +1,20 @@ | |
| 1 | 
            +
            module DXOpal
         | 
| 2 | 
            +
              class Font
         | 
| 3 | 
            +
                def self.default; @@default ||= Font.new(24); end
         | 
| 4 | 
            +
                def self.default=(f); @@default = f; end
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                def initialize(size, fontname=nil, option={})
         | 
| 7 | 
            +
                  @size = size
         | 
| 8 | 
            +
                  @orig_fontname = fontname
         | 
| 9 | 
            +
                  @fontname = fontname || "sans-serif"
         | 
| 10 | 
            +
                end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                def size; @size; end
         | 
| 13 | 
            +
                def fontname; @orig_fontname; end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                # Return a string like "48px serif"
         | 
| 16 | 
            +
                def _spec_str
         | 
| 17 | 
            +
                  "#{@size}px #{@fontname}"
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
              end
         | 
| 20 | 
            +
            end
         | 
| @@ -0,0 +1,301 @@ | |
| 1 | 
            +
            require 'dxopal/remote_resource'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module DXOpal
         | 
| 4 | 
            +
              class Image < RemoteResource
         | 
| 5 | 
            +
                RemoteResource.add_class(Image)
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                # Load remote image (called via Window.load_resources)
         | 
| 8 | 
            +
                def self._load(path_or_url)
         | 
| 9 | 
            +
                  raw_img = `new Image()`
         | 
| 10 | 
            +
                  img_promise = %x{
         | 
| 11 | 
            +
                    new Promise(function(resolve, reject) {
         | 
| 12 | 
            +
                      raw_img.onload = function() {
         | 
| 13 | 
            +
                        resolve(raw_img);
         | 
| 14 | 
            +
                      };
         | 
| 15 | 
            +
                      raw_img.src = path_or_url;
         | 
| 16 | 
            +
                    });
         | 
| 17 | 
            +
                  }
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                  img = new(0, 0)
         | 
| 20 | 
            +
                  %x{
         | 
| 21 | 
            +
                    #{img_promise}.then(function(raw_img){
         | 
| 22 | 
            +
                      img.$_resize(raw_img.width, raw_img.height);
         | 
| 23 | 
            +
                      img.$_draw_raw_image(0, 0, raw_img);
         | 
| 24 | 
            +
                    });
         | 
| 25 | 
            +
                  }
         | 
| 26 | 
            +
                  return img, img_promise
         | 
| 27 | 
            +
                end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                # Create an instance of Image
         | 
| 30 | 
            +
                def initialize(width, height, color=C_DEFAULT, canvas: nil)
         | 
| 31 | 
            +
                  @width, @height = width, height
         | 
| 32 | 
            +
                  @canvas = canvas || `document.createElement("canvas")`
         | 
| 33 | 
            +
                  @ctx = `#{@canvas}.getContext('2d')`
         | 
| 34 | 
            +
                  _resize(@width, @height)
         | 
| 35 | 
            +
                  box_fill(0, 0, @width, @height, color)
         | 
| 36 | 
            +
                end
         | 
| 37 | 
            +
                attr_reader :ctx, :canvas, :width, :height
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                # Set size of this image
         | 
| 40 | 
            +
                def _resize(w, h)
         | 
| 41 | 
            +
                  @width, @height = w, h
         | 
| 42 | 
            +
                  %x{
         | 
| 43 | 
            +
                    #{@canvas}.width = w;
         | 
| 44 | 
            +
                    #{@canvas}.height = h;
         | 
| 45 | 
            +
                  }
         | 
| 46 | 
            +
                end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                # Draw an Image on this image
         | 
| 49 | 
            +
                def draw(x, y, image)
         | 
| 50 | 
            +
                  %x{
         | 
| 51 | 
            +
                    #{@ctx}.drawImage(#{image.canvas}, x, y);
         | 
| 52 | 
            +
                  }
         | 
| 53 | 
            +
                  return self
         | 
| 54 | 
            +
                end
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                # Draw an Image on this image with rotation
         | 
| 57 | 
            +
                # - angle: Rotation angle (radian)
         | 
| 58 | 
            +
                # - center_x, center_y: Rotation center in the `image` (default: center of the `image`)
         | 
| 59 | 
            +
                def draw_rot(x, y, image, angle, center_x=nil, center_y=nil)
         | 
| 60 | 
            +
                  draw_ex(x, y, image, angle: angle, center_x: center_x, center_y: center_y)
         | 
| 61 | 
            +
                end
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                def draw_ex(x, y, image, options={})
         | 
| 64 | 
            +
                  scale_x = options[:scale_x] || 1
         | 
| 65 | 
            +
                  scale_y = options[:scale_y] || 1
         | 
| 66 | 
            +
                  center_x = options[:center_x] || image.width/2
         | 
| 67 | 
            +
                  center_y = options[:center_y] || image.height/2 
         | 
| 68 | 
            +
                  # TODO: alpha
         | 
| 69 | 
            +
                  # TODO: blend
         | 
| 70 | 
            +
                  angle = options[:angle] || 0
         | 
| 71 | 
            +
             | 
| 72 | 
            +
                  cx = x + center_x
         | 
| 73 | 
            +
                  cy = y + center_y
         | 
| 74 | 
            +
                  %x{
         | 
| 75 | 
            +
                    #{@ctx}.translate(cx, cy);
         | 
| 76 | 
            +
                    #{@ctx}.rotate(angle * Math.PI / 180.0);
         | 
| 77 | 
            +
                    #{@ctx}.scale(scale_x, scale_y);
         | 
| 78 | 
            +
                    #{@ctx}.drawImage(#{image.canvas}, x-cx, y-cy);
         | 
| 79 | 
            +
                    #{@ctx}.setTransform(1, 0, 0, 1, 0, 0); // reset
         | 
| 80 | 
            +
                  }
         | 
| 81 | 
            +
                  return self
         | 
| 82 | 
            +
                end
         | 
| 83 | 
            +
             | 
| 84 | 
            +
                # Draw some text on this image
         | 
| 85 | 
            +
                def draw_font(x, y, string, font, color=[255,255,255])
         | 
| 86 | 
            +
                  ctx = @ctx
         | 
| 87 | 
            +
                  %x{
         | 
| 88 | 
            +
                    ctx.font = #{font._spec_str};
         | 
| 89 | 
            +
                    ctx.textBaseline = 'top';
         | 
| 90 | 
            +
                    ctx.fillStyle = #{_rgba(color)};
         | 
| 91 | 
            +
                    ctx.fillText(string, x, y);
         | 
| 92 | 
            +
                  }
         | 
| 93 | 
            +
                  return self
         | 
| 94 | 
            +
                end
         | 
| 95 | 
            +
             | 
| 96 | 
            +
                # Get a pixel as ARGB array
         | 
| 97 | 
            +
                def [](x, y)
         | 
| 98 | 
            +
                  ctx = @ctx
         | 
| 99 | 
            +
                  ret = nil
         | 
| 100 | 
            +
                  %x{
         | 
| 101 | 
            +
                    var pixel = ctx.getImageData(x, y, 1, 1);
         | 
| 102 | 
            +
                    var rgba = pixel.data;
         | 
| 103 | 
            +
                    ret = [rgba[3], rgba[0], rgba[1], rgba[2]];
         | 
| 104 | 
            +
                  }
         | 
| 105 | 
            +
                  return ret
         | 
| 106 | 
            +
                end
         | 
| 107 | 
            +
             | 
| 108 | 
            +
                # Put a pixel on this image
         | 
| 109 | 
            +
                def []=(x, y, color)
         | 
| 110 | 
            +
                  box_fill(x, y, x, y, color)
         | 
| 111 | 
            +
                end
         | 
| 112 | 
            +
             | 
| 113 | 
            +
                # Return true if the pixel at `(x, y)` has the `color`
         | 
| 114 | 
            +
                def compare(x, y, color)
         | 
| 115 | 
            +
                  ctx = @ctx
         | 
| 116 | 
            +
                  rgba1 = _rgba_ary(color)
         | 
| 117 | 
            +
                  rgba2 = nil
         | 
| 118 | 
            +
                  ret = nil
         | 
| 119 | 
            +
                  %x{
         | 
| 120 | 
            +
                    var pixel = ctx.getImageData(x, y, 1, 1);
         | 
| 121 | 
            +
                    rgba2 = pixel.data;
         | 
| 122 | 
            +
                    // TODO: what is the right way to compare an Array and an Uint8ClampedArray?
         | 
| 123 | 
            +
                    ret = rgba1[0] == rgba2[0] &&
         | 
| 124 | 
            +
                          rgba1[1] == rgba2[1] &&
         | 
| 125 | 
            +
                          rgba1[2] == rgba2[2] &&
         | 
| 126 | 
            +
                          rgba1[3] == rgba2[3]
         | 
| 127 | 
            +
                  }
         | 
| 128 | 
            +
                  return ret
         | 
| 129 | 
            +
                end
         | 
| 130 | 
            +
             | 
| 131 | 
            +
                # Draw a line on this image
         | 
| 132 | 
            +
                def line(x1, y1, x2, y2, color)
         | 
| 133 | 
            +
                  ctx = @ctx
         | 
| 134 | 
            +
                  %x{
         | 
| 135 | 
            +
                    ctx.beginPath();
         | 
| 136 | 
            +
                    ctx.strokeStyle = #{_rgba(color)};
         | 
| 137 | 
            +
                    ctx.moveTo(x1, y1); 
         | 
| 138 | 
            +
                    ctx.lineTo(x2, y2); 
         | 
| 139 | 
            +
                    ctx.stroke(); 
         | 
| 140 | 
            +
                  }
         | 
| 141 | 
            +
                  return self
         | 
| 142 | 
            +
                end
         | 
| 143 | 
            +
             | 
| 144 | 
            +
                # Draw a rectangle on this image
         | 
| 145 | 
            +
                def box(x1, y1, x2, y2, color)
         | 
| 146 | 
            +
                  ctx = @ctx
         | 
| 147 | 
            +
                  %x{
         | 
| 148 | 
            +
                    ctx.beginPath();
         | 
| 149 | 
            +
                    ctx.strokeStyle = #{_rgba(color)};
         | 
| 150 | 
            +
                    ctx.rect(x1, y1, x2-x1+1, y2-y1+1); 
         | 
| 151 | 
            +
                    ctx.stroke(); 
         | 
| 152 | 
            +
                  }
         | 
| 153 | 
            +
                  return self
         | 
| 154 | 
            +
                end
         | 
| 155 | 
            +
             | 
| 156 | 
            +
                # Draw a filled box on this image
         | 
| 157 | 
            +
                def box_fill(x1, y1, x2, y2, color)
         | 
| 158 | 
            +
                  ctx = @ctx
         | 
| 159 | 
            +
                  %x{
         | 
| 160 | 
            +
                    ctx.beginPath();
         | 
| 161 | 
            +
                    ctx.fillStyle = #{_rgba(color)};
         | 
| 162 | 
            +
                    ctx.fillRect(x1, y1, x2-x1+1, y2-y1+1); 
         | 
| 163 | 
            +
                  }
         | 
| 164 | 
            +
                  return self
         | 
| 165 | 
            +
                end
         | 
| 166 | 
            +
             | 
| 167 | 
            +
                # Draw a circle on this image
         | 
| 168 | 
            +
                def circle(x, y, r, color)
         | 
| 169 | 
            +
                  ctx = @ctx
         | 
| 170 | 
            +
                  %x{
         | 
| 171 | 
            +
                    ctx.beginPath();
         | 
| 172 | 
            +
                    ctx.strokeStyle = #{_rgba(color)};
         | 
| 173 | 
            +
                    ctx.arc(x, y, r, 0, Math.PI*2, false)
         | 
| 174 | 
            +
                    ctx.stroke();
         | 
| 175 | 
            +
                  }
         | 
| 176 | 
            +
                  return self
         | 
| 177 | 
            +
                end
         | 
| 178 | 
            +
             | 
| 179 | 
            +
                # Draw a filled circle on this image
         | 
| 180 | 
            +
                def circle_fill(x, y, r, color)
         | 
| 181 | 
            +
                  ctx = @ctx
         | 
| 182 | 
            +
                  %x{
         | 
| 183 | 
            +
                    ctx.beginPath();
         | 
| 184 | 
            +
                    ctx.fillStyle = #{_rgba(color)};
         | 
| 185 | 
            +
                    ctx.arc(x, y, r, 0, Math.PI*2, false)
         | 
| 186 | 
            +
                    ctx.fill();
         | 
| 187 | 
            +
                  }
         | 
| 188 | 
            +
                  return self
         | 
| 189 | 
            +
                end
         | 
| 190 | 
            +
             | 
| 191 | 
            +
                # Draw a triangle on this image
         | 
| 192 | 
            +
                def triangle(x1, y1, x2, y2, x3, y3, color)
         | 
| 193 | 
            +
                  ctx = @ctx
         | 
| 194 | 
            +
                  %x{
         | 
| 195 | 
            +
                    ctx.beginPath();
         | 
| 196 | 
            +
                    ctx.strokeStyle = #{_rgba(color)};
         | 
| 197 | 
            +
                    ctx.moveTo(x1, y1);
         | 
| 198 | 
            +
                    ctx.lineTo(x2, y2);
         | 
| 199 | 
            +
                    ctx.lineTo(x3, y3);
         | 
| 200 | 
            +
                    ctx.lineTo(x1, y1);
         | 
| 201 | 
            +
                    ctx.stroke();
         | 
| 202 | 
            +
                  }
         | 
| 203 | 
            +
                  return self
         | 
| 204 | 
            +
                end
         | 
| 205 | 
            +
             | 
| 206 | 
            +
                # Draw a filled triangle on this image
         | 
| 207 | 
            +
                def triangle_fill(x1, y1, x2, y2, x3, y3, color)
         | 
| 208 | 
            +
                  ctx = @ctx
         | 
| 209 | 
            +
                  %x{
         | 
| 210 | 
            +
                    ctx.beginPath();
         | 
| 211 | 
            +
                    ctx.fillStyle = #{_rgba(color)};
         | 
| 212 | 
            +
                    ctx.moveTo(x1, y1);
         | 
| 213 | 
            +
                    ctx.lineTo(x2, y2);
         | 
| 214 | 
            +
                    ctx.lineTo(x3, y3);
         | 
| 215 | 
            +
                    ctx.fill();
         | 
| 216 | 
            +
                  }
         | 
| 217 | 
            +
                  return self
         | 
| 218 | 
            +
                end
         | 
| 219 | 
            +
             | 
| 220 | 
            +
                # Fill this image with `color`
         | 
| 221 | 
            +
                def fill(color)
         | 
| 222 | 
            +
                  box_fill(0, 0, @width-1, @height-1, color)
         | 
| 223 | 
            +
                end
         | 
| 224 | 
            +
             | 
| 225 | 
            +
                # Clear this image (i.e. fill with `[0,0,0,0]`)
         | 
| 226 | 
            +
                def clear
         | 
| 227 | 
            +
                  fill([0, 0, 0, 0])
         | 
| 228 | 
            +
                end
         | 
| 229 | 
            +
             | 
| 230 | 
            +
                # Return an Image which is a copy of the specified area
         | 
| 231 | 
            +
                def slice(x, y, width, height)
         | 
| 232 | 
            +
                  newimg = Image.new(width, height)
         | 
| 233 | 
            +
                  data = _image_data(x, y, width, height)
         | 
| 234 | 
            +
                  newimg._put_image_data(data, 0, 0)
         | 
| 235 | 
            +
                  return newimg
         | 
| 236 | 
            +
                end
         | 
| 237 | 
            +
             | 
| 238 | 
            +
                # Slice this image into xcount*ycount tiles
         | 
| 239 | 
            +
                def slice_tiles(xcount, ycount)
         | 
| 240 | 
            +
                  tile_w = @width / xcount
         | 
| 241 | 
            +
                  tile_h = @height / ycount
         | 
| 242 | 
            +
                  return (0...ycount).flat_map{|v|
         | 
| 243 | 
            +
                    (0...xcount).map{|u|
         | 
| 244 | 
            +
                      slice(tile_w * u, tile_h * v, tile_w, tile_h)
         | 
| 245 | 
            +
                    }
         | 
| 246 | 
            +
                  }
         | 
| 247 | 
            +
                end
         | 
| 248 | 
            +
             | 
| 249 | 
            +
                # Copy an <img> onto this image
         | 
| 250 | 
            +
                def _draw_raw_image(x, y, raw_img)
         | 
| 251 | 
            +
                  %x{
         | 
| 252 | 
            +
                    #{@ctx}.drawImage(#{raw_img}, x, y)
         | 
| 253 | 
            +
                  }
         | 
| 254 | 
            +
                end
         | 
| 255 | 
            +
             | 
| 256 | 
            +
                # Return .getImageData
         | 
| 257 | 
            +
                def _image_data(x=0, y=0, w=@width, h=@height)
         | 
| 258 | 
            +
                  return `#{@ctx}.getImageData(x, y, w, h)`
         | 
| 259 | 
            +
                end
         | 
| 260 | 
            +
             | 
| 261 | 
            +
                # Call .putImageData
         | 
| 262 | 
            +
                def _put_image_data(image_data, x, y)
         | 
| 263 | 
            +
                  `#{@ctx}.putImageData(image_data, x, y)`
         | 
| 264 | 
            +
                end
         | 
| 265 | 
            +
             | 
| 266 | 
            +
                # Return a string like 'rgb(255, 255, 255)'
         | 
| 267 | 
            +
                # `color` is 3 or 4 numbers
         | 
| 268 | 
            +
                def _rgb(color)
         | 
| 269 | 
            +
                  case color.length
         | 
| 270 | 
            +
                  when 4
         | 
| 271 | 
            +
                    # Just ignore alpha
         | 
| 272 | 
            +
                    rgb = color[1, 3]
         | 
| 273 | 
            +
                  when 3
         | 
| 274 | 
            +
                    rgb = color
         | 
| 275 | 
            +
                  else
         | 
| 276 | 
            +
                    raise "invalid color: #{color.inspect}"
         | 
| 277 | 
            +
                  end
         | 
| 278 | 
            +
                  return "rgb(" + rgb.join(', ') + ")";
         | 
| 279 | 
            +
                end
         | 
| 280 | 
            +
             | 
| 281 | 
            +
                # Return a string like 'rgba(255, 255, 255, 128)'
         | 
| 282 | 
            +
                # `color` is 3 or 4 numbers
         | 
| 283 | 
            +
                def _rgba(color)
         | 
| 284 | 
            +
                  return "rgba(" + _rgba_ary(color).join(', ') + ")"
         | 
| 285 | 
            +
                end
         | 
| 286 | 
            +
             | 
| 287 | 
            +
                # Return an array like `[255, 255, 255, 128]`
         | 
| 288 | 
            +
                def _rgba_ary(color)
         | 
| 289 | 
            +
                  case color.length
         | 
| 290 | 
            +
                  when 4
         | 
| 291 | 
            +
                    # color is ARGB in DXRuby, so move A to the last
         | 
| 292 | 
            +
                    color[1, 3] + [color[0]/255.0]
         | 
| 293 | 
            +
                  when 3
         | 
| 294 | 
            +
                    # Complement 255 as alpha 
         | 
| 295 | 
            +
                    color + [1.0]
         | 
| 296 | 
            +
                  else
         | 
| 297 | 
            +
                    raise "invalid color: #{color.inspect}"
         | 
| 298 | 
            +
                  end
         | 
| 299 | 
            +
                end
         | 
| 300 | 
            +
              end
         | 
| 301 | 
            +
            end
         | 
| @@ -0,0 +1,170 @@ | |
| 1 | 
            +
            module DXOpal
         | 
| 2 | 
            +
              module Input
         | 
| 3 | 
            +
                module MouseCodes
         | 
| 4 | 
            +
                  M_LBUTTON = 1
         | 
| 5 | 
            +
                  M_RBUTTON = 2
         | 
| 6 | 
            +
                  M_MBUTTON = 4
         | 
| 7 | 
            +
                  # DXOpal extention
         | 
| 8 | 
            +
                  M_4TH_BUTTON = 8
         | 
| 9 | 
            +
                  M_5TH_BUTTON = 16
         | 
| 10 | 
            +
                end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                def self._pressing_keys; @@pressing_keys; end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                # Internal setup for Input class
         | 
| 15 | 
            +
                def self._init(canvas)
         | 
| 16 | 
            +
                  @@tick = 0
         | 
| 17 | 
            +
                  @@pressing_keys = `new Object()`
         | 
| 18 | 
            +
                  @@mouse_info = `{x: 0, y: 0}`
         | 
| 19 | 
            +
                  @@pressing_mouse_buttons = `new Object()`
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                  rect = `canvas.getBoundingClientRect()`
         | 
| 22 | 
            +
                  @@canvas_x = `rect.left + window.pageXOffset`
         | 
| 23 | 
            +
                  @@canvas_y = `rect.top  + window.pageYOffset`
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                  self._init_mouse_events
         | 
| 26 | 
            +
                  self.keyevent_target = `window` unless Input.keyevent_target
         | 
| 27 | 
            +
                end
         | 
| 28 | 
            +
                
         | 
| 29 | 
            +
                # Called on every frame from Window
         | 
| 30 | 
            +
                def self._on_tick
         | 
| 31 | 
            +
                  @@tick += 1
         | 
| 32 | 
            +
                end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                # Return 1 if 'right', -1 if 'left'
         | 
| 35 | 
            +
                def self.x(pad_number=0)
         | 
| 36 | 
            +
                  ret = 0
         | 
| 37 | 
            +
                  ret += 1 if key_down?(K_RIGHT)
         | 
| 38 | 
            +
                  ret -= 1 if key_down?(K_LEFT)
         | 
| 39 | 
            +
                  ret
         | 
| 40 | 
            +
                end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                # Return 1 if 'down', -1 if 'up'
         | 
| 43 | 
            +
                def self.y(pad_number=0)
         | 
| 44 | 
            +
                  ret = 0
         | 
| 45 | 
            +
                  ret += 1 if key_down?(K_DOWN)
         | 
| 46 | 
            +
                  ret -= 1 if key_down?(K_UP)
         | 
| 47 | 
            +
                  ret
         | 
| 48 | 
            +
                end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                #
         | 
| 51 | 
            +
                # Keyboard
         | 
| 52 | 
            +
                #
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                # Return true if the key is being pressed
         | 
| 55 | 
            +
                def self.key_down?(code)
         | 
| 56 | 
            +
                  return `#{@@pressing_keys}[code] > 0`
         | 
| 57 | 
            +
                end
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                # Return true if the key is just pressed
         | 
| 60 | 
            +
                def self.key_push?(code)
         | 
| 61 | 
            +
                  return `#{@@pressing_keys}[code] == #{@@tick}-1`
         | 
| 62 | 
            +
                end
         | 
| 63 | 
            +
             | 
| 64 | 
            +
                # Return true if the key is just released
         | 
| 65 | 
            +
                def self.key_release?(code)
         | 
| 66 | 
            +
                  return `#{@@pressing_keys}[code] == -(#{@@tick}-1)`
         | 
| 67 | 
            +
                end
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                # (private) JS keydown event handler
         | 
| 70 | 
            +
                ON_KEYDOWN_ = %x{
         | 
| 71 | 
            +
                  function(ev){
         | 
| 72 | 
            +
                    #{Input._pressing_keys}[ev.keyCode] = #{@@tick};
         | 
| 73 | 
            +
                    ev.preventDefault();
         | 
| 74 | 
            +
                    ev.stopPropagation();
         | 
| 75 | 
            +
                  }
         | 
| 76 | 
            +
                }
         | 
| 77 | 
            +
                # (private) JS keyup event handler
         | 
| 78 | 
            +
                ON_KEYUP_ = %x{
         | 
| 79 | 
            +
                  function(ev){
         | 
| 80 | 
            +
                    #{Input._pressing_keys}[ev.keyCode] = -#{@@tick};
         | 
| 81 | 
            +
                    ev.preventDefault();
         | 
| 82 | 
            +
                    ev.stopPropagation();
         | 
| 83 | 
            +
                  }
         | 
| 84 | 
            +
                }
         | 
| 85 | 
            +
                # Set DOM element to receive keydown/keyup event
         | 
| 86 | 
            +
                #
         | 
| 87 | 
            +
                # By default, `window` is set to this (i.e. all key events are
         | 
| 88 | 
            +
                # stolen by DXOpal.) If canvas element is set to this, only key events
         | 
| 89 | 
            +
                # happend on canvas are processed by DXOpal.
         | 
| 90 | 
            +
                def self.keyevent_target=(target)
         | 
| 91 | 
            +
                  if @@keyevent_target
         | 
| 92 | 
            +
                    %x{
         | 
| 93 | 
            +
                      #{@@keyevent_target}.removeEventListener('keydown', #{ON_KEYDOWN_});
         | 
| 94 | 
            +
                      #{@@keyevent_target}.removeEventListener('keyup', #{ON_KEYUP_});
         | 
| 95 | 
            +
                    }
         | 
| 96 | 
            +
                  end
         | 
| 97 | 
            +
                  @@keyevent_target = target
         | 
| 98 | 
            +
                  %x{
         | 
| 99 | 
            +
                    if (#{@@keyevent_target}.tagName == "CANVAS") {
         | 
| 100 | 
            +
                      #{@@keyevent_target}.setAttribute('tabindex', 0);
         | 
| 101 | 
            +
                    }
         | 
| 102 | 
            +
                    #{@@keyevent_target}.addEventListener('keydown', #{ON_KEYDOWN_});
         | 
| 103 | 
            +
                    #{@@keyevent_target}.addEventListener('keyup', #{ON_KEYUP_});
         | 
| 104 | 
            +
                  }
         | 
| 105 | 
            +
                end
         | 
| 106 | 
            +
             | 
| 107 | 
            +
                # Return DOM element set by `keyevent_target=`
         | 
| 108 | 
            +
                def self.keyevent_target; @@keyevent_target; end
         | 
| 109 | 
            +
             | 
| 110 | 
            +
                #
         | 
| 111 | 
            +
                # Mouse
         | 
| 112 | 
            +
                #
         | 
| 113 | 
            +
             | 
| 114 | 
            +
                # (internal) initialize mouse events
         | 
| 115 | 
            +
                def self._init_mouse_events
         | 
| 116 | 
            +
                  %x{
         | 
| 117 | 
            +
                    document.addEventListener('mousemove', function(ev){
         | 
| 118 | 
            +
                      #{@@mouse_info}.x = ev.pageX - #{@@canvas_x};
         | 
| 119 | 
            +
                      #{@@mouse_info}.y = ev.pageY - #{@@canvas_y};
         | 
| 120 | 
            +
                    });
         | 
| 121 | 
            +
                    document.addEventListener('mousedown', function(ev){
         | 
| 122 | 
            +
                      #{@@mouse_info}.x = ev.pageX - #{@@canvas_x};
         | 
| 123 | 
            +
                      #{@@mouse_info}.y = ev.pageY - #{@@canvas_y};
         | 
| 124 | 
            +
                      for (var k=1; k<=16; k<<=1) {
         | 
| 125 | 
            +
                        if (ev.buttons & k) {
         | 
| 126 | 
            +
                          #{@@pressing_mouse_buttons}[k] = #{@@tick};
         | 
| 127 | 
            +
                        }
         | 
| 128 | 
            +
                      }
         | 
| 129 | 
            +
                    });
         | 
| 130 | 
            +
                    document.addEventListener('mouseup', function(ev){
         | 
| 131 | 
            +
                      #{@@mouse_info}.x = ev.pageX - #{@@canvas_x};
         | 
| 132 | 
            +
                      #{@@mouse_info}.y = ev.pageY - #{@@canvas_y};
         | 
| 133 | 
            +
                      for (var k=1; k<=16; k<<=1) {
         | 
| 134 | 
            +
                        if ((ev.buttons & k) == 0 && #{@@pressing_mouse_buttons}[k]) {
         | 
| 135 | 
            +
                          #{@@pressing_mouse_buttons}[k] = -#{@@tick};
         | 
| 136 | 
            +
                        }
         | 
| 137 | 
            +
                      }
         | 
| 138 | 
            +
                    });
         | 
| 139 | 
            +
                  }
         | 
| 140 | 
            +
                end
         | 
| 141 | 
            +
             | 
| 142 | 
            +
                # Return position of mouse cursor
         | 
| 143 | 
            +
                # (0, 0) is the top-left corner of the canvas
         | 
| 144 | 
            +
                def self.mouse_x
         | 
| 145 | 
            +
                  return `#{@@mouse_info}.x`
         | 
| 146 | 
            +
                end
         | 
| 147 | 
            +
                def self.mouse_y
         | 
| 148 | 
            +
                  return `#{@@mouse_info}.y`
         | 
| 149 | 
            +
                end
         | 
| 150 | 
            +
                class << self
         | 
| 151 | 
            +
                  alias mouse_pos_x mouse_x
         | 
| 152 | 
            +
                  alias mouse_pos_y mouse_y
         | 
| 153 | 
            +
                end
         | 
| 154 | 
            +
             | 
| 155 | 
            +
                # Return true if the mouse button is being pressed
         | 
| 156 | 
            +
                def self.mouse_down?(mouse_code)
         | 
| 157 | 
            +
                  return `#{@@pressing_mouse_buttons}[mouse_code] > 0`
         | 
| 158 | 
            +
                end
         | 
| 159 | 
            +
             | 
| 160 | 
            +
                # Return true if the mouse button is pressed in the last tick
         | 
| 161 | 
            +
                def self.mouse_push?(mouse_code)
         | 
| 162 | 
            +
                  return `#{@@pressing_mouse_buttons}[mouse_code] == -(#{@@tick}-1)`
         | 
| 163 | 
            +
                end
         | 
| 164 | 
            +
             | 
| 165 | 
            +
                # Return true if the mouse button is released in the last tick
         | 
| 166 | 
            +
                def self.mouse_release?(mouse_code)
         | 
| 167 | 
            +
                  return `#{@@pressing_mouse_buttons}[mouse_code] == -(#{@@tick}-1)`
         | 
| 168 | 
            +
                end
         | 
| 169 | 
            +
              end
         | 
| 170 | 
            +
            end
         |