Exemple #1
0
 public override void draw(cGraphics pgraphics, int drawflags = 0)
 {
     if (_armed) /* The gun looks bad if
                  * you're near the edge in 2D	graphics as it doesn't get clipped. */
     {
         /* We draw the "gun" as a line.  It might be better to have the following
          * code be part of the cSprite.drawing, because then that would happen while the
          * pDC is clipped in the cCritter call.  One way to do it would be to have a CpopView.DF_GUN
          * drawflag. */
         cVector3 start = _position;
         cVector3 end   = start.add(_aimvector.mult(_gunlength * Radius));
     }
     base.draw(pgraphics, drawflags);
     //Draw sprite on top of gun line.
 }
Exemple #2
0
        /* Overload this so as not to change
            velocity as I normally want my walls to be stable and not drift after being dragged. */

        public override bool collide(cCritter pcritter)
        {
            cVector3 oldlocalpos, newlocalpos;
            float newdistance;
            int oldoutcode, newoutcode;
            bool crossedwall;

            oldlocalpos = globalToLocalPosition(pcritter.OldPosition);
            oldoutcode = _pskeleton.outcode(oldlocalpos);
            newlocalpos = globalToLocalPosition(pcritter.Position);
            newdistance = _pskeleton.distanceToOutcode(newlocalpos,
                out newoutcode); //Sets the newoutcode as well.
            crossedwall = crossed(oldoutcode, newoutcode);

            if (newdistance >= pcritter.Radius && !crossedwall) //No collision 
                return false; /*See if there's a collision at all. We
		say there's a collision if crossedwall or if the
		cCritterWall.distance is less than radius.  Remember that
		cCritterWall.distance measures the distance to the OUTSIDE 
		PERIMETER of the box, not the distance to the box's center. */

            /* I collided, so I need to move back further into the last good
            zone I was in outside the wall.  I want to set newlocalpos so 
            the rim of its critter is touching the wall. The idea is to back
            up in the direction of oldlocalpos.  To allow the possibility
            of skidding along the wall, we plan to back up from the
            the face (or edge or corner) facing oldlocalpos.  This works
            only if oldlocalpos was a good one, not inside the box.  In 
            principle this should always be true, but some rare weird circumstance
            (like a triple collsion) might mess this up, so we check for the
            bad case before starting. */

            if (oldoutcode == cRealBox3.BOX_INSIDE) //Note that this almost never happens.
            {
                cVector3 insidepos = new cVector3();
                insidepos.copy(oldlocalpos);
                oldlocalpos.subassign(pcritter.Tangent.mult(_pskeleton.MaxSize));
                //Do a brutally large backup to get out of the box for sure.
                oldoutcode = _pskeleton.outcode(oldlocalpos);
                //Recalculate outcode at this new position.
                oldlocalpos = _pskeleton.closestSurfacePoint(oldlocalpos, oldoutcode,
                    insidepos, cRealBox3.BOX_INSIDE, false);
                //Go to the closest surface point from there.
                oldoutcode = _pskeleton.outcode(oldlocalpos);
                //Recalculate outcode one more time to be safe.
                crossedwall = crossed(oldoutcode, newoutcode);
                //Recalculate crossedwall 
            }
            /* I find that with this code, the mouse can drag things through walls,
        so I do a kludge to block it by setting crossedwall to TRUE, this
        affects the action of cRealBox.closestSurfacePoint, as modified
        in build 34_4. */
            if (pcritter.Listener.IsKindOf("cListenerCursor"))
                crossedwall = true; //Don't trust the mouse listener.
            newlocalpos = _pskeleton.closestSurfacePoint(oldlocalpos, oldoutcode,
                newlocalpos, newoutcode, crossedwall);
            /* This call to closestSurfacePoint will move the newlocal pos
        from the far new side (or inside, or overlapping) of the box back to 
        the surface, usually on the old near side, edge, or corner given by
        oldoutcode. This prevents going through the	wall.
            If oldoutcode is a corner position and you are in fact heading
        towards a face near the corner, we used to bounce off the corner
        even though visually you can see you should bounce off the
        face.  This had the effect of making a scooter player get hung up on
        a corner sometimes. As of build 34_3, I'm moving the 
        newlocalpos to the newoutocode side in the case where oldlocalpos
        is an edge or a corner, and where crossedwall isn't TRUE.  I
        have to force in a TRUE for the cCursorLIstener case.  The USEJIGGLE
        code below also helps keep non-player critters from getting stuck
        on corners. */
            //Now back away from the box.
            newoutcode = _pskeleton.outcode(newlocalpos);
            cVector3 avoidbox = _pskeleton.escapeVector(newlocalpos, newoutcode);
            newlocalpos.addassign(avoidbox.mult(pcritter.Radius));
            newoutcode = _pskeleton.outcode(newlocalpos);
            pcritter.moveTo(localToGlobalPosition(newlocalpos), true);
            //TRUE means continuous motion, means adjust tangent etc.
            //Done with position, now change the velocity 
            cVector3 localvelocity = globalToLocalDirection(pcritter.Velocity);
            cVector3 oldlocalvelocity = new cVector3();
            oldlocalvelocity.copy(localvelocity);
            _pskeleton.reflect(localvelocity, newoutcode);
            /* I rewrote the reflect code on Feb 22, 2004 for VErsion 34_3, changing
        it so that when you reflect off an edge or corner, you only bounce
        the smallest of your three velocity components. Balls stll seem to
        get hung up on the corner once is awhile. */
            /* Now decide, depending on the pcritter's absorberflag and bounciness,
        how much you want to use the new localvelocity vs. the 
        oldlocalvelocity. We decompose the new localvelocity into the
        tangentvelocity parallel to the wall and the normalvelocity
        away from the wall. Some pencil and paper drawings convince
        me that the tangent is half the sum of the oldlocalvelocity
        and the reflected new localvelocity. */
            cVector3 tangentvelocity = localvelocity.add(oldlocalvelocity).mult(0.5f);
            cVector3 normalvelocity = localvelocity.sub(tangentvelocity);
            float bouncefactor = 1.0f;
            if (pcritter.AbsorberFlag)
                bouncefactor = 0.0f;
            else
                bouncefactor = pcritter.Bounciness;
            localvelocity = tangentvelocity.add(normalvelocity.mult(bouncefactor));
            /* Maybe the rotation should depend on the kind of edge or corner.
            Right now let's just use critter's binormal. Don't to it 
            to the player or viewer as it's confusing.  */
            if (!(cRealBox3.isFaceOutcode(newoutcode)) && //edge or corner 
                !(pcritter.IsKindOf("cCritterViewer")) && //not viewer 
                !(pcritter.IsKindOf("cCritterArmedPlayer")))
            //Not player.  Note that cPlayer inherits from cCritterArmedPlayer, 
            //so don't use cCritterPlayer as the base class here.
            {
                localvelocity.rotate(new cSpin(
                    Framework.randomOb.randomReal(
                        -cCritterWall.CORNERJIGGLETURN,
                        cCritterWall.CORNERJIGGLETURN), //A random turn 
                        pcritter.Binormal)); //Around the critter's binormal 
                localvelocity.multassign(cCritterWall.CORNERJIGGLEKICK); //Goose it a little 
            }
            pcritter.Velocity = localToGlobalDirection(localvelocity);
            return true;
        }
Exemple #3
0
 public override cVector3 force(cCritter pcritter)
 {
     return(_pulldirection.mult(_intensity * pcritter.Mass));
 }
Exemple #4
0
        public void setViewpoint(cVector3 toViewer, cVector3 lookatPoint,
                                 bool trytoseewholeworld = true)
        {
            //First do some default setup stuff
            cVector3 toviewer = new cVector3();

            toviewer.copy(toViewer);
            cVector3 lookatpoint = new cVector3();

            lookatpoint.copy(lookatPoint);
            _fieldofviewangle = cCritterViewer.STARTFIELDOFVIEWANGLE;
            Speed             = 0.0f;
            _attitude         = new cMatrix3(new cVector3(0.0f, 0.0f, -1.0f),
                                             new cVector3(-1.0f, 0.0f, 0.0f), new cVector3(0.0f, 1.0f, 0.0f),
                                             new cVector3(0.0f, 0.0f, 0.0f));

            /* To get a reasonable default orientation, we arrange the viewer axes so that:
             * viewer x axis = world -z axis, viewer y axis = world -x axis, viewer z axis = world y axis.
             * We pick this orientation so that if the viewer moves "forward" (along its tangent vector)
             * it moves towards the world.  (We correct the mismatch between the coordinate systems in the
             * cCritterViewer.loadViewMatrix method, which has a long comment about this.)
             * Note that we will adjust _position (fourth column) later in this  call
             * with a moveTo, also we may rotate the _attitude a bit. */
            if (!_perspective)                                                                               //Ortho view, simply move up.
            {
                _proportionofworldtoshow = 1.0f;                                                             //Show all of a flat world.
                moveTo(lookatpoint.add((new cVector3(0.0f, 0.0f, 1.0f)).mult(cCritterViewer.ORTHOZOFFSET))); // Get above the world
                _maxspeed = _maxspeedstandard = 0.5f * cCritterViewer.ORTHOZOFFSET;                          //Mimic perspective case.
            }
            else //_perspective
            {
                if (toviewer.IsPracticallyZero)                    //Not usable, so pick a real direction.
                {
                    toviewer.copy(new cVector3(0.0f, 0.0f, 1.0f)); //Default is straight up.
                }
                if (trytoseewholeworld)                            /* Treat toviewer as a direction, and back off in that direction
                                                                    * enough to see the whole world */
                {
                    toviewer.normalize();                          //Make it a unit vector.
                    _proportionofworldtoshow = cCritterViewer.PROPORTIONOFWORLDTOSHOW;
                    //Trying to show all of a world when flying around it, often leaves too big a space around it.
                    float furthestcornerdistance = Game.Border.maxDistanceToCorner(lookatpoint);
                    float tanangle = (float)Math.Tan(_fieldofviewangle / 2.0f); /* We work with half the fov in this calculation,
                                                                                *  the tanangle will be the ratio of visible distance to distance above the world,
                                                                                *  that is, tanangle = dr/dz, where
                                                                                *  Our dr is _proportionofworldtoshow * furthestcornerdistance, and
                                                                                *  our dz is the unknown seeallz height we need to back off to.
                                                                                *  Swap tangangle and dz to get the next formula. */
                    float seeallz  = _proportionofworldtoshow * furthestcornerdistance / tanangle;
                    moveTo(lookatpoint.add(toviewer.mult(seeallz)));
                }
                else /*Not trytoseewholeworld.  In this case we don't normalize toviewer, instead
                      *         we treat it as a displacment from the lookatpoint. */
                {
                    moveTo(lookatpoint.add(toviewer));
                }
                lookAt(lookatpoint);
                _maxspeed = _maxspeedstandard = 0.5f * (Position.sub(lookatpoint)).Magnitude;

                /* Define the speed like this so it typically takes two seconds (1/0.5)
                 * to fly in to lookatpoint. */
                _lastgoodplayeroffset = Position.sub(Game.Player.Position);
            }
        }