|
1 | 1 | --[[
|
2 |
| - ECS Lua v2.1.2 |
| 2 | + ECS Lua v2.2.0 |
3 | 3 |
|
4 | 4 | ECS Lua is a fast and easy to use ECS (Entity Component System) engine for game development.
|
5 | 5 |
|
|
818 | 818 | __F__["ECS"] = function()
|
819 | 819 | -- src/ECS.lua
|
820 | 820 | --[[
|
821 |
| - ECS Lua v2.1.2 |
| 821 | + ECS Lua v2.2.0 |
822 | 822 |
|
823 | 823 | ECS Lua is a fast and easy to use ECS (Entity Component System) engine for game development.
|
824 | 824 |
|
@@ -1008,7 +1008,7 @@ __F__["Entity"] = function()
|
1008 | 1008 | data[cType] = nil
|
1009 | 1009 | archetypeNew = archetypeNew:Without(cType)
|
1010 | 1010 |
|
1011 |
| - elseif value.isComponent then |
| 1011 | + elseif (type(value) == "table" and value.isComponent) then |
1012 | 1012 | local old = data[cType]
|
1013 | 1013 | if (old ~= value) then
|
1014 | 1014 | if old then
|
@@ -1138,6 +1138,22 @@ __F__["Entity"] = function()
|
1138 | 1138 | return components
|
1139 | 1139 | end
|
1140 | 1140 |
|
| 1141 | + --[[ |
| 1142 | + 01) comp = entity:GetAny(PrimaryClass) |
| 1143 | + ]] |
| 1144 | + local function getAny(entity, qualifier) |
| 1145 | + if (qualifier ~= nil and qualifier.IsCType and not qualifier.isComponent) then |
| 1146 | + local data = entity._data |
| 1147 | + local ctypes = qualifier.Qualifiers() |
| 1148 | + for _,cType in ipairs(ctypes) do |
| 1149 | + local component = data[cType] |
| 1150 | + if component then |
| 1151 | + return component |
| 1152 | + end |
| 1153 | + end |
| 1154 | + end |
| 1155 | + end |
| 1156 | + |
1141 | 1157 | local Entity = {
|
1142 | 1158 | __index = function(e, key)
|
1143 | 1159 | if (type(key) == "table") then
|
@@ -1190,6 +1206,7 @@ __F__["Entity"] = function()
|
1190 | 1206 | Set = setComponent,
|
1191 | 1207 | Unset = unsetComponent,
|
1192 | 1208 | GetAll = getAll,
|
| 1209 | + GetAny = getAny, |
1193 | 1210 | }, Entity)
|
1194 | 1211 | end
|
1195 | 1212 |
|
@@ -2731,32 +2748,79 @@ __F__["Timer"] = function()
|
2731 | 2748 | -- if execution is slow, perform a maximum of 4 simultaneous updates in order to keep the fixrate
|
2732 | 2749 | local MAX_SKIP_FRAMES = 4
|
2733 | 2750 |
|
2734 |
| - local Time = {} |
2735 |
| - Time.__index = Time |
| 2751 | + local function loop(Time) |
| 2752 | + |
| 2753 | + local accumulator = 0.0 |
| 2754 | + local lastStepTime = 0.0 |
| 2755 | + |
| 2756 | + return function (newTime, stepName, beforeUpdateFn, updateFn) |
| 2757 | + local dtFixed = Time.DeltaFixed |
| 2758 | + local stepTime = newTime - lastStepTime |
| 2759 | + if stepTime > 0.25 then |
| 2760 | + stepTime = 0.25 |
| 2761 | + end |
| 2762 | + lastStepTime = newTime |
| 2763 | + |
| 2764 | + Time.Now = newTime |
| 2765 | + |
| 2766 | + -- 1000/30/1000 = 0.03333333333333333 |
| 2767 | + accumulator = accumulator + stepTime |
| 2768 | + |
| 2769 | + --[[ |
| 2770 | + Adjusting the framerate, the world must run on the same frequency, |
| 2771 | + this ensures determinism in the execution of the scripts |
| 2772 | + |
| 2773 | + Each system in "transform" step is executed at a predetermined frequency (in Hz). |
| 2774 | + |
| 2775 | + Ex. If the game is running on the client at 30FPS but a system needs to be run at |
| 2776 | + 120Hz or 240Hz, this logic will ensure that this frequency is reached |
| 2777 | + |
| 2778 | + @see https://gafferongames.com/post/fix_your_timestep/ |
| 2779 | + @see https://gameprogrammingpatterns.com/game-loop.html |
| 2780 | + @see https://bell0bytes.eu/the-game-loop/ |
| 2781 | + ]] |
| 2782 | + if stepName == "process" then |
| 2783 | + if accumulator >= dtFixed then |
| 2784 | + Time.Interpolation = 1 |
| 2785 | + |
| 2786 | + beforeUpdateFn(Time) |
| 2787 | + local nLoops = 0 |
| 2788 | + while (accumulator >= dtFixed and nLoops < MAX_SKIP_FRAMES) do |
| 2789 | + updateFn(Time) |
| 2790 | + nLoops = nLoops + 1 |
| 2791 | + Time.Process = Time.Process + dtFixed |
| 2792 | + accumulator = accumulator - dtFixed |
| 2793 | + end |
| 2794 | + end |
| 2795 | + else |
| 2796 | + Time.Interpolation = math.min(math.max(accumulator/dtFixed, 0), 1) |
| 2797 | + beforeUpdateFn(Time) |
| 2798 | + updateFn(Time) |
| 2799 | + end |
| 2800 | + end |
| 2801 | + end |
2736 | 2802 |
|
2737 | 2803 | local Timer = {}
|
2738 | 2804 | Timer.__index = Timer
|
2739 | 2805 |
|
2740 | 2806 | function Timer.New(frequency)
|
| 2807 | + local Time = { |
| 2808 | + Now = 0, |
| 2809 | + -- The time at the beginning of this frame. The world receives the current time at the beginning |
| 2810 | + -- of each frame, with the value increasing per frame. |
| 2811 | + Frame = 0, |
| 2812 | + Process = 0, -- The time the latest process step has started. |
| 2813 | + Delta = 0, -- The completion time in seconds since the last frame. |
| 2814 | + DeltaFixed = 0, |
| 2815 | + -- INTERPOLATION: The proportion of time since the previous transform relative to processDeltaTime |
| 2816 | + Interpolation = 0 |
| 2817 | + } |
| 2818 | + |
2741 | 2819 | local timer = setmetatable({
|
2742 | 2820 | -- Public, visible by systems
|
2743 |
| - Time = setmetatable({ |
2744 |
| - Now = 0, |
2745 |
| - NowReal = 0, |
2746 |
| - -- The time at the beginning of this frame. The world receives the current time at the beginning |
2747 |
| - -- of each frame, with the value increasing per frame. |
2748 |
| - Frame = 0, |
2749 |
| - FrameReal = 0, -- The REAL time at the beginning of this frame. |
2750 |
| - Process = 0, -- The time the latest process step has started. |
2751 |
| - Delta = 0, -- The completion time in seconds since the last frame. |
2752 |
| - DeltaFixed = 0, |
2753 |
| - -- INTERPOLATION: The proportion of time since the previous transform relative to processDeltaTime |
2754 |
| - Interpolation = 0 |
2755 |
| - }, Time), |
| 2821 | + Time = Time, |
2756 | 2822 | Frequency = 0,
|
2757 |
| - LastFrame = 0, |
2758 |
| - ProcessOld = 0, |
2759 |
| - FirstUpdate = 0, |
| 2823 | + _update = loop(Time) |
2760 | 2824 | }, Timer)
|
2761 | 2825 |
|
2762 | 2826 | timer:SetFrequency(frequency)
|
@@ -2791,87 +2855,7 @@ __F__["Timer"] = function()
|
2791 | 2855 | end
|
2792 | 2856 |
|
2793 | 2857 | function Timer:Update(now, step, beforeUpdate, update)
|
2794 |
| - if (self.FirstUpdate == 0) then |
2795 |
| - self.FirstUpdate = now |
2796 |
| - end |
2797 |
| - |
2798 |
| - -- corrects for internal time |
2799 |
| - local nowReal = now |
2800 |
| - now = now - self.FirstUpdate |
2801 |
| - |
2802 |
| - local Time = self.Time |
2803 |
| - |
2804 |
| - Time.Now = now |
2805 |
| - Time.NowReal = nowReal |
2806 |
| - |
2807 |
| - if step == "process" then |
2808 |
| - local processOldTmp = Time.Process |
2809 |
| - |
2810 |
| - -- first step, initialize current frame time |
2811 |
| - Time.Frame = now |
2812 |
| - Time.FrameReal = nowReal |
2813 |
| - |
2814 |
| - if self.LastFrame == 0 then |
2815 |
| - self.LastFrame = Time.Frame |
2816 |
| - end |
2817 |
| - |
2818 |
| - if Time.Process == 0 then |
2819 |
| - Time.Process = Time.Frame |
2820 |
| - self.ProcessOld = Time.Frame |
2821 |
| - end |
2822 |
| - |
2823 |
| - Time.Delta = Time.Frame - self.LastFrame |
2824 |
| - Time.Interpolation = 1 |
2825 |
| - |
2826 |
| - --[[ |
2827 |
| - Adjusting the framerate, the world must run on the same frequency, |
2828 |
| - this ensures determinism in the execution of the scripts |
2829 |
| - |
2830 |
| - Each system in "transform" step is executed at a predetermined frequency (in Hz). |
2831 |
| - |
2832 |
| - Ex. If the game is running on the client at 30FPS but a system needs to be run at |
2833 |
| - 120Hz or 240Hz, this logic will ensure that this frequency is reached |
2834 |
| - |
2835 |
| - @see https://gafferongames.com/post/fix_your_timestep/ |
2836 |
| - @see https://gameprogrammingpatterns.com/game-loop.html |
2837 |
| - @see https://bell0bytes.eu/the-game-loop/ |
2838 |
| - ]] |
2839 |
| - local nLoops = 0 |
2840 |
| - local updated = false |
2841 |
| - |
2842 |
| - beforeUpdate(Time) |
2843 |
| - |
2844 |
| - -- Fixed time is updated in regular intervals (equal to DeltaFixed) until time property is reached. |
2845 |
| - while (Time.Process <= Time.Frame and nLoops < MAX_SKIP_FRAMES) do |
2846 |
| - |
2847 |
| - updated = true |
2848 |
| - |
2849 |
| - update(Time) |
2850 |
| - |
2851 |
| - nLoops = nLoops + 1 |
2852 |
| - Time.Process = Time.Process + Time.DeltaFixed |
2853 |
| - end |
2854 |
| - |
2855 |
| - if updated then |
2856 |
| - self.ProcessOld = processOldTmp |
2857 |
| - end |
2858 |
| - else |
2859 |
| - -- executed only once per frame |
2860 |
| - |
2861 |
| - if Time.Process ~= self.ProcessOld then |
2862 |
| - Time.Interpolation = 1 + (now - Time.Process)/Time.Delta |
2863 |
| - else |
2864 |
| - Time.Interpolation = 1 |
2865 |
| - end |
2866 |
| - |
2867 |
| - beforeUpdate(Time) |
2868 |
| - update(Time) |
2869 |
| - |
2870 |
| - if step == "render" then |
2871 |
| - -- last step, save last frame time |
2872 |
| - self.LastFrame = Time.Frame |
2873 |
| - end |
2874 |
| - end |
| 2858 | + self._update(now, step, beforeUpdate, update) |
2875 | 2859 | end
|
2876 | 2860 |
|
2877 | 2861 | return Timer
|
|
0 commit comments