A function that works only after it has been removed
1 replies, posted
Hi, I have a rather strange problem, I try to add the effect of falling snow to my scoreboard, but something strange happens.
This is the script for snow animation (located in autorun / client):
local NEGPI2 = math.pi * -2
local snowmaxstartheight = -1.5
local snowflakeminsize = 0.1
local segmentslowerbound,segmentsupperbound = 6,9
local radiuslowerbound,radiusupperbound = 2,5
local snowflakefallspeed = 80
local snowflakeshrinkspeed = 1
local Segments = {}
local function GenerateSegments(seg)
Segments[seg] = {}
for i = 1, seg do
local a = (i / seg) * NEGPI2
Segments[seg][i] = {math.sin( a ),math.cos( a )}
end
return Segments[seg]
end
function draw.Circle( x, y, radius, seg )
local cir = {}
local segments = Segments[seg] or GenerateSegments(seg)
for i = 1,seg do
cir[i] = {x = x + segments[i][1] * radius, y = y + segments[i][2] * radius}
end
surface.DrawPoly( cir )
end
function DrawSnow(pnl, amt)
pnl.snowtbl = {}
for i = 1,amt do
pnl.snowtbl[i] = {math.random(pnl:GetTall() * snowmaxstartheight, 0),math.random(pnl:GetWide()),math.random(radiuslowerbound,radiusupperbound),math.random(segmentslowerbound,segmentsupperbound)}
end
local snowtbl = pnl.snowtbl
surface.SetDrawColor(230, 230, 250, 200)
draw.NoTexture()
for i = 1, amt do
if (snowtbl[i][1] >= pnl:GetTall()) then
snowtbl[i][3] = Lerp(snowflakeshrinkspeed * FrameTime(), snowtbl[i][3], 0)
if (snowtbl[i][3] <= snowflakeminsize) then
snowtbl[i][1] = math.random(pnl:GetTall() * snowmaxstartheight,0)
snowtbl[i][2] = math.random(pnl:GetWide())
snowtbl[i][3] = math.random(radiuslowerbound,radiusupperbound)
snowtbl[i][4] = math.random(segmentslowerbound,segmentsupperbound)
end
else
snowtbl[i][1] = math.Approach(snowtbl[i][1], pnl:GetTall(), snowflakefallspeed * FrameTime())
end
draw.Circle( snowtbl[i][2], snowtbl[i][1], snowtbl[i][3], snowtbl[i][4] )
end
end
In sb_main, in "function PANEL:Paint()" I have this:
DrawSnow(self, 50)
And here the problem arises - when everything is done as I have presented, the snow blocks on the upper edge and does not fall down, only after removing this part everything works as it should:
pnl.snowtbl = {}
for i = 1,amt do
pnl.snowtbl[i] = {math.random(pnl:GetTall() * snowmaxstartheight, 0),math.random(pnl:GetWide()),math.random(radiuslowerbound,radiusupperbound),math.random(segmentslowerbound,segmentsupperbound)}
end
However, after rebooting the server without providing some of the functions, the script does not work at all, so that it works, I have to do the following:
- Use the entire script that I gave at the beginning,
- delete the given part of the function when the server is on.
However, just change the map, and again nothing works, someone knows what can be done with it?
Based on about 15 minutes of cocking around on my own, after years of getting out of this game. I think I know what's going on.
As you're calling DrawSnow in the PANEL:Paint hook, every single frame your table of snowflakes is being recreated, meaning they never have a chance to travel, as a frame is just took damn fast. Instead what you should really be doing is creating that table of snowflakes within the PANEL:Init hook. This way the 50, 150, 5000+ snowflakes you want to make float down are created once, and their positions are persisted between frames correctly.
I was only able to get it working myself after creating a new Panel type that derived DPanel, there's probably better ways of going about that, but like I said, I've been out of the game far too long. I ended up with some along the lines of this;
function scoreboard:init(amt)
local SNOWPANEL = {}
function SNOWPANEL:Init()
self.snowtbl = {}
for i = 1,amt do
self.snowtbl[i] = {math.random(self:GetTall() * snowmaxstartheight, 0),math.random(self:GetWide()),math.random(radiuslowerbound,radiusupperbound),math.random(segmentslowerbound,segmentsupperbound)}
end
end
vgui.Register( "SnowPanel", SNOWPANEL, "DPanel" )
local panel = vgui.Create( "SnowPanel" )
-- Standard panel construction
function panel:Paint()
scoreboard:DrawSnow(self)
end
scoreboard.panel = panel
end
function scoreboard:show()
if (!scoreboard.panel) then
scoreboard:init(50)
end
scoreboard.panel:Show()
function scoreboard:hide()
scoreboard.panel:Hide()
end
end
The definition of DrawSnow no longer needs the "amt" parameter as you can just grab the length of the snowtbl easily enough;
function scoreboard:DrawSnow(pnl)
local snowtbl = pnl.snowtbl or {}
surface.SetDrawColor(230, 230, 250, 200)
draw.NoTexture()
for i = 1, #snowtbl do
-- Everything else
end
After seeing the flakes buzzing around like madmen and you mentioning it goes away when you remove the creation loop, that was a big giveaway that it was just some kind of table data being replaced every frame.
Be cautious about doing complex work or assignments within hooks such as Paint, they're called every single frame, and if you're not careful can annihilate performance.
Sorry, you need to Log In to post a reply to this thread.