C++实现推箱子功能附加回撤示例

跟着B站老师 做的,链接[C/C++]180行代码,推箱子就是这么简单~抄详细,学不会我还不信了,关卡切换和回退都实现了哦_哔哩哔哩_bilibili

编码环境:VS2019

利用 链栈实现的回撤功能。

LinkStack.h

#pragma once
/***链栈的实现***/
#ifdef _cplusplus
extern "C"
{
#endif

#include <fstream>
#include <iostream>
#include<stdbool.h>
using namespace std;

#define OK 1
#define ERROR 0
#define OVERFLOW -2
//typedef int Data;

struct Point
{
  int r;
  int c;
  int data;
};

typedef struct _State
{
  Point pos[3];
}Data,State;

typedef struct StackNode
{
  Data data;
  struct StackNode* next;
} StackNode, * LinkStack;

//算法1 链栈的初始化(无头节点)
void InitStack(LinkStack& S)
{ // 构造一个空栈 S,栈顶指针置空
  S = NULL;
 // return OK;
}

//算法2 链栈的入栈
void Push(LinkStack& S, Data e)
{ //在栈顶插入元素e
  LinkStack p;
  p = new StackNode; //生成新结点
  p->data = e;       //将新结点数据域置为e
  p->next = S;       //将新结点插入栈顶(类似与前插法,只不过没有头节点)
  S = p;             //修改栈顶指针为p
  printf("ok\n");
  //return OK;
}

//算法3链栈的出栈
void Pop(LinkStack& S)
{ //删除S的栈顶元素,用e返回其值
  LinkStack p;
  if (S == NULL)
      return ; //栈空
 // e = S->data;      //将栈顶元素赋给e
  p = S;            //用p临时保存栈顶元素空间,以备释放
  S = S->next;      //修改栈顶指针
  delete p;         //释放原栈顶元素的空间
 // return OK;
}
//算法4 取链栈的栈顶元素
Data GetTop(LinkStack S)
{                       //返回S的栈顶元素,不修改栈顶指针
  if (S != NULL)      //栈非空
      return S->data; //返回栈顶元素的值,栈顶指针不变
}

bool empty(LinkStack& S) {
  if (S == NULL)
      return true;

  else return false;
}
//
//void empty(LinkStack& S) {
//
//}

#ifdef _cplusplus
}
#endif
/*
int main()
{
  LinkStack s;
  int choose, flag = 0;
  SElemType j, t;
  cout << "1.初始化\n";
  cout << "2.入栈\n";
  cout << "3.读栈顶元素\n";
  cout << "4.出栈\n";
  cout << "0.退出\n\n";
  choose = -1;
  while (choose != 0)
  {
      cout << "请选择:";
      cin >> choose;
      switch (choose)
      {
      case 1: //算法q1 链栈的初始化
          if (InitStack(s))
          {
              flag = 1;
              cout << "成功对栈进行初始化\n\n";
          }
          else
              cout << "初始化栈失败\n\n";
          break;
      case 2:
      { //算法2 链栈的入栈
          fstream file;
          file.open("/Users/xiaokaixin/Documents/Code/cpp_code/txt_file/SqStack.txt");
          if (!file)
          {
              cout << "错误!未找到文件!\n\n"
                   << endl;
              exit(ERROR);
          }
          if (flag)
          {
              flag = 1;
              cout << "进栈元素依次为:\n";
              while (!file.eof())
              {
                  file >> j;
                  if (file.fail())
                      break;
                  else
                  {
                      Push(s, j);
                      cout << j << "  ";
                  }
              }
              cout << endl
                   << endl;
          }
          else
              cout << "栈未建立,请重新选择\n\n";
          file.close();
      }
      break;
      case 3: //算法3 取链栈的栈顶元素
          if (flag != -1 && flag != 0)
              cout << "栈顶元素为:\n"
                   << GetTop(s) << endl
                   << endl;
          else
              cout << "栈中无元素,请重新选择\n"
                   << endl;
          break;
      case 4: //算法4 链栈的出栈
          if (flag)
          {
              cout << "依次弹出的栈顶元素为:\n";
              while (Pop(s, t))
                  cout << t << "  ";
              cout << endl
                   << endl;
          }
          else
              cout << "栈未建立,请重新选择\n\n";
          break;
      }
  }
  return 0;
}
*/

cpp文件

#include<cstdlib>
#include<iostream>
#include<time.h>
#include<time.h>
#include<math.h>
#include<conio.h>
#include <WINDOWS.H>
#include<graphics.h>  //包含IMAGE数组
#include"LinkStack.h"

using namespace std;

#define SIZE 10
#define TOTAL_LEVEL 3

LinkStack ls; //??

enum MINE {
  SPACE,
  WALL,
  DEST,
  BOX,
  PLAYER,

};

//LinkStack* ls;

int x;
int y;
int level;
IMAGE all_image[6];
//空地0 墙1 目的地2 箱子3 玩家4 
//PLAYER+DEST 5   BOX+DEST:6
//a75  d77 72w 80s

int map[TOTAL_LEVEL][SIZE][SIZE] = {
  {
      {0,0,0,0,0,0,0,0,0,0},
      {0,0,0,1,1,1,0,0,0,0},
      {0,0,0,1,2,1,0,0,0,0},
      {0,0,0,1,3,1,1,1,1,0},
      {0,1,1,1,0,0,3,2,1,0},
      {0,1,2,3,4,0,1,1,1,0},
      {0,1,1,1,1,3,1,0,0,0},
      {0,0,0,0,1,2,1,0,0,0},
      {0,0,0,0,1,1,1,0,0,0},
      {0,0,0,0,0,0,0,0,0,0}
  },
  {
      {0,0,0,0,0,0,0,0,0,0},
      {0,0,1,1,1,1,1,1,0,0},
      {0,0,1,0,2,0,0,1,0,0},
      {0,0,1,0,0,3,0,1,0,0},
      {0,0,1,0,0,0,0,1,0,0},
      {0,0,1,0,0,4,0,1,0,0},
      {0,0,1,1,1,1,1,1,0,0},
      {0,0,0,0,0,0,0,0,0,0},
      {0,0,0,0,0,0,0,0,0,0},
      {0,0,0,0,0,0,0,0,0,0}
  },
  {
      {0,0,0,0,0,0,0,0,0,0},
      {0,1,1,1,0,0,0,0,0,0},
      {0,1,2,1,0,0,0,0,0,0},
      {0,1,3,1,0,0,0,0,0,0},
      {0,1,4,1,0,0,0,0,0,0},
      {0,1,1,1,0,0,0,0,0,0},
      {0,0,0,0,0,0,0,0,0,0},
      {0,0,0,0,0,0,0,0,0,0},
      {0,0,0,0,0,0,0,0,0,0},
      {0,0,0,0,0,0,0,0,0,0}
  }

};

void loadIMG()
{

  for (int i = 0; i < 6; i++)
  {
      char file[20] = "";
      sprintf(file, "./image/%d.bmp", i);
      loadimage(all_image + i, file, 64, 64);//IMAGE *pDstImg(// 保存图像的 IMAGE 对象指针), 
      //e.g.loadimage(all_image + i,"0.bmp",64,64); //LPCTSTR pImgFile,图片文件名
                                           //int nWidth = 0, int nHeight = 0, bool bResize = false);					
      //putimage(i*64,0,all_image + i); //坐标原点为左上角。注意x,y坐标

  }

}

void upMove() {
  if (map[level][x - 1][y] == SPACE || map[level][x - 1][y] == DEST) {
      map[level][x - 1][y] += PLAYER;
      map[level][x][y] -= PLAYER;
  }
  else if (map[level][x - 1][y] == BOX || map[level][x - 1][y] == BOX + DEST) {
      if (map[level][x - 2][y] == SPACE || map[level][x - 2][y] == DEST) {
          map[level][x - 2][y] += BOX;
          map[level][x - 1][y] = map[level][x - 1][y] + PLAYER - BOX;
          map[level][x][y] -= PLAYER;
      }

  }

}

void downMove() {
  if (map[level][x + 1][y] == SPACE || map[level][x + 1][y] == DEST) {
      map[level][x + 1][y] += PLAYER;
      map[level][x][y] -= PLAYER;
  }
  else if (map[level][x + 1][y] == BOX || map[level][x + 1][y] == BOX + DEST) {
      if (map[level][x + 2][y] == SPACE || map[level][x + 2][y] == DEST) {
          map[level][x + 2][y] += BOX;
          map[level][x + 1][y] = map[level][x + 1][y] + PLAYER - BOX;
          map[level][x][y] -= PLAYER;
      }

  }

}

void leftMove() {
  if (map[level][x][y - 1] == SPACE || map[level][x][y - 1] == DEST) {
      map[level][x][y - 1] += PLAYER;
      map[level][x][y] -= PLAYER;
  }
  else if (map[level][x][y - 1] == BOX || map[level][x][y - 1] == BOX + DEST) {
      if (map[level][x][y - 2] == SPACE || map[level][x][y - 2] == DEST) {
          map[level][x][y - 2] += BOX;
          map[level][x][y - 1] = map[level][x][y - 1] + PLAYER - BOX;
          map[level][x][y] -= PLAYER;
      }

  }

}

void rightMove() {
  if (map[level][x][y + 1] == SPACE || map[level][x][y + 1] == DEST) {
      map[level][x][y + 1] += PLAYER;
      map[level][x][y] -= PLAYER;
  }
  else if (map[level][x][y + 1] == BOX || map[level][x][y + 1] == BOX + DEST) {
      if (map[level][x][y + 2] == SPACE || map[level][x][y + 2] == DEST) {
          map[level][x][y + 2] += BOX;
          map[level][x][y + 1] = map[level][x][y + 1] + PLAYER - BOX;
          map[level][x][y] -= PLAYER;
      }

  }

}

void gameDraw() {
  for (int i = 0; i < SIZE; i++)
  {
      for (int j = 0; j < SIZE; j++)
      {
          switch (map[level][i][j])
          {
          case SPACE:
              putimage(j * 64, i * 64, all_image);
              break;
          case WALL:
              putimage(j * 64, i * 64, all_image + 1);
              break;
          case DEST:
              putimage(j * 64, i * 64, all_image + 2);
              break;
          case BOX:
              putimage(j * 64, i * 64, all_image + 3);
              break;
          case PLAYER:
              x = i;
              y = j;
              putimage(j * 64, i * 64, all_image + 4);
              break;
          case PLAYER + DEST:
              putimage(j * 64, i * 64, all_image + 4);
              x = i;
              y = j;
              break;
          case BOX + DEST:
              putimage(j * 64, i * 64, all_image + 5);
              break;
          default:
              break;
          }

      }
      cout << endl;

  }

}

//对应的ASC码值
//W w:119,87  Dd:100,68 Ww:119,87 Ss:115,83 空格:32
void saveState(int x, int y, int dir) {//player的坐标,以及keyevent
  //State t;
  State t;
  memset(&t, 0, sizeof(State));
  switch (dir)
  {
  case 119://w
  case 87:
      for (int i = 0; i < 3; i++)
      {
          t.pos[i].r = x - i;  //依次记录 player 、player的下一格、以及player的下下一格 的行列坐标以及data
          t.pos[i].c = y;
          t.pos[i].data = map[level][t.pos[i].r][t.pos[i].c];

      }
      Push(ls, t);
      break;
  case 115://s
  case 83:
      for (int i = 0; i < 3; i++)
      {
          t.pos[i].r = x + i;  //依次记录 player 、player的下一格、以及player的下下一格 的行列坐标以及data
          t.pos[i].c = y;
          t.pos[i].data = map[level][t.pos[i].r][t.pos[i].c];

      }
      Push(ls, t);
      Data p = GetTop(ls);
      break;

  case 97://a
  case 65:
      for (int i = 0; i < 3; i++)
      {
          t.pos[i].r = x;  //依次记录 player 、player的下一格、以及player的下下一格 的行列坐标以及data
          t.pos[i].c = y - i;
          t.pos[i].data = map[level][t.pos[i].r][t.pos[i].c];
      }
      Push(ls, t);
      break;

  case 100://d
  case 68:
      for (int i = 0; i < 3; i++)
      {
          t.pos[i].r = x;  //依次记录 player 、player的下一格、以及player的下下一格 的行列坐标以及data
          t.pos[i].c = y + i;
          t.pos[i].data = map[level][t.pos[i].r][t.pos[i].c];

      }
      Push(ls, t);
      break;
  default:
      break;
  }
  
}

void rollBack() {
  if (empty(ls))
  {
      return;
  }
  State t = GetTop(ls);
  for (int i = 0; i < 3; i++)
  {
      map[level][t.pos[i].r][t.pos[i].c] = t.pos[i].data;
  }
  Pop(ls);
}

void keyEvent() {
  char event = _getch();
  if (event != 32  && event != -32) {
      saveState(x, y, event);
  }
  switch (event)
  {
  case 'W':
  case 'w':
      upMove();
      break;

  case 's':
  case 'S':
      downMove();
      break;

  case 'A':
  case 'a':
      leftMove();
      break;
  case 'd':
  case 'D':
      rightMove();
      break;
  case 32:
      rollBack();
      break;
  default:
      break;
  }


}

bool judge_pass() {
  for (int i = 0; i < SIZE; i++)
  {
      for (int j = 0; j < SIZE; j++)
      {
          if (map[level][i][j] == BOX)
          {
              return false;
          }

      }

  }

  return true;
}

int main() {
  InitStack(ls);
  initgraph(SIZE * 64, SIZE * 64, TRUE);
  loadIMG();
  //system("mode con lines=20 cols=25");
  level = 0;
  while (level < TOTAL_LEVEL)
  {
      //system("cls");
      gameDraw();
      keyEvent();

      if (judge_pass())
      {
          if (level == TOTAL_LEVEL - 1) {
              //system("cls");
              gameDraw();
          }
          level++;
          while (!empty(ls))
          {
              Pop(ls);
          }

      }

  }

  MessageBox(NULL, TEXT("CONGRATULATIONS!"), TEXT("GAME OVER"), MB_OK);

  // getchar();


  return 0;
}

附文件结构

关于C+++实现推箱子功能附加回撤示例的文章就介绍至此,更多相关C+++ 推箱子内容请搜索编程宝库以前的文章,希望大家多多支持编程宝库

 C++98时代C++98编译器对int常量情有独钟,因为这是少数它能直接识别的东西。因为这个有限的能力,编译器就能够预先判定数组的大小了:TEST_METHOD(TestConstVar){ //in ...