Author Topic: Theory behind Laser Beams?  (Read 6877 times)

Garmichael

  • Member
  • **
  • Posts: 89
  • Karma: +0/-0
    • View Profile
Theory behind Laser Beams?
« on: Mon, May 10, 2010 »
I want to create an enemy that fire's out a laser beam that grows in length.

In fact, the sort of laser I want to make is the type found in Super Smash TV. For a visual, check out the first couple minutes of http://www.youtube.com/watch?v=t64e2pYQ-5g

So the laser emits from the enemy, and travels until it hits a wall. Then, it stays like that for a short bit, then disappears. The part of this that confuses me is how it extends but isn't being scaled. Any ideas how I would go about achieving this?

Rybar

  • Contributor
  • ****
  • Posts: 279
  • Karma: +0/-0
    • View Profile
Re: Theory behind Laser Beams?
« Reply #1 on: Mon, May 10, 2010 »
Most shooters achieve beam effects by using a sprite that represents a small part of the beam, and repeating it over and over along the path of the desired direction. Another method would be to just draw it to FlxG.buffer using Flash's drawing API.  Either way would be pretty easy to implement. Let me know if you get stuck.

flowstate

  • Guest
Re: Theory behind Laser Beams?
« Reply #2 on: Tue, May 11, 2010 »
out of curiosity, why not scale it? It's likely cheaper than repeating a small piece over and over (though I haven't delved into the way the framework handles each).

If you're trying to achieve something specific that can't be done with scaling, let us know, and maybe we can come up with a better solution.

bjc

  • Member
  • **
  • Posts: 19
  • Karma: +0/-0
    • View Profile
Re: Theory behind Laser Beams?
« Reply #3 on: Tue, May 11, 2010 »
I think mostly because of the flexibility that a series of continuous sprite instances gives you when emulating a laser such as cases where the beam is cut off at mid points or reflected

Garmichael

  • Member
  • **
  • Posts: 89
  • Karma: +0/-0
    • View Profile
Re: Theory behind Laser Beams?
« Reply #4 on: Tue, May 11, 2010 »
I don't want to scale because I want to make the graphic look pleasing, like with slashy lines going through it.

I think the continuous sprites thing might work best, although I don't know how easy it would be to do angled beams.

Rybar, I have no idea how to do anything with the flxG.buffer.. I've seen some posts with effects on this board that utilize the buffer, but I don't even know where to begin.. Can you point me to a primer on how to use the buffer and what it can do?

cai

  • Contributor
  • ****
  • Posts: 465
  • Karma: +0/-0
  • the illest of villains
    • View Profile
    • Brandon Cash
Re: Theory behind Laser Beams?
« Reply #5 on: Tue, May 11, 2010 »
I've been seeing a lot of questions lately in which writing directly to the buffer have been a good solution.  I don't know of any tutorials utilizing it, but maybe it's time to change that.  Of course, each application is different, so it would have to be fairly generalized.

Basically, FlxG.buffer is a BitmapData object that represents what's on screen at any given frame.  It is blanked and drawn over again on the next frame, so you will need to redraw on it every frame, too.  That can be invoked through flixel pretty easily by overriding pretty much anything's update() or render().

You would use it by drawing lines or other bitmaps onto it each frame.  In this instance, it probably wouldn't be the best solution; instead I would go the route of repeating a tile.  For angling, you'd probably have to draw the entire beam and rotate it.  That would get pretty costly if you have several on screen at once, as rotating means it's drawn with the Flash drawing API, which is a lot slower than just copying a bitmap onto the buffer (which is the default flixel action).
Follow me on Twitter | Come join us at #flixel on irc.freenode.net!

Rybar

  • Contributor
  • ****
  • Posts: 279
  • Karma: +0/-0
    • View Profile
Re: Theory behind Laser Beams?
« Reply #6 on: Wed, May 12, 2010 »
Here's a quick demo using a lightning class from an existing project; it uses the Flash drawing API to create the lightning bolt, and then draws it to the screen with FlxG.buffer.draw().

To see it in action:
http://flashdev.niklofide.net/EffectsDemo/
mouse button draws a lightning bolt to screen center

Source:
http://flashdev.niklofide.net/EffectsDemo.zip


flowstate

  • Guest
Re: Theory behind Laser Beams?
« Reply #7 on: Wed, May 12, 2010 »
To OP:

Forgive me, as I'm coming to Flex/Flixel from the world of 3d game programming in c++/c#, but I think raytracing should have a place in this convo. I mean, you've already got the angle property built in to FlxObjects...

And, if you're going for the oldschool kind of feel for this game, then the lasers will probably only be able to be shot in 8 directions, and if so, you only have to do 2 sets of sprites, one for cardinal and one for ordinal.

Or am I way off base?

Garmichael

  • Member
  • **
  • Posts: 89
  • Karma: +0/-0
    • View Profile
Re: Theory behind Laser Beams?
« Reply #8 on: Wed, May 12, 2010 »
@flowstate: My game is old school in game play, but not in execution. Firing angles are 360, but Raytracing is something I'll have to brush up on, too :S

@Rybar:

So I've scrubbed through this code. Correct me if I'm misunderstanding.

In the Render() function, you:
1. Set up all the angle/radian stuff. (Im familiar with this bit)
2. Created a new draw space of type Shape called Canvas... This is where you draw everything to.  I noticed that you didn't set any X/Y/W/H properties. Does this mean that a blank shape covers the entire space and that I wouldn't have to factor in the X/Y of the Canvas when determining where to draw to? The line "canvas.graphics.lineStyle(2, 0xff0000); doesn't seem to do anything when I rem it out. What was its intended purpose?
3. The While block creates a single jagged line traveling from the bolt origin (the mouse) to the center point. Then you add a glow.
4. Here's the magic bit.. Without drawing the glowing line just created to the buffer, it never shows up. In the playstate, the mouse.pressed function is creating one single bolt of lightening with its own canvas, and an illusion is created.

The buffer.draw is just to "add" any shape.graphics stuff to the screen. And thats it? It doesn't actually do any of the special effects. The special effects are done with the shape.graphic stuff, and not the actual buffer functions?


Edit: Okay, so I went and checked out some of the methods of the buffer.. There are quite a bit of things I could do with the buffer..

Can the buffer be used only in render()?
Here's an arbitrary situation: Say I have a creature in my game that has a light bulb on its head and I want to create a glow effect of the color matching the light bulb, but the light bulb changes colors randomly using a colorTransform. So I use getPixel to get the color of the light bulb for the color of the glow. (probably not the cleanest way to do this, but lets suppose I try this for sake of understanding).

Now, would all this go into the render() of the creature? Or could it also go in the update() of that creature? Or, would it go in the render()/update() of something else?


By the way, thanks for guiding a buffer.noob;
« Last Edit: Wed, May 12, 2010 by Garmichael »

Rybar

  • Contributor
  • ****
  • Posts: 279
  • Karma: +0/-0
    • View Profile
Re: Theory behind Laser Beams?
« Reply #9 on: Wed, May 12, 2010 »
FlxG.buffer is erased and redrawn every tick in Flixel, like cai said:

Basically, FlxG.buffer is a BitmapData object that represents what's on screen at any given frame.  It is blanked and drawn over again on the next frame, so you will need to redraw on it every frame, too.  That can be invoked through flixel pretty easily by overriding pretty much anything's update() or render().

so no, no special effects are actually created by the buffer itself, its just what you want to draw to once you've created the effect; so omitting the buffer.draw line results in seeing nothing, as you noted.

As for the canvas.graphics.lineStyle(2, 0xff0000); code, I think that was leftover from before I had the bolt decreasing in width from source to target, just never deleted it.

Here's how I would tackle your lightbulb:
Create a new Lightbulb class with the glow effect in place, or better yet, just draw the glow effect into your sprite so you don't have any overhead from the glow effect, and then do the color transform. This way you don't have to do getpixel either. Then add an instance of the light class to your creature class. 

zez

  • Active Member
  • ***
  • Posts: 203
  • Karma: +0/-0
    • View Profile
    • Devlog
Re: Theory behind Laser Beams?
« Reply #10 on: Thu, May 13, 2010 »
wow... hey Rybar, that effect is friggin gorgeous, you mind if I steal and tweak it a bit for my shmup?

Rybar

  • Contributor
  • ****
  • Posts: 279
  • Karma: +0/-0
    • View Profile
Re: Theory behind Laser Beams?
« Reply #11 on: Thu, May 13, 2010 »
@zez, I'm glad you like it. Please feel free to do whatever you like with it, I'd only ask you show me what you do with it.


zez

  • Active Member
  • ***
  • Posts: 203
  • Karma: +0/-0
    • View Profile
    • Devlog
Re: Theory behind Laser Beams?
« Reply #12 on: Thu, May 13, 2010 »
For sure, it probably wont actually make it into the code for awhile, but Ill be sure to PM you with a link once I play with it.

Garmichael

  • Member
  • **
  • Posts: 89
  • Karma: +0/-0
    • View Profile
Re: Theory behind Laser Beams?
« Reply #13 on: Thu, May 13, 2010 »
Well, thank you Rybar and Cai!

The code and theory helped out quite a bit, and I've built my laser.

Check it out:

http://www.swfcabin.com/open/1273785937

If it helps anyone else, here's my laser class.

Code: [Select]
package Projectiles
{

import flash.display.*;
import flash.geom.*;
import org.flixel.*;
import org.flixel.data.FlxConsole;
import flash.filters.GlowFilter;
import flash.filters.BevelFilter;
import flash.filters.BlurFilter;

public class Lazer extends FlxSprite
{

[Embed(source="../../_assets/laser_pattern.png")] private var IMG_LASER:Class;

//important vars
public var lifeSpan:Number = 0; //ticks
public var LaserOrigin:FlxPoint; //Point where the laser originally fires from
public var FAngle:Number; //Angle fired
public var speed:Number = 20; //distance per tick
public var laser_base:Number = 0; //Point at the base of the laser
public var laser_length:Number = 0; //length of the laser
public var FTime:Number; //Timeout for when the laser 'turns off'

//for variable laser width
public var widthDir:int = 1;
public var widthMax:int = 5;
public var widthMin:int = 4;
public var laser_width:int = widthMin;

//for variable spark diameter
public var sparkDir:int = 1;
public var sparkMax:int = 10;
public var sparkMin:int = 8;
public var sparkCur:int = sparkMin;

//for variable glow
public var glowDir:int = 1;
public var glowMax:int = 16;
public var glowMin:int = 1;
public var glowCur:int = glowMin;

public function Lazer(X:int,Y:int, fireAngle:Number, fireTime:Number)
{
LaserOrigin = new FlxPoint(X, Y)
FAngle = fireAngle;
FTime = fireTime;
super(X,Y);
}

override public function update():void {
lifeSpan += FlxG.elapsed;
super.update();
}

override public function render():void
{
var canvas:Shape = new Shape();

var scrollX:int = FlxG.scroll.x;
var scrollY:int = FlxG.scroll.y;

//Get useful radial angles
var fRadians:Number = FAngle * Math.PI / 180;
var lRadians:Number = (FAngle - 90) * Math.PI / 180;
var rRadians:Number = (FAngle + 90) * Math.PI / 180;

//Get New Origin, calcuating in the scrolling.
var newOrigin:Point = new Point(LaserOrigin.x + scrollX, LaserOrigin.y + scrollY);

laser_width += widthDir;
if (laser_width == widthMax || laser_width == widthMin) widthDir = -widthDir;

//Set up the four points that outline the beam's rectangle
var closeRight:Point = new Point(newOrigin.x + Math.cos(rRadians) * laser_width,newOrigin.y + Math.sin(rRadians) * laser_width);
var farRight:Point = new Point(newOrigin.x + Math.cos(rRadians) * laser_width + Math.cos(fRadians) * laser_length, newOrigin.y + Math.sin(rRadians) * laser_width + Math.sin(fRadians) * laser_length);
var farLeft:Point = new Point(newOrigin.x + Math.cos(lRadians) * laser_width + Math.cos(fRadians) * laser_length,newOrigin.y + Math.sin(lRadians) * laser_width + Math.sin(fRadians) * laser_length);
var closeLeft:Point = new Point (newOrigin.x + Math.cos(lRadians) * laser_width,newOrigin.y + Math.sin(lRadians) * laser_width);
var sparkpoint:Point = new Point (newOrigin.x + Math.cos(fRadians) * laser_length, newOrigin.y + Math.sin(fRadians) * laser_length);

//If extending the beam isn't inside a tile, extend it.
var collidePoint:FlxPoint;
if (PlayState.map_collide.getTile((farLeft.x - scrollX + Math.cos(fRadians) * speed) / 32, (farLeft.y - scrollY + Math.sin(fRadians) * speed) / 32) == 0 &&
PlayState.map_collide.getTile((farRight.x - scrollX + Math.cos(fRadians) * speed) / 32, (farRight.y - scrollY + Math.sin(fRadians) * speed) / 32) == 0 )
{
laser_length += speed;
}

//If we've been firing long enough, "turn off the beam"
if (lifeSpan > FTime) {
LaserOrigin.x += Math.cos(fRadians) * speed; //move the origin up.
LaserOrigin.y += Math.sin(fRadians) * speed; //move the origin up.
laser_length -= speed; //reduce the length.
}

//If the origin has caught up with the laser's length
if (laser_length < 0)
kill();

//Create the Beam's Fill, tell it to rotate equal to the beam.
var pattern:BitmapData = FlxG.addBitmap(IMG_LASER);
canvas.graphics.moveTo(newOrigin.x, newOrigin.y);
var patternMatrix:Matrix = new Matrix();
            patternMatrix.rotate(FAngle * Math.PI / 180);
canvas.graphics.beginBitmapFill(pattern, patternMatrix, true, true);

//Create the Actual Beam. Starts at origin.
canvas.graphics.lineTo(closeRight.x,closeRight.y);
canvas.graphics.lineTo(farRight.x,farRight.y);
canvas.graphics.lineTo(farLeft.x,farLeft.y);
canvas.graphics.lineTo(closeLeft.x, closeLeft.y);
canvas.graphics.lineTo(newOrigin.x, newOrigin.y);
canvas.graphics.endFill();

//Add the spark at the end
sparkCur += sparkDir;
if (sparkCur == sparkMax || sparkCur == sparkMin) sparkDir = -sparkDir;
patternMatrix.createGradientBox(sparkCur * 2, sparkCur * 2, 0 , sparkpoint.x-sparkCur, sparkpoint.y-sparkCur);
canvas.graphics.beginGradientFill(GradientType.RADIAL, [ 0xffffff, 0x9BFFFF], [1, 1], [100, 255], patternMatrix);
canvas.graphics.drawCircle(sparkpoint.x, sparkpoint.y, sparkCur);
canvas.graphics.endFill();

//Add the Glow
glowCur += glowDir;
if (glowCur == glowMax || glowCur == glowMin) glowDir = -glowDir;
var glow:GlowFilter = new GlowFilter;
glow.color = 0x7CC2FF;
glow.strength = 4;
glow.blurX = glowCur;
glow.blurY = glowCur;
glow.alpha = glowCur / glowMax;
canvas.filters = [glow];
//Add the blur
var blur:BlurFilter = new BlurFilter(2,2,1);
canvas.filters = [glow,blur];

//Draw it in, finally.
FlxG.buffer.draw(canvas, null, null,"hardlight");
}
}
}

Garmichael

  • Member
  • **
  • Posts: 89
  • Karma: +0/-0
    • View Profile
Re: Theory behind Laser Beams?
« Reply #14 on: Fri, May 14, 2010 »
Okay, I need one more bit of help.

How do I check for overlap? I looked at the source for overlap, and the comments say that it doesn't consider scrollfactor, which I assume is the problem.

zuperxtreme

  • Contributor
  • ****
  • Posts: 254
  • Karma: +0/-0
    • View Profile
    • Buddah
Re: Theory behind Laser Beams?
« Reply #15 on: Thu, Aug 11, 2011 »
Sorry to bump an old topic, but were you able to get your lasers to collide with FlxSprites/Groups?
..."without order nothing exists, without chaos nothing evolves"... 
Zoklet.net

babyMonkey

  • New Member
  • *
  • Posts: 2
  • Karma: +0/-0
    • View Profile
Re: Theory behind Laser Beams?
« Reply #16 on: Sun, Aug 14, 2011 »
Sorry to bump too,
i tried the coding from Garmichael, it works, but i don't think it can collide or overlap a FlxSprite.
Help somebody???

babyMonkey

  • New Member
  • *
  • Posts: 2
  • Karma: +0/-0
    • View Profile
Re: Theory behind Laser Beams?
« Reply #17 on: Mon, Aug 15, 2011 »
I forgot to say that i'm really new at this.
But since I noticed that any FlxSprite (excluding FlxSprite that use Shape) would detect collision/overlap, i just added a :

this.createGraphic(laser_length, 10, 0x00000000);


in the override render function and it works (eventhough still not perfectly the way i want it). I still don't get why even if i set the alpha of the color to 100%, i still can't see the graphic. Maybe it's because the buffer.draw will draw over it. I also don't get why eventhough i set the width of the createGraphic to laser_length, the graphic is actually longer than the drawing of the canvas, thus making it look as if the object intended to be killed when zapped is already zapped pixels before it actually touches the laser.

Esti

  • Active Member
  • ***
  • Posts: 104
  • Karma: +0/-0
    • View Profile
Re: Theory behind Laser Beams?
« Reply #18 on: Mon, Jan 7, 2013 »
It looks like the laser class is outdated and the demo disappeared   :'(

Someone can shed some light on this?

Check it out on Mochi!

wg/funstorm

  • Global Moderator
  • Key Contributor
  • *****
  • Posts: 596
  • Karma: +0/-0
    • View Profile
    • Funstorm
Re: Theory behind Laser Beams?
« Reply #19 on: Mon, Jan 7, 2013 »
Getting a fully functional laser is actually a lot of work in my experience. It includes...
- drawing a laser graphic
- figuring out where the laser collides with the world and stopping the graphic there
- figuring out when the player / enemies / objects are colliding with the laser

From reading the posts in the thread, it sounds like the class only took care of drawing the laser and world collision is only checked while the beam is growing.

I think this tutorial does it better... it deals with drawing the laser and colliding it with an FlxTilemap (but leaves out the player-laser collision): http://bullettimeninja.blogspot.co.uk/2012/01/lasers-and-ray-casting.html
« Last Edit: Mon, Jan 7, 2013 by wg/funstorm »