Doongogar Posted May 17 Share Posted May 17 Esse código cria uma imagem virada para camera do client quando o player tem certo elementdata, porém quando eu vou para muito longe a imagem fica grande demais, e perto fica bom, teria um jeito de deixar esse discrepância menos perceptível sem alterar muito o tamanho da imagem? function desenharp() for _, player in ipairs(getElementsByType("player")) do if isElement(player) then if getElementData(player, "imortalp") == true then local alpha = getElementAlpha(player) local px, py, pz = getElementPosition(player) local camX, camY, camZ = getCameraMatrix() local dist = getDistanceBetweenPoints3D(camX, camY, camZ, px, py, pz) local notModifiedDist = dist if notModifiedDist < options.distance then local headPosX, headPosY, headPosZ = getPedBonePosition(player, 4) if headPosX and headPosY and headPosZ then local screenX, screenY = getScreenFromWorldPosition(headPosX, headPosY, headPosZ, 25, false) if screenX then local width, height = (47 * 3) * 1, (47 * 3) * 1 local iconX, iconY = math.floor(screenX - width / 2), math.floor(screenY - 80 - height / 2) dxDrawImage(iconX + 20, iconY + 120, width - 95, height - 95, "Patro.png", 0, 0, 0, tocolor(255, 255, 0, alpha)) end end end end end end end addEventHandler("onClientRender", root, desenharp) E caso o código apresente mais erros ou possíveis erros, porfavor sintam-se a vontade para aponta-los para quer eu possa corrigir. Link to comment
Other Languages Moderators Lord Henry Posted May 20 Other Languages Moderators Share Posted May 20 (edited) Utilize DxDrawMaterialLine3D (3D) em vez de DxDrawImage (2D). On 17/05/2024 at 20:29, Doongogar said: E caso o código apresente mais erros ou possíveis erros, porfavor sintam-se a vontade para aponta-los para quer eu possa corrigir. Não precisa usar ipairs quando a ordem dos elementos não importa. Utilize pairs que é levemente mais rápido. for _, player in pairs(getElementsByType("player")) do Se sua elementData só pode ter valores true ou false, não precisa verificar se ela é == true. Neste caso, só isso já serve: if getElementData(player, "imortalp") then -- Se for qualquer valor, passa na condição. Se for false, não passa. Edited May 20 by Lord Henry Link to comment
Doongogar Posted May 20 Author Share Posted May 20 3 hours ago, Lord Henry said: Utilize DxDrawMaterialLine3D (3D) em vez de DxDrawImage (2D). Não precisa usar ipairs quando a ordem dos elementos não importa. Utilize pairs que é levemente mais rápido. for _, player in pairs(getElementsByType("player")) do Se sua elementData só pode ter valores true ou false, não precisa verificar se ela é == true. Neste caso, só isso já serve: if getElementData(player, "imortalp") then -- Se for qualquer valor, passa na condição. Se for false, não passa. Eu dei uma verificada na função DxDrawMaterialLine3D e tentei fazer por meio deste, porém quando a tela do client se move, a imagem rotaciona junto com a tela do client proporcionando um posicionamento estranho da imagem em alguns angulos e também quando o player se move a imagem fica meio tremula meio que como se ela não atualizasse bem todo frame, e está reduzindo bastante o FPS também local screenWidth, screenHeight = guiGetScreenSize() local options = { scaleMultiplier = (screenWidth + 1920) / (1920 * 2), distance = 20, aimdistance = 0, } options.aimdistance = options.distance - options.distance * 0.15 function desenhar() for _, player in pairs(getElementsByType("player")) do if isElement(player) then if getElementData(player, "imortal") then local alpha = getElementAlpha(player) local px, py, pz = getElementPosition(player) local camX, camY, camZ = getCameraMatrix() local dist = getDistanceBetweenPoints3D(camX, camY, camZ, px, py, pz) local notModifiedDist = dist if notModifiedDist < options.distance then local headPosX, headPosY, headPosZ = getPedBonePosition(player, 4) if headPosX and headPosY and headPosZ then local height = - 0.3 local width = 0.3 local halfHeight = height / 2 local texture = dxCreateTexture("Logo.png") if texture then local bottomX, bottomY, bottomZ = headPosX, headPosY, headPosZ - halfHeight local topX, topY, topZ = headPosX, headPosY, headPosZ + halfHeight dxDrawMaterialLine3D(bottomX, bottomY, bottomZ, topX, topY, topZ, texture, width, tocolor(255, 255, 255, alpha)) end end end end end end end addEventHandler("onClientRender", root, desenhar) ali na altura eu deixei negativo pois a imagem estava sendo gerada de cabeça pra baixo, não sei o porque também... Link to comment
Other Languages Moderators Lord Henry Posted May 21 Other Languages Moderators Share Posted May 21 (edited) Pra melhorar um pouco o FPS, deixe o dxCreateTexture fora da função, numa variável local. E ali no getElementsByType, faça assim pra pegar só os jogadores que estão sendo sincronizados pelo localPlayer. Não faz sentido pegar player que está muito longe. getElementsByType("player", root, true) Sobre o ângulo estranho, como a imagem sempre ficará voltada para a câmera, então é melhor voltar ao 2D mesmo. Uma coisa que você pode usar para calcular melhor a escala do dxDrawImage, é pegar 3 posições X,Y,Z ao redor da cabeça do jogador, onde começa e termina a imagem. Mas essas posições levam em consideração a rotação da câmera, sendo assim, não adianta simplesmente somar ou subtrair os valores, pois fazendo isso, as posições ficarão relativas ao cenário fixo. Para isso, você precisa criar um objeto qualquer invisível e sem colisão na cabeça do jogador (no osso). Depois disso você deve rotacionar esse objeto para sempre ficar apontado para a câmera utilizando a função útil findRotation3D. (o objeto não pode ser anexado no jogador, ele apenas tem sua posição setada na cabeça dele a cada frame.) Só depois de você ter um objeto invisível e sem colisão na cabeça do jogador sempre apontado para a câmera, utilize getElementMatrix para obter as posições do lado e em cima desse objeto, essas posições você usará no getScreenFromWorldPosition para desenhar o dxDrawImage final. Como eu faria: local texture = dxCreateTexture("Logo.png") -- Cria a textura. local objetos = {} -- Tabela onde os objetos invisíveis vão ficar. local options = { distance = 100, escala = 1, } addEventHandler("onClientRender", root, function() for _, player in pairs(getElementsByType("player", root, true)) do -- Para cada jogador sendo sincronizado por este cliente, faça: if isElement(player) then -- Se o jogador existe, então: (evita erros quando o player desconecta neste frame) if getElementData(player, "imortalp") then -- Se essa elementData não for false, então: local alpha = getElementAlpha(player) local px, py, pz = getElementPosition(player) local camX, camY, camZ = getCameraMatrix() local dist = getDistanceBetweenPoints3D(camX, camY, camZ, px, py, pz) if dist < options.distance then -- Se a distância da câmera para o jogador for menor que o limite, então: local headPosX, headPosY, headPosZ = getPedBonePosition(player, 4) -- Obtém a posição do osso da cabeça do jogador. if headPosX then -- Se obteve uma das posições (significa que obteve as outras também), então: if not isElement(objetos[player]) then -- Se ainda não existe o objeto invisível na cabeça desse jogador, então: objetos[player] = createObject (3003, headPosX, headPosY, headPosZ, 0, 0, 0, true) -- Cria um objeto sem colisão associado ao jogador. setElementAlpha(objetos[player], 0) -- Deixa o objeto invisível. else -- Se já existe o objeto, apenas mantém ele na cabeça do jogador a cada frame. setElementPosition(objetos[player], headPosX, headPosY, headPosZ) end local rx, ry, rz = findRotation3D(headPosX, headPosY, headPosZ, camX, camY, camZ) -- Encontra a rotação relativa do objeto com a câmera. setElementRotation(objetos[player], rx, ry, rz) -- Aponta o objeto para a câmera. local rightX, rightY, rightZ = getPositionFromElementOffset(objetos[player], options.escala / 2, 0, 0) -- Obtém a posição XYZ na direita da cabeça do jogador. local leftX, leftY, leftZ = getPositionFromElementOffset(objetos[player], (options.escala / 2) * -1, 0, 0) -- Obtém a posição XYZ na esquerda da cabeça do jogador. local screenX1, screenY1 = getScreenFromWorldPosition(rightX, rightY, rightZ) local screenX2 = getScreenFromWorldPosition(leftX, leftY, leftZ) local _, screenY3 = getScreenFromWorldPosition(headPosX, headPosY, headPosZ + options.escala) -- Apenas para testes -- dxDrawText("1", screenX1 or 0, screenY1 or 0) -- dxDrawText("2", screenX2 or 0, screenY1 or 0) -- dxDrawText("3", screenX2 or 0, screenY3 or 0) if screenX1 and screenX2 and screenY3 then local width, height = screenX2 - screenX1, screenY1 - screenY3 -- Calcula os tamanhos subtraindo as posições da tela. dxDrawImage(screenX1, screenY3, width, height, texture, 0, 0, 0, tocolor(255, 255, 0, alpha)) -- A imagem precisa ser quadrada, preferencialmente múltipla de 2. (16x16, 32x32, 64x64, 128x128, etc) end end elseif isElement(objetos[player]) then -- Se o jogador não está perto o suficiente e tem o objeto invisível em sua cabeça, então: destroyElement(objetos[player]) -- Destrói o objeto. objetos[player] = nil -- Limpa a variável dele para liberar espaço na memória. end end end end end) addEventHandler("onClientElementStreamOut", root, function() -- Ativa esse evento quando um elemento para de ser sincronizado por este client. if getElementType(source) == "player" then -- Se foi um jogador, então: if isElement(objetos[source]) then -- Se existe o objeto invisível daquele jogador, então: destroyElement(objetos[source]) -- Destrói o objeto. objetos[source] = nil -- Limpa a variável dele para liberar espaço na memória. end end end) -- Funções úteis. function findRotation3D(x1, y1, z1, x2, y2, z2) local rotx = math.atan2 (z2 - z1, getDistanceBetweenPoints2D (x2, y2, x1, y1)) rotx = math.deg(rotx) local rotz = -math.deg(math.atan2(x2 - x1, y2 - y1)) rotz = rotz < 0 and rotz + 360 or rotz return rotx, 0, rotz end function getPositionFromElementOffset(element,offX,offY,offZ) local m = getElementMatrix(element) local x = offX * m[1][1] + offY * m[2][1] + offZ * m[3][1] + m[4][1] local y = offX * m[1][2] + offY * m[2][2] + offZ * m[3][2] + m[4][2] local z = offX * m[1][3] + offY * m[2][3] + offZ * m[3][3] + m[4][3] return x, y, z end Edited May 21 by Lord Henry Link to comment
Doongogar Posted June 3 Author Share Posted June 3 On 21/05/2024 at 15:07, Lord Henry said: Pra melhorar um pouco o FPS, deixe o dxCreateTexture fora da função, numa variável local. E ali no getElementsByType, faça assim pra pegar só os jogadores que estão sendo sincronizados pelo localPlayer. Não faz sentido pegar player que está muito longe. getElementsByType("player", root, true) Sobre o ângulo estranho, como a imagem sempre ficará voltada para a câmera, então é melhor voltar ao 2D mesmo. Uma coisa que você pode usar para calcular melhor a escala do dxDrawImage, é pegar 3 posições X,Y,Z ao redor da cabeça do jogador, onde começa e termina a imagem. Mas essas posições levam em consideração a rotação da câmera, sendo assim, não adianta simplesmente somar ou subtrair os valores, pois fazendo isso, as posições ficarão relativas ao cenário fixo. Para isso, você precisa criar um objeto qualquer invisível e sem colisão na cabeça do jogador (no osso). Depois disso você deve rotacionar esse objeto para sempre ficar apontado para a câmera utilizando a função útil findRotation3D. (o objeto não pode ser anexado no jogador, ele apenas tem sua posição setada na cabeça dele a cada frame.) Só depois de você ter um objeto invisível e sem colisão na cabeça do jogador sempre apontado para a câmera, utilize getElementMatrix para obter as posições do lado e em cima desse objeto, essas posições você usará no getScreenFromWorldPosition para desenhar o dxDrawImage final. Como eu faria: local texture = dxCreateTexture("Logo.png") -- Cria a textura. local objetos = {} -- Tabela onde os objetos invisíveis vão ficar. local options = { distance = 100, escala = 1, } addEventHandler("onClientRender", root, function() for _, player in pairs(getElementsByType("player", root, true)) do -- Para cada jogador sendo sincronizado por este cliente, faça: if isElement(player) then -- Se o jogador existe, então: (evita erros quando o player desconecta neste frame) if getElementData(player, "imortalp") then -- Se essa elementData não for false, então: local alpha = getElementAlpha(player) local px, py, pz = getElementPosition(player) local camX, camY, camZ = getCameraMatrix() local dist = getDistanceBetweenPoints3D(camX, camY, camZ, px, py, pz) if dist < options.distance then -- Se a distância da câmera para o jogador for menor que o limite, então: local headPosX, headPosY, headPosZ = getPedBonePosition(player, 4) -- Obtém a posição do osso da cabeça do jogador. if headPosX then -- Se obteve uma das posições (significa que obteve as outras também), então: if not isElement(objetos[player]) then -- Se ainda não existe o objeto invisível na cabeça desse jogador, então: objetos[player] = createObject (3003, headPosX, headPosY, headPosZ, 0, 0, 0, true) -- Cria um objeto sem colisão associado ao jogador. setElementAlpha(objetos[player], 0) -- Deixa o objeto invisível. else -- Se já existe o objeto, apenas mantém ele na cabeça do jogador a cada frame. setElementPosition(objetos[player], headPosX, headPosY, headPosZ) end local rx, ry, rz = findRotation3D(headPosX, headPosY, headPosZ, camX, camY, camZ) -- Encontra a rotação relativa do objeto com a câmera. setElementRotation(objetos[player], rx, ry, rz) -- Aponta o objeto para a câmera. local rightX, rightY, rightZ = getPositionFromElementOffset(objetos[player], options.escala / 2, 0, 0) -- Obtém a posição XYZ na direita da cabeça do jogador. local leftX, leftY, leftZ = getPositionFromElementOffset(objetos[player], (options.escala / 2) * -1, 0, 0) -- Obtém a posição XYZ na esquerda da cabeça do jogador. local screenX1, screenY1 = getScreenFromWorldPosition(rightX, rightY, rightZ) local screenX2 = getScreenFromWorldPosition(leftX, leftY, leftZ) local _, screenY3 = getScreenFromWorldPosition(headPosX, headPosY, headPosZ + options.escala) -- Apenas para testes -- dxDrawText("1", screenX1 or 0, screenY1 or 0) -- dxDrawText("2", screenX2 or 0, screenY1 or 0) -- dxDrawText("3", screenX2 or 0, screenY3 or 0) if screenX1 and screenX2 and screenY3 then local width, height = screenX2 - screenX1, screenY1 - screenY3 -- Calcula os tamanhos subtraindo as posições da tela. dxDrawImage(screenX1, screenY3, width, height, texture, 0, 0, 0, tocolor(255, 255, 0, alpha)) -- A imagem precisa ser quadrada, preferencialmente múltipla de 2. (16x16, 32x32, 64x64, 128x128, etc) end end elseif isElement(objetos[player]) then -- Se o jogador não está perto o suficiente e tem o objeto invisível em sua cabeça, então: destroyElement(objetos[player]) -- Destrói o objeto. objetos[player] = nil -- Limpa a variável dele para liberar espaço na memória. end end end end end) addEventHandler("onClientElementStreamOut", root, function() -- Ativa esse evento quando um elemento para de ser sincronizado por este client. if getElementType(source) == "player" then -- Se foi um jogador, então: if isElement(objetos[source]) then -- Se existe o objeto invisível daquele jogador, então: destroyElement(objetos[source]) -- Destrói o objeto. objetos[source] = nil -- Limpa a variável dele para liberar espaço na memória. end end end) -- Funções úteis. function findRotation3D(x1, y1, z1, x2, y2, z2) local rotx = math.atan2 (z2 - z1, getDistanceBetweenPoints2D (x2, y2, x1, y1)) rotx = math.deg(rotx) local rotz = -math.deg(math.atan2(x2 - x1, y2 - y1)) rotz = rotz < 0 and rotz + 360 or rotz return rotx, 0, rotz end function getPositionFromElementOffset(element,offX,offY,offZ) local m = getElementMatrix(element) local x = offX * m[1][1] + offY * m[2][1] + offZ * m[3][1] + m[4][1] local y = offX * m[1][2] + offY * m[2][2] + offZ * m[3][2] + m[4][2] local z = offX * m[1][3] + offY * m[2][3] + offZ * m[3][3] + m[4][3] return x, y, z end Dessa forma o client está conseguindo ver que a imagem e 2D se visualizar de baixo para cima ou de cima para baixo, e quando o player se movimenta a imagem aparentemente não segue o player em tempo real pois ela fica dando umas mini travadas, além de consumir muito FPS. Não teria como manter o meio pelo qual a imagem está sendo criada somente usando algum calculo para diminuir a imagem com relação na distancia de visão do client? Quando um player se distancia demais além de a imagem ficar grande demais ela "sai de perto do player" atingindo um distanciamento considerável do player que está com a imagem Link to comment
Other Languages Moderators Lord Henry Posted June 3 Other Languages Moderators Share Posted June 3 Hum, não consigo pensar numa forma diferente de fazer. 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