Getting across spikes

Hi all!

I'm new to Pulp and new to the forum, but excited to be here!

I've found @SquidGodDev 's video tutorial to be an awesome starting point.

One thing I think I got working, but I'm curious if folks would recommend a better way, is how to time "spikes" such that if the player needs to move across a field of alternating spikes, that it's possible to do so without damage.

For example:

I used this kind of event loop as suggested in @SquidGodDev 's video:

on loop do
	fElapsed = event.frame
	fElapsed /= spikeInterval
	fElapsedFloor = floor fElapsed
	if fElapsed==fElapsedFloor then
		emit "spikeUpdate"
	end

However, when I naively lay out spikes next to each other like that, it seems impossible for the player to get across without hitting a spike or two, because there's no point in time the player can be standing on SpikesDown and move to the next set of SpikesDown – because the spikes they're standing on come up at the exact same time the next row of spikes goes down.

So I figured I needed to insert some kind of delay of having the spikes come back up, so that there's a slight gap when all the spikes are down.

I did so by modifying the SpikesDown update as follows:

on spikeUpdate do
	wait 0.2 then
		call "spikesGoUp"
	end
end

on spikesGoUp do
	swap "Spikes"
	
	if event.x==event.px then
		if event.y==event.py then
			damage = spikeDamage
			tell event.player to
				call "damagePlayer"
			end
		end
	end
end

This gives a 0.2 second delay when the player can jump between rows while everything is down. It's still tricky, but seems like it works.

I'm new to all this so curious if anyone would have an alternate suggestion of how to do this.

Thanks all!
Josh

PS... here's my current go at all this:
Penguin Pulp.json.zip (4.9 KB)
(is this the right way to share on here? export the JSON, and zip it up?)

Hmmm..... I ran into a problem with my solution.

If you exit the room while in this wait block, the swapping of spikes will happen in the next room, which can effectively create spikes in the wrong place =P

I tried to fix this by having a variable that I can set to cancel the pending update. This works, but also can cause the state of the spikes to get flipped relatively to other spikes if you go back and forth between the rooms :-/

Hmmmmm

Hi! One thing you can do instead of using wait as a timer is using play.

I had this example that seems to work without problems:
SpikesExample.json.zip (3.7 KB)

On the room's script where you have the spikes we have this code for starting the loop and for avoiding bugs:

on enter do
	emit "spikeLoop"
end

on exit do
	emit "spikeReset"
end

We call the event "spikeLoop" that affects the tile "spikeHole" (which is an Item type tile) that does this:

on spikeLoop do
	player_XY = event.px
	player_XY *= 100
	player_XY += event.py
	
	XY = event.x
	XY *= 100
	XY += event.y
	
	if player_XY==XY then
		tell event.player to
			call "playerTakesHit"
		end
	end
	
	play "spikeUp" then
		play "spikeHole" then
			call "spikeLoop"
		end
	end
end

At the beginning of the event we make damage to the player if it's on top of it, and then we start the loop where it changes the tile using play to the "spikeUp" tile (also an Item type). "spikeUp" has this code to make damage if the player enters the spike when it's animating, and to reset it to a "spikeHole" tile when we call it when we exit the room:

on collect do
	tell event.player to
		call "playerTakesHit"
	end
end

on spikeReset do
	swap "spikeHole"
end

And one last note, "spikeHole" has two identical frames which we are using as the "timer". If you want it to be faster, you just need to change its FPS. If you want it to be slower than 2 seconds you can duplicate frames :slight_smile:

1 Like

I think there's some ideas in here that will help me fix it – but your example doesn't quite do the challenge I want... that is..

I want rows...

xoxoxo
xoxoxo
xoxoxo
xoxoxo
xoxoxo

where the odd rows (x)'s the spikes start up, and the even rows (o)'s the spikes start down, and they effectively alternate – however it needs to be possible for the player to get across without being damaged. So there has to be a slight gap when the X spikes go down, the O spikes need to be still down for a fraction of a second before they come up.

Thanks!
Josh

Have you considered just duplicating the spike sprite(s) and having two, something like spike and spike_offset, then you don't need to worry about delaying the swap, just manually align the two separate timers/behaviours. Sure you duplicate the sprite appearance and a bit of code, but you could probably minimise the latter with mimic.

1 Like

I haven't tried that yet – maybe that would simplify things.

But it seems I'd still have the basic challenge of wanting an event to happen 200ms later than an event that's ticking at a regular interval.

It's funny how this simple spikes problem can turn into a rabbit hole of challenges :wink:

I've implemented my own spike tiles now and thought you might be interested in my approach! Here's a demo:

pulp_spikes_demo

There are two different spike tiles visible there, both with 4 frames of animation. One has the extended spikes as its first frame, the other has the extended spikes as its third frame. They are "item" tiles with the following script:

on collect do
end

on playerPresent do
	current_frame = frame
	if current_frame==0 then
		tell event.player to
			call "takeDamage"
		end
	end
end

Where the current_frame conditional changes to match the frame with the extended spikes. Elsewhere there is a little supporting code:

In the game script:

on loop do
	if iframes>0 then
		iframes--
	end
	
	tell event.px,event.py to
		call "playerPresent"
	end
end

In the player script:

on takeDamage do
	if iframes==0 then
		iframes = 20
		health--
		shake 0.2
	end
end

I think this is quite neat. The game loop tries to call a generically named event on the player's current tile every frame. That tile is then responsible for doing something, if anything - in this case telling the player to take damage if the spikes are extended. The generalised takeDamage event on the player implements invincibility frames to prevent damage being taken every single frame.

Note I had to declare the collect event to prevent the default item collection behaviour.

1 Like

Nice! This feels like a pretty elegant solution.