3D 服务器端以向量计算为主的角色位置的算法

3D服务器端玩家行走处理是服务器端根据客户端行走路径、玩家行走时间以及速度(包括变化速度)计算得出玩家的当前位置。

由于客户端行走是一条路径,不使用2D中的格子计算算法,未能高效的获取角色的当前位置,运用玩家行走路径,行走速度,行走时间这些已量,进行计算玩家的当前精确位置。由于3D游戏中的点为xyz的空间点,所以牵连的计算为3维向量计算。

空间两点距离计算公式为:

玩家在某条线段上的坐标x:

玩家在某条线段上的坐标y:

玩家在某条线段上的坐标z:

角色当前位置计算原理分析:

角色行走是一条路径,这条路径使用点序列表示,角色开始行走记录当前时间TimeStart,获取觉得当前位置的计算,首先获取当前时间TimeNow,根据TimeNow-TimeStart的时间差与角色的行走速度,获取角色已经行走过的距离distance,计算每两点的距离,判定角色当前时间所处在哪一条路径上,及角色在哪两点之间。然后使用向量计算公式计算当前角色处于的坐标点位置。

角色位置位置计算的类封装实现代码:

#pragma once

class CCoordinatePath
{
public:
	CCoordinatePath(void);
	~CCoordinatePath(void);

public:
	// 更新行走路径
	void UpdatePath(COORDINATE_3D stopCoordinate3D);
	void UpdatePath(vector<COORDINATE_3DPATH> vtPath, COORDINATE_3D stopCoordinate3D, float nCompletePath = 0);
	// 开始行走(移动计算)
	void StartMove(DWORD dwStartTime);
	// 获取当前空间位置
	COORDINATE_3D GetCoordinate(DWORD dwNowTime);
	// 获取行走路径
	const vector<COORDINATE_3DPATH>* GetPath();
	// 获取停止位置
	COORDINATE_3D GetStopCoordinate();
	// 获取移动总距离(从开始行走到现在的行走总距离)
	float GetCompletePath(DWORD dwNowTime);
	// 更新玩家速度
	void UpdateSpeed(unsigned short wSpeed, DWORD dwNowTime);
	// 获取当前速度
	unsigned short GetSpeed();
	// 玩家是否正在移动
	bool IsMoving(DWORD dwNowTime);

private:
	// 行走路径
	vector<COORDINATE_3DPATH> m_vtPath;
	// 停止点
	COORDINATE_3D m_stopCoordinate3D;

	// 已完成路径
	float m_nCompletePath;
	// 玩家当前速度
	unsigned short m_wCurSpeed;
	// 行走路径开始时间
	DWORD m_dwStartMoveTime;
	
};

#include "StdAfx.h"
#include "CoordinatePath.h"

CCoordinatePath::CCoordinatePath(void)
{
	m_wCurSpeed = 4;
}

CCoordinatePath::~CCoordinatePath(void)
{
}

void CCoordinatePath::UpdatePath( COORDINATE_3D stopCoordinate3D )
{
	m_vtPath.clear();
	m_stopCoordinate3D = stopCoordinate3D;
	m_nCompletePath = 0;
}

void CCoordinatePath::UpdatePath( vector<COORDINATE_3DPATH> vtPath, COORDINATE_3D stopCoordinate3D, float nCompletePath /*= 0*/ )
{
	m_vtPath = vtPath;
	m_stopCoordinate3D = stopCoordinate3D;
	m_nCompletePath = nCompletePath;
}

void CCoordinatePath::StartMove( DWORD dwStartTime )
{
	m_dwStartMoveTime = dwStartTime;
}

COORDINATE_3D CCoordinatePath::GetCoordinate(DWORD dwNowTime)
{
	if (m_vtPath.size() == 0)
	{
		return m_stopCoordinate3D;
	}

	float nTotalDistance = GetCompletePath(dwNowTime);

	if (nTotalDistance < 0)
	{
		cout << "计算玩家移动距离错误" << endl;
		return m_stopCoordinate3D;
	}

	// ceshi
	//cout << "距离:" << nTotalDistance << "时间" << (dwNowTime-m_dwStartMoveTime) << endl;

	COORDINATE_3D coordinate3D;

	// 上面已经计算出玩家行走总距离,计算玩家位置
	vector<COORDINATE_3DPATH>::iterator itPath = m_vtPath.begin();
	for (; itPath!=m_vtPath.end(); ++itPath)
	{
		if (itPath->allDistance > nTotalDistance)
		{
			// 角色当前位置在当前path中,计算当前位置
			float nCurDistance = nTotalDistance - (itPath->allDistance - itPath->curDistance);

			if (nCurDistance < 0)
			{
				cout << "[严重错误]获取坐标" << endl;
				return m_stopCoordinate3D;
			}

			coordinate3D.x = itPath->x + itPath->dFormula*itPath->xDistance*nCurDistance;
			coordinate3D.y = itPath->y + itPath->dFormula*itPath->yDistance*nCurDistance;
			coordinate3D.z = itPath->z + itPath->dFormula*itPath->zDistance*nCurDistance;
			coordinate3D.dir = itPath->dir;

			if (coordinate3D.x ==1 && coordinate3D.y==1 && coordinate3D.z == 1)
			{
				int i = 0;
			}
			///yang
			//cout << "当前移动坐标:x:" << coordinate3D.x << ",y:" << coordinate3D.y << ",z:" << coordinate3D.z << endl;
			///yang
			return coordinate3D;
		}
	}

	// 到达目标点做先前点路径的清理工作
	m_vtPath.clear();

	return m_stopCoordinate3D;
}

const vector<COORDINATE_3DPATH>* CCoordinatePath::GetPath()
{
	return &m_vtPath;
}

COORDINATE_3D CCoordinatePath::GetStopCoordinate()
{
	return m_stopCoordinate3D;
}

float CCoordinatePath::GetCompletePath( DWORD dwNowTime )
{
	// 无变速的移动距离计算
	DWORD dwMoveTime = dwNowTime-m_dwStartMoveTime;

	return (m_nCompletePath + m_wCurSpeed*dwMoveTime/1000.0f);
}

void CCoordinatePath::UpdateSpeed( unsigned short wSpeed, DWORD dwNowTime )
{
	// 计算已经完成路径
	m_nCompletePath += GetCompletePath(dwNowTime);
	m_dwStartMoveTime = dwNowTime;

	m_wCurSpeed = wSpeed;	//当前速度
}

unsigned short CCoordinatePath::GetSpeed()
{
	return m_wCurSpeed;
}

bool CCoordinatePath::IsMoving( DWORD dwNowTime )
{
	GetCoordinate(dwNowTime);

	if (m_vtPath.size() > 0)
	{
		return true;
	}
	else
	{
		return false;
	}
}



For more complete information about compiler optimizations, see our Optimization Notice.