The agent state transitions is handled by changeState(agent)
Here is a link to the sprite sheet commissioned by Leopardpm that I used.
http://opengameart.org/content/goblin-lumberjack
I downloaded goblin_lumberjack_red.png as I think the red stands out.
Load the sprite sheet into a paint program and resave it as goblinRed.bmp
I loaded them into MS PAINT and the transparency was lost but for this demo I wasn't using the transparency so it didn't matter.
The demo uses a tile world and tile collisions. A red border around the goblin shows the size of the image and the blue box shows the collision box of the sprite which collides with tiles with objects.
The red tiles would hold an image of a tree to be chopped into logs.
Finite State Machine:
The agent walks about in the "walk_with_axe" state until it hit a tile with a tree (red tile). The red tile turns into a walkable tile. It then goes into the "chopping" state for a fixed number of cycles. It then goes into the "walk_with_logs" state until it hits a border tile (pink). It releases the logs (animation not shown yet) and returns to the "walk_with_axe" state.
When I get in the mood I will add the picking up and placing down of logs animations along with an isometric version with images for trees.
Code: Select all
const WORLDW = 25 'dimensions of world in tiles
const WORLDH = 25
const TILEW = 16 'used in collision detection not size of image
const TILEH = 16
const SCRW = 1280 'screen dimensions
const SCRH = 600
const POSX = 32 'top/left position of 2D display
const POSY = 32
'====================================================================
'STATES
const WALK_WITH_AXE = 1
const WALK_WITH_LOGS = 2
const CHOPPING = 3
const PICK_UP_LOGS = 4
const PUT_DOWN_LOGS = 5
'====================================================================
dim shared as integer hitItem,hitx,hity 'item hit and tile coordinates
dim shared as integer foundItem
dim shared as integer counter 'count for chopping
screenres SCRW,SCRH,32
color rgb(0,0,0),rgb(255,255,255):cls
dim shared as any ptr goblinSheet
goblinSheet = imagecreate(2432,512)
bload "goblinRedT.bmp",goblinSheet
put (0,0),goblinSheet,trans
'create a tile world and read data
dim shared as integer world(WORLDW,WORLDH)
for j as integer = 0 to WORLDH-1
for i as integer = 0 to WORLDW-1
read world(i,j)
next i
next j
type AGENT
as integer x 'current position of image
as integer y
as integer w
as integer h
as integer hx 'hit and positioning box within image
as integer hy
as integer hw
as integer hh
as integer xd 'velocity in pixel change
as integer yd
as integer d 'direction of travel
as integer ID
as integer state 'current state agent is in
as integer a 'this sprite is being used if a = 1
as integer item 'item held by agent
end type
dim shared as AGENT ag1
ag1.x = 12*16 'top left corner of image
ag1.y = 12*16
ag1.w = 64 'dimensions of image
ag1.h = 64
ag1.hx = 24 'displacement within image block of collision rectangle
ag1.hy = 44 'of sprite positioning rectangel
ag1.hw = TILEW 'tile collision and sprite postioning rectangle dimensions
ag1.hh = TILEH
ag1.xd = 2
ag1.yd = 2
ag1.d = 3
ag1.item = 0 'id of item held by agent
ag1.state = 1 'walking with axe
type STRIPS
as integer x,y,w,h '
as integer f,d 'frame and direction
as integer tf 'total frames
end type
sub drawStrip(s as STRIPS)
put (ag1.x,ag1.y),goblinSheet,(s.f*s.w+s.x,ag1.d*s.h)-(s.f*s.w+s.w-1+s.x,ag1.d*s.h+s.h-1),trans
s.f = s.f + 1
if s.f >= s.tf then s.f = 0
end sub
dim shared as STRIPS strip(0 to 4)
strip(0).tf = 1 'stop
strip(0).f = 0
strip(0).d = 0
strip(0).x = 0
strip(0).y = 0
strip(0).w = 64
strip(0).h = 64
strip(1).tf = 8 'walk with axe
strip(1).f = 0
strip(1).d = 0
strip(1).x = 4*64
strip(1).y = 0
strip(1).w = 64
strip(1).h = 64
strip(2).tf = 8 'walk with logs
strip(2).f = 0
strip(2).d = 0
strip(2).x = 12*64
strip(2).y = 0
strip(2).w = 64
strip(2).h = 64
strip(3).tf = 6 'chop logs state
strip(3).f = 0
strip(3).d = 0
strip(3).x = 20*64
strip(3).y = 0
strip(3).w = 64
strip(3).h = 64
strip(4).tf = 4 'pick up logs
strip(4).f = 0
strip(4).d = 0
strip(4).x = 26*64
strip(4).y = 0
strip(4).w = 64
strip(4).h = 64
'=====================================================================
function spriteCollision(b1 as AGENT,b2 as AGENT) as boolean
return (b2.y) < (b1.y + b1.h) and (b2.y + b2.h) > (b1.y) and (b2.x) < (b1.x + b1.w) and (b2.x + b2.w) > (b1.x)
end function
'=====================================================================
function tileCollision(ag as AGENT) as integer
dim as integer hit = 0
dim as integer TILEX,TILEY
dim as integer px,py
px = ag.x+ag.hx-POSX 'displacement within image of hit block
py = ag.y+ag.hy-POSY
'test overlap of another tile
TILEX = int(px/TILEW)
TILEY = int(py/TILEH)
if world(TILEX,TILEY)<>0 then
hit = world(TILEX,TILEY)
hitx = TILEX
hity = TILEY
end if
TILEX = int((px+TILEW-1)/TILEW)
TILEY = int((py)/TILEH)
if world(TILEX,TILEY)<>0 then
hit = world(TILEX,TILEY)
hitx = TILEX
hity = TILEY
end if
TILEX = int((px)/TILEW)
TILEY = int((py+TILEH-1)/TILEH)
if world(TILEX,TILEY)<>0 then
hit = world(TILEX,TILEY)
hitx = TILEX
hity = TILEY
end if
TILEX = int((px+TILEW-1)/TILEW)
TILEY = int((py+TILEH-1)/TILEH)
if world(TILEX,TILEY)<>0 then
hit = world(TILEX,TILEY)
hitx = TILEX
hity = TILEY
end if
return hit
end function
function outOfBounds(ag as AGENT) as boolean
dim as integer px,py
px = ag.x+ag.hx
py = ag.y+ag.hy 'top/left corner of collision box
return (px < POSX) or (px >= WORLDW*TILEW-TILEW+POSX) or (py < POSY) or (py >= WORLDH*TILEH-TILEH+POSY) 'then
end function
sub setDirection(ag as AGENT)
If ag.xd < 0 and ag.yd = 0 then ag.d = 6 'left
If ag.xd > 0 and ag.yd = 0 then ag.d = 2 'right
If ag.yd < 0 and ag.xd = 0 then ag.d = 0 'up
If ag.yd > 0 and ag.xd = 0 then ag.d = 4 'down
If ag.xd < 0 and ag.yd < 0 then ag.d = 7 'W up/left
If ag.xd > 0 and ag.yd > 0 then ag.d = 3 'A down/right
If ag.yd < 0 and ag.xd > 0 then ag.d = 1 'S down/left
If ag.yd > 0 and ag.xd < 0 then ag.d = 5 'D up/right
end sub
sub makeMove(ag as AGENT)
ag.x = ag.x + ag.xd
ag.y = ag.y + ag.yd
end sub
sub undoMove(ag as AGENT)
ag.x = ag.x - ag.xd 'undo move
ag.y = ag.y - ag.yd
end sub
sub changeDirection(ag as AGENT)
ag.xd = int(rnd(1)*3)-1
ag.yd = int(rnd(1)*3)-1
while ag.xd = 0 and ag.yd = 0 '(ag.dx and ag.dy) or (ag.dx=0 and ag.dy=0)
ag.xd = int(rnd(1)*3)-1
ag.yd = int(rnd(1)*3)-1
wend
ag.xd = ag.xd * 2
ag.yd = ag.yd * 2
end sub
sub drawWorld()
screenlock
cls
line (POSX,POSY)-(WORLDW*TILEW+POSX,WORLDH*TILEH+POSY),rgb(181,230,29),bf
line (POSX,POSY)-(WORLDW*TILEW+POSX,WORLDH*TILEH+POSY),rgb(0,0,0),b
drawStrip(strip(ag1.state)) 'show animation for this state
for j as integer = 0 to WORLDH-1
for i as integer = 0 to WORLDW-1
if world(i,j)=1 then
line (i*TILEW+POSX,j*TILEH+POSY)-(i*TILEW+TILEW+POSX,j*TILEH+TILEH+POSY),rgb(200,10,0),bf
end if
if world(i,j)=2 then
line (i*TILEW+POSX,j*TILEH+POSY)-(i*TILEW+TILEW+POSX,j*TILEH+TILEH+POSY),rgb(20,100,200),bf
end if
if world(i,j)=3 then
line (i*TILEW+POSX,j*TILEH+POSY)-(i*TILEW+TILEW+POSX,j*TILEH+TILEH+POSY),rgb(200,100,100),bf
end if
next i
next j
line (ag1.x,ag1.y)-(ag1.x+ag1.w-1,ag1.y+ag1.h-1),rgb(255,0,0),b 'border image
line (ag1.x+ag1.hx,ag1.y+ag1.hy)-(ag1.x+ag1.hx+ag1.hw-1,ag1.y+ag1.hy+ag1.hh-1),rgb(0,0,255),b 'border collision box
locate 2,2
print "found item ";foundItem
screenunlock
end sub
sub update()
drawWorld()
end sub
sub changeState(ag as AGENT)
Select Case As Const ag.state
Case WALK_WITH_AXE
makeMove(ag)
setDirection(ag)
hitItem = tileCollision(ag)
if hitItem <> 0 then
if hitItem = 1 then 'hit a pile of logs?
world(hitx,hity)=0
ag.state = 3 'chopping
counter = 0 'start counter
end if
foundItem = hitItem
undoMove(ag)
changeDirection(ag)
end if
Case WALK_WITH_LOGS
makeMove(ag)
setDirection(ag)
hitItem = tileCollision(ag)
if hitItem <> 0 then
foundItem = hitItem
undoMove(ag)
changeDirection(ag)
if hitItem = 3 then 'border place down logs
ag.state = 1
end if
end if
Case CHOPPING
counter = counter + 1
if counter = 100 then
ag.state = 2
end if
Case PICK_UP_LOGS
Case PUT_DOWN_LOGS
End Select
end sub
cls
dim as single now1
now1 = timer
update()
do
if timer > now1 + 0.05 then
now1 = timer
changeState(ag1)
update()
end if
sleep 2
loop until multikey(&H01)
sleep
'0 = walkable tile, 1 = logs, 2 = unwalkable tile, 3 = border tile
data 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3
data 3,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3
data 3,0,2,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,3
data 3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3
data 3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,3
data 3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3
data 3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3
data 3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3
data 3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3
data 3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3
data 3,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3
data 3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,3
data 3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,3
data 3,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3
data 3,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3
data 3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,3
data 3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,3
data 3,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3
data 3,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3
data 3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3
data 3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3
data 3,0,0,1,0,1,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,3
data 3,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,2,0,0,3
data 3,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,3
data 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3