Skip to content

Commit 8f704f0

Browse files
authored
Merge pull request #80 from active-logic/Misc
Sim time and logging err fix
2 parents 1bf7daf + 8fa791a commit 8f704f0

31 files changed

+100
-89
lines changed

Doc/QuickStart.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,18 @@
55

66
Be welcome! Here is a hands-on introduction to Active Logic. Let's get started.
77

8-
This introduction is engine agnostic; if you are using Unity, read the [Unity Quick Start Guide](QuickStart-Unity.md).
8+
This introduction is engine agnostic. Unity users may prefer the [Unity Quick Start Guide](QuickStart-Unity.md).
9+
10+
## Setting the time
11+
12+
Before evaluating a behaviour tree, set the time:
13+
14+
```
15+
// Set at game frame start or before invoking your ticker
16+
SimTime.time = System.DateTime.Now.TotalMilliseconds/1000f;
17+
```
18+
19+
Active Logic uses [simulated time](Reference/SimTime.md) to evaluate certain decorators, such as intervals and cooldowns.
920

1021
## Status expressions and the update loop
1122

Doc/Reference/Constants-and-logging.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,23 @@ loop.cont()
4343
impending.done() // will not compile since 'impending' never succeeds
4444
```
4545

46+
## Using `undef()`
47+
48+
If you defer implementing a status function, use `undef`:
49+
50+
```cs
51+
status Defend() => undef();
52+
```
53+
54+
Release and optimized builds do not support `undef`; this ensures your product is feature-complete before shipping.
55+
56+
By default `undef` returns the failing status; this may be customized:
57+
58+
```cs
59+
status Defend() => undef(cont); // with Active.Raw
60+
status Defend() => undef(cont()); // with Active.Status
61+
```
62+
4663
## Expression wrappers
4764

4865
Via `Active.Raw` or `Active.Status`, use a wrapper to include any expression within a status expression, then return an arbitrary status constant; here is an example:

Doc/Reference/SimTime.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
*Sources: SimTime.cs - Last Updated: 2021.07.18*
2+
3+
# SimTime Reference
4+
5+
In order for time-reliant decorators (cooldown, delay, interval, timeout, wait and perhaps others) to work as expected, the time should be correctly set.
6+
7+
- In a video game, usually you want game time; this (ordinarily) is different from real time.
8+
- When evaluating a simulation, set the time at the beginning of each iteration.
9+
- For some applications, real time may be just what you need.
10+
11+
## Setting the time
12+
13+
Depending on the intended use case, there's a couple of approaches to setting the time:
14+
15+
1- If all the agents/tickers in your game use the same time, consider setting `SimTime.time` at the beginning of each iteration (or game/physics frame)
16+
17+
2- In less common cases, different agents may each use their own time. For example, in a turn based game, 'tactical time' (round count) may be used to evaluate some agents while other parts of your game may use real time for animation.
18+
19+
**Sim time is not thread safe** - you may use sim time in a multi-threaded environment, provided all agents use the same time, and all threads complete work within the current iteration.
20+
21+
Note: in *Unity*, time defaults to `UnityEngine.Time.time`; you may change this on a stepper basis (see [Steppers](Unity/Steppers.md))
22+
23+
## Fields & Properties
24+
25+
`time` - get/set the current time.

README.md

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -19,25 +19,23 @@ Active Logic seamlessly integrates with C#:
1919
```cs
2020
class Duelist : UTask{
2121

22-
float health = 100;
23-
24-
Transform threat => null;
22+
float health = 100;
23+
Transform threat;
2524

2625
// BT selectors and sequences via || and &&
27-
override public status Step() => Attack() || Defend() || Retreat();
26+
override public status Step()
27+
=> Attack()
28+
|| Defend()
29+
|| Retreat();
2830

2931
// Conditionals without 'conditional nodes'
30-
status Attack() => threat && health > 25
31-
? Engage(threat) && Cooldown(1.0f)?[ Strike(threat) ]
32-
: fail(log && $"No threat, or low hp ({health})");
33-
34-
// Special statuses (pending, impending, action, ...) are useful
35-
// when you know a task will never fail, never succeed or similar.
36-
// (optional but type safe!)
37-
pending Defend() => + undef();
38-
status Engage(Transform threat) => undef();
39-
impending Retreat() => - undef();
40-
action Strike(Transform threat) => @void();
32+
status Attack() => (threat && health > 25) ?
33+
Engage(threat) && Cooldown(1.0f)?[ Strike(threat) ]
34+
: fail(log && $"No threat, or low hp ({health})");
35+
36+
status Defend() => ...;
37+
38+
// ...
4139
4240
}
4341
```

Src/Decorators/Cooldown.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,9 @@ public Gate? this[float s]
3030

3131
}
3232

33-
#if !AL_BEST_PERF
3433
partial class Task{
3534
public Conditional.Gate? Cooldown(float duration, [Tag] int key = -1)
3635
=> store.Decorator<Cooldown>(key, Active.Core.Cooldown.id)[duration];
3736
}
38-
#endif
3937

4038
}

Src/Decorators/Delay.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,10 @@ public Gate? this[float duration]{ get{
3737

3838
}
3939

40-
#if !AL_BEST_PERF
4140
partial class Task{
4241
public Waiter.Gate? After(float delay, [Tag] int key = -1)
4342
=> store.Decorator<Delay>(key, Active.Core.Delay.id)[delay];
4443
}
45-
#endif
4644

4745
} // Active.Core
4846

Src/Decorators/Drive.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,6 @@ public StatusRef this[status s]{ get{
6767

6868
}
6969

70-
#if !AL_BEST_PERF
7170
partial class Task{
7271
public Self.Gate? While(status @in, [Tag] int key = -1)
7372
=> store.Decorator<Self>(key, Self.id)[@in, crit: false];
@@ -78,6 +77,5 @@ partial class Task{
7877
public Self.Gate? Tie(bool @in, [Tag] int key = -1)
7978
=> store.Decorator<Self>(key, Self.id)[@in, crit: true];
8079
}
81-
#endif
8280

8381
}

Src/Decorators/FrameDelay.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,11 @@ public Gate? this[int duration]{ get{
3737

3838
}
3939

40-
#if !AL_BEST_PERF
4140
partial class Task{
4241
public Waiter.Gate? AfterFrames(int frames, [Tag] int key = -1)
4342
=> store.Decorator<FrameDelay>(key,
4443
Active.Core.FrameDelay.id)[frames];
4544
}
46-
#endif
4745

4846
} // Active.Core
4947

Src/Decorators/InOut.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,9 @@ public class InOut : Conditional{
2323

2424
}
2525

26-
#if !AL_BEST_PERF
2726
partial class Task{
2827
public Conditional.Gate? InOut(bool @in, bool @out, [Tag] int key = -1)
2928
=> store.Decorator<InOut>(key, Active.Core.InOut.id)[@in, @out];
3029
}
31-
#endif
3230

3331
}

Src/Decorators/Init.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,9 @@ public readonly struct Gate{
5656

5757
}
5858

59-
#if !AL_BEST_PERF
6059
partial class Task{
6160
public Init With([Tag] int key = -1)
6261
=> store.Decorator<Init>(key, Active.Core.Init.id).pass;
6362
}
64-
#endif
6563

6664
} // end-Active.Core

0 commit comments

Comments
 (0)