#### Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

# Ghosties - work in progress

edited April 2015 in Examples Posts: 745

Here is a simple example of a finite state machine engine - mainly aimed at beginners with a decent amount of comments. This came from a request / comment on one of the videos of the fruit ninja ghost game I'm working on -

Hopefully the commenter is lurking here and finds it useful

``````--Simple Finite State Machine plus rising and fading sprite menu effect
-- by West

function setup()
displayMode(FULLSCREEN)
--set up the states for the Finite State Machine.
PLAYING=2 --the state for the actual game play
LEVELCOMPLETE=3 --the state for the level complete screen
GAMEOVER=4 --the state for the game over screen
gamestate=READY --set a variable to control the current state

-- set up a variable to allow a short delay between moving from different states
scrdelay=0
--set up a variable to store the current level
currentlevel=1

--set up a table to handle the touches
touches={}

spacemen={} --set up a table to hold each of the spacemen objects
--create a loop to add 30 new instances of the spaceman to the table
for i=1,30 do
-- insert a new instance with the following variables
-- x - the horizontal screen position of the spaceman.
-- y - the vertical screen position of the spaceman.
-- size - the size of the spaceman - initial value a random value between 0.3 and 1
-- fade - the transparency of the spaceman
-- dir - the direction of the fade with 1 meaning getting more solid and -1 getting more transparent
-- spd - the speed at which the spaceman rises up the screen
end
end

-- This function gets called once every frame. This is the main program loop
function draw()
--the controller for the Finite State Machine. All this does is check to see what state the game is currently in and calls the appropriate function for that state
-- the scrdelay variable is a counter which is used to add a delay between moving between screens
if gamestate==PLAYING then
play()
scrdelay = scrdelay + 1
elseif gamestate==LEVELCOMPLETE then
scrdelay = scrdelay + 1
levelover()
elseif gamestate==GAMEOVER then
scrdelay = scrdelay + 1
gameoverscreen()
end
end

-- the function to drawthe main menu screen. Consists of 3 parts:
-- 1) the rising and fading spacemen
-- 2) the title
-- 3) the "tap to start" message which appears after the delay
-- handling the user interaction through touches is done through the touch function and is the same regardless of which gamestate we are in
--set a background colour
background(33, 71, 148, 255)
-- 1) the rising and fading spacemen
--set up a loop where each instance of the spacemen will be dealt with in turn
for i,s in pairs(spacemen) do
--inside this loop, the current spaceman is represented by the variable s and each of the properties is accessed using the .property form
--For example, to get the x position of the current spaceman use s.x

-- set the transparency of the spaceman based on its fade value
-- draw the spaceman on the screen based on its position and size. 65 and 92 are the width and height of the spaceman spriteand these vales are multiplied by the scaling factor (or size) variable
sprite("Platformer Art:Guy Standing",s.x,s.y,65*s.size,92*s.size)
--change the transparency based on the dir property which can be either 1 or -1
--run a check on the fade - if it is outside the maximum value (255 / solid) or minimum value (0 / fully transparent) then reverse the direction of fade
-- so if dir was 1 then the spaceman is getting more solid by adding 1 to the fade property each loop of the main game
-- When it reaches the maximum value of 255 then set dir to be -1 and the fade value will now start to decraese and the spaceman will fade
--[[
--optional extra - move the spaceman to a new random position when it fades away completely
s.x=math.random(WIDTH)
s.y=math.random(HEIGHT)
end
]]--
--move the spaceman up the screen based on its speed. Here the raw speed has been slowed by a factor of 10
s.y = s.y + s.spd/10
--detect if the spaceman has gone past the top of the screen and if so then reset its height to the bottom of the screen
-- the + and - offsets are to take into account the height of the sprite.  the y position is the centre of the sprite so there would be an untidy jump as the sprite would disappear when the middle of the sprite crosses the top of the screen
if s.y>HEIGHT+50 then s.y=-50 end
end
--housekeeping - reset the transparency to ensure that anything else drawn isn't faded
noTint()
-- 2) the title
--set up the font and print out the title
strokeWidth(2)
fill(171, 199, 221, 255)
font("AmericanTypewriter-Light")
fontSize(96)
text("FSM Demo",WIDTH/2,5*HEIGHT/8)

-- 3) the "tap to start" message which appears after the delay
font("AmericanTypewriter-Light")
fontSize(32)
if scrdelay>100 then
text("Tap to start",WIDTH/2,3*HEIGHT/8)
end
end

-- these next two functions are basically repeats of points 2) and 3) from the menu function above
function levelover()
background(33, 71, 148, 255)
strokeWidth(2)
fill(141, 127, 33, 255)
fontSize(64)
--  use .. to join strings together - here the current level is inserted into the message
text("Level "..currentlevel.." complete",WIDTH/2,HEIGHT/2)
fontSize(32)
if scrdelay>100 then
text("Tap for next level",WIDTH/2,3*HEIGHT/8)
end
end

function gameoverscreen()
background(33, 71, 148, 255)
strokeWidth(2)
fill(141, 127, 33, 255)
fontSize(64)
text("Game over",WIDTH/2,HEIGHT/2)
fontSize(32)
if scrdelay>100 then
end
end

function play()
--very simple game - ifyou tap on the left hand side of the screen you win
-- this is just to demonstrate the finite state machine - obviously you would substitue your actual game function here
background(198, 18, 18, 255)
fill(117, 255, 0, 255)
rect(0,0,WIDTH/2,HEIGHT)
fill(63, 28, 144, 255)
font("AmericanTypewriter-CondensedLight")
fontSize(72)
text("The Game",WIDTH/2,3*HEIGHT/4)
text("Win",WIDTH/4,HEIGHT/2)
text("Lose",3*WIDTH/4,HEIGHT/2)
end

function touched(touch)
--this function is called each time the screen is touched regardless of what gamestate we are in.
--therefore we need to do a check on which state we are in and respond accordingly
-- in the menu, level complete and game over screens we are simply responding to a tap anywhere
-- in the actual gameplay we need to check where in the screen the tap has occured so a separate function is needed
if touch.state==ENDED or touch.state==CANCELLED then
if gamestate==PLAYING then
--separate function to check position of tap
processTouch(touch)
--if the gamestate is on the main menu, change it to the game play state and reset the scrdelay counter
gamestate=PLAYING
scrdelay=0
elseif gamestate==LEVELCOMPLETE and scrdelay>100 then
--if the gamestate is on the level complete, change it to the game play state and reset the scrdelay counter
gamestate=PLAYING
scrdelay=0
--    increase the current level
currentlevel = currentlevel + 1
elseif gamestate==GAMEOVER and scrdelay>100 then
--if the gamestate is on the gameover, change it to the main menu state and reset the scrdelay counter
--reset the current level
currentlevel=1
end
touches[touch.id] = nil
else
touches[touch.id] = touch
end
end

function processTouch(touch)
--check the x position of the tap - if it is greater than half the width then change the game state to gameover and reset the scrdelay counter
if touch.x>WIDTH/2 then
scrdelay=0
gamestate=GAMEOVER
else
--otherwise the tap was on the left and so change the game state to level complete and reset the scrdelay counter
scrdelay=0
gamestate=LEVELCOMPLETE
end
end

``````

• Mod
Posts: 2,020

I love the slicing animation here, very impressive. One suggestion for the state machine, use a function pointer instead of a set of globals and a branching if statement. So to change state you write `scene=play`, `scene=menu`, `scene=levelover` etc, and then your draw loop is just `scene()`.

• Posts: 289

it felt so right, ghosts are so cute that i could slice them

• Posts: 745

@yojimbo - I've not really tried that before but it looks a much more elegant solution. This was supposed to be pitche'd at an absolute beginner so don't know if that adds a complexity which is harder to understand (as opposed to if statements which are pretty close to "English")

Have also done some new backgrounds for the ghost slicing game. 10 bonus points for the subtle movie reference in one background

• Posts: 300

Batteries not included.

• Posts: 745
• Mod
Posts: 2,020

Ghostbusters!

• Mod
Posts: 2,020

I love the silhouette art style. Are you using an iPad vector art app like Inkpad or something for that?

I also really like the idea of the different methods by which each ghost has to be dispatched. I always found the original Fruit Ninja mechanic to be a little simplistic (even my cat can play it), but this adds a very original twist (it's probably too difficult for my cat now tho ;-) ).

• Posts: 745

@yojimbo2000 - yep Ghostbusters!

I've been toying with variations on the dispatching methods. I could increase from the 5 current ones (up/down slide, left/right slice, tap, spin and pinch) by differentiating between clockwise and anticlockwise spins and double/triple taps as well. This might go in different game modes. At the moment limiting to swipes only but ramping up the appearance rate makes for quite a challenge. The pinch and spin gestures are also not as robust as I'd like them to be, which can be frustrating if they are picked up incorrectly

• Posts: 745

Added a few new backgrounds. The snowflakes also respond to swipes. Will use most of them as bonus round backgrounds keeping the straightforward spooky ones as the main gameplay ones

• Posts: 398

Ha! Good work @West - love the Star Wars inspired one towards the end.. made me chuckle!!! :-D

• Posts: 3

Great backgrounds! =D>

• Posts: 745

Cheers! It's much smoother on the actual iPad - video capture seems to slow it down quite a bit.

• Posts: 2,042

@West, these backgrounds are great! Very impressive

• Posts: 745

@JakAttak - thanks!

• Posts: 745

Testing out a "bonus" ghost which needs to be "trimmed" down to reveal a bonus (in this case a heart). May set different conditions for the bonus ghost (eg time limits, limited slices to release bonus, no more than x fragments on screen at once)

• Posts: 289

if add a few skulls and skeletons?

• Posts: 745

Thanks for the suggestion but I'll concentrate on ghosts at the moment

• Posts: 1,255

What a lovely game.

• Posts: 745

Thanks @Mark