const float InvertIncrement = 0.01f; //10ms internal Game(GraphicsDevice gd, string gameRootDir) { mGD = gd; mGameRootDir = gameRootDir; mResX = gd.RendForm.ClientRectangle.Width; mResY = gd.RendForm.ClientRectangle.Height; mSKeeper = new StuffKeeper(); mSKeeper.eCompileNeeded += SharedForms.ShaderCompileHelper.CompileNeededHandler; mSKeeper.eCompileDone += SharedForms.ShaderCompileHelper.CompileDoneHandler; mSKeeper.Init(mGD, gameRootDir); mFontMats = new MatLib(gd, mSKeeper); mCPrims = new CommonPrims(gd, mSKeeper); mFonts = mSKeeper.GetFontList(); mFontMats.CreateMaterial("Text"); mFontMats.SetMaterialEffect("Text", "2D.fx"); mFontMats.SetMaterialTechnique("Text", "Text"); mST = new ScreenText(gd.GD, mFontMats, mFonts[0], 1000); mSUI = new ScreenUI(gd.GD, mFontMats, 100); mTextProj = Matrix.OrthoOffCenterLH(0, mResX, mResY, 0, 0.1f, 5f); //load avail static stuff if (Directory.Exists(mGameRootDir + "/Statics")) { DirectoryInfo di = new DirectoryInfo(mGameRootDir + "/Statics"); FileInfo[] fi = di.GetFiles("*.MatLib", SearchOption.TopDirectoryOnly); if (fi.Length > 0) { mStaticMats = new MatLib(gd, mSKeeper); mStaticMats.ReadFromFile(fi[0].DirectoryName + "\\" + fi[0].Name); mStaticMats.InitCelShading(1); mStaticMats.GenerateCelTexturePreset(gd.GD, (gd.GD.FeatureLevel == FeatureLevel.Level_9_3), false, 0); mStaticMats.SetCelTexture(0); mKeeper.AddLib(mStaticMats); } mStatics = Mesh.LoadAllStaticMeshes(mGameRootDir + "\\Statics", gd.GD); foreach (KeyValuePair <string, IArch> arch in mStatics) { arch.Value.UpdateBounds(); } fi = di.GetFiles("*.StaticInstance", SearchOption.TopDirectoryOnly); foreach (FileInfo f in fi) { string archName = FileUtil.StripExtension(f.Name); if (archName.Contains('_')) { archName = archName.Substring(0, f.Name.IndexOf('_')); } archName += ".Static"; if (!mStatics.ContainsKey(archName)) { continue; } StaticMesh sm = new StaticMesh(mStatics[archName]); sm.ReadFromFile(f.DirectoryName + "\\" + f.Name); mMeshes.Add(sm); sm.UpdateBounds(); sm.SetMatLib(mStaticMats); Vector3 randPos = Mathery.RandomPosition(mRand, Vector3.UnitX * 100f + Vector3.UnitZ * 100f); mMeshPositions.Add(randPos); mMeshRotations.Add(Vector3.Zero); mMeshScales.Add(Vector3.One); UpdateStaticTransform(mMeshes.Count - 1); } AddStaticCollision(); } //skip hair stuff when computing bone bounds //hits to hair usually wouldn't activate much List <string> skipMats = new List <string>(); skipMats.Add("Hair"); //load character stuff if any around if (Directory.Exists(mGameRootDir + "/Characters")) { DirectoryInfo di = new DirectoryInfo(mGameRootDir + "/Characters"); FileInfo[] fi = di.GetFiles("*.AnimLib", SearchOption.TopDirectoryOnly); if (fi.Length > 0) { mCharAnims = new AnimLib(); mCharAnims.ReadFromFile(fi[0].DirectoryName + "\\" + fi[0].Name); List <Anim> anims = mCharAnims.GetAnims(); foreach (Anim a in anims) { mAnims.Add(a.Name); } } fi = di.GetFiles("*.MatLib", SearchOption.TopDirectoryOnly); if (fi.Length > 0) { mCharMats = new MatLib(mGD, mSKeeper); mCharMats.ReadFromFile(fi[0].DirectoryName + "\\" + fi[0].Name); mCharMats.InitCelShading(1); mCharMats.GenerateCelTexturePreset(gd.GD, gd.GD.FeatureLevel == FeatureLevel.Level_9_3, false, 0); mCharMats.SetCelTexture(0); mKeeper.AddLib(mCharMats); } fi = di.GetFiles("*.Character", SearchOption.TopDirectoryOnly); foreach (FileInfo f in fi) { IArch arch = new CharacterArch(); arch.ReadFromFile(f.DirectoryName + "\\" + f.Name, mGD.GD, true); mCharArchs.Add(FileUtil.StripExtension(f.Name), arch); } fi = di.GetFiles("*.CharacterInstance", SearchOption.TopDirectoryOnly); foreach (FileInfo f in fi) { string archName = f.Name; if (archName.Contains('_')) { archName = f.Name.Substring(0, f.Name.IndexOf('_')); } if (!mCharArchs.ContainsKey(archName)) { continue; } Character c = new Character(mCharArchs[archName], mCharAnims); //map this to an arch mCharToArch.Add(c, mCharArchs[archName]); c.ReadFromFile(f.DirectoryName + "\\" + f.Name); c.SetMatLib(mCharMats); c.SetTransform(Matrix.Translation( Mathery.RandomPosition(mRand, Vector3.UnitX * 100f + Vector3.UnitZ * 100f))); c.ComputeBoneBounds(skipMats); c.AutoInvert(true, mInvertInterval); mCharacters.Add(c); } if (mCharacters.Count > 0) { mAnimTimes = new float[mCharacters.Count]; mCurAnims = new int[mCharacters.Count]; mCBone = new int[mCharacters.Count]; mCBones = new Dictionary <int, Matrix> [mCharacters.Count]; } foreach (KeyValuePair <string, IArch> arch in mCharArchs) { //build draw data for bone bounds (arch.Value as CharacterArch).BuildDebugBoundDrawData(mGD.GD, mCPrims); } } //typical material group for characters //or at least it works with the ones //I have right now //TODO: way to define these in the asset? List <string> skinMats = new List <string>(); skinMats.Add("Face"); skinMats.Add("Skin"); skinMats.Add("EyeWhite"); skinMats.Add("EyeLiner"); skinMats.Add("IrisLeft"); skinMats.Add("PupilLeft"); skinMats.Add("IrisRight"); skinMats.Add("PupilRight"); skinMats.Add("Nails"); mKeeper.AddMaterialGroup("SkinGroup", skinMats); mTextColor = Vector4.UnitY + (Vector4.UnitW * 0.15f); mHitColor = Vector4.One * 0.9f; mHitColor.Y = mHitColor.Z = 0f; mSUI.AddGump("UI\\CrossHair", "CrossHair", Vector4.One, Vector2.UnitX * ((mResX / 2) - 16) + Vector2.UnitY * ((mResY / 2) - 16), Vector2.One); //string indicators for various statusy things mST.AddString(mFonts[0], "", "StaticStatus", mTextColor, Vector2.UnitX * 20f + Vector2.UnitY * 460f, Vector2.One); mST.AddString(mFonts[0], "", "InvertStatus", mTextColor, Vector2.UnitX * 20f + Vector2.UnitY * 480f, Vector2.One); mST.AddString(mFonts[0], "", "AnimStatus", mTextColor, Vector2.UnitX * 20f + Vector2.UnitY * 500f, Vector2.One); mST.AddString(mFonts[0], "", "CharStatus", mTextColor, Vector2.UnitX * 20f + Vector2.UnitY * 520f, Vector2.One); mST.AddString(mFonts[0], "", "PosStatus", mTextColor, Vector2.UnitX * 20f + Vector2.UnitY * 540f, Vector2.One); mST.AddString(mFonts[0], "", "HitStatus", mTextColor, Vector2.UnitX * 20f + Vector2.UnitY * 560f, Vector2.One); mST.AddString(mFonts[0], "", "ThreadStatus", mTextColor, Vector2.UnitX * 20f + Vector2.UnitY * 580f, Vector2.One); UpdateCAStatus(); UpdateInvertStatus(); UpdateStaticStatus(); }
//if running on a fixed timestep, this might be called //more often with a smaller delta time than RenderUpdate() internal void Update(UpdateTimer time, List <Input.InputAction> actions, PlayerSteering ps) { //Thread.Sleep(30); float secDelta = time.GetUpdateDeltaSeconds(); // mZone.UpdateModels(secDelta); float yawAmount = 0f; float pitchAmount = 0f; bool bGravity = false; float friction = GroundFriction; if (!mbOnGround) { //gravity if (!mbFly) { bGravity = true; } if (mbBadFooting) { friction = GroundFriction; } else { friction = AirFriction; } } else { if (!mbFly) { friction = GroundFriction; } else { friction = AirFriction; } } bool bCamJumped = false; foreach (Input.InputAction act in actions) { if (act.mAction.Equals(Program.MyActions.Jump)) { if (mbOnGround && !mbFly) { friction = AirFriction; bCamJumped = true; } } else if (act.mAction.Equals(Program.MyActions.ToggleFly)) { mbFly = !mbFly; ps.Method = (mbFly)? PlayerSteering.SteeringMethod.Fly : PlayerSteering.SteeringMethod.FirstPerson; } else if (act.mAction.Equals(Program.MyActions.Turn)) { yawAmount = act.mMultiplier; } else if (act.mAction.Equals(Program.MyActions.Pitch)) { pitchAmount = act.mMultiplier; } else if (act.mAction.Equals(Program.MyActions.RayStart)) { mRayStart = GetModelPos(); } else if (act.mAction.Equals(Program.MyActions.RayEnd)) { mRayEnd = GetModelPos(); mbRayHit = mTModel.Trace(mRayStart, mRayEnd, out mRayHit); mColRays.Add(mRayStart); mColRays.Add(mRayEnd); if (mbRayHit) { //scale up to view space Vector3 viewHit = mRayHit; viewHit.X *= 16f; viewHit.Z *= 16f; mColHits.Add(viewHit); } mDrawRays.BuildRayDrawInfo(mColRays, mColHits, 16f); } else if (act.mAction.Equals(Program.MyActions.RayCrazy)) { Stopwatch sw = new Stopwatch(); sw.Start(); mColRays.Clear(); mColHits.Clear(); Vector3 randSpace = Vector3.One * 1000f; randSpace.Y *= 5f; for (int i = 0; i < 1000; i++) { Vector3 start = Mathery.RandomPosition(mRand, randSpace); Vector3 end = Mathery.RandomPosition(mRand, randSpace); //wrap xz if (start.X < 0) { start.X += 1000f; } if (start.Z < 0) { start.Z += 1000f; } if (end.X < 0) { end.X += 1000f; } if (end.Z < 0) { end.Z += 1000f; } Vector3 hit; if (mTModel.Trace(start, end, out hit)) { //scale up to view space Vector3 viewHit = hit; viewHit.X *= 16f; viewHit.Z *= 16f; mColHits.Add(viewHit); } mColRays.Add(start); mColRays.Add(end); } sw.Stop(); mDrawRays.BuildRayDrawInfo(mColRays, mColHits, 16f); } } // UpdateDynamicLights(actions); Vector3 startPos = mGroundPos; Vector3 moveVec = ps.Update(startPos, mGD.GCam.Forward, mGD.GCam.Left, mGD.GCam.Up, actions); if (mbOnGround || mbFly) { moveVec *= JogMoveForce; } else if (mbBadFooting) { moveVec *= StumbleForce; } else { moveVec *= MidAirMoveForce; } mVelocity += moveVec * 0.5f; mVelocity -= (friction * mVelocity * secDelta * 0.5f); Vector3 pos = startPos; if (bGravity) { mVelocity += Vector3.Down * GravityForce * (secDelta * 0.5f); } if (bCamJumped) { mVelocity += Vector3.Up * JumpForce * 0.5f; pos += mVelocity * (1f / 60f); } else { pos += mVelocity * secDelta; } mVelocity += moveVec * 0.5f; mVelocity -= (friction * mVelocity * secDelta * 0.5f); if (bGravity) { mVelocity += Vector3.Down * GravityForce * (secDelta * 0.5f); } if (bCamJumped) { mVelocity += Vector3.Up * JumpForce * 0.5f; } Vector3 camPos = Vector3.Zero; Vector3 endPos = pos; // Move(endPos, time.GetUpdateDeltaMilliSeconds(), false, // mbFly, !bCamJumped, true, true, out endPos, out camPos); mGroundPos += moveVec; bool bWrapped = WrapPosition(ref mGroundPos); WrapGridCoordinates(); if (bWrapped && mTerrain != null) { mTerrain.BuildGrid(mGD, mChunkRange, mNumStreamThreads); } if (mTerrain != null) { mTerrain.SetCellCoord(mGridCoordinate); mTerrain.UpdatePosition(mGroundPos, mTerMats); } mGD.GCam.Update(-mGroundPos, ps.Pitch, ps.Yaw, ps.Roll); mOtherCam.Update(-GetViewPos(), ps.Pitch, ps.Yaw, ps.Roll); if (!mbFly) { if (mbOnGround) { //kill downward velocity so previous //falling momentum doesn't contribute to //a new jump if (mVelocity.Y < 0f) { mVelocity.Y = 0f; } } if (mbBadFooting) { //reduce downward velocity to avoid //getting stuck in V shaped floors if (mVelocity.Y < 0f) { mVelocity.Y -= (StumbleFriction * mVelocity.Y * secDelta); } } } //get ground pos at current location float groundHeight = mTModel.GetHeight(GetModelPos()); mAudio.Update(mGD.GCam); mST.ModifyStringText(mFonts[0], "Grid: " + mGridCoordinate.ToString() + ", LocalPos: " + mGroundPos.IntStr() + ", ModelPos: " + GetModelPos(), "PosStatus"); mST.ModifyStringText(mFonts[0], "Height: " + groundHeight + ", Hit: " + mbRayHit + ", HitPos: " + mRayHit, "ColStatus"); if (mTerrain != null) { mST.ModifyStringText(mFonts[0], "Threads Active: " + mTerrain.GetThreadsActive() + ", Thread Counter: " + mTerrain.GetThreadCounter(), "ThreadStatus"); } mST.Update(mGD.DC); }