I am currently developing a kind of 2d game from a certain perspective (camera) and making it look like a 3d game.
The perspective never changes (turns).
Whatever. I have now reached the point of coding the hitboxes and the player is already able to recognize Colissions with other objects (Entitys).
Now I want to keep the player from running into other entities (hitboxes). My idea was to perform a colission detection as described below and then calculate the intersection so that I know on which side of the hitbox the player and the entity collide. Finally, I set the x or y speed of the player to 0, depending on where the overlap occurs.
I don't really know how to detect the Overlapping Axis / Axes, all I've found so far is that there is a Colission.
Colission:
function getColission(a, b) {
return (a.x <= b.x+b.sizeX && a.x+a.sizeX >= b.x) &&
(a.y <= b.y+b.sizeY && a.y+a.sizeY >= b.y) &&
(a.z <= b.z+b.sizeX && a.z+a.sizeZ >= b.z);
}
Currently I am working on a 2D particle simulator. I have each particle moving on a unique angle. I found a basic formula to change x and y velocity, but I currently have a set velocity that moves according to the angle.
particles[a][3] += particles[a][1] * cos(radians(particles[a][5]));//move X
particles[a][4] += particles[a][1] * sin(radians(particles[a][5]));//move Y
I have a basic collision for collisions on walls, but can't find the best way to sort the collisions out. Currently I just multiply the rotation by -1, but that only works on the top and bottom. Note: The particle will always move after running the collision (its not getting stuck in the collision boxes and bugging out).
if(particles[a][3] < 0 || particles[a][3] > windowWidth/2 || particles[a][4] < 0 || particles[a][4] > windowHeight/2) {
/*windowWidth and windowHeight are divided by 2 to find the canvas size. In the setup() I have the canvas set to that value).*/
particles[a][5] *= -1;
}
Array values:
particles[a][1] = speed
particles[a][3] = x position
particles[a][4] = y position
particles[a][5] = rotation
My question is what is the best way to run these collision tests. I understand that collisions bounce at 90 degrees, but I'd like to use as few if statements as possible (simpler the better) instead of a tedious bunch.
Merry Christmas, and thanks in advance!
Figured it out!
Final code:
if(particles[a][4] < 0 || particles[a][4] > windowHeight/2) {
particles[a][5] *= -1;
} else if(particles[a][3] < 0 || particles[a][3] > windowWidth/2) {
particles[a][5] = 180 - particles[a][5];
}
Try googling "javascript reflect angle" and you'll find formulas for reflecting around both the X and Y axis. You do one when you collide with the top or bottom, and you do the other when you collide with the left or right.
Also, you probably shouldn't be using an array to hold your data. Create a class that holds your values, and then create instances of that class. Using magic array indexes is a recipe for headaches.
If you still can't get it working, then please post an MCVE and we'll go from there. Good luck.
I have a fiddle with the following code. ColorWalk clone
Here is the js code:
function floodFill(x, y, selectedColor, grayColor) {
if (x < 0 || x >= 600) return;
if (y < 0 || y >= 400) return;
let square = $('.blockattribute').filter(function(ind, el) {
return $(el).css('left') == x + 'px' && $(el).css('top') == y + 'px'
});
let squareColor = square.css('background-color');
if (squareColor === grayColor || squareColor === selectedColor) {
square.removeClass().addClass('blockattribute gray');
floodFill(x + 20, y, selectedColor, grayColor);
floodFill(x, y + 20, selectedColor, grayColor);
floodFill(x - 20, y, selectedColor, grayColor);
floodFill(x, y - 20, selectedColor, grayColor);
}
else {
return;
}
}
I've been working on learning javascript/jquery and algorithms and I've pretty much have this clone working except for the fact that when I get deeper and deeper into the grid, the slower and slower the code is. I've been reading about memoization and trying to use it on the grid but I'm getting stuck as to how to approach. All I'm really looking for is a little push regarding how to do this. Maybe memoization isn't the way to go and maybe I can optimize my code some other way. My current thinking is that I need to grab the last gray square and then proceed from there. Am I on the right track?
----Edit------
I realized that I can combine the if/else operator to check for matching gray color or selected color
Reading from and writing to the DOM are very expensive in Javascript. You also should never use the DOM as the source of your data.
To speed up your algorithm, store the pixel data offline as regular Javascript data, manipulate the data only, then update the visual code only once. This way you minimize the number of DOM operations.
Additionally, Javascript is not "tail call optimized," meaning you can't recurse forever, and every level of recursion will slow down the program to some degree. If you can use a non-recursive flood fill algorithm in this case, it will likely be faster.
I needed to show some simple code example for friend, for example moving a button along the edge of the screen clockwise. Sure this is something very simple, no, this is simplest. But I found myself spending about almost 30 minutes on that. I was embarased, because I am professional programmer for 20+ years, and I even needed to start the program many times before the button was flying the right ways. And I was thinking, why? So I speculated that this kind of code is difficult to get right immediately, because it is very old style, each case is typed separately, each check must be entered manually, you need to go through each iteration and make carefully sure that all numbers and checks are exactly precisely correct, and this is hard to do because of the nature of code style, which is, eehh, spaghetti, messy?
So I was like, is there a way to convert it to "modern" way, like use loop instead of cases, use templates or other meta-programming, use functional approach or at least use arrays. And it seems I cannot find any good way for this.
var mx = screen.width - b.w, my = screen.height - b.h
setInterval(function() {
var step = 3
if (state == 1) {
b.x += step
if (b.x >= mx) b.x = mx, state++
} else if (state == 2) {
b.y += step
if (b.y >= my) b.y = my, state++
} else if (state == 3) {
b.x -= step
if (b.x <= 0) b.x = 0, state++
} else if (state == 4) {
b.y -= step
if (b.y <= 0) b.y = 0, state = 1
}
b.apply()
}, 1)
This is JavaScript, in C it would be even more difficult to get right fast, because you need to think about types.
Here is what I come up myself... This maybe demonstrating what I am trying to achieve. I am not talking about choosing different algorithm. but rather abotu exploring language(s) features, and programming techniques.
var D = 3, name = ['x','y'], delta = [D,D,-D,-D],
limit = [screen.width - b.w, screen.height - b.h,0,0]
setInterval(function() {
b[name[0]] += delta[0]
if (delta[0] > 0 && b[name[0]] > limit[0] || b[name[0]] <= 0)
b[name[0]] = limit[0],
[name,delta,limit].some(function(x){ x.push(x.shift()) })
b.apply()
},1)
This one at least separates data from code, making it simpler to get it right. It worked for me from the first attempt. But I am still not satisfied completely)
The average American newspaper article is written at something like a 6th grade reading level. This isn't because the person writing it never went beyond 6th grade; rather, they've learned that it's better to write in a manner that everyone can understand. I bring this up because you're calling your code childish or unsophisticated, yet it's the most clear and concise code there is for the task you had, and therefore the best.
If you want to go around a square, you're really not going to have any choice besides what you did - have four different directions to go, and keep track of where you're at. You code shows off the basics of a state machine, because that's what you need to go around in four different straight lines.
If you're willing to fake it with a slightly different movement, you can remove all states and just go around in an ellipse using some trigonometry. (It actually should be a circle, but since the screen is rectangular, you'll get an ellipse, with different speeds on the long and short sides of the screen.)
Here's the basics. It may need some tweaking to make sure you have the edges hitting the right spot. Truthfully, I think by the time you work out the special cases on this version, you'll find your solution was more elegant.
// find the center x and y
var centerX = screen.width / 2;
var centerY = screen.height / 2;
// first, find the radius. If you want to cover everything, you need half the diagonal
var radius = Math.sqrt(centerX * centerX + centerY * centerY);
var increment = 0.01; // higher values, of course, will move you faster
var theta = 0;
setInterval(function() {
b.x = Math.min(Math.max(centerX + radius * Math.cos(x), screen.width), 0);
b.y = Math.min(Math.max(centerY + radius * Math.sin(y), screen.height), 0);
theta -= increment;
b.apply();
}, 1);
As I mentioned, this will almost certainly need some tweaking to come anywhere as close to looking good as the code you made. My code may be less childish, but it's less easy to understand - and it actually does less well at accomplishing your task.
Don't worry about how fancy your code was. It works well, and is clear to understand, and that's really what matters.
Edit
I realized later on that I forgot to base everything from the center, and the code I had posted would do a circle from the top left. I've added in the center stuff above. See? Adding complexity doesn't at all imply the code will be better... :-)
Also, I did figure out one change I would recommend to your original algorithm: name your states! Make them strings, and have state be "top", "right", "bottom" and "left", and actively set them rather than using state++. That will help make your code even more readable.
I have an array of objects that are all 'rectangles'. I also have a circle that is the object. The equation I use for gravity is:
newYPos = oldYPos + prevFallingSpeed + gravity
Basically, I am adding the rate of gravity to the number of pixels the circle 'fell' in the previous frame and then adding that to the position of the circle in the last frame.
I am detecting if any part of the ball is inside of any of the objects using this code:
for(var i = 0; i < objects.length; i++){
if(ball.x > objects[i].x - ball.r && ball.y > objects[i].y - ball.r && ball.x < ball.r + objects[i].x + objects[i].w && ball.y < ball.r + objects[i].y + objects[i].h){
alert('test');
gSy = (-1 * gSy);
}
}
The code checks if the circle's coordinates plus or minus the radius is greater than the top/left positions of the walls of the box and less than the right/bottom positions of the walls of the box.
The ball is inside the object at one point, but I never get an alert. I've tried everything I can think of. Hopefully I'm just making some dumb mistake I can't see...
Here is a jsfiddle if you are up for messing with my code or don't understand the variables:
http://jsfiddle.net/JGKx5/
The small problem:
You have four objects.
Two of them (numbers 1 and 3) are tall and thin, and off to the left or right. The ball never goes near them.
One of them (number 2) is short and wide, and at y-coordinates smaller than the ball ever attains.
The other one (number 0) is short and wide, and its y-coordinates are ones that a real physical ball would pass through -- but because your ball moves in discrete steps your script never actually sees it do so. (It goes from y=580.4 to y=601.2.)
The big problem:
In the jsfiddle, all your comparisons in the collision test appear to be exactly the wrong way around :-). (Which is odd since the ones in the code here are the right way around.)
With both of these changed (I made the ball move by 0.1*gSy instead of by gSy, and flipped all the comparison operators), collisions are detected.