For Each and picking

For questions about using Classic.

Post » Mon Jun 11, 2012 5:58 am

I have the following events:


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

http://www.scirra.com/forum/solved-custom-lineofsight-issue_topic43661.html

Here's an image of its code



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.Juryiel2012-06-11 05:59:34
B
11
S
2
G
3
Posts: 283
Reputation: 1,968

Post » Mon Jun 11, 2012 7:26 am

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)
"Construct 4 lets YOU make advanced games! (maybe)" Construct Classic - Examples Kit
B
86
S
28
G
13
Posts: 2,092
Reputation: 15,009

Post » Mon Jun 11, 2012 3:16 pm

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).
B
11
S
2
G
3
Posts: 283
Reputation: 1,968

Post » Tue Jun 12, 2012 2:26 am

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') & ", " )
Image
B
23
S
8
G
10
Posts: 1,820
Reputation: 8,242

Post » Tue Jun 12, 2012 2:52 am

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.
B
11
S
2
G
3
Posts: 283
Reputation: 1,968

Post » Tue Jun 12, 2012 2:55 am

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)
B
11
S
2
G
3
Posts: 283
Reputation: 1,968

Post » Tue Jun 12, 2012 3:14 am

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.
B
11
S
2
G
3
Posts: 283
Reputation: 1,968

Post » Tue Jun 12, 2012 3:17 am

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 :)
B
24
S
9
G
2
Posts: 294
Reputation: 3,160

Post » Tue Jun 12, 2012 3:25 am

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.Juryiel2012-06-12 03:28:56
B
11
S
2
G
3
Posts: 283
Reputation: 1,968

Post » Tue Jun 12, 2012 3:51 am

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. Juryiel2012-06-12 05:31:38
B
11
S
2
G
3
Posts: 283
Reputation: 1,968

Next

Return to Help & Support using Construct Classic

Who is online

Users browsing this forum: No registered users and 5 guests