How to detect which face is hit by a projectile

Discussion in 'Plugin Development' started by SuperJenBot, Aug 2, 2015.

Thread Status:
Not open for further replies.
  1. Offline


    So I recently learned how to change a block to another block on projectile impact. For what I'm trying to do I realized that I need the block to also change if it is hit from the one of it's 4 sides, bottom, or top. Currently my code only works for the top of the block. I have researched a lot and have tried many things but I cannot figure out how to detect which side of the block is being hit, and changing the area relative to it's position (for example if the top is hit I will change the location on the y axis to subtract 1 so that the air block above is not changed). My current code:

    public void snowballHit(ProjectileHitEvent e) {
            Block block = e.getEntity().getWorld().getBlockAt(e.getEntity().getLocation().subtract(0.0D, 1, 0.0D));
            if (block.getType() == Material.GRASS) {
    I didn't include everything in there but as you can see, it will subtract 1 from the y axis, save that location, and then change the block occupying that location. How can I change this code so it will detect which side is being hit and make the location changes accordingly?
  2. Offline


    Referring to the image below...
    Ill assume fist uou meaning for the case where a snowball solidly hits the side face of the Redstone block that has its sides exposed and its top covered, to identify the redstone block...

    But in more complex cases such as below, please answer what your intentions are (may or may not be possible):
    If a snowball fell solidly on the center face of the orange block, do you care about the green or purple blocks?
    If the snowball hit in the corner inside, do you need the orange, green and purple?
    If the snowball hit straight-on the green face only, concerned about orange or green?
    If the snowball hits the 'crease' between green and purple, do you need both or just the one that the ball was closest to?

  3. Offline


    I did explain a bit vaguely didn't I. Here is my own illustration to display what currently happens:


    Now in the first frame, this is what happens if I do not have the location set to subtract 1 from the y axis. The wool block will appear on top. Frame 2 is what currently happens with the code I have shown in the original post. If the snowball hits the top of the block, the block it hits will change to wool. My problem is, I would like the block hit to change no matter which side it is hit from. I do not want any other blocks affected, just the one which the snowball hits. Currently it will only change if the top is hit.
  4. Offline


    The projectile ends its life inside of a block-cell space, hitting the top of the grass block means its location is inside of the space around the grass block. In your specific case hitting the top, its above it.
    The projectile ends its life by hitting something 'solid' so that is either going to be the top surface from a downwards tradjectory, or the solid side surfaces.

    You would need to get pretty heavy into some vector math and comparisons in order to figure out if it hit a block face, or a block side. In my diagram, the cube of space that is on top of the orange block can be the final resting spot for the snowball if it falls down on orange, face onto green, or face on to purple. So simply knowing where it ends up isn't enough.

    In the case of a snowball hitting the redstone block, it would be in one of the airspaces with airspaces below. So thats a simple case of looking the block below and seeing it is air, and eliminating it being a top-surface hit. Its obvious you could look at all the north, south, east, west blocks around it, and only one wont be air, and that must be the solid block that stopped the projectile.

    Algorithm sofar: The block will always land in an 'air block' (if it hits a ladder, vine, carpet, etc it actually ends its life in the block beside those as if they were solid blocks as well - you can test this by throwing at those things and always converting where it lands into a diamond block or such...)

    Okay, so always lands in an airblock. So first, check the block below it. if it is air, then the block must have hit a side-face somewhere, and you then check the blocks n, e, s, w of it. If it is solid, might be the top surface. So check the sides n, s, e, w around - if all of them are air, then it was that blocks top.

    Not a bad start to a process, but, you can see there is a flaw.

    The snowball will end its life in the space above the gold block, between purple and blue if its death is caused by the solid below it, or either solid wool beside it. We've only been able to simplify the cases where the gold block stands alone, with no blocks at all that could have otherwise hit it; or, where the purple block stands alone, where the air space has air below and no other solids around it. So... are we done for? No, not quite.

    The nice thing is, the LOCATION of the snowball returns not only the xyz of the impact, but also a pitch and yaw that depend on the snowball movement. If I face direct north in the client, and turn a bit to the west, my client says my yaw is 173... a snowball thrown in that direction, to hit a block on its SOUTH face gives me a snowball yaw of: -173.4
    Facing just off east at a yaw of -86, the snowball yaw is 86 hitting the WEST face of a solid block. Southernly at -10, hitting the north face of a block, the yaw is at 9.6, southernly at 2.5, hitting north face, yaw is -3.

    So the yaw for the snowball is the negative of the yaw the ball was travelling on.

    It should be possible to convert the yaw into the maximum of two blocks in the plane it could hit - n+e, n+w, s+e, s+w
    And the block below. And even thats pushing it, really, you could say 'as long as the angle is between here and there, call that northbound, between there and yar, call that eastbound...' and reduce the job to one block in the plane, and the block below and not be wrong - im only concerned about a fraction of a degree from and angle throw, if the angles dont quite align perfectly to slice it at the exactly NE or NW diagonal line...

    You would now test the block below - if it is air, then there is no way that it landed on the block, and we know it must be a side. If it landed on a solid, well... maybe we hit the top, maybe we hit the side. If you find a solid block based on the yaw next to it, well, we're back to square one again here - which did it hit. So the yaw is only helping us to determine which faces to CHECK for solids that could have been hit - if they are air, then its definitely the block below.

    Air below - must be a side face strike - possible to get from the yaw to convert to needing to getBlockRelative(BlockFace.EAST) for example

    Solid below - might be a top stricke.
    If the yaw-based blocks are air, it was a top strike and its getBlockRelative(BlockFace.DOWN)
    If the yaw-based blocks are solid, then we dont yet know which got hit

    (instead of relative faces, you can always refer to the other blocks with y-1 , x-1, x+1, z-1 or z+1 coordinate block recoveries

    The problem case is the L shape entry, where it hits a face above a solid...

    There has to be a way to isolate that better, though its not really different from the "examine the two possible blocks N+E or N+W etc" if both of them come back solid -- either go with a definition that you'll tag both blocks to replace... or that you'll always pick the bottom.. or that you'll always pick a face if a face is present, perferd to the top..
  5. Offline


  6. Offline


    Unfortunately, that forum link doesn't help fully. Changing the so-called hit block in many cases when hitting a flat face on a cliff results in no change, but the block deeper in the wall is changed...

    But I think it might be possible using the velocity vector as well slightly differently..

    This is now a challange itching part of my brain

    I spent a bit more time on this this evening, and it is kind of discouraging to me.. I also tried to do the same tests with arrows, since they remain after hittng and clearly show how they hit something, etc.

    I made a test method that simply replaces the location of the projectile hit with a block (diamond ore, emerald ore, something unique) - simple as that - get location , change block material. no computations of any sort Then went about throwing snowballs or arrows at a variety of things, trying to hit particular faces of blocks nearby or far straight on, from above, from the angle, etc.. The idea was to highlight the landing-box reported, and if everything worked right, it would put the block adjacent to the face i was aiming to hit.

    The results were quite shocking - the replaced block often was on a full diagonal, not orthagonal to the faces, when thrown with a fair bit of angle throw, but more often, it was also diagonal in all three axes. In many cases, even a clean throw at a block almost straight on sometimes resulted in the block appearing 2 blocks away and 1 up from the block i was trying to hit, as if hitting an invisible wall in front of the block; on srong angles that was possible, but many cases not.

    To add to weirdness - using the arrows, the effect was identical, despite the arrow being at rest two blocks further ahead of the location it reported.

    Seeing how i could not successfully 'place blocks where i was aiming for them to be' it would seem that trying to determine which face of that space was the block i hit would still be a challange since is not actually correctly reporting its landing position all the time.

    Please try to replicate this test - only a few lines of code in a projectile-hit event - and see if you get the similar results. It might just be the older bukkit API jar I am using since im doing my tests in 1.7.9 bukkit

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
    Last edited by a moderator: Jun 11, 2016
Thread Status:
Not open for further replies.

Share This Page