I am still trying to get my little 2D Mario clone off the ground, but I need help! I have decided to preface every post I do with “2D Tutorial Question #X” and if I ever get a level made I will post a full tutorial for all others to follow.
Question #1: I am using the following move script form the script reference, but the problem is that I can simply hold down jump and keep jumping forever. This is not the way most 2D side scrolling games are. How can I force the player to have to press jump each time they want to jump, i.e. holding jump will only result in jumping once until the button is released and pressed again?
Thank you!
/// This script moves the character controller forward
/// and sideways based on the arrow keys.
/// It also jumps when pressing space.
/// Make sure to attach a character controller to the same game object.
var speed = 6.0;
var jumpSpeed = 8.0;
var gravity = 20.0;
private var moveDirection = Vector3.zero;
function FixedUpdate() {
var controller : CharacterController = GetComponent(CharacterController);
if (controller.isGrounded) {
// We are grounded, so recalculate
// move direction directly from axes
moveDirection = Vector3(Input.GetAxis("Horizontal"), 0,
Input.GetAxis("Vertical"));
moveDirection = transform.TransformDirection(moveDirection);
moveDirection *= speed;
if (Input.GetButton ("Jump")) {
moveDirection.y = jumpSpeed;
}
}
// Apply gravity
moveDirection.y -= gravity * Time.deltaTime;
// Move the controller
controller.Move(moveDirection * Time.deltaTime);
}
I also tried GetButtonDown, but it was not responding to each press. Maybe a weird refresh issue of some kind? It works most of the time, but then it just wouldn’t register. Usually after I had just jumped.
Any thoughts? All I want here is Mario-style responsiveness to the player’s input.
Thank you so very much for an exceptionally quick reply.
You could also put a yes/no 1/0 into a variable that then had to wait a second or two before being allowed to refire (jump again) by testing if he variable still says yes (that wasn’t well explained, was it?). The FPS tutorial has something like that to prevent firing weapons continuiously.
The problem isn’t the firing again issue in terms of the player being able to jump again too soon. It’s the fact that platform games require the jump button to be pressed per each jump. And GetButtonDown does not work every time. I need a smart person to help me figure this out.
Pleased to be of service. But you’re right…I tried it and it’s sporadic. That’s weird. It works much better if you change FixedUpdate to Update, for some reason. However, even then there are still issues…moving and trying to jump repeatedly doesn’t work; apparently GetButtonDown waits for all keys to be released, not just the one in question. Or maybe it’s a keyboard thing and it would work properly with a gamepad, but I didn’t try that.
I guess the thing to do is try implementing GetButtonDown yourself without actually using GetButtonDown. Put a:
I tried using GetButtonUp to do that, but as I suspected it had the same issues as GetButtonDown, so this is the best I can come up with at the moment. Seems to work though.
We really are on our way here to a working Mario like controller script. Are you ready for the next problem?
How do I control the movement of the jump in the air?
Currently the script is such that if the character jumps while not pushing left or right, it is forced to simply jump straight vertical without the ability to change direction in mid jump.
I have learned enough this past week to know that the “isGrounded” part of the controller is a prerequisite for the ability to move left and right, but how do I change this so it isn’t the case?
Here is the current script:
/// This script moves the character controller forward
/// and sideways based on the arrow keys.
/// It also jumps when pressing space.
/// Make sure to attach a character controller to the same game object.
var speed = 6.0;
var jumpSpeed = 8.0;
var gravity = 20.0;
var buttonPressed = false;
private var moveDirection = Vector3.zero;
function FixedUpdate() {
var controller : CharacterController = GetComponent(CharacterController);
if (controller.isGrounded) {
// We are grounded, so recalculate
// move direction directly from axes
moveDirection = Vector3(Input.GetAxis("Horizontal"), 0,
Input.GetAxis("Vertical"));
moveDirection = transform.TransformDirection(moveDirection);
moveDirection *= speed;
if (Input.GetButton ("Jump") !buttonPressed) {
moveDirection.y = jumpSpeed;
buttonPressed = true;
}
if (buttonPressed !Input.GetButton ("Jump") ) {
buttonPressed = false;
}
}
// Apply gravity
moveDirection.y -= gravity * Time.deltaTime;
// Move the controller
controller.Move(moveDirection * Time.deltaTime);
}
I’ve never found CharacterController’s isGrounded detection to be very reliable, especially when moving on slopes. In my 2D platform test (which I really should post up here sometime) I ended up writing my own grounded-detection using raycasts.
Platformers, and especially 2D ones, have a very different traditional “feel” than what Unity’s CC provides as far as jumping is concerned, based more on timing than whether a character is actually grounded. That is to say, in many 2d platformers, a character is still considered “grounded” for a fraction of a second after he leaves the ground.
if (controller.isGrounded) {
// We are grounded, so recalculate
// move direction directly from axes
moveDirection = Vector3(Input.GetAxis("Horizontal"), 0,
Input.GetAxis("Vertical"));
moveDirection = transform.TransformDirection(moveDirection);
moveDirection *= speed;
if (Input.GetButton ("Jump") !buttonPressed) {
moveDirection.y = jumpSpeed;
buttonPressed = true;
}
if (buttonPressed !Input.GetButton ("Jump") ) {
buttonPressed = false;
}
}
After the if block that tells you if the character is grounded, you want to add an else. So you know the character is not grounded. In there you just add some motion to the moveDirection.
eg.
Thank you so much!!! But someone’s going to kill me because I’m getting a compiling error. Here is the script as it stands:
/// This script moves the character controller forward
/// and sideways based on the arrow keys.
/// It also jumps when pressing space.
/// Make sure to attach a character controller to the same game object.
var speed = 6.0;
var jumpSpeed = 8.0;
var gravity = 20.0;
var buttonPressed = false;
var inAirSpeed = 10;
private var moveDirection = Vector3.zero;
function FixedUpdate() {
var controller : CharacterController = GetComponent(CharacterController);
if (controller.isGrounded) {
// We are grounded, so recalculate
// move direction directly from axes
moveDirection = Vector3(Input.GetAxis("Horizontal"), 0,
Input.GetAxis("Vertical"));
moveDirection = transform.TransformDirection(moveDirection);
moveDirection *= speed;
else
{
moveDirection += Vector3(Input.GetAxis("Horizontal"), 0,
Input.GetAxis("Vertical")) * inAirSpeed;
}
if (Input.GetButton ("Jump") !buttonPressed) {
moveDirection.y = jumpSpeed;
}
if (buttonPressed !Input.GetButton ("Jump") ) {
buttonPressed = false;
}
}
// Apply gravity
moveDirection.y -= gravity * Time.deltaTime;
// Move the controller
controller.Move(moveDirection * Time.deltaTime);
}
The error is
and
Now I’m guessing it has something to do with a missing or extra bracket or something, but I tried my best and couldn’t figure it out.
However, dear god I’m amazed I even get replies at this point, there is a NEW problem. When I jump I quite literally shoot through the air in the horizontal directions!
Curses! Surely the members of this forum are not brave enough to help me fix yet another problem?
I am really starting to develop a complex about the one-sided relationship I have going here?
Does somebody want to make some kind of trade for helping me finish a Mario-style controller script once and for all?
Great Great Great, Super Great. BUT, heh, the new problem is that the character can fly simply by holding down jump! In other words, the character is jumping over and over in the air and flying away!
/// This script moves the character controller forward
/// and sideways based on the arrow keys.
/// It also jumps when pressing space.
/// Make sure to attach a character controller to the same game object.
var speed = 6.0;
var jumpSpeed = 8.0;
var gravity = 20.0;
var buttonPressed = false;
var inAirSpeed = 10;
private var moveDirection = Vector3.zero;
function FixedUpdate() {
var controller : CharacterController = GetComponent(CharacterController);
if (controller.isGrounded) {
// We are grounded, so recalculate
// move direction directly from axes
moveDirection = Vector3(Input.GetAxis("Horizontal"), 0,
Input.GetAxis("Vertical"));
moveDirection = transform.TransformDirection(moveDirection);
moveDirection *= speed;
}
else
{
moveDirection += Vector3(Input.GetAxis("Horizontal"), 0,
Input.GetAxis("Vertical")) * inAirSpeed * Time.deltaTime;
}
if (Input.GetButton ("Jump") !buttonPressed) {
moveDirection.y = jumpSpeed;
}
if (buttonPressed !Input.GetButton ("Jump") ) {
buttonPressed = false;
}
// Apply gravity
moveDirection.y -= gravity * Time.deltaTime;
// Move the controller
controller.Move(moveDirection * Time.deltaTime);
}
Joachim: you are simply going to kill me at some point!
Just glancing at your script, but don’t you need to set buttonPressed to true at some point? Otherwise
if (Input.GetButton ("Jump") !buttonPressed) {
moveDirection.y = jumpSpeed;
}
will get performed each FixedUpdate where you have the “Jump” button pressed, so moveDirection.y will be set each time to jumpSpeed and then you will apply that to your object. Perhaps you need to set buttonPressed to true at that point. Since this is outside the “isGrounded” if statement this statement will be evalutated each time FixedUpdate() is called.