这次带来一个有趣的编队代码,简单的算法得到令人惊叹的编队队形,叹为观止,前几天刷视频的时候看到一个有趣的展示,来自youtube大神:Tarodev的队形计算展示《 Fun with Formations - Game Dev Adventure

他的是Unity实现的,我用最新发布的Creator 3.3版本制作了一个,视频如下:

参考资料:https://www.youtube.com/watch?v=NEFxWkTRVCc

开发工具 CocosCreator 3.3.0

BGM: Jazzy Frenchy form bensound

Creator3以后的引擎,对于3D方面的计算基本上和Unity很像了,转译C#代码并不难,原版代码在这里:GitHub - Matthew-J-Spencer/Formations: Some simple scripts to create formations in Unity

CocosCreator中的关键代码如下:

/** 编队的基类 */
import { _decorator, Component, Node, Vec3, v3 } from 'cc';
const { ccclass, property } = _decorator;
@ccclass('BaseFormation')
export class BaseFormation extends Component {
@property
noise: number = 0;
@property
Spread: number = 1;
offsetPos:Vec3 = v3();
EvaluatePoints(): Vec3[] {
return null;
}
GetNoise(pos: Vec3): Vec3 {
const noise = this.noise;
const x = pos.x + Math.random() * noise - noise / 2;
const z = pos.z + Math.random() * noise - noise / 2;
pos.x = x;
pos.z = z;
return pos;
}
}
/** 方形编队组件脚本代码 */
import { _decorator, Component, Node, Vec3, v3 } from 'cc';
import { BaseFormation } from './BaseFormation';
const { ccclass, property } = _decorator;
@ccclass('BoxFormation')
export class BoxFormation extends BaseFormation {
@property
unitWidth: number = 5;
@property
unitDepth: number = 5;
@property
hollow: boolean = false;
@property
nthOffset: number = 0;
EvaluatePoints(): Vec3[] {
const ret: Vec3[] = [];
const middleOffset = v3((this.unitWidth - 1) * 0.5, 0, (this.unitDepth - 1) * 0.5);
for (let x = 0; x < this.unitWidth; x++) {
for (let z = 0; z < this.unitDepth; z++) {
if (this.hollow && x != 0 && x != this.unitWidth - 1 && z != 0 && z != this.unitDepth - 1) continue;
let pos = v3(x + (z % 2 == 0 ? 0 : this.nthOffset), 0, z); pos = pos.subtract(middleOffset); pos = this.GetNoise(pos); pos = pos.multiplyScalar(this.Spread);
pos.add(this.offsetPos);
ret.push(pos);
}
}
return ret;
}
}
/** 放射编队组件脚本代码 */
import { _decorator, Component, Node, Vec3, v3 } from 'cc';
import { BaseFormation } from './BaseFormation';
const { ccclass, property } = _decorator;
@ccclass('RadialFormation')
export class RadialFormation extends BaseFormation {
@property
amount: number = 10;
@property
radius: number = 1;
@property
radiusGrowthMultiplier: number = 0;
@property
rotations: number = 1;
@property
rings: number = 1;
@property
ringOffset: number = 1;
@property
nthOffset: number = 1;
EvaluatePoints(): Vec3[] {
const ret: Vec3[] = [];
let amountPerRing = this.amount / this.rings;
let ringOffset = 0;
for (var i = 0; i < this.rings; i++) {
for (var j = 0; j < amountPerRing; j++) {
let angle = j * Math.PI * (2 * this.rotations) / amountPerRing + (i % 2 != 0 ? this.nthOffset : 0); let radius = this.radius + ringOffset + j * this.radiusGrowthMultiplier;
let x = Math.cos(angle) * radius;
let z = Math.sin(angle) * radius; let pos = new Vec3(x, 0, z); pos = this.GetNoise(pos); pos = pos.multiplyScalar(this.Spread); pos.add(this.offsetPos);
ret.push(pos);
}
ringOffset += this.ringOffset;
}
return ret;
}
}

以上便是CocosCreator3版本的核心计算代码了,可以自行贴在编队节点上,人物控制应该是由特定的渲染代码完成。

编队展示处理代码

/**
* 编队渲染展示的代码,挂在到你想展示的节点容器上,配合对应的Formation组件
* 请自行构建Actor角色组件用于处理人物逻辑,实现removeSelf和moveTo
* 在合适的时机处理编队的刷新,比如编队参数变化、队伍移动的时候
*/
import { _decorator, Component, Node, Prefab, instantiate, director } from 'cc';
import { Actor } from '../actors/Actor';
import { BaseFormation } from '../formations/BaseFormation';
const { ccclass, property } = _decorator; @ccclass('FormationShow')
export class FormationShow extends Component {
@property(Prefab)
actor: Prefab = null;
start() {
this.FormationUpdate();
}
FormationUpdate(prop?: string, value?: number) {
const formation = this.getComponent(BaseFormation);
if (formation) {
if (prop) {
const old = formation[prop];
formation[prop] = value;
if (old == formation[prop]) {
return;
}
}
const points = formation.EvaluatePoints();
for (let i = this.node.children.length - 1; i >= points.length; i--) {
this.node.children[i].getComponent(Actor).removeSelf();
}
const len = this.node.children.length;
for (let i = 0; i < points.length; i++) {
if (i < points.length && i >= len) {
let actor = null;
if (len > 0) {
actor = this.node.children[len - 1];
} else {
actor = this.actor;
}
const a = instantiate(actor);
this.node.addChild(a);
}
this.node.children[i].getComponent(Actor).moveTo(points[i]);
}
}
}
}

结语

视频中的源码工程已经发布到Cocos的官方商店,有需要的自取
https://store.cocos.com/app/detail/3210

最新文章

  1. vue-router2使用
  2. Robot Framework入门学习2 创建第一个测试用例
  3. 使用commons-fileupload包进行大文件上传注意事项
  4. editplus批量删除重复行(编辑-删除-删除重复行)
  5. spring定时器 @Scheduled
  6. strace
  7. H TML5 之 (3)转动的圆球
  8. Access中出现改变字段“自己主动编号”类型,不能再改回来!(已解决)
  9. GCD的使用和面试题集锦
  10. sqm(sqlmapGUI) pcat修改版
  11. html一些东东
  12. 教你在不使用框架的情况下也能写出现代化 PHP 代码
  13. 利用编辑距离(Edit Distance)计算两个字符串的相似度
  14. css3动画--位移加阴影
  15. hdu1394逆序数(线段树)
  16. Linux常用基本命令:grep-从文件或者管道中筛选匹配的行
  17. 【题解】Luogu P1533 可怜的狗狗
  18. js+ajax+springmvc实现无刷新文件上传
  19. python 集合从头部删除元素
  20. java.lang.Integer can not be cast to java.lang.Long

热门文章

  1. 二 MongoDB数据类型和$type操作符
  2. 从eclipse转idea不适记录【持续更新】
  3. ProjectEuler 004题
  4. urllib3中学到的LRU算法
  5. Vue.JS快速上手(指令和实例方法)
  6. Java如何调用C语言程序,JNI技术
  7. canvas二次贝塞尔&amp;三次贝塞尔操作实例
  8. PC微信多开
  9. Java创建线程池的方法
  10. 【进阶之路】持续集成、持续交付与持续部署(CI/CD)