MMO中,游戏场景即游戏地图,服务器要做的就是将地图上所有的玩家信息同步。为了减轻服务器压力,根据游戏本身的设定,如能见度,服务器只需根据不同的玩家返回相应的数据即可。

        假设将地图切成了N个矩形块,在 (0, 0) 这个坐标上的玩家,我们只需要给玩家返回 (-1, 1) (0, 1) (1, 1) (-1, 0) (0, 0) (1, 0) (-1, -1) (0, -1) (1, -1) 矩形块上的数据即可。

        但是,使用矩形切片,每次需要计算的场景为 9。如果使用正六边形切片,每次需要计算的场景则为 7。使用正六边形,并不会减少总的数据量,但能减少周围场景服务器的访问次数。而且,相比矩形,正六边形的计算更为复杂。

六边形cube坐标系:

六边形区域计算:

将cube坐标系转换成offset坐标系(此处假定step=0.5):

初始化将地图的某个点的相对 cube 坐标传入,并设置步长,计算出 radius 的值。

xy::utils::hexagon::Hexagon::Hexagon(double x, double y, double z, long double step) : cube{x, y, z}, step(step) {this->offset = {static_cast<double>((y - x) * step), static_cast<double>(-std::sqrt(3) * z * step)};this->radius = (2.0 * std::sqrt(3) / 3.0) * step;
}

根据玩家的绝对坐标,判断玩家是否跨越了此区域。

double xy::utils::hexagon::Hexagon::compute_distance(double x, double y) {return std::sqrt(std::pow(x - this->offset.x, 2) + std::pow(y - this->offset.y, 2));
}bool xy::utils::hexagon::Hexagon::has_in_radius(double x, double y) {return this->compute_distance(x, y) <= this->radius ? true : false;
}

如果玩家跨越了此区域,获取玩家当前所在的区域,然后将玩家的数据复制到玩家所在区域去。

这里需要用到 offset 转 cube 的公式。

xy::utils::hexagon::Hexagon::Cube xy::utils::hexagon::Hexagon::offset2cube(double x, double y) {x -= this->offset.x;y -= this->offset.y;return this->offset2cube_absolutely(x, y);
}xy::utils::hexagon::Hexagon::Cube xy::utils::hexagon::Hexagon::offset2cube_absolutely(double x, double y) {/*ax + by = mcx + dy = nx = (md - bn) / (ad - bc)y = (mc - an) / (bc - ad)*/double a = 1.0, b = -1.0, c = 1.0, d = 1.0;double z = -std::sqrt(3) / 3.0 * y / this->step;double m = -x / this->step, n = -z;x = (d * m - b * n) / (a * d - b * c);y = (c * m - a * n) / (b * c - a * d);Cube cube {x, y, z};return cube;
}

如果用 python 的 numpy 结合线性代数解方程组就简单了,可惜 python 运算效率实在太慢,用来做服务器将大大降低承载量。

import numpy
import mathdef offset2cube_absolutely(offset_x, offset_y, step=0.5):a = numpy.asarray([[1, -1],[1, 1]])z = -(math.sqrt(3) / 3) * offset_y / stepb = numpy.asarray([-offset_x / step, -z])x, y = numpy.linalg.solve(a, b)return x, y, z

完整代码:

hexagon.h

#ifndef XY_HEXAGON
#define XY_HEXAGONnamespace xy {namespace utils {namespace hexagon {class Hexagon {public:struct Cube {double x, y, z;};public:struct Offset {double x, y;};public:Hexagon(double, double, double, long double=0.5);~Hexagon();private:Cube cube;Offset offset;long double step;long double radius;public:Cube& get_cube();Offset& get_offset();long double get_step() const;long double get_radius() const;public:double compute_distance(Offset&);double compute_distance(double, double);bool has_in_radius(Offset&);bool has_in_radius(double, double);Cube offset2cube(Offset&);Cube offset2cube(double, double);Cube offset2cube_absolutely(Offset&);Cube offset2cube_absolutely(double, double);};}}
}#endif

hexagon.cpp

#include <cmath>
#include "hexagon.h"xy::utils::hexagon::Hexagon::Hexagon(double x, double y, double z, long double step) : cube{x, y, z}, step(step) {this->offset = {static_cast<double>((y - x) * step), static_cast<double>(-std::sqrt(3) * z * step)};this->radius = (2.0 * std::sqrt(3) / 3.0) * step;
}xy::utils::hexagon::Hexagon::~Hexagon() {}xy::utils::hexagon::Hexagon::Cube& xy::utils::hexagon::Hexagon::get_cube() {return this->cube;
}xy::utils::hexagon::Hexagon::Offset& xy::utils::hexagon::Hexagon::get_offset() {return this->offset;
}long double xy::utils::hexagon::Hexagon::get_step() const {return this->step;
}long double xy::utils::hexagon::Hexagon::get_radius() const {return this->radius;
}double xy::utils::hexagon::Hexagon::compute_distance(Offset& offset) {return this->compute_distance(offset.x, offset.y);
}double xy::utils::hexagon::Hexagon::compute_distance(double x, double y) {return std::sqrt(std::pow(x - this->offset.x, 2) + std::pow(y - this->offset.y, 2));
}bool xy::utils::hexagon::Hexagon::has_in_radius(Offset& offset) {return this->has_in_radius(offset.x, offset.y);
}bool xy::utils::hexagon::Hexagon::has_in_radius(double x, double y) {return this->compute_distance(x, y) <= this->radius ? true : false;
}xy::utils::hexagon::Hexagon::Cube xy::utils::hexagon::Hexagon::offset2cube(Offset& offset) {return this->offset2cube(offset.x, offset.y);
}xy::utils::hexagon::Hexagon::Cube xy::utils::hexagon::Hexagon::offset2cube(double x, double y) {x -= this->offset.x;y -= this->offset.y;return this->offset2cube_absolutely(x, y);
}xy::utils::hexagon::Hexagon::Cube xy::utils::hexagon::Hexagon::offset2cube_absolutely(Offset& offset) {return this->offset2cube_absolutely(offset.x, offset.y);
}xy::utils::hexagon::Hexagon::Cube xy::utils::hexagon::Hexagon::offset2cube_absolutely(double x, double y) {/*ax + by = mcx + dy = nx = (md - bn) / (ad - bc)y = (mc - an) / (bc - ad)*/double a = 1.0, b = -1.0, c = 1.0, d = 1.0;double z = -std::sqrt(3) / 3.0 * y / this->step;double m = -x / this->step, n = -z;x = (d * m - b * n) / (a * d - b * c);y = (c * m - a * n) / (b * c - a * d);Cube cube {x, y, z};return cube;
}

main.cpp

#include <iostream>
#include <cmath>
#include "hexagon.h"using namespace std;
using namespace xy::utils::hexagon;void relatively_demo() {Hexagon* hexagon_12_1 = new Hexagon(-1, 2, -1);Hexagon* hexagon_20_2 = new Hexagon(2, 0, -2);const Hexagon::Cube cube_tmp_0 = hexagon_12_1->offset2cube(hexagon_20_2->get_offset());cout << "(2, 0, -2)相对(-1, 2, -1),其偏移量为: x=" << cube_tmp_0.x << " y=" << cube_tmp_0.y << " z=" << cube_tmp_0.z << endl;const Hexagon::Cube cube_tmp_1 = hexagon_20_2->offset2cube(hexagon_12_1->get_offset());cout << "(-1, 2, -1)相对(2, 0, -2),其偏移量为: x=" << cube_tmp_1.x << " y=" << cube_tmp_1.y << " z=" << cube_tmp_1.z << endl;if (hexagon_12_1) {delete hexagon_12_1;}if (hexagon_20_2) {delete hexagon_20_2;}
}void absolutely_demo() {Hexagon* hexagon = new Hexagon(2, -1, -1);const Hexagon::Cube& cube_tmp_0 = hexagon->offset2cube_absolutely(-1.0 / 2.0, 3.0 * sqrt(3) / 2.0);cout << "(-1/2, 3*sqrt(3)/2): " << "x=" << cube_tmp_0.x << " y=" << round(cube_tmp_0.y) << " z=" << cube_tmp_0.z << endl;const Hexagon::Cube& cube_tmp_1 = hexagon->offset2cube_absolutely(3.0 / 2.0, sqrt(3) / 2.0);cout << "(3/2, sqrt(3)/2): " << "x=" << cube_tmp_1.x << " y=" << round(cube_tmp_1.y) << " z=" << cube_tmp_1.z << endl;Hexagon::Offset offset_tmp{ -2, -sqrt(3) };const Hexagon::Cube& cube_tmp_2 = hexagon->offset2cube_absolutely(offset_tmp);cout << "(-2, -sqrt(3): " << "x=" << cube_tmp_2.x << " y=" << round(cube_tmp_2.y) << " z=" << cube_tmp_2.z << endl;if (hexagon) {delete hexagon;}
}int main() {relatively_demo();cout << endl;absolutely_demo();return 0;
}

运行结果:

正六边形坐标系参考:正六边形网格化(Hexagonal Grids)原理与实现

二元一次方程组解法参考:怎么用C编程语言求解二元一次方程组的解

游戏场景offset坐标系关联正六边形cube坐标系相关推荐

  1. 二维平面坐标系中,判断某点是否在正六边形内 | python 实现 + 数学推导(已知正六边形六个顶点坐标)

    参考:高效判断点是否在正六边形蜂窝内的方法 上述文章给了我们一个高效的思路:在正六边形为原点且中心轴与y轴重合时,如何高效判断点是否在该正六边形内.本文的工作是将这种情况推广到正六边形处于任意位置. ...

  2. 青瓷引擎打造HTML5游戏第一弹——《神奇的六边形》Part 4

    近期出现一款魔性的消除类HTML5游戏<神奇的六边形>,今天我们一起来看看如何通过开源免费的青瓷引擎(www.zuoyouxi.com)来实现这款游戏. (点击图片可进入游戏体验) 因内容 ...

  3. 【微信小游戏实战】零基础制作《欢乐停车场》三、游戏场景制作

    1.游戏立项 微信小游戏中有一款<欢乐停车场Plus>的小游戏,大家可以搜索玩下.这是一款益智类的小游戏,游戏中有红.黄.绿.蓝.紫5辆豪车6个停车位,玩家通过可行走路线移动小车,最终让各 ...

  4. 简谈游戏场景灯光配置方案

    http://tieba.baidu.com/p/2690022869 转眼从北京辞职回老家也一年多了,在游戏公司干了几年回来我们这样的小城镇还真不知道该做点什么,所以也一直没找工作,在家花了几个月时 ...

  5. C#游戏开发快速入门 2.1 构建游戏场景

    C#游戏开发快速入门 2.1  构建游戏场景 如果已经计划好了要编写什么样的游戏,在打开Unity以后,要做的第一件事情就是构建游戏场景(Scene).游戏场景就是玩家游戏时,在游戏视图中看到的一切, ...

  6. 实验二 建立基本的游戏场景

    实验二 建立基本的游戏场景 一.实验内容: 1. 建立一个简单的游戏场景: 2. 通过摄像机实现场景的切换: 3. 使用不同的光照实现阴影效果: 二.实验目的: 1. 了解Ogre程序的工作方法和Og ...

  7. 游戏场景中的建筑设计,专访暴雪娱乐首席美术师 PhilipKlevestav

    生动.逼真的图像与演示已成为方案展示不可或缺的组成部分.当下,设计师们正运用最先进的软件,建构精致三维模型,力求尽可能真实地展现他们的作品.而对于电子游戏领域来说,这个方式所关乎的不仅是图像质量与准确 ...

  8. Tiled-免费2D游戏场景Tile编辑器

    Tiled[1]是一款免费2D游戏场景Tile编辑器. Tiled支持正方形,平行四边形和六边形Tile. 同时Tiled也支持在场景上画矩形 用户手册 Tiled有详细的用户手册[2],罗列了编辑器 ...

  9. Unity 3D游戏开发 - U3D入门 | 游戏场景基本操作

    注:本系列版本为Unity 5.3.5. 新建项目与新建场景 新建项目 每一个游戏都是一个独立的项目. 打开 Unity,输入项目名称 --> 选择本地存储位置 --> 选择 3D模式 - ...

最新文章

  1. c语言编程题及答案-难,C语言常见编程题及答案40题
  2. 1.html5究竟是什么
  3. Android图片处理
  4. Drupal的介绍----第一章:Drupal的介绍
  5. python3 json.dump乱码问题
  6. 感知机数据算法的对偶形式
  7. Python数据可视化词云展示周董的歌
  8. 修改大型 XML 文件的有效方法
  9. DevC++如何安装自定义头文件并使用
  10. Mybatis占位符问题—ReflectionException: There is no getter for property named xxx
  11. TensorFlow 第一步 开门见山:Hello World!
  12. ZetCode 杂项教程
  13. journalctl命令详解
  14. 本地 Git 文件夹显示绿色标识
  15. SpringCloud学习笔记(五)服务发现Discovery
  16. 抖音可以传多长的视频?
  17. 沪市和深市股票托管方式的区别
  18. ajax img src如何索引,使用jQuery的ajax方法作为blob检索图像
  19. 行业分析:什么样的公司有前景?深入分析智力密集型行业公司的类型与特征
  20. Offer一个候选人的正确姿势

热门文章

  1. 收获与努力同行——2015年总结
  2. 用netty实现zcool_Netty 系列一(核心组件和实例).
  3. 三维视频融合 开放源代码 混合模式 内嵌web容器 c++ js 混合开发 时空克隆引擎 数字孪生 点卯 系列 魔镜系列
  4. 《王者荣耀》还有什么比被鲁班炮死更憋屈的死法?
  5. 浅谈用户研究那些事(上)定性研究
  6. Bootstrap5 文字排版讲解
  7. Win10安装cuda和cudnn(可安装多版本并自由切换)
  8. 猿人学第一题超详细-JS逆向过程
  9. 加壳器第二部分,加壳器
  10. IG痛失亚军,含泪夺冠,奖杯是用区块链的技术合成的你知道吗