Is it possible to detect if a player is within a mob's line of sight? And if so, can that line of sight be changed to only see things in 1 axis? For example, only being able to see things in front of it, but not if it's 1 or more blocks away from it.

  • 2
    Hi anomanous. It is extremely difficult but possible. I once tried to create an aimbot combining this mechanic and failed to do so. What I tried is to teleport the player facing the nearest mob and use a predicate looking_at to determine if the player is looking at an entity or not. If there are obstacles in between, tag the nearest mob because it cannot be seen. This way on the next tick we find the nearest mob without that tag so on and so on until we find the nearest mob without a tag. However, this method has many flaws and bugs so it is merely a concept.
    – hfanatic
    Jan 9 at 2:04
  • 2
    Moreover, the predicate looking_at does not apply to mobs. So you might have to teleport the mobs facing you, then use raycasting to see if there are blocks between the mob and you. If there are blocks, simply stop raycasting forward. If the raycast is able to detect you it means that the mob will probably see you. You can mess around with raycasting to change the mobs sight distance. I can provide you with a detailed answer if you ask for it.
    – hfanatic
    Jan 9 at 2:08
  • 1
    Hello, I would very much like any answer for this question , no matter how difficult.
    – anomanous
    Jan 9 at 2:22
  • you can use radius eg.(@e[r=....]) but it breaks the things you wanted and it works even through blocks
    – AidanGamin
    Jan 13 at 5:27
  • You can use ^ ^ ^ it can phase through blocks though.
    – AidanGamin
    Jan 13 at 5:28

sorry for the late answer but I have found the ultimate trivial method to do what you want. To start off, it involves passenger entities and raycasting. The code is really short but you will still need a datapack for the raycasting function.

The only downside to this method is that the subject entities that can detect your presence must be unique and summoned manually.

First, spawn a mob with an armor stand riding it using the following command. summon zombie ~ ~1 ~ {Passengers:[{id:"minecraft:armor_stand",Invisible:1b,Invulnerable:1b,Tags:["probe"]}]}

In this case a zombie with an invisible armor stand tagged "probe" is spawned.

Now you want to have this mcfunction in your datapack.

execute run particle flame 
execute if entity @p[distance=0..0.99] run say hit!
execute if block ~ ~ ~ #permeable positioned ^ ^ ^0.2 run function namespace:raycast

It is really short and efficient and the particle command is of no practical use other than displaying to you the ray so you can delete it later. Next up, the command checks for the nearest player within a 1 block radius. Note that the detection range is set to 0.99 so that there is a minimum risk of detecting though blocks. Last command dictates that if the block it is currently in is not classified as permeable, it does not repeat itself (stops raycasting).

Now what you have to do is simple --- execeute as @e[tag=probe] at @s run function namespace:raycast. Watch as the armor stand detects you within its line of sight and say hit!. The armor stand does not detect you if there are blocks in between.

A few Tweaks you can bring to the command You might want to consider entities obstacles as well. That is, if you are hiding behind mobs, the armor stand could not detect you. If that is the case, replace the function command in the .mcfunction with execute if block ~ ~ ~ #permeable unless entity @e[type=#exclude,distance=0..0.99,limit=1,sort=nearest] positioned ^ ^ ^0.2 run function namespace:raycast

As you have mentioned in the question, you would like the mob to have a maximum detection range. I would take it as 10 blocks for example.

The frequency of raycasting in the function is 5 times/ block, which means that if the function runs 50 times, a maximum total of 10 blocks have been covered within 1 tick. You can set up a dummy scoreboard. scoreboard objectives add count dummy. Insert this into the middle of your function scoreboard players add @s count 1. Replace the run function command with this execute as @s[scores={count=..50}] if block ~ ~ ~ #permeable positioned ^ ^ ^0.2 run function namespace:raycast And at the end of the function you would insert this line of command. execute as @s[scores={count=51..}] run scoreboard players set @s count 0 This way you have limited the range of raycasting. Just for you to double check, the code in raycast.mcfunction should look something like this now.

execute run particle flame 
scoreboard players add @s count 1
execute if entity @p[distance=0..0.99] run say hit!
execute as @s[scores={count=0..50}] if block ~ ~ ~ #permeable positioned ^ ^ ^0.2 run function namespace:raycast
execute as @s[scores={count=51..}] run scoreboard players set @s count 0

How to integrate Probe with the mob it rides on Until now although the probe rides the zombie, they are still literally two different entities. To eliminate this discrepancy we use a selector @e[type=zombie,limit=1,sort=nearest] to figure out the closest zombie in relation to the probe armor stand, then execute a function as that zombie.

It should look like this now.

execute run particle flame 
scoreboard players add @s count 1
execute if entity @p[distance=0..0.99] run execute as @e[type=zombie,sort=nearest,limit=1] run say I see you lmao
execute as @s[scores={count=0..50}] if block ~ ~ ~ #permeable positioned ^ ^ ^0.2 run function namespace:raycast
execute as @s[scores={count=51..}] run scoreboard players set @s count 0

Replace the "I see you lmao" with a function of your own choice.

zombie seeing me

Killing the Probe In your tick function, execute as @e[tag=probe] at @s unless entity @e[type=zombie,distance=0..2,limit=1,sort=nearest] run kill @s

All the above code has been verified by myself and all works. There are other variations you can play with the function but I surely won't list out all of them here. Your question is certainly a great one as it is mutually beneficial. I could use this method for my own project as well. Hope that works for you as well.

Have a good one.

Edit: the #permeable group is a predefined block type tag in the datapack.

  • For some reason the code works and all, but only if I do it manually for some reason. I put all the code in and it should be working, but it is not, does it need to be in a specific line of folders, does it need a specific name, or does it need a specific version?
    – anomanous
    Jan 13 at 22:01
  • If you look carefully the entire code is based on a probe entity mounted on its host. The reason is that if I rotate the zombie itself facing the player, it won't move at all.
    – hfanatic
    Jan 13 at 23:08
  • Did you define the #permeable block type? I had put the json file content down there. If you want to save yourself from the hassle you can replace the #permeable simply with "air". But I do warn you that it might not work underground.
    – hfanatic
    Jan 13 at 23:11
  • Also did you create objective "count"? It should be a dummy
    – hfanatic
    Jan 13 at 23:13
  • As said above, only zombies spawned with the specific summon command would obey the datapack.
    – hfanatic
    Jan 13 at 23:16

I just commented something about using ^^^ and I almost forgot armour stand exists. what you can do with this is you can make the armour stand into a ray and use it for ray casting just like one of the comments said.

you can make it go forward for a few times using tp

execute at @e[type=minecraft:zombie, tag=...] if @e[r=10, type=minecraft:armour_stand, tag=...] run tp @e[type=minecraft:armour_stand, tag=...] ^ ^ ^1

then while its doing that make it check if its inside a block then make it go back to its starting point if it is.

execute as @e[type=minecraft:zombie, tag=...] at @e[type=minecraft:armour_stand, tag=...] if block ~ ~ ~ minecraft:air run tp @e[type=minecraft:armour_stand, tag=...] @s

then check if the ray is near/within the player then you can now run what ever you like if the mob is looking at you.

execute as @e[type=minecraft:zombie, tag=...] at @e[type=minecraft:armour_stand, tag=...] if entity ~ ~ ~ @a
    execute as @e[type=minecraft:zombie, tag=...] at @a unless entity ~ ~ ~ @e[r=1, type=minecraft:zombie, tag=...]

  • I reckon that education edition or bedrock edition commands.
    – hfanatic
    Jan 13 at 7:29
  • Teleportation can be really inconsistent and laggy, especially when there are many armor stands. Armor stands are difficult to render for the game and adding the invisibility tag to them brings no improvement at all.
    – hfanatic
    Jan 13 at 7:30
  • Besides, if you have ever tried in-game, teleporting entities to your position is always delayed, rendering your method pretty unreliable and inconsistent
    – hfanatic
    Jan 13 at 7:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.