Dzsozi (h03) Posted March 13, 2017 Share Posted March 13, 2017 Hey! I would like to create a junkyard script where you can search for items, and to search for an item you would have to play a minigame, but I bumped into problems and I don't know - how to get a random screen position inside given positions (for example I have a box in the middle of the screen and I would like to get a random position inside that box only) - how to rotate every image in other angle created from a table Like this: http://imgur.com/2Pq43OB - how to move the junk items (images) seperately, I would like to make the minigame work like when you hold the left mouse button the junk items will move in the opposite way, so it's like pushing out the junk from the middle of the box while you are holding mouse button. Like this: http://imgur.com/pxgRpRi So I would like people to play this kind of minigame when they are looking for items in a junkyard, and inside the yellow box there would be the item that they have found, if they found anything. Hope you can understand me and what I am trying to do and you can help me. Can't think about any good way to start it, here's my current code: CLIENT: local sx, sy = guiGetScreenSize() local junkSize = 128 local junkImageDistance = 50 local junkPositionX, junkPositionY = sx/2-junkSize/2, sy/2-junkSize/2 local junkyardCollision = nil local searchTime = 1000 local searchTimeMultiplier = 1 local minimumSearchTimeMultiplier, maximumSearchTimeMultiplier = 5, 15 function createJunkyards() for k,v in ipairs(junkyards) do junkyardCollision = createColCuboid(v[1], v[2], v[3]-0.85, v[4], v[5], v[6]) end end addEventHandler("onClientResourceStart", getResourceRootElement(getThisResource()), createJunkyards) local junks = { -- image, size {"burgershot-bag", 128}, {"cup", 128}, {"boot", 256}, {"bin-bag", 256}, {"apple", 128}, {"paper", 128}, {"bottle", 128}, {"glass", 128}, {"tin-can", 128}, } local junkRotation = 0 function rotateJunk() for k, v in ipairs(junks) do local rot = math.random(1,360) junkRotation = rot end end rotateJunk() function renderJunk() for k, v in ipairs(junks) do dxDrawImage(junkPositionX+k*junkImageDistance, junkPositionY+k*junkImageDistance, v[2], v[2], "junkyard/files/" .. v[1] ..".png", junkRotation, 0, 0, tocolor(255,255,255,255), false) end end addEventHandler("onClientRender", getRootElement(), renderJunk) function startSearching() if junkyardCollision and isElement(junkyardCollision) then if isElementWithinColShape(localPlayer, junkyardCollision) then searchTimeMultiplier = math.random(minimumSearchTimeMultiplier,maximumSearchTimeMultiplier) local finalSearchTime = searchTime*searchTimeMultiplier triggerServerEvent("syncSearchingFromServer", localPlayer, localPlayer, finalSearchTime) setTimer(function() triggerServerEvent("giveFoundJunkItem", localPlayer, localPlayer) end,finalSearchTime,1) else exports["cg_notifications"]:addNotification("Ezt a parancsot csak szeméttelepen tudod használni!", "error") end end end addCommandHandler("turkal", startSearching) GLOBALS (shared): junkyards = { -- x, y, z, width, length, height, {2164.6706542969, -1504.7607421875, 23.984375, 10, 10, 2} } items = { -- item id, chance (%), amount {13, 20, 1}, -- cigar {25, 60, 1}, -- rope {67, 40, 1}, -- lighter {68, 5, 100}, -- graffiti patron } SERVER: function syncSearchingFromServer(player, searchTime) if player and isElement(player) and getElementType(player) == "player" then setPedAnimation(player, "BOMBER", "BOM_Plant_Loop", searchTime, true, false, false, false) end end addEvent("syncSearchingFromServer", true) addEventHandler("syncSearchingFromServer", getRootElement(), syncSearchingFromServer) function giveFoundJunkItem(player) if player and isElement(player) and getElementType(player) == "player" then local foundItem = math.random(1,#items) local currentChance = math.random(1,100) if currentChance <= items[foundItem][2] then outputChatBox("Item a táblából: " .. tostring(foundItem)) outputChatBox("Saját Esély: " .. tostring(currentChance)) outputChatBox(" ") outputChatBox("Item: " .. tostring(items[foundItem][1])) outputChatBox("Item Esély: " .. tostring(items[foundItem][2])) outputChatBox("Item Mennyiség: " .. tostring(items[foundItem][3])) outputChatBox(" ") outputChatBox("megkaptad") else exports["cg_notifications"]:addNotification(player, "Sajnos semmit sem találtál.", "info") return end end end addEvent("giveFoundJunkItem", true) addEventHandler("giveFoundJunkItem", getRootElement(), giveFoundJunkItem) Thank you for your help in advance! Link to comment
Moderators Citizen Posted March 14, 2017 Moderators Share Posted March 14, 2017 (edited) Alright, after severals hours, I managed to do this (game resolution: 1024x768, used my own images): MP4 (HQ) Maybe we can improve it using vectors I don't know but I'm not confortable with them. Here is the client code (the hard part is done. I left the debug drawings but you can remove everything that has the "-- debug" comment) junkyards = { -- x, y, z, width, length, height, {2164.6706542969, -1504.7607421875, 23.984375, 10, 10, 2} } items = { -- item id, chance (%), amount {13, 20, 1}, -- cigar {25, 60, 1}, -- rope {67, 40, 1}, -- lighter {68, 5, 100}, -- graffiti patron } local sx, sy = guiGetScreenSize() local junkSize = sx/2 local junkImageDistance = 50 local junkPositionX, junkPositionY = sx/2-junkSize/2, sy/2-junkSize/2 local junks = {} -- holds all junks images with position, rotation etc local board = {x = junkPositionX, y = junkPositionY, width = junkSize, height = junkSize} local mouseRadius = 20 -- how big the mouse's hitbox is (higher = easier to move junks) local repulseSpeed = 12 -- how fast the junks go away from mouse's hitbox local junkyardCollision = nil local searchTime = 1000 local searchTimeMultiplier = 1 local minimumSearchTimeMultiplier, maximumSearchTimeMultiplier = 5, 15 function createJunkyards() for k,v in ipairs(junkyards) do junkyardCollision = createColCuboid(v[1], v[2], v[3]-0.85, v[4], v[5], v[6]) end end addEventHandler("onClientResourceStart", getResourceRootElement(getThisResource()), createJunkyards) local junkImages = { -- image, size, hitradius {"burgershot-bag", 128, 50}, {"cup", 128, 50}, {"boot", 256, 100}, {"bin-bag", 256, 100}, {"apple", 128, 50}, {"paper", 128, 50}, {"bottle", 128, 50}, {"glass", 128, 50}, {"tin-can", 128, 50} } function createJunks() junks = {} for k, v in ipairs(junkImages) do local size = v[2] local rot = math.random(1,360) local midX, midY = getRandomPointInCircle(board.x+board.width/2, board.y+board.width/2, board.width/4) local x, y = midX - size/2, midY - size/2 -- we want the middle of the image to be placed at that point table.insert(junks, {x = x, y = y, size = size, img = v[1], rot = rot, hitradius = v[3]}) end end showCursor(true) -- debug (add it to your command that shows the junk) bindKey("f5", "down", createJunks) -- debug (F5 to (re)create the junk) function renderJunk() dxDrawRectangle(board.x, board.y, board.width, board.height, tocolor(200, 0, 0, 255)) -- debug (junk board) dxDrawCircle(board.x+board.width/2, board.y+board.width/2, board.width/4, 1, 1, 0, 360, tocolor(0, 0, 0, 255)) -- debug (spawn area - black circle) for k, j in ipairs(junks) do local cx, cy = getCursorPosition() cx, cy = cx * sx, cy * sy -- absolute cursor position local imgCenterX, imgCenterY = j.x+j.size/2, j.y+j.size/2 -- center of the junk's image dxDrawImage(j.x, j.y, j.size, j.size, "junkyard/files/" ..j.img..".png", j.rot, 0, 0, tocolor(255,255,255,255), false) dxDrawCircle(imgCenterX, imgCenterY, j.hitradius, 1, 1, 0, 360, tocolor(0, 0, 200, 255)) -- debug (junk's hitbox - blue circle) dxDrawCircle(cx, cy, mouseRadius, 1, 1, 0, 360, tocolor(255, 255, 0, 255)) -- debug (mouse's hitbox) if getKeyState("mouse1") and isCircleInCircle(imgCenterX, imgCenterY, j.hitradius, cx, cy, mouseRadius) then -- move it away if it collides with the cursor's hitbox local angle = findRotation(imgCenterX, imgCenterY, cx, cy) local newX, newY = getPointFromDistanceRotation(imgCenterX, imgCenterY, repulseSpeed, -angle + 180) local offsetX, offsetY = imgCenterX - newX, imgCenterY - newY j.x, j.y = j.x-offsetX, j.y-offsetY -- debug: local newX, newY = getPointFromDistanceRotation(imgCenterX, imgCenterY, 200, -angle + 180) -- debug dxDrawLine(imgCenterX, imgCenterY, newX, newY, tocolor(0, 200, 0, 255)) -- debug (shows direction where the junk is going - green line) end end end addEventHandler("onClientRender", getRootElement(), renderJunk) function startSearching() if junkyardCollision and isElement(junkyardCollision) then if isElementWithinColShape(localPlayer, junkyardCollision) then searchTimeMultiplier = math.random(minimumSearchTimeMultiplier,maximumSearchTimeMultiplier) local finalSearchTime = searchTime*searchTimeMultiplier triggerServerEvent("syncSearchingFromServer", localPlayer, localPlayer, finalSearchTime) setTimer(function() triggerServerEvent("giveFoundJunkItem", localPlayer, localPlayer) end,finalSearchTime,1) else exports["cg_notifications"]:addNotification("Ezt a parancsot csak szeméttelepen tudod használni!", "error") end end end addCommandHandler("turkal", startSearching) ----------------------------------------------------- -- From https://wiki.multitheftauto.com/wiki/DxDrawCircle (was only used for debug drawings) function dxDrawCircle( posX, posY, radius, width, angleAmount, startAngle, stopAngle, color, postGUI ) if ( type( posX ) ~= "number" ) or ( type( posY ) ~= "number" ) then return false end local function clamp( val, lower, upper ) if ( lower > upper ) then lower, upper = upper, lower end return math.max( lower, math.min( upper, val ) ) end radius = type( radius ) == "number" and radius or 50 width = type( width ) == "number" and width or 5 angleAmount = type( angleAmount ) == "number" and angleAmount or 1 startAngle = clamp( type( startAngle ) == "number" and startAngle or 0, 0, 360 ) stopAngle = clamp( type( stopAngle ) == "number" and stopAngle or 360, 0, 360 ) color = color or tocolor( 255, 255, 255, 200 ) postGUI = type( postGUI ) == "boolean" and postGUI or false if ( stopAngle < startAngle ) then local tempAngle = stopAngle stopAngle = startAngle startAngle = tempAngle end for i = startAngle, stopAngle, angleAmount do local startX = math.cos( math.rad( i ) ) * ( radius - width ) local startY = math.sin( math.rad( i ) ) * ( radius - width ) local endX = math.cos( math.rad( i ) ) * ( radius + width ) local endY = math.sin( math.rad( i ) ) * ( radius + width ) dxDrawLine( startX + posX, startY + posY, endX + posX, endY + posY, color, width, postGUI ) end return true end -- From http://cgp.wikidot.com/circle-to-circle-collision-detection function isCircleInCircle(x1, y1, r1, x2, y2, r2) return math.sqrt( ( x2-x1 ) * ( x2-x1 ) + ( y2-y1 ) * ( y2-y1 ) ) < ( r1 + r2 ) end -- From https://wiki.multitheftauto.com/wiki/FindRotation function findRotation( x1, y1, x2, y2 ) local t = -math.deg( math.atan2( x2 - x1, y2 - y1 ) ) return t < 0 and t + 360 or t end -- From https://wiki.multitheftauto.com/wiki/GetPointFromDistanceRotation function getPointFromDistanceRotation(x, y, dist, angle) local a = math.rad(90 - angle); local dx = math.cos(a) * dist; local dy = math.sin(a) * dist; return x+dx, y+dy; end -- From https://gamedev.stackexchange.com/questions/26713/calculate-random-points-pixel-within-a-circle-image/26714 function getRandomPointInCircle(x, y, radius) local angle = math.random() * math.pi * 2 radius = math.random() * radius local x = x + radius * math.cos(angle) local y = y + radius * math.sin(angle) return x, y end How to use: Start the script and then press F5 to test it. Press the left mouse button and start moving the junks away. Then press F5 again to reset the junks positions. You might want to modify the hitradius/hitbox for each junk image for a better interaction with the junks. You might also want to modify the mouseRadius and the repulseSpeed (see comments for what they are meant for). This is a pretty complex script and I don't have time to add more comments in the code for tonight, but feel free to ask what you do not understand and I'll try my best to explain it. Edited March 14, 2017 by Citizen typo 2 Link to comment
Dzsozi (h03) Posted March 14, 2017 Author Share Posted March 14, 2017 Oh my god thank you so much! Works perfectly, just like I wanted it to work, thank you so much again! You helped me out alot!! But there is one more thing I would like to do and can't figure it out how to do it. I would like to have an item behind the junks, so you have to move the junks away from the item to get it, but I don't know how can I detect if there is nothing in front of the item. I have tried it this way: local sx, sy = guiGetScreenSize() local junkSize = sx/3 local junkImageDistance = 50 local junkPositionX, junkPositionY = sx/2-junkSize/2, sy/2-junkSize/2 local searchingTimer = nil local searchState = false local junks = {} -- holds all junks images with position, rotation etc local board = {x = junkPositionX, y = junkPositionY, width = junkSize, height = junkSize} local item = {} local mouseRadius = 15 -- how big the mouse's hitbox is (higher = easier to move junks) local repulseSpeed = 1 -- how fast the junks go away from mouse's hitbox local junkyardCollision = nil local searchTime = 1000 local searchTimeMultiplier = 1 local minimumSearchTimeMultiplier, maximumSearchTimeMultiplier = 5, 15 local itemColor = tocolor(255,0,0,255) function createJunkyards() for k,v in ipairs(junkyards) do junkyardCollision = createColCuboid(v[1], v[2], v[3]-0.85, v[4], v[5], v[6]) end end addEventHandler("onClientResourceStart", getResourceRootElement(getThisResource()), createJunkyards) local junkImages = { -- image, size, hitradius {"burgershot-bag", 128, 30}, {"burgershot-bag", 128, 30}, {"burgershot-bag", 128, 30}, {"cup", 128, 25}, {"cup", 128, 25}, {"cup", 128, 25}, {"cup", 128, 25}, {"boot", 256, 75}, {"bin-bag", 256, 75}, {"bin-bag", 256, 75}, {"apple", 128, 10}, {"apple", 128, 10}, {"paper", 128, 10}, {"paper", 128, 10}, {"paper", 128, 10}, {"paper", 128, 10}, {"paper", 128, 10}, {"bottle", 128, 25}, {"bottle", 128, 25}, {"glass", 128, 50}, {"tin-can", 128, 25}, {"tin-can", 128, 25}, {"tin-can", 128, 25} } function createJunks() junks = {} item = {} for k, v in ipairs(junkImages) do local size = v[2] local rot = math.random(1,360) local midX, midY = getRandomPointInCircle(board.x+board.width/2, board.y+board.width/2, board.width/2) local x, y = midX - size/2, midY - size/2 -- we want the middle of the image to be placed at that point table.insert(junks, {x = x, y = y, size = size, img = v[1], rot = rot, hitradius = v[3]}) end local itemX, itemY = getRandomPointInCircle(board.x+board.width/2, board.y+board.width/2, board.width/3) local itemSize = 64 local itemRadius = itemSize/2 table.insert(item, {x = itemX, y = itemY, size = itemSize, radius = itemRadius}) end showCursor(true) -- debug (add it to your command that shows the junk) bindKey("f5", "down", createJunks) -- debug (F5 to (re)create the junk) function renderJunk() dxDrawRectangle(board.x, board.y, board.width, board.height, tocolor(0, 0, 0, 150)) -- debug (junk board) --dxDrawCircle(board.x+board.width/2, board.y+board.width/2, board.width/4, 1, 1, 0, 360, tocolor(0, 0, 0, 255)) -- debug (spawn area - black circle) for k, item in ipairs(item) do itemX, itemY = item.x, item.y itemSize = item.size itemRadius = item.radius dxDrawCircle(itemX+itemSize/2, itemY+itemSize/2, itemRadius, 1, 1, 0, 360, tocolor(245, 140, 20, 255)) dxDrawRectangle(itemX, itemY, itemSize, itemSize, itemColor) end for k, j in ipairs(junks) do local cx, cy = getCursorPosition() cx, cy = cx * sx, cy * sy -- absolute cursor position local imgCenterX, imgCenterY = j.x+j.size/2, j.y+j.size/2 -- center of the junk's image dxDrawImage(j.x, j.y, j.size, j.size, "junkyard/files/" ..j.img..".png", j.rot, 0, 0, tocolor(255,255,255,255), false) --dxDrawCircle(imgCenterX, imgCenterY, j.hitradius, 1, 1, 0, 360, tocolor(0, 0, 200, 255)) -- debug (junk's hitbox - blue circle) --dxDrawCircle(cx, cy, mouseRadius, 1, 1, 0, 360, tocolor(255, 255, 0, 255)) -- debug (mouse's hitbox) if getKeyState("mouse1") and isCircleInCircle(imgCenterX, imgCenterY, j.hitradius, cx, cy, mouseRadius) then -- move it away if it collides with the cursor's hitbox if exports["sgr_main"]:isMouseInPosition(board.x, board.y, board.width, board.height) then local angle = findRotation(imgCenterX, imgCenterY, cx, cy) local newX, newY = getPointFromDistanceRotation(imgCenterX, imgCenterY, repulseSpeed, -angle + 180) local offsetX, offsetY = imgCenterX - newX, imgCenterY - newY j.x, j.y = j.x-offsetX, j.y-offsetY -- debug: --local newX, newY = getPointFromDistanceRotation(imgCenterX, imgCenterY, 200, -angle + 180) -- debug --dxDrawLine(imgCenterX, imgCenterY, newX, newY, tocolor(0, 200, 0, 255)) -- debug (shows direction where the junk is going - green line) end end if not isCircleInCircle(imgCenterX, imgCenterY, j.hitradius, itemX+itemSize/2, itemY+itemSize/2, itemRadius) then itemColor = tocolor(0,255,0,255) outputChatBox("a") else itemColor = tocolor(255,0,0,255) outputChatBox("b") end end end addEventHandler("onClientRender", getRootElement(), renderJunk) function startSearching() if junkyardCollision and isElement(junkyardCollision) then if isElementWithinColShape(localPlayer, junkyardCollision) then if not searchState then searchTimeMultiplier = math.random(minimumSearchTimeMultiplier,maximumSearchTimeMultiplier) local finalSearchTime = searchTime*searchTimeMultiplier showCursor(true) createJunks() addEventHandler("onClientRender", getRootElement(), renderJunk) searchState = true triggerServerEvent("syncSearchingFromServer", localPlayer, localPlayer, finalSearchTime) searchingTimer = setTimer(function() showCursor(false) triggerServerEvent("giveFoundJunkItem", localPlayer, localPlayer) removeEventHandler("onClientRender", getRootElement(), renderJunk) end,finalSearchTime,1) end else exports["cg_notifications"]:addNotification("Ezt a parancsot csak szeméttelepen tudod használni!", "error") end end end addCommandHandler("turkal", startSearching) function isPlayerSearchingInJunkyard(player) if player and isElement(player) and getElementType(player) == "player" then if searchState == true then return true else return false end end return false end ----------------------------------------------------- -- From https://wiki.multitheftauto.com/wiki/DxDrawCircle (was only used for debug drawings) function dxDrawCircle( posX, posY, radius, width, angleAmount, startAngle, stopAngle, color, postGUI ) if ( type( posX ) ~= "number" ) or ( type( posY ) ~= "number" ) then return false end local function clamp( val, lower, upper ) if ( lower > upper ) then lower, upper = upper, lower end return math.max( lower, math.min( upper, val ) ) end radius = type( radius ) == "number" and radius or 50 width = type( width ) == "number" and width or 5 angleAmount = type( angleAmount ) == "number" and angleAmount or 1 startAngle = clamp( type( startAngle ) == "number" and startAngle or 0, 0, 360 ) stopAngle = clamp( type( stopAngle ) == "number" and stopAngle or 360, 0, 360 ) color = color or tocolor( 255, 255, 255, 200 ) postGUI = type( postGUI ) == "boolean" and postGUI or false if ( stopAngle < startAngle ) then local tempAngle = stopAngle stopAngle = startAngle startAngle = tempAngle end for i = startAngle, stopAngle, angleAmount do local startX = math.cos( math.rad( i ) ) * ( radius - width ) local startY = math.sin( math.rad( i ) ) * ( radius - width ) local endX = math.cos( math.rad( i ) ) * ( radius + width ) local endY = math.sin( math.rad( i ) ) * ( radius + width ) dxDrawLine( startX + posX, startY + posY, endX + posX, endY + posY, color, width, postGUI ) end return true end -- From http://cgp.wikidot.com/circle-to-circle-collision-detection function isCircleInCircle(x1, y1, r1, x2, y2, r2) return math.sqrt( ( x2-x1 ) * ( x2-x1 ) + ( y2-y1 ) * ( y2-y1 ) ) < ( r1 + r2 ) end -- From https://wiki.multitheftauto.com/wiki/FindRotation function findRotation( x1, y1, x2, y2 ) local t = -math.deg( math.atan2( x2 - x1, y2 - y1 ) ) return t < 0 and t + 360 or t end -- From https://wiki.multitheftauto.com/wiki/GetPointFromDistanceRotation function getPointFromDistanceRotation(x, y, dist, angle) local a = math.rad(90 - angle); local dx = math.cos(a) * dist; local dy = math.sin(a) * dist; return x+dx, y+dy; end -- From https://gamedev.stackexchange.com/questions/26713/calculate-random-points-pixel-within-a-circle-image/26714 function getRandomPointInCircle(x, y, radius) local angle = math.random() * math.pi * 2 radius = math.random() * radius local x = x + radius * math.cos(angle) local y = y + radius * math.sin(angle) return x, y end But for some reason the rectangle that represents the item is always green, even if there is junk on it, it never changes to red or outputs "b" and I don't really understand why. How can I detect if there is nothing in front of the item? Link to comment
Moderators Citizen Posted March 14, 2017 Moderators Share Posted March 14, 2017 (edited) Ok here you go (I've cheated the mouse radius in the result below): MP4 (HQ) The way to do it was to set a boolean (itemDiscovered) to true before looping through the junks and set it to false if a junk's hitbox collides the item's hitbox using the previously used isCircleInCircle. After the for loop, we check if that boolean value is still true, if yes then we discovered the item. But as we are in an onClientRender, we need another boolean (itemDiscoveredAlready) to prevent it to call the discovered function for every next frames. Source: local sx, sy = guiGetScreenSize() local junkSize = sx/3 local junkImageDistance = 50 local junkPositionX, junkPositionY = sx/2-junkSize/2, sy/2-junkSize/2 local searchingTimer = nil local searchState = false local item = nil -- no item at first local junks = {} -- holds all junks images with position, rotation etc local board = {x = junkPositionX, y = junkPositionY, width = junkSize, height = junkSize} local mouseRadius = 20 -- how big the mouse's hitbox is (higher = easier to move junks) local repulseSpeed = 5 -- how fast the junks go away from mouse's hitbox local junkyardCollision = nil local searchTime = 1000 local searchTimeMultiplier = 1 local minimumSearchTimeMultiplier, maximumSearchTimeMultiplier = 5, 15 function createJunkyards() for k,v in ipairs(junkyards) do junkyardCollision = createColCuboid(v[1], v[2], v[3]-0.85, v[4], v[5], v[6]) end end addEventHandler("onClientResourceStart", getResourceRootElement(getThisResource()), createJunkyards) local junkImages = { -- image, size, hitradius {"burgershot-bag", 128, 30}, {"burgershot-bag", 128, 30}, {"burgershot-bag", 128, 30}, {"cup", 128, 25}, {"cup", 128, 25}, {"cup", 128, 25}, {"cup", 128, 25}, {"boot", 256, 75}, {"bin-bag", 256, 75}, {"bin-bag", 256, 75}, {"apple", 128, 10}, {"apple", 128, 10}, {"paper", 128, 10}, {"paper", 128, 10}, {"paper", 128, 10}, {"paper", 128, 10}, {"paper", 128, 10}, {"bottle", 128, 25}, {"bottle", 128, 25}, {"glass", 128, 50}, {"tin-can", 128, 25}, {"tin-can", 128, 25}, {"tin-can", 128, 25} } function createJunks() -- creating junks junks = {} for k, v in ipairs(junkImages) do local size = v[2] local rot = math.random(1,360) local midX, midY = getRandomPointInCircle(board.x+board.width/2, board.y+board.width/2, board.width/2) local x, y = midX - size/2, midY - size/2 -- we want the middle of the image to be placed at that point table.insert(junks, {x = x, y = y, size = size, img = v[1], rot = rot, hitradius = v[3]}) end -- creating the item (should be in another function imo) local itemSize = 64 local itemX, itemY = getRandomPointInCircle(board.x+board.width/2, board.y+board.width/2, board.width/3) itemX, itemY = itemX - itemSize/2, itemY - itemSize/2 -- we want the middle of the image to be placed at that point local itemRadius = itemSize/2 local color = tocolor(255, 0, 0, 255) -- full red by default -- no need for item to be a list of dictionaries, just a dictionary: item = {x = itemX, y = itemY, size = itemSize, radius = itemRadius, color = color} -- reseting that global itemDiscoveredAlready = false end showCursor(true) -- debug (add it to your command that shows the junk) bindKey("f5", "down", createJunks) -- debug (F5 to (re)create the junk) function renderJunk() -- Safety check just un case to prevent spamming errors if try to draw before calling createJunks if #junks == 0 or not item then return end dxDrawRectangle(board.x, board.y, board.width, board.height, tocolor(0, 0, 0, 150)) -- debug (junk board) --dxDrawCircle(board.x+board.width/2, board.y+board.width/2, board.width/4, 1, 1, 0, 360, tocolor(0, 0, 0, 255)) -- debug (spawn area - black circle) -- drawing item -- local itemX, itemY = item.x, item.y local itemSize = item.size local itemRadius = item.radius local itemColor = item.color dxDrawRectangle(itemX, itemY, itemSize, itemSize, itemColor) -- drawing junks -- local itemDiscovered = true -- will tell us after the loop if there is still a junk on it for k, j in ipairs(junks) do local cx, cy = getCursorPosition() cx, cy = cx * sx, cy * sy -- absolute cursor position local imgCenterX, imgCenterY = j.x+j.size/2, j.y+j.size/2 -- center of the junk's image dxDrawImage(j.x, j.y, j.size, j.size, "junkyard/files/" ..j.img..".png", j.rot, 0, 0, tocolor(255,255,255,255), false) -- dxDrawCircle(imgCenterX, imgCenterY, j.hitradius, 1, 1, 0, 360, tocolor(0, 0, 200, 100)) -- debug (junk's hitbox - blue circle) -- dxDrawCircle(cx, cy, mouseRadius, 1, 1, 0, 360, tocolor(255, 255, 0, 255)) -- debug (mouse's hitbox) -- handling item discovery local itemCenterX, itemCenterY = itemX + itemSize/2, itemY + itemSize/2 -- "if the item is still considered as discovered but the current junk's hitbox collides with the item then ..." if itemDiscovered and isCircleInCircle(imgCenterX, imgCenterY, j.hitradius, itemCenterX, itemCenterY, itemRadius) then itemDiscovered = false -- "we finally consider it's not discovered" -- Setting it to false will also stop the code to call the isCircleInCircle above for the remaining junks end dxDrawCircle(itemCenterX, itemCenterY, itemRadius, 1, 1, 0, 360, tocolor(245, 140, 20, 255)) -- debug (item's hitbox) -- Moving junks ability: if getKeyState("mouse1") and isCircleInCircle(imgCenterX, imgCenterY, j.hitradius, cx, cy, mouseRadius) then -- move it away if it collides with the cursor's hitbox if exports["sgr_main"]:isMouseInPosition(board.x, board.y, board.width, board.height) then local angle = findRotation(imgCenterX, imgCenterY, cx, cy) local newX, newY = getPointFromDistanceRotation(imgCenterX, imgCenterY, repulseSpeed, -angle + 180) local offsetX, offsetY = imgCenterX - newX, imgCenterY - newY j.x, j.y = j.x-offsetX, j.y-offsetY -- debug: --local newX, newY = getPointFromDistanceRotation(imgCenterX, imgCenterY, 200, -angle + 180) -- debug --dxDrawLine(imgCenterX, imgCenterY, newX, newY, tocolor(0, 200, 0, 255)) -- debug (shows direction where the junk is going - green line) end end end -- We drew and calculated everything for that frame. Did we just discover the item ? if itemDiscovered and not itemDiscoveredAlready then item.color = tocolor(0, 255, 0, 255) -- full green itemDiscoveredAlready = true -- This will prevent it to be called for every next frames onItemDiscovered( item ) -- call the function for when we discover the item end end addEventHandler("onClientRender", getRootElement(), renderJunk) -- called as soon as an item is discovered function onItemDiscovered( item ) outputChatBox("item discovered !") -- do lightweight stuff here as we are still inside a onClientRender call end function startSearching() if junkyardCollision and isElement(junkyardCollision) then if isElementWithinColShape(localPlayer, junkyardCollision) then if not searchState then searchTimeMultiplier = math.random(minimumSearchTimeMultiplier,maximumSearchTimeMultiplier) local finalSearchTime = searchTime*searchTimeMultiplier showCursor(true) createJunks() addEventHandler("onClientRender", getRootElement(), renderJunk) searchState = true triggerServerEvent("syncSearchingFromServer", localPlayer, localPlayer, finalSearchTime) searchingTimer = setTimer(function() showCursor(false) triggerServerEvent("giveFoundJunkItem", localPlayer, localPlayer) removeEventHandler("onClientRender", getRootElement(), renderJunk) end,finalSearchTime,1) end else exports["cg_notifications"]:addNotification("Ezt a parancsot csak szeméttelepen tudod használni!", "error") end end end addCommandHandler("turkal", startSearching) function isPlayerSearchingInJunkyard(player) if player and isElement(player) and getElementType(player) == "player" then if searchState == true then return true else return false end end return false end ----------------------------------------------------- -- From https://wiki.multitheftauto.com/wiki/DxDrawCircle (was only used for debug drawings) function dxDrawCircle( posX, posY, radius, width, angleAmount, startAngle, stopAngle, color, postGUI ) if ( type( posX ) ~= "number" ) or ( type( posY ) ~= "number" ) then return false end local function clamp( val, lower, upper ) if ( lower > upper ) then lower, upper = upper, lower end return math.max( lower, math.min( upper, val ) ) end radius = type( radius ) == "number" and radius or 50 width = type( width ) == "number" and width or 5 angleAmount = type( angleAmount ) == "number" and angleAmount or 1 startAngle = clamp( type( startAngle ) == "number" and startAngle or 0, 0, 360 ) stopAngle = clamp( type( stopAngle ) == "number" and stopAngle or 360, 0, 360 ) color = color or tocolor( 255, 255, 255, 200 ) postGUI = type( postGUI ) == "boolean" and postGUI or false if ( stopAngle < startAngle ) then local tempAngle = stopAngle stopAngle = startAngle startAngle = tempAngle end for i = startAngle, stopAngle, angleAmount do local startX = math.cos( math.rad( i ) ) * ( radius - width ) local startY = math.sin( math.rad( i ) ) * ( radius - width ) local endX = math.cos( math.rad( i ) ) * ( radius + width ) local endY = math.sin( math.rad( i ) ) * ( radius + width ) dxDrawLine( startX + posX, startY + posY, endX + posX, endY + posY, color, width, postGUI ) end return true end -- From http://cgp.wikidot.com/circle-to-circle-collision-detection function isCircleInCircle(x1, y1, r1, x2, y2, r2) return math.sqrt( ( x2-x1 ) * ( x2-x1 ) + ( y2-y1 ) * ( y2-y1 ) ) < ( r1 + r2 ) end -- From https://wiki.multitheftauto.com/wiki/FindRotation function findRotation( x1, y1, x2, y2 ) local t = -math.deg( math.atan2( x2 - x1, y2 - y1 ) ) return t < 0 and t + 360 or t end -- From https://wiki.multitheftauto.com/wiki/GetPointFromDistanceRotation function getPointFromDistanceRotation(x, y, dist, angle) local a = math.rad(90 - angle); local dx = math.cos(a) * dist; local dy = math.sin(a) * dist; return x+dx, y+dy; end -- From https://gamedev.stackexchange.com/questions/26713/calculate-random-points-pixel-within-a-circle-image/26714 function getRandomPointInCircle(x, y, radius) local angle = math.random() * math.pi * 2 radius = math.random() * radius local x = x + radius * math.cos(angle) local y = y + radius * math.sin(angle) return x, y end Also note that the mouseRadius will change with resolutions as it's in pixels. Same goes for repulseSpeed which is additionally dependent on FPS. For better performance, you should not add too much junks nor call exported functions (at line 127) but local functions instead (consider copying and paste the function at the bottom of that script). Edited March 14, 2017 by Citizen Link to comment
Dzsozi (h03) Posted March 14, 2017 Author Share Posted March 14, 2017 It works perfectly, just as I wanted thank you! But I have noticed that there is (for me) a kind of big fps drop when the panel is visible, and it didn't happen before, not even when I added tons of junks. Do you have any idea why is this happening? Link to comment
Dzsozi (h03) Posted March 14, 2017 Author Share Posted March 14, 2017 EDIT: Here's my current script, I don't get any errors in debugscript, everything works fine except the FPS drop. local sx, sy = guiGetScreenSize() local junkSize = sx/3 local junkImageDistance = 50 local junkPositionX, junkPositionY = sx/2-junkSize/2, sy/2-junkSize/2 local searchState = false local item = nil -- no item at first local junks = {} -- holds all junks images with position, rotation etc local board = {x = junkPositionX, y = junkPositionY, width = junkSize, height = junkSize} local mouseRadius = 20 -- how big the mouse's hitbox is (higher = easier to move junks) local repulseSpeed = 5 -- how fast the junks go away from mouse's hitbox local junkyardCollision = nil function createJunkyards() for k,v in ipairs(junkyards) do junkyardCollision = createColCuboid(v[1], v[2], v[3]-0.85, v[4], v[5], v[6]) end end addEventHandler("onClientResourceStart", getResourceRootElement(getThisResource()), createJunkyards) local junkImages = { -- image, size, hitradius {"burgershot-bag", 128, 30}, {"burgershot-bag", 128, 30}, {"burgershot-bag", 128, 30}, {"cup", 128, 25}, {"cup", 128, 25}, {"cup", 128, 25}, {"cup", 128, 25}, {"boot", 256, 75}, {"bin-bag", 256, 75}, {"bin-bag", 256, 75}, {"apple", 128, 30}, {"apple", 128, 30}, {"paper", 128, 30}, {"paper", 128, 30}, {"paper", 128, 30}, {"paper", 128, 30}, {"paper", 128, 30}, {"bottle", 128, 25}, {"bottle", 128, 25}, {"glass", 128, 50}, {"tin-can", 128, 25}, {"tin-can", 128, 25}, {"tin-can", 128, 25}, -- duplicated amount, didn't cause lag before, but now it lags even if i delete the junks under here {"burgershot-bag", 128, 30}, {"burgershot-bag", 128, 30}, {"burgershot-bag", 128, 30}, {"cup", 128, 25}, {"cup", 128, 25}, {"cup", 128, 25}, {"cup", 128, 25}, {"boot", 256, 75}, {"bin-bag", 256, 75}, {"bin-bag", 256, 75}, {"apple", 128, 30}, {"apple", 128, 30}, {"paper", 128, 30}, {"paper", 128, 30}, {"paper", 128, 30}, {"paper", 128, 30}, {"paper", 128, 30}, {"bottle", 128, 25}, {"bottle", 128, 25}, {"glass", 128, 50}, {"tin-can", 128, 25}, {"tin-can", 128, 25}, {"tin-can", 128, 25} } function createJunks() -- creating junks junks = {} for k, v in ipairs(junkImages) do local size = v[2] local rot = math.random(1,360) local midX, midY = getRandomPointInCircle(board.x+board.width/2, board.y+board.width/2, board.width/2) local x, y = midX - size/2, midY - size/2 -- we want the middle of the image to be placed at that point table.insert(junks, {x = x, y = y, size = size, img = v[1], rot = rot, hitradius = v[3]}) end -- creating the item (should be in another function imo) local itemSize = 64 local itemX, itemY = getRandomPointInCircle(board.x+board.width/2, board.y+board.width/2, board.width/3) itemX, itemY = itemX - itemSize/2, itemY - itemSize/2 -- we want the middle of the image to be placed at that point local itemRadius = itemSize/2 local color = tocolor(255, 0, 0, 255) -- full red by default -- no need for item to be a list of dictionaries, just a dictionary: item = {x = itemX, y = itemY, size = itemSize, radius = itemRadius, color = color} -- reseting that global itemDiscoveredAlready = false end --showCursor(true) -- debug (add it to your command that shows the junk) --bindKey("f5", "down", createJunks) -- debug (F5 to (re)create the junk) function renderJunk() -- Safety check just un case to prevent spamming errors if try to draw before calling createJunks if #junks == 0 or not item then return end dxDrawRectangle(board.x, board.y, board.width, board.height, tocolor(0, 0, 0, 150)) -- debug (junk board) --dxDrawCircle(board.x+board.width/2, board.y+board.width/2, board.width/4, 1, 1, 0, 360, tocolor(0, 0, 0, 255)) -- debug (spawn area - black circle) -- drawing item -- local itemX, itemY = item.x, item.y local itemSize = item.size local itemRadius = item.radius local itemColor = item.color dxDrawRectangle(itemX, itemY, itemSize, itemSize, itemColor) -- drawing junks -- local itemDiscovered = true -- will tell us after the loop if there is still a junk on it for k, j in ipairs(junks) do local cx, cy = getCursorPosition() cx, cy = cx * sx, cy * sy -- absolute cursor position local imgCenterX, imgCenterY = j.x+j.size/2, j.y+j.size/2 -- center of the junk's image dxDrawImage(j.x, j.y, j.size, j.size, "junkyard/files/" ..j.img..".png", j.rot, 0, 0, tocolor(255,255,255,255), false) --dxDrawCircle(imgCenterX, imgCenterY, j.hitradius, 1, 1, 0, 360, tocolor(0, 0, 200, 100)) -- debug (junk's hitbox - blue circle) --dxDrawCircle(cx, cy, mouseRadius, 1, 1, 0, 360, tocolor(255, 255, 0, 255)) -- debug (mouse's hitbox) -- handling item discovery local itemCenterX, itemCenterY = itemX + itemSize/2, itemY + itemSize/2 -- "if the item is still considered as discovered but the current junk's hitbox collides with the item then ..." if itemDiscovered and isCircleInCircle(imgCenterX, imgCenterY, j.hitradius, itemCenterX, itemCenterY, itemRadius) then itemDiscovered = false -- "we finally consider it's not discovered" -- Setting it to false will also stop the code to call the isCircleInCircle above for the remaining junks end dxDrawCircle(itemCenterX, itemCenterY, itemRadius, 1, 1, 0, 360, tocolor(245, 140, 20, 255)) -- debug (item's hitbox) -- Moving junks ability: if getKeyState("mouse1") and isCircleInCircle(imgCenterX, imgCenterY, j.hitradius, cx, cy, mouseRadius) then -- move it away if it collides with the cursor's hitbox if exports["sgr_main"]:isMouseInPosition(board.x, board.y, board.width, board.height) then local angle = findRotation(imgCenterX, imgCenterY, cx, cy) local newX, newY = getPointFromDistanceRotation(imgCenterX, imgCenterY, repulseSpeed, -angle + 180) local offsetX, offsetY = imgCenterX - newX, imgCenterY - newY j.x, j.y = j.x-offsetX, j.y-offsetY -- debug: --local newX, newY = getPointFromDistanceRotation(imgCenterX, imgCenterY, 200, -angle + 180) -- debug --dxDrawLine(imgCenterX, imgCenterY, newX, newY, tocolor(0, 200, 0, 255)) -- debug (shows direction where the junk is going - green line) end end end -- We drew and calculated everything for that frame. Did we just discover the item ? if itemDiscovered then item.color = tocolor(0, 255, 0, 255 * math.abs(getTickCount() % 1000 - 500) / 500) -- full green if not itemDiscoveredAlready then itemDiscoveredAlready = true -- This will prevent it to be called for every next frames setTimer(function() onItemDiscovered(item) -- call the function for when we discover the item end, 3000, 1) end end end -- called as soon as an item is discovered function onItemDiscovered(item) searchState = false outputChatBox("item discovered !") showCursor(false) triggerServerEvent("giveFoundJunkItem", localPlayer, localPlayer) removeEventHandler("onClientRender", getRootElement(), renderJunk) itemDiscovered = false exports["sgr_main"]:syncAnimationFromServer(localPlayer, false) -- do lightweight stuff here as we are still inside a onClientRender call end function startSearching() if junkyardCollision and isElement(junkyardCollision) then if isElementWithinColShape(localPlayer, junkyardCollision) then if not isPedInVehicle(localPlayer) then if not searchState then searchState = true showCursor(true) createJunks() addEventHandler("onClientRender", getRootElement(), renderJunk) exports["sgr_main"]:syncAnimationFromServer(localPlayer, "BOMBER", "BOM_Plant_Loop", -1, true, false, false, false) end else exports["cg_notifications"]:addNotification("Járműben nem használhatod ezt a parancsot!", "error") end else exports["cg_notifications"]:addNotification("Ezt a parancsot csak szeméttelepen tudod használni!", "error") end end end addCommandHandler("turkal", startSearching) function isPlayerSearchingInJunkyard(player) if player and isElement(player) and getElementType(player) == "player" then if searchState == true then return true else return false end end return false end ----------------------------------------------------- -- From https://wiki.multitheftauto.com/wiki/DxDrawCircle (was only used for debug drawings) function dxDrawCircle( posX, posY, radius, width, angleAmount, startAngle, stopAngle, color, postGUI ) if ( type( posX ) ~= "number" ) or ( type( posY ) ~= "number" ) then return false end local function clamp( val, lower, upper ) if ( lower > upper ) then lower, upper = upper, lower end return math.max( lower, math.min( upper, val ) ) end radius = type( radius ) == "number" and radius or 50 width = type( width ) == "number" and width or 5 angleAmount = type( angleAmount ) == "number" and angleAmount or 1 startAngle = clamp( type( startAngle ) == "number" and startAngle or 0, 0, 360 ) stopAngle = clamp( type( stopAngle ) == "number" and stopAngle or 360, 0, 360 ) color = color or tocolor( 255, 255, 255, 200 ) postGUI = type( postGUI ) == "boolean" and postGUI or false if ( stopAngle < startAngle ) then local tempAngle = stopAngle stopAngle = startAngle startAngle = tempAngle end for i = startAngle, stopAngle, angleAmount do local startX = math.cos( math.rad( i ) ) * ( radius - width ) local startY = math.sin( math.rad( i ) ) * ( radius - width ) local endX = math.cos( math.rad( i ) ) * ( radius + width ) local endY = math.sin( math.rad( i ) ) * ( radius + width ) dxDrawLine( startX + posX, startY + posY, endX + posX, endY + posY, color, width, postGUI ) end return true end -- From http://cgp.wikidot.com/circle-to-circle-collision-detection function isCircleInCircle(x1, y1, r1, x2, y2, r2) return math.sqrt( ( x2-x1 ) * ( x2-x1 ) + ( y2-y1 ) * ( y2-y1 ) ) < ( r1 + r2 ) end -- From https://wiki.multitheftauto.com/wiki/FindRotation function findRotation( x1, y1, x2, y2 ) local t = -math.deg( math.atan2( x2 - x1, y2 - y1 ) ) return t < 0 and t + 360 or t end -- From https://wiki.multitheftauto.com/wiki/GetPointFromDistanceRotation function getPointFromDistanceRotation(x, y, dist, angle) local a = math.rad(90 - angle); local dx = math.cos(a) * dist; local dy = math.sin(a) * dist; return x+dx, y+dy; end -- From https://gamedev.stackexchange.com/questions/26713/calculate-random-points-pixel-within-a-circle-image/26714 function getRandomPointInCircle(x, y, radius) local angle = math.random() * math.pi * 2 radius = math.random() * radius local x = x + radius * math.cos(angle) local y = y + radius * math.sin(angle) return x, y end Link to comment
Moderators Citizen Posted March 15, 2017 Moderators Share Posted March 15, 2017 (edited) For me I already had FPS drops when you added some junks the first time. Anyway, I improved everything I could find (didn't test, report errors if any): local sx, sy = guiGetScreenSize() local junkSize = sx/3 local junkImageDistance = 50 local junkPositionX, junkPositionY = sx/2-junkSize/2, sy/2-junkSize/2 local searchState = false local item = nil -- no item at first local junks = {} -- holds all junks images with position, rotation etc local board = {x = junkPositionX, y = junkPositionY, width = junkSize, height = junkSize} local mouseRadius = 20 -- how big the mouse's hitbox is (higher = easier to move junks) local repulseSpeed = 5 -- how fast the junks go away from mouse's hitbox local junkyardCollision = nil function createJunkyards() for k,v in ipairs(junkyards) do junkyardCollision = createColCuboid(v[1], v[2], v[3]-0.85, v[4], v[5], v[6]) end end addEventHandler("onClientResourceStart", getResourceRootElement(getThisResource()), createJunkyards) local junkImages = { -- image, size, hitradius {"burgershot-bag", 128, 30}, {"burgershot-bag", 128, 30}, {"burgershot-bag", 128, 30}, {"cup", 128, 25}, {"cup", 128, 25}, {"cup", 128, 25}, {"cup", 128, 25}, {"boot", 256, 75}, {"bin-bag", 256, 75}, {"bin-bag", 256, 75}, {"apple", 128, 30}, {"apple", 128, 30}, {"paper", 128, 30}, {"paper", 128, 30}, {"paper", 128, 30}, {"paper", 128, 30}, {"paper", 128, 30}, {"bottle", 128, 25}, {"bottle", 128, 25}, {"glass", 128, 50}, {"tin-can", 128, 25}, {"tin-can", 128, 25}, {"tin-can", 128, 25}, -- duplicated amount, didn't cause lag before, but now it lags even if i delete the junks under here {"burgershot-bag", 128, 30}, {"burgershot-bag", 128, 30}, {"burgershot-bag", 128, 30}, {"cup", 128, 25}, {"cup", 128, 25}, {"cup", 128, 25}, {"cup", 128, 25}, {"boot", 256, 75}, {"bin-bag", 256, 75}, {"bin-bag", 256, 75}, {"apple", 128, 30}, {"apple", 128, 30}, {"paper", 128, 30}, {"paper", 128, 30}, {"paper", 128, 30}, {"paper", 128, 30}, {"paper", 128, 30}, {"bottle", 128, 25}, {"bottle", 128, 25}, {"glass", 128, 50}, {"tin-can", 128, 25}, {"tin-can", 128, 25}, {"tin-can", 128, 25} } function createJunks() -- creating junks junks = {} for k, v in ipairs(junkImages) do local image = "junkyard/files/"..v[1].".png" local size = v[2] local rot = math.random(1,360) local midX, midY = getRandomPointInCircle(board.x+board.width/2, board.y+board.width/2, board.width/2) local x, y = midX - size/2, midY - size/2 -- we want the middle of the image to be placed at that point table.insert(junks, {x = x, y = y, size = size, halfSize = size/2, img = image, rot = rot, hitradius = v[3]}) end -- creating the item (should be in another function imo) local itemSize = 64 local itemX, itemY = getRandomPointInCircle(board.x+board.width/2, board.y+board.width/2, board.width/3) itemX, itemY = itemX - itemSize/2, itemY - itemSize/2 -- we want the middle of the image to be placed at that point local itemRadius = itemSize/2 local color = tocolor(255, 0, 0, 255) -- full red by default -- no need for item to be a list of dictionaries, just a dictionary: item = {x = itemX, y = itemY, size = itemSize, halfSize = itemSize/2, radius = itemRadius, color = color} -- reseting that global itemDiscoveredAlready = false end --showCursor(true) -- debug (add it to your command that shows the junk) --bindKey("f5", "down", createJunks) -- debug (F5 to (re)create the junk) function renderJunk() -- Safety check just un case to prevent spamming errors if try to draw before calling createJunks if #junks == 0 or not item then return end dxDrawRectangle(board.x, board.y, board.width, board.height, tocolor(0, 0, 0, 150)) -- debug (junk board) --dxDrawCircle(board.x+board.width/2, board.y+board.width/2, board.width/4, 1, 1, 0, 360, tocolor(0, 0, 0, 255)) -- debug (spawn area - black circle) -- drawing item -- local itemX, itemY = item.x, item.y local itemSize = item.size local itemHalfSize = item.halfSize local itemRadius = item.radius local itemColor = item.color local itemCenterX, itemCenterY = itemX + itemHalfSize, itemY + itemHalfSize dxDrawRectangle(itemX, itemY, itemSize, itemSize, itemColor) -- Getting the cursor position once per frame local cx, cy = getCursorPosition() cx, cy = cx * sx, cy * sy -- absolute cursor position local cursorInsideBoard = cx > board.x and cx < board.x + board.width and cy > board.y and cy < board.y + board.height local mouse1State = getKeyState("mouse1") -- drawing junks -- local itemDiscovered = true -- will tell us after the loop if there is still a junk on it for k, j in ipairs(junks) do dxDrawImage(j.x, j.y, j.size, j.size, j.img, j.rot, 0, 0, tocolor(255,255,255,255), false) -- handling item discovery local imgCenterX, imgCenterY = j.x+j.halfSize, j.y+j.halfSize -- center of the junk's image -- "if the item is still considered as discovered but the current junk's hitbox collides with the item then ..." if itemDiscovered and isCircleInCircle(imgCenterX, imgCenterY, j.hitradius, itemCenterX, itemCenterY, itemRadius) then itemDiscovered = false -- "we finally consider it's not discovered" -- Setting it to false will also stop the code to call the isCircleInCircle above for the remaining junks end --dxDrawCircle(itemCenterX, itemCenterY, itemRadius, 1, 1, 0, 360, tocolor(245, 140, 20, 255)) -- debug (item's hitbox) --dxDrawCircle(imgCenterX, imgCenterY, j.hitradius, 1, 1, 0, 360, tocolor(0, 0, 200, 100)) -- debug (junk's hitbox - blue circle) --dxDrawCircle(cx, cy, mouseRadius, 1, 1, 0, 360, tocolor(255, 255, 0, 255)) -- debug (mouse's hitbox) -- Moving junks ability: if mouse1State and cursorInsideBoard and isCircleInCircle(imgCenterX, imgCenterY, j.hitradius, cx, cy, mouseRadius) then -- move it away if it collides with the cursor's hitbox local angle = findRotation(imgCenterX, imgCenterY, cx, cy) local newX, newY = getPointFromDistanceRotation(imgCenterX, imgCenterY, repulseSpeed, -angle + 180) local offsetX, offsetY = imgCenterX - newX, imgCenterY - newY j.x, j.y = j.x-offsetX, j.y-offsetY -- debug: --local newX, newY = getPointFromDistanceRotation(imgCenterX, imgCenterY, 200, -angle + 180) -- debug --dxDrawLine(imgCenterX, imgCenterY, newX, newY, tocolor(0, 200, 0, 255)) -- debug (shows direction where the junk is going - green line) end end -- We drew and calculated everything for that frame. Did we just discover the item ? if itemDiscovered then item.color = tocolor(0, 255, 0, 255 * math.abs(getTickCount() % 1000 - 500) / 500) -- full green if not itemDiscoveredAlready then itemDiscoveredAlready = true -- This will prevent it to be called for every next frames setTimer(function() onItemDiscovered(item) -- call the function for when we discover the item end, 3000, 1) end end end -- called as soon as an item is discovered function onItemDiscovered(item) searchState = false outputChatBox("item discovered !") showCursor(false) triggerServerEvent("giveFoundJunkItem", localPlayer, localPlayer) removeEventHandler("onClientRender", getRootElement(), renderJunk) itemDiscovered = false exports["sgr_main"]:syncAnimationFromServer(localPlayer, false) -- do lightweight stuff here as we are still inside a onClientRender call end function startSearching() if junkyardCollision and isElement(junkyardCollision) then if isElementWithinColShape(localPlayer, junkyardCollision) then if not isPedInVehicle(localPlayer) then if not searchState then searchState = true showCursor(true) createJunks() addEventHandler("onClientRender", getRootElement(), renderJunk) exports["sgr_main"]:syncAnimationFromServer(localPlayer, "BOMBER", "BOM_Plant_Loop", -1, true, false, false, false) end else exports["cg_notifications"]:addNotification("Járműben nem használhatod ezt a parancsot!", "error") end else exports["cg_notifications"]:addNotification("Ezt a parancsot csak szeméttelepen tudod használni!", "error") end end end addCommandHandler("turkal", startSearching) function isPlayerSearchingInJunkyard(player) if player and isElement(player) and getElementType(player) == "player" then if searchState == true then return true else return false end end return false end ----------------------------------------------------- -- From https://wiki.multitheftauto.com/wiki/DxDrawCircle (was only used for debug drawings) function dxDrawCircle( posX, posY, radius, width, angleAmount, startAngle, stopAngle, color, postGUI ) if ( type( posX ) ~= "number" ) or ( type( posY ) ~= "number" ) then return false end local function clamp( val, lower, upper ) if ( lower > upper ) then lower, upper = upper, lower end return math.max( lower, math.min( upper, val ) ) end radius = type( radius ) == "number" and radius or 50 width = type( width ) == "number" and width or 5 angleAmount = type( angleAmount ) == "number" and angleAmount or 1 startAngle = clamp( type( startAngle ) == "number" and startAngle or 0, 0, 360 ) stopAngle = clamp( type( stopAngle ) == "number" and stopAngle or 360, 0, 360 ) color = color or tocolor( 255, 255, 255, 200 ) postGUI = type( postGUI ) == "boolean" and postGUI or false if ( stopAngle < startAngle ) then local tempAngle = stopAngle stopAngle = startAngle startAngle = tempAngle end for i = startAngle, stopAngle, angleAmount do local startX = math.cos( math.rad( i ) ) * ( radius - width ) local startY = math.sin( math.rad( i ) ) * ( radius - width ) local endX = math.cos( math.rad( i ) ) * ( radius + width ) local endY = math.sin( math.rad( i ) ) * ( radius + width ) dxDrawLine( startX + posX, startY + posY, endX + posX, endY + posY, color, width, postGUI ) end return true end -- From http://cgp.wikidot.com/circle-to-circle-collision-detection function isCircleInCircle(x1, y1, r1, x2, y2, r2) return math.sqrt( ( x2-x1 ) * ( x2-x1 ) + ( y2-y1 ) * ( y2-y1 ) ) < ( r1 + r2 ) end -- From https://wiki.multitheftauto.com/wiki/FindRotation function findRotation( x1, y1, x2, y2 ) local t = -math.deg( math.atan2( x2 - x1, y2 - y1 ) ) return t < 0 and t + 360 or t end -- From https://wiki.multitheftauto.com/wiki/GetPointFromDistanceRotation function getPointFromDistanceRotation(x, y, dist, angle) local a = math.rad(90 - angle); local dx = math.cos(a) * dist; local dy = math.sin(a) * dist; return x+dx, y+dy; end -- From https://gamedev.stackexchange.com/questions/26713/calculate-random-points-pixel-within-a-circle-image/26714 function getRandomPointInCircle(x, y, radius) local angle = math.random() * math.pi * 2 radius = math.random() * radius local x = x + radius * math.cos(angle) local y = y + radius * math.sin(angle) return x, y end Changes: No more division in the rendering part for item and junks image center (calculated at the creation and stored in the "objects" in halfSize attribute) Getting the cursor position with the absolute convertion only once per frame instead of #junks per frame (cx, cy) Removed your exported function and calculate if inside the board manually outside the junk loop as we have all informations we need (cursorInsideBoard) Getting the mouse1 key state only once per frame instead of #junks per frame (mouse1State) Moved the string concatenations for the junk's image path into createJunks function. Also what are you trying to do at line 173 please ? Edited March 15, 2017 by Citizen Link to comment
Dzsozi (h03) Posted March 15, 2017 Author Share Posted March 15, 2017 Works perfectly now, thank you so much Citizen! BTW at line 173 it changes the item picture to green and then makes it flashing, because I would like the player to see the item for 3 seconds, so he is notified about finding it. Link to comment
Moderators Citizen Posted March 15, 2017 Moderators Share Posted March 15, 2017 Alright, cool to hear it fixed the issue and that I didn't break anything by refactoring the calculations. Feel free to remove the commented lines and debug things to make the code cleaner (the dxDrawCircle function definition can normally be removed if you don't use it anywhere else in that script). Link to comment
Dzsozi (h03) Posted March 15, 2017 Author Share Posted March 15, 2017 Okay, will do that, thank you! Link to comment
Dzsozi (h03) Posted March 15, 2017 Author Share Posted March 15, 2017 I would like to ask for help with one more thing. CLIENT: function createJunks() -- creating junks junks = {} for k, v in ipairs(junkImages) do local image = "junkyard/files/"..v[1]..".png" local size = v[2] local rot = math.random(1,360) local midX, midY = getRandomPointInCircle(board.x+board.width/2, board.y+board.width/2, board.width/2) local x, y = midX - size/2, midY - size/2 -- we want the middle of the image to be placed at that point table.insert(junks, {x = x, y = y, size = size, halfSize = size/2, img = image, rot = rot, hitradius = v[3]}) end -- creating the item (should be in another function imo) local itemSize = 64 local itemX, itemY = getRandomPointInCircle(board.x+board.width/2, board.y+board.width/2, board.width/3) itemX, itemY = itemX - itemSize/2, itemY - itemSize/2 -- we want the middle of the image to be placed at that point local itemRadius = itemSize/2 local color = tocolor(255, 0, 0, 255) -- full red by default -- no need for item to be a list of dictionaries, just a dictionary: item = {x = itemX, y = itemY, size = itemSize, halfSize = itemSize/2, radius = itemRadius, color = color} -- reseting that global itemDiscoveredAlready = false triggerServerEvent("setJunkItem", localPlayer) local foundItemImage = -- what to write here to get the number of the item from server side?? like items[foundItem][1] is the way I get it on server side, but there is no such thing as foundItem end SERVER: local isItem = false local foundItem = nil function setJunkItem() --if player and isElement(player) and getElementType(player) == "player" then foundItem = math.random(1,#items) local currentChance = math.random(1,100) if currentChance <= items[foundItem][2] then outputChatBox("Item a táblából: " .. tostring(foundItem)) outputChatBox("Saját Esély: " .. tostring(currentChance)) outputChatBox(" ") outputChatBox("Item: " .. tostring(items[foundItem][1])) outputChatBox("Item Esély: " .. tostring(items[foundItem][2])) outputChatBox("Item Mennyiség: " .. tostring(items[foundItem][3])) isItem = true else isItem = false end --end end addEvent("setJunkItem", true) addEventHandler("setJunkItem", getRootElement(), setJunkItem) function giveJunkItem(player) if player and isElement(player) and getElementType(player) == "player" then if isItem then --if item == items[foundItem][1] then exports["cg_items"]:giveItem(player, items[foundItem][1], items[foundItem][3]) outputChatBox(exports["cg_items"]:getItemName(items[foundItem][1])) --end else exports["cg_notifications"]:addNotification(player, "Sajnos semmit sem találtál.", "info") return end end end addEvent("giveJunkItem", true) addEventHandler("giveJunkItem", getRootElement(), giveJunkItem) As I wrote in a comment inside the client side script, I would like to get the item number generated in the server side script. The reason is why I want to get it is because I would like to draw the item's image instead of the red and green rectangle under the junk, but I have no idea how I can do that. Is there any way doing it? I have tried things like -- SERVER function setJunkItem() foundItem = math.random(1,#items) local currentChance = math.random(1,100) if currentChance <= items[foundItem][2] then outputChatBox("Item a táblából: " .. tostring(foundItem)) outputChatBox("Saját Esély: " .. tostring(currentChance)) outputChatBox(" ") outputChatBox("Item: " .. tostring(items[foundItem][1])) outputChatBox("Item Esély: " .. tostring(items[foundItem][2])) outputChatBox("Item Mennyiség: " .. tostring(items[foundItem][3])) isItem = true return items[foundItem][1] else isItem = false return 0 end end addEvent("setJunkItem", true) addEventHandler("setJunkItem", getRootElement(), setJunkItem) -- CLIENT local foundItemImage = nil function createJunks() -- creating junks junks = {} for k, v in ipairs(junkImages) do local image = "junkyard/files/"..v[1]..".png" local size = v[2] local rot = math.random(1,360) local midX, midY = getRandomPointInCircle(board.x+board.width/2, board.y+board.width/2, board.width/2) local x, y = midX - size/2, midY - size/2 -- we want the middle of the image to be placed at that point table.insert(junks, {x = x, y = y, size = size, halfSize = size/2, img = image, rot = rot, hitradius = v[3]}) end -- creating the item (should be in another function imo) local itemSize = 64 local itemX, itemY = getRandomPointInCircle(board.x+board.width/2, board.y+board.width/2, board.width/3) itemX, itemY = itemX - itemSize/2, itemY - itemSize/2 -- we want the middle of the image to be placed at that point local itemRadius = itemSize/2 local color = tocolor(255, 0, 0, 255) -- full red by default -- no need for item to be a list of dictionaries, just a dictionary: item = {x = itemX, y = itemY, size = itemSize, halfSize = itemSize/2, radius = itemRadius, color = color} -- reseting that global itemDiscoveredAlready = false foundItemImage = triggerServerEvent("setJunkItem", localPlayer) end But of course it's not working because - as MTA Wiki says - triggerServerEvent returns a bool, so I have no idea how I could do that. Could you help me out with this please? Link to comment
NeXuS™ Posted March 17, 2017 Share Posted March 17, 2017 You could trigger it back to the client side with a triggerClientEvent easily. Link to comment
Dzsozi (h03) Posted March 18, 2017 Author Share Posted March 18, 2017 But I don't really understand how. Link to comment
NeXuS™ Posted March 18, 2017 Share Posted March 18, 2017 Replace return items[foundItem][1] with triggerClientEvent(source, "setJunkItem", getRootElement(), items[foundItem][1]) And then client side: addEvent("setJunkItem", true) addEventHandler("setJunkItem", getRootElement(), function(itemID) foundItemImage = itemID end) I think this one should work. 2 Link to comment
Dzsozi (h03) Posted March 18, 2017 Author Share Posted March 18, 2017 Yes, it works that way, thank you! 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