· 4 years ago · Aug 05, 2021, 06:14 PM
1local MapRenderer = {}
2MapRenderer.__index = MapRenderer
3
4--[[ ------------------------------------------------------------------ |
5 Map Renderer : by frriend
6 Created 8/5/2021
7
8 This module handles algorythmic terrain generation.
9
10 API:
11 :Initalize() => Initalize Module.
12 :Generate() => Generates Platforms with Given Dimensions.
13 :CleanUp() => Cleans up everything made by this module.
14
15 :RegisterHit(integer : ID) => Fire :Trigger() within a platform's event module (if applicable).
16--]] ------------------------------------------------------------------ |
17
18--[[ Constnats ]]------------------------------------------------------------------------------------------------------------------------------------------------------------------------
19local BLOCK_TAG = "Render"
20
21local RENDER_SIZE = Vector2.new(100, 500) -- Bounds of the render from the origin point.
22local PLATFORMS_PER_LEVEL = Vector2.new(2, 4) -- (Min/Max) Amount of Playforms per story
23local STORY_Y_HEIGHT = 15 -- Studs between stories
24local PLATFORM_PADDING = 15 -- Studs between playforms on single story
25local CRUMBLE_CHANCE = 3 -- Crumble Platforms spawn every (x) platforms!
26
27--[[ Variables ]]------------------------------------------------------------------------------------------------------------------------------------------------------------------------
28local Platforms = {}
29local PlatformModules = {}
30local EffectBin = {} -- {[id] = EffectObject}
31local InstanceBin = {}
32
33local CrumbleCounter = 0
34local LastID = 0
35
36local WinPlatform = nil
37local BasePlatform = nil
38local BottomLeftPos = nil
39local Origin = nil
40
41local LastRandom;
42
43local PhysicalPlatforms = workspace:WaitForChild("Platforms"):GetChildren()
44
45--[[ Internal Methods ]]------------------------------------------------------------------------------------------------------------------------------------------------------------------------
46function GetRandomPlatformByType(attribute, value) -- Gets a random platform sorted by attribute
47 local canidates = {}
48
49 for _, obj in ipairs(PhysicalPlatforms) do
50 local data = obj:GetAttribute(attribute)
51
52 if data == value then
53 table.insert(canidates, obj)
54 end
55 end
56
57 return canidates[math.random(1, #canidates)]
58end
59
60function drawPlatform(Object, Position)
61 local Platform = Object:Clone()
62 LastID += 1
63
64 Platform.Parent = InstanceBin
65 Platform:MoveTo(Position)
66 Platform.PrimaryPart:SetAttribute(BLOCK_TAG, true)
67
68 -- Creates an ID Attribute that the client can read --
69 Platform:SetAttribute("ID", LastID)
70
71 --[[ @DEPRICATED
72 local ID = Instance.new("IntValue")
73 ID.Parent = Platform
74 ID.Name = "ID"
75 ID.Value = LastID
76 ]]
77
78 table.insert(Platforms, Platform)
79
80 local RequiredModule = Platform:GetAttribute("ON_HIT")
81
82 -- If the object has a ON_HIT module callback --
83 if RequiredModule and RequiredModule ~= "" then
84
85 -- Assert that the object's ON_HIT attribute is properly labeled --
86 assert(PlatformModules[RequiredModule], ("Index not found inside of the table! Was it indexed? (Key : %s)"):format(RequiredModule))
87
88 local EffectObject = PlatformModules[RequiredModule].new(Platform)
89 table.insert(EffectBin, LastID, EffectObject) -- Insert the new Object
90 else
91 table.insert(EffectBin, LastID, nil) -- Insert nothing, because we are not doing anything ON_HIT
92 end
93
94 return Platform
95end
96
97function DrawStory(story)
98 -- Prevents repeating numbers in the randomizer --
99 local NumPlatforms
100 repeat
101 NumPlatforms = math.random(PLATFORMS_PER_LEVEL.X, PLATFORMS_PER_LEVEL.Y)
102 until NumPlatforms ~= LastRandom
103
104 LastRandom = NumPlatforms
105
106 -- Calculations --
107 local renderBottomX = Origin - Vector3.new(RENDER_SIZE.X / 2, 0, 0)
108 local segmentSize = RENDER_SIZE.X / NumPlatforms
109 BottomLeftPos = renderBottomX
110
111 -- Render platforms on current story --
112 for i = 1, NumPlatforms do
113 local relYPos = Origin.Y + STORY_Y_HEIGHT * story
114 local relXPos = (i - 1) * segmentSize + (segmentSize / 2)
115
116 local newVector = renderBottomX + Vector3.new(relXPos, relYPos, 0)
117
118 if (i == 1) or (i == NumPlatforms) then -- if we are on the edge of the map --
119 drawPlatform(GetRandomPlatformByType("SIZE", "LARGE"), newVector)
120 elseif CrumbleCounter >= CRUMBLE_CHANCE then -- Spawn a crumble platform every X platforms --
121 drawPlatform(GetRandomPlatformByType("ON_HIT", "CRUMBLE"), newVector)
122 CrumbleCounter = 0
123 else
124 drawPlatform(GetRandomPlatformByType("SIZE", "SMALL"), newVector)
125 end
126
127 CrumbleCounter += 1
128 end
129end
130
131--[[ API ]]----------------------------------------------------------------------------------------------------------------------------------------------------------------
132function MapRenderer:GetPlatforms()
133 return Platforms
134end
135
136function MapRenderer:Initialize()
137 InstanceBin = Instance.new("Folder")
138 InstanceBin.Parent = workspace
139 InstanceBin.Name = "InstanceBin"
140
141 Origin = self:GetMap().RenderOrigin.Position
142end
143
144function MapRenderer:Render()
145 assert(Origin, "Origin is Undefined; Did you forget to call :Initalize()")
146
147 local NumberOfStories = math.ceil(RENDER_SIZE.Y / STORY_Y_HEIGHT)
148
149 -- Draw (#NumberOfStories) Stories
150 for Story = 1, NumberOfStories do
151 DrawStory(Story)
152 end
153
154 -- Draw Winner Platform --
155 local WinY = (NumberOfStories + 1) * STORY_Y_HEIGHT
156 WinPlatform = drawPlatform(BasePlatform, Origin + Vector3.new(0, WinY, 0))
157
158 BasePlatform = drawPlatform(BasePlatform, Origin)
159 BasePlatform.PrimaryPart.CanCollide = false -- temp
160 BasePlatform:Destroy() -- temp
161end
162
163--[[ Invoked by Client ]]--
164 -- + Implement Serverside Check
165function MapRenderer:RegisterHit(ID)
166 if EffectBin[ID] then
167 EffectBin[ID]:Trigger()
168 end
169end
170
171function MapRenderer:CleanUp()
172 EffectBin = {}
173 InstanceBin:ClearAllChildren();
174end
175
176return MapRenderer