Render a triangle to the screen based on a world coordinate.
It’s not perfect, but it does the job.
It’s not perfect, but it does the job.
Nice idea ![]()
Could be used for any sort of direction indicator, most notably damage indicator or where a grenade has landed etc.
Great job!
hope you dont mind, here is a edited version that always points towards a active waypoint on the map
offscreen.lua (3.3 KB)
That is really cool!
What about the performance?
The performance is not that great, but not terrible, It is 0.06ms when rendering.
I have made a damage indicator with it (and yes the color is red
)
local damageIndicators = {}
local debugMode = true
local function draw_line(first, second, width, color)
local x,y = GetActiveScreenResolution()
DrawLine_2d(first.x / x, first.y / y, second.x / x, second.y / y, width, color.r, color.g, color.b, color.a)
end
local function sign(x)
return x > 0 and 1 or x < 0 and -1 or 0
end
local function rotate_point(point, cos, sin)
return vec2(point.x * cos - point.y * sin, point.x * sin + point.y * cos)
end
local function get_camera_forward()
local cam_rot = GetFinalRenderedCamRot(2)
local heading = math.rad(cam_rot.z)
local pitch = math.rad(cam_rot.x)
return vec3(-math.sin(heading) * math.cos(pitch), math.cos(heading) * math.cos(pitch), math.sin(pitch))
end
local function draw_triangle(worldVec, width, color, ignoreScreen)
local on_screen, screen_x, screen_y = GetScreenCoordFromWorldCoord(worldVec.x, worldVec.y, worldVec.z)
if not on_screen and not ignoreScreen then return end
local res_x, res_y = GetActiveScreenResolution()
local res_center_x = res_x * 0.5
local res_center_y = res_y * 0.5
local player_position = GetEntityCoords(PlayerPedId())
local delta = worldVec - player_position
delta = norm(delta)
local forward = get_camera_forward()
local dotted = dot(delta, forward)
local crossed = cross(delta, forward)
local angle = math.atan2(#crossed, dotted)
local sign = sign(crossed.z)
angle = angle + 1.570796251
if sign == 1 then angle = math.pi - angle end
local sin_angle = math.sin(angle)
local cos_angle = math.cos(angle)
local radius = 120.0
local triangle_size = 14
local triangle_center = vec2(res_center_x + radius * cos_angle, res_center_y - radius * sin_angle)
local triangle_point_one = rotate_point(vec2(1.0, 0.0), cos_angle, -sin_angle) * triangle_size
local triangle_point_two = rotate_point(vec2(-1.0, 0.75), cos_angle, -sin_angle) * triangle_size
local triangle_point_three = rotate_point(vec2(-1.0, -0.75), cos_angle, -sin_angle) * triangle_size
draw_line(triangle_center + triangle_point_one, triangle_center + triangle_point_two, width, color)
draw_line(triangle_center + triangle_point_two, triangle_center + triangle_point_three, width, color)
draw_line(triangle_center + triangle_point_three, triangle_center + triangle_point_one, width, color)
end
local function AddDamageIndicator(attacker)
local attackerPos = GetEntityCoords(attacker)
table.insert(damageIndicators, {
position = attackerPos,
color = {r = 255, g = 0, b = 0, a = 255},
width = 0.0005,
timeAdded = GetGameTimer(),
duration = 2000
})
end
local function SpawnAttackingPed()
local playerPed = PlayerPedId()
local playerCoords = GetEntityCoords(playerPed)
local spawnDistance = 10.0
local spawnAngle = math.random() * 2 * math.pi
local spawnX = playerCoords.x + spawnDistance * math.cos(spawnAngle)
local spawnY = playerCoords.y + spawnDistance * math.sin(spawnAngle)
local pedHash = GetHashKey("s_m_y_swat_01")
RequestModel(pedHash)
while not HasModelLoaded(pedHash) do
Wait(1)
end
local ped = CreatePed(4, pedHash, spawnX, spawnY, playerCoords.z, 0.0, true, true)
SetPedArmour(ped, 100)
SetPedAccuracy(ped, 50)
SetPedCombatAttributes(ped, 46, true)
SetPedCombatAbility(ped, 100)
local weaponHash = GetHashKey("WEAPON_PISTOL")
GiveWeaponToPed(ped, weaponHash, 999, false, true)
TaskCombatPed(ped, playerPed, 0, 16)
Citizen.SetTimeout(10000, function()
if DoesEntityExist(ped) then
DeleteEntity(ped)
end
end)
end
AddEventHandler('gameEventTriggered', function(name, args)
if name == "CEventNetworkEntityDamage" then
local victim = args[1]
local attacker = args[2]
local isDead = args[4]
local weapon = args[7]
if victim == PlayerPedId() and DoesEntityExist(attacker) then
AddDamageIndicator(attacker)
end
end
end)
Citizen.CreateThread(function()
while true do
local currentTime = GetGameTimer()
for i = #damageIndicators, 1, -1 do
local indicator = damageIndicators[i]
local timeAlive = currentTime - indicator.timeAdded
if timeAlive < indicator.duration then
indicator.color.a = math.floor(255 * (1 - (timeAlive / indicator.duration)))
draw_triangle(indicator.position, indicator.width, indicator.color, true)
else
table.remove(damageIndicators, i)
end
end
Wait(0)
end
end)
Citizen.CreateThread(function()
while debugMode do
SpawnAttackingPed()
Wait(10000)
end
end)