Blobmonster

Previous topic - Next topic

Albert

So Charlie has this tutorial and source code in BlitzMax: http://www.charliesgames.com/wordpress/?p=441
I ported it to glBasic, have fun!



Code (glbasic) Select

// --------------------------------- //
// Project: blobmonster
// Start: Friday, February 04, 2011
// IDE Version: 8.200

SETCURRENTDIR("Media") // seperate media and binaries?

//ported to glBasic by Bence Dobos, 2011

//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

GLOBAL KEY_ESCAPE=1
GLOBAL blob=0
GLOBAL w, h

//load the image
LOADSPRITE "blob.png", blob
GETSPRITESIZE blob, w, h

//create a blobMonster object
LOCAL test AS blobMonster

test.Create(10, 10)
//main loop
WHILE KEY(KEY_ESCAPE)=0
//update and draw the blobmonster
CLEARSCREEN
test.Update()
test.Draw()

SHOWSCREEN
WEND
END
//Finished!

//simple class (type in glBasic) to hold a 2d coordinate
TYPE point
x#
y#
ENDTYPE

//here's the blob monster type
TYPE blobMonster

//x and y coords
x#
y#

//speed, try changing it
speed# = 1

//number of nodes along the body, try changing it to 100
segments# = 10

//array to hold the points along the body
tail[] AS point

time# = 0

//function that returns a new blob monster object. Blitzmax equivalent (kind of)
//of a constructor in C++/Java
FUNCTION Create AS blobMonster:inX#, inY#
DIM self.tail[self.segments]
//starting point of the blob monster
self.x = inX
self.y = inY
//give the tail some coordinates, just make them the same as the main x and y for now
FOR i = 0 TO self.segments - 1
self.tail[i].x# = inX
self.tail[i].y# = inY
NEXT

RETURN self
ENDFUNCTION

FUNCTION Update%:
//time is a bit misleading, it's used for all sorts of things
INC self.time#, self.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
self.y = (15 * COS(self.time * -6)) + (240 + (180 * SIN(self.time * 1.3)))
self.x = (15 * SIN(self.time * -6)) + (320 + (200 * COS(self.time / 1.5)))

//put the head of the tail at x,y coords
self.tail[0].x = self.x
self.tail[0].y = self.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 self.segments - 1
    //calculate distance between the current point and the previous
    LOCAL distX# = (self.tail[i - 1].x - tail[i].x)
        LOCAL distY# = (self.tail[i - 1].y - tail[i].y)
LOCAL dist# = SQR(distX * distX + distY * distY)
      //move if too far away
          IF dist > 7
//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
self.tail[i].x = self.tail[i].x + (distX * (0.3))
            self.tail[i].y = self.tail[i].y + (distY * (0.3))
          ENDIF

NEXT

RETURN FALSE
ENDFUNCTION

FUNCTION Draw:
//time to draw stuff!

//this sets the blend mode to LIGHTBLEND, or additive blending, which makes
//the images progressively more bright as they overlap
//ALPHAMODE LIGHTBLEND
LOCAL color=RGB( 0, 200, 150 )
LOCAL scale=1
//###########
//draw the main bit of the body
//begin looping through the segments of the body
FOR i = 0 TO self.segments - 1
//set the alpha transparency vaue to 0.15, pretty transparent
ALPHAMODE 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.
scale = 1 + (0.5 * SIN(i * 35))
//draw the image
PolySprite(blob, self.tail[i].x, self.tail[i].y, scale, scale, color, 0.5, 0.5, 0, w, h)

//this next chunk just draws smaller dots in the center of each segment of the body
ALPHAMODE 0.8
scale = 0.1
PolySprite(blob, self.tail[i].x, self.tail[i].y, scale, scale, color, 0.5, 0.5, 0, w, h)
NEXT

//#########################
//draw little spikes on tail
color = RGB( 255, 255, 255 )
//note that the x and y scales are different
LOCAL scalex = 0.6
LOCAL scaley = 0.1
LOCAL rot=0
//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

//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.
rot = 10 * SIN(self.time * 10) + calculateAngle(self.tail[self.segments - 1].x, self.tail[self.segments - 1].y, self.tail[self.segments - 5].x, self.tail[self.segments - 5].y) + 90
PolySprite(blob, self.tail[self.segments - 1].x, self.tail[self.segments - 1].y, scalex, scaley, color,0, 0.5, rot, w, h)

//second tail image uses negative time to make it move in the opposite direction
rot = 10 * SIN(-self.time * 10) + calculateAngle(self.tail[self.segments - 1].x, self.tail[self.segments - 1].y, self.tail[self.segments - 5].x, self.tail[self.segments - 5].y) + 90
PolySprite(blob, self.tail[self.segments - 1].x, self.tail[self.segments - 1].y, scalex, scaley, color,0, 0.5, rot, w, h)



//#####################
//draw little fins/arms
ALPHAMODE 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 self.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.
scalex = 0.1 + (0.6 * SIN(i * 30))
scaley = 0.05

//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.
rot = 33 * SIN(self.time * 5 + i * 30) + calculateAngle(self.tail[i].x, self.tail[i].y, self.tail[i - 1].x, self.tail[i - 1].y)
PolySprite( blob, self.tail[i].x, self.tail[i].y, scalex, scaley, color, 0, 0.5, rot, w, h)

//rotate the opposte fin, note that the signs have changes (-time and -i*30)
//to reflect the rotations of the other fin
rot = 33 * SIN(-self.time * 5 - i * 30) + calculateAngle(self.tail[i].x, self.tail[i].y, self.tail[i - 1].x, self.tail[i - 1].y) + 180
PolySprite( blob, self.tail[i].x, self.tail[i].y, scalex, scaley, color, 0, 0.5, rot, w, h)

NEXT

//###################
//Draw the eyes. These are just at 90 degrees to the head of the tail.
color = RGB( 255, 0, 0 )
scale = 0.6
ALPHAMODE 0.3
LOCAL ang# = calculateAngle(self.tail[0].x, self.tail[0].y, self.tail[1].x, self.tail[1].y)
PolySprite(blob, self.x + (7 * COS(ang + 50)), self.y + (7 * SIN(ang + 50)), scale, scale, color, 0.5, 0.5, 0.0, w, h)
PolySprite(blob, self.x + (7 * COS(ang + 140)), self.y + (7 * SIN(ang + 140)), scale, scale, color, 0.5, 0.5, 0.0, w, h)
color = RGB( 255, 255, 255 )
scale = 0.1
ALPHAMODE 0.5
PolySprite(blob, self.x + (7 * COS(ang + 50)), self.y + (7 * SIN(ang + 50)), scale, scale, color, 0.5, 0.5, 0.0, w, h)
PolySprite(blob, self.x + (7 * COS(ang + 140)), self.y + (7 * SIN(ang + 140)), scale, scale, color, 0.5, 0.5, 0.0, w, h)

//draw beaky thing
color = RGB( 0, 200, 155 )
scalex = 0.3
scaley = 0.1
ALPHAMODE 0.8
rot = ang + 95
PolySprite(blob, self.x, self.y, scalex, scaley, color, 0.0, 0.5, rot, w, h)

//yellow light
color = RGB( 255, 255, 0 )
ALPHAMODE 0.2
scale = 4
PolySprite(blob, self.x, self.y, scale, scale, color, 0.5, 0.5, 0, w, h)

//Finished!
ENDFUNCTION

ENDTYPE

//This function calculates and returns the angle between two 2d coordinates
FUNCTION calculateAngle#:x1#,y1#,x2#,y2#
LOCAL theX#=x1-x2
LOCAL theY#=y1-y2
LOCAL theAngle#=-ATAN(theX,theY)
RETURN theAngle
ENDFUNCTION

//Draw and colorize a sprite. You can set the handle point, rotation, scale and color of the sprite
//Written by Bence Dobos
//spr - the ID of the sprite
//scalex, scaley - the ratio of the sprite scale [0.0-inf]
//color - 0xffffff is the normal color
//xc,yc - the ratio of the handle point of the sprite [0.0-1.0], this point is used to draw the sprite, rotate and scale. 0,0 is the top-left point, 0.5,0.5 is the center point
//rot - rotation of the sprite [0-360]
//w,h - width, height of the sprite in pixel, if not specified it's determined automatically
FUNCTION PolySprite: spr, x, y, scalex, scaley, color=0xffffff, xc=0.0, yc=0.0, rot=0, w=-1, h=-1
IF w=-1
GETSPRITESIZE spr, w, h
ENDIF
LOCAL w2=w*scalex
LOCAL h2=h*scaley
LOCAL xcenter=x+xc*w2
LOCAL ycenter=y+yc*h2
LOCAL xr1=-xc*w2
LOCAL yr1=-yc*h2
LOCAL xr2=(1.0-xc)*w2
LOCAL yr2=-yc*h2
LOCAL xr3=(1.0-xc)*w2
LOCAL yr3=(1.0-yc)*h2
LOCAL xr4=-xc*w2
LOCAL yr4=(1.0-yc)*h2

LOCAL x1, y1, x2, y2
LOCAL x3, y3, x4, y4
IF rot<>0
LOCAL sp = SIN(rot)
LOCAL cp = COS(rot)
x1 = xr1*cp-yr1*sp+x
y1 = xr1*sp+yr1*cp+y
x2 = xr2*cp-yr2*sp+x
y2 = xr2*sp+yr2*cp+y
x3 = xr3*cp-yr3*sp+x
y3 = xr3*sp+yr3*cp+y
x4 = xr4*cp-yr4*sp+x
y4 = xr4*sp+yr4*cp+y
ELSE
x1=xr1+x
y1=yr1+y
x2=xr2+x
y2=yr2+y
x3=xr3+x
y3=yr3+y
x4=xr4+x
y4=yr4+y
ENDIF

STARTPOLY spr
  POLYVECTOR   x1, y1,  0,  0, color
  POLYVECTOR   x2, y2,  0,  h, color
  POLYVECTOR   x3, y3,  w,  h, color
  POLYVECTOR   x4, y4,  w,  0, color
ENDPOLY
ENDFUNCTION


Edit: Missing beaky thing, fixed.

[attachment deleted by admin]

Wampus

Heheh. Cute.

Albert

Cute? See in motion. I have nithmares with it.  :O

Slydog

Very cool effect!  :good:

It would look great in a game.
Or to apply to a caterpillar animation.  (By using some of the code of course, everything but the drawing I guess!)
It's neat how the only external graphic is the 'blob' circle and how it's used to create the creature part by part.
My current project (WIP) :: TwistedMaze <<  [Updated: 2015-11-25]

DmitryK

wow super effect  :blink:
Our life is just a Game!

Ian Price

That is wonderfully organic. Clever stuff. :)
I came. I saw. I played.

Wampus

Quote from: Ian Price on 2011-Feb-11
That is wonderfully organic. Clever stuff. :)

Yeah, organic it is. Even when it twists in reversals or half reversals it is very life-like.

Stuff like this would be great in a rehash of the first level of Spore. That was the most fun part of that game imo.

Albert

The beak beetween its two eye was missing. I added it and changed the first post.

Hark0

VERY GOOD!!!

:good:
http://litiopixel.blogspot.com
litiopixel.blogspot.com - Desarrollo videojuegos Indie · Pixel-Art · Retroinformática · Electrónica Development Indie Videogames · Pixel-Art · Retrocomputing · Electronic

Leginus

Wow!  Thats a really nice routine. Wish i had paid more attention to maths at school MANY MANY years ago :)

Moebius

Very nice!
Endless Loop: n., see Loop, Endless.
Loop, Endless: n., see Endless Loop.
- Random Shack Data Processing Dictionary

aonyn

Wow, that is really very cool.  ;)
For by grace are ye saved through faith, and that not of yourselves: it is the gift of God: Not of works, lest any man should boast. -Ephesians 2:8-9

Schranz0r

I like that style!
I <3 DGArray's :D

PC:
AMD Ryzen 7 3800X 16@4.5GHz, 16GB Corsair Vengeance LPX DDR4-3200 RAM, ASUS Dual GeForce RTX™ 3060 OC Edition 12GB GDDR6, Windows 11 Pro 64Bit, MSi Tomahawk B350 Mainboard

phaelax

I really need to find a way to work that creature into a game

Albert

You are free to do it, just told to Charlie :) He wants to see what games are we make with his monsters: http://www.charliesgames.com/wordpress/?p=441