Other Languages Moderators Lord Henry Posted September 23, 2017 Other Languages Moderators Share Posted September 23, 2017 (edited) Galera, fiz esse script para resolver um problema solicitado por um usuário aqui do fórum. O objetivo é fazer com que os jogadores e veículos que estiverem dentro de uma zona de colisão fiquem no "modo ghost" (sem colisão) para que os veículos e jogadores que estiverem dentro da zona não colidam entre si e voltem ao normal quando saírem da zona. O esquema é simples de se fazer usando setElementCollidableWith e onClientColShapeHit. O problema é que os veículos criados dentro da zona não eram afetados, pois ainda não existiam quando o jogador entrou na zona, sendo necessário o jogador sair da zona e entrar de novo nela para que este novo veículo fosse afetado também. Para contornar esse problema fiz tudo usando onClientRender, porém não sei se essa é a melhor maneira, levando em conta que consome maior processamento e existem muitos verificadores dentro dele. O script ficou assim: (client-side) Spoiler ghostZone = createColSphere (2490, -1668, 12.5, 25) -- Cria uma esfera de colisão na Grove Street. allVehicles = {} -- Cria uma variável vazia do tipo tabela. allPlayers = {} theVehicle = {} function infiniteGhost () -- Executa isso a cada frame. if isElementWithinColShape (localPlayer, ghostZone) then -- Se o jogador local estiver na zona, então: theVehicle[localPlayer] = getPedOccupiedVehicle (localPlayer) -- O veículo em que o jogador está. (será nulo se o jogador estiver a pé.) allVehicles[localPlayer] = getElementsWithinColShape (ghostZone, "vehicle") -- Todos os elementos do tipo 'vehicle' que estão dentro da zona. allPlayers[localPlayer] = getElementsWithinColShape (ghostZone, "player") -- Todos os elementos do tipo 'player' que estão dentro da zona. if allVehicles[localPlayer][1] then -- Se existir algum elemento do tipo 'vehicle' dentro da zona, então: for i,vehicle in ipairs (allVehicles[localPlayer]) do -- Para cada veículo dentro da zona, faça isso: setElementCollidableWith (vehicle, localPlayer, false) -- Faz aquele veículo não colidir com o jogador local. end if theVehicle[localPlayer] then -- Se o jogador local está em um veículo, então: for i,vehicle in ipairs (allVehicles[localPlayer]) do -- Para cada veículo dentro da zona, faça isso: setElementCollidableWith (vehicle, theVehicle[localPlayer], false) -- Faz aquele veículo não colidir com o veículo que o jogador local está. end end end if allPlayers[localPlayer][1] then -- Se existir algum elemento do tipo 'player' dentro da zona, então: for i,player in ipairs (allPlayers[localPlayer]) do -- Para cada jogador dentro da zona, faça isso: setElementCollidableWith (player, localPlayer, false) -- Faz aquele jogador não colidir com o jogador local. end if theVehicle[localPlayer] then -- Se o jogador local está em um veículo, então: for i,player in ipairs (allPlayers[localPlayer]) do -- Para cada veículo dentro da zona, faça isso: setElementCollidableWith (player, theVehicle[localPlayer], false) -- Faz aquele jogador não colidir com o veículo que o jogador local está. end end end else -- Se o jogador local não estiver na zona, faz a mesma coisa só que deixa ele colidir com os veículos e jogadores novamente. theVehicle[localPlayer] = getPedOccupiedVehicle (localPlayer) allVehicles[localPlayer] = getElementsWithinColShape (ghostZone, "vehicle") allPlayers[localPlayer] = getElementsWithinColShape (ghostZone, "player") if allVehicles[localPlayer][1] then for i,vehicle in ipairs (allVehicles[localPlayer]) do setElementCollidableWith (vehicle, localPlayer, true) end if theVehicle[localPlayer] then for i,vehicle in ipairs (allVehicles[localPlayer]) do setElementCollidableWith (vehicle, theVehicle[localPlayer], true) end end end if allPlayers[localPlayer][1] then for i,player in ipairs (allPlayers[localPlayer]) do setElementCollidableWith (player, localPlayer, true) end if theVehicle[localPlayer] then for i,player in ipairs (allPlayers[localPlayer]) do setElementCollidableWith (player, theVehicle[localPlayer], true) end end end if theVehicle[localPlayer] then setElementCollidableWith (localPlayer, theVehicle[localPlayer], true) end removeEventHandler ("onClientRender", getRootElement(), infiniteGhost) -- Para de ficar executando isso a cada frame. end end function ghostmode_on (hitElement, matchingDimension) if hitElement == localPlayer then addEventHandler ("onClientRender", getRootElement(), infiniteGhost) -- Começa a executar aquela função a cada frame. end end addEventHandler( "onClientColShapeHit", ghostZone, ghostmode_on) Alguém tem alguma ideia de fazer esse script "mais leve"? Ou esse jeito é o único possível para evitar o problema? Edited September 23, 2017 by Lord Henry Link to comment
DNL291 Posted September 24, 2017 Share Posted September 24, 2017 (edited) Você poderia fazer assim, 1º passo: ter o controle de todos elementos dentro da colshape. Adicione na tabela os elementos que colidirem e remova quando sair da colshape (onClientColShapeHit/Leave). Aí vem aquele porém que você citou, e a solução é com "onClientRender". Acho que a melhor alternativa é usar getElementsWithinColShape mas ao mesmo tempo não seria muito bom pra performance dar loop na tabela a cada frame - só que é a única solução, o quão negativo deve ser, isso eu não sei porque depende do volume de jogadores/veículos no servidor e requer um teste pra saber mais precisamente se vale a pena. Talvez também tenham outras formas lidar com os outros veículos criados, por exemplo, um evento que é chamado quando cria um veículo por meio de um painel. Não entendi muito bem o uso dessas tabela no código, fora isso, vejo algumas coisas que precisam de otimização. Você está usando setElementCollidableWith mesmo quando não há necessidade, te recomendo usar uma verificação antes: if isElementCollidableWith( theElement, withElement ) then setElementCollidableWith( theElement, withElement, bool ) end O que você tá fazendo é quase o mesmo que isto: addEventHandler( "onClientRender", root, function() setElementCollidableWith( localPlayer, elem, false ) end ) Outro conselho também, sempre use variáveis locais sempre que puder. Também, muitos dizem que usar pairs é pouca coisa mais rápido pra executar do que ipairs (deve ser uma diferença realmente baixa). Edited September 24, 2017 by DNL291 Link to comment
Other Languages Moderators Lord Henry Posted September 24, 2017 Author Other Languages Moderators Share Posted September 24, 2017 5 hours ago, DNL291 said: te recomendo usar uma verificação antes: if isElementCollidableWith( theElement, withElement ) then setElementCollidableWith( theElement, withElement, bool ) end Vou colocar isso. No caso das tabelas ali é pq eu pretendo depois usar com mais de uma zona ao mesmo tempo, dai os elementos de uma serão diferentes de outra. Link to comment
raynner Posted September 29, 2017 Share Posted September 29, 2017 eu acho que usar "onClientRender" nesta função não é correto há outras formas de fazer isso e que não exigem tanto ^^ porém os proprios eventos do colShape e utilize isElementInColShape para reavaliar os valores para os velhos e novos players ^^ Link to comment
Other Languages Moderators Lord Henry Posted September 30, 2017 Author Other Languages Moderators Share Posted September 30, 2017 16 hours ago, raynner said: eu acho que usar "onClientRender" nesta função não é correto há outras formas de fazer isso e que não exigem tanto ^^ porém os proprios eventos do colShape e utilize isElementInColShape para reavaliar os valores para os velhos e novos players ^^ Como eu detectaria um elemento que acabou de ser criado dentro da zona se os elementos criados dentro de uma zona de colisão só são detectados após uma nova verificação? Link to comment
raynner Posted September 30, 2017 Share Posted September 30, 2017 (edited) Just now, Lord Henry said: Como eu detectaria um elemento que acabou de ser criado dentro da zona se os elementos criados dentro de uma zona de colisão só são detectados após uma nova verificação? Bom este é o grande problema do nosso amado MTA ele não tem um evento para "onVehicleSpawn" correto o que temos deveria se chamar "onVehicleRespawn" pois ele apenas é desencadeado quando um veículo e respawnado e não temos um "onVehicleSpawn" verdadeiro porém você pode usar um setTimer para verificar que será menos prejudicial ao invés de utilizar "onClientRender". Bom mais é apenas uma sugestão você pode sim utilizar Render porém não acho correto tendo em mente que ele exige um pouco do processador. Edited September 30, 2017 by raynner Link to comment
Other Languages Moderators Lord Henry Posted September 30, 2017 Author Other Languages Moderators Share Posted September 30, 2017 (edited) 4 hours ago, raynner said: Bom este é o grande problema do nosso amado MTA ele não tem um evento para "onVehicleSpawn" correto o que temos deveria se chamar "onVehicleRespawn" pois ele apenas é desencadeado quando um veículo e respawnado e não temos um "onVehicleSpawn" verdadeiro porém você pode usar um setTimer para verificar que será menos prejudicial ao invés de utilizar "onClientRender". Bom mais é apenas uma sugestão você pode sim utilizar Render porém não acho correto tendo em mente que ele exige um pouco do processador. Pensei em usar timer, só que como a verificação deve acontecer em curtíssimo período de tempo, não achei que valeria a pena. Até porque cada jogador dentro da zona criaria seu próprio timer. Por isso que eu cancelo o "onClientRender" do jogador quando ele sai da zona, para que ele pare de consumir esse processamento por frame. E sim, realmente um "onVehicleSpawn" seria perfeito para essa ocasião, dai não precisaria de nenhum timer nem render. Edited September 30, 2017 by Lord Henry Link to comment
Banex Posted October 3, 2017 Share Posted October 3, 2017 O próprio evento onClientColShapeHit já é acionado quando um elemento é criado dentro de sua área. Certamente, o motivo do veículo não ser afetado, é que possui algo errado em seu código. Link to comment
Other Languages Moderators Lord Henry Posted October 3, 2017 Author Other Languages Moderators Share Posted October 3, 2017 12 hours ago, Banex said: O próprio evento onClientColShapeHit já é acionado quando um elemento é criado dentro de sua área. Certamente, o motivo do veículo não ser afetado, é que possui algo errado em seu código. Não funciona para veículos criados no jogador. Por exemplo os veículos do painel Admin. Link to comment
Other Languages Moderators Lord Henry Posted October 3, 2017 Author Other Languages Moderators Share Posted October 3, 2017 Então fiz assim, usando também o "onClientVehicleEnter": ghostZone = createColSphere (2490, -1668, 12.5, 25) -- Cria uma esfera de colisão no CJ. allVehicles = {} allPlayers = {} theVehicle = {} function ghostChecker (theElement, matchingDimension) theVehicle[localPlayer] = getPedOccupiedVehicle (localPlayer) -- O veículo em que o jogador está. (será nulo se o jogador estiver a pé.) allVehicles[localPlayer] = getElementsWithinColShape (ghostZone, "vehicle") -- Todos os elementos do tipo 'vehicle' que estão dentro da zona. allPlayers[localPlayer] = getElementsWithinColShape (ghostZone, "player") -- Todos os elementos do tipo 'player' que estão dentro da zona. if isElementWithinColShape (localPlayer, ghostZone) then outputChatBox ("O novo objeto não está colidindo em você.") -- Use só pra testes. if allVehicles[localPlayer][1] then -- Se existir algum elemento do tipo 'vehicle' dentro da zona, então: for i,vehicle in ipairs (allVehicles[localPlayer]) do -- Para cada veículo dentro da zona, faça isso: setElementCollidableWith (vehicle, localPlayer, false) -- Faz aquele veículo não colidir com o jogador local. end if theVehicle[localPlayer] then -- Se o jogador local está em um veículo, então: for i,vehicle in ipairs (allVehicles[localPlayer]) do -- Para cada veículo dentro da zona, faça isso: setElementCollidableWith (vehicle, theVehicle[localPlayer], false) -- Faz aquele veículo não colidir com o veículo que o jogador local está. end end end if allPlayers[localPlayer][1] then -- Se existir algum elemento do tipo 'player' dentro da zona, então: for i,player in ipairs (allPlayers[localPlayer]) do -- Para cada jogador dentro da zona, faça isso: setElementCollidableWith (player, localPlayer, false) -- Faz aquele jogador não colidir com o jogador local. end if theVehicle[localPlayer] then -- Se o jogador local está em um veículo, então: for i,player in ipairs (allPlayers[localPlayer]) do -- Para cada veículo dentro da zona, faça isso: setElementCollidableWith (player, theVehicle[localPlayer], false) -- Faz aquele jogador não colidir com o veículo que o jogador local está. end end end else outputChatBox ("O novo objeto está colidindo em você.") -- Use só pra testes. if allVehicles[localPlayer][1] then for i,vehicle in ipairs (allVehicles[localPlayer]) do setElementCollidableWith (vehicle, localPlayer, true) end if theVehicle[localPlayer] then for i,vehicle in ipairs (allVehicles[localPlayer]) do setElementCollidableWith (vehicle, theVehicle[localPlayer], true) end end end if allPlayers[localPlayer][1] then for i,player in ipairs (allPlayers[localPlayer]) do setElementCollidableWith (player, localPlayer, true) end if theVehicle[localPlayer] then for i,player in ipairs (allPlayers[localPlayer]) do setElementCollidableWith (player, theVehicle[localPlayer], true) end end end if theVehicle[localPlayer] then setElementCollidableWith (localPlayer, theVehicle[localPlayer], true) end end end addEventHandler ("onClientColShapeHit", ghostZone, ghostChecker) addEventHandler ("onClientColShapeLeave", ghostZone, ghostChecker) addEventHandler ("onClientVehicleEnter", getRootElement(), function (thePlayer, seat) -- Para casos de veículos criados no jogador. outputChatBox ("Entrou em algum veículo.") -- Use só para testes. ghostChecker () -- Executa aquela função acima. end) Parece funcionar, mas precisa testar com mais de um jogador ao mesmo tempo. Link to comment
Banex Posted October 3, 2017 Share Posted October 3, 2017 Não é necessário usar tabelas, mesmo se você quiser usar esse sistema em várias áreas Tente isso, deve funcionar bem. function onClientColShapeHit(theElement, matchingDimension) if (matchingDimension) then for _,element in ipairs(getElementsWithinColShape(source,"player")) do setElementCollidableWith(element, theElement, false) end for _,element in ipairs(getElementsWithinColShape(source,"vehicle")) do setElementCollidableWith(element, theElement, false) end end end addEventHandler("onClientColShapeHit", resourceRoot, onClientColShapeHit) function onClientColShapeLeave(theElement, matchingDimension) if (matchingDimension) then for _,element in ipairs(getElementsWithinColShape(source),"player") do setElementCollidableWith(element, theElement, true) end for _,element in ipairs(getElementsWithinColShape(source),"vehicle") do setElementCollidableWith(element, theElement, true) end end end addEventHandler("onClientColShapeLeave", resourceRoot, onClientColShapeLeave) Link to comment
Other Languages Moderators Lord Henry Posted October 3, 2017 Author Other Languages Moderators Share Posted October 3, 2017 Já me ocorreu diversas vezes de eu criar uma variável local client-side, e ela ser compartilhada com todos os clientes, quando na verdade era pra ser única ao jogador local. Por isso prefiro usar tabela para obrigar a ocorrer separadamente. Link to comment
DNL291 Posted October 4, 2017 Share Posted October 4, 2017 (edited) Eu fiz um teste com uma Colshape no servidor e realmente o "onClientColShapeHit" também é acionado quando cria o elemento (o veículo, no caso) dentro dele. Nesse caso, é só usar os eventos onClientColShapeHit/Leave que deve funcionar; e ao mesmo tempo vai ser bem melhor em questão de performance. A propósito, o código do @Banex têm resourceRoot nos eventos, isso quer dizer que só é chamado para os elementos do próprio resource, então lembre-se de trocar por root. Edited October 4, 2017 by DNL291 Link to comment
Other Languages Moderators Lord Henry Posted October 4, 2017 Author Other Languages Moderators Share Posted October 4, 2017 (edited) 3 hours ago, DNL291 said: Eu fiz um teste com uma Colshape no servidor e realmente o "onClientColShapeHit" também é acionado quando cria o elemento (o veículo, no caso) dentro dele. Nesse caso, é só usar os eventos onClientColShapeHit/Leave que deve funcionar; e ao mesmo tempo vai ser bem melhor em questão de performance. A propósito, o código do @Banex têm resourceRoot nos eventos, isso quer dizer que só é chamado para os elementos do próprio resource, então lembre-se de trocar por root. Sim, também testei e ele detecta. Só não detectou quando criei o veículo pelo painel Admin. Por isso que usei o "onClientVehicleEnter". Mas se trocar por root dai vai ativar em todas as zonas de colisão do servidor, não é? Edited October 4, 2017 by Lord Henry Link to comment
DNL291 Posted October 4, 2017 Share Posted October 4, 2017 (edited) Sim, é resourceRoot, não tinha lembrado que é só pra colshape do script Então, eu testei dando um veículo pelo painel admin; criei o elemento de colisão, adicionei o evento com a saída no chat e funcionou (usei setDevelopmentMode() + showcol pra ver a colshape). Edited October 4, 2017 by DNL291 Link to comment
Other Languages Moderators Lord Henry Posted October 5, 2017 Author Other Languages Moderators Share Posted October 5, 2017 (edited) 4 hours ago, DNL291 said: Sim, é resourceRoot, não tinha lembrado que é só pra colshape do script Então, eu testei dando um veículo pelo painel admin; criei o elemento de colisão, adicionei o evento com a saída no chat e funcionou (usei setDevelopmentMode() + showcol pra ver a colshape). Fiz exatamente a mesma coisa. Usando outputChatBox pra testar. Mas não detectou o veículo criado em mim. Mas detectou quando eu coloquei o "onClientVehicleEnter". Edited October 5, 2017 by Lord Henry Link to comment
DNL291 Posted October 7, 2017 Share Posted October 7, 2017 Você quer dizer quando você cria um veículo e warpa nele usando o admin né? Eu tinha falado do teste que fiz sobre o evento onClientColShapeHit ser chamado quando cria um elemento já dentro dele. Quanto a esse problema de não chamar o evento quando warpa no veículo, acho que não é simples de se resolver, mas você pode fazer um código dentro do "onClientRender" e o evento onClientVehicleEnter com mais alguns outros meios para saber se o jogador entrou no veículo normalmente ou se foi com warp. Ou editar o admin e adicionar um evento pra esta acão. Bem que o MTA já podia ter feito algo pra isso, tipo chamar onClientVehicleEnter quando a função warpPedIntoVehicle é usada. No entanto, pode ser que tenha outro jeito mais simples de detectar isso, pois estou meio por fora do MTA ultimamente. Link to comment
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now