I don't know a lot about JS, but i have to do assignments with it. right now i have a ball that bounces from one side of the screen to the other. with every bounce the colour of the screen and the ball change. but i'd like a slight increase of speed with every bounce as well(or a random speed every time it bounces if that's easier). this is the code I have for moving, the bouncing and the colour changing now:
fill(r,g,b);
ellipse(circleX, circleY, circleSize, circleSize);
circleX += moveX;
if (circleX > width - circleSize / 2 || circleX < circleSize / 2) {
moveX = -moveX;
r = random(255);
g = random(255);
b = random(255);
}
moveX is always 5 now and changes to -5 when turning back. but i'd like it if it turned into -6 and then +7 when going forward again. or something like that at least.
I thank you guys in advance for helping me and please explain it like you're explaining it to a child.
First, lets make a function which takes a number and returns +1 for non-negative numbers (positive or 0) and -1 for negative numbers, i.e. it's sign
function sign(x) {
if (x < 0) return -1;
return 1;
}
A full implementation of sign would have a special case for 0, and is available natively in ES6
Next, when it becomes time to change moveX separate it's magnitude (absolute value) and sign, increment it's magnitude and put the two pieces back together again before flipping the sign over
moveX = -sign(moveX) * (Math.abs(moveX) + 1);
You'll want to add another test inside your collision detection code to increase the speed. If the velocity is positive, then you want to add 1. If the velocity is negative, you want to subtract 1. Your code would look something like this...
...
moveX = -moveX
if (moveX < 0) {
--moveX;
} else {
++moveX;
}
...
Keep track of how many times the circle has "bounced" and add it to the speed.
var base_speed = 5;
var bounces = 0;
var direction = 1; //positive for moving right, negative for moving left
var moveX = base_speed + bounces * direction;
circleX += moveX;
if (circleX > width - circleSize / 2 || circleX < circleSize / 2) {
direction = -direction;
bounces++;
r = random(255);
g = random(255);
b = random(255);
}
Related
I'm currently working on a game which is based on a svg canvas as shown
and what I'm trying to do now is to allow the ball to move at random once the game starts, but I'm having difficulties coding out the random movement.
function createBall() {
const svg = document.getElementById("canvas")!,
ball = new Elem(svg, 'circle') #create the ball
.attr("cx",300).attr("cy",300)
.attr("r",8)
.attr('fill','grey');
Observable.interval(10).takeUntil(Observable.interval(4000)) #10 milliseconds until 4000 milliseconds
.subscribe( () => ball.attr("cx", 2 + Number(ball.attr("cx")))); #I'm having issue here when i subscribe as i can only allow the ball to move to the right at the moment, aside from being random
}
I think you would need a constant velocity towards a certain direction in x and y coordinates.
My suggestion would be to create two random integer values for x_velocity and y_velocity. You could try to use Math.random() and Math.floor():
function getRandomInt(min, max) {
return Math.floor((Math.random() + min) * Math.floor(max));
}
Then you will need to determine the direction, if it is negative (go left) or positive (go right):
function getDirection() {
return this.getRandomInt(0, 2) === 0? -1 : 1;
}
Use these two functions to set your x_velocity and y_velocity. The ball should now be able to go to the left, right, up, or down:
directionX = this.getDirection();
directionY = this.getDirection();
x_velocity = directionX * this.getRandomInt(1,8); // the number will be between -8 and 8 excluding 0
y_velocity = directionY * this.getRandomInt(1,8); // same here
Observable.interval(10).takeUntil(Observable.interval(4000))
.subscribe( () => {
ball.attr("cx", x_velocity + Number(ball.attr("cx"))); // the ball should go towards the left or the right
ball.attr("cy", y_velocity + Number(ball.attr("cy"))); // the ball should go up or down
);
Happy Coding! :)
Using three.js, I'm creating a game with cars that move in a specific direction, depending on their y-rotation. An example would be 90 degrees. I use object.translateZ() to move them forward but I've run into a problem.
I'm using physijs to simulate the cars. Cars that run into each other may change their y-rotation (because of the crash) and I want to find a way for the cars to slowly change their rotation back to the original rotation like they are turning to get back on the road. Without this my city is very chaotic.
Here's the code that I'm already using (this is just part of it):
var targetRotation = 90
var rotation = car.mesh.rotation.y * 180 / Math.PI //to convert to degrees
I want to find a way to slowly change the car's rotation so it's the same as the target rotation.
Any help is appreciated! (but some sort of function would be perfect)
I've done stuff like this before in other systems (2D, not Three.js), and essentially all you want to do is gradually increment the angle until you reach something close enough to the target angle. Usually this means the float is less than the turning speed you're incrementing by (so you don't "overshoot" the value).
The amount of the increment depends on how quickly you want them to turn.
You also want to check if it's better to increase the angle or decrease (do you turn clockwise or counterclockwise) depending on if you're closer to 360 or 0. This prevents the car from turning the "long way" around. You can find this out by seeing if the difference is greater/less than 180.
We can use the modulus operator to get the "real" angle between -360/360.
var currentAngle = car.mesh.rotation.y * 180 / Math.PI; //car's angle in degrees
var targetAngle = 90; //preferred angle *this time* ;)
var turningSpeed = 1; //one degree per update (wayyy to high for real stuff, usually)
currentAngle = currentAngle % 360; //get the 0-360 remainder
if ( Math.abs(targetAngle - currentAngle) >= turningSpeed) {
var addto = 0
if (targetAngle - currentAngle < 0) {
addto = 360
}
if ( targetAngle - currentAngle + addto <= 180 ) {
currentAngle += turningSpeed;
}
else {
currentAngle -= turningSpeed;
}
}
else { currentAngle = targetAngle; } //we're close enough to just set it
car.mesh.rotation.y = ( currentAngle * Math.PI ) / 180; // back to radians!
this is my first question after having relied on this site for years!
Anyway, I'd like to accomplish something similar to this effect:
http://www.flashmonkey.co.uk/html5/wave-physics/
But on a circular path, instead of a horizon. Essentially, a floating circle/blob in the center of the screen that would react to mouse interaction. What I'm not looking for is gravity, or for the circle to bounce around the screen - only surface ripples.
If at all possible I'd like to apply a static texture to the shape, is this a possibility? I'm completely new to Canvas!
I've already tried replacing some code from the above example with circular code from the following link, to very limited success:
http://www.html5canvastutorials.com/tutorials/html5-canvas-circles/
If only it were that easy :)
Any ideas?
Thanks in advance!
I tried to figure out how wave simulation works using View Source and JavaScript console. It's working fine but threw some JS errors. Also, it seems physics update is entangled with rendering in the render() method.
Here is what I found about the code:
The mouseMove() method creates disturbances on the wave based on mouse position, creating a peak around the mouse. The target variable is the index of the particle that needs to be updated, it's calculated from mouse pos.
if (particle && mouseY > particle.y) {
var speed = mouseY - storeY;
particles[target - 2].vy = speed / 6;
particles[target - 1].vy = speed / 5;
particles[target].vy = speed / 3;
particles[target + 1].vy = speed / 5;
particles[target + 2].vy = speed / 6;
storeY = mouseY;
}
Then, the particles around target are updated. The problem I found is that it does no bounds checking, i.e. it can potentially particles[-1] when target == 0. If that happens, an exception is thrown, the method call ends, but the code does not stop.
The render() method first updates the particle positions, then renders the wave.
Here is its physics code:
for (var u = particles.length - 1; u >= 0; --u) {
var fExtensionY = 0;
var fForceY = 0;
if (u > 0) {
fExtensionY = particles[u - 1].y - particles[u].y - springs[u - 1].iLengthY;
fForceY += -fK * fExtensionY;
}
if (u < particles.length - 1) {
fExtensionY = particles[u].y - particles[u + 1].y - springs[u].iLengthY;
fForceY += fK * fExtensionY;
}
fExtensionY = particles[u].y - particles[u].origY;
fForceY += fK / 15 * fExtensionY;
particles[u].ay = -fForceY / particles[u].mass;
particles[u].vy += particles[u].ay;
particles[u].ypos += particles[u].vy;
particles[u].vy /= 1.04;
}
Basically, it's Hooke's Law for a chain of particles linked by springs between them. For each particle u, it adds the attraction to the previous and next particles (the if statements check if they are available), to the variable fForceY. I don't fully understand the purpose of the springs array.
In the last four lines, it calculates the acceleration (force / mass), updates the velocity (add acceleration), then position (add velocity), and finally, reduce velocity by 1.04 (friction).
After the physics update, the code renders the wave:
context.clearRect(0, 0, stageWidth, stageHeight);
context.fillStyle = color;
context.beginPath();
for (u = 0; u < particles.length; u++) {
...
}
...
context.closePath();
context.fill();
I'm not explaining that, you need to read a canvas tutorial to understand it.
Here are some ideas to get started, note that I didn't test these code.
To modify the code to draw a circular wave, we need introduce a polar coordinate system, where the particle's x-position is the angle in the circle and y-position the distance from center. We should use theta and r here but it requires a large amount of refactoring. We will talk about transforming later.
mouseMove(): Compute particle index from mouse position on screen to polar coordinates, and make sure the disturbance wrap around:
Define the function (outside mouseMove(), we need this again later)
function wrapAround(i, a) { return (i + a.length) % a.length; }
Then change
particles[target - 2] --> particles[wrapAround(target - 2, particles)]
particles[target - 1] --> particles[wrapAround(target - 1, particles)]
...
The modulo operator does the job but I added particles.length so I don't modulo a negative number.
render(): Make sure the force calculation wrap around, so we need to wrapAround function again. We can strip away the two if statements:
fExtensionY = particles[wrapAround(u - 1, particles)].y - particles[u].y - springs[wrapAround(u - 1, springs)].iLengthY;
fForceY += -fK * fExtensionY;
fExtensionY = particles[u].y - particles[wrapAround(u + 1, particles)].y - springs[warpAround(u, springs)].iLengthY;
fForceY += fK * fExtensionY;
Here is the result so far in jsfiddle: Notice the wave propagate from the other side. http://jsfiddle.net/DM68M/
After that's done, the hardest part is rendering them on a circle. To do that, we need coordinate transform functions that treat particle's (x, y) as (angle in the circle, distance from center), and we also need inverse transforms for mouse interaction in mouseMove().
function particleCoordsToScreenCoords(particleX, particleY) {
return [ radiusFactor * particleY * Math.cos(particleX / angleFactor),
radiusFactor * particleY * Math.sin(particleX / angleFactor) ];
}
function screenCoordsToParticleCoords(screenX, screenY) {
// something involving Math.atan2 and Math.sqrt
}
Where the ...Factor variables needed to be determined separately. The angleFactor is two pi over the highest x-position found among particles array
Then, in the coordinates supplied to the context.lineTo, context.arc, use the particleCoordsToScreenCoords to transform the coordinates.
I'm working on a top down shooter, and basically the character starts in the middle of the screen, inside a rect (Safe Zone). The character isn't static, the scene is. He can walk around, inside the safe zone. As soon as the character walks out of this zone, the statics switch over ... the character is static, and the scene is moving around him.
The only problem with this is that I can't walk back into the safe zone, allowing my statics to switch over again.
So I'm forever stuck outside the zone. All I'm doing is checking to see whether my character position is 'within' a certain value (which is the rect), if he's out - then my KeyControls then affect the Map, not the character.
So this is my boundary (Safe Zone) checker:
//Walking Window Boundaries
var boundarySizeX = 400;
var boundarySizeY = 200;
ctxWalkBoundary.fillStyle = "grey";
ctxWalkBoundary.fillRect(gameWidth/2 - boundarySizeX/2, gameHeight/2 - boundarySizeY/2, boundarySizeX, boundarySizeY);
ctxWalkBoundary.clearRect((gameWidth/2 - boundarySizeX/2) + 2, (gameHeight/2 - boundarySizeY/2) + 2, (boundarySizeX) - 4, (boundarySizeY) -4 );
var paddingLeft = (gameWidth - boundarySizeX) / 2;
var paddingRight = gameWidth - ((gameWidth - boundarySizeX) / 2) - this.charWidth;
var paddingTop = (gameHeight - boundarySizeY) / 2;
var paddingBottom = gameHeight - ((gameHeight - boundarySizeY) / 2) - this.charHeight;
var paddingY = (gameHeight - boundarySizeY) / 2;
if(this.drawX > paddingLeft && this.drawX < paddingRight && this.drawY > paddingTop && this.drawY < paddingBottom){
inBoundary = true;
}
else{
inBoundary = false;
console.debug("Out Of Boundary!");
}
And this is my KeyChecker:
//UP
if(this.isUpKey){
//Character movement
if(inBoundary){
this.drawX = this.drawX + this.speed * Math.cos((this.characterRotation));
this.drawY = this.drawY + this.speed * Math.sin((this.characterRotation));
}
else{
mapPositionX = mapPositionX - this.speed * Math.cos((this.characterRotation));
mapPositionY = mapPositionY - this.speed * Math.sin((this.characterRotation));
}
My character always faces my mouse (rotates). So every time the user pressed W, or Up - the character will always walk towards the mouse position.
Any ideas how I can get back into the zone?
----- Update -----
I guess I need to somehow check if I'm still facing outside the safe zone - if not, then reverse he statics.
Just separate two things: map and view.
Map is your level, you keep there objects with coordinates.
View is part of map you see on screen.
View has 4 properties: x, y, widht and height, where widht and height most likely is your canvas size.
If your game start with view on map point (0,0) in the middle of screen, then your view (x,y) coordinates should be (-view.width/2, -view.height/2).
How to draw your character and objects in a view?
In first place, draw only thing that are in the view rectangle.
So loop over all objects and check if
object.x >= view.x && object.x <= view.x + view.width && object.y >= view.y && object.y <= view.y + view.height
(you probably should take into account objects boundaries too).
If object is in view area then draw it at position (object.x - view.x, object.y - view.y).
And that's all about drawing things.
Moving character and view area with him.
Now when your character collides with boundary, in example (colliding with right border)
character.x >= view.x + view.width
then move view to the right by incrementing view.x with some value (that might be character.width/2).
-- UPDATE --
I see that you are not using OOP in your game (actually you are because everything in JS is an object, but you are not using it on purpose).
OOP in JS is a lot of explaining, so I'll try to make it short.
You can make objects like your Character, Map and View using JSON format.
character = {
x: 0,
y: 0,
xspeed: 0,
yspeed: 0,
speed: 0,
radius: 20,
}
map = {
objects: [
{sprite: 'tree.jpg', x: 100, y: 50},
{sprite: 'stone.jpg', x: 20, y: 30},
],
}
view = {
width: canvas.width,
height: canvas.height,
x: -this.width/2,
y: -this.height/2,
}
These are objects that you can use like in your functions like that:
for (var i=0; i++, i<map.objects.length) {
if (map_obj.x >= view.x && map_obj.x <= view.x + view.width && map_obj.y >= view.y && map_obj.y <= view.y + view.height) {
var map_obj = map.objects[i];
draw_sprite(map_obj.sprite, map_obj.x - view.x, map_obj.y - view.y);
}
}
It's not the best way, but it's still much better than yours right now. When you understand what OOP is about you will make it better for your own.
The problem here is that you're waiting for the character to go out of bounds, then moving the map instead. But the flag has already been tripped, and now the character movement is static no matter what direction you go in, because you're already out of bounds.
You could instead detect when a character is going to cross the boundary and prevent it by moving the map instead:
//UP
if(this.isUpKey){
// save the x and y offset to prevent needless recalculation
var xOffset = this.speed * Math.cos(this.characterRotation),
yOffset = this.speed * Math.sin(this.characterRotation);
//Character movement
if( boundaryCheck(xOffset, yOffset) ){
this.drawX = this.drawX + xOffset;
this.drawY = this.drawY + yOffset;
}
else{
mapPositionX = mapPositionX - xOffset
mapPositionY = mapPositionY - yOffset;
}
then boundaryCheck takes the x and y delta's and figures out if they're still in bounds. If the character will still be in bounds, return true and the character will move, otherwise the map will move.
function boundaryCheck(xOffset, yOffset){
// variables set and other stuff done...
if(this.drawX + xOffset > paddingLeft && this.drawX + xOffset < paddingRight && this.drawY + yOffset > paddingTop && this.drawY + yOffset < paddingBottom){
return true;
}
else{
console.debug("Out Of Boundary!");
return false;
}
};
This way you don't have to figure out whether an out of bounds character is moving toward the boundary or not. Instead, you pre-determine where the character is going, and adjust accordingly, always keeping him in boundaries.
Without full code this isn't testable, of course, but I think it should work with what you've given.
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/