Best way to draw a line of arbitrary length when using blitting system

21 posts

Flag Post

OK, so I’m blitting most of my objects from embedded .gifs, but I have one attack that I want to be a beam that stops when it hits the first viable target.

What I am thinking of doing is having a Rectangle of (assuming vertical orientation) width 1, and height of the difference between the y of the character’s firing position and the y of the relevant screen edge (is that understandable at all?) that during collision detection would be shortened to whatever distance it is to the closest target. I would then create a byteArray of Rectangle.height elements, which I would then copyPixels onto the renderer.
Addition: I forgot to mention that the beam will only go in orthogonal directions in this case.

…Or I could just have a loop and copyPixel onto the renderer, forgoing the Rectangle and byteArray…
Edit: Actually, I’d stilll use the Rectangle for collision detection, so just the byteArray would be tossed.

Is there a better way to do this?

Also, as long as I’m here:
While I don’t need it for my current project, for another project I hope to do soon afterward I will need to draw a circle of an arbitrary size. Should I just make a Shape object and use that, or is there a more efficient way? I’ll only be doing it rarely, so I suppose that would be easiest in any event…
Addition: No collision detection is required in this case.

 
Flag Post

First of all, just because you have a blitting system doesn’t mean that you can’t have basic drawing functions for when the task is best suited for it. Blitting a laser is pretty wasteful and hard.

The way I do it is by simply having some basic drawing methods like drawPixel, drawCircle, drawRect and drawLine. When somebody makes a laser attack, I run a loop that first “travels” the path without actually drawing anything, checking for collisions every 5th pixel or so (any more and it might skip over tiny things). When the laser either hits something or reaches it’s maximum allowed travel distance, I simply use my drawLine method to draw a line between the starting point and the ending point of the laser.

I guess it could be optimized to do the drawing as it’s traveling looking for a collision, but I have a strict separation of gameplay and rendering.

Obviously the method of detecting collision is important for this to be able to run effectively. I have a pretty good spatial collision engine that is optimized for tons of tiny tests like this, allowing for lasers and billions of bullets.

Just don’t get any crazy ideas about making a shape object and using hitTest.

 
Flag Post

Maybe I’m misunderstanding you or I’m missing something, but

// vertical beam collision test
if ((enemy.x <= beam.x) && (enemy.x + enemy.width >= beam.x))
{ // don't need to check against beam width, as it is 1 in this case 
  if ((enemy.y <= beam.y + beam.height) && (enemy.y + enemy.height >= beam.y))
  {
    // You sunk my enemy! You b@$t@rd!
  }
}

is almost certainly more efficient (and accurate) than checking every n pixels for collision.

I was under the impression drawing functions were slow.

Anyway, as for my circle issue, there won’t be collision detection associated with that (it is just an effect), so I don’t need to worry about that there, which is why I’m considering just using the Shape object…

 
Flag Post

Dragon_of_celts, that only works if the beam is fired orthogonally.

And also doesn’t take into account making the beam not extend past the hit target.

 
Flag Post

Oh, yes, I guess I should’ve mentioned that it will only be firing in orthogonal directions, ne? Sorry about that…
Addition: My example of using copyPixels with the Rectangle wouldn’t work (at least the easy way I envisioned it) if it wasn’t just orthogonals — in that case, the for loop and copyPixel might still do, though…?

As far as not extending past the hit target, if I do something like this:

var closestHit:int = -1;
var hitDist:int;
for (var ei = enemies.length; ei >= 0; ei--)
{ // vertical beam collision test
  if ((enemy.x <= beam.x) && (enemy.x + enemy.width >= beam.x))
  { // don't need to check against beam width, as it is 1 in this case 
    if ((enemy.y <= beam.y + beam.height) && (enemy.y + enemy.height >= beam.y))
    {
      hitDist = beam.y - enemy.y;
      if (hitDist < 0)
     {
        hitDist *= -1;
     }
      if (beam.height > hitDist)
     {
        beam.height = hitDist;  // needs adjustment by enemy height if shooting upward
        closestHit = ei;
     }
    }
  }
}
// closestHit should now have the index of the closest enemy and beam should be at the correct length

it should work, I think… Obviously not optimized.
Addition: I would try to find a way to work this into the overall collision detection loop, if possible/practical; this is just for the sake of (relatively simple) example.

To check a line in an arbitrary direction against collision, I would use a line intersection formula four times on each enemy (where the first line is the beam, and the second line is one edge of the collision detection box for the enemy). Is this less efficient than checking n pixels? I don’t know, but I don’t think it would be by much, if it is, and it should be a lot more accurate…

 
Flag Post

It depends on your situation really. I can imagine scenarios where different techniques have the advantage. I needed my system for some added benefits of being able to “slow” the laser down.

 
Flag Post

Could you elaborate (on the “slowing down” part)? Do you mean so that the beam extending/retreating is visible? I still don’t see how checking n points would be preferable, though…

 
Flag Post
Originally posted by dragon_of_celts:

Could you elaborate (on the “slowing down” part)? Do you mean so that the beam extending/retreating is visible? I still don’t see how checking n points would be preferable, though…

I think slowing down means multi-sampling by 6 pixels a couple times every frame and completing the entire check over several frames.

 
Flag Post

Indeed!

But part of the was also that the game had time manipulation as a weapon. Obviously if I coded anything to be “instant” the time manipulation wouldn’t work. Essentially I gave my laser the highest speed my engine allowed, so it would appear instant if time was flowing at it’s regular pace.

 
Flag Post

OK, sorry if I’m being dense, but I still don’t get it, and I want to understand. Time manipulation or no, the beam will always be certain dimensions at a certain location at a specified time (unless there is a component to the time manipulation that I am not comprehending). Given that, I’m still confused as to why checking n pixels would be more desirable than line intersection checks.

The “multi-sampling by 6 pixels a couple times every frame” to complete over several frames doesn’t make sense to me, either. Are there portions of the beam that you don’t want applying damage at specific time intervals? If not, why would you want this?
Addition: Except it is explicitly stated that checks are done every 5 pixels to avoid missing a collision…

 
Flag Post

In fact, I’d plain draw() a required Shape once in a while even with the blitting engine. I mean, you want a beam – okay, you have its start point and its end point is plain dynamic. You make yourself a Shape object that contains some beam graphics, starting from start point and ending at end point, then you plain draw() it in the required phase of your rendering.

 
Flag Post
Originally posted by dragon_of_celts:

Given that, I’m still confused as to why checking n pixels would be more desirable than line intersection checks.

It all depends on your situation. If you have destructible terrain like in Worms, line intersection checks simply won’t work. I guess my case was really a bit too specialized to bring forth as an example.

 
Flag Post

First, let me just give a cute yet overly rambunction kitten to those who attempt to help me:

ö ⌠
ΩΩ

Is using a draw function better than a loop and copyPixel? My understanding was that draw functions were slow (yes, I realize that “slow” is relative; but if a faster, more efficient method exists without excessive extra work required, why not use it?).

@Drakim: No, it’s just that I’m hazy (at best) on the particulars of the application of your example. I’m aware that there are few, if any, “once size fits all” solutions. However, to choose the best solution for a given situation, I have to understand the options and their advantages and disadvantages.

Could you please give an example of how your method would be preferable in the event of destructable terrain?

Addition: Heresy as it may be, I’m not really familiar with Worms, except vaguely by reputation. It occurs to me that by “destructable terrain” you are referring to pixel-level adjustments such as is done in Scorched Earth (I think that was the title — where players aim the trajectory and force of their cannons to try to hit the other cannons).

 
Flag Post
Originally posted by dragon_of_celts:

First, let me just give a cute yet overly rambunction kitten to those who attempt to help me:

ö ⌠
ΩΩ

Is using a draw function better than a loop and copyPixel? My understanding was that draw functions were slow (yes, I realize that “slow” is relative; but if a faster, more efficient method exists without excessive extra work required, why not use it?).

@Drakim: No, it’s just that I’m hazy (at best) on the particulars of the application of your example. I’m aware that there are few, if any, “once size fits all” solutions. However, to choose the best solution for a given situation, I have to understand the options and their advantages and disadvantages.

Could you please give an example of how your method would be preferable in the event of destructable terrain?

Draw is generally slower than copyPixels- but to be honest using copyPixels 100 times as opposed to draw once, I’d use draw.

 
Flag Post
Originally posted by RTL_Shadow:

Draw is generally slower than copyPixels- but to be honest using copyPixels 100 times as opposed to draw once, I’d use draw.

Uh, you mean a loop where copyPixel is called 100 times, or 100 different discrete copyPixel implementations?

I’m assuming that you mean this with respect to ease of implementation, so I’m leaning toward the latter interpretation.

Really, though, you just wanted the kitten, right? ;)

Addition: Given the overhead of function calls, though, I’m not certain that you don’t mean the former (with a copyPixel loop, not copyPixels, which is a different function). For drawing a straight line, the implementation of a copyPixel loop would be simple enough…

 
Flag Post

calling draw once will probably be faster than copyPixels looped 100 times.
E: In all honesty it’ll be easier too.

 
Flag Post

Ah, OK. Thank you. That was what I was looking for.

Have an extra kitten, on me.

ö ⌠
ΩΩ
 
Flag Post

Does flash still not have inline functions yet?

 
Flag Post
Originally posted by draganviper:

Does flash still not have inline functions yet?

They’ve been added in the new compiler, ASC2.0.

 
Flag Post

When I had to do it, I went with bitmaps of the laser beam, which I repeatedly copypixeled onto the screen to compose the laser beam. The reasons I went this way were:

1) I wanted a beam which was more artsy than a simple straight line, one pixel wide. Making a bitmap of the cross-section of my laser allowed me to have it look a lot better. It also allowed me to animate the beam. The end result is much nicer than a straight line. I realize in retrospect I could have used Draw() with a wider line and applied a lot of filters and effects to achieve a comparable result, although I didn’t and still don’t know how. Maybe if I’d tried I would now know.

2) I was only shooting lasers horizontally and vertically, so I only needed bitmaps for those two cases.

3) I was operating from a tiled level map, which allowed me to make the beam bitmaps one tile long. I knew the longest beam I’d ever have to display would only require as many copypixels() as the width of my display, in tiles. Pretty cheap.

4) I wanted special images at the origin (a bulge) and the end (a splash) of the beam. Using bitmaps made it easy to have a beginning and end picture.

5) Once I realized I didn’t have to copypixels() an entire beam tile, but I could copy only a fraction of it, making pixel perfect collisions with moving objects became a breeze: All I had to know was where the objects were and their shape. I could ‘cut’ the beam at any point and make it hit wherever it would look best.

Edit: I don’t ‘see’ the kitten. Which way am I supposed to tilt my head?

 
Flag Post
Originally posted by Ace_Blue:

Edit: I don’t ‘see’ the kitten. Which way am I supposed to tilt my head?

The “o” with the umlauts is the head, the omegas are the body/feet, and the upper-half of the s-curve is the tail… but (head angle = tan(cat/playfulness^2) * curiosity) yields the best cat::enjoyment ratio.

I had actually thought about doing what you describe (more or less; not the bulging, splashing part), but I dismissed it somewhere along the way, probably because my particular beam wouldn’t be anything fancy at all… I’m not sure I’d gain much by doing that over a copyPixel loop or one copyPixels call (as it would essentially be just drawing a simple line of a few pixels width — it is intended to be in the style of old-school shooter games such as Matrix Runner (actually the inspiration for the original idea), so I’m actively trying not to embellish things), but I’ll mull it over. Thanks.