Kneighbors wrote: »
Don't take things in too complicated manner, everything is simple. Surely game development is not the most complicated thing people did for amount of money ZoS get. Yea, I'm jealous of them because I think they get much more money than they are supposed to.
OK, if game coding isn't so hard here's a little task for you, there's a mistake in this code, please find it, you have 10 minutes ...-- LUA Script - precede every function and global member with lowercase name of script + '_main'
-- Default script - does nothing.
-- Add this to always active entity - only one is needed
local Q = require "scriptbank\\quatlib"
local deg = math.deg
local rad = math.rad
local sin = math.sin
local cos = math.cos
local atan = math.atan2
local tan = math.tan
local pi = math.pi
local abs = math.abs
local modf = math.modf
local sqrt = math,sqrt
local pickUpDistance = 150
local pickUppableEntity = {Ent = nil}
local function Rotate3D (x, y, z, xrot, yrot, zrot)
function RotatePoint2D (x, y, Ang) -- Ang in radians
local Sa, Ca = sin(Ang), cos(Ang)
return x*Ca - y*Sa, x*Sa + y*Ca
end
local NX, NY, NZ = x, y, z
-- X
NZ, NY = RotatePoint2D (NZ, NY, -xrot)
-- Y
NX, NZ = RotatePoint2D (NX, NZ, -yrot)
-- Z
NY, NX = RotatePoint2D (NY, NX, -zrot)
return NX, NY, NZ
end
local function WrapAng(Ang)
local RAng = Ang
while RAng >= 360 do
RAng = RAng - 360
end
while RAng < 0 do
RAng = RAng + 360
end
return RAng
end
function ray_collision_test_init(e)
pickUppableEntity.Ent = nil
end
local function GetObjectSize(p)
p.l, p.h, p.w = 0, 0, 0
local Ent = g_Entity[p.Ent]
local x, y, z = Ent.x, Ent.y, Ent.z
local ax, ay, az = rad(Ent.anglex), rad(WrapAng(Ent.angley)), rad(Ent.anglez)
local xwi, yli, zwi = Rotate3D(1, 0, 0, ax, ay, az)
local xli, yli, zli = Rotate3D(0, 0, 1, ax, ay, az)
-- find height of object
local height = y + 1
local ignore = 0
local newx, newz = x + xwi, z + zwi
while IntersectAll(newx, height, newz, x, height, z, ignore) ~= p.Obj do
newx, newz = newx + xwi, newz + zwi
end
while IntersectAll(newx, height, newz, x, height, z, ignore) == p.Obj do
height = height + 10
end
while IntersectAll(newx, height, newz, x, height, z, ignore) ~= p.Obj do
height = height - 1
end
p.h = height - y + 1
local newy = y + height + 2
local stX, stZ = newx, newz
-- measure 'width'
local foundEdge = false
local fObj = 0
while not foundEdge do
fObj = IntersectAll(newx, newy, newz, newx, y, newz, ignore)
if fObj == p.Obj then
foundEdge = true
elseif fObj ~= nil and fObj ~= 0 then
ignore = fObj
else
newx, newz = newx - xwi, newz - zwi
end
end
foundEdge = false
ignore = 0
while not foundEdge do
fObj = IntersectAll(newx, newy, newz, newx, y, newz, ignore)
if fObj ~= p.Obj then
if fObj == nil or fObj == 0 then
foundEdge = true
else
ignore = fObj
end
else
newx, newz = newx - (xwi * 10), newz - (zwi * 10)
end
end
foundEdge = false
ignore = 0
while not foundEdge do
fObj = IntersectAll(newx, newy, newz, newx, y, newz, ignore)
if fObj == p.Obj then
foundEdge = true
elseif fObj ~= nil and fObj ~= 0 then
ignore = fObj
else
newx, newz = newx + xwi, newz + zwi
end
end
local xd, zd = newx - stX, newz - stZ
p.w = sqrt(xd*xd+zd*zd)
-- measure 'length'
newx, newz = x, z
foundEdge = false
ignore = 0
while not foundEdge do
fObj = IntersectAll(newx, newy, newz, newx, y, newz, ignore)
if fObj ~= p.Obj then
if fObj == nil or fObj == 0 then
foundEdge = true
else
ignore = fObj
end
else
newx, newz = newx - (xli * 10), newz - (zli * 10)
end
end
foundEdge = false
ignore = 0
while not foundEdge do
fObj = IntersectAll(newx, newy, newz, newx, y, newz, ignore)
if fObj == p.Obj then
foundEdge = true
elseif fObj ~= nil and fObj ~= 0 then
ignore = fObj
else
newx, newz = newx + xli, newz + zli
end
end
xd, zd = newx - x, newz - z
p.l = (sqrt(xd*xd+zd*zd) + 1) * 2
end
local function PrintDetails(p)
if p.l > p.w then
PromptLocal(p.Ent, p.Ent .. ", len=" .. p.l .. " width=" .. p.w .. " height=" .. p.h)
else
PromptLocal(p.Ent, p.Ent .. ", len=" .. p.w .. " width=" .. p.l .. " height=" .. p.h)
end
end
function ray_collision_test_main(e)
if pickUppableEntity.Ent ~= nil then
PrintDetails(pickUppableEntity)
end
-- Only check every 10th second
if not scheduler(e) then return end
local x, y, z = g_PlayerPosX, g_PlayerPosY + 35, g_PlayerPosZ
local rayX, rayY, rayZ = 0, 0, pickUpDistance
local paX, paY, paZ = rad(g_PlayerAngX), rad(g_PlayerAngY), rad(g_PlayerAngZ)
rayX, rayY, rayZ = Rotate3D(rayX, rayY, rayZ, paX, paY, paZ)
local Pobj = IntersectAll(x, y, z, x + rayX, y + rayY, z + rayZ, 0)
if Pobj ~= 0 then
for k,v in pairs(g_Entity) do
if v.obj == Pobj then
if pickUppableEntity.Ent ~= k then
pickUppableEntity = {Ent = k, Obj = Pobj, pickedUp = false}
GetObjectSize(pickUppableEntity)
end
return
end
end
end
pickUppableEntity.Ent = nil
end
-- Scheduler, this nifty little function keeps track of time. --
-- The main routine should be called every frame and returns --
-- a flag indicating whether the passed in time has expired --
-- since the last time it was called. --
-- If no time period is specified 100ms is used by default, --
-- i.e. 1/10th of a second. --
-- The caller can either ignore the return flag or use it to --
-- trigger time sensitive functionality. --
-- A global value giving the frames per second count is also --
-- generated, this can be used in script to make animations --
-- independent of frames. --
-- The reason this function is tied to an entity rather than --
-- being global is so that each entity can be triggered at a --
-- different time rather than all being triggered in the same --
-- frame.
g_scheduler = {}
function scheduler(e, period)
period = period or 100 -- defaults to tenths of a second (100ms)
if g_Time == nil then return false end
if g_scheduler[e] == nil then
g_scheduler[e] = {frames_per_second = 60,
period_accumulated = math.random(0, period),
accumulated_time = 0,
timer_value_last_frame = g_Time,
frame_counter = 0};
-- 'test' mode sometimes doesn't clear Lua globals so if
-- this appears to be the case initialise everything
elseif g_scheduler[e].accumulated_time > 2000 then
g_scheduler[e].frames_per_second = 60
g_scheduler[e].period_accumulated = math.random(0, period)
g_scheduler[e].accumulated_time = 0
g_scheduler[e].timer_value_last_frame = g_Time
g_scheduler[e].frame_counter = 0
end
local entry = g_scheduler[e]
local do_this_frame_flag = false
entry.frame_counter = entry.frame_counter + 1
local time_since_last_frame = g_Time - entry.timer_value_last_frame
if (entry.period_accumulated + time_since_last_frame) > period then
entry.period_accumulated = (entry.period_accumulated +
time_since_last_frame) - period;
do_this_frame_flag = true
else
entry.period_accumulated = entry.period_accumulated + time_since_last_frame
end
if (entry.accumulated_time + time_since_last_frame) > 1000 then -- more than a second passed?
entry.accumulated_time = (entry.accumulated_time +
time_since_last_frame) - 1000;
entry.frames_per_second = entry.frame_counter
entry.frame_counter = 0
else
entry.accumulated_time = entry.accumulated_time + time_since_last_frame
end
entry.timer_value_last_frame = entry.timer_value_last_frame + time_since_last_frame
return do_this_frame_flag
end
This script an experiment in ray-cast detection for moving objects in a game engine, all this code basically does is detect the size, shape, and location of an object, not as easy as you thought eh?
(note: there's actually quite a few mistakes on there, but only one that will make it completely fall down, the rest are intentional "mistakes" used as workarounds for testing.)