Class: Chingu::Rect

Inherits:
Array
  • Object
show all
Defined in:
lib/chingu/rect.rb

Overview

A Rect is a representation of a rectangle, with four core attributes (x offset, y offset, width, and height) and a variety of functions for manipulating and accessing these attributes.

Like all coordinates in Rubygame (and its base library, SDL), x and y offsets are measured from the top-left corner of the screen, with greater y offsets being lower. Thus, specifying the x and y offsets of the Rect is equivalent to setting the location of its top-left corner.

In Rubygame, Rects are used for collision detection and describing the area of a Surface to operate on.

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Array

#each_bounding_box_collision, #each_bounding_circle_collision, #each_collision

Constructor Details

#initialize(*argv) ⇒ Rect

Create a new Rect, attempting to extract its own information from the given arguments. The arguments must fall into one of these cases:

- 4 integers +(x, y, w, h)+.
- 1 Rect or Array containing 4 integers +([x, y, w, h])+.
- 2 Arrays containing 2 integers each +([x,y], [w,h])+.
- 1 object with a +rect+ attribute which is a valid Rect object.

All rect core attributes (x,y,w,h) must be integers.



84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/chingu/rect.rb', line 84

def initialize(*argv)
  case argv.length
  when 1
    if argv[0].kind_of? Array; super(argv[0])
    elsif argv[0].respond_to? :rect; super(argv[0])
    end
  when 2
    super(argv[0].concat(argv[1]))
  when 4
    super(argv)
  end
  return self
end

Class Method Details

.new_from_object(object) ⇒ Object

Extract or generate a Rect from the given object, if possible, using the following process:

1. If it's a Rect already, return a duplicate Rect.
2. Elsif it's an Array with at least 4 values, make a Rect from it.
3. Elsif it has a +rect+ attribute., perform (1) and (2) on that.
4. Otherwise, raise TypeError.


106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# File 'lib/chingu/rect.rb', line 106

def Rect.new_from_object(object)
  case(object)
  when Rect
    return object.dup
  when Array 
    if object.length >= 4
      return Rect.new(object)
    else
      raise(ArgumentError,"Array does not have enough indices to be made into a Rect (%d for 4)."%object.length )
    end
  else
    begin
      case(object.rect)
      when Rect
        return object.rect.dup
      when Array
        if object.rect.length >= 4
          return Rect.new(object.rect)
        else
          raise(ArgumentError,"Array does not have enough indices to be made into a Rect (%d for 4)."%object.rect.length )
        end
      end        # case object.rect

    rescue NoMethodError # if no rect.rect

      raise(TypeError,"Object must be a Rect or Array [x,y,w,h], or have an attribute called 'rect'. (Got %s instance.)"%object.class)
    end
  end # case object

end

Instance Method Details

#bottomObject Also known as: b

Return the y coordinate of the bottom side of the Rect.



202
# File 'lib/chingu/rect.rb', line 202

def bottom; return self.at(1)+self.at(3); end

#bottom=(b) ⇒ Object Also known as: b=

Set the y coordinate of the bottom side of the Rect by translating the Rect (adjusting the y offset).



206
# File 'lib/chingu/rect.rb', line 206

def bottom=(b); self[1] = b - self.at(3); return b; end

#bottom_sideObject



376
377
378
# File 'lib/chingu/rect.rb', line 376

def bottom_side
   Rect.new([ x, y + (height * 0.75), width, height * 0.25 ])
end

#bottomleftObject Also known as: bl

Return the x and y coordinates of the bottom-left corner of the Rect



275
# File 'lib/chingu/rect.rb', line 275

def bottomleft; return self.at(0), self.bottom; end

#bottomleft=(bottomleft) ⇒ Object Also known as: bl=

Set the x and y coordinates of the bottom-left corner of the Rect by translating the Rect (adjusting the x and y offsets).

Raises:

  • (ArgumentError)


279
280
281
282
283
# File 'lib/chingu/rect.rb', line 279

def bottomleft=(bottomleft)
  raise ArgumentError, "Rect#bottomleft= takes an Array of form [x, y]." if bottomleft.size != 2
  self[0], self.bottom = bottomleft
  return bottomleft
end

#bottomrightObject Also known as: br

Return the x and y coordinates of the bottom-right corner of the Rect



289
# File 'lib/chingu/rect.rb', line 289

def bottomright; return self.right, self.bottom; end

#bottomright=(bottomright) ⇒ Object Also known as: br=

Set the x and y coordinates of the bottom-right corner of the Rect by translating the Rect (adjusting the x and y offsets).

Raises:

  • (ArgumentError)


293
294
295
296
297
# File 'lib/chingu/rect.rb', line 293

def bottomright=(bottomright)
  raise ArgumentError, "Rect#bottomright= takes an Array of form [x, y]." if bottomright.size != 2
  self.right, self.bottom = bottomright
  return bottomright
end

#centerObject Also known as: c

Return the x and y coordinates of the center of the Rect.



212
# File 'lib/chingu/rect.rb', line 212

def center; return self.centerx, self.centery; end

#center=(center) ⇒ Object Also known as: c=

Set the x and y coordinates of the center of the Rect by translating the Rect (adjusting the x and y offsets).

Raises:

  • (ArgumentError)


216
217
218
219
220
# File 'lib/chingu/rect.rb', line 216

def center=(center)
    raise ArgumentError, "Rect#center= takes an Array of the form [x,y]." if center.size != 2
  self.centerx, self.centery = center
  center
end

#centerxObject Also known as: center_x, cx

Return the x coordinate of the center of the Rect



225
# File 'lib/chingu/rect.rb', line 225

def centerx; return self.at(0)+(self.at(2).div(2)); end

#centerx=(x) ⇒ Object Also known as: cx=

Set the x coordinate of the center of the Rect by translating the Rect (adjusting the x offset).



230
# File 'lib/chingu/rect.rb', line 230

def centerx=(x); self[0] = x - (self.at(2).div(2)); return x; end

#centeryObject Also known as: center_y, cy

Return the y coordinate of the center of the Rect



236
# File 'lib/chingu/rect.rb', line 236

def centery; return self.at(1)+(self.at(3).div(2)); end

#centery=(y) ⇒ Object Also known as: cy=

Set the y coordinate of the center of the Rect by translating the Rect (adjusting the y offset).



241
# File 'lib/chingu/rect.rb', line 241

def centery=(y); self[1] = y- (self.at(3).div(2)); return y; end

#clamp(rect) ⇒ Object

As #clamp!, but the original caller is not changed.



385
386
387
# File 'lib/chingu/rect.rb', line 385

def clamp(rect)
  self.dup.clamp!(rect)
end

#clamp!(rect) ⇒ Object

Translate the calling Rect to be entirely inside the given Rect. If the caller is too large along either axis to fit in the given rect, it is centered with respect to the given rect, along that axis.



392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
# File 'lib/chingu/rect.rb', line 392

def clamp!(rect)
  nself = self.normalize
  rect = Rect.new_from_object(rect)
  #If self is inside given, there is no need to move self

  unless rect.contain?(nself)

    #If self is too wide:

    if nself.at(2) >= rect.at(2)
      self[0] = rect.centerx - nself.at(2).div(2)
      #Else self is not too wide

    else
      #If self is to the left of arg

      if nself.at(0) < rect.at(0)
        self[0] = rect.at(0)
      #If self is to the right of arg

      elsif nself.right > rect.right
        self[0] = rect.right - nself.at(2)
      #Otherwise, leave x alone

      end
    end

    #If self is too tall:

    if nself.at(3) >= rect.at(3)
      self[1] = rect.centery - nself.at(3).div(2)
      #Else self is not too tall

    else
      #If self is above arg

      if nself.at(1) < rect.at(1)
        self[1] = rect.at(1)
      #If self below arg

      elsif nself.bottom > rect.bottom
        self[1] = rect.bottom - nself.at(3)
      #Otherwise, leave y alone

      end
    end
  end
  return self
end

#clip(rect) ⇒ Object

As #clip!, but the original caller is not changed.



432
433
434
# File 'lib/chingu/rect.rb', line 432

def clip(rect)
  self.dup.clip!(rect)
end

#clip!(rect) ⇒ Object

Crop the calling Rect to be entirely inside the given Rect. If the caller does not intersect the given Rect at all, its width and height are set to zero, but its x and y offsets are not changed.

As a side effect, the Rect is normalized.



441
442
443
444
445
446
447
448
449
450
451
452
453
454
# File 'lib/chingu/rect.rb', line 441

def clip!(rect)
  nself = self.normalize
  other = Rect.new_from_object(rect).normalize!
  if self.collide_rect?(other)
    self[0] = [nself.at(0), other.at(0)].max
    self[1] = [nself.at(1), other.at(1)].max
    self[2] = [nself.right, other.right].min - self.at(0)
    self[3] = [nself.bottom, other.bottom].min - self.at(1)
  else #if they do not intersect at all:

    self[0], self[1] = nself.topleft
    self[2], self[3] = 0, 0
  end
  return self
end

#collide_array(array_rects) ⇒ Object

Iterate through all elements in the given Array, and return the index of the first element which is a Rect that collides with the caller.



484
485
486
487
488
489
490
491
# File 'lib/chingu/rect.rb', line 484

def collide_array(array_rects)
  for i in (0...(array_rects.length))
    if array_rects[i].collide_rect?(self)
      return i
    end
  end
  return nil
end

#collide_array_all(array_rects) ⇒ Object

Iterate through all elements in the given Array, and return an Array containing the indices of every element that is a Rect that collides with the caller.



496
497
498
499
500
501
502
503
504
# File 'lib/chingu/rect.rb', line 496

def collide_array_all(array_rects)
  indexes = []
  for i in (0...(array_rects.length))
    if array_rects[i].collide_rect?(self)
      indexes += [i]
    end
  end
  return indexes
end

#collide_hash(hash_rects) ⇒ Object

Iterate through all key/value pairs in the given hash table, and return the first pair whose value is a Rect that collides with the caller.

Because a hash table is unordered, you should not expect any particular Rect to be returned first.



462
463
464
465
466
467
# File 'lib/chingu/rect.rb', line 462

def collide_hash(hash_rects)
  hash_rects.each { |key,value|
    if value.collide_rect?+(self); return [key,value]; end
  }
  return nil
end

#collide_hash_all(hash_rects) ⇒ Object

Iterate through all key/value pairs in the given hash table, and return an Array of every pair whose value is a Rect that collides the caller.

Because a hash table is unordered, you should not expect the returned pairs to be in any particular order.



475
476
477
478
479
# File 'lib/chingu/rect.rb', line 475

def collide_hash_all(hash_rects)
  hash_rects.select { |key,value|
    value.collide_rect?+(self)
  }
end

#collide_point?(x, y) ⇒ Boolean

True if the point is inside (including on the border) of the caller. If you have Array of coordinates, you can use collide_point?(*coords).

Returns:

  • (Boolean)


508
509
510
511
# File 'lib/chingu/rect.rb', line 508

def collide_point?(x,y)
  nself = normalize()
  x.between?(nself.left,nself.right) && y.between?(nself.top,nself.bottom)
end

#collide_rect?(rect) ⇒ Boolean

True if the caller and the given Rect overlap (or touch) at all.

Returns:

  • (Boolean)


514
515
516
517
518
519
# File 'lib/chingu/rect.rb', line 514

def collide_rect?(rect)
  nself = self.normalize
  rect  = Rect.new_from_object(rect).normalize!
  return ((nself.l >= rect.l && nself.l <= rect.r) or (rect.l >= nself.l && rect.l <= nself.r)) &&
         ((nself.t >= rect.t && nself.t <= rect.b) or (rect.t >= nself.t && rect.t <= nself.b))
end

#contain?(rect) ⇒ Boolean

True if the given Rect is totally within the caller. Borders may overlap.

Returns:

  • (Boolean)


523
524
525
526
527
528
# File 'lib/chingu/rect.rb', line 523

def contain?(rect)
  nself = self.normalize
  rect = Rect.new_from_object(rect).normalize!
  return (nself.left <= rect.left and rect.right <= nself.right and
        nself.top <= rect.top and rect.bottom <= nself.bottom)
end

#hObject Also known as: height

Returns self.at(3)



174
# File 'lib/chingu/rect.rb', line 174

def h; return self.at(3); end

#h=(val) ⇒ Object Also known as: height=

Sets self to val



176
# File 'lib/chingu/rect.rb', line 176

def h=(val); self[3] = val; end

#inflate(x, y) ⇒ Object

As #inflate!, but the original caller is not changed.



531
532
533
534
535
536
# File 'lib/chingu/rect.rb', line 531

def inflate(x,y)
  return self.class.new(self.at(0) - x.div(2),
                        self.at(1) - y.div(2),
                        self.at(2) + x,
                        self.at(3) + y)
end

#inflate!(x, y) ⇒ Object

Increase the Rect’s size is the x and y directions, while keeping the same center point. For best results, expand by an even number. X and y inflation can be given as an Array or as separate values.



541
542
543
544
545
546
547
# File 'lib/chingu/rect.rb', line 541

def inflate!(x,y)
  self[0] -= x.div(2)
  self[1] -= y.div(2)
  self[2] += x
  self[3] += y
  return self
end

#inspectObject

Print the Rect in the form “+#<Rect:id [x,y,w,h]>+”



139
# File 'lib/chingu/rect.rb', line 139

def inspect; "#<Rect:#{self.object_id} [%s,%s,%s,%s]>"%self; end

#left_sideObject

returns rects for side collision



364
365
366
# File 'lib/chingu/rect.rb', line 364

def left_side
   Rect.new([ x, y, width * 0.25, height ])
end

#midbottomObject Also known as: mb

Return the x and y coordinates of the midpoint on the left side of the Rect.



349
# File 'lib/chingu/rect.rb', line 349

def midbottom; return self.centerx, self.bottom; end

#midbottom=(midbottom) ⇒ Object Also known as: mb=

Set the x and y coordinates of the midpoint on the bottom side of the Rect by translating the Rect (adjusting the x and y offsets).

Raises:

  • (ArgumentError)


353
354
355
356
357
# File 'lib/chingu/rect.rb', line 353

def midbottom=(midbottom)
    raise ArgumentError, "Rect#midbottom= takes an Array of form [x, y]." if midbottom.size != 2
  self.centerx, self.bottom = midbottom
  return midbottom
end

#midleftObject Also known as: ml

Return the x and y coordinates of the midpoint on the left side of the Rect.



304
# File 'lib/chingu/rect.rb', line 304

def midleft; return self.at(0), self.centery; end

#midleft=(midleft) ⇒ Object Also known as: ml=

Set the x and y coordinates of the midpoint on the left side of the Rect by translating the Rect (adjusting the x and y offsets).

Raises:

  • (ArgumentError)


308
309
310
311
312
# File 'lib/chingu/rect.rb', line 308

def midleft=(midleft)
    raise ArgumentError, "Rect#midleft= takes an Array of form [x, y]." if midleft.size != 2
  self[0], self.centery = midleft
  return midleft
end

#midrightObject Also known as: mr

Return the x and y coordinates of the midpoint on the left side of the Rect.



334
# File 'lib/chingu/rect.rb', line 334

def midright; return self.right, self.centery; end

#midright=(midright) ⇒ Object Also known as: mr=

Set the x and y coordinates of the midpoint on the right side of the Rect by translating the Rect (adjusting the x and y offsets).

Raises:

  • (ArgumentError)


338
339
340
341
342
# File 'lib/chingu/rect.rb', line 338

def midright=(midright)
    raise ArgumentError, "Rect#midright= takes an Array of form [x, y]." if midright.size != 2
  self.right, self.centery = midright
  return midright
end

#midtopObject Also known as: mt

Return the x and y coordinates of the midpoint on the left side of the Rect.



319
# File 'lib/chingu/rect.rb', line 319

def midtop; return self.centerx, self.at(1); end

#midtop=(midtop) ⇒ Object Also known as: mt=

Set the x and y coordinates of the midpoint on the top side of the Rect by translating the Rect (adjusting the x and y offsets).

Raises:

  • (ArgumentError)


323
324
325
326
327
# File 'lib/chingu/rect.rb', line 323

def midtop=(midtop)
    raise ArgumentError, "Rect#midtop= takes an Array of form [x, y]." if midtop.size != 2
  self.centerx, self[1] = midtop
  return midtop
end

#move(x, y) ⇒ Object

As #move!, but the original caller is not changed.



550
551
552
# File 'lib/chingu/rect.rb', line 550

def move(x,y)
  self.dup.move!(x,y)
end

#move!(x, y) ⇒ Object

Translate the Rect by the given amounts in the x and y directions. Positive values are rightward for x and downward for y. X and y movement can be given as an Array or as separate values.



557
558
559
560
# File 'lib/chingu/rect.rb', line 557

def move!(x,y)
  self[0]+=x; self[1]+=y
  return self
end

#normalizeObject

As #normalize!, but the original caller is not changed.



563
564
565
# File 'lib/chingu/rect.rb', line 563

def normalize
  self.dup.normalize!()
end

#normalize!Object

Fix Rects that have negative width or height, without changing the area it represents. Has no effect on Rects with non-negative width and height. Some Rect methods will automatically normalize the Rect.



570
571
572
573
574
575
576
577
578
# File 'lib/chingu/rect.rb', line 570

def normalize!
  if self.at(2) < 0
    self[0], self[2] = self.at(0)+self.at(2), -self.at(2)
  end
  if self.at(3) < 0
    self[1], self[3] = self.at(1)+self.at(3), -self.at(3)
  end
  self
end

#rightObject Also known as: r

Return the x coordinate of the right side of the Rect.



192
# File 'lib/chingu/rect.rb', line 192

def right; return self.at(0)+self.at(2); end

#right=(r) ⇒ Object Also known as: r=

Set the x coordinate of the right side of the Rect by translating the Rect (adjusting the x offset).



196
# File 'lib/chingu/rect.rb', line 196

def right=(r); self[0] = r - self.at(2); return r; end

#right_sideObject



368
369
370
# File 'lib/chingu/rect.rb', line 368

def right_side
   Rect.new([ x + (width * 0.75), y, width * 0.25, height ])
end

#sizeObject

Return the width and height of the Rect.



182
# File 'lib/chingu/rect.rb', line 182

def size; return self[2,2]; end

#size=(size) ⇒ Object

Set the width and height of the Rect.

Raises:

  • (ArgumentError)


185
186
187
188
189
# File 'lib/chingu/rect.rb', line 185

def size=(size)
 raise ArgumentError, "Rect#size= takes an Array of form [width, height]." if size.size != 2
 self[2,2] = size
 size
end

#to_sObject

Print the Rect in the form “+#<Rect [x,y,w,h]>+”



136
# File 'lib/chingu/rect.rb', line 136

def to_s; "#<Rect [%s,%s,%s,%s]>"%self; end

#top_sideObject



372
373
374
# File 'lib/chingu/rect.rb', line 372

def top_side
   Rect.new([ x, y, width, height * 0.25 ])
end

#topleftObject Also known as: tl

Return the x and y coordinates of the top-left corner of the Rect



247
# File 'lib/chingu/rect.rb', line 247

def topleft; return self[0,2].to_a; end

#topleft=(topleft) ⇒ Object Also known as: tl=

Set the x and y coordinates of the top-left corner of the Rect by translating the Rect (adjusting the x and y offsets).

Raises:

  • (ArgumentError)


251
252
253
254
255
# File 'lib/chingu/rect.rb', line 251

def topleft=(topleft)
    raise ArgumentError, "Rect#topright= takes an Array of form [x, y]." if topleft.size != 2
  self[0,2] = topleft
  return topleft
end

#toprightObject Also known as: tr

Return the x and y coordinates of the top-right corner of the Rect



261
# File 'lib/chingu/rect.rb', line 261

def topright; return self.right, self.at(1); end

#topright=(topright) ⇒ Object Also known as: tr=

Set the x and y coordinates of the top-right corner of the Rect by translating the Rect (adjusting the x and y offsets).

Raises:

  • (ArgumentError)


265
266
267
268
269
# File 'lib/chingu/rect.rb', line 265

def topright=(topright)
    raise ArgumentError, "Rect#topright= takes an Array of form [x, y]." if topright.size != 2
  self.right, self[1] = topright
  return topright
end

#union(rect) ⇒ Object

As #union!, but the original caller is not changed.



581
582
583
# File 'lib/chingu/rect.rb', line 581

def union(rect)
  self.dup.union!(rect)
end

#union!(rect) ⇒ Object

Expand the caller to also cover the given Rect. The Rect is still a rectangle, so it may also cover areas that neither of the original Rects did, for example areas between the two Rects.



588
589
590
591
592
593
594
595
596
597
598
599
600
601
# File 'lib/chingu/rect.rb', line 588

def union!(rect)
  self.normalize!
   rleft, rtop = self.topleft
   rright, rbottom = self.bottomright
  r2 = Rect.new_from_object(rect).normalize!

  rleft = [rleft, r2.left].min
  rtop = [rtop, r2.top].min
  rright = [rright, r2.right].max
  rbottom = [rbottom, r2.bottom].max

  self[0,4] = rleft, rtop, rright - rleft, rbottom - rtop
  return self
end

#union_all(array_rects) ⇒ Object

As #union_all!, but the original caller is not changed.



604
605
606
# File 'lib/chingu/rect.rb', line 604

def union_all(array_rects)
  self.dup.union_all!(array_rects)
end

#union_all!(array_rects) ⇒ Object

Expand the caller to cover all of the given Rects. See also #union!



609
610
611
612
613
614
# File 'lib/chingu/rect.rb', line 609

def union_all!(array_rects)
  array_rects.each do |r|
     self.union!(r)
  end
  return self
end

#wObject Also known as: width

Returns self.at(2)



166
# File 'lib/chingu/rect.rb', line 166

def w; return self.at(2); end

#w=(val) ⇒ Object Also known as: width=

Sets self to val



168
# File 'lib/chingu/rect.rb', line 168

def w=(val); self[2] = val; end

#xObject Also known as: left, l

Returns self.at(0)



146
# File 'lib/chingu/rect.rb', line 146

def x; return self.at(0); end

#x=(val) ⇒ Object Also known as: left=, l=

Sets self to val



148
# File 'lib/chingu/rect.rb', line 148

def x=(val); self[0] = val; end

#yObject Also known as: top, t

Returns self.at(1)



156
# File 'lib/chingu/rect.rb', line 156

def y; return self.at(1); end

#y=(val) ⇒ Object Also known as: top=, t=

Sets self to val



158
# File 'lib/chingu/rect.rb', line 158

def y=(val); self[1] = val; end