Avoiding oscillating moving in layout algorithm - javascript

Following on from this question here:
Calculate distance to move a box to remove intersection
I have a problem where moving one box causes it to overlap with another box, and the algorithm as it currently stands will just move the first box back in (almost) the direction it came from causing it to overlap the first box again and so forth. Is there a good way to avoid this situation? I feel like remembering the vector from last time and somehow combining it with the new proposed move might be the solution.
Here's a simple fiddle:
http://jsfiddle.net/x8MT3/4/
Notice how the one box is moved, but then overlaps the other box, so the box is moved again back in the opposite direction and after 6 cycles, is still overlapping.
Here's the code for the add method - it adds boxes to a list, checking the current members for otherlaps:
self.add = function (item, iteration) {
// check intersections with existing boxes
iteration = iteration || 0;
if (iteration < 6) {
for (var i = 0; i < boxes.length; i++) {
var stationary = boxes[i];
var boundsA = getBounds(item);
var boundsB = getBounds(stationary);
if (doesIntersect(boundsA, boundsB)) {
item.elem.addClass("overlapped");
// move item
// Find vector from mid point of one box to the other
var centerA = {
x: item.x + item.width / 2,
y: item.y + item.height / 2
};
var centerB = {
x: stationary.x + stationary.width / 2,
y: stationary.y + stationary.height / 2
};
var line = {
x1: centerA.x,
y1: centerA.y,
x2: centerB.x,
y2: centerB.y
}
var vector = {
x: Math.min(item.x + item.width, stationary.x + stationary.width) - Math.max(item.x, stationary.x),
y: Math.min(item.y + item.height, stationary.y + stationary.height) - Math.max(item.y, stationary.y)
};
var signX = line.x1 - line.x2 > 0 ? 1 : -1;
var signY = line.y1 - line.y2 > 0 ? 1 : -1;
item.x = item.x + vector.x * signX;
item.y = item.y + vector.y * signY;
item.elem.offset({
left: item.x,
top: item.y
});
return self.add(item, iteration + 1);
}
}
}
boxes.push(item);
}

Why do not you use iterative process ... ???
as I see it you want to rearrange boxes so they not overlap
but do not change the layout too much
if you do not mind some space between boxes (the will not touch) then:
Algorithm:
1.find overlapped box
red box
2.find movement direction
green vector
between box centers
then change it size to movement step (few pixels...)
3.compute new position of overlapped
then check for new overlaps
if too close to another box stop movement in that direction
Blue arrows shows collision stop
4.apply this (loop from bullet 1) for all overlapped boxes
do just one or few steps
not the whole movement !!!
5.iteratively loop all (from bullet 1)
stop when no overlapped box found
or process has timeout-ed ...
because this can get also stuck
[Notes]
if box centers are the same
then add random direction to movement vector
the whole process can be applied more times with decreasing step for more speed

Related

PIXI Endlessly move sprite over the scene (show at the top as much as hide in bottom)

There is endlessly moving sprite "green block" from top to bottom and it works. Is it possible to show sprite moving like "around" the stage show at the top as much as hide in bottom. I don't know exactly how this effect can be called, but I mean when green block is starting to move down the scene border, then start showing it again at the top. How can it be done and can you, please, show how to do this?
const WIDTH = 500;
const HEIGHT = 500;
const app = new PIXI.Application({
width: WIDTH,
height: HEIGHT,
backgroundColor: 0x000000
});
document.body.appendChild(app.view);
const sprite = PIXI.Sprite.from('https://i.ibb.co/b3Sjn6M/greeenblock.png');
sprite.width = 100;
sprite.height = 100;
// Center
sprite.anchor.set(0.5);
sprite.x = app.screen.width / 2;
sprite.y = app.screen.height / 2;
app.stage.addChild(sprite);
// Listen for animate update
app.ticker.add((delta) => {
// Move from topto bottom
sprite.position.y += delta * 2;
if (sprite.position.y > HEIGHT + sprite.height / 2) {
sprite.position.y = -sprite.height / 2;
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/5.3.3/pixi.min.js"></script>
Solution (with flickering) provided by #Blindman67:
const WIDTH = 500;
const HEIGHT = 500;
const app = new PIXI.Application({
width: WIDTH,
height: HEIGHT,
backgroundColor: 0x000000
});
document.body.appendChild(app.view);
const sprite = PIXI.Sprite.from('https://i.ibb.co/b3Sjn6M/greeenblock.png');
const spriteReverse = PIXI.Sprite.from('https://i.ibb.co/b3Sjn6M/greeenblock.png');
sprite.width = 100;
sprite.height = 100;
spriteReverse.width = 100;
spriteReverse.height = 100;
// Center
sprite.anchor.set(0.5);
sprite.x = app.screen.width / 2;
sprite.y = app.screen.height / 2;
spriteReverse.anchor.set(0.5);
spriteReverse.x = app.screen.width / 2;
spriteReverse.y = app.screen.height / 2;
app.stage.addChild(sprite);
app.stage.addChild(spriteReverse);
let y = 0;
// Euqlidian modulo
const modAbs = (value, modulo) => (value % modulo + modulo) % modulo;
// Listen for animate update
app.ticker.add((delta) => {
// Move from topto bottom
y += delta * 2;
if (y > HEIGHT + sprite.height / 2) {
y = -sprite.height / 2;
}
// use modulo to warp
y = modAbs(y, HEIGHT);
// check if sprite overlaps the screen edge
spriteReverse.visible = false;
if (y + sprite.height > HEIGHT) { // is crossing then
spriteReverse.visible = true;
spriteReverse.position.y = (y - HEIGHT) // ... draw a copy at opposite edge.
}
sprite.position.y = y
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/5.3.3/pixi.min.js"></script>
If I understand you: you have one box which you wish to move in an infinite loop from the top to the bottom. Once it hits the bottom it should start showing at the top.
The easiest way I can think of would be to have two identical boxes.
Both starts at the top and only one moves down. Once it hits the bottom the other box can start moving down.
When the first box is completely off-screen you reset it's position.
And repeat.
% Remainder operator
This can be done using the remainder operator %
For example if the screen is 1000 pixels wide and you have a coordinate of 1500, that is the object has warped around the screen 1.5 times, using the remainder operator 1500 % 1000 = 500.
If only moving in a positive direction then this is all that is needed (apart from popping)
x = x % screenWidth;
// and/or for y
y = y % screenHeight;
Negative space
However there is a problem if the object moves in the other direction as the remainder operation keeps the sign of the number -1500 % 1000 === -500, and even worse if you use Math.abs on the result you still get the wrong value Math.abs(-1200 % 1000) === 200 which should be 800
You can fix this using a slightly more complex function. You can add it to the Math object or use a stand alone function as follows.
const modAbs = (value, modulo) => (value % modulo + modulo) % modulo;
With the above function negative values are correctly moved into positive space.
So if you have a coordinate x, y to make it warp the screen with
x = modAbs(x, screenWidth);
y = modAbs(y, screenHeight);
That seams easy, but unfortunately there are still some problems to overcome.
Popping
Using the above function to warp across the screen does not consider the size of the sprite, and because you are rendering only one copy when the sprite is move across the playfield edge it will not appear at the other side until the coordinate crossed the edge.
This causes the sprite to pop in and or out depending on the direction of movement and the position of the sprites origin.
There are two solutions.
Extend the playfield
If you make the playfield larger than the view (Viewable area) by 2 times the size of the sprite and warp using the larger playfield then the sprite will not warp until it has completely disappeared from view. This prevents the ugly popping in and out when warping and is most suited to NPC type sprites. For player (focused) sprites this is not a good options as the sprite will not be completely visible as it crosses the screen edges.
Render extra copies.
To keep the sprite fully visible at all times you need to render it more than once when it is crossing the screen. Example pseudo code
// use modulo to warp
x = modAbs(x, screenWidth);
// check if sprite overlaps the screen edge
if (x + spriteWidth > screenWidth) { // is crossing then
drawSprite(x - screenWidth, // ... draw a copy at opposite edge.
If you are only warping between top and bottom (or left and right) this is all that is needed.
If you are warping in all directions you will need to render the sprite up to 4 times. Twice when crossing top bottom or left right. 4 times if crossing in a corner.
As your question only indicates up and down warps I assume you don't need the extra code.

How to draw a tiled wall between two points on a grid on canvas?

I'm creating a simulator with the Pixijs engine.
I have a function that is is to be used to draw a wall using the mouse. But I just can't seem to get it right. This is probably more of a math issue than programming.
Anyway, it should work like this:
User clicks on a square tile (start position is set)
Tink library for Pixi returns the (x,y) position just clicked on
relative to the canvas
User clicks on second square (in same row or column) and the
destination point is set
Please take a look at this Fiddle.
https://jsfiddle.net/ensf32e0/18/
I can get it to draw from left to right and from top to bottom. But right to left and bottom to top fail me.
I'm using an object with booleans to keep track of whether the user is putting down a start position or an end position. I'm not sure this isa good implementation.
let wallsObj={
start:{
x:0,
y:0,
done:false
},
end:{
x:1,
y:1,
done:false
}
};
drawTile draws a single tile and drawWallLine is the function with the problem. It takes the start and end positions and draws a tiled line between them:
function drawWallLine (obj,size) {
// Determine whether line is to be drawn horizontally or vertically
// if abs(x2-x1) is larger than abs(y2-y1) then horizontal else vertical
// assign len the the actual length of line
let len = Math.abs(obj.end.x - obj.start.x) > Math.abs(obj.end.y - obj.start.y)
? obj.end.x - obj.start.x
: obj.end.y - obj.start.y;
console.log('drawWallLine', len);
// same as above. If direction is horizontal, mx = 1 and my = 0 and vice versa
// this to be used to determine the polarity of size
let mx = Math.abs(obj.end.x - obj.start.x) > Math.abs(obj.end.y - obj.start.y) ? 1 : 0;
let my = Math.abs(obj.end.x - obj.start.x) < Math.abs(obj.end.y - obj.start.y) ? 1 : 0;
console.log("mx, my", mx, my);
// Get polarity of size. +size is going down or right while -size is going up or left
if (mx === 1) {
size = obj.end.x - obj.start.x >= 0 ? size : size * -1;
}
if (my === 1) {
size = obj.end.y- obj.start.y >= 0 ? size : size * -1;
}
console.log('size', size);
// If going down or right then
if (size >=0 ) {
for (let i = 0; i < Math.abs(len); i+=size) {
drawTile({
len: rs,
x: obj.start.x - obj.start.x%rs - .5 + i * mx,
y: obj.start.y - obj.start.y%rs - .5 + i * my,
line:{
width:1,
color:0xC2C2C2,
alpha:1
},
fill:{
color:0xFFFFFF,
alpha:1
}
});
}
} else { // if going up or left
for (let i = Math.abs(len); i > 0; i+=size) {
drawTile({
len: rs,
x: obj.start.x - obj.start.x%rs - .5 + i * mx,
y: obj.start.y - obj.start.y%rs - .5 + i * my,
line:{
width:1,
color:0xC2C2C2,
alpha:1
},
fill:{
color:0xFFFFFF,
alpha:1
}
});
}
}
}
This is my first time doing something like this so please bear with me. I feel like there's an obvious solution but i'm failing to see it.
Well, a simple fix to your problem is just to make sure that the start x/y is always the lower then the end x/y value. So I added the following code to the beginning of the drawWallLine function:
function drawWallLine (obj, size) {
if(obj.start.x > obj.end.x){
var temp = obj.start.x;
obj.start.x = obj.end.x;
obj.end.x = temp;
}
if(obj.start.y > obj.end.y){
var temp = obj.start.y;
obj.start.y = obj.end.y;
obj.end.y = temp;
}
This basically makes sure that the start value is always the lower value by swapping between start and end if start is bigger than end.
Here is the updated working fiddle: https://jsfiddle.net/ensf32e0/24/

svg.js animated rotation of elements gives unexpected results (visible "jiggling")

I am using svg.js to create an animation of a bicyle rider. Semi-complete version here: https://pedalfuriously.neocities.org/. I'm running in to a bit of a problem with moving and rotating svg elements during animation created with requestAnimationFrame (rather than the svg.js built in animation).
If you take a look at the link, and use the cadence slider to make the rider pedal very fast, and then flip the slider quickly all the way back to zero, you can see that his lower leg "jiggles" in a disconnected way. What's really doing my head in is that the postion of the legs are determined in each frame based on an absolute relation to the rotation of the cranks (rather than taking some delta time value to determine movement over that frame).
I think I've been able to confirm what aspect of my code is causing the problem. Here is a minimal example that doesn't exhibit the exact behaviour, but I think illustrates the kind of thing I think is responsible:
var draw = SVG("drawing").viewbox(0, 0, 400, 400)
var origin = {
x: 70,
y: 70
}
var length = 60
var blueLine = draw.group()
blueLine.line(0, 0, 0 + length, 0).move(origin.x, origin.y)
.stroke({
color: "#00f",
width: 4
})
blueLine.angle = 0
var greenLine = draw.group()
greenLine.line(0, 0, 0 + length, 0).move(origin.x, origin.y)
.stroke({
color: "#0f0",
width: 4
})
greenLine.angle = 0
var previous = 0
var dt = 0
var step = function(timestamp) {
dt = timestamp - previous
previous = timestamp
blueLine.angle += 0.18 * dt
blueLine.rotate(blueLine.angle, origin.x, origin.y)
var endX = Math.cos(toRad(blueLine.angle)) * length
var endY = Math.sin(toRad(blueLine.angle)) * length
// Comment out this line, and rotation works fine
greenLine.move(endX, endY)
greenLine.angle = blueLine.angle - 10
// Comment out this line, and movement works fine
greenLine.rotate(greenLine.angle, origin.x, origin.y)
// But they don't work together. If I both move and rotate
// the green line, it goes in this crazy huge arc, rather
// than rotating neatly around the end of the blue line
// as expected.
window.requestAnimationFrame(step)
}
window.requestAnimationFrame(step)
function toRad(deg) {
return deg * (Math.PI / 180)
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/svg.js/2.6.4/svg.js"></script>
<div id="drawing"></div>
Something else I noticed with my actual code is that if I move the position of the legs, it changes the severity of the problem, or even stops it altogether. If the hips are positioned all the way near the front of the bicycle, the problem is not nearly as bad. Also, if I disable rotation on the lower legs, there is no jiggling. In some positions, the lower leg will just rotate out of the screen instantly on load, even before any motion has been started.
I'm hoping for some guidance on wether I'm misunderstanding the way manipulating elements works, either in svg.js in particular, or SVG in general.
Thank you kind vector graphics experts!
Here is the actual code for the legs. The step() function would probably be the most relevant. Not sure if it will be helpful:
Rider.Leg = function(foot, front, xOffset, yOffset) {
var upper = front ? SVGE.upperLeg : SVGE.upperLegBack
var lower = front ? SVGE.lowerLeg : SVGE.lowerLegBack
this.foot = foot
this.draw = foot.draw
this.geo = {
upper: {
x: this.foot.pedal.gear.x + 150,
y: this.foot.pedal.gear.y - 750,
length: 396
},
lower: {
length: 390
}
}
this.upper = this.draw.group().svg(upper).move(this.geo.upper.x, this.geo.upper.y)
.transform({ scale: 0.95, cx: 0, cy: 0 })
this.lower = this.draw.group().svg(lower).move(this.geo.upper.x, this.geo.upper.y)
}
// Step function does not take in a time argument. Positioning of legs is based only on
// the absolute position of other elements, none of which jiggle.
Rider.Leg.prototype.step = function () {
var angle = this.pedalAngle() - Math.PI
var ha = this.scaleneAngle(this.geo.lower.length, this.geo.upper.length, this.pedalDistance())
var ka = this.scaleneAngle(this.pedalDistance(), this.geo.lower.length, this.geo.upper.length)
var x = this.geo.upper.length * Math.cos(ha + angle)
var y = this.geo.upper.length * Math.sin(ha + angle)
this.upper.rotate(Drive.toDeg(angle + ha), 0, 0)
this.lower.move(this.geo.upper.x + x, + this.geo.upper.y + y)
this.lower.rotate(Drive.toDeg(angle + ha + ka - Math.PI), 0, 0)
}
// Gets the distance between the hip joint and the pedal
Rider.Leg.prototype.pedalDistance = function () {
var pos = this.foot.getPos()
var xDist = this.geo.upper.x - pos.x
var yDist = this.geo.upper.y - pos.y
return Math.hypot(xDist, yDist)
}
// Gets the angle between the hip joint and the pedal
Rider.Leg.prototype.pedalAngle = function () {
var pos = this.foot.getPos()
var xDist = this.geo.upper.x - pos.x
var yDist = this.geo.upper.y - pos.y
return Math.atan2(yDist, xDist)
}
Rider.Leg.prototype.scaleneAngle = function (a, b, c) {
return Math.acos(((b * b) + (c * c) - (a * a)) / (2 * b * c))
}
When you call move() on a group it is internally represented as a translation. svg.js figures out crazy ways to translate the object to the new place without changing any other transformations. That often does not work out. Especially not, when you rotate.
Thats why you should avoid these absolute transformations and go with relative ones. Just call untransform before every move and go from zero. Then you can do:
greenLine.transform({x:endX, y:endY, relative: true})
To move the line by a certain amount. That should work way better.

javascript game sprite positioning

I'm trying to create a chess board, and place it in the middle of the screen, so far i cannot get it to be directly in the center. i don't want to hard code the position to the screen because i'm going to be dealing with different screen sizes.
var winsize = cc.director.getWinSize();
var centerpos = cc.p(winsize.width / 2, winsize.height / 2);
for (i=0; i<64; i++){
var tile = cc.Sprite.create(res.tile_png);
this.addChild(tile,0);
tile.setPosition(winsize.width+i%8*50/-10, winsize.height-Math.floor(i/8)*50);
}
But the tiles and positioning is completely off
#jumpman8947, if you're using Cocos2d js perhaps you have a similar line: cc.view.setDesignResolutionSize(480, 320, cc.ResolutionPolicy.SHOW_ALL);
In this particular case the game will scale to any sceeen, but still run in 480x320 resolution, so no matter what screen resoultion you use, the center in the cocos world would always be cc.p(240, 160) so no matter what's the window size or the screen resolution, the resolution of the game stays the same
You can read more about resolution policies here (and in official js-doc):
http://www.cocos2d-x.org/wiki/Multiple_Resolution_Policy_for_Cocos2d-JS
Also please be aware, that the Sprite position in Cocos is the position of the centre of the sprite, not bottom left corner
In your question it's not completely clear exactly what you want. However, I made some assumptions. The explanation for my solution is embedded in the comments in the code below.
// var winsize = cc.director.getWinSize();
// Here is some example hard-coded return values:
var winsize = {width: 600, height: 400};
// You can change these numbers to see how they influence
// the outcome.
// var centerpos = cc.p(winsize.width / 2, winsize.height / 2);
// This line doesn't seem relevant for the question you asked.
// Or, rather, the following calculations will result in the tiles
// being centred on the screen anyway, so this calculation here
// is unnecessary.
// Being a chess board, I assume that you want the tiles to be square,
// i.e. to have the same width and height.
// If so, first find out which is the minimum dimension
// and calculate the tile size as being 1/8 of that.
var minDimn = Math.min(winsize.width, winsize.height);
var tileSize = minDimn / 8;
// Find out how far in from the left and how far down from the top
// you need the upper left corner of the upper left tile to start.
// This assumes that you don't need any "margin" around the board.
// (If you do need such a "margin", basically subtract it twice
// from each of winsize.width and winsize.height above.)
// Start with default values of 0 for each, but then add in the
// excess for the longer dimension, but divide it by two
// because that excess will be split between either
// the top and bottom or the left and right.
var xStart = 0, yStart = 0;
if (winsize.width > winsize.height) {
xStart = (winsize.width - winsize.height) / 2;
} else if (winsize.height > winsize.width) {
yStart = (winsize.height - winsize.width) / 2;
}
// Instead of looping through all 64 positions in one loop,
// loop through all the horizontal positions in an outer loop
// and all the vertical positions in an inner loop.
for (i = 0; i < 8; i++) {
// For the horizontal dimension, calculate x for each tile
// as the starting position of the left-most tile plus
// the width of the tile multiplied by the number of tiles (0-based)
var x = xStart + i * tileSize;
// Now the inner loop
for (j = 0; j < 8; j++) {
// Same type of calculation for the y value.
var y = yStart + j * tileSize;
// You can see the values in this demo here.
document.write("<pre>(" + x + ", " + y + ")</pre>");
// The following two lines don't seem to be relevant to the question.
// var tile = cc.Sprite.create(res.tile_png);
// this.addChild(tile,0);
// Use your calculated values in your function call.
// tile.setPosition(x, y);
}
}

randomly mapping divs

I am creating a new "whack-a-mole" style game where the children have to hit the correct numbers in accordance to the question. So far it is going really well, I have a timer, count the right and wrong answers and when the game is started I have a number of divs called "characters" that appear in the container randomly at set times.
The problem I am having is that because it is completely random, sometimes the "characters" appear overlapped with one another. Is there a way to organize them so that they appear in set places in the container and don't overlap when they appear.
Here I have the code that maps the divs to the container..
function randomFromTo(from, to) {
return Math.floor(Math.random() * (to - from + 1) + from);
}
function scramble() {
var children = $('#container').children();
var randomId = randomFromTo(1, children.length);
moveRandom('char' + randomId);
}
function moveRandom(id) {
var cPos = $('#container').offset();
var cHeight = $('#container').height();
var cWidth = $('#container').width();
var pad = parseInt($('#container').css('padding-top').replace('px', ''));
var bHeight = $('#' + id).height();
var bWidth = $('#' + id).width();
maxY = cPos.top + cHeight - bHeight - pad;
maxX = cPos.left + cWidth - bWidth - pad;
minY = cPos.top + pad;
minX = cPos.left + pad;
newY = randomFromTo(minY, maxY);
newX = randomFromTo(minX, maxX);
$('#' + id).css({
top: newY,
left: newX
}).fadeIn(100, function () {
setTimeout(function () {
$('#' + id).fadeOut(100);
window.cont++;
}, 1000);
});
I have a fiddle if it helps.. http://jsfiddle.net/pUwKb/8/
As #aug suggests, you should know where you cannot place things at draw-time, and only place them at valid positions. The easiest way to do this is to keep currently-occupied positions handy to check them against proposed locations.
I suggest something like
// locations of current divs; elements like {x: 10, y: 40}
var boxes = [];
// p point; b box top-left corner; w and h width and height
function inside(p, w, h, b) {
return (p.x >= b.x) && (p.y >= b.y) && (p.x < b.x + w) && (p.y < b.y + h);
}
// a and b box top-left corners; w and h width and height; m is margin
function overlaps(a, b, w, h, m) {
var corners = [a, {x:a.x+w, y:a.y}, {x:a.x, y:a.y+h}, {x:a.x+w, y:a.y+h}];
var bWithMargins = {x:b.x-m, y:b.y-m};
for (var i=0; i<corners.length; i++) {
if (inside(corners[i], bWithMargins, w+2*m, h+2*m) return true;
}
return false;
}
// when placing a new piece
var box;
while (box === undefined) {
box = createRandomPosition(); // returns something like {x: 15, y: 92}
for (var i=0; i<boxes.length; i++) {
if (overlaps(box, boxes[i], boxwidth, boxheight, margin)) {
box = undefined;
break;
}
}
}
boxes.push(box);
Warning: untested code, beware the typos.
The basic idea you will have to implement is that when a random coordinate is chosen, theoretically you SHOULD know the boundaries of what is not permissible and your program should know not to choose those places (whether you find an algorithm or way of simply disregarding those ranges or your program constantly checks to make sure that the number chosen isn't within the boundary is up to you. the latter is easier to implement but is a bad way of going about it simply because you are entirely relying on chance).
Let's say for example coordinate 50, 70 is selected. If the picture is 50x50 in size, the range of what is allowed would exclude not only the dimensions of the picture, but also 50px in all directions of the picture so that no overlap may occur.
Hope this helps. If I have time, I might try to code an example but I hope this answers the conceptual aspect of the question if that is what you were having trouble with.
Oh and btw forgot to say really great job on this program. It looks awesome :)
You can approach this problem in at least two ways (these two are popped up in my head).
How about to create a 2 dimensional grid segmentation based on the number of questions, the sizes of the question panel and an array holding the position of each question coordinates and then on each time frame to position randomly these panels on one of the allowed coordinates.
Note: read this article for further information: http://eloquentjavascript.net/chapter8.html
The second approach follow the same principle, but this time to check if the panel overlap the existing panel before you place it on the canvas.
var _grids;
var GRID_SIZE = 20 //a constant holding the panel size;
function createGrids() {
_grids = new Array();
for (var i = 0; i< stage.stageWidth / GRID_SIZE; i++) {
_grids[i] = new Array();
for (var j = 0; j< stage.stageHeight / GRID_SIZE; j++) {
_grids[i][j] = new Array();
}
}
}
Then on a separate function to create the collision check. I've created a gist for collision check in Actionscript, but you can use the same principle in Javascript too. I've created this gist for inspirational purposes.
Just use a random number which is based on the width of your board and then modulo with the height...
You get a cell which is where you can put the mole.
For the positions the x and y should never change as you have 9 spots lets say where the mole could pop up.
x x x
x x x
x x x
Each cell would be sized based on % rather then pixels and would allow re sizing the screen
1%3 = 1 (x)
3%3 = 0 (y)
Then no overlap is possible.
Once the mole is positioned it can be show or hidden or moved etc based on some extended logic if required.
If want to keep things your way and you just need a quick re-position algorithm... just set the NE to the SW if the X + width >= x of the character you want to check by setting the x = y+height of the item which overlaps. You could also enforce that logic in the drawing routine by caching the last x and ensuring the random number was not < last + width of the item.
newY = randomFromTo(minY, maxY);
newX = randomFromTo(minX, maxX); if(newX > lastX + characterWidth){ /*needful*/}
There could still however be overlap...
If you wanted to totally eliminate it you would need to keep track of state such as where each x was and then iterate that list to find a new position or position them first and then all them to move about randomly without intersecting which would would be able to control with just padding from that point.
Overall I think it would be easier to just keep X starting at 0 and then and then increment until you are at a X + character width > greater then the width of the board. Then just increase Y by character height and Set X = 0 or character width or some other offset.
newX = 0; newX += characterWidth; if(newX + chracterWidth > boardWidth) newX=0; newY+= characterHeight;
That results in no overlap and having nothing to iterate or keep track of additional to what you do now, the only downside is the pattern of the displayed characters being 'checker board style' or right next to each other (with possible random spacing in between horizontal and vertical placement e.g. you could adjust the padding randomly if you wanted too)
It's the whole random thing in the first place that adds the complexity.
AND I updated your fiddle to prove I eliminated the random and stopped the overlap :)
http://jsfiddle.net/pUwKb/51/

Categories