⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 unit2.pas

📁 3d snake 游戏编程源码
💻 PAS
📖 第 1 页 / 共 3 页
字号:

   glMaterialfv(GL_FRONT, GL_AMBIENT, @MaterialAmbient);
   glMaterialfv(GL_FRONT, GL_DIFFUSE, @MaterialDiffuse);
   glMaterialfv(GL_FRONT, GL_SPECULAR, @MaterialSpecular);
   glMaterialfv(GL_FRONT, GL_SHININESS, @MaterialShininess);

   glLightfv(GL_LIGHT0, GL_POSITION, @AmbientLightPosition);
   glLightfv(GL_LIGHT0, GL_AMBIENT, @LightAmbient);


   glLightModelfv(GL_LIGHT_MODEL_AMBIENT, @LightAmbient);
   glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);

   glEnable(GL_LIGHTING);
   glEnable(GL_LIGHT0);

   glEnable(GL_COLOR_MATERIAL);
   GLShadeModel(GL_SMOOTH);
end;

procedure TDrawEngine.SetEye;
var posi: T3DPoint; i: Byte;
begin
   glMatrixMode(GL_PROJECTION); // 切换到投影变换栈
   glLoadIdentity(); // 初始化投影变换栈
   gluPerspective(88, 665 / 430, 1, 50); // 压入透视投影矩阵

   for i := 1 to 3 do
      posi[i] := EyePosH[ViewAngleH, i] * MapSize[i];
   posi[2] := EyePosV[ViewAngleV] * MapSize[2];
   posi[AbsoluteAxis[ViewAngleH]] := posi[AbsoluteAxis[ViewAngleH]] * FarNearValue[ViewDistance];

   gluLookAt(posi[1], posi[2], posi[3], BoxCenter[1], BoxCenter[2], BoxCenter[3], 0, 1, 0);
   glMatrixMode(GL_MODELVIEW); // 切换到几何变换
end;

procedure TDrawEngine.IniBlockState;
var x, y, z: SmallInt; i: Byte; tmp: BlockStates;
begin
   fillChar(BlockState, sizeof(BlockState), 0); //都设成 bs_Empty

   //外围墙都是障碍物
   for x := -1 to MapSize[1] do
      for y := -1 to MapSize[2] do begin
         BlockState[x, y, -1] := bs_Wall;
         BlockState[x, y, MapSize[3]] := bs_Wall;
      end;
   for x := -1 to MapSize[1] do
      for z := -1 to MapSize[3] do begin
         BlockState[x, -1, z] := bs_Wall;
         BlockState[x, MapSize[2], z] := bs_Wall;
      end;
   for y := -1 to MapSize[2] do
      for z := -1 to MapSize[3] do begin
         BlockState[-1, y, z] := bs_Wall;
         BlockState[MapSize[1], y, z] := bs_Wall;
      end;

   //将场景中的障碍物所在方块设为 bs_Obstacle
   if BlockCount <> 0 then
      for i := 0 to BlockCount - 1 do
         with Blocks[i] do begin
            if _Type = bt_Block then
               tmp := bs_Obstacle
            else
               tmp := bs_Empty;
            for x := LeftBackBottom[1] to RightFrontTop[1] do
               for y := LeftBackBottom[2] to RightFrontTop[2] do
                  for z := LeftBackBottom[3] to RightFrontTop[3] do
                     BlockState[x, y, z] := tmp;
         end;
end;

function TDrawEngine.ReturnAnEmptyBlock: T3DPointB; //返回一个空的格子
var i: Byte;
begin
   Randomize;
   repeat
      for i := 1 to 3 do
         Result[i] := RandomRange(0, MapSize[i] - 1);
   until BlockState[Result[1], Result[2], Result[3]] = bs_Empty;
end;

procedure TDrawEngine.ReadScript;
var i: Byte;
begin
   try
      ExitShow := False;
      EatAppleCount := 0;
      with MapProperty do begin
         UseEngineVersion := StrToInt(ReadSpaceSection(MapScript.Strings[0]));
         MapName := ReadSpaceSection(MapScript.Strings[1]);
         MapDescription := ReadSpaceSection(MapScript.Strings[2]);
         DrawDataFromCommaExp(ReadSpaceSection(MapScript.Strings[3]));
         for i := 1 to 3 do
            MapSize[i] := CommaData[i];
         for i := 1 to 3 do
            BoxCenter[i] := MapSize[i] / 2;
         MapValue := StrToInt(ReadSpaceSection(MapScript.Strings[4]));
         AppleCount := StrToInt(ReadSpaceSection(MapScript.Strings[5]));
         SnakeSpeed := StrToInt(ReadSpaceSection(MapScript.Strings[6]));
         DrawDataFromCommaExp(ReadSpaceSection(MapScript.Strings[7]));
         for i := 1 to 3 do
            Ori_SnakeHead[i] := CommaData[i];
         for i := 1 to 3 do
            OriSnakeTail[i] := CommaData[i + 3];
         AppleList := ReadSpaceSection(MapScript.Strings[8]);
         BlockCount := StrToInt(ReadSpaceSection(MapScript.Strings[9]));

         OutputGameProperties;
         IniScene;
         IniLighting;
         MakeWallDrawLists;
         LoadBlocks;
         PrepareSnake;
         ShowKeyDirectors;
         IniBlockState;
         CreateApple; //生成第一个苹果
      end;
   except
      on E: Exception do begin
         MessageDlg(msg_FileFailed, mtError, [mbOK], 0);
      end;
   end;
end;

procedure TDrawEngine.SetGLColor(idx: ObjNames);
begin
   glColor3ub(GameOption.ColorsRGB[idx, 1], GameOption.ColorsRGB[idx, 2], GameOption.ColorsRGB[idx, 1]);
end;

procedure TDrawEngine.DrawCube(p1, p2: T3DPointB; _Type: Integer = GL_QUADS);
begin
   //必需保证以p1为"左后下"顶点,p2为"右前上"顶点
   inc(p2[1]);
   inc(p2[2]);
   inc(p2[3]);

   //上面
   glBegin(_Type);
   glNormal3f(0, 1, 0);
   glVertex3f(p1[1], p2[2], p1[3]);
   glVertex3f(p1[1], p2[2], p2[3]);
   glVertex3f(p2[1], p2[2], p2[3]);
   glVertex3f(p2[1], p2[2], p1[3]);
   glEnd;

   //下面
   glBegin(_Type);
   glNormal3f(0, -1, 0);
   glVertex3f(p2[1], p1[2], p1[3]);
   glVertex3f(p2[1], p1[2], p2[3]);
   glVertex3f(p1[1], p1[2], p2[3]);
   glVertex3f(p1[1], p1[2], p1[3]);
   glEnd;

   //左面
   glBegin(_Type);
   glNormal3f(-1, 0, 0);
   glVertex3f(p1[1], p2[2], p1[3]);
   glVertex3f(p1[1], p1[2], p1[3]);
   glVertex3f(p1[1], p1[2], p2[3]);
   glVertex3f(p1[1], p2[2], p2[3]);
   glEnd;

   //右面
   glBegin(_Type);
   glNormal3f(1, 0, 0);
   glVertex3f(p2[1], p2[2], p2[3]);
   glVertex3f(p2[1], p1[2], p2[3]);
   glVertex3f(p2[1], p1[2], p1[3]);
   glVertex3f(p2[1], p2[2], p1[3]);
   glEnd;

   //前面
   glBegin(_Type);
   glNormal3f(0, 0, 1);
   glVertex3f(p1[1], p2[2], p2[3]);
   glVertex3f(p1[1], p1[2], p2[3]);
   glVertex3f(p2[1], p1[2], p2[3]);
   glVertex3f(p2[1], p2[2], p2[3]);
   glEnd;

   //后面
   glBegin(_Type);
   glNormal3f(0, 0, -1);
   glVertex3f(p2[1], p2[2], p1[3]);
   glVertex3f(p2[1], p1[2], p1[3]);
   glVertex3f(p1[1], p1[2], p1[3]);
   glVertex3f(p1[1], p2[2], p1[3]);
   glEnd;
end;

procedure TDrawEngine.LoadBlocks;
var i: Byte;
begin
   SetLength(Blocks, BlockCount);
   for i := BlockDataBeginLine to BlockDataBeginLine + BlockCount - 1 do begin
      DrawDataFromCommaExp(ReadSpaceSection(MapScript.Strings[i]));
      with Blocks[i - BlockDataBeginLine] do begin
         if MapScript.Strings[i][1] = 'A' then
            _Type := bt_AntiBlock
         else
            _Type := bt_Block;
         LeftBackBottom[1] := CommaData[1];
         LeftBackBottom[2] := CommaData[2];
         LeftBackBottom[3] := CommaData[3];
         RightFrontTop[1] := CommaData[4];
         RightFrontTop[2] := CommaData[5];
         RightFrontTop[3] := CommaData[6];
      end;
   end;
end;

procedure TDrawEngine.DrawSphere(Part: PTSnakeBody); //实际为绘制蛇身的一节一节
begin
   with Part^ do begin
      gluDeleteQuadric(qObj);
      qObj := gluNewQuadric;
      gluQuadricDrawStyle(qObj, GLU_FILL);
      gluQuadricNormals(qObj, GLU_SMOOTH);
      glPushMatrix;
      glTranslate(CenterPos[1], CenterPos[2], CenterPos[3]); //在这一点画球
      gluSphere(qObj, 0.5, 10, 10);
      glPopMatrix;
   end;
end;

procedure TDrawEngine.PrepareSnake;
var P, i: Byte; tmp, tmp2: PTSnakeBody;
   procedure SubAddBody;
   begin
      New(tmp^.Next);
      tmp2 := tmp^.Next;
      with tmp2^ do begin
         Pre := tmp;
         OriPos := MapProperty.Ori_SnakeHead;
         OriPos[P] := i;
         _3DPointB_To_3DPoint(CenterPos, OriPos);
         MakeItToSphereCenter(CenterPos);
         BlockState[OriPos[1], OriPos[2], OriPos[3]] := bs_SnakeBody;
      end;
      tmp := tmp2;
   end;
begin
   with MapProperty do begin
      for P := 1 to 3 do //找出相同的坐标,判断蛇的方向,好绘制蛇身
         if Ori_SnakeHead[P] <> OriSnakeTail[P] then
            Break;
      New(SnakeHead);
      with SnakeHead^ do begin
         OriPos := Ori_SnakeHead;
         _3DPointB_To_3DPoint(CenterPos, Ori_SnakeHead);
         MakeItToSphereCenter(CenterPos);
         BlockState[OriPos[1], OriPos[2], OriPos[3]] := bs_SnakeBody; //将蛇身所在的方块设为 bs_SnakeBody
      end;
      tmp := SnakeHead;
      if Ori_SnakeHead[P] > OriSnakeTail[P] then
         for i := Ori_SnakeHead[P] - 1 downto OriSnakeTail[P] do
            SubAddBody
      else
         for i := Ori_SnakeHead[P] + 1 to OriSnakeTail[P] do
            SubAddBody;
      SnakeTail := tmp;
      SnakeTail^.Next := nil; //不明白为什么这句必需写上
      SnakeLength := Abs(Ori_SnakeHead[P] - OriSnakeTail[P]) + 1;
   end;
   SnakeDirection := SnakeDirectionID[P, SnakeHead^.CenterPos[P] > SnakeTail^.CenterPos[P]]; //蛇的初始运动方向
   ShowSnakePosLengthInLabel;
end;

procedure TDrawEngine.DrawGridLine; //绘制辅助观察线
var pos: array[1..3] of SmallInt; i: Byte;
begin
   SetGLColor(obj_GridLine);
   for i := 1 to 3 do
      pos[i] := SnakeHead^.OriPos[i] + MoveDirection[SnakeDirection, i];

   while (BlockState[pos[1], pos[2], pos[3]] <> bs_Obstacle) and (BlockState[pos[1], pos[2], pos[3]] <> bs_Wall) do begin
      glBegin(gl_Line_Loop);
      for i := 1 to 4 do
         glVertex3f(pos[1] + DrawGridLineFace[SnakeDirection, i, 1],
            pos[2] + DrawGridLineFace[SnakeDirection, i, 2], pos[3] + DrawGridLineFace[SnakeDirection, i, 3]);
      glEnd;
      for i := 1 to 3 do
         inc(pos[i], MoveDirection[SnakeDirection, i]);
   end;

   //在墙壁上再画一个方格,提示玩家蛇头还有多远碰到障碍物
   glBegin(gl_Line_Loop);
   for i := 1 to 4 do
      glVertex3f(pos[1] + DrawGridLineFace[SnakeDirection, i, 1],
         pos[2] + DrawGridLineFace[SnakeDirection, i, 2], pos[3] + DrawGridLineFace[SnakeDirection, i, 3]);
   glEnd;
end;

procedure TDrawEngine.DrawAidLine(posi: T3DPointB);
var d: Directions; i, t: Byte; _4Points: array[1..4] of T3DPointB; AxisSameWithSnake, ToSetAxis: Byte;
begin
   for d := md_Up to md_Out do begin
      AxisSameWithSnake := AidLineXYZWithSnake[d];
      if posi[AxisSameWithSnake] = SnakeHead^.OriPos[AxisSameWithSnake] then
         SetGLColor(obj_HighlightedAidLine)
      else
         SetGLColor(obj_AidLine);

      for i := 1 to 4 do
         for t := 1 to 3 do
            _4Points[i][t] := posi[t] + DrawGridLineFace[d, i, t];

      ToSetAxis := AidLineToSetAxis[d];
      for i := 1 to 4 do
         _4Points[i][ToSetAxis] := MapSize[ToSetAxis] * AidLineSetToWhat[d];

      glBegin(gl_Line_Loop);
      for i := 1 to 4 do
         glVertex3f(_4Points[i][1], _4Points[i][2], _4Points[i][3]);
      glEnd;
   end;

end;

procedure TDrawEngine.MakeWallDrawLists;
var i, t: Byte;
begin
   for i := 1 to 6 do begin
      WallLists[i] := glGenLists(1);
      glNewList(WallLists[i], GL_COMPILE);
      glColor4ub(GameOption.WallColor[i, 1],
         GameOption.WallColor[i, 2],
         GameOption.WallColor[i, 3], GameOption.WallAlpha);
      glBegin(GL_QUADS);
      glNormal3f(BoxNormals[i, 1], BoxNormals[i, 2], BoxNormals[i, 3]);
      for t := 1 to 4 do
         glVertex3f(MapSize[1] * BoxVertex[i, t, 1], MapSize[2] * BoxVertex[i, t, 2], MapSize[3] * BoxVertex[i, t, 3]);
      glEnd;
      glEndList;
   end;
end;

procedure TDrawEngine.DrawWall;
var i: Byte;
begin
   glDisable(GL_CULL_FACE); //墙体两面都可看见,所以取消删除面
   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
   glEnable(GL_BLEND);
   //glDisable(GL_DEPTH_TEST);
   for i := 1 to 6 do
      glCallList(WallLists[WallDrawOrder[ViewAngleH, ViewAngleV, i]]);
   glEnable(GL_DEPTH_TEST);
   glEnable(GL_CULL_FACE);
end;

procedure TDrawEngine.SnakeTurn(Turn: TurnDirection);
begin
   if Turn = td_Accelerate then begin //加速,不转向
      SnakeMove; //强制蛇移动
      Exit;
   end;
   SnakeDirection := TurnedDirection[ViewAngleH, SnakeDirection, Turn]; //计算出转向后蛇的方向
   SnakeMove; //转向后强制蛇移动,防止慢速条件下不能立即显示蛇的转向情况
   ShowKeyDirectors;
end;

procedure TDrawEngine.SnakeMove; //实现蛇移动的原理是将蛇尾的球移到蛇头的前面位置成为新蛇头,这种方法比较快,而且不用记录蛇的路径
var i: Byte; Old: PTSnakeBody; oldTailPos, posi: T3DPointB; ExtraState: SnakeExtraState;
begin
   posi := SnakeHead^.OriPos;
   for i := 1 to 3 do
      inc(posi[i], MoveDirection[SnakeDirection, i]); //计算移动后的位置

   ExtraState := se_None;
   case BlockState[posi[1], posi[2], posi[3]] of
      bs_Wall: begin
            _GameCtrl^.SnakeCollision(ct_Wall);
            Exit;
         end;
      bs_Obstacle: begin
            _GameCtrl^.SnakeCollision(ct_Obstacle);
            Exit;
         end;
      bs_SnakeBody: begin
            _GameCtrl^.SnakeCollision(ct_SelfBody);
            Exit;
         end;
      bs_IncApple: begin
            PickApple;
            ExtraState := se_IncApple;
         end;
      bs_DecApple: begin
            PickApple;
            ExtraState := se_DecApple;
         end;
      bs_Exit: begin
            ExtraState := se_Exit;
         end;
   end;

   Old := SnakeHead; //原蛇头
   oldTailPos := SnakeTail^.OriPos;

   BlockState[oldTailPos[1], oldTailPos[2], oldTailPos[3]] := bs_Empty;
   SnakeHead := SnakeTail;
   SnakeTail := SnakeTail^.Pre;
   SnakeTail^.Next := nil;
   with SnakeHead^ do begin
      Next := Old;
      Pre := nil;
      OriPos := posi;
      _3DPointB_To_3DPoint(CenterPos, OriPos);
      MakeItToSphereCenter(CenterPos);
      BlockState[OriPos[1], OriPos[2], OriPos[3]] := bs_SnakeBody;
   end;
   Old^.Pre := SnakeHead;

   case ExtraState of
      se_IncApple: begin //在尾部增加一节身体
            New(SnakeTail^.Next);
            with SnakeTail^.Next^ do begin

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -