public override int clamp(cRealBox3 border) { /* We don't change _pskeleton as it has the geometric info. We * just change _position. */ if (_baseAccessControl == 1) { return(base.clamp(border)); } cRealBox3 effectivebox = border; cVector3 oldcorner; cVector3 newcorner = new cVector3(); int outcode = 0; int totaloutcode = 0; for (int i = 0; i < 8; i++) //Step through the wall's corners { oldcorner = _pskeleton.corner(i) + _position; newcorner.copy(oldcorner); outcode = effectivebox.clamp(newcorner); if (outcode != cRealBox3.BOX_INSIDE) //corner was moved { _position += newcorner - oldcorner; /* As long at the wall is small enough to * fit inside the border, the successive * corrections won't cancel each other out. */ totaloutcode |= outcode; } } _wrapposition1.copy(_position); _wrapposition2.copy(_position); _wrapposition3.copy(_position); /* So it won't think it wrapped. */ return(outcode); }
/* Uses _foveaproportion which lies between 0.0 and 1.0. We say something is visible if it * appears on the inner _foveaproportion central box of the viewer's image screen, * which is what you see in the view window. */ //overloads //Use _pownerview to get the CpopDoc and get the cGame from that. public override void update(ACView pactiveview, float dt) { base.update(pactiveview, dt); ZClipPlanes = Game.Border.outerBox(cSprite.MAXPRISMDZ); if (_trackplayer && !((Listener != null) && Listener.RuntimeClass == "cListenerViewerRide")) /* The meaning of the visibleplayer() condition is that it doesn't make sense * to track the player if it's not an onscreen player. The reason for the * listener condition is that you don't want to stare at the player when * riding it. */ /* I should explain that the goal here is to not bother turning when the player * is moving around in the middle of the veiw area, and only to turn when he's near * the edge, but to have the turning when he's near the edge be smoooth. * The use of the 0.85 foveaproportion parameter means that you react before the player * gets right up to the edge. The reactproportion factor in lookAtProportional and * moveToProportional is delicate and should probably be adjusted according to the * current player speed relative to the visible window. The issue is that (a) if I make * reactproportion too small, like 0.01, then the viewer doesn't turn (or move) fast * enough to catch up with the player and keep it in view, but (b) if I make reactpropotion * too big, like 0.5, then the turning or moving is such an abrupt jump that the visual * effect is jerky. The goal is to do turns that are just big enough to not look jerky, * but to have the turns be big enough so you aren't turning more often than you really * have to. Another downside of a toosmall reactproportion, by the way, is that it can be * computationally expensive to react. * The way we finally solved this is to do a while loop to turn just * far enough, moving just a little at a time so as to not overshoot. */ { if (isVisible(Game.Player.Position)) // Uses _foveaproportion { _lastgoodplayeroffset = Position - Game.Player.Position; } /*I'm not sure about constantly changing _lastgoodplayeroffset. On the * one hand, the offset I set in setViewpoint was a standard good one, so why * not keep it. On the other, if I want to move my viewpoint around then I * do want to be able to get a new value here. It seems ok for now.*/ else //not visible, so do somehting about it. { int loopcount = 0; /* Never have a while loop without a loopcount * to make sure you don't spin inside the while forever under some * unexpected situation like at startup. */ cVector3 lookat = Game.Player.Position; cVector3 viewerpos = lookat + _lastgoodplayeroffset; if (Game.worldShape() == cGame.SHAPE_XSCROLLER) { lookat = new cVector3(Game.Player.Position.X, Game.Border.Midy, Game.Player.Position.Z); viewerpos = new cVector3(lookat.X, Position.Y, Position.Z); } if (Game.worldShape() == cGame.SHAPE_YSCROLLER) { lookat = new cVector3(Game.Border.Midx, Game.Player.Position.Y, Game.Player.Position.Z); viewerpos = new cVector3(Position.X, lookat.Y, Position.Z); } if (_perspective) { while (!isVisible(lookat) && loopcount < 100) // Uses _foveaproportion { moveToProportional(viewerpos, cCritterViewer.TURNPROPORTION); loopcount++; } } else //ortho case { while (!isVisible(lookat) && loopcount < 100) // Uses _foveaproportion { moveToProportional(lookat + Game.Player.Binormal * 10.0f, cCritterViewer.TURNPROPORTION); loopcount++; } } } } //Possibly ride the player. if (Listener is cListenerViewerRide) { cCritter pplayer = Game.Player; cVector3 offset = ((cListenerViewerRide)Listener).Offset; moveTo(pplayer.Position + pplayer.AttitudeTangent * offset.X + pplayer.AttitudeNormal * offset.Y + pplayer.AttitudeBinormal * offset.Z); cRealBox3 skeleton = pplayer.MoveBox; if (skeleton.ZSize < 0.5f) { skeleton.setZRange(0.0f, offset.Z); } if (skeleton.YSize < 0.5f) { skeleton.setYRange(0.0f, offset.Z); } skeleton.clamp(_position); for (int i = 0; i < Game.Biota.count(); i++) { cCritter pother = Game.Biota.GetAt(i); if (pother is cCritterWall) { pother.collide(this); } } /* colliding with the wall may have twisted the viwer's orientation, * so align it once again. */ Attitude = pplayer.Attitude; /* Before we call lookAt, * make sure your attitude matches the player. For one thing, * you may have gotten twisted around in the COLLIDEVIEWER code. */ lookAt(pplayer.Position + pplayer.AttitudeTangent * cListenerViewerRide.PLAYERLOOKAHEAD * pplayer.Radius); /* This has the effect that as offset gets large you change your * looking direction see right in front of the player. The multiplier * cCritterViewer.PLAYERLOOKAHEAD is tweaked to work well * with the default cCritterViewer.OFFSET. */ } }