Cocos2d-js agar 细胞模拟

用的版本是 cocos2d-js v3.7,直接上代码。

// app.js
// by WM, QQ: 348915654

var g_versionStr = "v1.0";
var g_timestamp = +new Date;

var g_leftPos = 50; // min x
var g_bottomPos = 50; // min y
var g_rightPos = 600; // max x
var g_topPos = 600; // max y

// 四叉树
var Quad = {
init: function (args) {
function Node(x, y, w, h, depth) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.depth = depth;
this.items = ];
this.nodes = ]
}

var c = args.maxChildren || 2,
d = args.maxDepth || 4;
Node.prototype = {
x: 0,
y: 0,
w: 0,
h: 0,
depth: 0,
items: null,
nodes: null,
exists: function (selector) {
for (var i = 0; i < this.items.length; ++i) {
var item = this.items;
if (item.x >= selector.x && item.y >= selector.y && item.x < selector.x + selector.w && item.y < selector.y + selector.h) return true
}
if (0 != this.nodes.length) {
var self = this;
return this.findOverlappingNodes(selector, function (dir) {
return self.nodes.exists(selector)
})
}
return false;
},
retrieve: function (item, callback) {
for (var i = 0; i < this.items.length; ++i) callback(this.items);
if (0 != this.nodes.length) {
var self = this;
this.findOverlappingNodes(item, function (dir) {
self.nodes.retrieve(item, callback)
})
}
},
insert: function (a) {
if (0 != this.nodes.length) {
this.nodes.insert(a);
} else {
if (this.items.length >= c && this.depth < d) {
this.devide();
this.nodes.insert(a);
} else {
this.items.push(a);
}
}
},
findInsertNode: function (a) {
return a.x < this.x + this.w / 2 ? a.y < this.y + this.h / 2 ? 0 : 2 : a.y < this.y + this.h / 2 ? 1 : 3
},
findOverlappingNodes: function (a, b) {
return a.x < this.x + this.w / 2 && (a.y < this.y + this.h / 2 && b(0) || a.y >= this.y + this.h / 2 && b(2)) || a.x >= this.x + this.w / 2 && (a.y < this.y + this.h / 2 && b(1) || a.y >= this.y + this.h / 2 && b(3)) ? true : false
},
devide: function () {
var a = this.depth + 1,
c = this.w / 2,
d = this.h / 2;
this.nodes.push(new Node(this.x, this.y, c, d, a));
this.nodes.push(new Node(this.x + c, this.y, c, d, a));
this.nodes.push(new Node(this.x, this.y + d, c, d, a));
this.nodes.push(new Node(this.x + c, this.y + d, c, d, a));
a = this.items;
this.items = ];
for (c = 0; c < a.length; c++) this.insert(a)
},
clear: function () {
for (var a = 0; a < this.nodes.length; a++) this.nodes.clear();
this.items.length = 0;
this.nodes.length = 0
}
};
var internalSelector = {
x: 0,
y: 0,
w: 0,
h: 0
};
return {
root: new Node(args.minX, args.minY, args.maxX - args.minX, args.maxY - args.minY, 0),
insert: function (a) {
this.root.insert(a)
},
retrieve: function (a, b) {
this.root.retrieve(a, b)
},
retrieve2: function (a, b, c, d, callback) {
internalSelector.x = a;
internalSelector.y = b;
internalSelector.w = c;
internalSelector.h = d;
this.root.retrieve(internalSelector, callback)
},
exists: function (a) {
return this.root.exists(a)
},
clear: function () {
this.root.clear()
}
}
}
};

var g_qTree = null;

var Cell = cc.Class.extend({
m_id: 0,
m_x: 0,
m_y: 0,
m_size: 100, // 细胞的半径
m_pointsNum: 128, // 点的数量
m_points: null, // @private
m_pointsAcc: null, // @private
m_isVirus: false, // 如果为 true 细胞将呈现锯齿状
m_isAgitated: false, // 如果是激活状态细胞将振动得更加激烈
m_drawNode: null,

ctor: function () {
this.m_points = ];
this.m_pointsAcc = ];
this.CreatePoints();
},

Destroy: function () {
this.m_points = null;
this.m_pointsAcc = null;
},

GetNumPoints: function () {
return this.m_pointsNum;
},

CreatePoints: function () {
var sampleNum = 0;
var rand = 0;
var rand2 = 0;
var point = null;

sampleNum = this.GetNumPoints();
for ( ; this.m_points.length > sampleNum; ) {
rand = ~~(Math.random() * this.m_points.length);
this.m_points.splice(rand, 1);
this.m_pointsAcc.splice(rand, 1);
}
if (this.m_points.length == 0 && sampleNum > 0) {
this.m_points.push({
ref: this,
size: this.m_size,
x: this.m_x,
y: this.m_y
});
this.m_pointsAcc.push(Math.random() - 0.5);
}
while (this.m_points.length < sampleNum) {
rand2 = ~~(Math.random() * this.m_points.length);
point = this.m_points;
this.m_points.splice(rand2, 0, {
ref: this,
size: point.size,
x: point.x,
y: point.y
});
this.m_pointsAcc.splice(rand2, 0, this.m_pointsAcc);
}
},

MovePoints: function () {
this.CreatePoints();
var points = null;
var pointsAcc = null;
var numPoints = 0;
var i = 0;
var pos1 = null;
var pos2 = null;
var ref = null;
var isVirus = false;
var j = 0;
var f = 0;
var e = 0;
var m = 0;
var isCollide = false;
var posX = 0;
var posY = 0;

for (points = this.m_points, pointsAcc = this.m_pointsAcc, numPoints = points.length, i = 0;
i < numPoints; i++) {
pos1 = pointsAcc(i - 1 + numPoints) % numPoints];
pos2 = pointsAcc(i + 1 + numPoints) % numPoints];
pointsAcc += (Math.random() - 0.5) * (this.m_isAgitated ? 3 : 1); // 半径随机的变化从这里来
pointsAcc *= 0.7;
if (pointsAcc > 10) {
pointsAcc = 10;
}
if (pointsAcc < -10) {
pointsAcc = 10;
}
pointsAcc = (pos1 + pos2 + 8 * pointsAcc) / 10;
}

// isVirus 用于这个循环的累加角度,如果是病毒则不计算累加角度
for (ref = this, isVirus = this.m_isVirus ? 0 : (this.m_id / 1000 + g_timestamp / 10000) % (2 * Math.PI), j = 0;
樀 < numPoints; j++) {
f = points.size;
e = points(j - 1 + numPoints) % numPoints].size;
m = points(j + 1 + numPoints) % numPoints].size;

{ // 判断是否与其它点产生碰撞 //...
isCollide = false;
posX = points.x;
posY = points.y;
// 与其它节点的碰撞 //...
if (g_qTree != null) {
g_qTree.retrieve2(posX - 5, posY - 5, 10, 10, function (node) {
if (node.ref != ref &&
((posX - node.x) * (posX - node.x) + (posY - node.y) * (posY - node.y) < 25)) {
isCollide = true;
}
})
}
// 与墙壁的碰撞
if (!isCollide && posX < g_leftPos || posX > g_rightPos || posY < g_bottomPos || posY > g_topPos) {
isCollide = true;
}
if (isCollide) {
if (pointsAcc > 0) {
pointsAcc = 0;
}
pointsAcc -= 1;
}
}

f += pointsAcc; // 半径变化
if (f < 0) {
f = 0;
}
f = this.m_isAgitated ? (19 * f + this.m_size) / 20 : (12 * f + this.m_size) / 13; // 半径向 this.m_size 变化
points.size = (e + m + 8 * f) / 10; // 半径根据两旁的半径来变化 // 两旁的各占一份,自己占八份

e = 2 * Math.PI / numPoints; // 单份的角度
m = this.m_points.size; // 半径
// 如果是病毒还可以呈现出锯齿效果
if (this.m_isVirus && 0 == j % 2) {
m += 5;
}
// 这是圆的公式
points.x = this.m_x + Math.cos(e * j + isVirus) * m;
points.y = this.m_y + Math.sin(e * j + isVirus) * m;
}
},

ShouldRender: function () {
return true;
},

DrawOneCell: function (drawNode) {
if (this.ShouldRender()) {
this.MovePoints();
var d = this.GetNumPoints();
var c = 0;
var e = 0;
var verts = ];

for (c = 1; c <= d; c++) {
e = c % d;
verts.push(cc.p(this.m_points.x, this.m_points.y));
}
drawNode.clear();
drawNode.drawPoly(verts, cc.color.WHITE, 2, cc.color.BLACK);
}
},

HaHaTest: function () {

}
});

var g_mainLogic = null;

var HelloWorldLayer = cc.Layer.extend({
sprite:null,
m_cells: null,

ctor:function () {
//////////////////////////////
// 1. super init first
this._super();

/////////////////////////////
// 2. add a menu item with "X" image, which is clicked to quit the program
//  礀漀甀 may modify it.
// ask the window size
var size = cc.winSize;

// add a "close" icon to exit the progress. it's an autorelease object
var closeItem = new cc.MenuItemImage(
res.CloseNormal_png,
res.CloseSelected_png,
function () {
cc.log("Menu is clicked!");
}, this);
closeItem.attr({
x: size.width - 20,
y: 20,
anchorX: 0.5,
anchorY: 0.5
});

var menu = new cc.Menu(closeItem);
menu.x = 0;
menu.y = 0;
this.addChild(menu, 1);

/////////////////////////////
// 3. add your codes below...
// add a label shows "Hello World"
// create and initialize a label
var helloLabel = new cc.LabelTTF(g_versionStr, "Arial", 38);
// position the label on the center of the screen
helloLabel.x = size.width / 2;
helloLabel.y = 0;
// add the label as a child to this layer
this.addChild(helloLabel, 5);

// add "HelloWorld" splash screen"
this.sprite = new cc.Sprite(res.HelloWorld_png);
this.sprite.attr({
x: size.width / 2,
y: size.height / 2,
scale: 0.5,
rotation: 180
});
this.addChild(this.sprite, 0);

this.sprite.runAction(
cc.sequence(
cc.rotateTo(2, 0),
cc.scaleTo(2, 1, 1)
)
);
helloLabel.runAction(
cc.spawn(
cc.moveBy(2.5, cc.p(0, size.height - 40)),
cc.tintTo(2.5,255,125,0)
)
);

this.scheduleUpdate();
g_mainLogic = this;
this.MyInit();

return true;
},

update: function (dt) {
this._super(dt);
var cell = null;

g_timestamp = +new Date;

this.BuildQTree();

for (var i = 0; i < this.m_cells.length; i++) {
cell = this.m_cells*;
cell.DrawOneCell(cell.m_drawNode);
}
},

BuildQTree: function () {
var a = Number.POSITIVE_INFINITY; // minX
var b = Number.POSITIVE_INFINITY; // minY
var c = Number.NEGATIVE_INFINITY; // maxX
var d = Number.NEGATIVE_INFINITY; // maxY
var e = 0; // maxRadius

var cell = null;
var posX = 0;
var posY = 0;

for (var i = 0; i < this.m_cells.length; i++) {
cell = this.m_cells*;
if (cell.ShouldRender()) { // 判断条件还会扩展 //...
a = Math.min(cell.m_x, a);
b = Math.min(cell.m_y, b);
c = Math.max(cell.m_x, c);
d = Math.max(cell.m_y, d);
e = Math.max(cell.m_size, e);
}
}
g_qTree = Quad.init({
minX: a - (e + 100),
minY: b - (e + 100),
maxX: c + (e + 100),
maxY: d + (e + 100),
maxChildren: 2,
maxDepth: 4
});
for (var i = 0; i < this.m_cells.length; i++) {
cell = this.m_cells*;
if (cell.ShouldRender()) { // 判断条件还会扩展 //...
for (var j = 0; j < cell.m_points.length; j++) {
posX = cell.m_points.x;
posY = cell.m_points.y;
if (true) { // 判断条件还会扩展 //...
g_qTree.insert(cell.m_points);
}
}
}
}
},

MyInit: function () {
var winSize = cc.winSize;
var cell = null;
var drawNode = null;

this.m_cells = ];

// 创建一个病毒
cell = new Cell();
cell.m_isVirus = true;
cell.m_size = 100;
cell.m_pointsNum = 128;
cell.m_x = 120;
cell.m_y = 120;
drawNode = new cc.DrawNode();
this.addChild(drawNode, 100);
cell.m_drawNode = drawNode;
this.m_cells.push(cell);

cell = new Cell();
cell.m_isVirus = false;
cell.m_size = 50;
cell.m_pointsNum = 64;
cell.m_x = 240;
cell.m_y = 80;
drawNode = new cc.DrawNode();
this.addChild(drawNode, 90);
cell.m_drawNode = drawNode;
this.m_cells.push(cell);

cell = new Cell();
cell.m_isVirus = false;
cell.m_size = 120;
cell.m_pointsNum = 128;
cell.m_x = 400;
cell.m_y = 300;
drawNode = new cc.DrawNode();
this.addChild(drawNode, 110);
cell.m_drawNode = drawNode;
this.m_cells.push(cell);

cell = new Cell();
cell.m_isVirus = false;
cell.m_size = 50;
cell.m_pointsNum = 64;
cell.m_x = 400;
cell.m_y = 160;
drawNode = new cc.DrawNode();
this.addChild(drawNode, 90);
cell.m_drawNode = drawNode;
this.m_cells.push(cell);
}
});

var HelloWorldScene = cc.Scene.extend({
onEnter:function () {
this._super();
var layer = new HelloWorldLayer();
this.addChild(layer);
}
});


```
***

奇怪了,原来写的是 cell = this.m_cells i ]; 发出贴之后变成了 cell = this.m_cells;