OP
Expert
Joined: Feb 2008
Posts: 3,232
Australia
|
Heres another little something Ive put together, a LIGHTING BOLT generator. Ever needed a genuinely random, 3D lightning-strike from point A to boint B? With variable thickness, color, and complexity? And with a cool glowing after-image? (retina-burn) Ever wanted that "beautiful" bolt to be repeatable at a later time? Now you can with a single function call. Comes as a complete DEMO main.c with no necessary additional files. Plenty of included documentation. Once again, any suggestions, questions, or instructional issues, just let me know... [EDIT] NOW BUGFIXED FOR A7 Ver 7.82.2 !!
#include <acknex.h>
#include <default.c>
//
//
//////////////////////////////////////////////////////////////////////////////////////////
// 3D-LIGHTNING-BOLT-SPAWN 2.1 //
// --------------------------- //
// //
// Author : EvilSOB //
// Date : 31-07-2009 //
// Updated : 06-04-2010 (7.82.2 bugfix) //
// //
//////////////////////////////////////////////////////////////////////////////////////////
//LB_spawn(VECTOR*Start,VECTOR*Finish,Div,Branch,Depth,Size,COLOR*Core,COLOR*Flare,FlareTime,Seed)//
//--------------------------------------------------------------------------------------//
// Parameters:: //
// Start = Start Vector of Lightning Bolt (sky) //
// Finish = Target Vector of Lightning Bolt (ground) //
// Div = Number of primary "segments" in central bolt (suggest 5->20)//
// Branch = 0.0->1.0 chance to "branch" at primary segment point.(suggest 0.4) //
// Depth = depth of complexity to calculate into branches. (suggest 4) //
// Size = diameter in quants of "core" bolt. (suggest 8) //
// Core = color of lightning "bolt" (suggest 255,128,128)//
// Flare = color of lightning-bolt 'afterimage' (suggest 128, 0, 0)//
// FlareTime= duration in seconds of 'afterimage' (suggest 1.5) //
// Seed = random number seed (for forcing duplicates) (suggest 0) //
// //
// NOTES : "Flare" = NULL or nullvector will suppress the "afterimage" generation. //
// "Seed" = Zero is random, set to "any" number will generate duplicate stikes//
// "Div" = !Be cautious with Divisions above 20, it can be a real FPS eater! //
// "Depth" = !Be cautious with the depth above 3, it can be a real FPS eater! //
// //
//////////////////////////////////////////////////////////////////////////////////////////
// Example:: //
// LB_spawn(me.x, you.x, 15, 0.4, 4, 8, vector(255,128,128), vector(180,0,0), 0); //
// //
//////////////////////////////////////////////////////////////////////////////////////////
// //
//
void LB_segment_fade(PARTICLE* p) { p.lifespan = p.alpha -= time_step*p.skill_x; }
//
void LB_segment_core(PARTICLE* p)
{ vec_set(p.blue, you.skill3);
set(p, BEAM|BRIGHT|TRANSLUCENT|UNLIT|CAST);
p.alpha = 100;
p.size = you.skill2;
p.skill_x = 20;
p.event = LB_segment_fade;
}
//
void LB_segment_flare(PARTICLE* p)
{ vec_set(p.blue, you.skill6);
set(p, BEAM|BRIGHT|TRANSLUCENT|UNLIT|CAST);
p.alpha = 20;
p.size = you.skill2*2;
p.skill_x = 1.28/you.skill7;
p.event = LB_segment_fade;
}
//
void LB_divide(VECTOR* A, VECTOR* B, long Div, float noise, VECTOR** Points)
{ VECTOR *points = (VECTOR*)malloc(sizeof(VECTOR)*Div);
if(!Points) free(*Points); *Points = points;
var idx; for(idx=0; idx<Div; idx++)
{ vec_lerp(points[idx], A, B, (float)idx/(Div-1));
if((idx>0)&&(idx<(Div-1)))
{ points[idx].x += random(noise*2)-noise;
points[idx].y += random(noise*2)-noise;
points[idx].z += random(noise)-noise/2;
} } }
//
//
void LB_spawn(VECTOR* Start, VECTOR* Finish, long Div, float Branch, long Depth, long Size, COLOR* Core, COLOR* Flare, float FlareTime, var Seed)
{ if(Div<3) return;
if(!Seed) Seed = timer();
VECTOR A, B, C, D, tmpV, corec, flarec, *fine=0, *crude=0; vec_zero(flarec);
vec_set(A, Start); vec_set(B, Finish); vec_set(corec, Core);
if(Flare) vec_set(flarec, Flare);
wait(1);
long i, cnt, seg_size = vec_dist(A,B)/Div; random_seed(Seed);
LB_divide(A, B, Div, vec_dist(A,B)/(Div+1), crude);
me = ent_create(NULL, NULL, NULL); me.skill2 = Size; vec_set(me.skill3, corec);
vec_set(me.skill6, flarec); me.skill7 = FlareTime;
for(i=1; i<Div; i++)
{ LB_divide(crude[i-1],crude[i],Div/2,vec_dist(crude[i-1],crude[i])/Div/2+1,fine);
for(cnt=1; cnt<(Div/2); cnt++)
{ vec_set(tmpV, fine[cnt]); vec_sub(tmpV, fine[cnt-1]);
if(vec_length(tmpV))
vec_scale(tmpV, vec_length(tmpV)/vec_length(tmpV));
if(vec_length(flarec)) effect(LB_segment_flare, 1, fine[cnt-1], tmpV);
effect(LB_segment_core, 1, fine[cnt-1], tmpV); }
if((Depth>1)&&(random(1)<Branch)&&(i<(Div-1)))
{ vec_diff(C, crude[i], crude[i-1]);
vec_diff(D, crude[i], crude[i+1]);
vec_lerp(tmpV, D, C, random(1)+0.35);
vec_normalize(tmpV, random(seg_size*(Div-i))*0.6); vec_add(tmpV,crude[i]);
LB_spawn(crude[i], tmpV, Div*0.6, Branch, Depth-1, Size*0.6, corec, flarec, FlareTime, Seed+random(15));
} }
wait(1); ent_remove(me); free(crude); free(fine);
}
//
//
//////////////////////////////////////////////////////////////////////////////////////////
//
//
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
// Remaining code is for DEMO purposes only. //
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
//
//
VECTOR FromPoint, ToPoint;
var strike() { LB_spawn(FromPoint, ToPoint, 20, 0.7, 7, 8, vector(255,128,128), vector(180,0,0), 1.5, 00); }
var arcing()
{ var last_key = key_lastpressed;
while(key_pressed(last_key))
{ LB_spawn(FromPoint, ToPoint, 13, 0.6, 3, 13, vector(255,128,128), vector(128,0,0), 1, 0);
wait(-0.07);
} }
//
//
function main()
{ max_entities = 10000;
level_load(NULL); wait(2); diag("\n\n\n");
vec_set(sky_color, vector(1,1,1));
vec_set(camera.x, vector(-700,0,255));
//
vec_set(FromPoint, vector(0,0,500));
vec_set(ToPoint, vector(0,100,0));
on_space = strike;
on_enter = arcing;
//
//
strike();
while(1)
{
draw_text(_str("Hit SPACEBAR for Lightning Strike!"), 10, 10, NULL);
draw_text(_str("Hold ENTER for an Elecrical Arc!"), 10, 30, NULL);
draw_point3d(FromPoint, vector(255,200,200), 100, 10);
draw_point3d(ToPoint, vector(255,200,200), 100, 10);
wait(1);
}
//
sys_exit("");
}
For historical purposes, here is Version 2.0. Its the same as 2.1, just doesnt allow control over the color of the after-image 'flare'.
#include <acknex.h>
#include <default.c>
//
//
//////////////////////////////////////////////////////////////////////////////////////////
// 3D-LIGHTNING-BOLT-SPAWN 2.0 //
// --------------------------- //
// //
// Author : EvilSOB //
// Date : 31-07-2009 //
// Updated : 06-04-2010 (7.82.2 bugfix) //
// //
//////////////////////////////////////////////////////////////////////////////////////////
//LB_spawn(VECTOR*Start,VECTOR*Finish,Div,Branch,Depth,Size,COLOR*Core,COLOR*Flare,Seed)//
//--------------------------------------------------------------------------------------//
// Parameters:: //
// Start = Start Vector of Lightning Bolt (sky) //
// Finish = Target Vector of Lightning Bolt (ground) //
// Div = Number of primary "segments" in central bolt (suggest 5->20)//
// Branch = 0.0->1.0 chance to "branch" at primary segment point.(suggest 0.4) //
// Depth = depth of complexity to calculate into branches. (suggest 4) //
// Size = diameter in quants of "core" bolt. (suggest 8) //
// Core = color of lightning "bolt" (suggest 255,128,128)//
// Flare = color of lightning-bolt 'afterimage' (suggest 128, 0, 0)//
// Seed = random number seed (for forcing duplicates) (suggest 0) //
// //
// NOTES : "Flare" = NULL or nullvector will suppress the "afterimage" generation. //
// "Seed" = Zero is random, set to "any" number will generate duplicate stikes//
// "Div" = !Be cautious with Divisions above 20, it can be a real FPS eater! //
// "Depth" = !Be cautious with the depth above 3, it can be a real FPS eater! //
// //
//////////////////////////////////////////////////////////////////////////////////////////
// Example:: //
// LB_spawn(me.x, you.x, 15, 0.4, 4, 8, vector(255,128,128), vector(180,0,0), 0); //
// //
//////////////////////////////////////////////////////////////////////////////////////////
// //
//
void LB_segment_fade(PARTICLE* p) { p.lifespan = p.alpha -= time_step*p.skill_x; }
//
void LB_segment_core(PARTICLE* p)
{ vec_set(p.blue, you.skill3);
set(p, BEAM|BRIGHT|TRANSLUCENT|UNLIT|CAST);
p.alpha = 100;
p.size = you.skill2;
p.skill_x = 20;
p.event = LB_segment_fade;
}
//
void LB_segment_flare(PARTICLE* p)
{ vec_set(p.blue, you.skill6);
set(p, BEAM|BRIGHT|TRANSLUCENT|UNLIT|CAST);
p.alpha = 20;
p.size = you.skill2*2;
p.skill_x = 1;
p.event = LB_segment_fade;
}
//
void LB_divide(VECTOR* A, VECTOR* B, long Div, float noise, VECTOR** Points)
{ VECTOR *points = (VECTOR*)malloc(sizeof(VECTOR)*Div);
if(!Points) free(*Points); *Points = points;
var idx; for(idx=0; idx<Div; idx++)
{ vec_lerp(points[idx], A, B, (float)idx/(Div-1));
if((idx>0)&&(idx<(Div-1)))
{ points[idx].x += random(noise*2)-noise;
points[idx].y += random(noise*2)-noise;
points[idx].z += random(noise)-noise/2;
} } }
//
//
void LB_spawn(VECTOR* Start, VECTOR* Finish, long Div, float Branch, long Depth, long Size, COLOR* Core, COLOR* Flare, var Seed)
{ if(Div<3) return;
if(!Seed) Seed = timer();
VECTOR A, B, C, D, tmpV, corec, flarec, *fine=0, *crude=0; vec_zero(flarec);
vec_set(A, Start); vec_set(B, Finish); vec_set(corec, Core);
if(Flare) vec_set(flarec, Flare);
wait(1);
long i, cnt, seg_size = vec_dist(A,B)/Div; random_seed(Seed);
LB_divide(A, B, Div, vec_dist(A,B)/(Div+1), crude);
me = ent_create(NULL, NULL, NULL); me.skill2 = Size;
vec_set(me.skill3, corec); vec_set(me.skill6, flarec);
for(i=1; i<Div; i++)
{ LB_divide(crude[i-1],crude[i],Div/2,vec_dist(crude[i-1],crude[i])/Div/2+1,fine);
for(cnt=1; cnt<(Div/2); cnt++)
{ vec_set(tmpV, fine[cnt]); vec_sub(tmpV, fine[cnt-1]);
if(vec_length(tmpV))
vec_scale(tmpV, vec_length(tmpV)/vec_length(tmpV));
if(vec_length(flarec)) effect(LB_segment_flare, 1, fine[cnt-1], tmpV);
effect(LB_segment_core, 1, fine[cnt-1], tmpV); }
if((Depth>1)&&(random(1)<Branch)&&(i<(Div-1)))
{ vec_diff(C, crude[i], crude[i-1]);
vec_diff(D, crude[i], crude[i+1]);
vec_lerp(tmpV, D, C, random(1)+0.35);
vec_normalize(tmpV, random(seg_size*(Div-i))*0.6); vec_add(tmpV,crude[i]);
LB_spawn(crude[i], tmpV,Div*0.6,Branch,Depth-1,Size*0.6, corec, flarec, Seed+random(15));
} }
wait(1); ent_remove(me); free(crude); free(fine);
}
//
//
//////////////////////////////////////////////////////////////////////////////////////////
//
//
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
// Remaining code is for DEMO purposes only. //
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
//
//
VECTOR FromPoint, ToPoint;
var strike() { LB_spawn(FromPoint, ToPoint, 20, 0.4, 5, 8, vector(255,128,128), vector(180,0,0), 0); }
var arcing()
{ var last_key = key_lastpressed;
while(key_pressed(last_key))
{ LB_spawn(FromPoint, ToPoint, 10, 0.4, 2, 10, vector(255,128,128), vector(180,0,0), 0);
wait(-0.07);
} }
//
//
function main()
{
warn_level = 6;
level_load(NULL); wait(2); diag("\n\n\n");
vec_set(sky_color, vector(1,1,1));
vec_set(camera.x, vector(-700,0,255));
//
vec_set(FromPoint, vector(0,0,500));
vec_set(ToPoint, vector(0,100,0));
on_space = strike;
on_1 = arcing;
//
//
strike();
while(1)
{
draw_text(_str("Hit SPACEBAR for Lightning Strike!"), 10, 10, NULL);
draw_point3d(FromPoint, vector(255,200,200), 100, 10);
draw_point3d(ToPoint, vector(255,200,200), 100, 10);
wait(1);
}
//
sys_exit("");
}
Also historical purposes, here is Ye-Olde Version 1.0. Much simpler code. Its basically the same as 2.0, but doesnt allow ANY control over the after-image 'flare'.
#include <acknex.h>
#include <default.c>
//
//
//////////////////////////////////////////////////////////////////////////////////////////
// 3D-LIGHTNING-BOLT-SPAWN 1.0 //
// --------------------------- //
// //
// Author : EvilSOB //
// Date : 25-07-2009 //
// //
//////////////////////////////////////////////////////////////////////////////////////////
//LB_spawn(VECTOR* start, VECTOR* finish, long Div, float branch, long depth, long size)//
//--------------------------------------------------------------------------------------//
// Parameters:: //
// start = Start Vector of Lightning Bolt (sky) //
// finish = Target Vector of Lightning Bolt (ground) //
// Div = Number of primary "segments" in central bolt (suggest 20) //
// branch = 0.0->1.0 chance to "branch" at primary segment point. (suggest 0.4) //
// depth = depth of complexity to calculate into branches. (suggest 4) //
// size = diameter in quants of "core" bolt.(2^depth minimum) (suggest 8) //
// //
//////////////////////////////////////////////////////////////////////////////////////////
// Example:: //
// LB_spawn(start, finish, 20, 0.4, 4, 8); //
// //
//////////////////////////////////////////////////////////////////////////////////////////
// //
void LB_segment_fade(PARTICLE* p)
{ p.alpha -= 20 * p.skill_a * time_step;
if (p.alpha <= 0) p.lifespan = 0;
}
//
void LB_segment_flare(PARTICLE* p)
{ vec_set(p.blue, vector(128,0,0));
set(p, BEAM|BRIGHT|TRANSLUCENT|UNLIT|CAST);
p.alpha = 50;
p.size = (long)you*3;
p.skill_a = 0.3;
p.event = LB_segment_fade;
}
//
void LB_segment_core(PARTICLE* p)
{ vec_set(p.blue, vector(255,128,128));
set(p, BEAM|BRIGHT|TRANSLUCENT|UNLIT|CAST);
p.alpha = 100;
p.size = (long)you;
p.skill_a = 1.5;
p.event = LB_segment_fade;
}
//
void LB_draw_segment(VECTOR *start, VECTOR *finish, long size)
{ me = size;
VECTOR tmpV; vec_set(tmpV, finish); vec_sub(tmpV,start);
effect(LB_segment_core, 5, start, tmpV);
effect(LB_segment_flare, 1, start, tmpV);
me = size;
}
//
//
void LB_randomize(VECTOR* point, float noise)
{
point.x += random(noise*2)-noise;
point.y += random(noise*2)-noise;
point.z += random(noise)-noise/2;
}
//
void LB_subdivide(VECTOR* A, VECTOR* B, long Div, float noise, VECTOR** Points)
{ VECTOR *points = (VECTOR*)malloc(sizeof(VECTOR)*Div);
if(!Points) free(*Points); *Points = points;
var idx; for(idx=0; idx<Div; idx++)
{ vec_lerp(points[idx], A, B, (float)idx/(Div-1));
if((idx>0)&&(idx<(Div-1))) LB_randomize(points[idx], noise);
}
}
//
void LB_spawn(VECTOR* start,VECTOR* finish,long Div,float branch,long depth,long size)
{ VECTOR A, B; vec_set(A, start); vec_set(B, finish); wait(1);
long i, cnt, seg_size=vec_dist(A,B)/Div;
VECTOR *fine=0, *crude=0; LB_subdivide(A, B, Div, vec_dist(A,B)/(Div+1), crude);
for(i=1; i<Div; i++)
{ LB_subdivide(crude[i-1],crude[i],Div/2,vec_dist(crude[i-1],crude[i])/Div/2+1,fine);
for(cnt=1; cnt<(Div/2); cnt++) LB_draw_segment(fine[cnt-1], fine[cnt], size);
if((depth>1)&&(random(1)<branch))
{ VECTOR tmpV; vec_set(tmpV,crude[i]); LB_randomize(tmpV, vec_dist(A,B)/5);
LB_spawn(crude[i-1], tmpV, Div/2, branch, depth-1, size/2);
} }
free(crude); free(fine);
}
//////////////////////////////////////////////////////////////////////////////////////////
//
//
VECTOR start, finish;
void strike() { LB_spawn(start, finish, 20, 0.4, 4, 8); }
//
//
function main()
{
level_load(NULL); wait(2); diag("\n\n\n");
vec_set(sky_color, vector(1,1,1));
vec_set(camera.x, vector(-700,0,255));
//
on_space = strike;
//
vec_set(start, vector(0,0,500));
vec_set(finish, vector(0,100,0));
LB_spawn(start, finish, 20, 0.4, 4, 8);
//
while(1)
{
draw_point3d(start, vector(255,200,200), 100, 10);
draw_point3d(finish, vector(255,200,200), 100, 10);
wait(1);
}
}
Last edited by EvilSOB; 04/05/10 15:10.
"There is no fate but what WE make." - CEO Cyberdyne Systems Corp. A8.30.5 Commercial
|