ID:155026
 
Okay so, what I want to do SOUNDS relatively simple, but I've come to understand it's not.

What I want to do is get an object to orbit another object, with pixel movement enabled. Sadly there isn't an orbit proc so I have no idea how to do this. Also consider that my math skills aren't the greatest.

To keep things simple, said orbit should be a constant, perfect circle.

Any ideas, even a starting point, would be amazing if anyone doesn't mind lending a hand.

EDIT: I say orbit because the primary object may or may not move, so I need it to understand where it is and where it should be.
proc/orbit(atom/movable/planet,atom/movable/satelite,distance,rotation)
var/degree=arcsin(((planet.x*32+planet.step_x)-(satelite.x*32+satelite.step_x))/((planet.y*32+planet.step_y)-(satelite.y*32+satelite.step_y)))
spawn for()
if(degree>360) degree-=360
if(degree<0) degree+=360
degree+=rotation
satelite.set_location((planet.x*32+planet.step_x+planet.bound_x+planet.bound_width/2)+cos(degree)*distance,(planet.y*32+planet.step_y+planet.bound_y+planet.bound_height/2)+sin(degree)*distance,planet.z)
sleep(world.tick_lag)
atom/movable/proc/set_location(px,py,pz)
src.loc=locate(round(px/32)+1,round(px/32)+1,pz)
src.step_x=px-src.x*32-src.bound_x-src.bound_width/2
src.step_y=py-src.y*32-src.bound_y-src.bound_height/2


Didn't do any testing on that snippet, so you may need to change things if problems do arise. But otherwise that should be the basic way to make something orbit.

(Note: "rotation" should be a positive number for clockwise and negative for counter-clockwise and increasing the magnitude of the number increases the rate of rotation.)

Hope that helped! (:
In response to Oasiscircle (#1)
You beat me to it, I was writing up a snippet as well. instead of doing spawn for() you can do a while loop and add a sleep(-1) before it so you do get an infinite loop error.
In response to Oasiscircle (#1)
I attempted to convert it into this so I could use it with my naming scheme:
proc/orbit(var/atom/movable/a,atom/movable/b,distance,rotation)
var/degree=arcsin(((a.x*32+a.step_x)-(b.x*32+b.step_x))/((a.y*32+a.step_y)-(b.y*32+b.step_y)))
spawn for()
if(degree>360) degree-=360
if(degree<0) degree+=360
degree+=rotation
sleep(world.tick_lag)
b.set_location((a.x*32+a.step_x+a.bound_x+a.bound_width/2)+cos(degree)*distance,(a.y*32+a.step_y+a.bound_y+a.bound_height/2)+sin(degree)*distance,a.z)

atom/movable/proc/set_location(px,py,pz)
src.loc=locate(round(px/32)+1,round(px/32)+1,pz)
src.step_x=px-src.x*32
src.step_y=py-src.y*32


Problem is, I get a 'division by zero' error. Here's how I'm calling the proc:

                var/celestial/planet/C = new B(locate(x,O.y,world.maxz))
orbit(O,C,get_dist(C,O)*32,1)


get_dist IS reporting accurately, but maybe I'm misunderstanding what distance is suppose to be set to?
In response to Stevenw9 (#3)
Oh, I forgot to tell you about that division by zero that you'll have to avoid.
If your planet and satelite have the same x value, there will be division by zero. You can handle that how you want, perhaps imposing a extremely small x distace (like 0.000001) if the x values are the same.
In response to Oasiscircle (#4)
Even increasing the x position of 'a' still returns a division by zero problem.

EDIT: This actually may be a problem on my end. Searching...
In response to Stevenw9 (#5)
It'd be extremely helpful if you were posting how you're handling this workaround.
In response to Oasiscircle (#6)
The problem was having the same y axis, now my new problem is all my orbiting objects disappeared. lol

EDIT: Problem traced to set_location. px and py are coming in as 0.

var/celestial/planet/C = new B(locate(x,O.y+1,world.maxz)); That's how I 'fixed' the zero issue. Refer to my second reply for the 'original' code.
Proc together with demo:
proc/orbit(obj/O, x, y, speed, dist)
spawn()
for(var/degrees = 0; 1; degrees += speed)
if(degrees >= 360) degrees -= 360
if(degrees < 0) degrees += 360
var/s = sin(degrees)
var/c = cos(degrees)
var/nx = round(c * dist + x, 1)
var/ny = round(s * dist + y, 1)
O.loc = locate(round(nx / 32) + 1, round(ny / 32) + 1, O.z)
O.step_x = nx - O.x * 32 - O.bound_x - O.bound_width / 2
O.step_y = ny - O.y * 32 - O.bound_y - O.bound_height / 2
sleep(world.tick_lag)

obj/pixel
icon = 'pixel.dmi'
bound_x = 0
bound_y = 0
bound_width = 1
bound_height = 1

world
maxx = 10
maxy = 10
maxz = 1
tick_lag = 0.1

New()
..()
new/obj/pixel(locate(5, 5, 1))
orbit(new/obj/pixel(locate(1, 1, 1)), 160, 160, 2, 100) // object must be on correct z level, so I locate it here


Trivia: changing nx calculation to round(c * s * dist + x, 1) causes pixel to 'draw' number 8
In response to Zaoshi (#8)
Going off of this, how would one simulate elliptic (I believe this is what it's called? Orbit that's not a perfect circle, but more like an oval) orbit as well as orbital decay (an object will orbit the source so many times, and each time it will get a little bit closer to the source until it collides with it)?
In response to LordAndrew (#9)
Making elliptic movement is pretty easy. You have to make two different distance variables, one for X and one for Y. Make one larger or smaller than the other and you'll have an elliptical movement.

Orbital decay could be done by gradually decreasing the distance variables attached to the orbiting object and the object will gradually get closer and closer to the source, and finally just stop the orbit when the distance becomes zero.
In response to LordAndrew (#9)
LordAndrew wrote:
Going off of this, how would one simulate elliptic (I believe this is what it's called?

For elliptic movement along x or y axis, simple difference between distx and disty will be enough (which is pretty much what Oasiscircle said).
var/nx = round(c * distx + x, 1)
var/ny = round(s * disty + y, 1)


'Rotated' orbits require some extra calculations:
proc/orbit(obj/O, x, y, speed, distx, disty, elipseAngle)
spawn()
for(var/degrees = 0; 1; degrees += speed)
if(degrees >= 360) degrees -= 360
if(degrees < 0) degrees += 360

var/s = sin(degrees)
var/c = cos(degrees)
var/sr = sin(elipseAngle)
var/cr = cos(elipseAngle)

var/nx = c * distx
var/ny = s * disty

var/nnx = nx * cr + ny * sr
var/nny = nx * -sr + ny * cr

nx = round(nnx + x, 1)
ny = round(nny + y, 1)

O.loc = locate(round(nx / 32) + 1, round(ny / 32) + 1, O.z)
O.step_x = nx - O.x * 32 - O.bound_x - O.bound_width / 2
O.step_y = ny - O.y * 32 - O.bound_y - O.bound_height / 2
sleep(world.tick_lag)


Picture shows two orbits (15 degree and 45 degree) created using code above. I used disty twice bigger than distx


orbital decay (an object will orbit the source so many times, and each time it will get a little bit closer to the source until it collides with it)?

As Oasiscircle said, you'll need to decrease distance. You could add distDecay variable, and subtract it from dist every iteration.
I'm still having issues here. Oasis' code causes my orbiting objects to just vanish. Zaoshi's code doesn't factor in another object as the center (what if I make my sun or something orbit the galactic center guys?!). If it wasn't for the math I'd probably understand what I'm doing. x.X
In response to Stevenw9 (#12)
Stevenw9 wrote:
Zaoshi's code doesn't factor in another object as the center (what if I make my sun or something orbit the galactic center guys?!)

If you can't change code to use non-constant x and y values it's not really my fault.
In response to Zaoshi (#13)
Oh. I'm sorry. It's hard for me to figure out what's actually going on when you start throwing sin, cos, and other funky things way outside my knowledge base.

EDIT: Got it working.
In response to Stevenw9 (#14)
For example you could replace x and y with object, which needs to be orbited, then use it's coordinates.
In response to Zaoshi (#15)
Yep yep, I ended up with

proc/orbit(atom/movable/a,atom/movable/b, speed, dist)
spawn()
for(var/degrees = 0; 1; degrees += speed)
if(degrees >= 360) degrees -= 360
if(degrees < 0) degrees += 360
var/s = sin(degrees)
var/c = cos(degrees)
var/nx = round(c * dist + b.x, 1)
var/ny = round(s * dist + b.y, 1)
a.loc = locate(round(nx / 32) + 1, round(ny / 32) + 1, a.z)
a.step_x = nx - a.x * 32 - a.bound_x - a.bound_width / 2
a.step_y = ny - a.y * 32 - a.bound_y - a.bound_height / 2
sleep(world.tick_lag)


and now it works perfectly. Thanks for the help guys!
In response to Stevenw9 (#16)
I take that back, for some reason all my objects are getting lumped into the bottom left hand side of the screen, except the orbits center (or b).

Here's the orbit proc:
proc/orbit(atom/movable/a,atom/movable/b, speed, dist)
spawn()
for(var/degrees = 0; 1; degrees += speed)
if(degrees >= 360) degrees -= 360
if(degrees < 0) degrees += 360
var/s = sin(degrees)
var/c = cos(degrees)
var/nx = round(c * dist + b.x, 1)
var/ny = round(s * dist + b.y, 1)
a.loc = locate(round(nx / 32) + 1, round(ny / 32) + 1, a.z)
a.step_x = nx - a.x * 32 - a.bound_x - a.bound_width / 2
a.step_y = ny - a.y * 32 - a.bound_y - a.bound_height / 2
sleep(world.tick_lag)


Here's how I'm calling it:
    genplanets(var/atom/movable/O)
var
pminx=O.x-10
for(var/x=pminx,x<=O.x,x++)
if(x==O.x||x==O.x-1) continue
var/B=pickweight(planets)
if(B)
var/celestial/planet/C = new B(locate(x,O.y+1,world.maxz))
//alert("[C.x],[C.y] | [O.x],[O.y]")
orbit(C,O,1,get_dist(C,O)*32)
In response to Stevenw9 (#17)
Try
var/nx = round(c * dist + b.x * 32 + b.bound_x + b.bound_width / 2, 1)
var/ny = round(s * dist + b.y * 32 + b.bound_y + b.bound_height / 2, 1)
In response to Stevenw9 (#17)
To be honest this would be so much easier using vectors, but I guess there's nothing wrong with how you guys are doing it.
Page: 1 2