Detecting phone shakes - javascript

I am developing shake detecting on Android and I can not deal with one issue - rotating the phone. My algorithm detects shakes properly, but it reacts to rotates also.
It looks like this:
//for every second
if(!alarmed) {
if(Math.abs(oldX - acceleration.x) > threshold ||
Math.abs(oldY - acceleration.y) > threshold ||
Math.abs(oldZ - acceleration.z) > threshold) {
// shake detected
}
}
oldX = acceleration.x;
oldY = acceleration.y;
oldZ = acceleration.z;
It's JavaScript, because I write with Cordova.
Any help would be appreciated.

After few hours, I came up with solution:
Instead of comparing all three acceleration dimensions with threshold, we should compare sum of all three with (modified) threshold. It prevents reacting to rotations.

Related

Improving collision detection performance in HTML5/Javascript

I'm currently creating a game that involves coins that come up from the bottom of the screen in a random X position. If the hero overlaps/collides with the coins, the user gets a point.
My issue is, when I put my collision detection in a fast interval function, it seems that the collision is not registering at some instances.
I've replicated the game in the jsfiddle below (originally it uses the phone's accelerometer to move the hero but for this example I've quickly made it a left/right key based control) -
http://jsfiddle.net/wpavxn6k/1/
Snippet of the interval below -
//keep checking to see if collision has occured
window.setInterval(function () {
if (hitTest(app.hero, app.coinClassUnique) == true) {
app.coinClassUnique.css('display', 'none');
app.score++;
$("h2").html(app.score);
}
}, 5);
//measure the width/height and position of the coin div and the hero image to determine if they are overlapping
function hitTest(a, b) {
var aPos = a.offset();
var bPos = b.offset();
var aLeft = aPos.left;
var aRight = aPos.left + a.width();
var aTop = aPos.top;
var aBottom = aPos.top + a.height();
var bLeft = bPos.left;
var bRight = bPos.left + b.width();
var bTop = bPos.top;
var bBottom = bPos.top + b.height();
return !(bLeft > aRight || bRight < aLeft || bTop > aBottom || bBottom < aTop);
}
My question is whether you can see an obvious flaw in my code that may be affecting performance, or if there are any tips of how I can improve performance and collision detection in a real-time based game like this.
I just wanted to post the answer for this question incase someone encounters a similar issue. The interval of the game was happening at different times so I rebuilt the game inside a Canvas element with requestFrameAnimation. This way, all the elements reload at once.
I had some issues like images not loading properly etc. at first, which is why I avoided using canvas - but with the help of preloading and rendering the images into separate canvases that are hidden off screen - I was able to tackle these issues.

Smooth rotation issue with javascript

I have searched all over for a solution to my problem on smooth rotation. I can get it 99% working however there is one small issue that keeps messing with me. The rotations works fine except when the target makes a drastic change. The basic idea is I have a ball and a player when the player comes in contact with the ball he changes the balls direction and speed. The player follows the ball correctly however when he comes in contact with the ball or the ball's location is reset thus making the delta between the angles greater than 45 degrees the player instantly jumps to fact the ball. Here is the code that I have partly working. Thank you for any help in advance.
var newFacing = Math.atan2(theBall.y-player.y,theBall.x-player.x);
var diff = (Math.abs(newFacing) - Math.abs(player.facing));
if (diff < Math.PI*0.1 && diff > -Math.PI*0.1){
player.facing = newFacing;
}else if (diff > Math.PI) {
player.facing -= Math.PI*0.1;
} else {
player.facing += Math.PI*0.1;
}
if (player.facing > Math.PI) {
player.facing -= Math.PI*2;
} else if (player.facing < -Math.PI) {
player.facing += Math.PI*2;
}
Updated: Changed the || to && and added a condition to ensure I do not go above or below PI radians. There are still some odd rotational issues at some angles. For example if the ball passes below the player he will rotate clockwise to follow rather than the logical counter clockwise. At times the player will do a full 360 before tracking the ball again. Without tracing it I am not sure what conditions are causing this.

Attempting to get two simultaneous joysticks working with touch events

I've been battling with this for two days. I'm using an HTML5/JS game engine called ImpactJS and someone made a very useful plugin to create joystick touch zones for mobile devices. The idea is that you specify a zone on the screen where the joystick is activated when that area is touched.
The code for the plugin I am using is here. I have modified it slightly to add "curPos" (x and y coordinates of the spot that the user is currently touching), otherwise all code is identical. I have been trying to solve this problem myself as well as contacting the original creator, but they seem to be unreachable at this time and I'm getting nowhere.
I'm sure I'm doing something very wrong here, but while I can get the touch zones to work perfectly on their own, every time I try to use both joysticks at the same time they partially overwrite each other.
I have specified two zones as follows when my game initializes:
this.joystick1 = new TouchJoystickZone(0, 0, ig.system.width / 2, ig.system.height);
this.joystick2 = new TouchJoystickZone(ig.system.width / 2, 0, ig.system.width / 2, ig.system.height);
this.joystick1 is responsible for player rotation. this.joystick2 is responsible for player acceleration. In my Player entity I have the following movement code for the two joysticks. Again, this works perfectly when I only have one finger on the screen/one joystick in use:
if( ig.ua.mobile ) {
// ROTATION
if (ig.game.joystick1.touchStart.x > 0 && ig.game.joystick1.touchStart.x < ig.system.width/2) {
if (Math.abs(ig.game.joystick1.delta.x) >= 50 || Math.abs(ig.game.joystick1.delta.y) >= 50) {
this.joystickAngle = ig.game.Controller.toDegrees(ig.game.Controller.joystickAngle());
if (this.angle > this.joystickAngle + 20) {
this.angle -= this.turnSpeed * ig.system.tick;
}
else if (this.angle < this.joystickAngle - 20) {
this.angle += this.turnSpeed * ig.system.tick;
}
else {
this.angle = this.joystickAngle;
}
}
}
// THRUST
if (ig.game.joystick2.touchStart.x > ig.system.width / 2) {
if (ig.game.joystick2.delta.y <= -50) {
this.accel.x = Math.cos(this.angle*Math.PI/180)*this.thrust;
this.accel.y = (Math.sin(this.angle*Math.PI/180)*this.thrust);
this.fuel -= 0.1;
}
else if (ig.game.joystick2.delta.y >= 50) {
this.accel.x = Math.cos(this.angle*Math.PI/180)*-this.thrust;
this.accel.y = (Math.sin(this.angle*Math.PI/180)*-this.thrust);
this.fuel -= 0.1;
}
}
else {
this.accel.x = 0;
this.accel.y = 0;
}
}
As soon as I place a second finger on the screen, however, the first joystick becomes overwritten. I can rotate and then move or move and then rotate and it works fine, but I need to do both at the same time.
I found out that touchStart.x and touchStart.y seems to be being set for both joysticks when I tap to use the other stick and not just the relevant joystick1 or joystick2, even though in the plugin code those coordinates are only meant to be affected if the touch for that joystick is within the specified zone. I believe this is partly what is contributing to the issue. At this stage I've spent hours trying to figure this out and am just as lost as when I started.
Can someone possibly point me in the right direction with using both of these joysticks at the same time?
The joystick script you are using is only looking for the first finger. The following is from lines 47-48
var x = ev.touches[0].pageX - pos.left,
y = ev.touches[0].pageY - pos.top;
The '0' determines which finger to track.
The script would have the be changed to be aware which finger is on which element and then only track that finger. You could do that by either determining which element was pressed first or by location.
JSFiddle Example: http://jsfiddle.net/7WR88/5/
http://www.sitepen.com/blog/2008/07/10/touching-and-gesturing-on-the-iphone/
As mentioned by #Dcullen, there may be multiple touches in each event starting at the first touch.
It would be a simple solution to iterate through the ev.touches collection and see if each touch falls into a hotzone. If it falls under hot zone 1, treat it as a touch for joystick 1. If it falls under hotzone 2, treat it as a touch for joystick 2.
This would mean that it doesn't matter in which order the touches appear, because they will always map to the correct joystick if they are near to it.

Vectors, calculate movement forces with max speed

Im building a small space shooter game. I have how ever stubbed on a math problem when it come to the space physics.
Describing this with words is following:
There is a max speed.
So if you give full full speed you ship will move with this over the screen over and over again like in the old asteroids games.
If then release the rocket boost you ship should be keep moving with that speed over the screen.
Then the tricky part where Im stuck right now.
If you rotate the ship ANY angle and gives boost again the ship should try to get to this direction and NEVER surpas the max speed when it comes to how fast it is moving. so my question is. anyone have a good idea formula for this issue? feels like it has been done before if you know what to look for. :)
Ill add this small image to illustrate what is tried to be done with some vector calculations.
Red ring: Max speed
Green line: current ship direction.
Black line: direction(s) and how fast the ship is moveing in x and y.
Black ring: origin of movement.
Can illustrate it but hard to find a good math solution for this. :)
EDIT
This is the code Im using right now in every frame. It gives movement to the ship but does not give the force of movement the user has to counter-react with its rocket boosters to get the ship to stop or slow down. With this it stops the instant you release the accelerating speed for the ship.
//Calculates ship movement rules
var shipVelocityVec = GetVectorPosByAngle(shipMoveSpeed, shipRotationAngle);
var shipUnitVec =$V([Math.cos(shipRotationAngle),Math.sin(shipRotationAngle),0]);
var rawAccel = shipAccelSpeed / shipMass;
var scale = (shipUnitVec.dot(shipVelocityVec))/(shipTopSpeed * shipTopSpeed);
var v1 = shipUnitVec.subtract(shipVelocityVec.multiply(scale));
var finalAccelVec = v1.multiply(rawAccel);
console.log(finalAccelVec);
//move ship according to rules
var shipPosVector = $V([shipxPos, shipyPos, 0]);
var movementVector = shipPosVector.add(finalAccelVec);
shipxPos = movementVector.elements[0];
shipyPos = movementVector.elements[1];
To give the acceleration speed the user has to keep the button pressed. the instance the user releases the button the acceleration is set to zero and have to boost over again to give maximum acceleration throttle.
Solution found! Posted it here how it was done.
You seem to be confusing something - there is no issue capping the velocity to a maximum speed, even when the acceleration is at a different angle, if you are using vectors correctly.
Your setup should look something like this:
Your ship should have a position, a velocity, and an acceleration. Each of these can be represented as a 2D vector (with separate x and y components).
Every frame, add the velocity to the position, and the acceleration to the velocity.
Every frame, check that the speed does not exceed some maximum. If it does, cap the speed by normalizing the velocity vector and multiplying it by the max speed.
That's it! There are no special cases to consider - that's the magic of vector algebra!
#BlueRaja's solution should work, although you will get an abrupt change in behavior when you hit the max speed.
If you want a solution with no "seams", I believe you can do what you're looking for by adding the right kind of adjustment to the acceleration, as follows:
ship_unit_vec = [cos(ship_angle), sin(ship_angle)]
raw_accel = (engine_thrust / ship_mass)
scale = dot_product(ship_unit_vec, ship_velocity_vec) / max_speed^2
final_accel_vec = raw_accel * (ship_unit_vec - scale * ship_velocity_vec)
Notes:
If |ship_velocity_vec|<<max_speed, the scale * ship_velocity_vec component is negligable.
If |ship_velocity_vec|==max_speed, the scale * ship_velocity_vec component cancels all additional acceleration in the "wrong" direction, and aids acceleration in the "right" direction.
I've never tried this out, so I don't know how it will feel to the player...
More generally, if there are more sources of acceleration than just the ship thrusters, you can add them all together (say, as raw_accel_vec), and perform the above operation all at once:
scale_forall = dot_product(raw_accel_vec, ship_velocity_vec) / max_speed^2
final_accel_vec = raw_accel_vec - scale_forall * ship_velocity_vec
Rather than just imposing an ad hoc maximum speed, you could use some actual physics and impose a drag force. This would be an extra force acting on the spaceship, directed opposite to the velocity vector. For the magnitude of the drag force, it's simplest to just take it proportional to the velocity vector.
The overall effect is that the drag force increases as the spaceship moves faster, making it harder to accelerate in the direction of motion when the ship moves faster. It also makes acceleration easier when it is opposed to the direction of motion.
One point where this diverges from your description is that the spaceship won't continue at maximum speed forever, it will slow down. It won't, however, come to a halt, since the drag force drops as the ship slows down. That matches my memory of asteroids better than the ship continuing forever at constant velocity, but it has been quite a while since I've played.
I did it! Thank you for your help.
Finally found the solution. the problem was I was trying to modify the ships current movement when it comes to speed and then of this calculate the "drag" forces that would be the product of this movement when the user tried to go another direction. The solution was like #BlueRaja and #Comingstorm mentioned. All forces should be added together when it comes to the movement. This should be what then alter the ships position. Should not be added to the ships current movement. You might be able to effect a current movement to but then you have to do this differently. So I thought I share my solution for this how it looks.
This function is run each time the user accelerates the ship.
function CalcShipMovement() {
//Calculates ship movement rules
shipPosVector = $V([shipxPos, shipyPos, 0]);
var shipVelocityVec = GetVectorPosByAngle(shipAccelSpeed, shipRotationAngle);
var shipUnitVec = $V([Math.cos(shipRotationAngle), Math.sin(shipRotationAngle), 0]);
if(currentShipMoveVector != null && Get2DVectorLength(currentShipMoveVector) > 0) {
var nextMove = currentShipMoveVector.add(shipVelocityVec);
var nextSpeed = Get2DVectorLength(nextMove);
//check if topspeed of movement should be changed
if(nextSpeed > shipTopSpeed) {
var scale = nextSpeed / shipTopSpeed;
currentShipMoveVector = DevideVector(nextSpeed, scale);
} else {
currentShipMoveVector = currentShipMoveVector.add(shipVelocityVec);
}
}
if(currentShipMoveVector != null && Get2DVectorLength(currentShipMoveVector) == 0) {
currentShipMoveVector = currentShipMoveVector.add(shipVelocityVec);
}}
This code is run in every frame the graphics for the ship is generated to alter its position.
function SetShipMovement() {
if(currentShipMoveVector != null && Get2DVectorLength(currentShipMoveVector) > 0) {
shipMoveSpeed = Get2DVectorLength(currentShipMoveVector);
shipPosVector = shipPosVector.add(currentShipMoveVector);
shipxPos = shipPosVector.elements[0];
shipyPos = shipPosVector.elements[1];
//Makes the ship slow down if no acceleration is done for the ship
if(shipAccelSpeed == 0) {
currentShipMoveVector = currentShipMoveVector.subtract(DevideVector(currentShipMoveVector, 50));
}
} else {
currentShipMoveVector = $V([0, 0, 0]);
}}

Game programming: remove movement lag (jumping)

I'm developing an HTML5 3D fps-like engine that already looks quite nice, but as this might be one of the worst language choices to make 3D there's noticeable lag sometimes.
I programmed movements (WASD) to be independent of rendering speed, so sometimes it's quite jerky, but other times is working at an acceptable 30+ fps (depending on CPU of course).
The only thing I can't wrap my mind around is jumping: currently the jumping is done by adding a positive constant to the falling variable (gravity is always negative and then corrected by collision detection) and then subtracting a constant, this is called every time a new frame is rendered, the thing is that when fps go low I feel like I'm on the moon. I prefer jerkiness to slow-mo effect.
If I use the same method like I do for moving (calculate time between current and last frame) the deducted variable gets too big sometimes and the jumping apex changes (to half of the value compared to high fps) - this is unacceptable as jumping height must be always the same.
Here's some pseudo-code to help understanding the problem (called during one rendering routine):
// when clicked on spacebar:
if(spacebar)
{
// this defines jumping apex
jump = 0.5
}
// constant added to y (vertical position) later in the code
cy += jump;
// terminal velocity = -2
if(jump > -2)
{
// gravity (apex multiple to get maximum height)
jump -= 0.05;
}
if(collision_with_floor)
{
// stop falling
cy = 0;
if(jump < 0)
{
jump = 0;
}
}
player.position.y += cy;
Now with time dependent jumping (replace in the code above):
// terminal velocity = -2
if(jump > -2)
{
// gravity, 0.4 is an arbitrary constant
jump -= (now - last_frame)*0.4;
last_frame = now;
}
To illustrate even better here's an image of what's going on:
Blue dots indicate frame renders.
I'm not even sure of this is the right way to program jumping routine. Basically jerkiness and constant jumping height is better than smoothness and slow-mo effect.
If the frame updates are coming too slowly to get accurate physics, then maybe you can hack in the jump apex so that the player always hits it. The cue here might be when the y velocity changes from positive to negative. If I'm reading your pseudocode right, then it looks like:
old_cy = cy;
cy += jump;
if(old_cy > 0 && cy <= 0)
player.position.y = jump_apex_height;
In terms of your graph, the idea is that you want to identify the blue dot that reaches the orange line, then bump it up to the dotted line.
And now that I'm thinking about it, if the player really has to reach the jump apex every time, then this might help even for high-rate updates.

Categories