Hallo Community!
Ich brauchte für ein Projekt einen Algorithmus der Blitze erzeugen kann und habe mir mangels bereits verfügbarem Code selbst einen geschrieben. Damit der nächste das nicht mehr machen muss... oder zumindest nicht bei Null anfangen muss, hier der Code:
Version 1: www.blitzforum.de/upload/file.php?id=12876
Version 2 (Update von DAK):
BlitzMax: [AUSKLAPPEN] [EINKLAPPEN] Type TLightning Const MIN_SEG_LENGTH:Int = 20 Const MIN_SEG_BRANCH_LENGTH:Int = 5 Const BRANCH_ANGLE_MOD:Int = 40 Const GLOWCOLOR_R:Int = 100 Const GLOWCOLOR_G:Int = 100 Const GLOWCOLOR_B:Int = 255 Field segments:TList = CreateList() Field branches:TList = CreateList() Field branches2:TList = CreateList() Field generations:Int = 4 Field offset:Int = 10
Function getInstance:TLightning(x1:Int, y1:Int, x2:Int, y2:Int) Local instance:TLightning = New TLightning instance.setStartEndPoint(x1, y1, x2, y2) Return instance End Function
Method setStartEndPoint(x1:Int, y1:Int, x2:Int, y2:Int) Local startpoint:TPoint = TPoint.getInstance(x1, y1) Local endpoint:TPoint = TPoint.getInstance(x2, y2) Local firstSeg:TSegment = TSegment.getInstance(startpoint, endpoint) Self.segments.Clear() Self.branches.Clear() Self.branches2.Clear() Self.segments.AddFirst(firstSeg) Self.segmentize(Self.segments, Self.generations, Self.offset) Self.branches = Self.createBranches(Self.segments) Self.segmentize(Self.branches, Self.generations - 1, Self.offset - 7, True) Self.branches2 = Self.createBranches(Self.branches) Self.segmentize(Self.branches2, Self.generations - 3, Self.offset - 7, True) End Method
Method draw() SetBlend(ALPHABLEND) Self.setDrawings(0.4, 3, True) Self.drawSegments(Self.branches2) Self.setDrawings(0.5, 1) Self.drawSegments(Self.branches2) Self.setDrawings(0.5, 5, True) Self.drawSegments(Self.branches) Self.setDrawings(0.6, 1) Self.drawSegments(Self.branches) Self.setDrawings(0.09, 20, True) Self.drawSegments(Self.segments) Self.setDrawings(0.25, 11, True) Self.drawSegments(Self.segments) Self.setDrawings(0.55, 6, True) Self.drawSegments(Self.segments) SetColor(255, 255, 255) SetAlpha(1.0) Local counter:Int = 0 For Local seg:TSegment = EachIn Self.segments counter:+1 Local thickness:Float = 0.3 * Float(Self.segments.Count() - counter) If thickness < 2.0 Then thickness = 2.0 SetLineWidth(thickness) DrawLine(seg.startpoint.x, seg.startpoint.y, seg.endpoint.x, seg.endpoint.y) Next End Method
Method drawSegments(givenList:TList) Local realLineWidth:Float = GetLineWidth() For Local seg:TSegment = EachIn givenList Local lineWidth:Float = realLineWidth/2 Local ps1point:TPoint Local ps2point:TPoint Local pe1point:TPoint Local pe2point:TPoint Local lastSeg:TSegment = seg.lastSegment Local nextSeg:TSegment = seg.nextSegment Local tvec:TPoint = seg.endpoint.sub(seg.startpoint) Local tvecn:TPoint = tvec.normalize() Local tnorm:TPoint = tvec.normalize().normal() If (lastSeg=Null) Then ps1point = seg.startpoint.add(tnorm.mult(lineWidth)) ps2point = seg.startpoint.add(tnorm.mult(-lineWidth)) Else Local lvec:TPoint = lastSeg.endpoint.sub(lastSeg.startpoint) Local lnorm:TPoint = lvec.normalize().normal() ps1point = seg.startpoint.add(lnorm.mult(lineWidth)) ps2point = seg.startpoint.add(lnorm.mult(-lineWidth)) EndIf If (nextSeg=Null) Then lineWidth = lineWidth/2 EndIf pe1point = seg.endpoint.add(tnorm.mult(-lineWidth)) pe2point = seg.endpoint.add(tnorm.mult(lineWidth)) Local corners:Float[] = [ps1point.x,ps1point.y,ps2point.x,ps2point.y,pe1point.x,pe1point.y,pe2point.x,pe2point.y] DrawPoly(corners) SetColor(TLightning.GLOWCOLOR_R, TLightning.GLOWCOLOR_G, TLightning.GLOWCOLOR_B) Next End Method
Method setDrawings(alpha:Float, lineThickness:Float, isGlowing:Byte = False) SetColor(255, 255, 255) If isGlowing Then SetColor(TLightning.GLOWCOLOR_R, TLightning.GLOWCOLOR_G, TLightning.GLOWCOLOR_B) SetAlpha(alpha) SetLineWidth(lineThickness) End Method
Method segmentize(givenList:TList, generations:Int, offset:Int, isBranch:Byte = False) If givenList.IsEmpty() Then Return Local minLength:Int = TLightning.MIN_SEG_LENGTH If isBranch Then minLength = TLightning.MIN_SEG_BRANCH_LENGTH For Local i:Int = 1 To generations Local workList:TList = givenList.Copy() For Local seg:TSegment = EachIn workList If TDistance.pointToPoint(seg.startpoint.x, seg.startpoint.y, seg.endpoint.x, seg.endpoint.y) >= minLength Then Local lastSegment:TSegment = seg.lastSegment Local nextSegment:TSegment = seg.nextSegment givenList.Remove(seg) Local midpoint:TPoint = seg.getMidPoint() Local randomAngle:Int = 90 If Rand(1, 2) = 1 Then randomAngle = -90 midpoint.x:+(Cos(seg.angle + randomAngle) * offset) midpoint.y:+(Sin(seg.angle + randomAngle) * offset) Local seg1:TSegment = TSegment.getInstance(seg.startpoint, midpoint) Local seg2:TSegment = TSegment.getInstance(midpoint, seg.endpoint) seg1.lastSegment = lastSegment seg1.nextSegment = seg2 seg2.lastSegment = seg1 seg2.nextSegment = nextSegment If (lastSegment<>Null) Then lastSegment.nextSegment = seg1 If (nextSegment<>Null) Then nextSegment.lastSegment = seg2 givenList.AddLast(seg1) givenList.AddLast(seg2) End If Next Next End Method
Method createBranches:TList(givenList:TList) If givenList.IsEmpty() Then Return Null Local returnList:TList = New TList Local i:Int = 0 For Local seg:TSegment = EachIn givenList i:+1 Local branchAngle:Int = seg.angle + Rand(-TLightning.BRANCH_ANGLE_MOD, TLightning.BRANCH_ANGLE_MOD) Local branchLength:Int = Float((Rnd(1.0, 3.0) * TDistance.pointToPoint(seg.startpoint.x, seg.startpoint.y, seg.endpoint.x, seg.endpoint.y))) * Float((Float(i) / Float(givenList.Count()))) Local branchX:Int = seg.endpoint.x + Cos(branchAngle) * branchLength Local branchY:Int = seg.endpoint.y + Sin(branchAngle) * branchLength Local branchpoint:Tpoint = TPoint.getInstance(branchX, branchY) Local branch:TSegment = TSegment.getInstance(seg.endpoint, branchpoint) returnList.AddLast(branch) Next Return returnList End Method End Type
Type TSegment Field startpoint:TPoint Field endpoint:TPoint Field angle:Int Field lastSegment:TSegment Field nextSegment:TSegment
Function getInstance:TSegment(startpoint:TPoint, endpoint:TPoint) Local instance:TSegment = New TSegment instance.startpoint = startpoint instance.endpoint = endpoint instance.angle = ATan2((endpoint.y - startpoint.y), (endpoint.x - startpoint.x)) Return instance End Function
Method getMidPoint:TPoint() Local midpoint:Tpoint = New TPoint midpoint.x = (startpoint.x + endpoint.x)/2 midpoint.y = (startpoint.y + endpoint.y)/2 Return midpoint End Method End Type
Type TPoint Field x:Float Field y:Float
Function getInstance:TPoint(x:Float, y:Float) Local instance:TPoint = New TPoint instance.x = x instance.y = y Return instance End Function
Method add:TPoint(other:TPoint) Return getInstance(x+other.x,y+other.y) End Method
Method sub:TPoint(other:TPoint) Return getInstance(x-other.x,y-other.y) End Method
Method mult:TPoint(f:Float) Return getInstance(x*f,y*f) End Method
Method length:Float() Return Sqr(x*x+y*y) End Method
Method normalize:TPoint() Return mult(1.0/length()) End Method
Method normal:TPoint() Return getInstance(y,-x) End Method
Method dot:Float(other:TPoint) Return (x*other.x+y*other.y) End Method End Type
Type TDistance Abstract
Function pointToPoint:Double(x1:Double, y1:Double, x2:Double, y2:Double) Return Sqr(TDistance.quad(x2 - x1) + TDistance.quad(y2 - y1)) End Function
Function quad:Double(v:Double) Return (v * v) End Function End Type
+ Demo: www.blitzforum.de/upload/file.php?id=12877
BlitzMax: [AUSKLAPPEN] [EINKLAPPEN] Include "Lightning.bmx"
Graphics 1024, 768 Global blitz:TLightning = TLightning.getInstance(100, 100, 500, 500) Global oldMausX:Int Global oldMausY:Int SetClsColor(10, 10, 10)
Repeat Cls If MouseX() <> oldMausX Or MouseY() <> oldMausY Then oldMausX = MouseX() oldMausY = MouseY() blitz.setStartEndPoint(100, 100, MouseX(), MouseY()) End If blitz.draw() Flip Until AppTerminate()
Optisch wie ich finde brauchbar, allerdings ist auch noch deutlich Potential nach oben... also wer das ganze noch verbessern möchte, nur zu!
Aus Faulheitsgründen habe ich auch nicht mehr Funktionen hinzugefügt, um den Blitz zu modifizieren.
So siehts aus:
Und lässt sich so simpel wie folgt benutzen:
BlitzMax: [AUSKLAPPEN] [EINKLAPPEN] Local blitz:TLightning = TLightning.getInstance(startX, startY, endX, endY) blitz.draw()
|