// this method will be called once per frame
(plane as any).tick = (delta: number) => {
let pos = geometry.getAttribute("position");
let pa = pos.array as Float32Array;
let vectorArr : THREE.Vector3[] = [];
for (let i = 0; i < pa.length; i += 3) {
vectorArr.push(new THREE.Vector3(pa[i], pa[i + 1], pa[i + 2]));
}
for (let vect of vectorArr) {
vect.x -= 5 * delta;
if (vect.x < - 40) {
vect.x = 40;
removeArr.push(vect);
}
}
vectorArr.map((vect, i) => {
pa[3 * i] = vect.x;
pa[3 * i + 1] = vect.y;
pa[3 * i + 2] = vect.z;
});
pos.needsUpdate = true;
}
The above code is used for modifying the plane, I'm basically just trying to reset the vectors that are past x=-40, but that's leaving behind some sort of 'connecting plane' between the plane. Image below an example, the material is double sided(but changing it still leaves behind the weird connecting plane).
What it looks like normally, without the vector.x -= 5 * delta below.
I'm basically just trying to create an infinite scrolling landscape, so if you have a good way to do this in ThreeJS apart from my code, please let me know!
I am fairly new to p5.js, however I am trying to read a .txt file which contains the below text, and draw a picture depending on the value within the .txt file.
00000
20022
00222
22020
11111
I am currently stumped as to how to draw an image depending on the number in the array, as an example '1' would be grass. I have loaded the file in as a string using the following code: track = loadStrings("track1.txt");
I am trying to load it as a 5x5 'tile' if you will. Any help would be appreciated :)
I've used p5.Image to create a picture based on the pixels in the file.
This is a way of writing the code:
let track;
let colors;
let img;
function setup() {
createCanvas(100, 100);
track=loadStrings("track1.txt")
colors = [color(255,0,0),color(0,255,0),color(0,0,255)]
}
function draw() {
background(220);
img = createImage(track.length, track[0].length)
img.loadPixels();
for (let i = 0 ; i < track.length ; i++){
for (let j = 0 ; j < track.length ; j++){
img.set(i, j, colors[int(track[i][j])]);
}
}
img.updatePixels();
image(img, 50, 50);
}
Well you could probs split it up into arrays and also if you'd have some sort of seperator for colors, like: track1.txt: 10, 30, 255\n ... r, g, b\n .... Right now you would have to use the rgb rrrgggbbb
let colors = track.split("\n") // makes every new line into an array
for(let x = 0; x <= width; x ++) // "\n" = new line
for(let y = 0; y <= height; y ++){
let currentCol = []
for(let i = 0; i < 9; i += 3)
currentCol.push(
colors[x + y][0 + i] + // I'm really not sure about the: colors[x + y]...
colors[x + y][1 + i] +
colors[x + y][2 + i]
)
set(x, y, color(currentCol[0], currentCol[1], currentCol[2]))
}
I also made a function with a slightly different formula, which might work better, i am not sure though, but this is the actual formula to get from pixel array
function getColor(x, y, allColorsArr){
let _col = [] // current color, underscore not to accidentally clear your variable
for(let i = 0; i < 3; i ++)
_col.push(
allColorsArr[x + y * width][0 + i * 3] +
allColorsArr[x + y * width][1 + i * 3] +
allColorsArr[x + y * width][2 + i * 3]
)
return {
r: parseInt(_col[0], 10),
g: parseInt(_col[1], 10),
b: parseInt(_col[2], 10)
} // returning an object here just for the `.r`; `.g`; `.b`
} // you could do something like: let Colors = {red: 0, green: 1, blue: 2}
// col[Colors.red], col[Colors.green], col[Colors.blue] if you want
// example: let col = getColor(1, 0, track.split("\n"))
// example: stroke(col.r, col.g, col.b)
THERE IS MOST LIKELY IS A BETTER WAY TO DO THIS, but at least this works...
I have seen this question for other languages but not for AS3... and I'm having a hard time understanding it...
I need to generate 3 numbers, randomly, from 0 to 2, but they cannot repeat (as in 000, 001, 222, 212 etc) and they cannot be in the correct order (0,1,2)...
Im using
for (var u: int = 0; u < 3; u++)
{
mcCor = new CorDaCarta();
mcCor.x = larguraTrio + (mcCor.width + 5) * (u % 3);
mcCor.y = alturaTrio + (mcCor.height + 5) * (Math.floor(u / 3));
mcCor.gotoAndStop((Math.random() * (2 - u + 1) + u) | 0); // random w/ repeats
//mcCor.gotoAndStop(Math.floor(Math.random() * (2 - u + 1) + u)); // random w/ repeats
//mcCor.gotoAndStop((Math.random() * 3) | 0); // crap....
//mcCor.gotoAndStop(Math.round(Math.random()*u)); // 1,1,1
//mcCor.gotoAndStop(u + 1); // 1,2,3
mcCor.buttonMode = true;
mcCor.addEventListener(MouseEvent.CLICK, cliquetrio);
mcExplic.addChild(mcCor);
trio.push(mcCor);
}
those are the codes i've been trying.... best one so far is the active one (without the //), but it still gives me duplicates (as 1,1,1) and still has a small chance to come 0,1,2....
BTW, what I want is to mcCor to gotoAndStop on frames 1, 2 or 3....without repeating, so THE USER can put it on the right order (1,2,3 or (u= 0,1,2), thats why I add + 1 sometimes there)
any thoughts?? =)
I've found that one way to ensure random, unique numbers is to store the possible numbers in an array, and then sort them using a "random" sort:
// store the numbers 0, 1, 2 in an array
var sortedNumbers:Array = [];
for(var i:int = 0; i < 3; i++)
{
sortedNumbers.push(i);
}
var unsortedNumbers:Array = sortedNumbers.slice(); // make a copy of the sorted numbers
trace(sortedNumbers); // 0,1,2
trace(unsortedNumbers); // 0,1,2
// randomly sort array until it no longer matches the sorted array
while(sortedNumbers.join() == unsortedNumbers.join())
{
unsortedNumbers.sort(function (a:int, b:int):int { return Math.random() > .5 ? -1 : 1; });
}
trace(unsortedNumbers); // [1,0,2], [2,1,0], [0,1,2], etc
for (var u: int = 0; u < 3; u++)
{
mcCor = new CorDaCarta();
mcCor.x = larguraTrio + (mcCor.width + 5) * (u % 3);
mcCor.y = alturaTrio + (mcCor.height + 5) * (Math.floor(u / 3));
// grab the corresponding value from the unsorted array
mcCor.gotoAndStop(unsortedNumbers[u] + 1);
mcCor.buttonMode = true;
mcCor.addEventListener(MouseEvent.CLICK, cliquetrio);
mcExplic.addChild(mcCor);
trio.push(mcCor);
}
Marcela is right. Approach with an Array is widely used for such task. Of course, you will need to check 0, 1, 2 sequence and this will be ugly, but in common code to get the random sequence of integers can look like this:
function getRandomSequence(min:int, max:int):Array
{
if (min > max) throw new Error("Max value should be greater than Min value!");
if (min == max) return [min];
var values:Array = [];
for (var i:int = min; i <= max; i++) values.push(i);
var result:Array = [];
while (values.length > 0) result = result.concat(values.splice(Math.floor(Math.random() * values.length), 1));
return result;
}
for (var i:uint = 0; i < 10; i++)
{
trace(getRandomSequence(1, 10));
}
You will get something like that:
2,9,3,8,10,6,5,1,4,7
6,1,2,4,8,9,5,10,7,3
3,9,10,6,8,2,5,4,1,7
7,6,1,4,3,8,9,2,10,5
4,6,7,1,3,2,9,10,8,5
3,10,5,9,1,7,2,4,8,6
1,7,9,6,10,3,4,5,2,8
4,10,8,9,3,2,6,1,7,5
1,7,8,9,10,6,4,3,2,5
7,5,4,2,8,6,10,3,9,1
I created this for you. It is working but it can be optimized...
Hope is good for you.
var arr : Array = [];
var r : int;
for (var i: int = 0; i < 3; i++){
r=rand(0,2);
if(i == 1){
if(arr[0] == r){
i--;
continue;
}
if(arr[0] == 0){
if(r==1){
i--;
continue;
}
}
}else if(i==2){
if(arr[0] == r || arr[1] == r){
i--;
continue;
}
}
arr[i] = r;
}
trace(arr);
for(var i=0;i<3;i++){
mcCor = new CorDaCarta();
mcCor.x = larguraTrio + (mcCor.width + 5) * (i % 3);
mcCor.y = alturaTrio + (mcCor.height + 5) * (Math.floor(i / 3));
mcCor.gotoAndStop(arr[i]);
mcCor.buttonMode = true;
mcCor.addEventListener(MouseEvent.CLICK, cliquetrio);
mcExplic.addChild(mcCor);
trio.push(mcCor);
}
function rand(min:int, max:int):int {
return Math.round(Math.random() * (max - min) + min);
}
try this...
This is a basic piece of code I've created that generates a random two-coloured level:
var map:Array = new Array();
var mLength:int = 28;
var mHeight:int = 16;
var mArea:int = mLength * mHeight;
var tileWidth:int = 20;
var tileHeight:int = 20;
var tileX:int = 0 - tileWidth;
var tileY:int = 0;
var genTile:int;
var genDone:Boolean = false;
var waterChance:int = 10;
var grassChance:int = 33;
var tile:Sprite = new Sprite();
var waterTile:Sprite = new Sprite();
var waterHolder:Sprite = new Sprite();
var genericTileHolder:Sprite = new Sprite();
var hitting:Boolean = false;
var i:int = 0;
for (i = 0; i < mArea; i++) {
if (map[i - 27] == 1) {
waterChance * 8;
grassChance / 2;
}
if (map[i - 28] == 1) {
waterChance * 8;
grassChance / 2;
}
if (map[i - 29] == 1) {
waterChance * 8;
grassChance / 2;
}
if (map[i - 1] == 1) {
waterChance * 8;
grassChance / 2;
}
tileX += tileWidth;
if (tileX >= mLength * tileWidth) {
tileX = 0;
tileY += tileHeight;
}
genTile = (Math.round((Math.random()*(waterChance+grassChance))));
if (0 < genTile < waterChance) {
waterTile.graphics.beginFill(0x0033CC);
waterTile.graphics.drawRect(tileX,tileY,tileWidth,tileHeight);
waterHolder.addChildAt(waterTile, 0);
map.push("1");
}
if ((waterChance + 1) < genTile && genTile < (waterChance + grassChance)) {
tile.graphics.beginFill(0x216B18);
tile.graphics.drawRect(tileX,tileY,tileWidth,tileHeight);
genericTileHolder.addChildAt(tile, 0);
map.push("2");
}
grassChance = 33;
waterChance = 10;
}
stage.addChildAt(waterHolder, 0);
stage.addChildAt(genericTileHolder, 1);
The problem is two-fold. One, whenever the array generates, the length seems to have a random bit of variation- using trace(map.length) I get a lot of different lengths, from 750 to 780, when it should only be 400 at most.
Secondly, whenever I trace the level itself, using trace(map) I find that the first element seems to be set by default to 1. I can't figure out why it's doing this, as it should be 2 at least once after 20 tries.
You cant compare more than 2 items in actionscript:
if (0 < genTile < waterChance) {...
It will always return true (i think). Instead:
if ((0 < genTile) && (genTile < waterChance)) {...
Also, looks like each loop can do map.push("1") and map.push("2") - hence map is larger than mArea - i assume it should do one or the other?
Problem 2: first element of map is 1 by default
if (0 < genTile < waterChance)
{
waterTile.graphics.beginFill (0x0033CC); // Blue
waterTile.graphics.drawRect (tileX,tileY,tileWidth,tileHeight);
waterHolder.addChildAt (waterTile, 0);
map.push ("1");
}
Since < operator is left-associative, the expression will be evaluated as (0 < genTile) < waterChance.
Since genTile is never less than 0, (0 < genTile) is always false.
And since waterChance is also never less than 0, (false < waterChance)
which translates to (0 < waterChance) is always true.
That makes (0 < genTile) < waterChance always true.
Therefore the first element of map is always "1".
Problem 1: map.length varies
if ((waterChance + 1) < genTile && genTile < (waterChance + grassChance))
{
tile.graphics.beginFill (0x216B18); // Green
tile.graphics.drawRect (tileX,tileY,tileWidth,tileHeight);
genericTileHolder.addChildAt (tile, 0);
map.push ("2");
}
Since mArea equals 448, the water tiles will always total to 448 .
And since genTile is a random number, the grass tiles will always total to a random number.
Therefore map.length varies.
I hope that helps.
I'm working in Actionscript 3, but this is pretty general.
I'd like to make a simple function that I can call, e.g. GiveCords(Width, Height, Num) that will take a width and height, map that out and using the Num variable place the given amount evenly across the space.
Say I give it a value of 500, 500, 1. I'd expect it to return an X, Y position of 250, 250.
But I'd like it to return an array of given points with X, Y.
So If I gave it 10 points, it would find the best position for them all to be of even distance apart from each other.
I'm guessing there is a simple formula for working this out, but I've searched a plenty and found nothing.
Cheers
If I understood correctly this should do the job:
var object:Object = {width: 500, height:500, num:10};
var points:Array = getCoordinates(object);
function getCoordinates(object:Object):Array {
var array:Array = new Array();
var widthMultiplier:Number = object.width / (object.num + 1);
var heightMultiplier:Number = object.height / (object.num + 1);
for (a = 1; a <= object.num; a++) {
var coordinates:Point = new Point();
coordinates.x = widthMultiplier * a;
coordinates.y = heightMultipler * a;
array.push(coordinates);
}
return array;
}
It takes the number of items and the total space, divides the total space by the number of items + 1 (to account for the space at the end of the last element) increment the objects each time.
Edit: In response to comments here is a version where you can state the number of rows you want your objects to spread across. If the number of rows does not divide the number of objects and return an integer then the function will return null. If you do not give it a rows paramater it assumes you want it across one row. Enjoy.
var object:Object = {width:500,height:500,num:10};
var points:Array = getCoordinates(object,2);
function getCoordinates(object:Object, rows:int = 1):Array
{
if ((object.num / rows) % 1)
{
return null;
}
else
{
var columns:int = object.num / rows;
var array:Array = new Array();
var widthMultiplier:Number = object.width / (columns + 1);
var heightMultiplier:Number = object.height / (rows + 1);
for (var a = 1; a <= rows; a++)
{
for (var b = 1; b <= columns; b++)
{
var coordinates:Point = new Point();
coordinates.x = widthMultiplier * b;
coordinates.y = heightMultiplier * a;
array.push(coordinates);
}
}
return array;
}
}