Hi, All. I'm working on a game which requires an orbital crosshair. That is; a crosshair that moves in a circle around the player.

I am having two issues with this. One is a simple math issue which I really should be able to solve myself (however if you would like to help me out that'd be great). This problem is that as you rotate the crosshair around the player it gets farther away. In the beginning it is 20 units from the player and after just 1 rotation it is 24.

Here is the code:

if (ig.input.state('e')) {
var angle = thePlayer.angleTo(this);
x = Math.cos(angle);
y = Math.sin(angle);
this.pos.x = (this.pos.x) + (Math.sin(angle));
this.pos.y = (this.pos.y) - (Math.cos(angle));
console.log(this.distanceTo(thePlayer));
}

The second issue is less trivial and I'm not sure I can find a solution to it. This problem is that when moving around the screen, the crosshair seems to "lag" behind the position it is meant to be in until a few frames after you have stopped moving.

You can see an example of the problem here:

http://falconerd.com/barf/
I have tried a few things including moving the crosshair function into its' own js file (it was originally inside the player.js file)

##
10 years ago
by drhayes

I'm light on sleep so I'll have to stay away from the math problem. I'm pretty sure you have `Math.sin`

and `Math.cos`

swapped, though. You want to use cosine with X coordinates, generally. I also wonder if creeping floating point error is getting in your way and a `Math.floor()`

around the position calculation wouldn't smooth things out. But I'm sleepy, so maybe not. ( =

As for the second issue: are you determining the crosshair's position before calling `this.parent`

in your player? That would do exactly what you describe: the crosshair would be a frame behind your player's current position since position is updated in Entity::update.

To cure the crosshair's lag, I'd suggest putting

`this.pos.x = thePlayer.pos.x`

and

`this.pos.y = thePlayer.pos.y`

(plus your corrections) as the first lines in its update call.

Something like

update: function(){
this.parent();
this.pos.x = thePlayer.pos.x;
this.pos.y = thePlayer.pos.y;
//rest of the code

This will guarantee its always aligned with the player, but probably won't allow the circling movement.

In the demo, holding down E moves the player to the right, but that's about it, crosshair does nothing other than acompany me. It also generates no log messages, guess it's an older build?

Thanks for your replies and apologies for the live version earlier. The one that is up now does contain the code to rotate complete with the increasing radius. I did try the code you suggested Cavalier, but I can't get that to consistently work. Now to think of a way to make both work & in tandem...

##
10 years ago
by drhayes

You want it to be at a constant radius, right? Don't worry about the angle of the crosshair to the player, that lets me do things like rotate it, walk past it, then keep rotating it in the wrong direction.

Make the crosshair maintain its angle (between 0 and Math.PI*2) and every frame the player is rotating it change the angle. You can then calculate its position like this:

// assuming this.radius is crosshair's radius
// and this.angle is crosshair's angle
var cx = this.player.pos.x;
var cy = this.player.pos.y;
this.pos.x = Math.floor(cx + (Math.cos(this.angle) * this.radius));
this.post.y = Math.floor(cy + (Math.sin(this.angle) * this.radius));

That should do it.

Thanks to all of you I now have a working version up (same URL). With the code below it creates a follow effect which is quite cool and will be useful in the future. When I get home I will take a crack at keeping the position relative whilst moving.

URL again:

http://falconerd.com/barf
update: function() {
this.parent();
if (!ig.input.state('e') && !ig.input.state('q')) {
var angle = ig.game.getEntityByName('player').angleTo(this);
this.pos.x = Math.cos(angle) * 20 + ig.game.getEntityByName('player').pos.x;
this.pos.y = Math.sin(angle) * 20 + ig.game.getEntityByName('player').pos.y;
} else {
if (ig.input.state('e')) {
var angle = ig.game.getEntityByName('player').angleTo(this);
this.pos.x = Math.cos(angle + .1) * 20 + ig.game.getEntityByName('player').pos.x;
this.pos.y = Math.sin(angle + .1) * 20 + ig.game.getEntityByName('player').pos.y;
}
if (ig.input.state('q')) {
var angle = ig.game.getEntityByName('player').angleTo(this);
this.pos.x = Math.cos(angle - .1) * 20 + ig.game.getEntityByName('player').pos.x;
this.pos.y = Math.sin(angle - .1) * 20 + ig.game.getEntityByName('player').pos.y;
}
}
}

Hey all. I've run into another issue. When calculating the angleTo, the docs state that it calculates an angle based from the centre of each entity.

*What is the centre if the entity is an even number of pixels?*
In the

example you can see that the crosshair is all working fine now, except that it rotates around the .pos.x and .pos.y of the player which is the top left corner. Every attempt to change this point so far has failed.

Here is the crosshair code (Which solved some previous issues so I hope it helps someone):

EntityCrosshair = ig.Entity.extend({
size: {x:16, y:16},
collides: ig.Entity.COLLIDES.NONE,
gravityFactor: 0,
animSheet: new ig.AnimationSheet('media/player/crosshair.png', 6, 6),
init: function(x, y, settings) {
this.parent(x, y, settings);
theCrosshair = this;
this.addAnim('idle', 1, [0]);
this.currentAnim = this.anims.idle;
this.radius = 20;
this.turnspeed = .075;
},
update: function() {
this.pos.x = thePlayer.pos.x - prevcrosshairx;
this.pos.y = thePlayer.pos.y - prevcrosshairy;
if (ig.input.state('e')) {
var angle = thePlayer.angleTo(this);
this.pos.x = Math.cos(angle + this.turnspeed) * this.radius + thePlayer.pos.x;
this.pos.y = Math.sin(angle + this.turnspeed) * this.radius + thePlayer.pos.y;
prevcrosshairx = thePlayer.pos.x - this.pos.x;
prevcrosshairy = thePlayer.pos.y - this.pos.y;
}
if (ig.input.state('q')) {
var angle = thePlayer.angleTo(this);
this.pos.x = Math.cos(angle - this.turnspeed) * this.radius + thePlayer.pos.x;
this.pos.y = Math.sin(angle - this.turnspeed) * this.radius + thePlayer.pos.y;
prevcrosshairx = thePlayer.pos.x - this.pos.x;
prevcrosshairy = thePlayer.pos.y - this.pos.y;
}
this.parent();
}
});

You might notice that the crosshair is only 6px but has a size of 16*16. This is because any attempt to make the crosshair size a different size from the player entity causes it to fail and get stuck in rotation at a point.

Any guidance would be appreciated and I will post the answer I use in this thread either way.

Cheers.

14 hours and ~10 coffees later (I have been doing other stuff too!). Here is the many-a-time revised version with comments.

As promised:

EntityCrosshair = ig.Entity.extend({
size: {x:6, y:6},
collides: ig.Entity.COLLIDES.NONE,
gravityFactor: 0,
name: 'crosshair',
animSheet: new ig.AnimationSheet('media/player/crosshair.png', 6, 6),
init: function(x, y, settings) {
this.parent(x, y, settings);
theCrosshair = this;
this.addAnim('idle', 1, [0]);
this.currentAnim = this.anims.idle;
this.radius = 20;
this.turnspeed = .075;
this.arc = {a: 90, b: -90, c: 180, d: -180};
this.prev = {x: 0, y: 0};
},
update: function() {
this.parent();
// Facing right?
if (thePlayer.flip == false) {
// Set position while moving
this.pos.x = thePlayer.pos.x - this.prev.x;
this.pos.y = thePlayer.pos.y - this.prev.y;
if (ig.input.state('down')) {
// Get the angle
this.angle = Math.atan2((this.pos.y) - (thePlayer.pos.y + 5), (this.pos.x) - (thePlayer.pos.x + 5));
// If the crosshair tries to go past the 180 degree bounds, place it at the edge
if ((this.angle).toDeg() > this.arc.a) this.angle = this.arc.a.toRad();
// Move the crosshair in the right direction
this.pos.x = Math.cos(this.angle + this.turnspeed) * this.radius + (thePlayer.pos.x + 5);
this.pos.y = Math.sin(this.angle + this.turnspeed) * this.radius + (thePlayer.pos.y + 5);
}
if (ig.input.state('up')) {
// Get the angle
this.angle = Math.atan2((this.pos.y) - (thePlayer.pos.y + 5), (this.pos.x) - (thePlayer.pos.x + 5));
// If the crosshair tries to go past the 180 degree bounds, place it at the edge
if ((this.angle).toDeg() < this.arc.b) this.angle = this.arc.b.toRad();
// Move the crosshair in the right direction
this.pos.x = Math.cos(this.angle - this.turnspeed) * this.radius + (thePlayer.pos.x + 5);
this.pos.y = Math.sin(this.angle - this.turnspeed) * this.radius + (thePlayer.pos.y + 5);
}
// Set variables for moving
this.prev = {x: thePlayer.pos.x - this.pos.x, y: thePlayer.pos.y - this.pos.y};
} else { // Facing left
// Set position while moving
this.pos.x = thePlayer.pos.x + this.prev.x;
this.pos.y = thePlayer.pos.y - this.prev.y;
if (ig.input.state('down')) {
// Get the angle
this.angle = Math.atan2((this.pos.y) - (thePlayer.pos.y + 5), (this.pos.x) - (thePlayer.pos.x + 5));
// Because of the angle breaking at 90deg left, we have to do 2 checks to stop at down 90deg
if ((this.angle).toDeg() < this.arc.a) {
if ((this.angle).toDeg() > 0) {
this.angle = this.arc.a.toRad();
}
}
// Move the crosshair in the right direction
this.pos.x = Math.cos(this.angle - this.turnspeed) * this.radius + (thePlayer.pos.x + 5);
this.pos.y = Math.sin(this.angle - this.turnspeed) * this.radius + (thePlayer.pos.y + 5);
}
if (ig.input.state('up')) {
// Get the angle
this.angle = Math.atan2((this.pos.y) - (thePlayer.pos.y + 5), (this.pos.x) - (thePlayer.pos.x + 5));
// Because of the angle breaking at 90deg left, we have to do 2 checks to stop at up 90deg
if ((this.angle).toDeg() > this.arc.b) {
if ((this.angle).toDeg() < 0) {
this.angle = this.arc.b.toRad();
}
}
// Move the crosshair in the right direction
this.pos.x = Math.cos(this.angle + this.turnspeed) * this.radius + (thePlayer.pos.x + 5);
this.pos.y = Math.sin(this.angle + this.turnspeed) * this.radius + (thePlayer.pos.y + 5);
}
// Set variables for moving
this.prev = {x: this.pos.x - thePlayer.pos.x, y: thePlayer.pos.y - this.pos.y};
}
}
});

Still having a bit of an offset issue when changing directions, but it's almost there.

Page 1 of 1

« first
« previous
next ›
last »