JK provides two "touched" messages: one sent to a thing's cog when another thing touches it, and one sent to a surface's cog when a thing touches it. If we wanted to detect when a player touches any wall surface, we could use the second "touched" message, but would have to link every surface to a cog. This seems like too much work. What would be nice is to have a "touched" message sent to the player's cog when the player touches any surface. The message would also have which surface the player touched.
Having searched through the edit and cog forums, it looks like this "touched" message has not been implemented by anyone. (If someone has attempted or successfully implemented this message or something similar, would you post the cog(s)?) For now, I present the latest version of my "touched" message kit.
Templates needed:
The cog used by the toucher_wpn template (the core of the implementation):
The 3do used by toucher_wpn template is a copy of ky.3do with the insert offset changed to:
The following code shows an example of usage:
Placed in a startup message (such as in kyle.cog):
Placed in kyle.cog:
Comments in the header of the thing_touch.cog explain the problems I have encountered. These problems might be the only ones remaining. If we find solutions to these problems, this new "touched" message should provide an easier way to implement other fun features in our levels.
Anyone think there is a better way? Anyone think this is crazy?
[This message has been edited by ZeqMacaw (edited August 12, 2004).]
Having searched through the edit and cog forums, it looks like this "touched" message has not been implemented by anyone. (If someone has attempted or successfully implemented this message or something similar, would you post the cog(s)?) For now, I present the latest version of my "touched" message kit.
Templates needed:
Code:
+toucher_exp none orient=(0.000000/0.000000/0.000000) type=explosion thingflags=0x1 damageclass=0x4 light=0.200000 timer=0.500000 typeflags=0x33 blasttime=0.300000 maxlight=0.400000 toucher_wpn none size=0.173778 movesize=0.17378 orient=(0/0/0) type=weapon collide=3 move=physics thingflags=0x20000400 cog=thing_touch.cog explode=+toucher_exp model3d=wp_touch.3do mass=0 physflags=0x200 typeflags=0x5
The cog used by the toucher_wpn template (the core of the implementation):
Code:
# thing_touch.cog # # Purpose: # - Allows a player's cog to receive a "touched" message when the # player touches a surface. # # Notes: # - Touch detection works as follows: # - Use a weapon template that uses an explosion template, a cog # (this one), a 3do (which corresponds to shape of player's 3do), and the # proper settings. # - Attach a thing (which uses the weapon template) to the player. # - Receive the "removed" message in the thing's cog. The message is sent # when the thing touches a surface. # - Surface index detection uses dot product to find distance between # player surface and each architecture surface in a sector. It does not test # surfaces upon which player is attached or surfaces that are not rendered. # - The "toucher" in this cog means the thing using the weapon template. # - Some stats for calculating player's surface position: # - z offset that visually looks right ingame: 0.13 # - insert offset of ky.3do: -0.000050 0.000000 0.120114 # - movesize of walkplayer: 0.065000 # - distance from walkplayer center to bottom of feet: # 0.120114 - 0.065000 = 0.055114 # - movesize of toucher_wpn: # did not work right: 0.065000 + (0.13 - 0.120114) = 0.074886 # currently using radius of ky.3do: 0.173779 # - radius of ky.3do: 0.173779 # # Problems: # - Adjustments are used to more accurately detect a touch because # toucher_wpn's collide=3 or its 3do is not working as expected. # - There is no known way to find if a surface is an adjoin surface. Want # to use GetSurfaceAdjoin() to avoid testing adjoin surfaces, but JK # crashes if used on non-adjoin surfaces. Currently, GetFaceGeoMode() is # used because adjoin surfaces will usually use geoMode = 0 (do not render). # - Surface index detection is wrong when the part of the player that is # touching surface is not in same sector as player's position. # - Sometimes the toucher becomes stuck even though player keeps moving. # This seems to occur at sector edges, probably while touching a surface. # - It would be nice if we only had to include this cog and the two templates # into a level, without changing them. Right now, we still have to change # the first param of SendMessageEx() to the correct cog number # (index in the jkl file + 1). We also need to include a 3do that # corresponds to the shape of the player. # - If, because of another mod, the player does not auto-attach, then the # touch is not detected below player's knees (using ky.3do). # # Testing: # - Use a separate thing attached to player for each major section of body, so # "removed" message will receive different senderRefs. This idea might also # help solve problem when toucher is across sector edges when touching. # # Written by ZeqMacaw 12-Aug-2004 # # Special thanks to Descent_pilot for posting his cog for detecting a surface # index. His method also used the dot product, but it was used differently. # #------------------------------------------------------------------------------ flags=0x240 symbols message startup message removed message timer int player local thing senderThing local vector position local int attachFlags local vector playerUpVector local sector sectorIndex local surface sectorSurfaceCount local surface sectorSurfaceIndex local surface surfaceIndex local int geoMode local vector surfaceNormal local flex playerCosineToSurface local vector surfaceCenter local flex distance local thing toucher local template toucher_tpl=toucher_wpn local end #------------------------------------------------------------------------------ code startup: Sleep(1); player = GetLocalPlayerThing(); jkStringClear(); jkStringConcatAsciiString("thing_touch startup"); jkStringConcatInt(player); jkStringOutput(-1, -1); return; removed: senderThing = GetSenderRef(); position = GetThingPos(player); attachFlags = GetAttachFlags(player); playerUpVector = GetThingUVec(player); sectorIndex = GetThingSector(player); sectorSurfaceCount = GetNumSectorSurfaces(sectorIndex); jkStringClear(); jkStringConcatAsciiString("["); jkStringConcatInt(sectorIndex); jkStringConcatAsciiString("] "); for (sectorSurfaceIndex = 0; sectorSurfaceIndex < sectorSurfaceCount; sectorSurfaceIndex = sectorSurfaceIndex + 1) { surfaceIndex = GetSectorSurfaceRef(sectorIndex, sectorSurfaceIndex); // Do not test a surface that is unrendered. geoMode = GetFaceGeoMode(surfaceIndex); if (geoMode != 0) { surfaceNormal = GetSurfaceNormal(surfaceIndex); playerCosineToSurface = VectorDot(surfaceNormal, playerUpVector); //jkStringConcatAsciiString("playerCosineToSurface = "); //jkStringConcatFlex(playerCosineToSurface); // Do not test a surface upon which player is attached. // Guessing 80 deg for surface angle upon which player can't // attach: cos(~80 deg) = ~0.17 if ( ((attachFlags & 0x1) == 0x0) || (((attachFlags & 0x1) == 0x1) && (playerCosineToSurface > -0.17) && (playerCosineToSurface < 0.17)) ) { // Calculate distance between toucher's position (same as // player's) and sector's surface. surfaceCenter = GetSurfaceCenter(surfaceIndex); distance = VectorDot(surfaceNormal, VectorSub(position, surfaceCenter)); if (distance < 0.075000) { //jkStringConcatFlex(distance); //jkStringConcatAsciiString(" "); SendMessageEx(1, touched, sectorSurfaceIndex, player, 3, 6); } } } } jkStringOutput(-1, -1); SetTimer(senderThing, 0.01); return; timer: // Attach a new "toucher" to player. position = VectorAdd(GetThingPos(player), '0.0 0.0 -0.01'); toucher = CreateThingAtPos(toucher_tpl, GetThingSector(player), position, '0.0 0.0 0.0'); SetThingLook(toucher, GetThingLVec(player)); AttachThingToThingEx(toucher, player, 0x4); return; end
The 3do used by toucher_wpn template is a copy of ky.3do with the insert offset changed to:
Code:
INSERT OFFSET 0.000000 0.000000 0.000000
The following code shows an example of usage:
Placed in a startup message (such as in kyle.cog):
Code:
// Place these in symbols section: // int player local // vector position local // thing toucher local // template toucher_tpl=toucher_wpn local Sleep(1); player = GetLocalPlayerThing(); // Attach "toucher" to player. position = VectorAdd(GetThingPos(player), '0.0 0.0 -0.01'); toucher = CreateThingAtPos(toucher_tpl, GetThingSector(player), position, '0.0 0.0 0.0'); SetThingLook(toucher, GetThingLVec(player)); AttachThingToThingEx(toucher, player, 0x4); // Using these for testing. // ClearPhysicsFlags(player, 0x40); // Disable auto-attaching to floors. SetPhysicsFlags(player, 0x2000); // Player can fly.
Placed in kyle.cog:
Code:
// Place this in symbol section: // message touched // surface sectorSurfaceIndex local touched: sectorSurfaceIndex = GetParam(1); jkStringClear(); jkStringConcatAsciiString(" <"); jkStringConcatInt(sectorSurfaceIndex); jkStringConcatAsciiString("> "); jkStringOutput(-1, -1); return;
Comments in the header of the thing_touch.cog explain the problems I have encountered. These problems might be the only ones remaining. If we find solutions to these problems, this new "touched" message should provide an easier way to implement other fun features in our levels.
Anyone think there is a better way? Anyone think this is crazy?
[This message has been edited by ZeqMacaw (edited August 12, 2004).]