How to make a Blob monster

Everything else that doesn't fall into one of the other PB categories.
Kelebrindae
Enthusiast
Enthusiast
Posts: 151
Joined: Tue Apr 01, 2008 3:23 pm

How to make a Blob monster

Post by Kelebrindae »

Hi!

I have converted to PB the following tutorial:http://www.charliesgames.com/wordpress/?p=441
The goal is to create some sort of "glow-in-the-dark insectoid thingies" (perfect for a shoot'em up), using only one image: a "blob".
(this is a blob =>) Image

It's pretty clever and fun to watch; kudos to Mr. Charlie Knight!

NB: due to a little portability problem in the "TransformSprite3D" command, this code doesn't work in openGL; please switch to DirectX9 or DirectX7 subsystems (or use WINE, for the linux users).

Don't forget to grab the image before running the code!

[EDIT 03/22/2011]
- Fix missing "WindowsEvent" in the main loop
- Fix missing "FreeImage" in "createBlobSprite"

Code: Select all

;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)
  FreeImage(blobImage)
  
  ; 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
  While WindowEvent() : Wend
  
	;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
Last edited by Kelebrindae on Tue Mar 22, 2011 9:54 am, edited 1 time in total.
rsts
Addict
Addict
Posts: 2736
Joined: Wed Aug 24, 2005 8:39 am
Location: Southwest OH - USA

Re: How to make a Blob monster

Post by rsts »

:D

Slick.

Thanks for the contribution.

Might be better in tips and tricks.
User avatar
luis
Addict
Addict
Posts: 3895
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: How to make a Blob monster

Post by luis »

Stunning and very interesting, thanks for converting it :)
"Have you tried turning it off and on again ?"
User avatar
kenmo
Addict
Addict
Posts: 2042
Joined: Tue Dec 23, 2003 3:54 am

Re: How to make a Blob monster

Post by kenmo »

Very cool... I could have sworn I saw this on the forum before, but I clicked that blog link and realized I saw it on Youtube a while back! Nice job porting it!

PS. (I haven't fully read through the code but...) you could probably remove all the Radian() calls and just store the angles as radians. No need to store them as degrees just because the original did (degrees were probably standard in Blitz ?).
Kelebrindae
Enthusiast
Enthusiast
Posts: 151
Joined: Tue Apr 01, 2008 3:23 pm

Re: How to make a Blob monster

Post by Kelebrindae »

Thanks :) !
But all credit goes to Mr. Knight; his blog is well worth the clicks.

@kenmo:
Yeah, you're right, but after some thoughts I've left them, half to keep the code more easily comparable to the original one, half because of my lazyness... :mrgreen:
User avatar
Comtois
Addict
Addict
Posts: 1431
Joined: Tue Aug 19, 2003 11:36 am
Location: Doubs - France

Re: How to make a Blob monster

Post by Comtois »

Added an array to see more blob monster on the screen. Kelebrindae, nice code, as always :)

Code: Select all

;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
ExamineDesktops()
Global  Srx, Sry
Srx= 800;DesktopWidth(0)
Sry= 600;DesktopHeight(0)

#BLOBSIZE = 32 ; bigger value = bigger monster
#Nb = 6

; 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
  blobSprite.i[4]
EndStructure

Dim test.blobMonster_struct(#Nb)
Define i, Quit, Event

;********************************************************
;- --- 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(*n.blobMonster_struct, 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
  
EndProcedure


Procedure blobMonsterUpdate(*ptrMonster.blobMonster_struct, nb.f)
  Protected i.i, t.f
  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))) + (Sry / 2 + ((Sry / 2 - 60) * Sin(Radian(*ptrMonster\time * 1.3))))
  *ptrMonster\x = (15 * Sin(Radian(*ptrMonster\time * -6))) + (Srx / 2 + ((Srx / 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.29)
      *ptrMonster\tail[i]\y = *ptrMonster\tail[i]\y + (distY * 0.29)
    EndIf
    
  Next i
  
EndProcedure


Procedure blobMonsterDraw(*ptrMonster.blobMonster_struct)
  Protected i.i
  Protected ang.f, scale.f
  Protected 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
  ;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(*ptrMonster\blobSprite[#CYANBLOB],#BLOBSIZE,#BLOBSIZE,#BLOBSIZE*0.5,#BLOBSIZE*0.5)
    
    ;draw the image
    DisplaySprite3D(*ptrMonster\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(*ptrMonster\blobSprite[#CYANBLOB],#BLOBSIZE * 0.1,#BLOBSIZE * 0.1,#BLOBSIZE*0.05,#BLOBSIZE*0.05)
    
    ;draw the image
    DisplaySprite3D(*ptrMonster\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(*ptrMonster\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(*ptrMonster\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(*ptrMonster\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(*ptrMonster\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(*ptrMonster\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(*ptrMonster\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(*ptrMonster\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(*ptrMonster\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(*ptrMonster\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(*ptrMonster\blobSprite[#REDBLOB], *ptrMonster\x + (7 * Cos(Radian(ang - 45))), *ptrMonster\y + (7 * Sin(Radian(ang - 45))),76.5) ; alpha = 0.3*255.0
  DisplaySprite3D(*ptrMonster\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(*ptrMonster\blobSprite[#REDBLOB],#BLOBSIZE * 0.1,#BLOBSIZE * 0.1,#BLOBSIZE*0.05,#BLOBSIZE*0.05)
  
  DisplaySprite3D(*ptrMonster\blobSprite[#REDBLOB], *ptrMonster\x + (7 * Cos(Radian(ang -45))), *ptrMonster\y + (7 * Sin(Radian(ang - 45))),127.5) ; alpha = 0.5*255.0
  DisplaySprite3D(*ptrMonster\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(*ptrMonster\blobSprite[#YELLOWBLOB],#BLOBSIZE * 0.3,#BLOBSIZE * 0.1,0,#BLOBSIZE*0.05,Radian(ang))
  DisplaySprite3D(*ptrMonster\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(*ptrMonster\blobSprite[#YELLOWBLOB],#BLOBSIZE * 4,#BLOBSIZE * 4,#BLOBSIZE*2,#BLOBSIZE*2)
  DisplaySprite3D(*ptrMonster\blobSprite[#YELLOWBLOB], *ptrMonster\x, *ptrMonster\y,51) ; alpha = 0.2*255.0
  
  ;Finished!
EndProcedure


;********************************************************
;- --- Main program ---
;********************************************************

;- initialization
InitSprite()
InitSprite3D()
InitKeyboard()
InitMouse()



OpenWindow(0, 0, 0, Srx, Sry, "Blob Monster", #PB_Window_ScreenCentered|#PB_Window_SystemMenu|#PB_Window_MinimizeGadget) ;#PB_Window_ScreenCentered|#PB_Window_BorderLess)
OpenWindowedScreen(WindowID(0), 0, 0, Srx,Sry, 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()
For i=0 To #Nb
  Test(i)\blobSprite[#WHITEBLOB] = createBlobSprite(255,255,255)
  Test(i)\blobSprite[#REDBLOB] = createBlobSprite(255,0,0)
  Test(i)\blobSprite[#YELLOWBLOB] = createBlobSprite(255, 255,0)
  Test(i)\blobSprite[#CYANBLOB] = createBlobSprite(Random(200)+55,Random(200)+55,Random(200)+55)
  test(i)\time = i*100 
  ; Create a blobMonster object
  blobMonsterCreate(@test(i), Random(Srx-30)+15, Random(Sry-30)+15)
Next

;- Main loop

Repeat
  
  Repeat
    Event = WindowEvent()
    Debug Event
    If Event = #PB_Event_CloseWindow
      Quit = 1
    EndIf
  Until Event=0  Or Quit
    
  ;update the blobmonster
  For i=0 To #Nb 
    blobMonsterUpdate(@test(i), i)
  Next 
  
  ClearScreen(0)
  
  ; Draw the monster
  ; Note: Anything that use Sprite3D must be done between "Start3D()" and "Stop3D()"
  Start3D()
  For i=0 To #Nb
    blobMonsterDraw(@test(i))
  Next 
  Stop3D()
  
  ; Display result
  FlipBuffers()
  
  ExamineKeyboard()
Until KeyboardPushed(#PB_Key_Escape) Or Quit


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
Please correct my english
http://purebasic.developpez.com/
DarkDragon
Addict
Addict
Posts: 2345
Joined: Mon Jun 02, 2003 9:16 am
Location: Germany
Contact:

Re: How to make a Blob monster

Post by DarkDragon »

Hello,

The monster looks nice :-D .

But: WindowEvent missing .. application does not respond after clicking on the window. ;-)
bye,
Daniel
Kelebrindae
Enthusiast
Enthusiast
Posts: 151
Joined: Tue Apr 01, 2008 3:23 pm

Re: How to make a Blob monster

Post by Kelebrindae »

@Comtois: Thanks a lot for the nice comment.

@DarkDragon: yes, noob error at line 414. :oops: Thanks for pointing it!
User avatar
bobobo
Enthusiast
Enthusiast
Posts: 206
Joined: Mon Jun 09, 2003 8:30 am

Re: How to make a Blob monster

Post by bobobo »

some speed dynamics with

Code: Select all

..
  *n\speed = Random(100)/60 +0.25
..
f.i. in the createprocedure
사십 둘 .
Post Reply