Hi everyone, pretty rad board here with lots of great talent! I'm building my first shmup and have conquered all problems except the beam weapon! I'm not interested in the collision detection part--I already have that down pretty well.
There's basically two methods that I know of:
1) Draw lines. The advantage here is that it "fits" perfectly--it's always a long as it should be because you only draw from point A to point B. Drawback is that it's just a line--no fancy gradients.
2) Paste down images in sequence. Starting from point A you copy pixels from the beam image (just a small segment). Advantage is that it looks as awesome as you draw it in Photoshop. Disadvantage is that, depending on the size of the segments, they can appear to overlap with the target. The obvious solution is to use really small segments, but the smaller they are, the more pixels are needlessly drawn (since I'm using baked rotation so there'd be a lot of transparent pixels), the bigger the performance hit.
So how have you solved this? What's the best way to draw lasers?
Having trouble coding laser beam graphics
-
- Posts: 6
- Joined: Tue Nov 30, 2010 3:41 am
Re: Having trouble coding laser beam graphics
There's a few ways you can achieve this.
Firstly, if you want a beam - you can scale and stretch your image... though I don't like that approach much - it can result in a nice look.
The other is to have it laid down in segments as you've said, you take the base of your laser and then you trace up in increments of whatever your laser is. The trick is always to hide what you're actually doing. If you can somehow get the exact Y axis point at which the laser collides with the enemy you could display your laser tip there and just draw it big enough to overlap.
Personally, I cheated big time and I just fire a lot of projectiles that move rapidly - then when the laser is off, apply any cleanup effects (like removing the players laser projectiles from the screen) and I also have a check written so if something crosses a beam half way through and you don't have the "invincible to small enemies" style laser, the beam tip will snap back down to the point of collision by iterating through the player projectiles and killing off any that reside above the point of impact.
Here's how my lasers look using additive glows:-

and the rubbish I typed above in picture form:

HTH, it's not how most people want to do their lasers but since I haven't been brave enough to mess with tristrips and sensibly forming a beam whilst doing other collision checks beyond nice fast rect/rect - this is the solution I've used and the end user doesn't really notice, which is the important bit
- Steve
Firstly, if you want a beam - you can scale and stretch your image... though I don't like that approach much - it can result in a nice look.
The other is to have it laid down in segments as you've said, you take the base of your laser and then you trace up in increments of whatever your laser is. The trick is always to hide what you're actually doing. If you can somehow get the exact Y axis point at which the laser collides with the enemy you could display your laser tip there and just draw it big enough to overlap.
Personally, I cheated big time and I just fire a lot of projectiles that move rapidly - then when the laser is off, apply any cleanup effects (like removing the players laser projectiles from the screen) and I also have a check written so if something crosses a beam half way through and you don't have the "invincible to small enemies" style laser, the beam tip will snap back down to the point of collision by iterating through the player projectiles and killing off any that reside above the point of impact.
Here's how my lasers look using additive glows:-

and the rubbish I typed above in picture form:
HTH, it's not how most people want to do their lasers but since I haven't been brave enough to mess with tristrips and sensibly forming a beam whilst doing other collision checks beyond nice fast rect/rect - this is the solution I've used and the end user doesn't really notice, which is the important bit

- Steve
Re: Having trouble coding laser beam graphics
I do the "draw a line of segments from ship to wherever instantly" approach, as shown here: http://www.youtube.com/watch?v=2QugYr_-gNw
Programming-wise, it's a DO-WHILE loop that moves a laser segment generator a distance (like 32 pixels) and generates a laser segment each loop step until the generator:
1.) hits a multi-HP enemy
2.) goes offscreen
3.) hits the foreground
Each segment is alive for just one frame, being removed after one frame.
Programming-wise, it's a DO-WHILE loop that moves a laser segment generator a distance (like 32 pixels) and generates a laser segment each loop step until the generator:
1.) hits a multi-HP enemy
2.) goes offscreen
3.) hits the foreground
Each segment is alive for just one frame, being removed after one frame.
The age of Alluro and JudgeSpear is over.
Re: Having trouble coding laser beam graphics
I figured out a similar graphic effect awhile back; but I used it as an engine backfire thing rather than a weapon, so I never got around to working out the collision part of it. Glad someone else made this thread, I'm sure I would've wanted to ask eventually. 
All I did was just draw multiple solid color lines, with the first one being drawn as the widest; but with the lowest alpha value and so on until you got to the center one on top, which was the thinnest; but had the highest alpha. Not exactly a true gradient; but it looks pretty smooth with enough layers.

All I did was just draw multiple solid color lines, with the first one being drawn as the widest; but with the lowest alpha value and so on until you got to the center one on top, which was the thinnest; but had the highest alpha. Not exactly a true gradient; but it looks pretty smooth with enough layers.
-
- Posts: 6
- Joined: Tue Nov 30, 2010 3:41 am
Re: Having trouble coding laser beam graphics
This is awesome, thanks everyone for sharing!
@Alluro : I tried layering lines like you said first, but I couldn't figure the math out since my shmup is n-directional shooting (WASD-Mouse controls). I couldn't figure out how to get the lines to appear correctly when at angles other than 0
I suck at math.
For some reason it never occurred to me to NOT draw the last segment/image if it hit, and instead place a hit animation there. Now to see if I can increment the hit sprite's position so that it appears to hit the target perfectly, rather than jump in the larger increments that the beam sprite used.
@Alluro : I tried layering lines like you said first, but I couldn't figure the math out since my shmup is n-directional shooting (WASD-Mouse controls). I couldn't figure out how to get the lines to appear correctly when at angles other than 0

For some reason it never occurred to me to NOT draw the last segment/image if it hit, and instead place a hit animation there. Now to see if I can increment the hit sprite's position so that it appears to hit the target perfectly, rather than jump in the larger increments that the beam sprite used.
Re: Having trouble coding laser beam graphics
Thanks to this thread, I got inspired to take another shot at this. Here's my approach:
The object itself is simply a very fast projectile (something like 10x faster than normal bullets) The beam is created by drawing three images in sequence:
-the 'flash', placed directly in front of the ship
-the tip, used for enemy collisions, placed just slightly past the bullet object's xy coords
-the middle section, which is scaled to meet the other two images at their edges and placed precisely between them.
The idea is that you have a nicely flexible middle part; but without compromising the overall aesthetics of the beam.

@vonWolfehaus:
Are you using Game Maker? If so, I would get acquainted with lengthdir_x and lengthdir_y.
The object itself is simply a very fast projectile (something like 10x faster than normal bullets) The beam is created by drawing three images in sequence:
-the 'flash', placed directly in front of the ship
-the tip, used for enemy collisions, placed just slightly past the bullet object's xy coords
-the middle section, which is scaled to meet the other two images at their edges and placed precisely between them.
The idea is that you have a nicely flexible middle part; but without compromising the overall aesthetics of the beam.

@vonWolfehaus:
Are you using Game Maker? If so, I would get acquainted with lengthdir_x and lengthdir_y.

Re: Having trouble coding laser beam graphics
Same, wrote this today. Code follows.Rozyrg wrote:Thanks to this thread, I got inspired to take another shot at this. Here's my approach:
Basically it enters a while loop and traces up the screen using my collision code (which is optimised to reduce checking against every damned thing on screen by using a collision grid)
I'm actually not using pixel art or traditional sprites for my lasers, instead I'm drawing additive blobs. One other thing to note, when I reset the laser (I've stopped firing in laser mode) -- its max distance gets smacked back down to zero - the result is a laser that extends out at a rate you can control. Playing around with the values of the actual beam shaft itself results in the traditional mushroom head look - as you may notice I draw a large additive blob at the top of the shaft. In this shot it just happens to be of very similar width because I've been playing with the values and procrastinating again

Result can be seen here:
Code: Select all
//-------------------------------------------------------
public void NewGraceLASER()
{
int lnX = 0;
int lnY = 0;
int GLOBBITS = 0;
int lnBeamWidth = 76;
int lnHalfBeam = lnBeamWidth / 2; // Tee hee... premature optimisation? Saves a division each loop..
int lnDamage = 1;
int lnBeamLength = 0;
bool lbHasHit = false;
// First set the origin of the beam to our current point.
mBeamOrigin = Position;
mBeamOrigin.Y -= 64;
lnX = (int)mBeamOrigin.X;
lnY = (int)mBeamOrigin.Y;
// It doesn't move horizontally so only set this once
mBeamHitBox.X = lnX - lnHalfBeam;
// Now trace up the screen
while (lnY > -32)
{
mBeamHitBox.Y = lnY - lnHalfBeam;
mBeamHitBox.X = lnX;
mBeamHitBox.Height = lnBeamWidth;
mBeamHitBox.Width = lnBeamWidth;
lbHasHit = CheckBeamHit(new Vector2(lnX, lnY), mBeamHitBox, lnDamage);
if (lbHasHit) break;
lnY -= 32;
lnBeamLength += 32;
if (lnBeamLength > mMaxBeamLength) break;
GLOBBITS++; if (GLOBBITS > 100) throw new Exception("Beam Error");
}
mMaxBeamLength += 32;
mBeamTip = lnY; // Set the tip of the beam for drawing purposes
}
//-------------------------------------------------------
public bool CheckBeamHit(Vector2 lVec, Rectangle lHitBox, int lnDamage)
{
int neighbours = 0; // The function will fuck with this
int offset = Game1.mEnemyCollGrid.GetNeighbourIndices(lVec, ref neighbours);
for (int g = 0; g < neighbours; g++)
{
int nodeIndex = Game1.mEnemyCollGrid.m_gridcache[offset + g];
if (lHitBox.Intersects(EnemyObjManager.ActiveEnemies[nodeIndex].Hitbox))
{
EnemyObjManager.ActiveEnemies[nodeIndex].TakeDamage((float)lnDamage, lVec, this.MyPlayerIndex, false, true);
return true;
}
}
return false;
}
//-------------------------------------------------------
public void DrawGraceLaser(SpriteBatch lBatch)
{
eShipClass lClass = Player.Players[(int)MyPlayerIndex].Inventory.mClass;
// Return if not applicable.
if (mbAltFireMode == false || lClass != eShipClass.Grace) return;
int lnX = (int)mBeamOrigin.X - 16;
int lnYOrigin = (int)mBeamOrigin.Y - 16;
int lnY = lnYOrigin;
int GLOBBITS = 0;
Color lCol = new Color(shieldColor.R, shieldColor.G, shieldColor.B, 196);//this is free. The joy of async rendering
float lrBaseScale = 64.0f / Config.mSmallGlow.Textures[0].Width;//scale so it normally lines up. ASSUMING SQUARE
float lrGlowScale = 3.0f;
Vector2 lrDrawPos = Vector2.Zero;
while (lnY > (mBeamTip))
{
lrGlowScale = 3.0f;
lrGlowScale += (float)(rnd.Next(-10, 5) / 10);
lrDrawPos.X = lnX + 16;
lrDrawPos.Y = lnY + 16;
for (int i = 0; i < 4; i++)
{
lBatch.Draw(Config.mSmallGlow.Textures[0],lrDrawPos,null, lCol, 0, new Vector2(8), lrBaseScale * lrGlowScale, SpriteEffects.None, 0);
lrGlowScale -= 0.5f;
}
lnY -= 32;
GLOBBITS++;
if (GLOBBITS > 100) throw new Exception("Beam Draw Error");
}
lrGlowScale = 4.0f;
for (int i = 0; i < 16; i++)
{
lrDrawPos.Y = mBeamTip;
lrDrawPos.X = mBeamOrigin.X;
lrGlowScale -= 0.25f;
lBatch.Draw(Config.mSmallGlow.Textures[0], lrDrawPos, null, lCol, 0, new Vector2(8), lrBaseScale * lrGlowScale, SpriteEffects.None, 0);
}
}
Re: Having trouble coding laser beam graphics
DUDE!... your game looks good, do you think you could share a demo with us?... i'd like to take it for a spin!.snafusan wrote:Same, wrote this today. Code follows.Rozyrg wrote:Thanks to this thread, I got inspired to take another shot at this. Here's my approach:
--- snip snip ---
SuperPang wrote:Where DOJ rapes you, DFK grabs your boob then runs away.
Re: Having trouble coding laser beam graphics
^ Agreed. Also, game needs a dedicated thread.
IGMO - Poorly emulated, never beaten.
Hi-score thread: http://shmups.system11.org/viewtopic.php?f=2&t=34327
Hi-score thread: http://shmups.system11.org/viewtopic.php?f=2&t=34327
-
- Posts: 6
- Joined: Tue Nov 30, 2010 3:41 am
Re: Having trouble coding laser beam graphics
@Rozyrg No I'm targeting Flash Player 10.1, built using FlashDevelop (pure AS3).
@snafusan I ended up doing what you describe in your explanatory graphic. I didn't want to because when it collides, it stops in "chunks" and doesn't move exactly right up to the sprite in a pixel-perfect manner (which is what my detection alg is).
For drawing, I caved and used Flash's built-in vector graphics to do a lineTo()--in combination with a gradient matrix I can get some awesome glow effects and the beam can scale as big as I want and the performance hit is the same (plus I can work the gradient to whatever colors so it looks fantastic).
But the bigger the beam, the bigger the invisible collision sprite has to be, the bigger the "chunk" the beam moves in.. so the "skips" are obvious if the beam is over 50 pixels or so
EDIT: I just thought about this--I could decrease the step of the collision sprite... but that means a LOT more checks, which mean a lot more performance issues. But there's probably a sweet spot I can look for...
@snafusan I ended up doing what you describe in your explanatory graphic. I didn't want to because when it collides, it stops in "chunks" and doesn't move exactly right up to the sprite in a pixel-perfect manner (which is what my detection alg is).
For drawing, I caved and used Flash's built-in vector graphics to do a lineTo()--in combination with a gradient matrix I can get some awesome glow effects and the beam can scale as big as I want and the performance hit is the same (plus I can work the gradient to whatever colors so it looks fantastic).
But the bigger the beam, the bigger the invisible collision sprite has to be, the bigger the "chunk" the beam moves in.. so the "skips" are obvious if the beam is over 50 pixels or so

EDIT: I just thought about this--I could decrease the step of the collision sprite... but that means a LOT more checks, which mean a lot more performance issues. But there's probably a sweet spot I can look for...