Re-use of animation pushable block?
Re-use of animation pushable block?
It seems, the pushable block elements are hardcoded. At least I can't find them in the asset pack.
For sure, one can find the object definition, and the commands in the scripting reference, but not the animation- and sound definition. Especially the action "push" is nowhere declared.
I would like to re-use the pushable block concept - but in a complete different environment. Therefore it would be helpful to get a hand on that definitions to alter them. For sure it is possible to change the behaviour with some tweaks, but this has a it's limits.
Does someone has an idea how to do that?
For sure, one can find the object definition, and the commands in the scripting reference, but not the animation- and sound definition. Especially the action "push" is nowhere declared.
I would like to re-use the pushable block concept - but in a complete different environment. Therefore it would be helpful to get a hand on that definitions to alter them. For sure it is possible to change the behaviour with some tweaks, but this has a it's limits.
Does someone has an idea how to do that?
Re: Re-use of animation pushable block?
There's no animation involved with pushable blocks. The PushableBlockComponent just sets world position/rotation every frame for the hovering effect and pushing.
Grimrock 1 dungeon
Grimrock 2 resources
I no longer answer scripting questions in private messages. Please ask in a forum topic or this Discord server.
Grimrock 2 resources
I no longer answer scripting questions in private messages. Please ask in a forum topic or this Discord server.
- Duncan1246
- Posts: 404
- Joined: Mon Jan 19, 2015 7:42 pm
Re: Re-use of animation pushable block?
I am not sure of what you have in mind with "completely different environment" but it's easy to replace the model by another in the definition, so you can push absolutely anything you want.THOM wrote:I would like to re-use the pushable block concept - but in a complete different environment.
Does someone has an idea how to do that?
The Blue Monastery (LOG1)
download at:http://www.nexusmods.com/grimrock/mods/399/?
Finisterrae(LOG2)
download at:http://www.nexusmods.com/legendofgrimrock2/mods/61/?
download at:http://www.nexusmods.com/grimrock/mods/399/?
Finisterrae(LOG2)
download at:http://www.nexusmods.com/legendofgrimrock2/mods/61/?
Re: Re-use of animation pushable block?
Consider the code used in the "Elevator" demo: http://www.nexusmods.com/legendofgrimrock2/mods/10/?
I imagine that you would be doing something similar, only moving horizontally instead of vertically
I imagine that you would be doing something similar, only moving horizontally instead of vertically
Re: Re-use of animation pushable block?
Thank you all.
I will have a closer look at the elevator definition - maybe that's it...
@Duncan1246: I know that I can replace the model of the block by something else. But then you are alway connected to sound and floating animation of the block. If you want something different - and maybe more than one replacement, it becomes tricky.
But probably I have the solution now.
I will have a closer look at the elevator definition - maybe that's it...
@Duncan1246: I know that I can replace the model of the block by something else. But then you are alway connected to sound and floating animation of the block. If you want something different - and maybe more than one replacement, it becomes tricky.
But probably I have the solution now.
Re: Re-use of animation pushable block?
*sigh*
I am still trying to get my move-animation to work
what I got so far is a script-component in the object whose function will be triggered by a timer-component of the object.
Result of my script is, that the object is not moved until it has reached the moddle of the next grid-square but until the end of the whole map...
obviously I am doing something wrong with the triggering and/or the computing of the coordinates. but what?
I am still trying to get my move-animation to work
what I got so far is a script-component in the object whose function will be triggered by a timer-component of the object.
Result of my script is, that the object is not moved until it has reached the moddle of the next grid-square but until the end of the whole map...
obviously I am doing something wrong with the triggering and/or the computing of the coordinates. but what?
Code: Select all
function moveCart()
local lx = self.go.x
local ly = self.go.y
if party.facing == 0 then
ly = ly -0.01
if ly > self.go.y -1 then
self.go:setPosition(self.go.x, self.go.y-ly, self.go.facing, self.go.elevation, self.go.level)
else
self.go.movetimer:stop()
end
end
if party.facing == 1 then
lx = lx +0.01
if lx < self.go.x +1 then
self.go:setPosition(self.go.x+lx, self.go.y, self.go.facing, self.go.elevation, self.go.level)
else
self.go.movetimer:stop()
end
end
if party.facing == 2 then
ly = ly +0.01
if ly < self.go.y +1 then
self.go:setPosition(self.go.x, self.go.y+ly, self.go.facing, self.go.elevation, self.go.level)
else
self.go.movetimer:stop()
end
end
if party.facing == 3 then
lx = lx -0.01
if lx > self.go.x -1 then
self.go:setPosition(self.go.x-lx, self.go.y, self.go.facing, self.go.elevation, self.go.level)
else
self.go.movetimer:stop()
end
end
endRe: Re-use of animation pushable block?
Lots of problems with this.
1. Using non-integer values for map position. You should use setWorldPosition() for that.
2. Not accounting for variable framerate. You should use Time.deltaTime() to move the object by the correct amount each frame.
3. Using party facing when it can clearly change in the middle of everything.
This is my object transformation code atm, lots of stuff is unfinished (rotation is unfinished, callbackpos in moveObjectDistance is unimplemented, callbacks are not called in the correct order) but it will accomplish what you are trying to do. The function you're interested in is moveObjectDistance(). You need to call update() once every frame; just use a TimerComponent on the party object with an interval like 0.00001, since timers only trigger once per frame at most.
The only functions you should call externally are:
- the functions in the "Simple stuff" section
- update() ONCE every frame
- translate(), rotate(), and scale() if you want instant translation/rotation/scaling
- moveObjectDistance() and rotateAngles() if you want smooth translation/rotation
Example call:
This moves the object "gazingStatue" 8 meters down at a speed of 1.6 m/s, and at the end, calls destroyStatue with the gazingStatue object as the only argument. Note that callbacks are referenced from the script with the translation code, which means that you should never try to use the local environment, only the function's arguments and global variables (here's why).
edit: updated with bug fix, huge thanks to alois for finding the bug!
1. Using non-integer values for map position. You should use setWorldPosition() for that.
2. Not accounting for variable framerate. You should use Time.deltaTime() to move the object by the correct amount each frame.
3. Using party facing when it can clearly change in the middle of everything.
This is my object transformation code atm, lots of stuff is unfinished (rotation is unfinished, callbackpos in moveObjectDistance is unimplemented, callbacks are not called in the correct order) but it will accomplish what you are trying to do. The function you're interested in is moveObjectDistance(). You need to call update() once every frame; just use a TimerComponent on the party object with an interval like 0.00001, since timers only trigger once per frame at most.
The only functions you should call externally are:
- the functions in the "Simple stuff" section
- update() ONCE every frame
- translate(), rotate(), and scale() if you want instant translation/rotation/scaling
- moveObjectDistance() and rotateAngles() if you want smooth translation/rotation
Code: Select all
-- Get rotation matrices that we can use for temporary storage. Here are some
-- properties of rotation matrices in Grimrock that you may not expect:
-- - GameObject:getWorldRotation() returns a COPY.
-- - According to a grimrock.net blog post, there's a "pool" of matrices so that
-- new ones aren't constantly being allocated.
-- To get away with these two matrices, we must follow a specific discipline:
-- assume scratchMatrix is invalidated after you call any function EXCEPT
-- for matrixMultiply.
scratchMatrix = {x={},y={},z={},w={}}
do
local s = self.go:getWorldRotation()
for c=1,4 do
scratchMatrix.x[c] = s.x[c]
scratchMatrix.y[c] = s.y[c]
scratchMatrix.z[c] = s.z[c]
scratchMatrix.w[c] = s.w[c]
end
end
--------------------------------------------------------------------------------
-- SIMPLE STUFF (spawn, destroy, set non-world position, etc.)
--------------------------------------------------------------------------------
-- spawn entity name at same position as on with id id
function spawnOn(on,name,id)
return spawn(name,on.level,on.x,on.y,on.facing,on.elevation,id)
end
-- spawn entity name at same position *and* world position as on with id id
function spawnOnExact(on,name,id)
local spawned = spawn(name,on.level,on.x,on.y,on.facing,on.elevation,id)
spawned:setWorldPosition(on:getWorldPosition())
return spawned
end
-- spawn entity name at same position *and* world position *and* world rotation as on with id id
function spawnOnExactWithRotation(on,name,id)
local spawned = spawn(name,on.level,on.x,on.y,on.facing,on.elevation,id)
spawned:setWorldPosition(on:getWorldPosition())
spawned:setWorldRotation(on:getWorldRotation())
return spawned
end
-- set world position taking a table instead of a vector
function setWorldPositionTable(gameObject,position)
gameObject:setWorldPosition(vec(position[1],position[2],position[3],position[4] or 0))
end
-- a version of setDoorState that...actually works
-- TODO: obsolete in 2.1.19, lol
function safeSetDoorState(gameObject,doorComponentName,state)
local door = gameObject[doorComponentName]
if state == "closed" then
local closeSound, closeVelocity, lockSound = door:getCloseSound(), door:getCloseVelocity(), door:getLockSound()
door:setCloseSound("silence") door:setCloseVelocity(-math.huge) door:setLockSound("silence")
door.go.controller:close()
game.frame.callNextFrame(safeSetDoorStateCleanup,{gameObject.id,doorComponentName,state,closeSound,closeVelocity,lockSound})
elseif state == "open" then
local openSound, openVelocity, lockSound = door:getOpenSound(), door:getOpenVelocity(), door:getLockSound()
door:setOpenSound("silence") door:setOpenVelocity(math.huge) door:setLockSound("silence")
door.go.controller:open()
game.frame.callNextFrame(safeSetDoorStateCleanup,{gameObject.id,doorComponentName,state,openSound,openVelocity,lockSound})
else
debug.exceptions.err("invalid door state ("..state..") in safeSetDoorState for "..gameObject.id.."."..doorComponentName)
end
end
function safeSetDoorStateCleanup(gameObjectId, doorComponentName, state, sound, velocity, lockSound)
local door = findEntity(gameObjectId)[doorComponentName]
door:setLockSound(lockSound)
if state == "closed" then
door:setCloseSound(sound) door:setCloseVelocity(velocity)
elseif state == "open" then
door:setOpenSound(sound) door:setOpenVelocity(velocity)
else
debug.exceptions.err("invalid door state ("..state..") in safeSetDoorStateCleanup for "..gameObjectId.."."..doorComponentName)
end
end
function setFacing(gobj,facing)
gobj:setPosition(gobj.x,gobj.y,facing,gobj.elevation,gobj.level)
end
function setX(gobj,x)
gobj:setPosition(x,gobj.y,gobj.facing,gobj.elevation,gobj.level)
end
function setY(gobj,y)
gobj:setPosition(gobj.x,y,gobj.facing,gobj.elevation,gobj.level)
end
function setElevation(gobj,e)
gobj:setPosition(gobj.x,gobj.y,gobj.facing,e,gobj.level)
end
-- like setPosition but leave arguments nil to keep original position
function setPositionPartial(gobj,x,y,facing,elevation,level)
gobj:setPosition(x or gobj.x,y or gobj.y,facing or gobj.facing,elevation or gobj.elevation,level or gobj.level)
end
-- call gobj:destroy()
function destroy(gobj)
gobj:destroy()
end
-- call gobj:destroy() and return true if gobj is not nil or false
-- do nothing and return false if gobj is nil or false
function safeDestroy(gobj)
if gobj then
gobj:destroy()
return true
else
return false
end
end
--------------------------------------------------------------------------------
-- TRANSFORMATION
--------------------------------------------------------------------------------
-- These functions are aimed at translating, rotating, and scaling GameObjects.
-- They change only world position and world rotation.
-- Performance here is not especially good, particularly for rotation, so don't
-- use on too many objects at once.
X = 1
Y = 2
Z = 3
W = 4
-- Table of moving GameObjects and corresponding data.
gameObjects = {}
-- Translate a game object's world position.
-- TODO: call callbacks in correct order.
function translate(gobj, x, y, z)
local pos = gobj:getWorldPosition()
local gid = gobj.id
local gData = gameObjects[gid]
local nx = pos[X]+(x or 0)
local ny = pos[Y]+(y or 0)
local nz = pos[Z]+(z or 0)
if gData then
local e = gData.endpoints
local v = gData.velocities
local c = gData.callbacks
local callx = false
local cally = false
local callz = false
if e then
-- reaching an endpoint; velocityCleanup will handle the rest
if e[X] and ((pos[X] <= e[X] and e[X] <= nx) or (pos[X] >= e[X] and e[X] >= nx)) then
nx = e[X]
if v then
v[X] = nil
if c and c[X] then
callx = true
end
end
end
if e[Y] and ((pos[Y] <= e[Y] and e[Y] <= ny) or (pos[Y] >= e[Y] and e[Y] >= ny)) then
ny = e[Y]
if v then
v[Y] = nil
if c and c[Y] then
cally = true
end
end
end
if e[Z] and ((pos[Z] <= e[Z] and e[Z] <= nz) or (pos[Z] >= e[Z] and e[Z] >= nz)) then
nz = e[Z]
if v then
v[Z] = nil
if c and c[Z] then
callz = true
end
end
end
end
gobj:setWorldPosition(vec(nx,ny,nz,pos[4]))
if callx then
c[X][1](gobj,c[X][2]) -- call callback with args
c[X] = nil
end
if cally then
c[Y][1](gobj,c[Y][2]) -- call callback with args
c[Y] = nil
end
if callz then
c[Z][1](gobj,c[Z][2]) -- call callback with args
c[Z] = nil
end
else -- if we dont have to worry about endpoints or callbacks, the code is somewhat shorter.
gobj:setWorldPosition(vec(nx,ny,nz,pos[4]))
end
end
-- Update moving objects. Should be called once per frame.
function update()
local dtime = Time.deltaTime()
for gobjId,data in pairs(gameObjects) do
local d = {[X]=0,[Y]=0,[Z]=0}
local ad = {[X]=nil,[Y]=nil,[Z]=nil}
local v = data.velocities
local a = data.accelerations
local av = data.angularVelocities
for dim = X, Z do
if v and v[dim] then
if a and a[dim] then
-- In case you failed both physics and calculus, this formula will
-- only work for constant acceleration.
d[dim] = (v[dim]+0.5*a[dim]*dtime)*dtime
v[dim] = v[dim]+a[dim]*dtime
else
d[dim] = v[dim]*dtime
end
end
if av and av[dim] then
ad[dim] = av[dim]*dtime
end
end
if v then translate(findEntity(gobjId),d[X],d[Y],d[Z]) end
if av then rotate(findEntity(gobjId),ad[X],ad[Y],ad[Z]) end
velocityCleanup(gobjId)
end
end
-- Here's where things get kind of sucky. I do not know of any way to create new
-- matrices other than acquiring them via GameObject:getWorldRotation(), which
-- creates a new copy of the matrix every time.
-- TODO: call callbacks in correct order
function rotate(gobj,dX,dY,dZ)
local gid = gobj.id
local gData = gameObjects[gid]
local mat = gobj:getWorldRotation()
local av = gData and gData.angularVelocities
local adr = gData and gData.angularDistanceRemaining
local c = gData and gData.angularCallbacks
local callx = false
local cally = false
local callz = false
if dX then
if adr then
local remaining = adr[X]
if remaining then
if (dX >= 0 and dY >= remaining) or (dY < 0 and dY <= remaining) then
dX = remaining
adr[X] = nil
av[X] = nil
if c and c[X] then
callx = true
end
else
adr[X] = remaining-dX
end
end
end
createRotationMatrixX(scratchMatrix,dX)
matrixMultiply(mat,scratchMatrix)
end
if dY then
if adr then
local remaining = adr[Y]
if remaining then
if (dY >= 0 and dY >= remaining) or (dY < 0 and dY <= remaining) then
dY = remaining
adr[Y] = nil
av[Y] = nil
if c and c[Y] then
cally = true
end
else
adr[Y] = remaining-dY
end
end
end
createRotationMatrixY(scratchMatrix,dY)
matrixMultiply(mat,scratchMatrix)
end
if dZ then
if adr then
local remaining = adr[Z]
if remaining then
if (dZ >= 0 and dZ >= remaining) or (dZ < 0 and dZ <= remaining) then
dZ = remaining
adr[Z] = nil
av[Z] = nil
if c and c[Z] then
callz = true
end
else
adr[Z] = remaining-dZ
end
end
end
createRotationMatrixZ(scratchMatrix,dZ)
matrixMultiply(mat,scratchMatrix)
end
gobj:setWorldRotation(mat)
if callx then
c[X][1](gobj,c[X][2]) -- call callback with args
c[X] = nil
end
if cally then
c[Y][1](gobj,c[Y][2]) -- call callback with args
c[Y] = nil
end
if callz then
c[Z][1](gobj,c[Z][2]) -- call callback with args
c[Z] = nil
end
end
function scale(gobj,dX,dY,dZ)
local gid = gobj.id
local gData = gameObjects[gid]
local mat = gobj:getWorldRotation()
scratchMatrix.x[1] = dX
scratchMatrix.x[2] = 0
scratchMatrix.x[3] = 0
scratchMatrix.x[4] = 0
scratchMatrix.y[1] = 0
scratchMatrix.y[2] = dY
scratchMatrix.y[3] = 0
scratchMatrix.y[4] = 0
scratchMatrix.z[1] = 0
scratchMatrix.z[2] = 0
scratchMatrix.z[3] = dZ
scratchMatrix.z[4] = 0
scratchMatrix.w[1] = 0
scratchMatrix.w[2] = 0
scratchMatrix.w[3] = 0
scratchMatrix.w[4] = 1
matrixMultiply(mat,scratchMatrix)
gobj:setWorldRotation(mat)
end
-- Set angular velocity of an object. x/y/z can be nil or 0 to leave alone.
function setAngularVelocity(gobj,x,y,z)
local gobjId = gobj.id
if not gameObjects[gobjId] then gameObjects[gobjId] = {} end
local gData = gameObjects[gobjId]
if not gData.angularVelocities then
local hasX = x and x ~= 0
local hasY = y and y ~= 0
local hasZ = z and z ~= 0
if hasX or hasY or hasZ then
gData.angularVelocities = {
[X]=hasX and x,
[Y]=hasY and y,
[Z]=hasZ and z
}
end
else
gData.angularVelocities[X] = x
gData.angularVelocities[Y] = y
gData.angularVelocities[Z] = z
end
end
-- Set angular distance remaining of an object. x/y/z can be nil or 0 to leave alone.
function setAngularDistanceRemaining(gobj,x,y,z)
local gobjId = gobj.id
local gData = gameObjects[gobjId]
if not gData.angularDistanceRemaining then
local hasX = x and x ~= 0
local hasY = y and y ~= 0
local hasZ = z and z ~= 0
if hasX or hasY or hasZ then
gData.angularDistanceRemaining = {
[X]=hasX and x,
[Y]=hasY and y,
[Z]=hasZ and z
}
end
else
gData.angularDistanceRemaining[X] = x
gData.angularDistanceRemaining[Y] = y
gData.angularDistanceRemaining[Z] = z
end
end
function createRotationMatrixX(mat, angle)
local sin = math.sin(angle)
local cos = math.cos(angle)
mat.x[1] = 1
mat.x[2] = 0
mat.x[3] = 0
mat.y[1] = 0
mat.y[2] = cos
mat.y[3] = sin
mat.z[1] = 0
mat.z[2] = -sin
mat.z[3] = cos
--return mat
end
function createRotationMatrixY(mat, angle)
local sin = math.sin(angle)
local cos = math.cos(angle)
mat.x[1] = cos
mat.x[2] = 0
mat.x[3] = -sin
mat.y[1] = 0
mat.y[2] = 1
mat.y[3] = 0
mat.z[1] = sin
mat.z[2] = 0
mat.z[3] = cos
--return mat
end
function createRotationMatrixZ(mat, angle)
local sin = math.sin(angle)
local cos = math.cos(angle)
mat.x[1] = cos
mat.x[2] = sin
mat.x[3] = 0
mat.y[1] = -sin
mat.y[2] = cos
mat.y[3] = 0
mat.z[1] = 0
mat.z[2] = 0
mat.z[3] = 1
--return mat
end
-- multiply 4x4 matrices (or tables) mat1 and mat2, place result in mat1
-- mat2 will be unchanged
function matrixMultiply(mat1,mat2)
-- XXX: I'm sure this can be optimized better, but it's Lua so using the
-- "good" algorithms may not help.
-- currently the final column is not copied since as soon as it's
-- overwritten, the original is no longer needed; we could, of course,
-- save on storage by making more assignments...
-- These are intentionally permanent variables. Why? This function is
-- called EXTREMELY often. (That's also why we don't use a table.) This
-- code is virtually impossible to profile, but based on my limited
-- knowledge of LuaJIT I am around 90% sure this is faster than using
-- temporary variables in this case.
scratchx1 = mat1.x[1]
scratchx2 = mat1.x[2]
scratchx3 = mat1.x[3]
scratchy1 = mat1.y[1]
scratchy2 = mat1.y[2]
scratchy3 = mat1.y[3]
scratchz1 = mat1.z[1]
scratchz2 = mat1.z[2]
scratchz3 = mat1.z[3]
scratchw1 = mat1.w[1]
scratchw2 = mat1.w[2]
scratchw3 = mat1.w[3]
for i = 1,4 do
mat1.x[i] = scratchx1 * mat2.x[i]
+ scratchx2 * mat2.y[i]
+ scratchx3 * mat2.z[i]
+ mat1.x[4] * mat2.w[i]
mat1.y[i] = scratchy1 * mat2.x[i]
+ scratchy2 * mat2.y[i]
+ scratchy3 * mat2.z[i]
+ mat1.y[4] * mat2.w[i]
mat1.z[i] = scratchz1 * mat2.x[i]
+ scratchz2 * mat2.y[i]
+ scratchz3 * mat2.z[i]
+ mat1.z[4] * mat2.w[i]
mat1.w[i] = scratchw1 * mat2.x[i]
+ scratchw2 * mat2.y[i]
+ scratchw3 * mat2.z[i]
+ mat1.w[4] * mat2.w[i]
end
--return mat1
end
-- Set velocity of an object. x/y/z can be nil to leave alone.
function setVelocity(gobj,x,y,z)
local gobjId = gobj.id
if not gameObjects[gobjId] then gameObjects[gobjId] = {} end
local gData = gameObjects[gobjId]
if not gData.velocities then
local hasX = x and x ~= 0
local hasY = y and y ~= 0
local hasZ = z and z ~= 0
if hasX or hasY or hasZ then
gData.velocities = {
[X]=hasX and x or nil,
[Y]=hasY and y or nil,
[Z]=hasZ and z or nil
}
end
else
gData.velocities[X] = x
gData.velocities[Y] = y
gData.velocities[Z] = z
velocityCleanup(gobjId)
end
end
-- Modify velocity of an object. x/y/z can be 0 to leave alone.
function modifyVelocity(gobj,x,y,z)
local gobjId = gobj.id
if not gameObjects[gobjId] then gameObjects[gobjId] = {} end
local gData = gameObjects[gobjId]
if not gData.velocities then
local hasX = x ~= 0
local hasY = y ~= 0
local hasZ = z ~= 0
if hasX or hasY or hasZ then
gData.velocities = {
[X]=hasX and x or nil,
[Y]=hasY and y or nil,
[Z]=hasZ and z or nil
}
end
else
gData.velocities[X] = (gData.velocities[X] or 0)+x
gData.velocities[Y] = (gData.velocities[Y] or 0)+y
gData.velocities[Z] = (gData.velocities[Z] or 0)+z
velocityCleanup(gobjId)
end
end
-- Move an object a certain distance on each axis with specified velocities,
-- canceling any existing movement *and canceling existing callbacks without calling them*.
-- gobj: object to move
-- move: table with info about how to move the object. Supports the following fields:
-- dx, dy, dz: distance to move each axis (can be nil)
-- vx, vy, vz: velocity to move each axis (sign should match corresponding distance)
-- callbackx, callbacky, callbackz: functions to call when finished moving on axis (can be nil), first argument passed will be the object
-- callbackxargs, callbackyargs, callbackzargs: additional arguments to pass to callbacks (can be nil)
-- callbackpos: function to call when object's map position changes (can be nil), i.e. it crosses a tile boundary, first argument passed will be the object,
-- then the object's *previous* x,y,elevation as the second, third, and fourth arguments.
-- callbackposargs: additional arguments to pass to callbackpos (can be nil)
function moveObjectDistance(gobj,move)
local gobjId = gobj.id
setVelocity(gobj,move.vx,move.vy,move.vz)
setEndpointsDelta(gobj,move.dx,move.dy,move.dz)
gameObjects[gobjId].accelerations = nil
if (move.dx and move.callbackx) or (move.dy and move.callbacky) or (move.dz and move.callbackz) or (move.callbackpos) then
gameObjects[gobjId].callbacks = {[X] = {move.callbackx,move.callbackxargs}, [Y] = {move.callbacky,move.callbackyargs}, [Z] = {move.callbackz,move.callbackzargs}, ["callbackpos"] = {move.callbackpos,move.callbackposargs}}
else
gameObjects[gobjId].callbacks = nil -- clear existing
end
end
-- WARNING XXX TODO NOTE ETC: the whole rotation code is completely broken
-- TODO: make this not completely useless for multiple axes (the framerate will change the
-- rotation as the axes are applied individually).
-- Rotate an object a certain distance (degrees) on each axis with specified velocities,
-- canceling any existing rotation.
-- Note that currently this is pretty inefficient, so don't rotate too many objects at once.
-- gobj: object to move
-- dx, dy, dz: angle to rotate each axis
-- tx, ty, tz: time for rotation on each axis to complete
-- callbackx, callbacky, callbackz: functions to call when finished moving on axis (can be nil), first argument passed will be the object
-- callbackxargs, callbackyargs, callbackzargs: additional arguments to pass to callbacks (can be nil)
function rotateAngles(gobj,dx,dy,dz,tx,ty,tz,callbackx,callbackxargs,callbacky,callbackyargs,callbackz,callbackzargs)
local gobjId = gobj.id
local avx = nil
local avy = nil
local avz = nil
if dx then avx = dx/tx end
if dy then avy = dy/ty end
if dz then avz = dz/tz end
setAngularVelocity(gobj,avx,avy,avz)
setAngularDistanceRemaining(gobj,dx,dy,dz)
velocityCleanup(gobjId)
if (dx and callbackx) or (dy and callbacky) or (dz and callbackz) then
gameObjects[gobjId].angularCallbacks = {[X] = {callbackx,callbackxargs}, [Y] = {callbacky,callbackyargs}, [Z] = {callbackz,callbackzargs}}
end
end
-- Set the endpoints of an object relative to its current position. Cancels
-- existing endpoints.
function setEndpointsDelta(gobj,dx,dy,dz)
local pos = gobj:getWorldPosition()
local points = {
[X] = (dx and dx ~= 0 and pos[X]+dx) or nil,
[Y] = (dy and dy ~= 0 and pos[Y]+dy) or nil,
[Z] = (dz and dz ~= 0 and pos[Z]+dz) or nil
}
if not gameObjects[gobj.id] then
gameObjects[gobj.id] = {endpoints = points}
else
gameObjects[gobj.id].endpoints = points
end
end
-- remove 0 velocities and corresponding endpoints
-- if channel has no or 0 velocity and no acceleration, will be removed
-- if all channels removed, object is freed
function velocityCleanup(gobjId)
local gData = gameObjects[gobjId]
if gData and findEntity(gobjId) then
local v = gData.velocities
local a = gData.accelerations
local av = gData.angularVelocities
if av then
local e = gData.angularDistanceRemaining
for i = X, Z do
if (not av[i]) or av[i] == 0 then
av[i] = nil
if e then e[i] = nil end
end
end
if not (av[X] or av[Y] or av[Z]) then
gData.angularVelocities = nil
gData.angularDistanceRemaining = nil
if not v then
gameObjects[gobjId] = nil
end
end
end
if v and not a then
local e = gData.endpoints
for i = X, Z do
if (not v[i]) or v[i] == 0 then
v[i] = nil
if e then e[i] = nil end
end
end
if not (v[X] or v[Y] or v[Z]) then
gData.velocities = nil
if not gData.angularVelocities then
gameObjects[gobjId] = nil
end
end
end
else
gameObjects[gobjId] = nil
end
endCode: Select all
gobj.script.moveObjectDistance(gazingStatue,{dy=-8,vy=-1.6,callbacky=destroyStatue})Code: Select all
-- WARNING: THIS FUNCTION IS REFERENCED FROM gobj.script. DO NOT USE
-- LOCAL ENVIRONMENT.
function destroyStatue(statue)
statue:destroy()
endedit: updated with bug fix, huge thanks to alois for finding the bug!
Last edited by minmay on Sat Oct 24, 2015 7:28 am, edited 1 time in total.
Grimrock 1 dungeon
Grimrock 2 resources
I no longer answer scripting questions in private messages. Please ask in a forum topic or this Discord server.
Grimrock 2 resources
I no longer answer scripting questions in private messages. Please ask in a forum topic or this Discord server.
Re: Re-use of animation pushable block?
Hey minmay - finally I found the time to have a look at your script. Thanks for that.
I've copied over the update and the moveObjectDistance function, added a timer (to my object). But when I trigger the update-function I get the error "bad argument #1 to 'pairs' (table expected, got nil)."
I've copied over the update and the moveObjectDistance function, added a timer (to my object). But when I trigger the update-function I get the error "bad argument #1 to 'pairs' (table expected, got nil)."
Re: Re-use of animation pushable block?
Because you only copied one function instead of the whole script...if you actually look at the functions, you'll see they call a lot of other functions and use some persistent data. I pasted the whole script because you need the whole script to do object transformation. (Well, you don't need the "SIMPLE STUFF" section, but you need the rest.)
Grimrock 1 dungeon
Grimrock 2 resources
I no longer answer scripting questions in private messages. Please ask in a forum topic or this Discord server.
Grimrock 2 resources
I no longer answer scripting questions in private messages. Please ask in a forum topic or this Discord server.
Re: Re-use of animation pushable block?
aaah - yes! I hoped, I could save unused stuff. my mod is packed enough... (and I havn't implemented grimTK, yet...)
[and I couldn't find a command "pairs" in the rest of the script - therefore I thought I didn't leave out something important.]
well - now it works all in all, but the command moveObjectDistance(self.go,{dy=-3,vy=-1.6, moves the object down. What do I have to use if I want the object to move horizontally?
[and I couldn't find a command "pairs" in the rest of the script - therefore I thought I didn't leave out something important.]
well - now it works all in all, but the command moveObjectDistance(self.go,{dy=-3,vy=-1.6, moves the object down. What do I have to use if I want the object to move horizontally?