For Each and picking

This forum is currently in read-only mode.
  • I have the following events:

    <img src="https://dl.dropbox.com/u/30864403/constructcode.jpg" border="0" />

    And the LOS function that is called is the one found in the third post by tulamide here:

    scirra.com/forum/solved-custom-lineofsight-issue_topic43661.html

    Here's an image of its code

    <img src="https://dl.dropbox.com/u/30864403/constructcode2.jpg" border="0" />

    The LOS checks if a member of the family NonPlayers has LOS on a member of the family called Players.

    The issue is that if I move a Player with ClassID=2 into LOS of a NonPlayer, it still acts as if I moved the Player with ClassID=1 into LOS (The toggled off Debug Text also reports 1 for ClassID when I turn it on), as if picking isn't working with the For Each. Why is that?

    Thanks for any help, and let me know if you need any more info. Sorry I'm not sure how to post bigger images, but if you copy the image url and paste it in a new tab you should be able to see it better.

  • I've found that using families + the LOS object seems to really glitch things up.

    In my game I made a LOS system from scratch (since it's one-player, I was able to have a sprite for each zombie that was invisble and the width of the zombie. The sprite then stretched all the way to the player and if the zombie was less than X pixels away from the player and its LOS sprite didn't overlap a solid object, it could see the player. I also did some math to make sure that the zombie was facing the general angle of the player)

  • Right, I am also using my own LOS system, as you can see by the function I posted above :) I stole it from the thread I linked above and the basic idea is that I check if player and enemy overlap certain offsets. Those offsets are placed along a cone that defines the LOS.

    The function itself can be quite demanding if you have many enemies checking LOS. As such, I made one change from the function in tulamide's linked post which, although I don't think are relevant to the issue I'm having, I might as well explain so people can see what the code is doing. You have 3 parameters to balance to get LOS working as you want, and those are spatial resolution, temporal resolution, and performance. You can trade performance to increase temporal and spatial resolution (check LOS more frequently or add more points along the cone where you check). The noise parameters in teh function are a way to trade temporal resolution to improve spatial resolution instead of trading performance for it. That is, instead of checking many points at specific locations along the LOS cone, you check a few randomly and uniformly distributed points, and run a few tests so that the cone is covered entirely after X tests. The idea is that you can take yoru time running the tests so that not all points are checked in the same frame, thus not sacrificing performance, but instead sacrificing temporal resolution in order to eventually cover the whole cone. So that's what teh noise parameters are doing, and everything else is explained in the linked tulamide's thread (but again, just check for overlap at offsets arranged in an LOS cone).

  • I'm not quite sure what causes the problem. I admit, the two pictures are not enough for me to find the cause. But the loops itself are very confusing. Maybe there's one of the issues. If I understand it right, you're looping through every 'NonPlayers', which is an action per tick. But as a subevent you're running 'every x milliseconds', which is an action over time (-> several ticks). I doubt this works. You would only get the first (time + 0 milliseconds) loop of it. All other loops are subevents of that 'every x milliseconds' event.

    If you get rid of the 'every x milliseconds'-event, deactivate the super-loop of s and move the 'DebugText'-action up into the 'for each Players'-event, does it show all 'ClassID' then? (You may need to alter to "Set Text to .Text & Players('ClassID') & ", " )

  • Here's the idea of what I"m trying to do (not necessarily what I'm actually doing).

    I only want to check LOS every X milliseconds. I want each individual NonPlayer to have its own check Every X + Random(200) milliseconds so that they don't all happen at the same frame. Temporal resolution is unimportant for these types of LOS checks (the player will not move out of LOS in less than 1 second unless he's teetering on the edge of the cone, and if he is that's fine). On the other hand I plan to have many enemies at once, up to 30-40+ in some instances so I want the checks to be staggered in time and not cause lag. Right now the way it's set up it's not quite doing that, instead it picks a random NonPlayer and does LOS on that NonPlayer. I tried deactivating the Every X event just now and it didn't fix the problem, but it did make the game unplayably laggy. I also tried disabling the superloop and moving the text as you described and yes, it shows all of the Player ClassIDs

    As for the Super loop, that checks to see if a player has already been added to the Hatelist of an enemy. When a NonPlayer sees a Player, that Player is added to the NonPlayer's Hatelist. This is because even if the player tries to move out of LOS, the NonPlayer has already seen him and begins to look for him outside of his LOS range. The thing is, players can build aggro, which is stored in that Super. THere are 6 players, and they can build aggro / hate with their actions, which is then used by the AI to determine its actions. If an enemy has already seen a player, I do not want to reset his aggro levels at every LOS check, so I loop through the Super that stores HateSlots, which are number arrays containing the Player.Value('ClassID') and the Player aggro levels. If a HateSlot with a ClassID matching the current Players.Value('ClassID') is found, then nothing is done since the enemy has already seen that player and now other code runs.

    In short I don't think I can get away with disabling the Super Loop. Also I don't think that it's the problem since that's not really doing anything to picking, it's just storing data that isn't used until another part of the code.

    I could PM you a cap if you woudl like but it is super complicated. Those are the only parts of the code that are relevant to this behavior, I think, but I could be wrong.

  • Just to add, the idea of the loops is:

    I want to have every NonPlayer check LOS with every player. So I thought the straightforward way to do that is to Loop through each NonPlayer and each of them checks every player for LOS. Don't get confused by the Super loop, it's just storing data and checking data structures, but the data it's storing is not yet being used (since it is not hte correct data)

  • Update:

    If I put the text where it says Function.Return Equal 1, it still returns both ClassIDs, (in fact it always returns both, right now I have 2 players, and the order it returns them in is 2,1, which is why I was getting 1 all the time before, since it always came last).

    So it looks like regardless of which player goes into LOS, the LOS function returns 1 for both Players the moment only one of them goes into LOS. Hmmm.

  • First, I didn't read all of the text.

    But I would make a LOS sprite for the enemy and put both in 1 container^^, yes I know, I just like containers...

    And then, if LOS-sprite and player overlaps, enemy:do some action?

    Since they in one container, it picks already the right enemy?

    Maybe I'm totally wrong cuz' I didn't read all of the text, but it was worth a try :)

  • LOS Sprite is not flexible enough for what I want to do. I want to be able to fully control which points are checked for LOS specifically, including Max radius, min radius, max angle, min angle (min angle not implemented yet but will be), and even specific points.

    Also, the NonPlayers are picked correctly. It's the players who are not, so a container of NonPlayers with LOS Sprites wouldn't likely solve this issue.

  • Update again:

    I put NonPlayers overlaps Players check in the LOS function under a "Players: Pick by Players.Value('ClassID') Equal 2"

    When I do that even if the player with ClassID=1 goes into LOS the NonPlayers will 'see' the player with ClassID=2. To me this suggests that the condition: NonPlayers overlaps Players does not respect picking (since I'm picking Player with CLassID=2 specifically right before I call it, yet it still triggers when Player with ClassID=1 goes into LOS)

    Grumble grumble grumble, now what?

    EDIT: Replaced the NonPlayers overlaps Players check with:

    Players overlaps NonPlayers (offset is now Players.X-NonPlayers.X-global('LOS_X'), etc). This seems to work. I expected the Player to be picked correctly but expected the NonPlayers to all agro when only one was in LOS since my guess of what was going on was that the second family in teh overlap comparison ignored picking. So now I'm totally confused.

  • he issue is that if I move a Player with ClassID=2 into LOS of a NonPlayer, it still acts as if I moved the Player with ClassID=1 into LOS (The toggled off Debug Text also reports 1 for ClassID when I turn it on), as if picking isn't working with the For Each. Why is that?

    I have a hunch it might be a bug that hasn't been squashed and comes up from time to time. It has to do with the wrong private variable being set when done from a family.

    Do this test:

    All you need in the layout are the objects in the player family and an event sheet with just this event:

    + System: Always (every tick)

    -> Players: Set 'ClassID' to 1942

    Run in debug mode and see if ClassID is 1942 for the objects. If some other variable is 1942 instead of ClassID then it's that bug.

    Either way pm the cap or post it here and I'll take a look.

  • The class ID seems correct. I didn't do your example, but I in my cap I set the class ID in the properties box and not using the events. Furthermore, I have a variety of functions that use ClassID and they all work correctly, picking the right players and reporting the correct ClassIDs. It sounds to me that you're saying that the bug is a result of setting ClassID at runtime, which I'm not doing. If that's incorrect let me know and I can try your example.

    I will be PMing you a cap shortly. You want to look at the SystemFunctions event sheet, specifically the groups "General Enemy Functions" and "Line of Sight Functions". You will also see a cone of all the spots checked for LOS at runtime. It only comes up randomly every second at a random NonPlayer. You can move individual players by selecting them with a mouse and clicking (RTS behavior). If you use the arrow keys they both move.

    If you move a player into the LOS cone and an LOS check occurs, the enemy should start chasing the player. This might not work correctly since I haven't tested the other parts of the code that deal with enemy actions, so using it for debugging might not be reliable, so that's why I have the DebugText to use instead.

  • Try Construct 3

    Develop games in your browser. Powerful, performant & highly capable.

    Try Now Construct 3 users don't see these ads
  • As an update for anyone else who might be facing the same issue, it does indeed appear to be a bug with how the Overlapping at Offset event picks the second object to compare (it seems to pick all of them).

    R0J0hound provided a fix, where the System Condition "Is overlapping (advanced)" is used. To "rig" the 'offset' part (since that condition doesn't support offsets), the NonPlayer is first moved to each comparison point, then the overlapping comparison is made using the "Is overlapping (advanced)" system condition, and then the NonPlayer is moved back to his position, simulating the "Overlapping at Offset". Since this is all done in the same frame, the moving of the NonPlayer is never drawn on screen.

    Thanks for the help!

Jump to:
Active Users
There are 1 visitors browsing this topic (0 users and 1 guests)