I'm making a frogger game in AS3 and when you press up, down, left and right, you "skip" a certain amount of space instead of gradually moving there like in most platformers now. How would I be able to do this?
Currently he moves up left, down and right on their respective keys. But he gradually moves there, not skipping the amount of space like in the real frogger.
Any ideas on how I could do this?
Code:
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
function keyDownHandler(event:KeyboardEvent):void{
if (event.keyCode == Keyboard.UP){
trace("frogger up");
player.y -= 5;
}
if(event.keyCode == Keyboard.DOWN){
trace("frogger down");
player.y += 5;
}
if(event.keyCode == Keyboard.LEFT){
trace("frogger left");
player.x -= 5;
}
if(event.keyCode == Keyboard.RIGHT){
trace("frogger right");
player.x += 5;
}
}
One way to do is to increase the X and Y with a certain amount like as Marty said in the comment, with 50.. or you could create two variables, let's name them xPosition & yPosition.
When holding down the keys, you would just increase/decrease these variables by 1, and then call a positioning function which would calculate the new position of the player depending on the xPosition and yPosition 's values and of course the grid sizes.
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
var xPosition:int = 0;
var yPosition:int = 0;
var gridWidth:int = 32;
var gridHeight:int = 32;
function keyDownHandler(event:KeyboardEvent):void{
if (event.keyCode == Keyboard.UP){
yPosition--;
repositionPlayer();
}
if(event.keyCode == Keyboard.DOWN){
yPosition++;
repositionPlayer();
}
if(event.keyCode == Keyboard.LEFT){
xPosition--;
repositionPlayer();
}
if(event.keyCode == Keyboard.RIGHT){
xPosition++;
repositionPlayer();
}
}
function repositionPlayer():void{
player.x = gridWidth*xPosition;
player.y = gridHeight*yPosition;
}
This gives you a big advantage in case you want to change the grid size.
Related
I'm very new to ActionScript3 and am making an asteroids-type game. Right now, the ship continues floating in a straight line when you let go of the movement buttons, and I want to be able to stop that from happening. I'm thinking either a dedicated button for braking, like the b key, or if the keys are not pressed to stop movement, whichever would be easier. Like I said I'm really new to AS3 so not even sure what part of my code is making them keep flying in a straight line. Here is the code to control movement for reference:
// register key presses
public function keyDownFunction(event:KeyboardEvent) {
if (event.keyCode == 37) {
leftArrow = true;
} else if (event.keyCode == 39) {
rightArrow = true;
} else if (event.keyCode == 38) {
upArrow = true;
//Add event listener for down arrow
} else if (event.keyCode == 40) {
downArrow = true;
// show thruster
if (gameMode == "play") ship.gotoAndStop(2);
} else if (event.keyCode == 32) { // space
var channel:SoundChannel = shootSound.play();
newMissile();
} else if (event.keyCode == 90) { // z
startShield(false);
var channel:SoundChannel = shieldSound.play();
}
}
// register key ups
public function keyUpFunction(event:KeyboardEvent) {
if (event.keyCode == 37) {
leftArrow = false;
} else if (event.keyCode == 39) {
rightArrow = false;
} else if (event.keyCode == 38) {
upArrow = false;
//Add listener for down arrow
} else if (event.keyCode == 40) {
downArrow = false;
// remove thruster
if (gameMode == "play") ship.gotoAndStop(1);
}
}
// animate ship
public function moveShip(timeDiff:uint) {
// rotate and thrust
if (leftArrow) {
ship.rotation -= shipRotationSpeed*timeDiff;
} else if (rightArrow) {
ship.rotation += shipRotationSpeed*timeDiff;
} else if (upArrow) {
shipMoveX += Math.cos(Math.PI*ship.rotation/180)*thrustPower;
shipMoveY += Math.sin(Math.PI*ship.rotation/180)*thrustPower;
//Added down arrow movement to allow player to move backwards
} else if (downArrow) {
shipMoveX -= Math.cos(Math.PI*ship.rotation/180)*thrustPower;
shipMoveY -= Math.sin(Math.PI*ship.rotation/180)*thrustPower;
}
// move
ship.x += shipMoveX;
ship.y += shipMoveY;
I agree that there is a little logic problem in your code. Your ship will move on 'til
judgement day because the two variables responsible for the speed of it's motion - shipMoveX
and shipMoveY - aren't automatically degraded over time.
Now there are literally thousands of ways of how this could be achieved but let's keep things
simple.
You are using a class variable called thrustPower - make sure to set it to 0.1 and that the value of both shipMoveX & shipMoveY is 0.
Additionally add these class variables:
private var thrustHorizontal:Number = 0;
private var thrustVertical:Number = 0;
private var speed:Number = 0;
private var maxSpeed:Number = 5;
private var decay:Number = 0.97;
Replace the moveShip function with this:
public function moveShip(timeDiff:uint):void
{
thrustHorizontal = Math.sin(Math.PI * ship.rotation / 180);
thrustVertical = Math.cos(Math.PI * ship.rotation / 180);
// rotate and thrust
if (leftArrow)
{
ship.rotation -= shipRotationSpeed * timeDiff;
}
else if (rightArrow)
{
ship.rotation += shipRotationSpeed * timeDiff;
}
else if (upArrow)
{
shipMoveX += thrustPower * thrustHorizontal;
shipMoveY += thrustPower * thrustVertical;
}
else if (downArrow)
{
shipMoveX -= thrustPower * thrustHorizontal;
shipMoveY -= thrustPower * thrustVertical;
}
if (!upArrow && !downArrow)
{
shipMoveX *= decay;
shipMoveY *= decay;
}
speed = Math.sqrt((shipMoveX * shipMoveX) + (shipMoveY * shipMoveY));
if (speed > maxSpeed)
{
shipMoveX *= maxSpeed / speed;
shipMoveY *= maxSpeed / speed;
}
ship.x += shipMoveX;
ship.y -= shipMoveY;
}
As you can see, there is this new if-block:
if (!upArrow && !downArrow)
{
shipMoveX *= decay;
shipMoveY *= decay;
}
Here we're handling the case, if the player neither pressed up nor down and multiply
the spaceships horizontal/vertical speed by decay. If you scroll back a bit, you notice
it's value is 0.97.
You can generally say, if you multiply a positive number x by 0 < y < 1, x will become smaller.
So if you're spaship is currently moving horizontally at 3 pixels per frame (shipMoveX=3 ; shipMoveY=0)
it will become 2.91 the next frame. The next frame it will be 2.8227, then 2.738019 ... and so on before it will finally reach zero in infinity.
I am making a platform game where the main character moves right and left and jumps however my character jumps and does not return to the ground but stays on top of the stage.My characters movie-clip symbol is called 'naruto' and my ground symbol is called 'ground'.
Here is my code:
import flash.events.KeyboardEvent;
import flash.ui.Keyboard;
import flash.display.MovieClip;
import flash.events.Event;
import flash.display.Stage;
naruto.gotoAndStop("stance");
var rightPressed:Boolean = new Boolean(false);
var leftPressed:Boolean = new Boolean(false);
var upPressed:Boolean = new Boolean(false);
var downPressed:Boolean = new Boolean(false);
var narutoSpeed:Number = 10;
stage.addEventListener(KeyboardEvent.KEY_DOWN,keyDownHandler);
stage.addEventListener(KeyboardEvent.KEY_UP,keyUpHandler);
stage.addEventListener(Event.ENTER_FRAME,gameLoop);
function keyDownHandler(keyEvent:KeyboardEvent):void
{
if (keyEvent.keyCode == Keyboard.RIGHT)
{
rightPressed = true;
}
else if(keyEvent.keyCode == Keyboard.LEFT)
{
leftPressed = true;
}
else if(keyEvent.keyCode == Keyboard.UP)
{
upPressed = true;
}else if(keyEvent.keyCode == Keyboard.DOWN)
{
downPressed = true;
}
}
function keyUpHandler(keyEvent:KeyboardEvent):void
{
if (keyEvent.keyCode == Keyboard.RIGHT)
{
rightPressed = false;
naruto.gotoAndStop("standright")
}
else if(keyEvent.keyCode == Keyboard.LEFT)
{
leftPressed = false;
naruto.gotoAndStop("standleft")
}
else if(keyEvent.keyCode == Keyboard.UP)
{
upPressed = false;
naruto.gotoAndStop("stance")
}else if(keyEvent.keyCode == Keyboard.DOWN)
{
downPressed = false;
naruto.gotoAndStop("stance")
}
}
function gameLoop(loopEvent: Event): void {
//If the right key is pressed, and the left key is NOT pressed
if (rightPressed && !leftPressed) {
naruto.x += narutoSpeed;
naruto.gotoAndStop("right");
}
if(leftPressed && !rightPressed) {
naruto.x -= narutoSpeed;
naruto.gotoAndStop("left");
}
var jumpHeight =0;
var defaultJumpSpeed = 20;
var jumpSpeed = 20;
if(upPressed && naruto.hitTestObject(ground))
{
trace("HELLO!");
naruto.y -= jumpSpeed;
jumpSpeed-= 4;
}
if(upPressed)
{
trace("HELLO!");
jumpHeight++;
naruto.y -= jumpSpeed;
if(jumpHeight>10)
jumpSpeed -= 4;
}
if(naruto.hitTestObject(ground))
{
trace("HELLO!");
jumpHeight =0;
jumpSpeed = defaultJumpSpeed;
}
}
Here is the link for my work: https://www.mediafire.com/?8d5opy49fuqmup5
Here is the problem:
The main issue, is in your current code, the player can only possible be in 3 positions:
Whatever the ground position is
16 (up is pressed and the character was not touching the ground
12 (up is pressed and the character was touching the ground)
Please see the code comments next to your original code to explain what is happening:
//you have this var inside the game loop, so every loop it resets to 20
var jumpSpeed = 20;
//so here, if up is pressed and the character is touching the ground
//you initiate a jump
if(upPressed && naruto.hitTestObject(ground))
{
trace("HELLO!");
naruto.y -= jumpSpeed;
jumpSpeed-= 4; //since you reset jumpSpeed to 20 every loop, this value will always just be 16
}
if(upPressed)
{
trace("HELLO!");
jumpHeight++;
//if naruto is touching the ground
//you are subtracting jumpSpeed above and right here again.
//so now the y position is 12 if touching the ground (or 16 if not touching the ground)
//since you reset jumpSpeed to 20 every loop, it always be one of those two values
naruto.y -= jumpSpeed;
if(jumpHeight>10)
jumpSpeed -= 4; //this serves no purpose, as your not using the value again and it gets reset to 20 next time the game loop runs
}
//this hit test will succeed in addition to the first one above when your jump starts.
if(naruto.hitTestObject(ground))
{
trace("HELLO!");
jumpHeight =0;
jumpSpeed = defaultJumpSpeed;
}
To remedy your jumping, you'll need to do something along these lines:
//initialize these vars outside of the game-loop for efficient and proper scoping (so their values don't reset every frame)
var isJumping:Boolean = false; //a flag to know if a jump is in progress
var jumpSpeed:Number = 0; //the current velocity of the jump
var defaultJumpSpeed:Number = 20; //the initial force (speed) of a jump
var jumpGravity:Number = 2; //subtract this from the speed every frame to slow the jump over time and fall
var onGround:Boolean = false; //a helper var for efficiency
function gameLoop(loopEvent: Event): void {
//If the right key is pressed, and the left key is NOT pressed
if (rightPressed && !leftPressed) {
naruto.x += narutoSpeed;
naruto.gotoAndStop("right");
}
if (leftPressed && !rightPressed) {
naruto.x -= narutoSpeed;
naruto.gotoAndStop("left");
}
//only do the hit test once per frame for efficiency (store the result)
onGround = naruto.hitTestObject(ground);
if (upPressed && onGround) {
trace("START JUMP");
isJumping = true;
jumpSpeed = defaultJumpSpeed; //set the initial jump velocity
}
if(isJumping){ //if jumping
naruto.y -= jumpSpeed; //move the player based off the current jump velocity
jumpSpeed -= jumpGravity; //slow the jump every frame (eventually causing it to be negative making the player fall)
}
//touching the ground and the up key is not pressed
//it's very important to put !upPressed so this doesn't run at the time as the initial jump above
if (!upPressed && onGround) {
//stop any jump motion
jumpSpeed = 0;
isJumping = false;
//you probably also want to snap the player to the ground
naruto.y = ground.y - naruto.height + 2; //the plus 2 ensures that the ground and the player touch so the hit test succeeds
}
}
So I'm making a collision detection when player touches an object. When it touches the object, you move and stop when colliding, but for example, if I press the D key to go right, and I press the A key and let go, then the player starts moving through the object.
This is my player moving code.
public function onKeyDown(event: KeyboardEvent): void
{
if (event.keyCode == Keyboard.D)
{
isRight = true;
}
if (event.keyCode == Keyboard.A)
{
isLeft = true;
}
if (event.keyCode == Keyboard.W)
{
isUp = true;
}
if (event.keyCode == Keyboard.S)
{
isDown = true;
}
}
private function onKeyUp(event: KeyboardEvent): void
{
if (event.keyCode == Keyboard.A || event.keyCode == Keyboard.D)
{
vx = 0;
}
else if (event.keyCode == Keyboard.S || event.keyCode == Keyboard.W)
{
vy = 0;
}
}
public function onEnterFrame(event: Event): void
{
if (isRight)
{
vx = 5;
x += vx;
}
if (isLeft)
{
vx = 5;
x -= vy;
}
if (isUp)
{
vx = 5;
y -= vy;
}
if (isDown)
{
vx = 5;
y += vy;
}
//collision detection
if (player.collisionArea.hitTestObject(wall0))
{
player.x -= vx;
player.y -= vy;
}
}
Your issue, is that vx is always 5. So one direction you subtract 5 from the x, the other direction you add it.
Yet in your collision if statement, you are always subtracting it from the player's x (which if moving left, would keep moving the player left until it's past the object it's colliding with).
Also, in your isLeft check, you are subtracting the vy value, but I imagine you want to actually subtract the vx value. On that same note, in your isUp/isDown checks, your set the vx var to 5, but it seems like you should be setting the vy.
As it's unclear what x and y affect in context to the player, it's hard to give you an exact code example.
Most likely, you just need to move the player to the wall edge, and choose the side based off the direction of the player:
//collision detection
if (player.collisionArea.hitTestObject(wall0))
{
//if the player x is colliding
if(player.x + player.width > wall0.x && player.x < wall0.x + wall0.width){
player.x = isRight ? wall0.x - player.width : wall0.x + wall0.width;
}else if(player.y + player.height > wall0.y && player.y < wall0.y + wall0.height){
player.y = isDown ? wall0.y - player.height : wall0.y + wall0.height;
}
}
I am having problems with getting the character to jump/fail when the up arrow is pressed. I'm trying to make it so when the up arrow key is pressed once it will jump a certain height then fall.
Here is my movement code:
public var gravity:int = 2;
public function fireboyMovement(e:KeyboardEvent):void
{
if (e.keyCode == 37) //right
{
fireboy1.x = fireboy1.x -5;
checkBorder()
}
else if (e.keyCode == 39) //left
{
fireboy1.x = fireboy1.x +5;
checkBorder()
}
if (e.keyCode == 38) //up
{
fireboy1.y = fireboy1.y -20;
fireboy1.y += gravity;
checkBorder()
}
Your issue is you need to increment the players position over time (and not all at once).
You can either use a tweening engine (like tweenlite), or roll your own timer or enter frame handler.
Here is an example of the latter:
if (e.keyCode == 38) //up
{
if(!isJumping){
isJumping = true;
velocity = 50; //how much to move every increment, reset every jump to default value
direction = -1; //start by going upwards
this.addEventListener(Event.ENTER_FRAME,jumpLoop);
}
}
var isJumping:Boolean = false;
var friction:Number = .85; //how fast to slow down / speed up - the lower the number the quicker (must be less than 1, and more than 0 to work properly)
var velocity:Number;
var direction:int = -1;
function jumpLoop(){ //this is running every frame while jumping
fireboy1.y += velocity * direction; //take the current velocity, and apply it in the current direction
if(direction < 0){
velocity *= friction; //reduce velocity as player ascends
}else{
velocity *= 1 + (1 - friction); //increase velocity now that player is falling
}
if(velocity < 1) direction = 1; //if player is moving less than 1 pixel now, change direction
if(fireboy1.y > stage.stageHeight - fireboy1.height){ //stage.stageheight being wherever your floor is
fireboy1.y = stage.stageHeight - fireboy1.height; //put player on the floor exactly
//jump is over, stop the jumpLoop
this.removeEventListener(Event.ENTER_FRAME,jumpLoop);
isJumping = false;
}
}
Sorry if this is obvious to others, but I can't get my head around something in ActionScript 3.0 (huge n00b btw)
I have this code for controlling velocity:
public function keyDownHandler(event:KeyboardEvent):void
{
if (event.keyCode == Keyboard.LEFT)
{
vx = -5;
}
else if (event.keyCode == Keyboard.RIGHT)
{
vx = 5;
}
else if (event.keyCode == Keyboard.UP)
{
vy = -5
}
else if (event.keyCode == Keyboard.DOWN)
{
vy = 5;
}
}
When run, if I hold both LEFT and UP the Sprite moves Diagonally, but the fact that the two last conditionals (Keyboard.UP & Keyboard.DOWN) are elseifs should prevent them from being evaluated at all shouldnt it?
Is anyone able to shed some light on the behaviour?
When you press both buttons flash fires two independent events for each button. If you want to skip this case, you can make state flags (leftPressed, rightPressed, etc) for each button, change state in key handler and call the check motion method according to current states of each button.
If you don't want diagonal movement, set the velocity components to zero first like this:
public function keyDownHandler(event:KeyboardEvent):void
{
vx = vy = 0; ////
if (event.keyCode == Keyboard.LEFT)
{
vx = -5;
}
else if (event.keyCode == Keyboard.RIGHT)
{
vx = 5;
}
else if (event.keyCode == Keyboard.UP)
{
vy = -5
}
else if (event.keyCode == Keyboard.DOWN)
{
vy = 5;
}
}