Merge pull request #3230 from Barnold1953/rockPaperScissors

Rock Paper Scissors CA script
This commit is contained in:
Philip Rosedale 2014-08-03 13:03:11 -07:00
commit 321b8de898
5 changed files with 292 additions and 1 deletions

View file

@ -0,0 +1,272 @@
// rockPaperScissorsCells.js
// examples
//
// Created by Ben Arnold on 7/16/14.
// Copyright 2014 High Fidelity, Inc.
//
// This sample script creates a voxel wall that simulates the Rock Paper Scissors cellular
// automata. http://www.gamedev.net/blog/844/entry-2249737-another-cellular-automaton-video/
// If multiple instances of this script are run, they will combine into a larger wall.
// NOTE: You must run each instance one at a time. If they all start at once there are race conditions.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
var NUMBER_OF_CELLS_EACH_DIMENSION = 48;
var NUMBER_OF_CELLS_REGION_EACH_DIMESION = 16;
var REGIONS_EACH_DIMENSION = NUMBER_OF_CELLS_EACH_DIMENSION / NUMBER_OF_CELLS_REGION_EACH_DIMESION;
var isLocal = false;
var currentCells = [];
var nextCells = [];
var cornerPosition = {x: 100, y: 0, z: 0 }
var position = {x: 0, y: 0, z: 0 };
var METER_LENGTH = 1;
var cellScale = (NUMBER_OF_CELLS_EACH_DIMENSION * METER_LENGTH) / NUMBER_OF_CELLS_EACH_DIMENSION;
var viewerPosition = {x: cornerPosition.x + (NUMBER_OF_CELLS_EACH_DIMENSION / 2) * cellScale, y: cornerPosition.y + (NUMBER_OF_CELLS_EACH_DIMENSION / 2) * cellScale, z: cornerPosition.z };
viewerPosition.z += 50;
var yaw = 0;
var orientation = Quat.fromPitchYawRollDegrees(0, yaw, 0);
//Feel free to add new cell types here. It can be more than three.
var cellTypes = [];
cellTypes[0] = { r: 255, g: 0, b: 0 };
cellTypes[1] = { r: 0, g: 255, b: 0 };
cellTypes[2] = { r: 0, g:0, b: 255 };
cellTypes[3] = { r: 0, g: 255, b: 255 };
//Check for free region for AC
var regionMarkerX = -1;
var regionMarkerY = -1;
var regionMarkerI = -1;
var regionMarkerJ = -1;
var regionMarkerColor = {r: 254, g: 0, b: 253};
function setRegionToColor(startX, startY, width, height, color) {
for (var i = startY; i < startY + height; i++) {
for (var j = startX; j < startX + width; j++) {
currentCells[i][j] = { changed: true, type: color };
// put the same value in the nextCells array for first board draw
nextCells[i][j] = { changed: true, type: color };
}
}
}
function init() {
for (var i = 0; i < REGIONS_EACH_DIMENSION; i++) {
for (var j = 0; j < REGIONS_EACH_DIMENSION; j++) {
var x = cornerPosition.x + (j) * cellScale;
var y = cornerPosition.y + (i + NUMBER_OF_CELLS_EACH_DIMENSION) * cellScale;
var z = cornerPosition.z;
var voxel = Voxels.getVoxelAt(x, y, z, cellScale);
if (voxel.x != x || voxel.y != y || voxel.z != z || voxel.s != cellScale ||
voxel.red != regionMarkerColor.r || voxel.green != regionMarkerColor.g || voxel.blue != regionMarkerColor.b) {
regionMarkerX = x;
regionMarkerY = y;
regionMarkerI = i;
regionMarkerJ = j;
i = REGIONS_EACH_DIMENSION; //force quit loop
break;
}
}
}
//Didnt find an open spot, end script
if (regionMarkerX == -1) {
Script.stop();
}
position.x = cornerPosition.x + regionMarkerJ * NUMBER_OF_CELLS_REGION_EACH_DIMESION;
position.y = cornerPosition.y + regionMarkerI * NUMBER_OF_CELLS_REGION_EACH_DIMESION;
position.z = cornerPosition.z;
Voxels.setVoxel(regionMarkerX, regionMarkerY, cornerPosition.z, cellScale, regionMarkerColor.r, regionMarkerColor.g, regionMarkerColor.b);
for (var i = 0; i < NUMBER_OF_CELLS_REGION_EACH_DIMESION; i++) {
// create the array to hold this row
currentCells[i] = [];
// create the array to hold this row in the nextCells array
nextCells[i] = [];
}
var width = NUMBER_OF_CELLS_REGION_EACH_DIMESION / 2;
setRegionToColor(0, 0, width, width, 0);
setRegionToColor(0, width, width, width, 1);
setRegionToColor(width, width, width, width, 2);
setRegionToColor(width, 0, width, width, 3);
}
function updateCells() {
var i = 0;
var j = 0;
var cell;
var y = 0;
var x = 0;
for (i = 0; i < NUMBER_OF_CELLS_REGION_EACH_DIMESION; i++) {
for (j = 0; j < NUMBER_OF_CELLS_REGION_EACH_DIMESION; j++) {
cell = currentCells[i][j];
var r = Math.floor(Math.random() * 8);
switch (r){
case 0:
y = i - 1;
x = j - 1;
break;
case 1:
y = i;
x = j-1;
break;
case 2:
y = i + 1;
x = j - 1;
break;
case 3:
y = i + 1;
x = j;
break;
case 4:
y = i + 1;
x = j + 1;
break;
case 5:
y = i;
x = j + 1;
break;
case 6:
y = i - 1;
x = j + 1;
break;
case 7:
y = i - 1;
x = j;
break;
default:
continue;
}
//check the voxel grid instead of local array when on the edge
if (x == -1 || x == NUMBER_OF_CELLS_REGION_EACH_DIMESION ||
y == -1 || y == NUMBER_OF_CELLS_REGION_EACH_DIMESION) {
var voxel = Voxels.getVoxelAt(position.x + x * cellScale, position.y + y * cellScale, position.z, cellScale);
var predatorCellType = ((cell.type + 1) % cellTypes.length);
var predatorCellColor = cellTypes[predatorCellType];
if (voxel.red == predatorCellColor.r && voxel.green == predatorCellColor.g && voxel.blue == predatorCellColor.b) {
nextCells[i][j].type = predatorCellType;
nextCells[i][j].changed = true;
}
} else {
if (currentCells[y][x].type == ((cell.type + 1) % cellTypes.length)) {
nextCells[i][j].type = currentCells[y][x].type;
nextCells[i][j].changed = true;
} else {
//indicate no update
nextCells[i][j].changed = false;
}
}
}
}
for (i = 0; i < NUMBER_OF_CELLS_REGION_EACH_DIMESION; i++) {
for (j = 0; j < NUMBER_OF_CELLS_REGION_EACH_DIMESION; j++) {
if (nextCells[i][j].changed == true) {
// there has been a change to this cell, change the value in the currentCells array
currentCells[i][j].type = nextCells[i][j].type;
currentCells[i][j].changed = true;
}
}
}
}
function sendNextCells() {
for (var i = 0; i < NUMBER_OF_CELLS_REGION_EACH_DIMESION; i++) {
for (var j = 0; j < NUMBER_OF_CELLS_REGION_EACH_DIMESION; j++) {
if (nextCells[i][j].changed == true) {
// there has been a change to the state of this cell, send it
// find the x and y position for this voxel, z = 0
var x = j * cellScale;
var y = i * cellScale;
var type = nextCells[i][j].type;
// queue a packet to add a voxel for the new cell
Voxels.setVoxel(position.x + x, position.y + y, position.z, cellScale, cellTypes[type].r, cellTypes[type].g, cellTypes[type].b);
}
}
}
}
var sentFirstBoard = false;
var voxelViewerInit = false;
var UPDATES_PER_SECOND = 6.0;
var frameIndex = 1.0;
var oldFrameIndex = 0;
var framesToWait = UPDATES_PER_SECOND;
function step(deltaTime) {
if (isLocal == false) {
if (voxelViewerInit == false) {
VoxelViewer.setPosition(viewerPosition);
VoxelViewer.setOrientation(orientation);
voxelViewerInit = true;
}
VoxelViewer.queryOctree();
}
frameIndex += deltaTime * UPDATES_PER_SECOND;
if (Math.floor(frameIndex) == oldFrameIndex) {
return;
}
oldFrameIndex++;
if (frameIndex <= framesToWait) {
return;
}
if (sentFirstBoard) {
// we've already sent the first full board, perform a step in time
updateCells();
} else {
// this will be our first board send
sentFirstBoard = true;
init();
}
if (isLocal == false) {
VoxelViewer.queryOctree();
}
sendNextCells();
}
function scriptEnding() {
Voxels.eraseVoxel(regionMarkerX, regionMarkerY, position.z, cellScale);
}
Script.scriptEnding.connect(scriptEnding);
Script.update.connect(step);
Voxels.setPacketsPerSecond(2000);
// test for local...
Menu.isOptionChecked("Voxels");
isLocal = true; // will only get here on local client

View file

@ -40,6 +40,15 @@ void ResourceCache::refresh(const QUrl& url) {
}
QSharedPointer<Resource> ResourceCache::getResource(const QUrl& url, const QUrl& fallback, bool delayLoad, void* extra) {
if (QThread::currentThread() != thread()) {
QSharedPointer<Resource> result;
QMetaObject::invokeMethod(this, "getResource", Qt::BlockingQueuedConnection,
Q_RETURN_ARG(QSharedPointer<Resource>, result), Q_ARG(const QUrl&, url), Q_ARG(const QUrl&, fallback),
Q_ARG(bool, delayLoad), Q_ARG(void*, extra));
return result;
}
if (!url.isValid() && !url.isEmpty() && fallback.isValid()) {
return getResource(fallback, QUrl(), delayLoad);
}

View file

@ -52,7 +52,7 @@ protected:
/// \param fallback a fallback URL to load if the desired one is unavailable
/// \param delayLoad if true, don't load the resource immediately; wait until load is first requested
/// \param extra extra data to pass to the creator, if appropriate
QSharedPointer<Resource> getResource(const QUrl& url, const QUrl& fallback = QUrl(),
Q_INVOKABLE QSharedPointer<Resource> getResource(const QUrl& url, const QUrl& fallback = QUrl(),
bool delayLoad = false, void* extra = NULL);
/// Creates a new resource.

View file

@ -80,11 +80,16 @@ void VoxelsScriptingInterface::setVoxel(float x, float y, float z, float scale,
DeleteVoxelCommand* deleteCommand = new DeleteVoxelCommand(_tree,
addVoxelDetail,
getVoxelPacketSender());
_undoStackMutex.lock();
_undoStack->beginMacro(addCommand->text());
// As QUndoStack automatically executes redo() on push, we don't need to execute the command ourselves.
_undoStack->push(deleteCommand);
_undoStack->push(addCommand);
_undoStack->endMacro();
//Unlock the mutex
_undoStackMutex.unlock();
} else {
// queue the destructive add
queueVoxelAdd(PacketTypeVoxelSetDestructive, addVoxelDetail);
@ -109,11 +114,15 @@ void VoxelsScriptingInterface::eraseVoxel(float x, float y, float z, float scale
}
if (_undoStack) {
DeleteVoxelCommand* command = new DeleteVoxelCommand(_tree,
deleteVoxelDetail,
getVoxelPacketSender());
_undoStackMutex.lock();
// As QUndoStack automatically executes redo() on push, we don't need to execute the command ourselves.
_undoStack->push(command);
_undoStackMutex.unlock();
} else {
getVoxelPacketSender()->queueVoxelEditMessages(PacketTypeVoxelErase, 1, &deleteVoxelDetail);
_tree->deleteVoxelAt(deleteVoxelDetail.x, deleteVoxelDetail.y, deleteVoxelDetail.z, deleteVoxelDetail.s);

View file

@ -102,6 +102,7 @@ private:
void queueVoxelAdd(PacketType addPacketType, VoxelDetail& addVoxelDetails);
VoxelTree* _tree;
QUndoStack* _undoStack;
QMutex _undoStackMutex;
};
#endif // hifi_VoxelsScriptingInterface_h