ambiera logo

Ambiera Forum

Discussions, Help and Support.

folder icon Ambiera Forum > CopperCube > Help with CopperCube
forum topic indicator can anybody please help me make this scene work?
person icon
paperbag
Registered User
Quote
2024-05-19 06:09:21

this is a mowing game and i can't get the grass to delete when the "blades" go over that scene node can anybody help?

thankshttps://1drv.ms/u/s!AiaHd2kpdCny...

person icon
okeoke
Registered User
Quote
2024-05-19 09:04:09

I've added another extension called Mower.

Basically, it checks distance to every node put into grassFolder. It checks the distance from the node it's attached to so please reattach it to knives node if required.

grassMowedCheckDistance - is distance from the node to grass patch there grass is considered "cut"

action - is action on cut, so you can add sound or any other logic that happens on cut like incrementing variables or play sound there.

// The following embedded xml is for the editor and describes how the behavior can be edited:
// Supported types are: int, float, string, bool, color, vect3d, scenenode, texture, action
/*
<behavior jsname="behavior_Mower" description="Mower 1.0">
<property name="grassFolder" type="scenenode" default="" />
<property name="grassMowedCheckDistance" type="float" default="3.0" />
<property name="removeGrassNode" type="bool" default="true" />
<property name="action" type="action" default="" />
</behavior>
*/

var behavior_Mower = function () {
};

behavior_Mower.prototype.onAnimate = function (node, timeMs) {
var pos = ccbGetSceneNodeProperty(node, 'Position');

var grassPatchesCount = ccbGetSceneNodeChildCount(this.grassFolder);
for (var i = 0; i < grassPatchesCount; i++) {
var curGrass = ccbGetChildSceneNode(this.grassFolder, i);

// workaround to avoid calling actionMultiple times
if (ccbGetSceneNodeProperty(curGrass, 'Name').indexOf('_removed') !== -1) continue;

var curGrassPos = ccbGetSceneNodeProperty(curGrass, 'Position');
var distToCurGrass = curGrassPos.substract(pos).getLength();
if (distToCurGrass <= this.grassMowedCheckDistance) {
ccbSetSceneNodeProperty(curGrass, 'Name', ccbGetSceneNodeProperty(curGrass, 'Name') + '_removed');
if (this.removeGrassNode) ccbRemoveSceneNode(curGrass);
ccbInvokeAction(this.action, node);
}
}
}


Updated file https://drive.google.com/file/d/...

person icon
paperbag
Registered User
Quote
2024-05-19 18:42:28

thankyou so much it works great, I had tried to make this game over a year ago and could never get that system to work you've helped me allot

person icon
paperbag
Registered User
Quote
2024-05-20 04:38:00

Is there any way you know of to make the performance better? Even when I use billboards for grass the frame rate is very bad

Thanks

person icon
okeoke
Registered User
Quote
2024-05-21 16:21:45

Divide the whole map into small squares, identify in which square the mower is located, and only do distance check for the grass nodes inside that square.

person icon
Guest
Guest
Quote
2024-05-22 02:52:08

@paperbag

Just do it like I did in this example: https://files.catbox.moe/wci1qd....

I added a function to make some grass patches, too. You can paste the code from the JS file into an Execute JS action in the Before First Draw behavior to get rid of the extra file. I commented the code to make it more explanatory.

About the performance issue: it's inadvisable to run loops inside of frame events. Loops in loops is amateurish code. Pre-calculate lists in the load instead.

person icon
paperbag
Registered User
Quote
2024-05-22 04:24:25

hey man, I really appreciate that thankyou

person icon
okeoke
Registered User
Quote
2024-05-23 23:28:54

I had some time to experiment with the approach I mentioned. I.e. to divide the whole field into the smaller squares and only check node inside that squares.

So, I have 150x150 field, that is divided into 2500 little squares. Each square is represented by its own node, which is a clone of a base field node. Each of the copied nodes has 3 children billboard grass patches. Which means there are 7500 grass patches in total.

I use a 2d array implementation which is basically a "flat" 2d array:
function Array2d(rows, cols) {
this.rows = rows;
this.cols = cols;
this.array = new Array(rows * cols);
}

Array2d.prototype.getIndex = function (row, col) {
return row * this.cols + col;
}

Array2d.prototype.getElement = function (row, col) {
const index = this.getIndex(row, col);
return this.array[index];
}

Array2d.prototype.setElement = function (row, col, value) {
const index = this.getIndex(row, col);
this.array[index] = value;
}

This allows me to store data for all 2500 squares in a 1d array, but still be able to get any of its elements by x and y indexes, like in a normal 2d array. It's also super easy to find the square there the mower currently is, by simply flooring it's x and z position divided by the square node size. I also need to substract initial field position since it can be not at 0, 0 (which is in my case -75, -75):
    var xi = Math.floor((px - fieldPos.x) / nodeSize);
var yi = Math.floor((py - fieldPos.y) / nodeSize);

I actually have to check up to 9 squares. The one there mower is and 8 around it, so:
function findNodesToCheck(px, py) {
var xi = Math.floor((px - fieldPos.x) / nodeSize);
var yi = Math.floor((py - fieldPos.y) / nodeSize);
var nodesToCheck = [];
for (var y = yi - 1; y <= yi + 1; y++) {
for (var x = xi - 1; x <= xi + 1; x++) {
if (x < 0 || y < 0 || x > fieldWidht - 1 || y > fieldHeight - 1) continue;
nodesToCheck.push(fieldNodes.getElement(x, y));
}
}
return nodesToCheck;
}

The last thing is to get this 0 to 9 squares, and distance check to every child of them using a juicy nested loop:
    var pos = ccbGetSceneNodeProperty(this.mower, 'Position');
var nodesToCheck = findNodesToCheck(pos.x, pos.z);

pos.y = 0;

for (var j = 0; j < nodesToCheck.length; j++) {
var nodeToCheck = nodesToCheck[j].node;

var grassPatchesCount = ccbGetSceneNodeChildCount(nodeToCheck);

for (var i = 0; i < grassPatchesCount; i++) {
var curGrass = ccbGetChildSceneNode(nodeToCheck, i);

// // workaround to avoid calling actionMultiple times
if (ccbGetSceneNodeProperty(curGrass, 'Name').indexOf('_removed') !== -1) continue;

var curGrassPos = ccbGetSceneNodeProperty(curGrass, 'PositionAbs');
var distToCurGrass = curGrassPos.substract(pos).getLength();
if (distToCurGrass <= 3.0) {
ccbSetSceneNodeProperty(curGrass, 'Name', ccbGetSceneNodeProperty(curGrass, 'Name') + '_removed');
ccbRemoveSceneNode(curGrass);
}
}
}

Using that approach I'm able to get almost stable 60 fps, with some spikes for 7500 grass patches, which seems good enough for me:)
embedded external image
🔎︎

demo project: https://drive.google.com/file/d/...

person icon
paperbag
Registered User
Quote
2024-05-25 03:41:31

I really appreciate you guys putting your time into it, is it scalable and if it is how would I do it? like can I make unusually shaped lawns? And just in general how do I scale it and customize it, I'm not to good with code

thankyou

person icon
okeoke
Registered User
Quote
2024-05-25 07:52:30

The demo I made is just a way of how you check for collision. If you need a more complex shape, you can either create a field manually, or write a generator that will spawn the vegetation inside a polygon shape.

Then create square "field", which completely covers the polygon shape even if some parts of it do not have grass at all.

Unfortunately, I don't think this could be done without coding.

I also believe, that in general in games like lawnmower simulator and similar, they somehow utilize shaders in order to get that effect, not 3d models or billboards.


Create reply:










 

  

Possible Codes


Feature Code
Link [url] www.example.com [/url]
Bold [b]bold text[/b]
Image [img]http://www.example.com/image.jpg[/img]
Quote [quote]quoted text[/quote]
Code [code]source code[/code]

Emoticons


icon_holyicon_cryicon_devilicon_lookicon_grinicon_kissicon_monkeyicon_hmpf
icon_sadicon_happyicon_smileicon_uhicon_blink   






Copyright© Ambiera e.U. all rights reserved.
Contact | Imprint | Products | Privacy Policy | Terms and Conditions |