Comme je n'ai pas des masses de temps en ce moment, juste un petit truc en passant.
J'ai adapté en PureBasic le code proposé dans ce tutorial:http://www.charliesgames.com/wordpress/?p=441
En gros, il s'agit de créer des bestioles qui ressemblent à des triops phosphorescents (idéal pour les shoot'em up), et ce à partir d'une seule image: un "blob" (cf. image ci-dessous).

Qu'y a-t-il d'intéressant dans ce code ?
- c'est plutôt marrant à regarder
- une petite procédure de mon cru pour coloriser une image (ça peut servir)
- un macro qui "enrobe" TransformSprite3D afin de faciliter le zoom, la rotation, et surtout le déplacement du point d'origine d'un sprite 3D (par défaut, ce point est en haut à gauche, mais ça peut être utile de le mettre au milieu du sprite, sur un côté, etc..)
Et puis, le dénommé Charlie Knight (l'auteur) invite toute personne ayant converti son code à lui envoyer le résultat; pour l'instant, il y a des conversions en Flash et en GLbasic. Si je lui envoie la mienne, ça fera un peu de pub pour PureBasic !
Allez, je vous laisse tester. Récupérez l'image, le code ci-dessous, et zou !
Code : Tout sélectionner
;How to make an Irukandji style blob monster.
;By Charlie Knight, 2009/2010
;http://www.charliesgames.com
;
;This code is public domain. Feel free to use as you please.
;If you use the code as a basis for your own blob monsters, let me know! I;d love To
;see what you came up with!
;
;The code is written using the Blitzmax language, but it should be fairly easy to port
;to C++/Java/Whatever with a suitable graphics library.
;
;the image blob.png can be found at http://www.charliesgames.com/wpimages/blob.png
;
;Cheers
;Charlie
; ---------------------------------------------------------------------------------------------------------------
; PureBasic conversion: Kelebrindae
; Date: March, 15, 2011
; PB version: v4.51
; ---------------------------------------------------------------------------------------------------------------
; NB: The original code uses degree angles, and PureBasic uses radian angles.
; => The calls to the "Radian" function are numerous and unaesthetic, but I've kept them for comparison's sake.
; NB 2: The original code uses images to display the monster. But as PureBasic lacks the needed image deformation
; commands, I've used 3d sprites instead.
; ---------------------------------------------------------------------------------------------------------------
EnableExplicit
; Window size
#SCREENWIDTH = 800
#SCREENHEIGHT = 500
#BLOBSIZE = 32 ; bigger value = bigger monster
; Rainbow
Enumeration
#WHITEBLOB
#REDBLOB
#YELLOWBLOB
#CYANBLOB
EndEnumeration
; Simple class (Structure in Pure Basic) to hold a 2d coordinate
Structure point_struct ; I always add "_struct" to the structure name, to distinguish the type from the instances (but it's not mandatory)
x.f
y.f
EndStructure
; Here's the blob monster type
Structure blobMonster_struct ; I always add "_struct" to the structure name, to distinguish the type from the instances (but it's not mandatory)
;x and y coords
x.f
y.f
; Speed, try changing it
speed.f
; Number of nodes along the body, try changing it to 100
segments.i
; Array to hold the points along the body
tail.point_struct[100]
time.f
EndStructure
Global NewList blobMonster.blobMonster_struct()
Global Dim blobSprite.i(4) ; 4 colours => 4 different sprites
Global *test.blobMonster_struct
; These variables are used in the myTransformSprite3D macro (they're defined here because it can't be done in the macro)
Global TRF3D_angCos.f,TRF3D_angSin.f,TRF3D_x1.f,TRF3D_y1.f,TRF3D_x2.f,TRF3D_y2.f,TRF3D_x3.f,TRF3D_y3.f,TRF3D_x4.f,TRF3D_y4.f
;********************************************************
;- --- Macros ---
;********************************************************
;This macro calculates and returns the angle between two 2d coordinates, in degrees
Macro calculateAngle(x1,y1,x2,y2)
Degree(ATan2(x1 - x2,y1 - y2))
EndMacro
; Define the size for a sprite3D, its origin (proportionnal to the size. 0.5,0.5 => center), and its rotation angle (absolute)
; Replace the following BlitzMax commands: "SetScale", "SetImageHandle", and "SetRotation"
Macro myTransformSprite3D(numSprite,sizeX,sizeY,pivotX = 0,pivotY = 0,angle = 0)
; In PureBasic, a Sprite3D is used the display 2D sprite with 3D hardware ; it's just a textured plane, actually.
; Thus, it's possible to zoom, rotate or deform a 3D sprite simply by moving its 4 vertex.
; This is done through the "TransformSprite3D" command.
If angle = 0
TransformSprite3D(numSprite,-(pivotX),-(pivotY),(sizeX) - (pivotX),-(pivotY),(sizeX) - (pivotX),(sizeY) - (pivotY),-(pivotX),(sizeY) - (pivotY))
Else
TRF3D_angCos = Cos(angle)
TRF3D_angSin = Sin(angle)
TRF3D_x1 = -(pivotX) * TRF3D_angCos - (-(pivotY) * TRF3D_angSin)
TRF3D_y1 = -(pivotY) * TRF3D_angCos + (-(pivotX) * TRF3D_angSin)
TRF3D_x2 = ((sizeX) - (pivotX)) * TRF3D_angCos - (-(pivotY) * TRF3D_angSin)
TRF3D_y2 = -(pivotY) * TRF3D_angCos + ((sizeX) - (pivotX)) * TRF3D_angSin
TRF3D_x3 = ((sizeX) - (pivotX)) * TRF3D_angCos - ((sizeY) - (pivotY)) * TRF3D_angSin
TRF3D_y3 = ((sizeY) - (pivotY)) * TRF3D_angCos + ((sizeX) - (pivotX)) * TRF3D_angSin
TRF3D_x4 = -(pivotX) * TRF3D_angCos - ((sizeY) - (pivotY)) * TRF3D_angSin
TRF3D_y4 = ((sizeY) - (pivotY)) * TRF3D_angCos + (-(pivotX) * TRF3D_angSin)
TransformSprite3D(numSprite,TRF3D_x1,TRF3D_y1,TRF3D_x2,TRF3D_y2,TRF3D_x3,TRF3D_y3,TRF3D_x4,TRF3D_y4)
EndIf
EndMacro
;********************************************************
;- --- Procedures ---
;********************************************************
Procedure tintImageFilterCallback(x, y, SourceColor, TargetColor)
; Take only the Red component from the Source, do not modify the others
Protected a.f = Red(TargetColor)/255.0
ProcedureReturn RGBA(Red(SourceColor)*a, Green(SourceColor)*a, Blue(SourceColor)*a, 255)
EndProcedure
; This procedure use a filter callback (the above procedure) to apply a "tint" effect on a white blob image.
; Then it loads this image as a sprite3D.
Procedure.i createBlobSprite(red.i,green.i,blue.i)
Protected blobImage.i,tintedImage.i,numSprite.i,numSprite3D.i
Protected fileName.s = "temp" + Str(red) + "-" + Str(green) + "-" + Str(blue) + ".bmp"
; Load up the white blob image from the ressources
blobImage = CatchImage(#PB_Any, ?blob)
; Create a temporary image
tintedImage = CreateImage(#PB_Any, ImageWidth(blobIMage),ImageHeight(blobImage))
; On this image, draw the white blob
; (Note: every drawing operation must be done between "StartDrawing" and "StopDrawing")
StartDrawing(ImageOutput(tintedImage))
DrawImage(ImageID(blobImage), 0, 0)
; Then switch to the "tintImage" filter and draw a colored box over the blob.
; The color of each pixel is multiplied by the color of the box => we have our colored blob
DrawingMode(#PB_2DDrawing_CustomFilter)
CustomFilterCallback(@tintImageFilterCallback())
Box(0,0,ImageWidth(blobIMage),ImageHeight(blobImage),RGB(red,green,blue))
StopDrawing()
; Save the tinted image and release the memory
SaveImage(tintedImage,fileName)
FreeImage(tintedImage)
; Reload the image as a sprite and delete the image file
numSprite = LoadSprite(#PB_Any, fileName, #PB_Sprite_Texture)
DeleteFile(fileName)
; Create a sprite3D from the sprite and return its number
numSprite3D = CreateSprite3D(#PB_Any,numSprite)
ProcedureReturn numSprite3D
EndProcedure
; The methods used to create / update / draw a blob monster are here because we can't put them
; in the blobMonster structure (PB isn't object oriented)
; Procedure that returns a pointer to a new blob monster object. Pure Basic equivalent (kind of)
; of a constructor in C++/Java
Procedure blobMonsterCreate(inX.f, inY.f)
Protected i.i
Protected *n.blobMonster_struct = AddElement(blobMonster())
;starting point of the blob monster
*n\x = inX
*n\y = iny
*n\segments = 10
*n\speed = 1
;give the tail some coordinates, just make them the same as the main x and y for now
For i = 0 To *n\segments - 1
*n\tail[i]\x = inX
*n\tail[i]\y = iny
Next i
ProcedureReturn *n
EndProcedure
Procedure blobMonsterUpdate(*ptrMonster.blobMonster_struct)
Protected i.i
Protected distX.f,distY.f,dist.f
;time is a bit misleading, it's used for all sorts of things
*ptrMonster\time + *ptrMonster\speed
;here the x and y coordinates are updated.
;this uses the following as a basic rule for moving things
;around a point in 2d space:
;x=radius*cos(angle)+xOrigin
;y=raduis*sin(angle)+yOrigin
;this basically is the basis for anything that moves in this example
;
;the 2 lines of code below make the monster move around, but
;you can change this to anything you like, try setting x and y to the mouse
;coordinates for example
*ptrMonster\y = (15 * Cos(Radian(*ptrMonster\time * -6))) + (#SCREENHEIGHT / 2 + ((#SCREENHEIGHT / 2 - 60) * Sin(Radian(*ptrMonster\time * 1.3))))
*ptrMonster\x = (15 * Sin(Radian(*ptrMonster\time * -6))) + (#SCREENWIDTH / 2 + ((#SCREENWIDTH / 2 - 120) * Cos(Radian(*ptrMonster\time / 1.5))))
; To force the monster to follow the mouse pointer, uncomment these 3 lines:
; ExamineMouse()
; *ptrMonster\x = MouseX()
; *ptrMonster\y = MouseY()
;put the head of the tail at x,y coords
*ptrMonster\tail[0]\x = *ptrMonster\x
*ptrMonster\tail[0]\y = *ptrMonster\y
;update the tail
;basically, the points don't move unless they're further that 7 pixels
;from the previous point. this gives the kind of springy effect as the
;body stretches
For i = 1 To *ptrMonster\segments - 1
;calculate distance between the current point and the previous
distX = (*ptrMonster\tail[i - 1]\x - *ptrMonster\tail[i]\x)
distY = (*ptrMonster\tail[i - 1]\y - *ptrMonster\tail[i]\y)
dist = Sqr(distX * distX + distY * distY)
;move if too far away
If dist >= #BLOBSIZE*0.5
;the (distX*0.2) bit makes the point move
;just 20% of the distance. this makes the
;movement smoother, and the point decelerate
;as it gets closer to the target point.
;try changing it to 1 (i.e 100%) to see what happens
*ptrMonster\tail[i]\x = *ptrMonster\tail[i]\x + (distX * 0.25)
*ptrMonster\tail[i]\y = *ptrMonster\tail[i]\y + (distY * 0.25)
EndIf
Next i
EndProcedure
Procedure blobMonsterDraw(*ptrMonster.blobMonster_struct)
Protected i.i
Protected ang.f, scale.f
;time to draw stuff!
;this sets the blend mode to LIGHTBLEND, or additive blending, which makes
;the images progressively more bright as they overlap
Sprite3DBlendingMode(5,7)
;SetColor 0, 200, 150
;###########
;draw the main bit of the body
;start by setting the images handle (i.e the origin of the image) to it's center
;MidHandleImage blob
;begin looping through the segments of the body
For i = 0 To *ptrMonster\segments - 1
;set the alpha transparency vaue to 0.15, pretty transparent
;SetAlpha 0.15
;the (0.5*sin(i*35)) bit basically bulges the size of the images being
;drawn as it gets closer to the center of the monsters body, and tapers off in size as it gets
;to the end. try changing the 0.5 to a higher number to see the effect.
;SetScale 1 + (0.5 * Sin(i * 35)), 1 + (0.5 * Sin(i * 35))
scale = 1 + (0.5 * Sin(Radian(i * 35)))
myTransformSprite3D(blobSprite(#CYANBLOB),#BLOBSIZE,#BLOBSIZE,#BLOBSIZE*0.5,#BLOBSIZE*0.5)
;draw the image
DisplaySprite3D(blobSprite(#CYANBLOB), *ptrMonster\tail[i]\x, *ptrMonster\tail[i]\y, 38.25) ; alpha = 0.15*255.0
;this next chunk just draws smaller dots in the center of each segment of the body
;SetAlpha 0.8
;SetScale 0.1, 0.1
myTransformSprite3D(blobSprite(#CYANBLOB),#BLOBSIZE * 0.1,#BLOBSIZE * 0.1,#BLOBSIZE*0.05,#BLOBSIZE*0.05)
;draw the image
DisplaySprite3D(blobSprite(#CYANBLOB), *ptrMonster\tail[i]\x, *ptrMonster\tail[i]\y, 204) ; alpha = 0.8*255.0
Next i
;#########################
;draw little spikes on tail
;SetColor 255, 255, 255
;note that the x and y scales are different
;SetScale 0.6, 0.1
;move the image handle to halfway down the left edge, this'll make the image
;appear to the side of the coordinate it is drawn too, rather than the
;center as we had for the body sections
;SetImageHandle blob, 0, ImageHeight(blob) / 2
;rotate the 1st tail image. basically, we're calculating the angle between
;the last 2 points of the tail, and then adding an extra wobble (the 10*sin(time*10) bit)
;to make the pincer type effect.
;SetRotation 10 * Sin(time * 10) + calculateAngle(*ptrMonster\tail[segments - 1]\x, *ptrMonster\tail[segments - 1]\y, *ptrMonster\tail[segments - 5]\x, *ptrMonster\tail[segments - 5]\y) + 90
myTransformSprite3D(blobSprite(#WHITEBLOB),#BLOBSIZE * 0.6,#BLOBSIZE * 0.1,0,#BLOBSIZE*0.05,Radian(10 * Sin(Radian(*ptrMonster\time * 10)) + calculateAngle(*ptrMonster\tail[*ptrMonster\segments - 1]\x, *ptrMonster\tail[*ptrMonster\segments - 1]\y, *ptrMonster\tail[*ptrMonster\segments - 2]\x, *ptrMonster\tail[*ptrMonster\segments - 2]\y) ))
DisplaySprite3D(blobSprite(#WHITEBLOB), *ptrMonster\tail[*ptrMonster\segments - 1]\x, *ptrMonster\tail[*ptrMonster\segments - 1]\y, 204) ; alpha = 0.8*255.0
;second tail image uses negative time to make it move in the opposite direction
;SetRotation 10 * Sin(-time * 10) + calculateAngle(*ptrMonster\tail[segments - 1]\x, *ptrMonster\tail[segments - 1]\y, *ptrMonster\tail[segments - 5]\x, *ptrMonster\tail[segments - 5]\y) + 90
myTransformSprite3D(blobSprite(#WHITEBLOB),#BLOBSIZE * 0.6,#BLOBSIZE * 0.1,0,#BLOBSIZE*0.05,Radian(10 * Sin(Radian(-*ptrMonster\time * 10)) + calculateAngle(*ptrMonster\tail[*ptrMonster\segments - 1]\x, *ptrMonster\tail[*ptrMonster\segments - 1]\y, *ptrMonster\tail[*ptrMonster\segments - 2]\x, *ptrMonster\tail[*ptrMonster\segments - 2]\y) ))
DisplaySprite3D(blobSprite(#WHITEBLOB), *ptrMonster\tail[*ptrMonster\segments - 1]\x, *ptrMonster\tail[*ptrMonster\segments - 1]\y, 204) ; alpha = 0.8*255.0
;#####################
;draw little fins/arms
;SetAlpha 1
;begin looping through the body sections again. Note that we don't want fins
;on the first and last section because we want other things at those coords.
For i = 1 To *ptrMonster\segments - 2
;like the bulging body, we want the fins to grow larger in the center, and smaller
;at the end, so the same sort of thing is used here.
;SetScale 0.1 + (0.6 * Sin(i * 30)), 0.05
scale = 0.1 + (0.6 * Sin(Radian(i * 30)))
;rotate the image. We want the fins to stick out sideways from the body (the calculateangle() bit)
;and also to move a little on their own. the 33 * Sin(time * 5 + i * 30) makes the
;fin rotate based in the i index variable, so that all the fins look like they're moving
;one after the other.
;SetRotation 33 * Sin(time * 5 + i * 30) + calculateAngle(*ptrMonster\tail[i]\x, *ptrMonster\tail[i]\y, *ptrMonster\tail[i - 1]\x, *ptrMonster\tail[i - 1]\y)
myTransformSprite3D(blobSprite(#WHITEBLOB),#BLOBSIZE * scale,#BLOBSIZE * 0.05,0,#BLOBSIZE*0.025,Radian(33 * Sin(Radian(*ptrMonster\time * 5 + i * 30)) + calculateAngle(*ptrMonster\tail[i]\x, *ptrMonster\tail[i]\y, *ptrMonster\tail[i - 1]\x, *ptrMonster\tail[i - 1]\y) - 90))
DisplaySprite3D(blobSprite(#WHITEBLOB), *ptrMonster\tail[i]\x, *ptrMonster\tail[i]\y, 255)
;rotate the opposte fin, note that the signs have changes (-time and -i*30)
;to reflect the rotations of the other fin
;SetRotation 33 * Sin(-time * 5 - i * 30) + calculateAngle(*ptrMonster\tail[i]\x, *ptrMonster\tail[i]\y, *ptrMonster\tail[i - 1]\x, *ptrMonster\tail[i - 1]\y) + 180
myTransformSprite3D(blobSprite(#WHITEBLOB),#BLOBSIZE * scale,#BLOBSIZE * 0.05,0,#BLOBSIZE*0.025,Radian(33 * Sin(Radian(-*ptrMonster\time * 5 - i * 30)) + calculateAngle(*ptrMonster\tail[i]\x, *ptrMonster\tail[i]\y, *ptrMonster\tail[i - 1]\x, *ptrMonster\tail[i - 1]\y) + 90))
DisplaySprite3D(blobSprite(#WHITEBLOB), *ptrMonster\tail[i]\x, *ptrMonster\tail[i]\y, 255)
Next i
;###################
;center the image handle
; MidHandleImage blob
;Draw the eyes. These are just at 90 degrees to the head of the tail.
; SetColor 255, 0, 0
; SetScale 0.6, 0.6
; SetAlpha 0.3
myTransformSprite3D(blobSprite(#REDBLOB),#BLOBSIZE * 0.6,#BLOBSIZE * 0.6,#BLOBSIZE*0.3,#BLOBSIZE*0.3)
ang = calculateangle(*ptrMonster\tail[0]\x, *ptrMonster\tail[0]\y, *ptrMonster\tail[1]\x, *ptrMonster\tail[1]\y)
DisplaySprite3D(blobSprite(#REDBLOB), *ptrMonster\x + (7 * Cos(Radian(ang - 45))), *ptrMonster\y + (7 * Sin(Radian(ang - 45))),76.5) ; alpha = 0.3*255.0
DisplaySprite3D(blobSprite(#REDBLOB), *ptrMonster\x + (7 * Cos(Radian(ang + 45))), *ptrMonster\y + (7 * Sin(Radian(ang + 45))),76.5) ; alpha = 0.3*255.0
; SetColor 255, 255, 255
; SetScale 0.1, 0.1
; SetAlpha 0.5
myTransformSprite3D(blobSprite(#REDBLOB),#BLOBSIZE * 0.1,#BLOBSIZE * 0.1,#BLOBSIZE*0.05,#BLOBSIZE*0.05)
DisplaySprite3D(blobSprite(#REDBLOB), *ptrMonster\x + (7 * Cos(Radian(ang -45))), *ptrMonster\y + (7 * Sin(Radian(ang - 45))),127.5) ; alpha = 0.5*255.0
DisplaySprite3D(blobSprite(#REDBLOB), *ptrMonster\x + (7 * Cos(Radian(ang + 45))), *ptrMonster\y + (7 * Sin(Radian(ang + 45))),127.5) ; alpha = 0.5*255.0
;draw beaky thing
; SetColor 0, 200, 155
; SetScale 0.3, 0.1
; SetAlpha 0.8
; SetImageHandle blob, 0, ImageWidth(blob) / 2
; SetRotation ang + 95
myTransformSprite3D(blobSprite(#YELLOWBLOB),#BLOBSIZE * 0.3,#BLOBSIZE * 0.1,0,#BLOBSIZE*0.05,Radian(ang))
DisplaySprite3D(blobSprite(#YELLOWBLOB), *ptrMonster\x, *ptrMonster\y,204) ; alpha = 0.8*255.0
;yellow light
; MidHandleImage blob
; SetColor 255, 255, 0
; SetAlpha 0.2
; SetScale 4, 4
myTransformSprite3D(blobSprite(#YELLOWBLOB),#BLOBSIZE * 4,#BLOBSIZE * 4,#BLOBSIZE*2,#BLOBSIZE*2)
DisplaySprite3D(blobSprite(#YELLOWBLOB), *ptrMonster\x, *ptrMonster\y,51) ; alpha = 0.2*255.0
;Finished!
EndProcedure
;********************************************************
;- --- Main program ---
;********************************************************
;- initialization
InitSprite()
InitSprite3D()
InitKeyboard()
InitMouse()
;- Window
OpenWindow(0, 0, 0, #SCREENWIDTH, #SCREENHEIGHT, "Blob Monster", #PB_Window_ScreenCentered|#PB_Window_SystemMenu|#PB_Window_MinimizeGadget)
OpenWindowedScreen(WindowID(0), 0, 0, #SCREENWIDTH,#SCREENHEIGHT, 0, 0, 0,#PB_Screen_SmartSynchronization)
;- Blob image
; As PureBasic can't easily tint a image or a sprite at runtime, we create the needed colored blob sprites here
UsePNGImageDecoder()
blobSprite(#WHITEBLOB) = createBlobSprite(255,255,255)
blobSprite(#REDBLOB) = createBlobSprite(255,0,0)
blobSprite(#YELLOWBLOB) = createBlobSprite(255,255,0)
blobSprite(#CYANBLOB) = createBlobSprite(0,255,255)
; Create a blobMonster object
*test = blobMonsterCreate(10.0, 10.0)
;- Main loop
Repeat
;update the blobmonster
blobMonsterUpdate(*test)
ClearScreen(0)
; Draw the monster
; Note: Anything that use Sprite3D must be done between "Start3D()" and "Stop3D()"
Start3D()
blobMonsterDraw(*test)
Stop3D()
; Display result
FlipBuffers()
ExamineKeyboard()
Until KeyboardPushed(#PB_Key_Escape)
End
;Finished!
;- Ressources
; We can insert the blobimage here, so it will be included in the exe when the source is compiled.
DataSection
blob: IncludeBinary "blob.png"
EndDataSection