FunSpIns - The hero must move, the enemies must move smarter.
Inspired by Rob Ashton’s series “Learn functional programming with me” It is time to feed things back to the actors! The actor signature did change a teeny bit:
That way we will be able to tell the rendering what colour we want our rectangles to be.
So, our enemies actor becomes:
changeX is a new method with a pretty simple implementation:
From which you can conclude that (+2) is actually a function, namely adding two to whatever supports adding twos to them.
Some changes where done on the loop. Indeed, there was no bail-out condition, which is introduced by checking whether ‘x’ is pressed. Also, I don’t want to react to any mouse events, hence it is sufficient to just pass on any key that is pressed by the gamer. The main and loop functions got some refactoring:
As you can see main is pretty much toned down to set up the SDL stuff and start looping with an initial version of our World. Loop became its own function:
the value of pollEvent is bound to the handleEvent function. That one is responsible for our bailout (matching on a keydown event where x is pressed), as well as keeping the loop going in any other event.
One speciality is that we extract the pressed key, and in case of any other event that may come through we do as if some unknown key would have been pressed. Hence, our World now does not keep the whole SDL event, but just the last key pressed. Also, while no KeyUp event is coming along, we moving the lastKey of the previous world on to the next. This has the nice effect that our actors will react to the keydown event as long as the given key is pressed (Your keyboard will thank me!). getRect and getPixel functions are helpers to map from our WorldItem into the SDL data types.
Now that we have a nice key event hanging around in the World, let’s get our hero into the equation:
Depending on whether the user pressed left or right cursor key, we define the position of our hero in the World and create the corresponding WorldItem. I also need to match any other key, otherwise a non-exhaustive pattern match error will occur at runtime - in this case we leave the world unchanged.
Enemy movement
Rob got somewhat ahead of me in that he has already sorted out the enemies moving from left to right and back, etc. - My enemies are currently edlessly wandering towards the left, leaving the screen and escaping the righteous vengeance of our world-defending hero.
For this I introduce a new state into the world:
where MovementPattern is defined as
A pattern is therefore a number of Tuples consisting of a movement definition and a function that evaluates to true/false based on an input of Points. The way to use the pattern is as follows:
- Extract the points from whatever WorldItems you want to consider
- If the function of the first element evaluates to True, leave things as they are
- If the function of the first element evaluates to False, roll over the pattern - first becomes last, second becomes first.
So I go ahead and express that code-wise:
where fst, snd are Prelude functions to extract the first and second value of a tuple, respectively. roll is just roll (x:xs) = xs++[x]. Armed with the ability to evaluate a movement pattern, let’s define one in the initialization of our World:
Hence, the pattern is right, while the maximum X of our point cloud is smaller than 620, the one time down (alwaysFalse returns false for whatever input), then left while the smallest X of the point cloud is bigger than 0, the one time down.
We can use this in our enemy actor to make sure that it moves properly throughout the screen:
Based on the current Movement, the enemy position is changed for the next iteration through our world.
At this point in the series we have…
- A bunch of enemies that move left to right, slowly coming down
- A red hero that can be moved to the left and the right
Doesn’t sound terribly impressive, but the total LoC is about 117, and that from a FP noob, but we have still some way to go.