zoukankan      html  css  js  c++  java
  • 原因好消息: PSP游戏自己主动算法设计(两)

    这是我们讲的传说中的一项措施A×算法。事实上,类上传之前似小件,下面我们分析一下它去

    毕竟,在游戏程序,我们从移动一个点到另一个点。和得到的轨迹的最短距离,类别似这样的算法以及几个。运营效率几乎是相同的,最根本无法跟踪


    首先,从一点移动到还有一点。最快就是直接走过去了,就像小男生爱上小女生。最好的办法就是直接走到她面前说:我爱你

    只是理想状态。差点儿是没有的,弯路那是必定的经过,有曲线。事实上更美……


    那么弯路该怎么走呢,是不是先去背景看下毛主席,再去三亚晒个太阳,再回来告诉她外面的世界好美,不。不,不……

    再怎么弯的曲线,越接近直接。越好,所以步骤是:


    1.向周围4个或8个方向,全部不是边界的点,记录这些点到目标的距离。从開始到这个点的距离。上一个到这里的点

    2.依据两个距离和最小为标准,依次“递归”全部的点直到目标点

    3.反向得到路径,就是近期的曲线路径


    问:会不会到达同一个点,存在不同的距离

    答:是,可是依据近期距离标准递推下去,更远距离的将被丢弃


    问:递归为什么加引號

    答:用队列实现堆栈,也算是递归,可是不会耗尽线程堆栈


    为了,方便在推箱子中检測能否打到某个点,我改动下代码实现不记录上一个点,加速运行

    只是后来就没有使用这个功能。主要代码例如以下:

    alpha.cpp

    // ****************************************************************************************************
    // 文件: alpha.cpp
    // 凝视:
    // A*寻路算法模块, 推断两点之间是否通行, 并得到路径和各节点的权值
    // 扩展不保存路径提速, 不使用Dijkstra, 參见http://www.2cto.com/kf/201104/87378.html
    // ****************************************************************************************************
    //#include <stdlib.h>
    #include <malloc.h>
    
    #define __LATTICE_DLL_INC_	// DLL内部编译
    #include "api.h"
    
    // 创建一个场景, 并初始化
    V32API PSCENE __stdcall AlphaInit(long dwSizeX, long dwSizeY, long dwMaxCost, UINT dwFlags)
    {
    	PSCENE ps = (PSCENE)malloc(sizeof(SCENE));
    	if(ps == NULL)
    	{
    		return NULL;
    	}
    	V32Clear32(ps, 0, sizeof(SCENE));	// memset, 自己主动计算DWORD数量
    
    	ps->NodeCount = dwSizeX * dwSizeY;	// 节点数量
    	ps->Nodes = (PNODE)malloc(ps->NodeCount * sizeof(NODE));
    	if(ps->Nodes == NULL)
    	{
    		AlphaExit(ps, 0xFFFFFFFF);
    		return NULL;
    	}
    
    	ps->Matrix = (PBYTE)malloc(ps->NodeCount * sizeof(BYTE));	// 场景矩阵
    	if(ps->Matrix == NULL)
    	{
    		AlphaExit(ps, 0xFFFFFFFF);
    		return NULL;
    	}
    
    	ps->Steps = (PSTEP)malloc(ps->NodeCount * sizeof(STEP));
    	if(ps->Steps == NULL)
    	{
    		AlphaExit(ps, 0xFFFFFFFF);
    		return NULL;
    	}
    
    	if(dwMaxCost <= 0)
    	{
    		dwMaxCost = dwSizeX * dwSizeY;	// 相邻格子逐个走遍
    	}
    	ps->MaxCost = dwMaxCost * CDC_PROP_NEAR;	// 最大消耗(距离值)
    	ps->SizeY = dwSizeY;
    	ps->SizeX = dwSizeX;
    	ps->Flags = dwFlags;
    	return ps;
    }
    
    // 编辑场景数据
    V32API int __stdcall AlphaEdit(PSCENE pScene, long dwPosX, long dwPosY, void *lpValue)
    {
    	PBYTE p;
    	if(dwPosX < 0 && dwPosY < 0)
    	{
    		// 读取
    		p = pScene->Scene;
    		if(p == NULL) p = pScene->Matrix;
    		*(PBYTE)lpValue = p[dwPosY * pScene->SizeX + dwPosX];
    		return 2;
    	}
    	if(dwPosX < 0 || dwPosY < 0)
    	{
    		// 使用外部数据指针
    		pScene->Scene = (PBYTE)lpValue;
    		return 3;
    	}
    	// 设置字节数值
    	if(dwPosX >= pScene->SizeX || dwPosY >= pScene->SizeY)
    	{
    		//memcpy(pScene->Matrix, lpValue, pScene->NodeCount);
    		return 0;
    	}
    	p = pScene->Scene;
    	if(p == NULL) p = pScene->Matrix;
    	if(lpValue == NULL)
    	{
    		return p[dwPosY * pScene->SizeX + dwPosX];	// 读取
    	}else
    	{
    		p[dwPosY * pScene->SizeX + dwPosX] = *(PBYTE)lpValue;	// 写入
    	}
    	return 1;
    }
    
    inline long AlphaCalc(PSTAR pStar1, PSTAR pStar2)
    {
    	// 直接使用坐标差和取代三角函数开方
    	if(pStar1->X > pStar2->X)
    	{
    		if(pStar1->Y > pStar2->Y)
    			return (pStar1->X - pStar2->X) + (pStar1->Y - pStar2->Y);
    		else
    			return (pStar1->X - pStar2->X) + (pStar2->Y - pStar1->Y);
    	}else
    	{
    		if(pStar1->Y > pStar2->Y)
    			return (pStar2->X - pStar1->X) + (pStar1->Y - pStar2->Y);
    		else
    			return (pStar2->X - pStar1->X) + (pStar2->Y - pStar1->Y);
    	}
    	//return dX + dY;
    }
    
    inline void AlphaNode(PSCENE pScene, long dwIndex, long dwPrevId, long dwCost, long dwLast, long dwPosX, long dwPosY)
    {
    	// 開始和循环各调用一次。dwIndex在调用之后自加。初始为0
    	if(dwIndex >= pScene->NodeCount)
    		return;
    	//pScene->Nodes[dwIndex].Star = *pStar;	// 是否会创建暂时结构体??
    	pScene->Nodes[dwIndex].Star.X = dwPosX;
    	pScene->Nodes[dwIndex].Star.Y = dwPosY;
    	pScene->Nodes[dwIndex].Prev = dwPrevId;
    	if(dwPrevId != -1)
    		pScene->Nodes[dwIndex].Step = pScene->Nodes[dwPrevId].Step + 1;
    	else
    		pScene->Nodes[dwIndex].Step = 1;
    	pScene->Nodes[dwIndex].Cost = dwCost;
    	pScene->Nodes[dwIndex].Last = dwLast * 10;	// 每次dwLen又一次计算得到格子数
    	pScene->Nodes[dwIndex].Flags = SNF_PROP_READY;
    	return;
    }
    
    inline BYTE fnAlphaUnit(PSCENE pScene, PSTAR ps)
    {
    	BYTE *pUnit = pScene->Scene;
    	if(pUnit == NULL) pUnit = pScene->Matrix;
    	return pUnit[ps->Y * pScene->SizeX + ps->X];
    }
    
    inline PSTEP fnAlphaStep(PSCENE pScene, PSTAR ps)
    {
    	return &pScene->Steps[ps->Y * pScene->SizeX + ps->X];
    }
    
    // 寻路指定场景
    V32API int __stdcall AlphaStar(PSCENE pScene, PSTAR lpStart, PSTAR lpTarget, long *pdwStep)
    {
    	PSTEP pStep;
    
    	long lCurCost, nMaxCost;	// 暂存消耗,最大列表
    	long i, j;					// temp & looping var
    	STAR tps, cps;				// test pos, current pos
    
    	long dwValue;
    	long dwIndex = 0;
    	long dwNode = 0;			// 当前Node数
    	long dwLoop;
    	long dwLen;					// 与终点距离
    
    	// check for memory address accessable
    	if(lpStart == NULL || lpTarget == NULL)
    	{
    		return 0;	// 始末坐标无效
    	}
    	
    	dwLen = AlphaCalc(lpStart, lpTarget);	// dwLen = ΔX + ΔY
    	if(dwLen == 0)
    	{
    		return -1;	// 始末坐标同样
    	}
    	// zero step memory(cell prop list)
    	V32Clear32(pScene->Steps, 0, pScene->NodeCount * sizeof(STEP));
    	// 加入第一个点
    	dwNode = 0;
    	AlphaNode(pScene, dwNode, -1, 0, dwLen, lpStart->X, lpStart->Y);
    	dwNode++;
    	
    	// enter loop - check around cells
    	while(1)
    	{
    		nMaxCost = pScene->MaxCost;	// 不可能比这个大
    		dwIndex = -1;
    		for(dwLoop = 0; dwLoop < dwNode; dwLoop++)
    		{
    			if(pScene->Nodes[dwLoop].Flags != SNF_PROP_ERROR)
    			{
    				//找未关闭中最小路程和的点
    				lCurCost = pScene->Nodes[dwLoop].Cost + pScene->Nodes[dwLoop].Last;
    				if(lCurCost < nMaxCost)
    				{
    					nMaxCost = lCurCost;	// 调整最大距离
    					dwIndex = dwLoop;		// 保存节点序号
    					//break;	// 全部节点都要计算
    				}
    			}
    		}
    		if(dwIndex == -1)
    		{
    			return -2;		// there is no path exist!
    		}
    		cps.X = pScene->Nodes[dwIndex].Star.X;
    		cps.Y = pScene->Nodes[dwIndex].Star.Y;
    		if((cps.X == lpTarget->X)&&(cps.Y == lpTarget->Y))
    		{
    			break;	// 当前点已是终点, 跳出while循环
    		}
    		//sprintf(szText, "select best cell:[%d,%d] for check:", cps.X, cps.Y);
    		for(i = -1; i <= 1; i++)
    		{
    			for(j = -1; j <= 1; j++)
    			{
    				//if(i == 0 && j == 0) continue;	// 同意走对角线,仅仅要两个不同一时候为零(即不是自身)
    				if(i == 0 && j == 0) continue;
    				if(i != 0 && j != 0) continue;	// 禁止走对角线,必有且仅仅有一个为零{[(i & j) == 0]&&[(i | j) != 0]}
    				tps.X = cps.X + i;
    				tps.Y = cps.Y + j;
    				if(tps.X < 0) continue;	// 左边越界
    				if(tps.X >= pScene->SizeX)	continue;	// 右边越界
    				if(tps.Y < 0) continue;	// 顶边越界
    				if(tps.Y >= pScene->SizeY) continue;	// 底边越界
    				// 该点坐标在矩阵范围内
    				if(fnAlphaUnit(pScene, &tps) & (BYTE)pScene->Flags)
    				{
    					continue;	// 消除特殊位以后仍然不可通行(独立程序: 仅同意空格或目标)
    				}
    				pStep = fnAlphaStep(pScene, &tps);
    				switch(pStep->Flags){
    				case SSF_PROP_UNKNOW:	// it'v not been check
    					dwValue = pScene->Nodes[dwIndex].Cost;
    					//if(i * j != 0)
    					//	dwValue += CDC_PROP_AWAY;	// 横纵坐标都是非零, 对角
    					//else
    						dwValue += CDC_PROP_NEAR;	// 不论什么一个坐标为零, 相邻
    					dwLen = AlphaCalc(&tps, lpTarget);	//dwLen = ΔX + ΔY
    					AlphaNode(pScene, dwNode, dwIndex, dwValue, dwLen, tps.X, tps.Y);
    					pStep->Flags = SSF_PROP_OPENED;	// open it
    					pStep->Index = dwNode++;
    					// sprintf(szText, "add cell:[%d,%d] for check:", tps.X, tps.Y);
    					break;
    				case SSF_PROP_OPENED:	// this cell is valid
    					dwValue = pStep->Index;
    					dwLen = pScene->Nodes[dwIndex].Cost;
    					dwLen += CDC_PROP_NEAR;	// 仅仅能相邻
    					if(dwLen < pScene->Nodes[dwValue].Cost)
    					{
    						pScene->Nodes[dwValue].Cost = dwLen;
    						pScene->Nodes[dwValue].Prev = dwIndex;
    						pScene->Nodes[dwValue].Step = pScene->Nodes[dwIndex].Step + 1;	//change level
    					}
    					//sprintf(szText, "change pID for cell:[%d,%d] to %d.", tps.X, tps.Y, nID);
    					break;
    				default:
    					//end if(lpOGrid[tps.X][tps.Y].State..
    					break;
    				}
    				//end if((lpCell..
    				//end if((tps.X..
    				//end if(((i..
    			}	//next j
    		}	//next i
    		// it will continue if any path and not at target
    		pStep = fnAlphaStep(pScene, &cps);
    		pScene->Nodes[dwIndex].Flags = SNF_PROP_ERROR;
    		pStep->Flags = SSF_PROP_CLOSED;		// close it
    		//sprintf(szText, "close cell:[%d,%d] ok.", cps.X, cps.Y);
    	}
    	// 函数malloc()和realloc()时间消耗大,用空间换取时间
    	dwValue = pScene->Nodes[dwIndex].Cost + pScene->Nodes[dwIndex].Last;
    	if(pdwStep == NULL)
    	{
    		// 不须要结果详情
    		return dwValue;		// return cost to get here
    	}
    	//sprintf(szText, "best path found in cost %d.", dwValue);
    	pScene->StarCount = pScene->Nodes[dwIndex].Step;
    	SafeFree(pScene->Stars);	// release old path
    	pScene->Stars = (PSTAR)malloc(pScene->StarCount * sizeof(STAR));
    	if(pScene->Stars == NULL)
    	{
    		return -3;	// Out of memory
    	}
        // ...
        dwLoop = pScene->StarCount;
    	*pdwStep = dwLoop;	// set the steps
    	while(dwLoop > 0)	// it can also base on dwIndex
    	{
    		dwLoop--;
    		//pScene->m_pStarPath[dwLoop].X = pScene->Nodes[dwIndex].Star.X;
    		//pScene->m_pStarPath[dwLoop].Y = pScene->Nodes[dwIndex].Star.Y;
    		pScene->Stars[dwLoop] = pScene->Nodes[dwIndex].Star;
    		dwIndex = pScene->Nodes[dwIndex].Prev;	// parent id
    		//sprintf(szText, "the %d cell:[%d,%d] added to path.", i, lpRoad[i].X, lpRoad[i].Y);
    	}
    	return dwValue;		// return cost to get here
    }
    
    V32API int __stdcall AlphaData(PSCENE pScene, UINT dwPropId, long dwIndex)
    {
    	VAR v;
    	v.pValue = (void*)pScene;
    	v.dwValue += dwPropId;
    	if(dwIndex < 0)
    	{
    		return (int)*v.plValue;	// 直接定位成员
    	}
    	v.dwValue = *v.pdwValue;
    	v.dwValue += dwIndex;
    	return (int)*v.plValue;
    }
    
    // 销毁一个场景, 释放资源
    V32API int __stdcall AlphaExit(PSCENE pScene, UINT dwFlags)
    {
    	if(pScene)
    	{
    		SafeFree(pScene->Stars);
    		pScene->StarCount = 0;
    		SafeFree(pScene->Steps);
    		pScene->Scene = NULL;	// 外部数据指针
    		SafeFree(pScene->Matrix);
    		SafeFree(pScene->Nodes);
    		pScene->NodeCount = 0;
    		free(pScene);
    		//pScene = NULL;
    	}
    	return 1;
    }

    当中V32API是一个宏定义。在v32/api.h中因此依赖V32.dll

    这是我的一个基础类库的基类,包含经常使用的C语言函数和C++封装类,另一些宏定义

    函数大多是内联汇编的裸函数。宏定义通常是高速释放内存用的,如

    #define SafeDelete(p)		if(p){delete p; p = NULL;}
    

    C++仅仅是封装C函数为类,同一时候扩展了C++特效。例如,智能指针,请参阅相关的头


    版权声明:本文博客原创文章。博客,未经同意,不得转载。

  • 相关阅读:
    apicloud 运费计算js+页面
    css让字体细长
    vue 请求完接口后执行方法
    js监听当前页面再次加载
    用apicloud+vue的VueLazyload实现缓存图片懒加载
    git merge和git rebase的区别(转)
    yuan先生博客链接
    django组件之contenttype(一)
    Django的orm中get和filter的不同
    python第三方库requests详解
  • 原文地址:https://www.cnblogs.com/mfrbuaa/p/4617166.html
Copyright © 2011-2022 走看看