00:00
00:00
Newgrounds Background Image Theme

SpeakyDooman just joined the crew!

We need you on the team, too.

Support Newgrounds and get tons of perks for just $2.99!

Create a Free Account and then..

Become a Supporter!

Options for character controls...

473 Views | 10 Replies
New Topic Respond to this Topic

Options for character controls... 2014-09-12 03:39:40


Tinkering around with a few games at the moment and one of them is a very simple platformer.

Depending on the level the character's control attributes will vary. By that I mean the player will use the same keys to move control the player (WASD or Arrows) but some levels the controls will be reversed or his speed will be greatly increased or reduced.

Wondering what would be the best way to go about organizing this.

My current idea is to use booleans inside the key handlers that will check which level it is.

I'm open to any other suggestions. Since I'm still fairly new to arrays/loops if you are going to suggest them in some way could you go a little into detail about how I would use them for this situation or give me some pseudo code demonstration.

Thanks in advance guys.

Response to Options for character controls... 2014-09-12 04:18:03


At 9/12/14 03:39 AM, Hero101 wrote: My current idea is to use booleans inside the key handlers that will check which level it is.

Imagine what your code would look like if you had 100 different levels and you put all possibilities inside the key handler...
Stuff that differs between levels (like gravity, friction etc) should be defined in the levels.
Include the environment variables when deciding what exactly your character does.

If you have multiple entities which should behave differently in your level (eg reversed controls for your character but not for monsters) you might want to consider to introduce a 'buff' system, implementing a nice&clean buff system can be complex though and might be overkill, so I think it's okay to use booleans like 'controlsReverted' in your character as long as you don't use too many behaviour modifiers.

Response to Options for character controls... 2014-09-12 04:35:38


At 9/12/14 04:18 AM, Etherblood wrote:
At 9/12/14 03:39 AM, Hero101 wrote: My current idea is to use booleans inside the key handlers that will check which level it is.
Imagine what your code would look like if you had 100 different levels and you put all possibilities inside the key handler...

Ah yeah you bring up a good point. The game will be about 20 simple levels and only 7 of the levels have altered controls like I mentioned.

Stuff that differs between levels (like gravity, friction etc) should be defined in the levels.

Include the environment variables when deciding what exactly your character does.
That's a great idea. Guess I'm still such a newbie that it didn't even cross my mind to define it when I call the level.

If you have multiple entities which should behave differently in your level (eg reversed controls for your character but not for monsters) you might want to consider to introduce a 'buff' system, implementing a nice&clean buff system can be complex though and might be overkill

Can you expand on this notion? It probably is overkill for this game as it is so simple and short, but I would like to know for future games. What do you mean by "buff" system?

Response to Options for character controls... 2014-09-12 04:59:35


At 9/12/14 04:35 AM, Hero101 wrote: Can you expand on this notion? It probably is overkill for this game as it is so simple and short, but I would like to know for future games. What do you mean by "buff" system?

What I mean with buff system is a way to attach 'buffs' to your units.
The most simple kind of buff is something that just does something every frame.
As example if your character is on fire you would attach an 'onFire' buff to your character.
This buff would then deal damage over time to your character until it expires or is otherwise removed.

It becomes more complex if the buffs modify the player behaviour, because the character should not check
'if i have buff reverseControl do x instead of y'
(implementing new buffs would require changing the character class each time a new buff is coded),
instead the buff should be like
'when my character does x do y instead'.
This way you don't have to edit your character each time new buffs are introduced and creating new buffs will be relatively easy.

An easy way to implement buffs that just do something to your characters would be to have an array containing buffs for each of your characters and updating them each time your character is updated.

Response to Options for character controls... 2014-09-12 05:11:41


At 9/12/14 04:59 AM, Etherblood wrote:
At 9/12/14 04:35 AM, Hero101 wrote:
What I mean with buff system is a way to attach 'buffs' to your units.

Ahhh ok I see. Thank you for explaining everything so well. I fully understand everything you just told me. I think I need to start asking more questions about best practices in the future. If I didn't ask this one I would have gone on checking things too often and only with boolean until it dawned on me much later down the road how there is a better overall way of doing things.

Thanks again I truly appreciate it.

Response to Options for character controls... 2014-09-12 11:13:16


At 9/12/14 03:39 AM, Hero101 wrote: Depending on the level the character's control attributes will vary. By that I mean the player will use the same keys to move control the player (WASD or Arrows) but some levels the controls will be reversed or his speed will be greatly increased or reduced.

So say you have some class that takes all the user input and transforms it into movement of the player:

// Controller.as

public function Controller (target:Player)

Which could be used like this:

var player:Player = new Player();
addChild(player);

var controller:Controller = new Controller(player);

To do that, your Player class could provide public methods like these:

// Player.as

public function set speedX(value:Number):void
{

// ...
}

public function set speedY(value:Number):void
{

// ...
}

The controller knows the player object and can set the speed of it.
Therefore the controller controls the player.

Now how could you make this connection between controller and player different for each level?

You could extract those methods into an interface as a start.
Again, all the controller does is call those two methods that set the speed, they do not necessarily have to be on a player object.
At the moment, the Controller asks for "some Player" and with the interface this changes to "something that has these two methods, I don't care what it actually is, because all I do all day long is call those methods. Did I mention those two methods?"

// ISpeedSettable.as

public function set speedX(value:Number):void;
public function set speedY(value:Number):void;

Now the Controller should expect that interface instead of Player as the type of its constructor parameter:

// Controller.as

public function Controller (target:ISpeedSettable)

Problem is that this breaks the code. You cannot pass Player to the Controller any more, because Player is not ISpeedSettable.
To fix this, let Player implement that interface:

// Player.as

public class Player implements ISpeedSettable

public function set speedX(value:Number):void
{
    // ...
}

public function set speedY(value:Number):void
{
    // ...
}

And sure enough it has both methods and the code compiles.
Finally, this code works again:

var player:Player = new Player();
addChild(player);

var controller:Controller = new Controller(player);

And we are right where we started. Ain't that awesome? *yay*

Except that there's this interface thingy now which we can do cool things with.
Instead of passing the Player, we could create something else that implements the interface and pass that thing to the Controller instead.
The Controller can be "fooled" to control something that isn't actually the player.

like this thing for example:

// TheThingThatFoolsTheController.as

public class TheThingThatFoolsTheController implements ISpeedSettable

public function set speedX(value:Number):void
{
    // trollolol, the controller is calling this function thinking it controls the player, but it's not
}

public function set speedY(value:Number):void
{
    // omg, we can totally take all the information originally sent to the player object and do secret stuff with it, this is feels so James Bond
}

Ok, let's fool the controller and give it that other object instead of Player:

var player:Player = new Player();
addChild(player);

var controller:Controller = new Controller(new TheThingThatFoolsTheController());

That should compile but nothing's happening, because we cut the connection between the Controller and the Player.
TheThingThatFoolsTheController should have a connection to Player, so the Player moves (after all, that's what we want, right?) so let's pass the Player to this class:

// TheThingThatFoolsTheController.as

public class TheThingThatFoolsTheController implements ISpeedSettable

private var _target:Player;

public function TheThingThatFoolsTheController(target:Player)
{
    _target = target;
}

public function set speedX(value:Number):void
{

// trollolol, the controller is calling this function thinking it controls the player, but it's not
}

public function set speedY(value:Number):void
{

// omg, we can totally take all the information originally sent to the player object and do secret stuff with it, this is feels so James Bond
}

To complete the connection, each of both method calls is delegated to the player:

// TheThingThatFoolsTheController.as

public class TheThingThatFoolsTheController implements ISpeedSettable

private var _target:Player;

public function TheThingThatFoolsTheController(target:Player)
{
    _target = target;
}

public function set speedX(value:Number):void
{
     _target.speedX = value;
}

public function set speedY(value:Number):void
{
     _target.speedY = value;
}

After all this effort we are where we started - again! (second round walking in this circle, w00t)

And because NG is retarded I have to continue in another post.

Response to Options for character controls... 2014-09-12 11:14:23


var player:Player = new Player();
addChild(player);

var controller:Controller = new Controller(new TheThingThatFoolsTheController(player));

I mean seriously, wtf? Why?
Well, we successfully placed something in between the Controller and the Player.
TheThingThatFoolsTheController monitors all the communication that goes from the Controller to the Player (in terms of the two relevant functions).

It's like the NSA.
You think you make a phone call to your friend, but actually your phone call goes to the NSA and the NSA calls your friend.
They are sitting in between and are listening to everything you say.
Let's put this new power to good use and actually manipulate phone calls of other people ...errr... speed, I mean speed of Player, of course:

Another class very similar to TheThingThatFoolsTheController could be this one:

// SuperFastMovement.as

public class SuperFastMovement implements ISpeedSettable

private var _target:Player;

public function SuperFastMovement(target:Player)
{
    _target = target;
}

public function set speedX(value:Number):void
{
     _target.speedX = 5 * value;
}

public function set speedY(value:Number):void
{
     _target.speedY = 5 * value;
}

It's as if you are whispering and your friend is wondering why you are screaming all the time.
The NSA in between turned the volume way up, that's why.

Whatever the Controller says, the player will move 5 times that fast.
If you read this far and still remember: that way the goal.

The usage is the same as before:

var player:Player = new Player();
addChild(player);

var controller:Controller = new Controller(new SuperFastMovement(player));

The system is set up so you can create objects that work like the NSA and hack into the communication between other objects.

But there's one last thing to do.
As you know, there are many other secret services and agencies that want to listen to the phone call with your friend.
But so far, there can only be one, what a shame.

This is where the interface thing comes in handy.
Remember that the controller only cares about those two methods?
So he only asks for the interface and not the Player class?
The same holds true for the 2 NSA-style classes created so far, so they should only ask for the interface as well:

// SuperFastMovement.as

public function SuperFastMovement(target:ISpeedSettable)

and

// TheThingThatFoolsTheController.as

public function TheThingThatFoolsTheController(target:ISpeedSettable)

You can now chain them together:

var player:Player = new Player();
addChild(player);

var controller:Controller = new Controller( new SuperFastMovement( new TheThingThatFoolsTheController( new SuperFastMovement( player ))));

It's like:
You call your friend.
Instead, you call the NSA, which then call your friend.
Instead, you call the NSA, which call the GCHQ, which call the MSS, which call the CIA, etc., ...which then call your friend.
But to you, it feels like you are just calling your friend.

Code untested and reduced to important parts.

Response to Options for character controls... 2014-09-12 11:50:37


At 9/12/14 03:39 AM, Hero101 wrote: Wondering what would be the best way to go about organizing this.

Mil's technically got the right solution, but personally I'd go for something simpler and probably not quite up-to-scratch.
Myself, I like to go with the "give ALL the options" route and put as many customizable variables as possible into a static class the user can play around with in a menu of some sort (hey, an options menu, that's a new idea)

However if you need to switch controls on a player for whatever reason, you can simply use a state machine and put each level into its own state that extends a base state class with automatic basic key handling. Then take they correct input keys on each state and assign them to the correct controls. Boom, done. Code stays clean, you get what you want, and everybody's happy.


Programming stuffs (tutorials and extras)

PM me (instead of MintPaw) if you're confuzzled.

thank Skaren for the sig :P

BBS Signature

Response to Options for character controls... 2014-09-12 11:57:21


At 9/12/14 11:50 AM, egg82 wrote: put as many customizable variables as possible into a static class

Or into the class that handles the user input where they belong ;)

Response to Options for character controls... 2014-09-12 12:08:19


At 9/12/14 11:57 AM, milchreis wrote: Or into the class that handles the user input where they belong ;)

Yeah, but then you have weirdness in the options menu if you decide to have one, trying to access either a nonexistent player class or having static variables in the player class that don't entirely belong. The best way to handle that is with an .ini file, but this is Flash, so the closest you're going to get is with either SharedObjects or a static graveyard.


Programming stuffs (tutorials and extras)

PM me (instead of MintPaw) if you're confuzzled.

thank Skaren for the sig :P

BBS Signature

Response to Options for character controls... 2014-09-12 20:04:23


@milchreis

Wow....when I asked to get some pseudo code to help me understand things better I didn't expect anyone to go into such detail. You went above and beyond with helping me with understanding everything and for that I say thank you so much! I truly do appreciate it dude :) Never would have been able to come up with everything you just suggested on my own. Well... maybe some day down the line (far down the line) as I learn more programming. I will have to fiddle around with everything you suggested.

Up until this point I have never seen "implements" used in defining the class. I will have to go read up on it but for now I think I get the gist of it due to everything you posted.

Thanks again for all of your input it is greatly appreciated.