PDA

View Full Version : [AS3] Optimization and Bad Practice Elimination


Eric_S
04-20-2012, 04:23 PM
I've been following two books; Friends of ED: Foundation Game Design with Flash, and O'reilly Learning Actionscript 3.0 in order to learn how to program OOP games and apps correctly and with efficiency. I started months ago piecing together roughly 530 lines of code that animate platformer type movements smoothly and naturally. All the code does is animate a sprite's movements according to 5 keypresses.

up looks up, down ducks, left walks left, right walks right, and Z is a running key which changes the walking animations for each respective direction. I started working on the code about a year ago and put it down until recently and finished it recently. It's part of an ongoing project to make a platformer, so eventually physics will be added to this code.

I'm still consider myself a beginner with AS3 as I can only read and tweak relatively basic code. As of right now I don't know much syntax at all and I wouldn't be able to start coding, something strictly from memory, from scratch. However that is a considerable step forward from wanting others to write my code for me then just copy and pasting it in ;P.

Basically, to put an end to this wall of text, I need help not only optimizing the code, but also finding out what is being optimized and how to not make the same mistakes again. The SWF file is the first file on the list at sites(dot)google(dot)com/site/esiewertjr/flash-games. Apparently I can't post links, so you'll have to replace (dot), and the code will be in the next post, apparently I went over the character limit. ^^;
-----
Just to point out, there are unimplemented things (like physics and the timer which will be used for the idleLong animation and things that won't be there in the final product (like the status testing at the end).

I appreciate any help. And if you are an experienced coder who'd be willing to kind of be a mentor, I'd love you skype info! xD

Eric_S
04-20-2012, 04:27 PM
Here's the code, and sorry for any apparent forum/coding noobishness xD. Also I removed the status test code, 'cause it's right enough for my uses and will be removed in the end anyways (and I was 474 characters over still...)

package {
import flash.display.MovieClip;
import flash.events.KeyboardEvent;
import flash.ui.Keyboard;
import flash.events.Event;
import flash.events.TimerEvent;
import flash.utils.Timer;

public class CharacterMovements2 extends MovieClip {

// Variables
private var _isOnGround:Boolean;
private var _bBox:MovieClip;
// Keys
private var _rightKeyIsDown:Boolean;
private var _leftKeyIsDown:Boolean;
private var _upKeyIsDown:Boolean;
private var _downKeyIsDown:Boolean;
private var _jumpKeyIsDown:Boolean;
private var _runKeyIsDown:Boolean;

private var _isMoving:Boolean;
private var _facingRight:Boolean;
private var _isJumping:Boolean;
private var _isFalling:Boolean;
private var _isLanding:Boolean;
private var _isRunning:Boolean;
private var _isDucking:Boolean;
private var _isLookingUp:Boolean;
private var _isGettingUp:Boolean;

public function CharacterMovements2() {

_bBox = this.boundBox;
_rightKeyIsDown = false;
_leftKeyIsDown = false;
_upKeyIsDown = false;
_downKeyIsDown = false;
_jumpKeyIsDown = false;
_runKeyIsDown = false;

_isMoving = undefined;
_facingRight = true;
_isJumping = false;
_isFalling = undefined;
_isRunning = false;
_isDucking = undefined;
_isLookingUp = undefined;
_isGettingUp = false;
this.stop();
this._bBox.visible = false;
_isOnGround = true;

// Event Listeners
stage.addEventListener(KeyboardEvent.KEY_DOWN,onKe yDown);
stage.addEventListener(KeyboardEvent.KEY_UP,onKeyU p);
addEventListener(Event.ENTER_FRAME,onEnterFrame);
addEventListener(Event.ENTER_FRAME,statusTest);
}

// onKeyDown
private function onKeyDown(e: KeyboardEvent):void {

if (e.keyCode == Keyboard.RIGHT)
{
_rightKeyIsDown = true;
if (_isOnGround)
{
if (! _isDucking)
{
if (! _isGettingUp)
{
if (! _leftKeyIsDown)
{
_isMoving = true;
_facingRight = true;
}
}
}
}
}

if (e.keyCode == Keyboard.LEFT)
{
_leftKeyIsDown = true;
if (_isOnGround)
{
if (! _isDucking)
{
if (! _isGettingUp)
{
if (! _rightKeyIsDown)
{
_isMoving = true;
_facingRight = false;
}
}
}
}
}

if (e.keyCode == Keyboard.UP)
{
_upKeyIsDown = true;
if (_isOnGround)
{
if (! _isMoving)
{
if (! _isDucking)
{
if (! _isGettingUp)
{
_isLookingUp = true;
}
}
}
}
else
{
_isLookingUp = false;
}
}

if (e.keyCode == Keyboard.DOWN)
{
_downKeyIsDown = true;
if (_isOnGround)
{
if (! _isMoving)
{
_isDucking = true;
_isGettingUp = false;
_isLookingUp = false;
}
}
}

if (e.keyCode == Keyboard.Z)
{
_isRunning = true;
}

if (e.keyCode == Keyboard.X)
{
if (_isOnGround)
{
_isJumping = true;
}
}
}

private function onKeyUp(e: KeyboardEvent):void {

if (e.keyCode == Keyboard.RIGHT)
{
_rightKeyIsDown = false;
if (_leftKeyIsDown && _isMoving)
{
_facingRight = false;
_isMoving = true;
}
if (_upKeyIsDown)
{
_isLookingUp = true;
}
else if (! _upKeyIsDown)
{
_isLookingUp = false;
}
if (_downKeyIsDown)
{
_isDucking = true;
}
else if (! _downKeyIsDown)
{
_isDucking = false;
}
if (_isOnGround)
{
if (_facingRight)
{
_isMoving = false;
}
}
}

if (e.keyCode == Keyboard.LEFT)
{
_leftKeyIsDown = false;
if (_rightKeyIsDown && _isMoving)
{
_facingRight = true;
_isMoving = true;
}
if (_upKeyIsDown)
{
_isLookingUp = true;
}
else if (! _upKeyIsDown)
{
_isLookingUp = false;
}
if (_downKeyIsDown)
{
_isDucking = true;
}
else if (! _downKeyIsDown)
{
_isDucking = false;
}
if (_isOnGround)
{
if (! _facingRight)
{
_isMoving = false;
}
}
}

if (e.keyCode == Keyboard.UP)
{
_upKeyIsDown = false;
if (_isLookingUp)
{
_isLookingUp = false;
}
}

if (e.keyCode == Keyboard.DOWN)
{
_downKeyIsDown = false;
if (_isOnGround)
{
_isDucking = false;
_isGettingUp = true;
if (_rightKeyIsDown)
{
_facingRight = true;
}
if (_leftKeyIsDown)
{
_facingRight = false;
}
}
}

if (e.keyCode == Keyboard.Z)
{
if (_isRunning)
{
_isRunning = false;
}
}

if (e.keyCode == Keyboard.X)
{
}
}

private function onEnterFrame(e: Event):void {

// Local Variables
var playerHalfWidth:uint = _bBox.width / 2;
var playerHalfHeight:uint = _bBox.height / 2;

// Actions
// Idle
if (_isOnGround)
{
if (! _isGettingUp)
{
if (! _isMoving)
{
// if (_vx = 0)
if (! _isLookingUp)
{
if (! _isDucking)
{
if (_facingRight)
{
this.gotoAndStop("IdleRight");
}
else if (! _facingRight)
{
this.gotoAndStop("IdleLeft");
}
}
}
}
}
}
// Walking and Running
if (_isMoving)
{
if (_facingRight)
{
if (! _isRunning)
{
this.gotoAndStop("WalkRight");
}
else if (_isRunning)
{
this.gotoAndStop("RunRight");
}
}
else if (! _facingRight)
{
if (! _isRunning)
{
this.gotoAndStop("WalkLeft");
}
else if (_isRunning)
{
this.gotoAndStop("RunLeft");
}
}
}
// Ducking
if (_isOnGround)
{
if (! _isMoving)
{
if (_isDucking)
{
if (_facingRight)
{
this.gotoAndStop("DuckRight");
_isMoving = false;
}
else if (! _facingRight)
{
this.gotoAndStop("DuckLeft");
_isMoving = false;
}
}
}
}
// Getting Up From Ducking
if (_isGettingUp && ! _isMoving)
{
_isDucking = false;
_isMoving = false;
if (_facingRight)
{
this.gotoAndStop("DuckUpRight");
}
else if (! _facingRight)
{
this.gotoAndStop("DuckUpLeft");
}
}
if (Object(DuckUpRight).currentFrame == 6)
{
_isGettingUp = false;
if (! _rightKeyIsDown && ! _leftKeyIsDown)
{
this.gotoAndStop("IdleRight");
_isMoving = false;
}
else if (_rightKeyIsDown)
{
_isMoving = true;
_facingRight = true;
if (! _isRunning)
{
this.gotoAndStop("WalkRight");
}
else if (_isRunning)
{
this.gotoAndStop("RunRight");
}
}
else if (_leftKeyIsDown)
{
_isMoving = true;
_facingRight = false;
if (! _isRunning)
{
this.gotoAndStop("WalkLeft");
}
else if (_isRunning)
{
this.gotoAndStop("RunLeft");
}
}
}
if (Object(DuckUpLeft).currentFrame == 6)
{
_isGettingUp = false;
if (! _rightKeyIsDown && ! _leftKeyIsDown)
{
this.gotoAndStop("IdleLeft");
_isMoving = false;
}
else if (_rightKeyIsDown)
{
_isMoving = true;
_facingRight = true;
if (! _isRunning)
{
this.gotoAndStop("WalkRight");
}
else if (_isRunning)
{
this.gotoAndStop("RunRight");
}
}
else if (_leftKeyIsDown)
{
_isMoving = true;
_facingRight = false;
if (! _isRunning)
{
this.gotoAndStop("WalkLeft");
}
else if (_isRunning)
{
this.gotoAndStop("RunLeft");
}
}
}
// Looking Up
if (_isOnGround)
{
if (_isLookingUp)
{
if (! _isMoving)
{
if (! _isDucking)
{
if (! _isGettingUp)
{
if (_facingRight)
{
this.gotoAndStop("UpRight");
}
else if (! _facingRight)
{
this.gotoAndStop("UpLeft");
}
}
}
}
}
}
// Physics
}
}
}

wvxvw
04-21-2012, 03:23 PM
Few things that you probably want to change:
- no need to initialize the variables to their default values in constructor. You just gave yourself an extra workload for zero profit. Booleans are created with the default value of false, untyped variables have the value of undefined by default.
- you have mutually exclusive conditions spelled as if (x == y) { ... } if (x == z) { ... }. I.e. given that y != z and x is not modified in the first if block, it should be if (x == y) { ... } else if (x == z) { ... }.
- long nesting of if() inside if() - you normally want to avoid it. I.e. you can do if (x) { if (y) { ... }} as if (x && y) { ... } - saves you some work and makes it easier to read.
- it is better to write shorter functions - something you can understand withing a glance. This also helps finding repetitious code and eliminating it. As a general rule, you shouldn't need to scroll in order to read the entire function.

Eric_S
04-28-2012, 11:55 PM
I've been hard at work revamping my code to the point where I've pretty much rewrote it from the ground up (maybe twice!). One thing that is very important to me is fluid and natural animation. I've been able to achieve that to a point in my platformer game, but I can't help but think that the way I've achieved it is incredibly inefficient. Here's the updated code abridged for just animation:
// onKeyPressed
private function onKeyPressed(e:KeyboardEvent):void {

if (e.keyCode == Keyboard.RIGHT)
{
_rightKeyIsDown;
if (! _isDucking && ! _isGettingUp && ! _leftKeyIsDown)
{
_isMoving = true;
_facingRight = true;
_isLookingUp = false;
}
}
if (e.keyCode == Keyboard.LEFT)
{
_leftKeyIsDown = true;
if (! _isDucking && ! _isGettingUp && ! _rightKeyIsDown)
{
_isMoving = true;
_facingRight = false;
_isLookingUp = false;
}
}

if (e.keyCode == Keyboard.UP)
{
_upKeyIsDown = true;
if (_isOnGround && ! _isMoving && ! _isDucking && ! _isGettingUp && ! _isLanding)
{
_isLookingUp = true;
}
}

if (e.keyCode == Keyboard.DOWN)
{
_downKeyIsDown = true;
if (_isOnGround && ! _isMoving && ! _isLanding)
{
_isDucking = true;
_isLookingUp = false;
_canJump = false;
_isMoving = false;
}
}

if (e.keyCode == Keyboard.Z)
{
_isRunning = true;
}

if (e.keyCode == Keyboard.X)
{
if (_isOnGround && _canJump)
{
_accelY = _jumpForce;
_isOnGround = false;
_canJump = false;
_isLookingUp = false;
_isDucking = false;
}
}
}
//onKeyReleased
private function onKeyReleased(e:KeyboardEvent):void {

if (e.keyCode == Keyboard.RIGHT)
{
_rightKeyIsDown = false;
if (_leftKeyIsDown && _isMoving)
{
_facingRight = false;
}
if (_upKeyIsDown && !_isMoving)
{
_isLookingUp = true;
}
if (_downKeyIsDown && !_isMoving)
{
_isDucking = true;
}
if (_facingRight)
{
_isMoving = false;
}
}

if (e.keyCode == Keyboard.LEFT)
{
_leftKeyIsDown = false;
if (_rightKeyIsDown && _isMoving)
{
_facingRight = true;
}
if (_upKeyIsDown && !_isMoving)
{
_isLookingUp = true;
}
else if (! _upKeyIsDown)
{
_isLookingUp = false;
}
if (_downKeyIsDown && !_isMoving)
{
_isDucking = true;
}
else if (! _downKeyIsDown)
{
_isDucking = false;
}
if (! _facingRight)
{
_isMoving = false;
}
}

if (e.keyCode == Keyboard.UP)
{
_upKeyIsDown = false;
if (_isOnGround && _isLookingUp)
{
_isLookingUp = false;
}
}

if (e.keyCode == Keyboard.DOWN)
{
_downKeyIsDown = false;
if (_isDucking && _isOnGround)
{
_isDucking = false;
_isGettingUp = true;
_canJump = true;
if (_rightKeyIsDown)
{
_facingRight = true;
}
else if (_leftKeyIsDown)
{
_facingRight = false;
}
}
}

if (e.keyCode == Keyboard.Z)
{
_isRunning = false;
}

if (e.keyCode == Keyboard.X)
{
_vy = _vy / 4;
if (! _isDucking)
{
_canJump = true;
}
}
}
private function onEnterFrame(e:Event):void {

// Local Variables
var playerHalfWidth:uint = _bBox.width * 0.5;
var playerHalfHeight:uint = _bBox.height * 0.5 + 40;

// Animations
// Idle
if (_isOnGround && ! _isGettingUp && ! _isMoving && ! _isLookingUp && ! _isDucking && ! _isLanding)
{
if (_facingRight)
{
this.gotoAndStop("IdleRight");
}
else if (! _facingRight)
{
this.gotoAndStop("IdleLeft");
}
}
// Walking & Running
if (! _isLanding && _isMoving && _isOnGround)
{
if (_facingRight)
{
if (! _isRunning)
{
this.gotoAndStop("WalkRight");
}
else if (_isRunning)
{
this.gotoAndStop("RunRight");
}
}
else if (! _facingRight)
{
if (! _isRunning)
{
this.gotoAndStop("WalkLeft");
}
else if (_isRunning)
{
this.gotoAndStop("RunLeft");
}
}
}
//Ducking
if (_isDucking && ! _isLanding)
{
if (_facingRight)
{
this.gotoAndStop("DuckRight");
}
else if (! _facingRight)
{
this.gotoAndStop("DuckLeft");
}
}
//Getting Up From Ducking
if (_isGettingUp)
{
_isDucking = false;
_isMoving = false;
_canJump = false;
if (_facingRight)
{
this.gotoAndStop("DuckUpRight");
}
else if (! _facingRight)
{
this.gotoAndStop("DuckUpLeft");
}
}
if (Object(DuckUpRight).currentFrame == 6)
{
_isGettingUp = false;
_canJump = true;

if (! _rightKeyIsDown && ! _leftKeyIsDown)
{
this.gotoAndStop("IdleRight");
_isMoving = false;
}
else if (_rightKeyIsDown)
{
_isMoving = true;
_facingRight = true;
if (! _isRunning)
{
this.gotoAndStop("WalkRight");
}
else if (_isRunning)
{
this.gotoAndStop("RunRight");
}
}
else if (_leftKeyIsDown)
{
_isMoving = true;
_facingRight = false;
if (! _isRunning)
{
this.gotoAndStop("WalkLeft");
}
else if (_isRunning)
{
this.gotoAndStop("RunLeft");
}
}
else if (_upKeyIsDown)
{
_isLookingUp = true;
}
}
if (Object(DuckUpLeft).currentFrame == 6)
{
_isGettingUp = false;
_canJump = true;
if (! _rightKeyIsDown && ! _leftKeyIsDown)
{
this.gotoAndStop("IdleLeft");
_isMoving = false;
}
else if (_rightKeyIsDown)
{
_isMoving = true;
_facingRight = true;
if (! _isRunning)
{
this.gotoAndStop("WalkRight");
}
else if (_isRunning)
{
this.gotoAndStop("RunRight");
}
}
else if (_leftKeyIsDown)
{
_isMoving = true;
_facingRight = false;
if (! _isRunning)
{
this.gotoAndStop("WalkLeft");
}
else if (_isRunning)
{
this.gotoAndStop("RunLeft");
}
}
}
// Looking Up
if (_isLookingUp)
{
if (_facingRight)
{
this.gotoAndStop("UpRight");
}
else if (! _facingRight)
{
this.gotoAndStop("UpLeft");
}
}
// Jumping, Falling, and Landing
if (_isJumping)
{
if (_facingRight)
{
this.gotoAndStop("JumpRight");
}
else if (! _facingRight)
{
this.gotoAndStop("JumpLeft");
}
}
if (_isFalling)
{
if (_facingRight)
{
this.gotoAndStop("FallRight");
}
else if (! _facingRight)
{
this.gotoAndStop("FallLeft");
}
}
if (_isFalling && _isOnGround)
{
_isFalling = false;
}
This achieves a fluid, fairly constant effect with some few hiccups for less significant movements (eg. getting up from ducking and holding the up key has a pause before the character looks up). Does anyone have any suggestions as to how I can make this code more efficient/easier to read/shorter, while still maintaining the same (or better) level of fluidity in the animation? Thanks in advance.

zarmeda
09-30-2013, 01:19 AM
In recent updates do not find such problems already :eek:

rashaeg
09-30-2013, 02:39 PM
- it is better to write shorter functions - something you can understand withing a glance. This also helps finding repetitious code and eliminating it. As a general rule, you shouldn't need to scroll in order to read the entire function.[/QUOTE]
i got it , thanks for the explanation