The only thing that I do inside the animation loop is update the x and y coordinates but the circle is still not moving as smoothly as it should. This is the fiddle. I am using CraftyJS to animate the circle. Here is the code that does the animation:
.bind("EnterFrame", function (eventData) {
this.x += this.xDirection;
this.y += this.yDirection;
if (this.x < 0) this.xDirection *= -1;
if (this.y < 0) this.yDirection *= -1;
if (this.x > (0.96*gWidth)) this.xDirection *= -1;
if (this.y > (0.96*gHeight)) this.yDirection *= -1;
});
Rest of the calculations are done just once and I don't think just a bunch of multiplications should make the animation lag. Any help on how to make the animation smooth will be appreciated.
I failed to mention earlier that xDirection is equal to 0.005*gWidthand yDirection is equal to 0.005*gHeight. If gWidth is 600 the ball is still moving just 3px. Is it really that fast? I don't want to specify the width in pixels (gWidth is the screen size) because then the gameplay will be different on different devices. Is there some way to move the circle quickly while still keeping the animation smooth?
Changing from 'fixed' to 'variable' steptype smoothed things out for me.
After Crafty.init, call Crafty.timer.steptype():
const _step = 20;
Crafty.init(gWidth, gHeight, document.getElementById('game'));
Crafty.timer.steptype('variable', _step);
// ...
You may also want to update your EnterFrame to take in to account time elapsed since the last frame:
.bind("EnterFrame", function (eventData) {
let dt = eventData.dt;
this.x += this.xDirection * dt / _step;
this.y += this.yDirection * dt / _step;
// ...
Related
Right so I'm a bit new to JS and I wanted to know how to put a roof or height limit within this small canvas game. It's practically W3's code but the teacher told us to just model after it. I wanted to fix the annoying issue of just jumping over the map to avoid obstacles.
I don't really know what to try since the height is set by canvas. I tried to make a new function based of hitBottom() which failed.
Just wanted to put the roof or height limit. Here's the original source: Here. Everything is literally the same except colors.
What you want to do is see if the current y-position is lower than 0, since that would be the 'roof' of the room. If the player y position is lower than 0, reset it back to 0, and stop the acceleration.
this.hitTop = function() {
if (this.y < 0) {
this.y = 0;
this.gravitySpeed = 0;
}
}
And to the newpos function, you want to call this function, so add this:
this.hitTop();
Check for y position in newPos method after increasing the y position. If it is less than 0 then make it 0. Code should look like below;
this.newPos = function() {
this.gravitySpeed += this.gravity;
this.x += this.speedX;
this.y += this.speedY + this.gravitySpeed;
/* Add below 4 lines */
if (this.y <= 0) {
this.y = 0;
this.gravitySpeed = 0;
}
/* Add above 4 lines */
this.hitBottom();
}
Happy coding ;)
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);
}
I'm experimenting with HTML5 canvas scripting in JavaScript and am having an issue with 2D collision detection. I'm basically checking the coordinates of the "player" against the coordinates of a box I've placed on screen but a strange result is occurring. I know why it's happening, but I don't know how to solve the problem.
Some of my code:
function Arc()
{
// Coordinates.
this.x = 540 / 2;
this.y = 0;
// Radius
this.r = 50;
// Gravity / velicoty.
this.g = 3;
this.vy = 15;
// Bounce.
this.b = -0;
this.speed = 20;
this.max_speed = 20;
this.friction = 0.03444;
}
Arc.prototype.collision = function()
{
for(var i = 0; i < game.sprites.length; i++)
{
if
(
// If the right side of the player is greater than the left side of the object.
this.x + this.r > game.sprites[i].x &&
// If the bottom of the player is greater than (meaning lower than) the top of the object.
this.y + this.r > game.sprites[i].y &&
// If the left side of the player is greater than the right side of the object.
this.x - this.r < game.sprites[i].x + game.sprites[i].w &&
// if the top of the player is greater than (meaning lower than) the bottom of the object.
this.y - this.r < game.sprites[i].y + game.sprites[i].h
)
{
this.y = game.sprites[i].y - this.r;
this.vy *= this.b;
}
}
}
The anomaly is that when I move the player sprite over the left or right of the box, it jumps upwards on the Y-axis because the logical check above is always true. Obviously this is unexpected because the sprite should only interact with the top of the box if a jump has occurred.
Note: I'm not looking for a solution that adds collision to the sides of the box only (that's very simple). Rather, I'm looking for the solution that allows for collision on all sides of the box (including the top) in the same way it currently works but without the anomaly where the sprite suddenly jumps on top of the box upon touching it.
I've reproduced my entire project on JSFiddle for the purposes of demonstration (keys a, d and space bar): http://jsfiddle.net/h5Fun/
Whether or not this is what you want, it solves the problem:
this.x = game.sprites[i].x + 150;
this.vx *= this.b;
The issue was you were setting the incorrect component upon collision. If you want the circle to stop when it hits the rectangle, not go on top of it, then use x, not y.
150 is the size of the rectangle. This means it will stop at the right side of the sprite. The bouncing is already there due to modifying the velocity (this.vx).
I'm building a game using the canvas element powered by JavaScript. Part of my player class includes an update() method which is called once per tick. In this method, I'm doing some math to update the players velocity based on keyboard input and also to move the player. Here's a chunk of that code:
// Gradually make the players velocity 0
if(this.xv > 0) {
this.xv -= 0.1;
} else if(this.xv < 0) {
this.xv += 0.1;
}
if(this.yv > 0) {
this.yv -= 0.1;
} else if(this.yv < 0) {
this.yv += 0.1;
}
// Update player position based on velocity
this.x += this.xv;
this.y += this.yv;
// Update velocity based on keyboard inputs
if(keyState[87]) {
this.yv -= 0.5;
}
if(keyState[65]) {
this.xv -= 0.5;
}
if(keyState[83]) {
this.yv += 0.5;
}
if(keyState[68]) {
this.xv += 0.5;
}
Now in theory this should all work okay, if the player holds down the W key for 4 ticks their velocity will be 2, and then after 40 more ticks their velocity will be reduced down to 0.
This doesn't work in practice though, as JavaScript doesn't seem to be entirely accurate when it comes to working with floating point numbers. If I console.log() the velocity variables each game tick I get this kind of output:
x: -1.0241807402167069e-14 y: -1.379452108096757e-14
x: 0.09999999999998976 y: 0.09999999999998621
x: -1.0241807402167069e-14 y: -1.379452108096757e-14
x: 0.09999999999998976 y: 0.09999999999998621
So there's two things that look wrong here, one is that JavaScript never calculates the velocity with good precision, and the other is when the velocity is negative it's always at least -1, which is a problem because the player sprite will now move at 1 pixel per tick.
How can I get more accurate calculations for this task?
I recommend using an "exponential decay" approach to smoothing out your velocity transitions. Instead of the conditional block you currently use to reduce the velocity to zero, I'd use the following:
this.xv *= 0.9;
this.yv *= 0.9;
Note that this caps your maximum velocity at ten times your constant acceleration, and that changing the rate of decay will change that multiplier. This might be okay, but if it's not, you can tweak the equations to ease into a target velocity:
var p = 0.9;
var q = 1.0 - p;
this.xv = this.xv * p + this.txv * q;
this.yv = this.yv * p + this.tyv * q;
Disclaimer: This has no real basis in Newtonian physics; it's just something I came up with to help smooth out state transitions in a robot. But it worked great for me, and hopefully will for you, too.
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.