Move a player n units closer to point X - javascript

I have a player, which looks like this:
{
x: [could be any integer],
y: [could be any integer],
facing: {
x: [could be any integer],
y: [could be any integer]
}
}
Assuming the player is at (player.x, player.y), and the player is facing in the direction of the mouse, which is at (player.facing.x, player.facing.y), what is a formula that I could use to move the player n units in the direction of the mouse?
Here is what I've tried so far, but it always results in null:
var facingDistance = Math.sqrt(Math.pow(game.players[i].facing.x, 2) - Math.pow(game.players[i].x, 2));
game.players[i].x += (game.players[i].speed/facingDistance) *
(game.players[i].x - game.players[i].facing.x);
game.players[i].y += (game.players[i].speed/facingDistance) *
(game.players[i].y - game.players[i].facing.y);

// prefetch player object for cleaner code
var plr = game.players[i];
// normalized player direction
var facingDX = plr.facing.x - plr.x;
var facingDY = plr.facing.y - plr.y;
var facingLen = Math.sqrt(facingDX * facingDX + facingDY * facingDY);
facingDX /= facingLen;
facingDY /= facingLen;
// add n times this to position + round to integer coordinates
plr.x = Math.round(plr.x + facingDX * n);
plr.y = Math.round(plr.y + facingDY * n);

Related

Getting X and Y coordinates from tile ID

I'm stumped on what is probably some pretty simple math. I need to get the X and Y coordinates from each tiles referenced ID. The grid below shows the order the ids are generated in. Each tile has a width and height of 32. Number ones x & y would be equal to (0,0). This is for a game I'm starting to make with canvas using a tileset.
1|2|3
4|5|6
7|8|9
So far for X, I've come up with...
(n % 3) * 32 - 32 // 3 is the width of the source image divded by 32
And for Y...
(n / 3) * 32
This is obviously wrong, but It's the closest I've come, and I don't think I'm too far off from the actual formula.
Here is my actual code so far:
function startGame() {
const canvas = document.getElementById("rpg");
const ctx = canvas.getContext("2d");
const tileSet = new Image();
tileSet.src = "dungeon_tiles.png";
let map = {
cols: 10,
rows: 10,
tsize: 32,
getTileX: function(counter, tiles) {
return ((tiles[counter] - 1) % 64) * 32;
},
getTileY: function(counter, tiles) {
return ((tiles[counter] - 1) / 64) * 32;
}
};
let counter = 0;
tileSet.onload = function() {
for (let c = 0; c < map.cols; c++) {
for (let r = 0; r < map.rows; r++) {
let x = map.getTileX(counter, mapObj.layers[0].data); // mapObj.layers[0].data is the array of values
let y = map.getTileY(counter, mapObj.layers[0].data);
counter += 1;
ctx.drawImage(
tileSet, // image
x, // source x
y, // source y
map.tsize, // source width
map.tsize, // source height
r * map.tsize, // target x
c * map.tsize, // target y
map.tsize, // target width
map.tsize // target height
);
}
}
};
}
If 1 is (0,0) and each tile is 32*32, then finding your horizontal position is a simple 32*(t-1) where t is your tile number. t-1 because your tiles start from 1 instead of 0. Now, you have 3 tiles per row so you want to reset every 3, so the final formula for your x is 32*((t-1)%3).
For the vertical position it's almost the same, but you want to increase your position by 32 only once every 3 tiles, so this is your y: 32*floor((t-1)/3).
floor((t-1)/3) is simply integer division since the numbers are always positive.
If I understand this correctly, you want to get the 1|2|3 values based on x, y correct? You can do something like this:
((y * total # of rows) + x) + 1
This would convert the 2D x, y index to a single index which is, as you stated, 1|2|3. This formula is based on your example where count starts at 1 and not 0. If you want to convert it to 0 base, just remove the + 1.
If you have the width and height, or probably location of input/character, you can have a GetX(int posX) and GetY(int posY) to get the x and y based on the position. Once you have converted the position to x, y values, use the formula above.
int GetX(int posX)
{
return (posX / 32);
}
int GetY(int posY)
{
return (posY / 32);
}
int GetIndex(int posX, int posY)
{
return ((GetY(posY) / totalRows) + GetX(posX)) + 1;
}

Calculate move cost based on speed and distance

I am working on canvas mini game and i want to build a function that calculates cost of moving your ship from point A to point B.
I need 2 things:
total cost before ship is dispatched
cost for every tick of move (server loop tick)
Cost is charged every time ship is moved (every time server loop ticks) so total must match sum of all ticks that server made to get it there.
I have simple server loop that moves ship:
setInterval(function() {
ship.move();
}, 10);
now the simplified ship code:
var rad = (p1, p2) => Math.atan2(p2.y - p1.y, p2.x - p1.x),
distance = (p1, p2) => Math.sqrt( (p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y) );
var ship = function() {
this.x; // current ship x
this.y; // current ship y
this.destination; // destination object
this.total_distance; // total distance before dispatch
this.remaining_distance; // remaining distance before arrival
this.speed = 0.5; // ship speed modifier
this.set_travel = function(target) {
this.destination = target;
this.total_distance = distance( { x: this.x, y: this.y }, { x: this.destination.x, y: this.destination.y } );
};
this.move = function() {
this.remaining_distance = distance( { x: this.x, y: this.y }, { x: this.destination.x, y: this.destination.y } );
var _rad = rad( { x: this.x, y: this.y }, { x: this.destination.x, y: this.destination.y } );
this.x += Math.cos(rad) * this.speed;
this.y += Math.sin(rad) * this.speed;
};
};
Now we could introduce fuel cost and add to above code like this:
var ship = function() {
...
this.total_fuel_cost; // total fuel cost that player will consume during entire travel
this.set_travel = function(target) {
...
this.total_fuel_cost = ?
};
this.move = function() {
...
player.fuel -= ? // fuel cost every tick that must match total after arrival
};
};
Maybe someone could help solve this problem. Maybe it could be good approach to assume that every 1 distance made cost x fuel, but i dont know if it can be done like this.
----- edit
when ship is created it is instantiated in this way:
objects.push(new ship())
as i explained in my question, its not acceptable to refuse flying if total is not enough, ship must go as long as it has fuel
I assembled a little demo using settings that has been provided:
move() loop going on 10 ms interval
fuel being consumed on the fly
fuel consumed throughout journey must be equal assumed consumption at the beginning
Logic explanation:
The only variable that is really needed you already have in your logic, it is ship speed.
Your code would look like this:
this.move = function() {
this.remaining_distance = distance( { x: this.x, y: this.y }, { x: this.destination.x, y: this.destination.y } );
var _rad = rad( { x: this.x, y: this.y }, { x: this.destination.x, y: this.destination.y } );
this.x += Math.cos(rad) * this.speed;
this.y += Math.sin(rad) * this.speed;
player.fuel -= this.speed;
};
Lets say that player has 1000 fuel and you need to fly distance of 845. If we assume that 1 distance === 1 fuel, we expect that at the end of journey you should have 155 fuel left. Additionally it doesn't matter if you fly fast (say 2) or slow (say 0.5), fuel consumption should be the same, as you consume more fuel while flying faster. Above code will do exactly that.
Demo link:
https://jsfiddle.net/7khvxkaa/1/
Fuel cost can be tempered with to deal with smaller numbers for example if assumed that 1 distance === 0.01 fuel you will end up consuming 10 fuel throughout 1000 distance journey. To account above situation this is the only change that needs to be made:
player.fuel -= this.speed / 100;
Also remember that demo is only for debugging purposes to verify proof of concept, in real environment where you have more variables (for example moving destination or ship acceleration / deceleration) it may be difficult to predict total fuel consume, however logic will still work as expected.
I think you mostly need an explanation about OOP.
Your function ship is not an object; it's (the constructor of) a class.
(Well, that's what other languages would call it.)
To make an object, you do this:
var myship = new ship();
Here is an example; a bit similar your game. But my main point is for you to look at how you can use an object. As you can see, the property myship.fuel keeps track of the fuel; it will refuse to move if a trip requires more fuel than it has.
Calculations you can handle yourself. Just look at "what properties do I have?" "What do I need?", ...
<script>
// constructor
function Ship(elementId) {
// properties
this.elm = document.getElementById(elementId);
this.x = 0; // current ship x
this.y = 0; // current ship y
this.fuel = 300;
this.fuelprice = 0.2; // moving 1 pixel costs 0.2 fuel
this.destination = {x:0, y:0}; // destination object
// static function, doesn't interact with any property, just takes parameters ans returns something
this.distance = function(p1, p2) {
return Math.sqrt( (p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y) ); // Pythagoras
}
this.rad = function(p1, p2) {
return Math.atan2(p2.y - p1.y, p2.x - p1.x);
}
// method. this is a function bound to an object. Whomever calls this function will be affected.
// in this case myship will be moved, but there could be many boats in the game; many buttons that each move 1 boat, ...
this.moveTo = function(to) {
var from = {x: this.x, y: this.y};
var totalDistance = this.distance(from, to);
// see if there is enougn fuel
var fuelNeeded = this.fuelprice * totalDistance;
if(this.fuel >= fuelNeeded) {
display(
'<h3>This trip</h3>'+
'total distance: ' + totalDistance + '<br/>'+
'fuel at start: ' + this.fuel +'<br/>'+
'fuel needed: ' + fuelNeeded +'<br/>'
);
this.moveStep(to, 10, 10);
//
this.fuel -= fuelNeeded;
}
else {
display(
'<h3>Not enough fuel</h3>'+
'fuel at start: ' + this.fuel +'<br/>'+
'fuel needed: ' + fuelNeeded +'<br/>'
);
}
}
// function that calls itself, until stepsLeft = 0
this.moveStep = function(to, steps, stepsLeft) {
var self = this; // within a setTimeout the "this" changes its meaning. So I make a copy.
var x = to.x + (this.x - to.x) * (stepsLeft / steps);
var y = to.y + (this.y - to.y) * (stepsLeft / steps);
if(stepsLeft > 0) {
this.elm.style.left = x;
this.elm.style.top = y;
setTimeout(function() { self.moveStep(to, steps, stepsLeft - 1) }, 100);
}
else {
// animation is finished, so the "to" situation becomes the new x and y
this.x = to.x;
this.y = to.y;
}
}
}
// function that uses the myship object
function submitMove() {
myship.moveTo({
x: Number(document.getElementById('x').value),
y: Number(document.getElementById('y').value)
});
}
// just to display messages to screen
function display(message) {
document.getElementById('display').innerHTML = message;
}
// now this is our object: myship
var myship;
// when the page is loaded we can make myship a Ship object
window.onload = function() {
myship = new Ship('boat');
}
</script>
<style>
#sea {
position: relative;
background: #2040f0;
height: 500px;
width: 500px;
}
#boat {
position: absolute;
}
</style>
<div id="sea">
<img id="boat" src="http://icons.veryicon.com/32/Leisure/Summer%20Holiday/sailing%20boat.png" />
</div>
<hr/>
<input id="x" placeholder="X" value="200">
<input id="y" placeholder="X" value="40">
<input type="button" value="GO" onclick="submitMove()">
<div id="display"></display>

find position of a point with origin, angle and radius

im stuck with a trigonometry problem in a javascript game im trying to make.
with a origin point(xa,ya) a radius and destination point (ya,yb) I need to find the position of a new point.
//calculate a angle in degree
function angle(xa, ya, xb, yb)
{
var a= Math.atan2(yb - ya, xb - xa);
a*= 180 / Math.PI;
return a;
}
function FindNewPointPosition()
{
//radius origine(xa,xb) destination(ya,yb)
var radius=30;
var a = angle(xa, xb, ya, yb);
newpoint.x = xa + radius * Math.cos(a);
newpoint.y = ya + radius * Math.sin(a);
return newpoint;
}
Imagine a image because I dont have enough reputation to post one :
blue square is the map (5000x5000), black square (500x500) what players see (hud).
Cross(400,400) is the origin and sun(4200,4200) the destination.
The red dot (?,?) indicate to player which direction take to find the sun ..
But sun and cross position can be reverse or in different corner or anywhere !
At the moment the red dot do not do that at all ..
Tks for your help.
Why did you use ATAN2? Change to Math.atan() - you will get angle in var A
Where you have to place your red dot? inside hud?
Corrected code
https://jsfiddle.net/ka9xr07j/embedded/result/
var obj = FindNewPointPosition(400,4200,400,4200); - new position 417. 425
Finally I find a solution without using angle.
function newpointposition(origin, destination)
{
// radius distance between cross and red dot
var r=30;
// calculate a vector
var xDistance = destination.x - origin.x;
var yDistance = destination.y - origin.y;
// normalize vector
var length = Math.sqrt(xDistance * xDistance + yDistance * yDistance);
xDistance /= length;
yDistance /= length;
// add the radius
xDistance = xDistance * r;
yDistance = yDistance * r;
var newpoint = { x: 0, y: 0 };
newpoint.x = origin.x + xDistance;
newpoint.y = origin.y + yDistance;
return newpoint;
}
var radar = newpointposition({
x: 500,
y: 800
}, {
x: 3600,
y: 2850
});
alert(radar.x + ' ' + radar.y);
ty Trike, using jsfiddle really help me.

Canvas jitters half my rendering

I was working on a fun project that implicates creating "imperfect" circles by drawing them with lines and animate their points to generate a pleasing effect.
The points should alternate between moving away and closer to the center of the circle, to illustrate:
I think I was able to accomplish that, the problem is when I try to render it in a canvas half the render jitters like crazy, you can see it in this demo.
You can see how it renders for me in this video. If you pay close attention the bottom right half of the render runs smoothly while the top left just..doesn't.
This is how I create the points:
for (var i = 0; i < q; i++) {
var a = toRad(aDiv * i);
var e = rand(this.e, 1);
var x = Math.cos(a) * (this.r * e) + this.x;
var y = Math.sin(a) * (this.r * e) + this.y;
this.points.push({
x: x,
y: y,
initX: x,
initY: y,
reverseX: false,
reverseY: false,
finalX: x + 5 * Math.cos(a),
finalY: y + 5 * Math.sin(a)
});
}
Each point in the imperfect circle is calculated using an angle and a random distance that it's not particularly relevant (it relies on a few parameters).
I think it's starts to mess up when I assign the final values (finalX,finalY), the animation is supposed to alternate between those and their initial values, but only half of the render accomplishes it.
Is the math wrong? Is the code wrong? Or is it just that my computer can't handle the rendering?
I can't figure it out, thanks in advance!
Is the math wrong? Is the code wrong? Or is it just that my computer can't handle the rendering?
I Think that your animation function has not care about the elapsed time. Simply the animation occurs very fast. The number of requestAnimationFrame callbacks is usually 60 times per second, So Happens just what is expected to happen.
I made some fixes in this fiddle. This animate function take care about timestamp. Also I made a gradient in the animation to alternate between their final and initial positions smoothly.
ImperfectCircle.prototype.animate = function (timestamp) {
var factor = 4;
var stepTime = 400;
for (var i = 0, l = this.points.length; i < l; i++) {
var point = this.points[i];
var direction = Math.floor(timestamp/stepTime)%2;
var stepProgress = timestamp % stepTime * 100 / stepTime;
stepProgress = (direction == 0 ? stepProgress: 100 -stepProgress);
point.x = point.initX + (Math.cos(point.angle) * stepProgress/100 * factor);
point.y = point.initY + (Math.sin(point.angle) * stepProgress/100 * factor);
}
}
Step by Step:
based on comments
// 1. Calculates the steps as int: Math.floor(timestamp/stepTime)
// 2. Modulo to know if even step or odd step: %2
var direction = Math.floor(timestamp/stepTime)%2;
// 1. Calculates the step progress: timestamp % stepTime
// 2. Convert it to a percentage: * 100 / stepTime
var stepProgress = timestamp % stepTime * 100 / stepTime;
// if odd invert the percentage.
stepProgress = (direction == 0 ? stepProgress: 100 -stepProgress);
// recompute position based on step percentage
// factor is for fine adjustment.
point.x = point.initX + (Math.cos(point.angle) * stepProgress/100 * factor);
point.y = point.initY + (Math.sin(point.angle) * stepProgress/100 * factor);

How to detect if a user has drawn a circle on a touch device using canvas and javascript?

I am creating a Tangram puzzle game using Javascript. And I need to detect when a user has drawn a circle (or circle like shape) with their finger. I have been able to gather hundreds (if not thousands) of x and y points with:
var touchX = event.targetTouches[0].pageX - canvas.offsetLeft;
var touchY = event.targetTouches[0].pageY - canvas.offsetTop;
I then push each x and y coordinate into an array:
touchMoveX.push(touchX);
touchMoveY.push(touchY);
I then loop through each array and create two points:
for(var i = 0; i < touchMoveX.length; i++)
{
for(var l=0; l < touchMoveY.length; l++)
{
var xPosition = touchMoveX[i];
var yPosition = touchMoveY[l];
var v1x = touchMoveX[i];
var v2x = touchMoveX[i + 1];
var v1y = touchMoveY[l];
var v2y = touchMoveY[l + 1];
Then using those two points, I use the following formula to figure out the angle between these two points in degrees:
var v1 = {x: v1x, y: v1y}, v2 = {x: v2x, y: v2y},
angleRad = Math.acos( (v1.x * v2.x + v1.y * v2.y) /
(Math.sqrt(v1.x*v1.x + v1.y*v1.y) * Math.sqrt(v2.x*v2.x + v2.y*v2.y) ) ),
angleDeg = angleRad * 180 / Math.PI;
I then sum up all of the angles and see if they are around 360 degrees.
But the above code I have described isn't working very well. Does someone out there have a better way to do this? Thank you very much.
yeah compute the average of all points (giving you a cheaply approximated center) then check if more than a certain percent of points are within a certain threshold. You can tune those values to adjust the precision until it feels right.
edit: Didn't consider that the circle could have multiple sizes, but you could just add another step computing the average of all distances. Adjusted the example for that.
var totalAmount = touchMoveX.length;
// sum up all coordinates and divide them by total length
// the average is a cheap approximation of the center.
var averageX = touchMoveX.reduce( function ( previous, current) {
return previous + current;
} ) / totalAmount ;
var averageY = touchMoveY.reduce( function ( previous, current) {
return previous + current;
} ) / totalAmount ;
// compute distance to approximated center from each point
var distances = touchMoveX.map ( function ( x, index ) {
var y = touchMoveY[index];
return Math.sqrt( Math.pow(x - averageX, 2) + Math.pow(y - averageY, 2) );
} );
// average of those distance is
var averageDistance = distances.reduce ( function ( previous, current ) {
return previous + current;
} ) / distances.length;
var min = averageDistance * 0.8;
var max = averageDistance * 1.2;
// filter out the ones not inside the min and max boundaries
var inRange = distances.filter ( function ( d ) {
return d > min && d < max;
} ).length;
var minPercentInRange = 80;
var percentInRange = inRange.length / totalAmount * 100;
// by the % of points within those boundaries we can guess if it's circle
if( percentInRange > minPercentInRange ) {
//it's probably a circle
}

Categories

Resources