Building Walls
Blitz3D Forums/Blitz3D Programming/Building Walls
| ||
I am trying to add the ability to construct walls in straight lines along a terrain. The walls are to be placed when holding down the mouse button and dragging along on the terrain to determine the length of the wall. The walls are only placed parallel to the global coordinate axes. The wall unit dimensions are multiples of units, so the positioning can be rounded to the nearest units. Essentially, think of the SIM city 'road' positioning, or, if anyone knows of it, wall/fence construction in the game "Warrior Kings" - I'm sure there's plenty of other examples... I'm controlling whether or not a wall is in progress with some global variables. The actual camerapick coordinates on the terrain etc. are working since I use the saame routines for terrain manipulation. The real problems I have is actually in determining the lengths and scaling of the wall. I have a function to distinguish and simplify the direction of the walls into whether horizontal or vertical: ;RETURNS TRUE IF X and Y COORDINATES ARE APPROXIMATELY ALIGNED TO oY AXIS Function nb_MATH_GetIsCoordinateAlignment(f_oX#,f_oY#,f_X#,f_Y#) If (f_oX=f_X) Return True If (f_oY=f_Y) Return False Local f_Orientation#=Abs(((ATan2(f_X-f_oX,f_y-f_oY) )) ) Local nb_Binary=( (f_Orientation>135) Or (f_Orientation<45) ) Return nb_Binary End function The real problem is actually with the scaling, and whether Blitz seems to want to scale absolutely or relatively and to maintain a consistent origin for the walls. I've tried a number of different approaches, but just can't seem to get it to work. I'd really appreciate if anyone has any suggestions or recommendations on how this ought to be approached. Currently the main function (still not working, with a few attempted 'fixes' or original tries, still present but commented: [code] Function v_CON_PlaceWall() If (nb_TRN_MousePickTerrain()) Local X=PickedX() Local Z=PickedZ() Local Y=TerrainY(thtr_TRN_TERRAIN,X,0,Z) DebugLog("CON (Place Wall): Picked "+Str(X)+" , "+Str(Y)) X=Floor(X) Y=Floor(Y) Z=Floor(Z) If (Not(gh3d_CON_PROPOSAL)) DebugLog("CON (Place Wall): No current proposal.") gh3d_CON_PROPOSAL=CreateCube();CopyEntity(th3d_CON_WALLMESH_TEMPLATE) PositionEntity gh3d_CON_PROPOSAL,X,Y,Z,True gn_CON_WALL_INIT_X=X gn_CON_WALL_INIT_Y=Y gn_CON_WALL_INIT_Z=Z DebugLog("CON (Place Wall): Proposal created at "+Str(gn_CON_WALL_INIT_X)+" , "+Str(gn_CON_WALL_INIT_Z)+" Altitude: "+Str(gn_CON_WALL_INIT_Y)) Return Else ; FreeEntity gh3d_CON_PROPOSAL ; gh3d_CON_PROPOSAL=CopyEntity(th3d_CON_WALLMESH_TEMPLATE) ; PositionEntity gh3d_CON_PROPOSAL,gn_CON_WALL_INIT_X,gn_CON_WALL_INIT_Y,gn_CON_WALL_INIT_Z,True End If Local Orient=nb_MATH_GetIsCoordinateAlignment(gn_CON_WALL_INIT_X,gn_CON_WALL_INIT_Z,X,Z) ;Z=(Z*(1-Orient))-gn_CON_WALL_INIT_X ;X=(X*(Orient))-gn_CON_WALL_INIT_Z If (Orient) DebugLog("CON (Place Wall): Aligned with proposal on Z axis") ;ScaleEntity gh3d_CON_PROPOSAL,cf_CON_WALLMESH_UNITWIDTH,cf_CON_WALLMESH_UNITHEIGHT,Z,True ScaleMesh gh3d_CON_PROPOSAL,cf_CON_WALLMESH_UNITWIDTH,cf_CON_WALLMESH_UNITHEIGHT,Z DebugLog("CON (Place Wall): Scaled to: "+Str(MeshWidth(gh3d_CON_PROPOSAL)+" , "+Str(MeshHeight(gh3d_CON_PROPOSAL))+" , "+Str(MeshDepth(gh3d_CON_PROPOSAL)))) Else DebugLog("CON (Place Wall): Aligned with proposal on X axis") ;ScaleEntity gh3d_CON_PROPOSAL,cf_CON_WALLMESH_UNITWIDTH,cf_CON_WALLMESH_UNITHEIGHT,Z,True ScaleMesh gh3d_CON_PROPOSAL,X,cf_CON_WALLMESH_UNITHEIGHT,cf_CON_WALLMESH_UNITDEPTH DebugLog("CON (Place Wall): Scaled to: "+Str(MeshWidth(gh3d_CON_PROPOSAL)+" , "+Str(MeshHeight(gh3d_CON_PROPOSAL))+" , "+Str(MeshDepth(gh3d_CON_PROPOSAL)))) End If End If End Function |
| ||
You might be mixing up ScaleEntity and ScaleMesh. A cube has vertices in eight locations. The default vertices are (1,1,1), (1,1,-1) etc. ScaleEntity does not change this. It temporarily multiplies coordinates by some scale factor before doing rendering and collision detection. There is no change to the underlying mesh. If you scale an entity by a factor of two, and then by a factor of three the end result is scaling by three. ScaleMesh actually changes coordinates. Thus if you ScaleMesh by a factor of two and then by a factor of three you have actually multiplied everything by six. |
| ||
Yeah I read that, and have tried with both commands. This executable code based on the above can highlight the problem better: ___ edit: Okay I've got a slightly better idea of the root of the problem now. I think it seems to be that the mesh is scaled around a central point, rather being extended from that point. I think I'll need to use FitMesh() or something? Or the "Laser" beam code in the archives which projected a mesh from point A to point B Pretty sure I'm on the right lines... Graphics3D 800,600,32,2 SetBuffer BackBuffer() Global Cam=CreateCamera() MoveEntity Cam,0,1,0 TurnEntity Cam,0,-45,0 AmbientLight 128,128,128 Global T=CreateTerrain(128) EntityPickMode T,2 Global gh3d_CON_PROPOSAL Global gn_CON_WALL_INIT_X Global gn_CON_WALL_INIT_y Global gn_CON_WALL_INIT_z While (Not(KeyDown(1))) If MouseDown(1) v_CON_PlaceWall Else FreeEntity gh3d_CON_PROPOSAL gh3d_CON_PROPOSAL=0 End If RenderWorld Flip Wend ;RETURNS TRUE IF X and Y COORDINATES ARE APPROXIMATELY ALIGNED TO oY AXIS Function nb_MATH_GetIsCoordinateAlignment(f_oX#,f_oY#,f_X#,f_Y#) If (f_oX=f_X) Return True If (f_oY=f_Y) Return False Local f_Orientation#=Abs(((ATan2(f_X-f_oX,f_Y-f_oY) )) ) Local nb_Binary=( (f_Orientation>135) Or (f_Orientation<45) ) Return nb_Binary End Function Function nb_TRN_MousepickTerrain() Return (CameraPick(Cam,MouseX(),MouseY())=T) End Function Function v_CON_PlaceWall() If (nb_TRN_MousepickTerrain()) Local X=PickedX() Local Z=PickedZ() Local Y=TerrainY(T,X,0,Z) DebugLog("CON (Place Wall): Picked "+Str(X)+" , "+Str(Y)) X=Floor(X) Y=Floor(Y) Z=Floor(Z) If (Not(gh3d_CON_PROPOSAL)) DebugLog("CON (Place Wall): No current proposal.") gh3d_CON_PROPOSAL=CreateCube();CopyEntity(th3d_CON_WALLMESH_TEMPLATE) EntityColor gh3d_CON_PROPOSAL,255,0,0 EntityAlpha gh3d_CON_PROPOSAL,0.5 PositionEntity gh3d_CON_PROPOSAL,X,Y,Z,True gn_CON_WALL_INIT_X=X gn_CON_WALL_INIT_y=Y gn_CON_WALL_INIT_z=Z DebugLog("CON (Place Wall): Proposal created at "+Str(gn_CON_WALL_INIT_X)+" , "+Str(gn_CON_WALL_INIT_z)+" Altitude: "+Str(gn_CON_WALL_INIT_y)) Return Else ; FreeEntity gh3d_CON_PROPOSAL ; gh3d_CON_PROPOSAL=CopyEntity(th3d_CON_WALLMESH_TEMPLATE) ; PositionEntity gh3d_CON_PROPOSAL,gn_CON_WALL_INIT_X,gn_CON_WALL_INIT_Y,gn_CON_WALL_INIT_Z,True End If Local Orient=nb_MATH_GetIsCoordinateAlignment(gn_CON_WALL_INIT_X,gn_CON_WALL_INIT_z,X,Z) ;Z=(Z*(1-Orient))-gn_CON_WALL_INIT_X ;X=(X*(Orient))-gn_CON_WALL_INIT_z If (Orient) DebugLog("CON (Place Wall): Aligned with proposal on Z axis") ScaleEntity gh3d_CON_PROPOSAL,1,1,Z,True ;ScaleMesh gh3d_CON_PROPOSAL,1,1,Z DebugLog("CON (Place Wall): Scaled to: "+Str(MeshWidth(gh3d_CON_PROPOSAL)+" , "+Str(MeshHeight(gh3d_CON_PROPOSAL))+" , "+Str(MeshDepth(gh3d_CON_PROPOSAL)))) Else DebugLog("CON (Place Wall): Aligned with proposal on X axis") ScaleEntity gh3d_CON_PROPOSAL,X,1,1,True ;ScaleMesh gh3d_CON_PROPOSAL,X,1,1 DebugLog("CON (Place Wall): Scaled to: "+Str(MeshWidth(gh3d_CON_PROPOSAL)+" , "+Str(MeshHeight(gh3d_CON_PROPOSAL))+" , "+Str(MeshDepth(gh3d_CON_PROPOSAL)))) End If End If End Function |
| ||
I went for a different approach which at least place a wall and extends it in the correct direction. However, I am still unable to see how I can get it to actually START at the 'marker' and END with the relevant cursor coord: unction v_CON_ProposeWall(n_X,n_Y,n_Z) If (gh3d_CON_CURRENT_PROPOSAL_MESH) FreeEntity gh3d_CON_CURRENT_PROPOSAL_MESH gh3d_CON_CURRENT_PROPOSAL_MESH=0 End If gh3d_CON_CURRENT_PROPOSAL_MESH=CopyEntity(th3d_CON_WALLMESH_TEMPLATE) ShowEntity gh3d_CON_CURRENT_PROPOSAL_MESH gm_CON_CURRENT_PROPOSAL_ORIENTATION=nb_MATH_GetIsCoordinateAlignment(gn_CON_CURRENT_PROPOSAL_X,gn_CON_CURRENT_PROPOSAL_Z,n_X,n_Z) Local ExtendX Local ExtendZ Select (gm_CON_CURRENT_PROPOSAL_ORIENTATION) Case cm_CON_ORIENTATION_HORIZONTAL: ExtendZ=(n_X-gn_CON_CURRENT_PROPOSAL_X) gn_CON_CURRENT_PROPOSAL_LENGTH=Abs(ExtendZ) ExtendZ=0-(ExtendZ*0.5) ExtendX=0 TurnEntity gh3d_CON_CURRENT_PROPOSAL_MESH,0,90,0 Case cm_CON_ORIENTATION_VERTICAL: ExtendX=(n_Z-gn_CON_CURRENT_PROPOSAL_Z) gn_CON_CURRENT_PROPOSAL_LENGTH=(Abs(ExtendX)) ExtendX=0-(ExtendX*0.5) ExtendZ=0 End Select PositionEntity gh3d_CON_CURRENT_PROPOSAL_MESH,gn_CON_CURRENT_PROPOSAL_X+ExtendX,gn_CON_CURRENT_PROPOSAL_Y,gn_CON_CURRENT_PROPOSAL_Z+ExtendZ,True ScaleEntity gh3d_CON_CURRENT_PROPOSAL_MESH,gn_CON_CURRENT_PROPOSAL_LENGTH,cf_CON_WALLMESH_UNITHEIGHT,1,True End Function |
| ||
Conceptually I would look at the placement this way. You have a standard cube which you want to scale and position. It originally extends from -1 to +1 on each axis. Later calculations are a little simpler if you do this ScaleMesh StandardCube, 0.5, 0.5, 0.5 Now it has length 1 on each axis and the center is still at (0,0,0). Suppose you want a section of wall to extend in the X direction from 5 to 9. This has length 4 and center 7. So you start with a copy of StandardCube, scale X by 4 so it has length 4 in the X direction, then place it at X = 7, i.e. place the center at the center of the wall segment. Similarly, if X is to go from A to B then the length is B-A and the center is 0.5*(A+B). I doubt it matters if length is negative ( A bigger than B ), but if it does you can use Abs(B-A) instead. Then scale X by (B-A) and position at X=0.5*(A+B). |
| ||
Thanks Floyd. That makes it all so much clearer. I think I confused myself positioning the object at the cursor offset instead of at the origin as well as forgetting the initial, local (X,Z) dimensions of the primitive are centred around 0.0 rather than extending FROM 0,0. I am actually using a flat quad, so that's why there's a RotateMesh (since the template has no actual Z dimension to scale) which also made things a little (possibly unnecessarily) more complicated. Anyway, I've gotten it working beautifully now: Function v_CON_ProposeWall(n_X,n_Y,n_Z) If (gh3d_CON_CURRENT_PROPOSAL_MESH) FreeEntity gh3d_CON_CURRENT_PROPOSAL_MESH gh3d_CON_CURRENT_PROPOSAL_MESH=0 End If gh3d_CON_CURRENT_PROPOSAL_MESH=h3d_CON_GetWallTemplateCopy() gm_CON_CURRENT_PROPOSAL_ORIENTATION=nb_MATH_GetIsCoordinateAlignment(gn_CON_CURRENT_PROPOSAL_X,gn_CON_CURRENT_PROPOSAL_Z,n_X,n_Z) Select (gm_CON_CURRENT_PROPOSAL_ORIENTATION) Case cm_CON_ORIENTATION_HORIZONTAL: gn_CON_CURRENT_PROPOSAL_LENGTH=n_Z - gn_CON_CURRENT_PROPOSAL_Z ScaleMesh gh3d_CON_CURRENT_PROPOSAL_MESH,gn_CON_CURRENT_PROPOSAL_LENGTH,1,1 RotateMesh gh3d_CON_CURRENT_PROPOSAL_MESH,0,90,0 Case cm_CON_ORIENTATION_VERTICAL: gn_CON_CURRENT_PROPOSAL_LENGTH=n_X-gn_CON_CURRENT_PROPOSAL_X ScaleMesh gh3d_CON_CURRENT_PROPOSAL_MESH,gn_CON_CURRENT_PROPOSAL_LENGTH,1,1 End Select PositionEntity gh3d_CON_CURRENT_PROPOSAL_MESH,gn_CON_CURRENT_PROPOSAL_X,gn_CON_CURRENT_PROPOSAL_Y,gn_CON_CURRENT_PROPOSAL_Z,True End Function |