📄 unit2.pas
字号:
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 + -