How can I control an actor clockwise and anti-clockwise while in orbit using a keyboard?

EddietheFistMonkeyEddietheFistMonkey Member Posts: 12
edited June 2012 in Working with GS (Mac)
Good early evening everyone (UK time),

I've come across a problem while creating my first game and after a thorough search and much experimentation I can't seem to find a solution.

I'll start by explaining in more detail what I want to achieve.

I have an Actor (Planet) in the centre orbited by 2 other actors at varying distances and at varying speeds. I have now begun creating a Player actor which I have set at the furthest distance of the three orbiting Actors from the central Actor (planet).
I have managed to allow the 'Player' to control this actor to move Clockwise or Anti-Clockwise by pressing either the Up or Down key. Now the problem is as some may have guessed by now that in switching direction the Player Actor will jump from one side of orbit to another before fulfilling it's direction change. For example it will be moving clockwise passing the theoretical hands of a clock 12, 1, 2, 3 ,4, 5, 6 upon changing direction it will jump back to 12 then 11,10,9,8.

I'm trying to work out how to make it so that the object will simply change direction with no transportation as it were. Now after searching the forums it seems that the problem is with both movements relying on the same Game.time within the game. I've tried piecing various bits of info together from a variety of forum posts and have attempted a solutions by creating a new attribute to replace Game.time and to then stagger them differently using timers or integers but by not really understanding this I feel I've gone wrong somewhere in implementing these approaches.

So now I turn to the community for help any of which would be greatly appreciated. I've included the formula I've used thus far below. Thank you I hope to hear from you guys on your thoughts.


ANTI-CLOCKWISE Movement

RULE: Actor receives event, key UP when Down.

(within RULE)

MOVE:

Direction formula is, 100*cos( self.Time *60%360)+128 Relative to Actor, Move type Additive.
Speed is 300

CONSTRAIN ATTRIBUTE: for Self position Y and X

Constrain to 140*sin( game.Time *60%360)+160 for Y

and 140*cos( game.Time *60%360)+236 for X


CLOCKWISE Movement

RULE: Same as Anti-Clockwise

(Within RULE)

MOVE: Same as Anti-Clockwise except replace sin with cos.

CONSTRAIN ATTRIBUTE: for self position Y and X

Constrain to 140*sin( game.Time *-60%360)+160 for Y

and 140*cos( game.Time *-60%360)+236 for X


Separate from Rules,

CONSTRAIN ATTRIBUTE (So player actor faces central Actor)

Constrain Attribute: Self.Rotation TO: vectorToAngle( game.Sun x - self.Position.X , game.sun y - self.Position.Y )

Best Answers

  • MobileRocketGamesMobileRocketGames Posts: 128
    edited June 2012 Accepted Answer
    Joints would come in super handy right now.
    If you could attach a joint to an arbitrary point and have an actor revolve around this joint you could just have the up and down arrow keys control the actors rotation with a simple rotate behavior. I will give this some thought. Maybe one of the more experienced forum members will come up with a quick solution.

    Oh, I was just reminded of the old animators acronym K.I.S.S. Keep it simple, stupid!
    What if you just cheated the math/position?
    Does that actor have to be there for any collision purposes? Even if so, we can get around those as well.

    Imagine this.
    You have a large 512x512 image in the center of your screen.
    This image is transparent except for lets say 64x64 pixels in the top right corner.
    Those 64x64 pixels contain your earth or whatever planet actor that you want the player to control.
    Pressing up on the keyboard accelerates the rotation CW and down accelerates the rotation CCW. You've now effectively fixed your problem and reduced the CPU load of the program by 1/3rd. Do the same for all 3 planets and your game will run at full speed all the time.

    Now you might say, what about collisions? It cant calculate the collision if there's nothing there.
    Well there doesn't have to be. You could create two game attribute that stores the theoretical location of the planet, (the center of those 64x64 pixels). You could update these points based on the rotation of the image and then calculate where that point would be at any given angle. If you had something you want to collide with the planet you could say, If self.Position.X is = game.PlanetX and self.position.Y is = game.PlanetY then spawn Explosion or etc.

    Or even better yet!!! Constrain an actors X and Y positions to the theoretical position of the planet (which is being controlled by the rotation angle) and have that be the collision. If you did that, you wouldnt need to use a 512x512 image and cheat the location, you could use a transparent 20x20 actor in the center and use your original planet image on an actor constrained to that theoretical point.

    I think the problem here is you are trying to move this planet actor based on the keys pressed, where as it should be constrained to a point and that point should be controlled by a simple rotation CW or CCW.

    Food for thought.
    Good luck!
  • RThurmanRThurman Posts: 2,881
    Accepted Answer
    game.Time is being used as a quick-n-dirty counter here. You can make your own counting attribute and replace game.Time with it. For example you could use an attribute called "counter" to do something like:

    When key "downArrow" is down
    -- change attribute: self.counter To: self.counter+1
    When key "upArrow" is down
    -- change attribute self.counter To: self.counter-1

    Using your formula, the constrain would then be:
    Constrain attribute: self.Position.Y To: 140*sin(self.counter*60%360)+160
    Constrain attribute: self.Position.X To: 140*cos(self.counter*60%360)+236
  • ORBZORBZ Posts: 1,304
    edited June 2012 Accepted Answer
    You can simplify this whole problem if you think about it like a wheel and axle.

    You will need four global variables:
    Axis-Rotation: angle
    Axis-x: real
    Axis-y: real
    Distance: real (set to however far away the player should be from the axis, ex: 300)

    Have an invisible "axis" actor in the middle and constrain the global vars to its rotation, x, and y positions.

    Like so:
    Constrain global var = axis local var

    You want the globals to be copies of the locals.

    Now then, this "axle" will have the behavior logic in it that says when up is pressed rotate clockwise and when down is pressed rotate counter-clockwise. (tip: you can even relocate it's x and y and this will still work)

    Finally, specify the player object to constrain it's x and y position using sin and cos functions, like so:

    Player.x = game.Axis-x + cos(game.Axis-rotation) * game.distance

    Player.y= game.Axis-y + sin(game.Axis-rotation) * game.distance

    Tada!

    Super simple, like maybe 10 lines of code.
  • MobileRocketGamesMobileRocketGames Posts: 128
    edited June 2012 Accepted Answer

    For example are Global Variables the Attributes that we create real, boolean etc and therefore would a local variable in this case be the self.postion.X or .Y?
    whoa! somewhere you've gotten off the track.
    Global attributes are the ones you create by selecting the attributes tab in the top level of the editor, from the Inspector pain in the top left (there are 3 tabs, Actor, Attributes and Devices). In other words, Game Attributes. these will be indicated by lowercase "game" before their name in the expression editor (e.g. "game.Time").

    Local attributes would be the ones you create by double clicking an actor and opening up the prototype. These are indicated by a self preposition (e.g. "self.Position.X")
    The only difference between these two is that you can link to and control game attributes from actor prototypes (global) where as scene and self attributes can only be controlled by actors already placed in the scene.

    It's best if you just create a backup of your game, then delete your current movement control system and start over using the instructions here.

    Basically just:
    -Add those 4 game attributes
    -Create "invisible actor" and place it directly in the center of the screen.
    -Add to the invisible actor 3 constrain attribute behaviors to control those global variables like ORBZ mentioned.
    -Create two rules, the first being "when up key is down" and the next being "when down key is down" and having each change the rotation CW or CWW.

    Then on your player actor add two constrain attributes:
    self.Position.X = game.Axis-x + cos(game.Axis-rotation) * game.distance

    self.Position.Y = game.Axis-y + sin(game.Axis-rotation) * game.distance
  • MobileRocketGamesMobileRocketGames Posts: 128
    Accepted Answer
    I took the liberty of creating this system for you. if you want to PM me your email I'll send you over the build so you can see how it works.
  • MobileRocketGamesMobileRocketGames Posts: 128
    edited June 2012 Accepted Answer
    Oh crap, i realized I just saved over my previous comment instead of adding a new one.
    it was a big one too =(

    I will rewrite the important parts:
    "
    For example are Global Variables the Attributes that we create real, boolean etc and therefore would a local variable in this case be the self.postion.X or .Y?
    You seem to have gotten off track somewhere. Let's clarify those two.

    A global attribute (in this case, known as a game attribute) is an attribute created by selecting the attributes tab in the inspector pane on the left hand side of the top level of the editor (the one that contains all your actors, it has 3 tabs, Actor, Attribute, Devices).

    A local attribute is a self or scene attribute. These attributes can only be accessed locally (that is, by an actor already placed in the scene). For example, from a prototype you cannot say, if this actor is touched, move some other specific actor 200px to the right. But you can if you place that actor in the scene and unlock it, then you can actually select from a drop down list any other actor in the scene and directly modify or control any of their variables.

    A global attribute will have the preposition "game" in the expression editor (e.g. "game.Time").
    A local attribute will have the preposition "self" or "scene" in the expression editor (e.g. "self.Position.X").

    The benefit of a game attribute is it can be accessed anywhere, by any actor. Where as local attributes are limited as to who or when they can be accessed.
    "

    I took the liberty of creating this system for you. If you want to PM me your email I'll send you over the build so you can see how it works. Super thanks to @ORBZ for the sin/cos formula.

Answers

  • EddietheFistMonkeyEddietheFistMonkey Member Posts: 12
    Thank you all of you for your quick reply, I do now however feel like a halfwit. I've been attempting the solutions of Orbz and Rthurman however MobilRocketGames your final thought seems to mirror Orbz's solution.

    I am however having real problems. Regarding Rthurmans solution I can only seem to create an attribute for Game.Counter and not Self.Counter showing how new i am to this.

    Regarding your solution Orbz I'm having trouble following it in practice, though you clearly know what you're talking about.

    For example are Global Variables the Attributes that we create real, boolean etc and therefore would a local variable in this case be the self.postion.X or .Y? This is the assumption I have made in trying out your method.

    I have had my central actor (our axis) around which the others are rotating constrained using 'Real' Attributes (Axis X and Y) and constraining them to its Self. X and Y positions. I have also set two rules and a behaviour for each for rotating when keys are pressed up and down.

    Now as for the acting player actor, how would this apply to the original formula I was using? I've thus far used;

    A Rule for each Key command up and down, with a Move behaviour as before and then two constrain attributes again for each rule like before,

    Example:
    game.Axis y +sin( game.Axle Rotation *60%360) game.Distance, and a corresponding formula for X axis. (would the game.distance be set at the attributes list where it begins as 0?)

    I also have a constrain attribute to 'vector angle' as before which seems to help the player return to the screen when down is pressed.

    At the moment the player when 'up' is pressed disappears and returns to orbit the centre at o distance and then veers off, 'down' results just in the player going off screen.

    I realise this must seem like gibberish but I'm rather confused and trying to get across as much information as possible.

    Thank you very much for your help, any further explanation that could help drag me kicking and screaming to success would be fantastic. Thanks a lot guys.

  • EddietheFistMonkeyEddietheFistMonkey Member Posts: 12
    You've all been incredibly helpful, i'm not one to turn down an offer like that MobileRocketGame :D
  • MobileRocketGamesMobileRocketGames Member Posts: 128
    what the hell? now my comments are there? but the other day they were gone...

    well, anyway I'm glad you're on your way to making your first game.
    The cookbook here on the gamesalad website actually has some helpful tutorials for learning the lingo and behaviors. Definitely worth checking out.
    Also check out @Tshirtbooth videos on his website www.GShelper.com for some great tutorials for things you will most likely want in your game (e.g. score counter, tables, store, etc).

    Good Luck!
  • EddietheFistMonkeyEddietheFistMonkey Member Posts: 12
    Hey man, once again thanks for your awesome help. Really looking forward to seeing it all come together and evolve more into the game I had initially planned as I learn more. The new Game Salad manual is very useful, I've checked out Tshirtbooth's vids on youtube, it'll be great to use the website also to make sure I've access to them all, they're very easy to follow and take in.

    Cheers :)
Sign In or Register to comment.