Hallo,
ich möchte hier kurz vorstellen, woran ich die letzten Tage gearbeitet habe, denn ich denke, es ist durchaus ganz ansehnlich geworden. Zudem könnte es den einen oder anderen interessieren.
Die dynamische Schadensmodell-Berechnung hat mich doch nicht in Ruhe gelassen - ich habe auch in diesem Forum den ein oder anderen Beitrag mit Fragen dazu gepostet. Mir schwebte schon etwas länger eine Idee im Kopf, wie man es zumindest halbwegs realistisch für zwei Dimensionen umsetzen könnte. Dennoch ist es nur eine Pseudo-dynamische Berechnung, denn physikalische Faktoren wie Material oder Stabilität fließen entweder gar nicht oder nur bedingt in die Berechnung mit ein.
Funktionsweise: Die 2D-"Modelle" werden in Würfel eingeteilt, je kleiner die Würfel, desto detaillierter später das Schadensmodell. Jeder dieser Würfel besitzt einen HP-Status - ist dieser auf 0, so wird der Würfel (das sog. Quad) nicht mehr gezeichnet. Dies bildet die Basis (natürlich besitzt das Quad an sich auch noch Verschönerungs-Funktionen (z.B. einen Welleneffekt, etc.) - Aber prinzipiell läuft es so. Aus diesen Quads besteht dann das Modell intern. Nun können Aufprälle simuliert werden, alles was dafür zu tun ist, ist anzugeben, von welcher Himmelsrichtung (relativ gesehen) der Aufprall kam, wie stark er war und in welchem Bereich er auftrat. Aus diesen Parametern werden dann die betreffenden Quads angepasst und fertig ist das berechnete Schadensmodell, mit dem dann weitergerechnet werden kann.
Das alles funktioniert soweit auch, es gibt allerdings noch ein paar Anomalien, weswegen es sich nur um Version 0.98 handelt. Zudem ist das RAM-Management glaube ich nicht das gelbe vom Ei - hier bin ich für Vorschläge offen. Womit ich auch noch nicht zufrieden bin ist die relativ hohe Prozessorauslastung bei wenigen Modellen. Dies könnte an den Pixmaps liegen, die ich verwende, ein besserer Weg fällt mir aber leider nicht ein.
So, jetzt aber genug geredet, hier mal ein paar Bilder (links das "normale" Modell):
Und der Quellcode (des Includes):
BlitzMax: [AUSKLAPPEN] [EINKLAPPEN]
SuperStrict
SeedRnd(MilliSecs())
Private Function BitIsSet:Byte(Data:Byte, Bits:Byte) If (Data & Bits = Bits) Return True Else Return False EndIf End Function
Public
Type TDDMQuad Const FLAG_NONE:Byte = 0 Const FLAG_ISENGINE:Byte = 1 Const FLAG_ISWHEEL:Byte = 2 Const FLAG_GODQUAD:Byte = 4 Const FLAG_ISBORDER:Byte = 8 Const FLAG_ISEDGE:Byte = 16 Const FLAG_ISCOLORED:Byte = 32 Const FLAG_DEFORMEDL:Byte = 64 Const FLAG_DEFORMEDR:Byte = 128 Const DEFORM_RIGHT:Int = 0 Const DEFORM_LEFT:Int = 1 Const DEFORM_NORTH:Int = 0 Const DEFORM_EAST:Int = 1 Const DEFORM_SOUTH:Int = 2 Const DEFORM_WEST:Int = 3 Const COLLAPSE_NORTH:Int = 0 Const COLLAPSE_EAST:Int = 1 Const COLLAPSE_SOUTH:Int = 2 Const COLLAPSE_WEST:Int = 3 Const QUAD_MAXHEALTH:Double = 100 Field ImageData:TImage Field ColorDataRed:Int Field ColorDataGreen:Int Field ColorDataBlue:Int Field Health:Double Field FLAGS:Byte Field QuadSize:Byte Function CreateImgQuad:TDDMQuad(ImageSrc:TImage, Health:Double = 100, Flags:Byte = FLAG_NONE, QuadSize:Int = 10) Local ReturnMe:TDDMQuad = New TDDMQuad ReturnMe.ImageData = ImageSrc If (Health > QUAD_MAXHEALTH) ReturnMe.Health = QUAD_MAXHEALTH Else ReturnMe.Health = Health EndIf ReturnMe.FLAGS = Flags ReturnMe.QuadSize = QuadSize Return ReturnMe End Function Function CreateColQuad:TDDMQuad(ColorRed:Int, ColorGreen:Int, ColorBlue:Int, Health:Double = 100, Flags:Byte = FLAG_ISCOLORED, QuadSize:Int = 10) Local ReturnMe:TDDMQuad = New TDDMQuad ReturnMe.ColorDataRed = ColorRed ReturnMe.ColorDataGreen = ColorGreen ReturnMe.ColorDataBlue = ColorBlue ReturnMe.Health = Health ReturnMe.FLAGS = Flags ReturnMe.QuadSize = QuadSize Return ReturnMe End Function Method SetHealth(Health:Double) Self.Health = Health End Method Method GetHealth:Double() Return Self.Health End Method Method DrawQuad(PositionX:Double, PositionY:Double) Local prevred:Int Local prevgreen:Int Local prevblue:Int If (Self.Health > 0 Or BitIsSet(Self.FLAGS, FLAG_GODQUAD)) GetColor(prevred, prevgreen, prevblue) If (BitIsSet(Self.FLAGS, FLAG_ISCOLORED)) SetColor(Self.ColorDataRed, Self.ColorDataGreen, Self.ColorDataBlue) DrawRect(PositionX, PositionY, Self.QuadSize, Self.QuadSize) Else If (Self.ImageData <> Null) SetColor(255, 255, 255) DrawImage(Self.ImageData, PositionX, PositionY) EndIf EndIf EndIf SetColor(prevred, prevgreen, prevblue) End Method Method Dent(Direction:Int, InvisibleARGB:Int = $FF000000) Local TakeMe:TImage = CreateImage(Self.QuadSize, Self.QuadSize) Local takemepix:TPixmap = LockImage(TakeMe) Local temppix:TPixmap = LockImage(Self.ImageData) For Local y:Int = 0 To (takemepix.height - 1) For Local x:Int = 0 To (takemepix.width - 1) WritePixel(takemepix, x, y, InvisibleARGB) Next Next Local diff:Int = 0 Local maxdiff:Int = (Self.QuadSize / 4) Local option:Int Local x:Int, y:Int Select(Direction) Case COLLAPSE_NORTH For x = 0 To (Self.QuadSize - 1) option = Rand(0, 1) If (option = 0) diff = diff + 1 If (diff > maxdiff) Then diff = maxdiff Else diff = diff - 1 If (diff < 0) Then diff = 0 EndIf For y = 0 To (Self.QuadSize - 1) If (y + diff < Self.QuadSize And y + diff >= 0) WritePixel(takemepix, x, (y + diff), ReadPixel(temppix, x, y)) Else WritePixel(takemepix, x, y, ReadPixel(temppix, x, y)) EndIf Next Next Case COLLAPSE_EAST For y = 0 To (Self.QuadSize - 1) option = Rand(0, 1) If (option = 0) diff = diff - 1 If (diff < -maxdiff) Then diff = -maxdiff Else diff = diff + 1 If (diff > 0) Then diff = 0 EndIf For x = 0 To (Self.QuadSize - 1) If (x + diff < Self.QuadSize And x + diff >= 0) WritePixel(takemepix, (x + diff), y, ReadPixel(temppix, x, y)) Else WritePixel(takemepix, x, y, ReadPixel(temppix, x, y)) EndIf Next Next Case COLLAPSE_SOUTH For x = 0 To (Self.QuadSize - 1) option = Rand(0, 1) If (option = 0) diff = diff - 1 If (diff < -maxdiff) Then diff = -maxdiff Else diff = diff + 1 If (diff > 0) Then diff = 0 EndIf For y = 0 To (Self.QuadSize - 1) If (y + diff < Self.QuadSize And y + diff >= 0) WritePixel(takemepix, x, (y + diff), ReadPixel(temppix, x, y)) Else WritePixel(takemepix, x, y, ReadPixel(temppix, x, y)) EndIf Next Next Case COLLAPSE_WEST For y = 0 To (Self.QuadSize - 1) option = Rand(0, 1) If (option = 0) diff = diff + 1 If (diff > maxdiff) Then diff = maxdiff Else diff = diff - 1 If (diff < 0) Then diff = 0 EndIf For x = 0 To (Self.QuadSize - 1) If (x + diff < Self.QuadSize And x + diff >= 0) WritePixel(takemepix, (x + diff), y, ReadPixel(temppix, x, y)) Else WritePixel(takemepix, x, y, ReadPixel(temppix, x, y)) EndIf Next Next End Select UnlockImage(Self.ImageData) UnlockImage(TakeMe) Self.ImageData = TakeMe End Method Method Deform(Align:Int, Direction:Int, NextQuad:TDDMQuad, InvisibleARGB:Int = $FF000000) If ((BitIsSet(Self.FLAGS, FLAG_ISEDGE) Or BitIsSet(Self.FLAGS, FLAG_ISBORDER)) And Not BitIsSet(Self.FLAGS, FLAG_ISCOLORED) And NextQuad <> Null) If (BitIsSet(Self.FLAGS, FLAG_DEFORMEDL) Or BitIsSet(Self.FLAGS, FLAG_DEFORMEDR)) Else Local ThisPixmap:TPixmap Local OtherPixmap:TPixmap ThisPixmap = LockImage(Self.ImageData) OtherPixmap = LockImage(NextQuad.ImageData) Local ResImage:TImage Local ResPixmap:TPixmap If (Direction = DEFORM_NORTH Or Direction = DEFORM_SOUTH) ResImage = CreateImage(Self.QuadSize, (Self.QuadSize + NextQuad.QuadSize)) ElseIf(Direction = DEFORM_EAST Or Direction = DEFORM_WEST) ResImage = CreateImage((Self.QuadSize + NextQuad.QuadSize), Self.QuadSize) EndIf ResPixmap = LockImage(ResImage) If (ResPixmap <> Null) Local Offset:Int, x:Int, y:Int, color:Int For y = 0 To (ResPixmap.Height - 1) For x = 0 To (ResPixmap.Width - 1) WritePixel(ResPixmap, x, y, InvisibleARGB) Next Next Select(Direction) Case DEFORM_NORTH If (Align = DEFORM_LEFT) Offset = (ThisPixmap.Height - 1) Else Offset = 0 EndIf For x = 0 To (ThisPixmap.Width - 1) For y = 0 To (ThisPixmap.Height - 1) WritePixel(ResPixmap, x, (y + Offset), ReadPixel(ThisPixmap, x, y)) Next If (Align = DEFORM_LEFT) Offset = Offset - 1 Else Offset = Offset + 1 EndIf Next If (Align = DEFORM_LEFT) Offset = ThisPixmap.Height + (OtherPixmap.Height - 1) Else Offset = ThisPixmap.Height EndIf For x = 0 To (OtherPixmap.Width - 1) For y = 0 To (OtherPixmap.Height - 1) If (y + Offset < ResPixmap.Height) WritePixel(ResPixmap, x, (y + Offset), ReadPixel(OtherPixmap, x, y)) EndIf Next If (Align = DEFORM_LEFT) Offset = Offset - 1 Else Offset = Offset + 1 EndIf Next For y = 0 To (Self.QuadSize - 1) For x = 0 To (Self.QuadSize - 1) WritePixel(ThisPixmap, x, y, ReadPixel(ResPixmap, x, y)) Next Next For y = 0 To (Self.QuadSize - 1) For x = 0 To (Self.QuadSize - 1) WritePixel(OtherPixmap, x, y, ReadPixel(ResPixmap, x, (y + Self.QuadSize))) Next Next Case DEFORM_EAST If (Align = DEFORM_LEFT) Offset = 0 Else Offset = (ThisPixmap.Width - 1) EndIf For y = 0 To (ThisPixmap.Height - 1) For x = 0 To (ResPixmap.Width - 1) If (x < ThisPixmap.Width) WritePixel(ResPixmap, (x + Offset), y, ReadPixel(ThisPixmap, x, y)) EndIf Next If (Align = DEFORM_LEFT) Offset = Offset + 1 Else Offset = Offset - 1 EndIf Next If (Align = DEFORM_LEFT) Offset = (OtherPixmap.Width - 1) Else Offset = 0 EndIf For y = 0 To (OtherPixmap.Height - 1) For x = 0 To (OtherPixmap.Width - 1) If ((x - Offset) >= 0) WritePixel(ResPixmap, (x - Offset), y, ReadPixel(OtherPixmap, x, y)) EndIf Next If (Align = DEFORM_LEFT) Offset = Offset - 1 Else Offset = Offset + 1 EndIf Next For y = 0 To (Self.QuadSize - 1) For x = 0 To (Self.QuadSize - 1) WritePixel(OtherPixmap, x, y, ReadPixel(ResPixmap, x, y)) Next Next For y = 0 To (Self.QuadSize - 1) For x = 0 To (Self.QuadSize - 1) WritePixel(ThisPixmap, x, y, ReadPixel(ResPixmap, (x + Self.QuadSize), y)) Next Next Case DEFORM_SOUTH If (Align = DEFORM_LEFT) Offset = 0 Else Offset = (ThisPixmap.Height - 1) EndIf For x = 0 To (ThisPixmap.Width - 1) For y = 0 To (ThisPixmap.Height - 1) WritePixel(ResPixmap, x, (y + Offset), ReadPixel(ThisPixmap, x, y)) Next If (Align = DEFORM_LEFT) Offset = Offset + 1 Else Offset = Offset - 1 EndIf Next If (Align = DEFORM_LEFT) Offset = (ThisPixmap.Height - 1) Else Offset = 0 EndIf For x = 0 To (OtherPixmap.Width - 1) For y = 0 To (OtherPixmap.Height - 1) If ((y - Offset) >= 0) WritePixel(ResPixmap, x, (y - Offset), ReadPixel(OtherPixmap, x, y)) EndIf Next If (Align = DEFORM_LEFT) Offset = Offset - 1 Else Offset = Offset + 1 EndIf Next For y = 0 To (Self.QuadSize - 1) For x = 0 To (Self.QuadSize - 1) WritePixel(OtherPixmap, x, y, ReadPixel(ResPixmap, x, y)) Next Next For y = 0 To (Self.QuadSize - 1) For x = 0 To (Self.QuadSize - 1) WritePixel(ThisPixmap, x, y, ReadPixel(ResPixmap, x, (y + Self.QuadSize))) Next Next Case DEFORM_WEST If (Align = DEFORM_LEFT) Offset = 0 Else Offset = (ThisPixmap.Width - 1) EndIf For y = 0 To (ThisPixmap.Height - 1) For x = 0 To (ResPixmap.Width - 1) If (x < ThisPixmap.Width) WritePixel(ResPixmap, (x + Offset), y, ReadPixel(ThisPixmap, x, y)) EndIf Next If (Align = DEFORM_LEFT) Offset = Offset + 1 Else Offset = Offset - 1 EndIf Next If (Align = DEFORM_LEFT) Offset = (ThisPixmap.Width) Else Offset = (ResPixmap.Width - 1) EndIf For y = 0 To (OtherPixmap.Height - 1) For x = 0 To (OtherPixmap.Width - 1) If ((Offset + x) < ResPixmap.Width) WritePixel(ResPixmap, (x + Offset), y, ReadPixel(OtherPixmap, x, y)) EndIf Next If (Align = DEFORM_LEFT) Offset = Offset + 1 Else Offset = Offset - 1 EndIf Next For y = 0 To (Self.QuadSize - 1) For x = 0 To (Self.QuadSize - 1) WritePixel(ThisPixmap, x, y, ReadPixel(ResPixmap, x, y)) Next Next For y = 0 To (Self.QuadSize - 1) For x = 0 To (Self.QuadSize - 1) WritePixel(OtherPixmap, x, y, ReadPixel(ResPixmap, (x + Self.QuadSize), y)) Next Next End Select EndIf UnlockImage(NextQuad.ImageData) UnlockImage(Self.ImageData) UnlockImage(ResImage) If (Align = DEFORM_RIGHT) Self.AddFlag(FLAG_DEFORMEDR) NextQuad.AddFlag(FLAG_DEFORMEDR) Else Self.AddFlag(FLAG_DEFORMEDL) NextQuad.AddFlag(FLAG_DEFORMEDL) EndIf Self.Dent(Direction, InvisibleARGB) EndIf EndIf End Method Method Collapse(Direction:Int, NextQuad:TDDMQuad, NewHealth:Double = QUAD_MAXHEALTH, InvisibleARGB:Int = $FF000000) If (NextQuad = Null) Then Return If (Self.Health > 0) NextQuad.ImageData = Self.ImageData NextQuad.Dent(Direction, InvisibleARGB) EndIf NextQuad.Health = NewHealth Self.Health = 0 End Method Method AddFlag(Flag:Byte) Self.FLAGS = Self.FLAGS + Flag End Method End Type
Function DDModelFromImage:TDDModel(ImageSrc:Object, QuadSize:Int = 10, QuadHP:Double = 100) Local Image:TImage = LoadImage(ImageSrc) If (Image = Null) Then Return Null If (ImageWidth(Image) Mod QuadSize <> 0 Or ImageHeight(Image) Mod QuadSize <> 0) Then Return Null Local Pixmap:TPixmap = LockImage(Image) Local tmpix:TPixmap Local tmpimg:TImage Local Width:Int = ImageWidth(Image) / QuadSize Local Height:Int = ImageHeight(Image) / QuadSize Local Quads:TDDMQuad[Width, Height] For Local y:Int = 0 To (Height - 1) For Local x:Int = 0 To (Width - 1) tmpimg = CreateImage(QuadSize, QuadSize) tmpix = LockImage(tmpimg) For Local yy:Int = 0 To (QuadSize - 1) For Local xx:Int = 0 To (QuadSize - 1) WritePixel(tmpix, xx, yy, ReadPixel(Pixmap, (x * QuadSize) + xx, (y * QuadSize) + yy)) Next Next UnlockImage(tmpimg) Quads[x, y] = TDDMQuad.CreateImgQuad(tmpimg, QuadHP, TDDMQuad.FLAG_NONE, QuadSize) Next Next UnlockImage(Image) Return TDDModel.Create(TDDModelQuadData.Create(Quads, Width, Height)) End Function
Type TDDModelQuadData Field Data:TDDMQuad[,] Field Width:Int Field Height:Int Function Create:TDDModelQuadData(Data:TDDMQuad[,], Width:Int, Height:Int) Local ReturnMe:TDDModelQuadData = New TDDModelQuadData ReturnMe.Data = Data ReturnMe.Width = Width ReturnMe.Height = Height Return ReturnMe End Function End Type
Type TDDModel Const DIRECTION_NORTH:Byte = 0 Const DIRECTION_EAST:Byte = 1 Const DIRECTION_SOUTH:Byte = 2 Const DIRECTION_WEST:Byte = 3
Field ModelData:TDDModelQuadData Field PositionX:Int Field PositionY:Int Field Rotation:Double Function Create:TDDModel(ModelData:TDDModelQuadData) Local ReturnMe:TDDModel = New TDDModel ReturnMe.ModelData = TDDModelQuadData.Create(ModelData.Data, ModelData.Width, ModelData.Height) ReturnMe.SyncBorder() Return ReturnMe End Function Method SyncBorder() If (Self.ModelData <> Null And Self.ModelData.Data <> Null) For Local y:Int = 0 To (Self.ModelData.Height - 1) For Local x:Int = 0 To (Self.ModelData.Width - 1) If (x = 0 Or x = (Self.ModelData.Width - 1) Or y = 0 Or y = (Self.ModelData.Height - 1)) Self.ModelData.Data[x, y].AddFlag(TDDMQuad.FLAG_ISBORDER) EndIf If ((x = 0 And y = 0) Or (x = (Self.ModelData.Width - 1) And y = 0) Or (x = 0 And y = (Self.ModelData.Height - 1)) Or (x = (Self.ModelData.Width - 1) And y = (Self.ModelData.Height - 1))) Self.ModelData.Data[x, y].AddFlag(TDDMQuad.FLAG_ISEDGE) EndIf Next Next EndIf End Method Method SetPosition(PositionX:Int, PositionY:Int) Self.PositionX = PositionX Self.PositionY = PositionY End Method Method SetRot(Rotation:Double) Self.Rotation = Rotation End Method Method Draw() Local PrevRot:Double = GetRotation() SetRotation(Self.Rotation) Local sizex:Int, sizey:Int, ergx:Double, ergy:Double, momQuad:TDDMQuad For Local y:Int = 0 To (Self.ModelData.Height - 1) For Local x:Int = 0 To (Self.ModelData.Width - 1) momQuad = Self.ModelData.Data[x, y] If (momQuad <> Null) sizex = momQuad.QuadSize * x sizey = momQuad.QuadSize * y ergx = Cos(Self.Rotation) * sizex - Sin(Self.Rotation) * sizey ergy = Sin(Self.Rotation) * sizex + Cos(Self.Rotation) * sizey momQuad.DrawQuad(Self.PositionX + ergx, Self.PositionY + ergy) EndIf Next Next SetRotation(PrevRot) End Method Method SimImpact(Direction:Byte, StartQuad:Int, Length:Int, Intensity:Double, Recursive:Byte = True, InvisibleARGB:Int = $FF000000) If (Direction = DIRECTION_NORTH Or Direction = DIRECTION_SOUTH) If (StartQuad < 0 Or (StartQuad + Length) > (Self.ModelData.Width - 1)) Return EndIf Else If (StartQuad < 0 Or (StartQuad + Length) > (Self.ModelData.Height - 1)) Return EndIf EndIf If (Intensity <= 0) Then Return Local x:Int, y:Int Select(Direction) Case DIRECTION_NORTH If (StartQuad >= 1) For y = 0 To (Self.ModelData.Height - 2) If (Self.ModelData.Data[(StartQuad - 1), y].Health > 0) Self.ModelData.Data[(StartQuad - 1), y].Deform(TDDMQuad.DEFORM_RIGHT, TDDMQuad.DEFORM_NORTH, Self.ModelData.Data[(StartQuad - 1), (y + 1)], InvisibleARGB) Exit EndIf Next EndIf If ((StartQuad + Length) < (Self.ModelData.Width - 1)) For y = 0 To (Self.ModelData.Height - 2) If (Self.ModelData.Data[(StartQuad + Length + 1), y].Health > 0) Self.ModelData.Data[(StartQuad + Length + 1), y].Deform(TDDMQuad.DEFORM_LEFT, TDDMQuad.DEFORM_NORTH, Self.ModelData.Data[(StartQuad + Length + 1), (y + 1)], InvisibleARGB) Exit EndIf Next EndIf
For x = StartQuad To (StartQuad + Length) For y = 0 To (Self.ModelData.Height - 2) If (Self.ModelData.Data[x, y].Health > 0) If (Intensity > (Self.ModelData.Data[x, y].Health * 100) And Recursive = True) Intensity = Intensity - (Self.ModelData.Data[x, y].Health * 100) Self.SimImpact(DIRECTION_NORTH, x, 1, Intensity, True, InvisibleARGB) Else If (Recursive = True) Self.ModelData.Data[x, y].Collapse(TDDMQuad.COLLAPSE_NORTH, Self.ModelData.Data[x, (y + 1)], ((Self.ModelData.Data[x, y].Health * 100) - Intensity), InvisibleARGB) Else Self.ModelData.Data[x, y].Collapse(TDDMQuad.COLLAPSE_NORTH, Self.ModelData.Data[x, (y + 1)], TDDMQuad.QUAD_MAXHEALTH, InvisibleARGB) EndIf Exit EndIf EndIf Next Next Case DIRECTION_EAST If (StartQuad >= 1) For x = (Self.ModelData.Width - 1) To 1 Step -1 If (Self.ModelData.Data[x, (StartQuad - 1)].Health > 0) Self.ModelData.Data[x, (StartQuad - 1)].Deform(TDDMQuad.DEFORM_RIGHT, TDDMQuad.DEFORM_EAST, Self.ModelData.Data[(x - 1), (StartQuad - 1)], InvisibleARGB) Exit EndIf Next EndIf If ((StartQuad + Length) < (Self.ModelData.Height - 1)) For x = (Self.ModelData.Width - 1) To 1 Step -1 If (Self.ModelData.Data[x, (StartQuad + Length + 1)].Health > 0) Self.ModelData.Data[x, (StartQuad + Length + 1)].Deform(TDDMQuad.DEFORM_LEFT, TDDMQuad.DEFORM_EAST, Self.ModelData.Data[(x - 1), (StartQuad + Length + 1)], $00FFFFFF) Exit EndIf Next EndIf For y = StartQuad To (StartQuad + Length) For x = (Self.ModelData.Width - 1) To 1 Step -1 If (Self.ModelData.Data[x, y].Health > 0) If (Intensity > (Self.ModelData.Data[x, y].Health * 100) And Recursive = True) Intensity = Intensity - (Self.ModelData.Data[x, y].Health * 100) Self.SimImpact(DIRECTION_EAST, y, 1, Intensity, True, InvisibleARGB) Else If (Recursive = True) Self.ModelData.Data[x, y].Collapse(TDDMQuad.COLLAPSE_EAST, Self.ModelData.Data[(x - 1), y], ((Self.ModelData.Data[x, y].Health * 100) - Intensity), InvisibleARGB) Else Self.ModelData.Data[x, y].Collapse(TDDMQuad.COLLAPSE_EAST, Self.ModelData.Data[(x - 1), y], TDDMQuad.QUAD_MAXHEALTH, InvisibleARGB) EndIf Exit EndIf EndIf Next Next Case DIRECTION_SOUTH If (StartQuad >= 1) For y = (Self.ModelData.Height - 1) To 1 Step -1 If (Self.ModelData.Data[(StartQuad - 1), y].Health > 0) Self.ModelData.Data[(StartQuad - 1), y].Deform(TDDMQuad.DEFORM_RIGHT, TDDMQuad.DEFORM_SOUTH, Self.ModelData.Data[(StartQuad - 1), (y - 1)], InvisibleARGB) Exit EndIf Next EndIf If ((StartQuad + Length) < (Self.ModelData.Width - 1)) For y = (Self.ModelData.Height - 1) To 1 Step -1 If (Self.ModelData.Data[(StartQuad + Length + 1), y].Health > 0) Self.ModelData.Data[(StartQuad + Length + 1), y].Deform(TDDMQuad.DEFORM_LEFT, TDDMQuad.DEFORM_SOUTH, Self.ModelData.Data[(StartQuad + Length + 1), (y - 1)], InvisibleARGB) Exit EndIf Next EndIf For x = StartQuad To (StartQuad + Length) For y = (Self.ModelData.Height - 1) To 1 Step -1 If (Self.ModelData.Data[x, y].Health > 0) If (Intensity > (Self.ModelData.Data[x, y].Health * 100) And Recursive = True) Intensity = Intensity - (Self.ModelData.Data[x, y].Health * 100) Self.SimImpact(DIRECTION_SOUTH, x, 1, Intensity, True, InvisibleARGB) Else If (Recursive = True) Self.ModelData.Data[x, y].Collapse(TDDMQuad.COLLAPSE_SOUTH, Self.ModelData.Data[x, (y - 1)], ((Self.ModelData.Data[x, y].Health * 100) - Intensity), InvisibleARGB) Else Self.ModelData.Data[x, y].Collapse(TDDMQuad.COLLAPSE_SOUTH, Self.ModelData.Data[x, (y - 1)], TDDMQuad.QUAD_MAXHEALTH, InvisibleARGB) EndIf Exit EndIf EndIf Next Next Case DIRECTION_WEST If (StartQuad >= 1) For x = 0 To (Self.ModelData.Width - 2) If (Self.ModelData.Data[x, (StartQuad - 1)].Health > 0) Self.ModelData.Data[x, (StartQuad - 1)].Deform(TDDMQuad.DEFORM_LEFT, TDDMQuad.DEFORM_WEST, Self.ModelData.Data[(x + 1), (StartQuad - 1)], InvisibleARGB) Exit EndIf Next EndIf If ((StartQuad + Length) < (Self.ModelData.Height - 1)) For x = 0 To (Self.ModelData.Width - 2) If (Self.ModelData.Data[x, (StartQuad + Length + 1)].Health > 0) Self.ModelData.Data[x, (StartQuad + Length + 1)].Deform(TDDMQuad.DEFORM_RIGHT, TDDMQuad.DEFORM_WEST, Self.ModelData.Data[(x + 1), (StartQuad + Length + 1)], InvisibleARGB) Exit EndIf Next EndIf For y = StartQuad To (StartQuad + Length) For x = 0 To (Self.ModelData.Width - 2) If (Self.ModelData.Data[x, y].Health > 0) If (Intensity > (Self.ModelData.Data[x, y].Health * 100) And Recursive = True) Intensity = Intensity - (Self.ModelData.Data[x, y].Health * 100) Self.SimImpact(DIRECTION_WEST, y, 1, Intensity, True, InvisibleARGB) Else If (Recursive = True) Self.ModelData.Data[x, y].Collapse(TDDMQuad.COLLAPSE_WEST, Self.ModelData.Data[(x + 1), y], ((Self.ModelData.Data[x, y].Health * 100) - Intensity), InvisibleARGB) Else Self.ModelData.Data[x, y].Collapse(TDDMQuad.COLLAPSE_WEST, Self.ModelData.Data[(x + 1), y], TDDMQuad.QUAD_MAXHEALTH, InvisibleARGB) EndIf Exit EndIf EndIf Next Next End Select End Method Method GetEngineHealth:Double() If (Self.ModelData.Data <> Null) Local EngineParts:Double = 0 Local DeadEngine:Double = 0 For Local y:Int = 0 To (Self.ModelData.Height - 1) For Local x:Int = 0 To (Self.ModelData.Width - 1) If (Self.ModelData.Data[x, y] <> Null) If (BitIsSet(Self.ModelData.Data[x, y].FLAGS, TDDMQuad.FLAG_ISENGINE)) EngineParts = EngineParts + 1 If (Self.ModelData.Data[x, y].Health <= 0) DeadEngine = DeadEngine + 1 EndIf EndIf EndIf Next Next If (DeadEngine <> 0 And EngineParts <> 0) Return (1 - (DeadEngine / EngineParts)) Else Return 1 EndIf EndIf End Method Method GetTotalHealth:Double() If (Self.ModelData.Data <> Null) Local TotalQuads:Double = Self.ModelData.Width * Self.ModelData.Height Local DeadQuads:Double = 0 For Local y:Int = 0 To (Self.ModelData.Height - 1) For Local x:Int = 0 To (Self.ModelData.Width - 1) If (Self.ModelData.Data[x, y] <> Null) If (Self.ModelData.Data[x, y].Health <= 0) DeadQuads = DeadQuads + 1 EndIf EndIf Next Next If (DeadQuads <> 0 And TotalQuads <> 0) Return (1.0 - (DeadQuads / TotalQuads)) Else Return 1 EndIf EndIf End Method End Type
und noch ein Beispiel:
BlitzMax: [AUSKLAPPEN] [EINKLAPPEN] Graphics(1600, 900)
SetMaskColor(255, 0, 255)
Local VehicleImg:TImage = LoadImage("test.png") Local VehiclePix:TPixmap = LockImage(VehicleImg)
Local QuadSize:Int = 5 Local TestModel:TDDModel = DDModelFromImage(VehiclePix, QuadSize, 20) Local TestModel2:TDDModel = DDModelFromImage(VehiclePix, QuadSize)
If (TestModel = Null) DebugLog("NEIN") End EndIf
Local momrot:Float = 0 Local FPS:TTimer = CreateTimer(60) Local FPSCounter:TFPS = TFPS.Create()
TestModel.SetPosition(400, 400) TestModel.SetRot(momrot)
For Local y:Int = 1 To 7 For Local x:Int = 4 To 8 TestModel.ModelData.Data[x, y].AddFlag(TDDMQuad.FLAG_ISENGINE) Next Next
TestModel2.SetPosition(600, 400)
SetClsColor(255, 255, 255)
Local t:Int
Repeat WaitTimer(FPS) Cls FPSCounter.Update() If (KeyDown(KEY_LEFT)) momrot = momrot - 1 EndIf If (KeyDown(KEY_RIGHT)) momrot = momrot + 1 EndIf If (KeyHit(KEY_R)) TestModel = DDModelFromImage(VehiclePix, QuadSize, 20) TestModel.SetPosition(400, 400) TestModel.SetRot(momrot) For Local y:Int = 1 To 7 For Local x:Int = 4 To 8 If (TestModel.ModelData.Data[x, y] <> Null) TestModel.ModelData.Data[x, y].AddFlag(TDDMQuad.FLAG_ISENGINE) EndIf Next Next TestModel2 = DDModelFromImage(VehiclePix, QuadSize) TestModel2.SetPosition(600, 400) TestModel2.SetRot(momrot) For Local y:Int = 1 To 7 For Local x:Int = 4 To 8 If (TestModel2.ModelData.Data[x, y] <> Null) TestModel2.ModelData.Data[x, y].AddFlag(TDDMQuad.FLAG_ISENGINE) EndIf Next Next EndIf If (KeyHit(KEY_W)) TestModel.SimImpact(TDDModel.DIRECTION_NORTH, t = Rand(0, (TestModel.ModelData.Width - 1)), Rand(1, ((TestModel.ModelData.Width - 1) - t)), Rand(75, 200), True, $00FFFFFF) TestModel2.SimImpact(TDDModel.DIRECTION_NORTH, t = Rand(0, (TestModel.ModelData.Width - 1)), Rand(1, ((TestModel.ModelData.Width - 1) - t)), Rand(75, 200), True, $00FFFFFF) EndIf If (KeyHit(KEY_S)) TestModel.SimImpact(TDDModel.DIRECTION_SOUTH, t = Rand(0, (TestModel.ModelData.Width - 1)), Rand(1, ((TestModel.ModelData.Width - 1) - t)), Rand(75, 200), True, $00FFFFFF) TestModel2.SimImpact(TDDModel.DIRECTION_SOUTH, t = Rand(0, (TestModel.ModelData.Width - 1)), Rand(1, ((TestModel.ModelData.Width - 1) - t)), Rand(75, 200), True, $00FFFFFF) EndIf If (KeyHit(KEY_A)) TestModel.SimImpact(TDDModel.DIRECTION_WEST, t = Rand(0, (TestModel.ModelData.Height - 1)), Rand(1, ((TestModel.ModelData.Height - 1) - t)), Rand(75, 200), True, $00FFFFFF) TestModel2.SimImpact(TDDModel.DIRECTION_WEST, t = Rand(0, (TestModel.ModelData.Height - 1)), Rand(1, ((TestModel.ModelData.Height - 1) - t)), Rand(75, 200), True, $00FFFFFF) EndIf If (KeyHit(KEY_D)) TestModel.SimImpact(TDDModel.DIRECTION_EAST, t = Rand(0, (TestModel.ModelData.Height - 1)), Rand(1, ((TestModel.ModelData.Height - 1) - t)), Rand(75, 200), True, $00FFFFFF) TestModel2.SimImpact(TDDModel.DIRECTION_EAST, t = Rand(0, (TestModel.ModelData.Height - 1)), Rand(1, ((TestModel.ModelData.Height - 1) - t)), Rand(75, 200), True, $00FFFFFF) EndIf TestModel.setrot(momrot) TestModel.Draw() TestModel2.Draw() TestModel2.setrot(momrot) SetColor(0, 0, 0) DrawText("FPS: " + FPSCounter.Get(), 0, 0) DrawText("Engine-Health (1): " + (TestModel.GetEngineHealth() * 100) + "%", 0, 40) DrawText("Total-Health (1): " + (TestModel.GetTotalHealth() * 100) + "%", 0, 60) DrawText("Engine-Health (2): " + (TestModel2.GetEngineHealth() * 100) + "%", 0, 100) DrawText("Total-Health (2): " + (TestModel2.GetTotalHealth() * 100) + "%", 0, 120) Flip 0 Until KeyHit(KEY_ESCAPE)
UnlockImage(VehicleImg)
End
Und das zum Beispiel gehörende Bild:
Und die zum Beispiel gehörende Steuerung:
Pfeiltasten links / rechts: Rotieren
Taste W: Zufallsschaden von Norden (relativ)
Taste S: Zufallsschaden von Süden (relativ)
Taste A: Zufallsschaden von Westen (relativ)
Taste D: Zufallsschaden von Osten (relativ)
Taste R: Reparieren
Und eine Funktionsreferenz:
Code: [AUSKLAPPEN] [EINKLAPPEN] -> Types:
-> Type TDDMQuad:
-> Variablen:
Field ImageData:TImage
Field ColorDataRed:Int
Field ColorDataGreen:Int
Field ColorDataBlue:Int
Field Health:Double
Field FLAGS:Byte
Field QuadSize:Byte
-> Konstruktion:
TDDMQuad.CreateImgQuad:TDDMQuad(ImageSrc:TImage, Health:Double = 100, Flags:Byte = FLAG_NONE, QuadSize:Int = 10)
-> Beschr.: Erzeugt ein Quad, welches aus einem Bild besteht.
-> Parameter:
ImageSrc:TImage - Das Bild
Health:Double - Die HP des Quads (0 < Health < QUAD_MAXHEALTH)
Flags:
Const FLAG_NONE:Byte = 0 ' Kein Flag gesetzt
Const FLAG_ISENGINE:Byte = 1 ' Es handelt sich bei dem Quad um ein EngineQuad, also um ein Quad, das den Motor repräsentiert (für erweiterte "Simulationen")
Const FLAG_ISWHEEL:Byte = 2 ' Es handelt sich bei dem Quad um ein WheelQuad, also um ein Quad, das einen Reifen repräsentiert (für erweiterte "Simulationen")
Const FLAG_GODQUAD:Byte = 4 ' Es handelt sich um ein unzerstörbares Quad
Const FLAG_ISBORDER:Byte = 8 ' Systemflag, nicht benutzen.
Const FLAG_ISEDGE:Byte = 16 ' Systemflag, nicht benutzen.
Const FLAG_ISCOLORED:Byte = 32 ' Bei dem Quad handelt es sich nicht um ein Image-Quad
Const FLAG_DEFORMEDL:Byte = 64 ' Systemflag, nicht benutzen.
Const FLAG_DEFORMEDR:Byte = 128 ' Systemflag, nicht benutzen.
QuadSize:Int - Größe eines Quads (Das Bild muss in den Dimensionen der QuadSize entsprechen)
TDDMQuad.CreateColQuad:TDDMQuad(ColorRed:Int, ColorGreen:Int, ColorBlue:Int, Health:Double = 100, Flags:Byte = FLAG_ISCOLORED, QuadSize:Int = 10)
-> Beschr.: Erzeugt ein einfach eingefärbtes Quad
-> Parameter:
ColorRed, ColorGreen, ColorBlue - Die Farbanteile des Quads in RGB
Health - Siehe oben
Flags - Siehe oben
QuadSize - Siehe oben
-> Methoden:
Method SetHealth(Health:Double)
-> Beschr.: Setzt die HP des Quads
Method GetHealth:Double()
-> Beschr.: Returned die HP des Quads
Method DrawQuad(PositionX:Double, PositionY:Double)
-> Beschr.: Malt das Quad (bzw. malt es nicht, falls HP <= 0) an die angegebene BILDSCHIRM-Position
Method Dent(Direction:Int, InvisibleARGB:Int = $FF000000)
-> Beschr.: Führt den "Welleneffekt" aus, um so ein beschädigtes Quad zu simulieren
-> Parameter:
Direction - Aus welcher Richtung soll der Welleneffekt kommen (An welcher Seite des Modells soll er auftreten?):
Const COLLAPSE_NORTH:Int = 0
Const COLLAPSE_EAST:Int = 1
Const COLLAPSE_SOUTH:Int = 2
Const COLLAPSE_WEST:Int = 3
InvisibleARGB: Die Unsichtbar-Farbe.
Method Deform(Align:Int, Direction:Int, NextQuad:TDDMQuad, InvisibleARGB:Int = $FF000000)
-> Beschr.: Erzeugt eine Schräge, um so den Übergang zwischen heilem und kaputtem Quad zu simulieren
-> Parameter:
Align - Schräge, die links oder rechts abfällt?
Const DEFORM_RIGHT:Int = 0
Const DEFORM_LEFT:Int = 1
Direction - An welcher Seite des Modells soll die Schräge auftreten?:
Const DEFORM_NORTH:Int = 0
Const DEFORM_EAST:Int = 1
Const DEFORM_SOUTH:Int = 2
Const DEFORM_WEST:Int = 3
NextQuad - Das nächte betroffene Quad (Meistens das hinter diesem liegende)
InvisibleARGB: Die Unsichtbar-Farbe.
Method Collapse(Direction:Int, NextQuad:TDDMQuad, NewHealth:Double = QUAD_MAXHEALTH, InvisibleARGB:Int = $FF000000)
-> Beschr.: Handelt es sich bei diesem Quad um ein Rahmen-Quad, so wird es "nach hinten geschoben", das dahinterliegende wird gelöscht
-> Parameter:
Direction - An welcher Seite des Modells soll das Quad verschoben werden?:
Const COLLAPSE_NORTH:Int = 0
Const COLLAPSE_EAST:Int = 1
Const COLLAPSE_SOUTH:Int = 2
Const COLLAPSE_WEST:Int = 3
NextQuad - Das nächte betroffene Quad (Meistens das hinter diesem liegende)
NewHealth - Welche HP soll das neu positionierte Quad nach der Positionsänderung bekommen?
InvisibleARGB: Die Unsichtbar-Farbe.
Method AddFlag(Flag:Byte)
-> Beschr.: Fügt diesem Quad ein neues FLAG hinzu
-> Type TDDModelQuadData
-> Variablen:
Field Data:TDDMQuad[,]
Field Width:Int
Field Height:Int
-> Konstruktion:
TDDModelQuadData.Create:TDDModelQuadData(Data:TDDMQuad[,], Width:Int, Height:Int)
Beschr.: Erzeugt eine neue TDDModelQuadData
-> Type TDDModel
-> Variablen:
Field ModelData:TDDModelQuadData
Field PositionX:Int
Field PositionY:Int
Field Rotation:Double
-> Konstruktion:
TDDModel.Create:TDDModel(ModelData:TDDModelQuadData)
Beschr.: Erzeugt ein neues TDDModel
-> Methoden:
Method SyncBorder()
Beschr.: Diese Methode setzt FLAG_ISBORDER und FLAG_ISEDGE Flags für die Quads des TDDModels. Wird im Konstruktor aufgerufen.
Method SetPosition(PositionX:Int, PositionY:Int)
Beschr.: Setzt die BILDSCHIRM-Position
Method SetRot(Rotation:Double)
Beschr.: Setzt die Rotation (0 - 359)
Method Draw()
Beschr.: Malt das TDDModel an seiner Position und mit seiner Rotation
Method SimImpact(Direction:Byte, StartQuad:Int, Length:Int, Intensity:Double, Recursive:Byte = True, InvisibleARGB:Int = $FF000000)
Beschr.: Simuliert einen Aufprall und erzeugt das entsprechende Schadensmodell.
Parameter:
Direction - Aus welcher Richtung (relativ) erfolgte der Aufschlag?:
Const DIRECTION_NORTH:Byte = 0
Const DIRECTION_EAST:Byte = 1
Const DIRECTION_SOUTH:Byte = 2
Const DIRECTION_WEST:Byte = 3
StartQuad - Beginn des Schadens (0 bis (Länge der Seite - 1))
Length - Länge des Schadens (1 bis (Länge der Seite - StartQuad))
Intesity - Wie stark war der Aufprall (Wie viel HP wird den betroffenen Quads abgezogen)?
Recursive - Soll der Schaden "weitergereicht" werden? (Ist die Intesity größer als die HP des betroffenen Quads, so wird das dahinterliegende auch noch beschädigt)
InvisibleARGB: Die Unsichtbar-Farbe.
Method GetEngineHealth:Double()
Beschr.: Ermittelt die HP aller Quads, die das Flag FLAG_ISENGINE besitzen und gibt den Prozentwert zurück
Method GetTotalHealth:Double()
Beschr.: Ermittelt die HP aller Quads und gibt den Prozentwert zurück
-> Funktionen:
-> Function DDModelFromImage:TDDModel(ImageSrc:Object, QuadSize:Int = 10, QuadHP:Double = 100)
Beschr.: Lädt ein DDModel von einem Bild. Dieses Bild muss in den Dimensionen ein Vielfaches der QuadSize sein.
Parameter:
ImageSrc:Object - Die Quelle des Bildes
QuadSize:Int = 10 - Größe eines Quads
QuadHP:Double = 100 - Welche Standard-HP sollen die Quads bekommen?
Hinweise:
Sollte kein Modell geladen werden können, so wird NULL zurückgegeben
Wer dies in einem seiner Projekte verwenden will, den bitte ich, zumindest meinen Namen (Marius Otto) in die Credits zu packen.
Für Lob und Kritik wäre ich euch dankbar.
EDIT:
Hier noch ein zweites Schaubild, diesmal mit einer Quadgröße von 10 x 10 Pixeln:
|