Hello there everyone,
I really like the spawn parkour, it's a really cool concept, so I decided to recreate it in my spare time, just for a bit of fun:
If anyone is interested in my solution to get this working, then feel free to keep reading for the nerdy stuff, else you can just enjoy the conciseness of this post.
How it works:
Generating the Jumps:
So in Minecraft, every single block in a world has associated coordinates, x y and z - you know the ones. If you think of a jump in parkour as just the distance between two blocks, we can calculate this very easily by just finding the difference in the coordinates. This is what is called a relative block mapping and this is what I used to generate each jump.
For example, a 1 block jump will be a coordinate increase of 2 in either the x or z-direction, so their relative coordinates are 2 in either the x or z.
So, now that we know we can get blocks relative to another one, we can just store a relative block mapping to generate that jump.
I built a bunch of parkour jumps, and placed signs with all of their relative block mappings from the starting block -> the target block.
So after testing all these jumps, I stored all their relative mappings in the config.yml file:
This way, you can easily add/remove/edit any jumps. The one with multiple mappings stores multiple blocks, in this case, a neo jump.
So now, all we need to do is convert these strings (a line of text) to an integer (a number). The reason we have to do this is that in programming, it doesn't recognize "1" as 1. You cannot perform calculations with text, so we have to attempt to parse (convert) them from one to the other.
It's quite simple to do this, we just loop through every value in the list, and convert each mapping to an integer, and store them in an int[] (a list of integers, called an array). For multiple blocks, we just create (now, bear with me!) a multi-dimensional-array (an array inside an array), so it can store every mapping for every block.
And tada, we now have the ability to generate a parkour jump! All that's left to do is create a method for randomly selecting one of these mappings:
Realistically, we should only use one instance of ThreadLocalRandom for speed and safety, but for the sakes of this quick botched plugin, it doesn't really matter.
Detecting the player's movements:
There is a starting pressure plate block which teleports the player and begins their parkour challenge. This is surprisingly very easy to recreate.
In Spigot's API, there are a huge number of events that are triggered when different things happen. We can hook into these events and modify the behaviour, such as teleporting the player once they step on a pressure plate.
For this task, we have to use what's called the PlayerInteractEvent, and this is fired whenever the player interacts with anything - an inventory, an entity, when they click, you get the idea.
We don't want every pressure plate to be able to start the parkour, so we store their specific location, and check for that location instead - blocks don't tend to move on their own, so it's much more reliable:
We don't want players to constantly run into each other while doing the parkour, so we have to space them out. I do this by teleporting them a multiple of 15 blocks away, depending on how many players are currently doing the parkour. Because we have jumps going in all directions, the player stays in roughly the same position, so I decided that 15 blocks distance was a reasonable amount.
Once the player is doing the pakour, we need to store some data associated with them, like the block they're currently on, the block they're supposed to jump to, any other blocks, their points etc.
To do this, I created a custom data class containing all this data to easily be able to edit everything inside them:
blockFrom is the block they started at, blockTo is the block they need to jump to, otherBlocks is a list of any other blocks, points is how many jumps they've made and block is the the type of block, like MELON_BLOCK, LAPIS_BLOCK, etc.
All we need to do now is detect when they land on the correct block and spawn the next one, or if they fall, clear everything. The easiest way to do this is use the PlayerMoveEvent, which is fired every time a players location is changed (including yaw and pitch!).
We can simply get the players location, and the block for their location - and, as we've already established, if we have a block we can get another block relative to it, therefore, getting the block underneath the player is very easy.
We can check if the location of the block underneath the player is the same location as the block they are meant to be jumping to, and if it is, we can spawn another one (and add some fancy effects too, such as simple sound and flame particles):
So now that we have detected if the player has landed on the correct block, the question is this:
> How can we accurately detect if the player has missed the block?
There are multiple ways to do this, but the way I decided to do it is check if the players y-level is 2 blocks below the target blocks y-level. This means they've fallen and we can remove their data. I simply checked if the players y-level + 2 is below the target blocks y-level:
This just sets all the blocks back to air, and clears any data we are currently holding with the player.
Conclusion:
So this essentially concludes this devlog thing, I haven't included all aspects of the code - I've just focused on the main ideas and mechanics.
I really hope I explained how this works in a way that is friendly to understand, but if you got lost, I don't blame you - when I was starting out I wouldn't have a clue what any word of this means.
If anyone is interested, the full code is on GitHub: https://github.com/ihellsmc/SpawnPK
Happy scrolling, and have a fantastic day!
Brandon
I really like the spawn parkour, it's a really cool concept, so I decided to recreate it in my spare time, just for a bit of fun:
If anyone is interested in my solution to get this working, then feel free to keep reading for the nerdy stuff, else you can just enjoy the conciseness of this post.
How it works:
Generating the Jumps:
So in Minecraft, every single block in a world has associated coordinates, x y and z - you know the ones. If you think of a jump in parkour as just the distance between two blocks, we can calculate this very easily by just finding the difference in the coordinates. This is what is called a relative block mapping and this is what I used to generate each jump.
For example, a 1 block jump will be a coordinate increase of 2 in either the x or z-direction, so their relative coordinates are 2 in either the x or z.
So, now that we know we can get blocks relative to another one, we can just store a relative block mapping to generate that jump.
I built a bunch of parkour jumps, and placed signs with all of their relative block mappings from the starting block -> the target block.
So after testing all these jumps, I stored all their relative mappings in the config.yml file:
This way, you can easily add/remove/edit any jumps. The one with multiple mappings stores multiple blocks, in this case, a neo jump.
So now, all we need to do is convert these strings (a line of text) to an integer (a number). The reason we have to do this is that in programming, it doesn't recognize "1" as 1. You cannot perform calculations with text, so we have to attempt to parse (convert) them from one to the other.
It's quite simple to do this, we just loop through every value in the list, and convert each mapping to an integer, and store them in an int[] (a list of integers, called an array). For multiple blocks, we just create (now, bear with me!) a multi-dimensional-array (an array inside an array), so it can store every mapping for every block.
And tada, we now have the ability to generate a parkour jump! All that's left to do is create a method for randomly selecting one of these mappings:
Realistically, we should only use one instance of ThreadLocalRandom for speed and safety, but for the sakes of this quick botched plugin, it doesn't really matter.
Detecting the player's movements:
There is a starting pressure plate block which teleports the player and begins their parkour challenge. This is surprisingly very easy to recreate.
In Spigot's API, there are a huge number of events that are triggered when different things happen. We can hook into these events and modify the behaviour, such as teleporting the player once they step on a pressure plate.
For this task, we have to use what's called the PlayerInteractEvent, and this is fired whenever the player interacts with anything - an inventory, an entity, when they click, you get the idea.
We don't want every pressure plate to be able to start the parkour, so we store their specific location, and check for that location instead - blocks don't tend to move on their own, so it's much more reliable:
We don't want players to constantly run into each other while doing the parkour, so we have to space them out. I do this by teleporting them a multiple of 15 blocks away, depending on how many players are currently doing the parkour. Because we have jumps going in all directions, the player stays in roughly the same position, so I decided that 15 blocks distance was a reasonable amount.
Once the player is doing the pakour, we need to store some data associated with them, like the block they're currently on, the block they're supposed to jump to, any other blocks, their points etc.
To do this, I created a custom data class containing all this data to easily be able to edit everything inside them:
blockFrom is the block they started at, blockTo is the block they need to jump to, otherBlocks is a list of any other blocks, points is how many jumps they've made and block is the the type of block, like MELON_BLOCK, LAPIS_BLOCK, etc.
All we need to do now is detect when they land on the correct block and spawn the next one, or if they fall, clear everything. The easiest way to do this is use the PlayerMoveEvent, which is fired every time a players location is changed (including yaw and pitch!).
We can simply get the players location, and the block for their location - and, as we've already established, if we have a block we can get another block relative to it, therefore, getting the block underneath the player is very easy.
We can check if the location of the block underneath the player is the same location as the block they are meant to be jumping to, and if it is, we can spawn another one (and add some fancy effects too, such as simple sound and flame particles):
So now that we have detected if the player has landed on the correct block, the question is this:
> How can we accurately detect if the player has missed the block?
There are multiple ways to do this, but the way I decided to do it is check if the players y-level is 2 blocks below the target blocks y-level. This means they've fallen and we can remove their data. I simply checked if the players y-level + 2 is below the target blocks y-level:
This just sets all the blocks back to air, and clears any data we are currently holding with the player.
Conclusion:
So this essentially concludes this devlog thing, I haven't included all aspects of the code - I've just focused on the main ideas and mechanics.
I really hope I explained how this works in a way that is friendly to understand, but if you got lost, I don't blame you - when I was starting out I wouldn't have a clue what any word of this means.
If anyone is interested, the full code is on GitHub: https://github.com/ihellsmc/SpawnPK
Happy scrolling, and have a fantastic day!
Brandon