Trying to develop an Agar clone, and I've got a lot of it, but I can't quite figure out how to decrement the player's speed as its mass increases. I've tried several different ways, but nothing works. How would I make the speed go down as the mass goes up? Here's my jsFiddle. This is where I set the speed of of the players:
var playerOneMass = 36;
var player1X = (canvas.width / 2) + 50;
var player = new Player({
x: player1X,
y: canvas.height / 2,
radius: playerOneMass,
speed: {
x: 5,
y: 5
},
name: "player 1",
dir: null
});
var playerTwoMass = 36;
var player2X = (canvas.width / 2) - 50;
var player2 = new Player({
x: player2X,
y: canvas.height / 2,
radius: playerTwoMass,
speed: {
x: 5,
y: 5
},
name: "player 2",
dir: null
});
Let us bring some math in to help us out a little bit. When you want something to grow smaller as another grows bigger, the best option that I have found is to use an inversely proportional relationship. This will allow a smooth smaller and smaller look for you.
new_speed = scalar * start_speed / current_mass
When coming up with the scalar, I have found it best to trial and error until it looks how you want it to.
Here is an example of the equation in action utilizing Two.js.
var two = new Two({width:320, height:180}).appendTo(document.getElementById("mytwo")),
rect = two.makeRectangle(100, 100, 10, 10),
circ = two.makeCircle(5, 100, 5),
mass = 10,
rspeed = Math.PI / 10,
mspeed = 14,
scalar = 10;
// Make it look pretty!
rect.fill = "rgb(100,255,100)";
circ.fill = "rgb(100,100,255)";
// Looping...
two.bind('update', function(fc) {
// Prevents from growing indefinitely
if(mass > 150) return;
mass += 1.5;
rect.scale += .1;
circ.scale += .1;
rect.rotation += scalar * rspeed / mass;
circ.translation.addSelf(new Two.Vector(
scalar * mspeed / mass, 0));
}).play();
<script type="text/javascript" src="http://cdn.jsdelivr.net/gh/jonobr1/two.js/build/two.min.js"></script>
<div id="mytwo"><div></div></div>
Related
Using the sample code from Konvajs.org as a base (https://konvajs.org/docs/sandbox/Multi-touch_Scale_Stage.html), I have added a large SVG to a layer (4096 x 3444) to experiment with zoom / pan of a vector-based map, base64 encoded SVG in this instance. Initial impressions are good however during testing I experience an odd bug where during a pinch the view of the map would snap to a different location on the map not the area that I centred on.
Here is the code (map base64 code removed due to length):
// by default Konva prevent some events when node is dragging
// it improve the performance and work well for 95% of cases
// we need to enable all events on Konva, even when we are dragging a node
// so it triggers touchmove correctly
Konva.hitOnDragEnabled = true;
var width = window.innerWidth;
var height = window.innerHeight;
var stage = new Konva.Stage({
container: 'container',
width: width,
height: height,
draggable: true,
});
var layer = new Konva.Layer();
var triangle = new Konva.RegularPolygon({
x: 190,
y: stage.height() / 2,
sides: 3,
radius: 80,
fill: 'green',
stroke: 'black',
strokeWidth: 4,
});
var circle = new Konva.Circle({
x: 380,
y: stage.height() / 2,
radius: 70,
fill: 'red',
stroke: 'black',
strokeWidth: 4,
});
let bg = new Konva.Image({
width: 4096,
height: 3444
});
layer.add(bg);
var image = new Image();
image.onload = function() {
bg.image(image);
layer.draw();
};
image.src = 'data:image/svg+xml;base64,...';
function getDistance(p1, p2) {
return Math.sqrt(Math.pow(p2.x - p1.x, 2) + Math.pow(p2.y - p1.y, 2));
}
function getCenter(p1, p2) {
return {
x: (p1.x + p2.x) / 2,
y: (p1.y + p2.y) / 2,
};
}
var lastCenter = null;
var lastDist = 0;
stage.on('touchmove', function (e) {
e.evt.preventDefault();
var touch1 = e.evt.touches[0];
var touch2 = e.evt.touches[1];
if (touch1 && touch2) {
// if the stage was under Konva's drag&drop
// we need to stop it, and implement our own pan logic with two pointers
if (stage.isDragging()) {
stage.stopDrag();
}
var p1 = {
x: touch1.clientX,
y: touch1.clientY,
};
var p2 = {
x: touch2.clientX,
y: touch2.clientY,
};
if (!lastCenter) {
lastCenter = getCenter(p1, p2);
return;
}
var newCenter = getCenter(p1, p2);
var dist = getDistance(p1, p2);
if (!lastDist) {
lastDist = dist;
}
// local coordinates of center point
var pointTo = {
x: (newCenter.x - stage.x()) / stage.scaleX(),
y: (newCenter.y - stage.y()) / stage.scaleX(),
};
var scale = stage.scaleX() * (dist / lastDist);
stage.scaleX(scale);
stage.scaleY(scale);
// calculate new position of the stage
var dx = newCenter.x - lastCenter.x;
var dy = newCenter.y - lastCenter.y;
var newPos = {
x: newCenter.x - pointTo.x * scale + dx,
y: newCenter.y - pointTo.y * scale + dy,
};
stage.position(newPos);
lastDist = dist;
lastCenter = newCenter;
}
});
stage.on('touchend', function () {
lastDist = 0;
lastCenter = null;
});
layer.add(triangle);
layer.add(circle);
stage.add(layer);
I am unsure if this is due to the large size of the image and / or canvas or an inherent flaw in the example code from Konvas.js. This has been tested, with the same results, on 2 models of iPad Pro, iPhone X & 11, Android Pixel 3, 5 and 6 Pro.
Here is the code on codepen as an example: https://codepen.io/mr-jose/pen/WNXgbdG
Any help would be appreciated, thanks!
I faced the same issue and discovered that it was caused by the dragging functionality of the stage. Everytime if (stage.isDragging()) evaluated to true, the jump happened.
For me what worked was setting draggable to false while pinch zooming and back to true on touch end.
stage.on('touchmove', function (e) {
...
if (touch1 && touch2) {
stage.draggable(false);
....
}
});
stage.on('touchend', function (e) {
...
stage.draggable(true);
});
I am current running into a bit of a math conundrum that has stumped me for days.
I am building a JavaScript game and attempting to create boundary coordinates to manage the pathing and movement of sprites, however it appears that lag/jitter/delay is reeking havoc on different entities moving in coordination with one another.
I believe I must calculate the jitter/lag/offset and somehow apply it to the coordinate range detection and movement functions but I have yet to crack the code correctly and alleviate the mis-aligning sprites.
Here is a replication of the issue in a CodeSandbox and the bulk of the code that shows it in action:
https://codesandbox.io/s/movetime-boundries-issue-example-2prow?file=/src/App.js
var obj = { x: 10, speed: 250 };
var obj2 = { x: 100 };
var objHighestX = { max: 0 };
var direction = 0;
var canvas = document.getElementById("mainScene");
var ctx = canvas && canvas.getContext("2d");
ctx.imageSmoothingEnabled = false;
ctx.font = "15px Courier";
var render = function () {};
var update = function (modifier) {
// console.log("Updating");
ctx.clearRect(0, 0, canvas.clientWidth, canvas.clientHeight);
ctx.fillRect(obj2.x, 60, 15, 15);
if (obj.x > objHighestX.max) {
objHighestX.max = obj.x;
}
ctx.fillText(String("X" + obj.x), 25, 100);
ctx.fillText(String("Furthest" + objHighestX.max), 125, 100);
if (obj.x >= obj2.x - 15) {
direction = 1;
} else if (obj.x <= 0) {
direction = 0;
}
if (direction === 0) {
obj.x += obj.speed * modifier;
ctx.clearRect(obj.x - 7, 9, 17, 17);
ctx.fillRect(obj.x, 60, 15, 15);
}
if (direction === 1) {
obj.x -= obj.speed * modifier;
ctx.clearRect(obj.x, 9, 17, 17);
ctx.fillRect(obj.x, 60, 15, 15);
}
};
var lastUpdate = Date.now();
// The main game loop
var main = function () {
var now = Date.now();
var delta = now - lastUpdate;
lastUpdate = now;
update(delta / 1000);
render();
requestAnimationFrame(main);
};
main();
If anyone has any suggestions or questions towards my case, I'm very eager to hear of it.
Perhaps I have to use the rate of change to create an offset for the boundaries?
Which I've tried like:
if (obj.x >= obj2.x - (15 * 1 * modifier))
But am still not yet getting this one down. Thank you all, greatly, in advance.
First, you're delta time calculations aren't complete.
var now = Date.now();
var delta = now - lastUpdate;
lastUpdate = now;
update(delta / 1000);
If you now request update() to be invoked via requestAnimationFrame, the number passed as a parameter will be the number of miliseconds passed between the last and the current frame. So if the screen refresh rate is 60hz it's roughly 16.6ms.
This value alone though isn't meaningful - you need to compare it against a target value.
Say we want to achieve a framerate of 30fps - equal to ~33.3ms. If we take this value and divide it from the 16.6ms above, we get roughly 0.5. This makes complete sense. We want 30fps, the monitor refreshes at 60hz, so everything should move at half the speed.
Let's modify your main() function to reflect that:
var main = function() {
var targetFrameRate = 30;
var frameTime = 1000 / targetFrameRate;
var now = Date.now();
var delta = now - lastUpdate;
lastUpdate = now;
update(delta / frameTime);
render();
requestAnimationFrame(main);
};
Second problem is the update() function itself.
Let's have a look at the following block:
if (direction === 0) {
obj.x += obj.speed * modifier;
ctx.clearRect(obj.x - 7, 9, 17, 17);
ctx.fillRect(obj.x, 60, 15, 15);
}
That means, wherever obj currently is, move it to the right by some amount. We are missing the boundary check at this point. You need to check if it would leave the bounds if we would move it to the right. In case it does, just move it next to the bounds.
Something like this:
var maxX=100;
if (direction === 0) {
var speed = obj.speed * modifier;
if (obj.x + obj.width + speed > maxX) {
direction = 1;
obj.x = maxX - obj.width;
} else {
obj.x += speed;
}
}
Maintain correct speed during collision frame
I notice that the object is always moving, which means the given answer does not correctly solve the problem.
An object should not slow down between frames if it has a constant speed
The illustration shows an object moving
At top how far it would move without interruption.
At center the point of collision. Note that there is still a lot of distance needed to cover to maintain the same speed.
At bottom the object is moved left the remaining distance such the total distance traveled matches the speed.
To maintain speed the total distance traveled between frames must remain the same. Positioning the object at the point of collision reduces the distance traveled and thus the speed of the object during the collision frame can be greatly reduced
The correct calculation is as follows
const directions = {
LEFT: 0,
RIGHT: 1,
};
const rightWallX = 100;
const leftWallX = 0;
if (obj.direction === directions.RIGHT) {
obj.x = obj.x + obj.speed;
const remainDist = (rightWallX - obj.width) - obj.x;
if (remainDist <= 0) {
obj.direction = directions.LEFT;
obj.x = (rightWallX - obj.width) + remainDist;
}
} else if (obj.direction === directions.LEFT) {
obj.x = obj.x - obj.speed;
const remainDist = leftWallX - obj.x;
if (remainDist >= 0) {
obj.direction = directions.RIGHT;
obj.x = leftWallX + remainDist;
}
}
Im working of a program that has a circle moving around inside another bigger circle.
var offX;
function setup() {
createCanvas(400, 400);
offX = 0.00;
}
function draw() {
background(220);
var bigBoy = {
x: 200,
y: 200,
r: 150,
};
var smallBoy = {
x: noise(offX) * 400,
y: map(sin(offX),-1,1,10,380),
r: 10,
};
offX += 0.005;
ellipse(bigBoy.x,bigBoy.y,bigBoy.r * 2);
ellipse(smallBoy.x,smallBoy.y,smallBoy.r * 2);
var d = dist(bigBoy.x,bigBoy.y,smallBoy.x,smallBoy.y);
text(round(d,0),30,20);
//-------------------------------//
if(d > bigBoy.r - smallBoy.r){
//move away from / dont cross over bigBoy's diameter//
} else{
//crack on mate//
}
}
could anyone advise me how I would keep the smaller circle within the bigger circles diameter. I would need it to look natural, like the small circle has a force preventing it from leaving the bigger one?
Thanks in advance!
P
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>
I have t his effect on this website
http://www.immersive-garden.com/
there's this point of light sparking, on hover you get the background, I want something similar without using flash
this is the script I'm using right now
/*
Particle Emitter JavaScript Library
Version 0.3
by Erik Friend
Creates a circular particle emitter of specified radius centered and offset at specified screen location. Particles appear outside of emitter and travel outward at specified velocity while fading until disappearing in specified decay time. Particle size is specified in pixels. Particles reduce in size toward 1px as they decay. A custom image(s) may be used to represent particles. Multiple images will be cycled randomly to create a mix of particle types.
example:
var emitter = new particle_emitter({
image: ['resources/particle.white.gif', 'resources/particle.black.gif'],
center: ['50%', '50%'], offset: [0, 0], radius: 0,
size: 6, velocity: 40, decay: 1000, rate: 10
}).start();
*/
particle_emitter = function (opts) {
// DEFAULT VALUES
var defaults = {
center: ['50%', '50%'], // center of emitter (x / y coordinates)
offset: [0, 0], // offset emitter relative to center
radius: 0, // radius of emitter circle
image: 'particle.gif', // image or array of images to use as particles
size: 1, // particle diameter in pixels
velocity: 10, // particle speed in pixels per second
decay: 500, // evaporation rate in milliseconds
rate: 10 // emission rate in particles per second
};
// PASSED PARAMETER VALUES
var _options = $.extend({}, defaults, opts);
// CONSTRUCTOR
var _timer, _margin, _distance, _interval, _is_chrome = false;
(function () {
// Detect Google Chrome to avoid alpha transparency clipping bug when adjusting opacity
if (navigator.userAgent.indexOf('Chrome') >= 0) _is_chrome = true;
// Convert particle size into emitter surface margin (particles appear outside of emitter)
_margin = _options.size / 2;
// Convert emission velocity into distance traveled
_distance = _options.velocity * (_options.decay / 1000);
// Convert emission rate into callback interval
_interval = 1000 / _options.rate;
})();
// PRIVATE METHODS
var _sparkle = function () {
// Pick a random angle and convert to radians
var rads = (Math.random() * 360) * (Math.PI / 180);
// Starting coordinates
var sx = parseInt((Math.cos(rads) * (_options.radius + _margin)) + _options.offset[0] - _margin);
var sy = parseInt((Math.sin(rads) * (_options.radius + _margin)) + _options.offset[1] - _margin);
// Ending Coordinates
var ex = parseInt((Math.cos(rads) * (_options.radius + _distance + _margin + 0.5)) + _options.offset[0] - 0.5);
var ey = parseInt((Math.sin(rads) * (_options.radius + _distance + _margin + 0.5)) + _options.offset[1] - 0.5);
// Pick from available particle images
var image;
if (typeof(_options.image) == 'object') image = _options.image[Math.floor(Math.random() * _options.image.length)];
else image = _options.image;
// Attach sparkle to page, then animate movement and evaporation
var s = $('<img>')
.attr('src', image)
.css({
zIndex: 10,
position: 'absolute',
width: _options.size + 'px',
height: _options.size + 'px',
left: _options.center[0],
top: _options.center[1],
marginLeft: sx + 'px',
marginTop: sy + 'px'
})
.appendTo('body')
.animate({
width: '1px',
height: '1px',
marginLeft: ex + 'px',
marginTop: ey + 'px',
opacity: _is_chrome ? 1 : 0
}, _options.decay, 'linear', function () { $(this).remove(); });
// Spawn another sparkle
_timer = setTimeout(function () { _sparkle(); }, _interval);
};
// PUBLIC INTERFACE
// This is what gets returned by "new particle_emitter();"
// Everything above this point behaves as private thanks to closure
return {
start:function () {
clearTimeout(_timer);
_timer = setTimeout(function () { _sparkle(); }, 0);
return(this);
},
stop:function () {
clearTimeout(_timer);
return(this);
},
centerTo:function (x, y) {
_options.center[0] = x;
_options.center[1] = y;
},
offsetTo:function (x, y) {
if ((typeof(x) == 'number') && (typeof(y) == 'number')) {
_options.center[0] = x;
_options.center[1] = y;
}
}
}
};
you probably need something like this: http://www.realcombiz.com/2012/09/customize-blackquote-with-light-bulb.html