Juego plataformas en AS3 con problemas al saltar

mTr

Hola, muy buenas mediavideros, vengo en busca de consejo sobre un problemilla que tengo con un juego de plataformas muy básico.

El caso es que estoy usando una forma muy básica para hacer que el personaje principal salte, lo había usado antes en XNA, pero al parecer, en ActionScript no funciona tan bien, o algo me he dejado por el camino (lo más seguro). Es tan básico como jugar con un parámetro de gravedad que disminuye la altura cuando el personaje no toca suelo, y otro parámetro que aumenta la altura mientras se mantiene la tecla pulsada, luchando así contra el parámetro de gravedad y haciendo que el personaje caiga de una forma un poco mas realista (cuanto mas tiempo en el aire, mas rápido cae).

El problema viene al detectar la colision con el suelo. Muchas veces, digamos que... el personaje baja mas de lo que deberia, y "atraviesa" el suelo. ¿ Puede ser por que estoy midiendo mal la velocidad a la que cae por fotogramas ?

Copio aquí las dos clases mas importantes que tienen que ver con el tema. Esta bastante sucio, pero bueno, es mas bien un esbozo para saber si era capaz de adentrarme en estos mundos jajaj.

PD: para evitar confusiones: SaltarE = Empezar a saltar, SaltarP = Parar de saltar. Tube que hacerlo así para poder usar la animación al caer xD Y si, mejor todo esto en un enum, pero me lié con otras cosas y al final no lo cambie.

Player.as:

package {
	import flash.events.*;
	import flash.display.*;


/**
*@public Clase del Player.
*/
public class Player extends MovieClip {

	public var Estado:String="respirar";
	var gravedad:Number=1.2;
	public var velocidadY:Number=1.1;
	public var velY:Number=0;
	public var velX:Number=0;

	public function Player() {
		x=100;
		y=300;

	}
	//player.x-20, player.y-75, 50,75
	public function PlayerLoop(nivel1_mc:MovieClip) {


		if (rectHit.hitTestObject(nivel1_mc)) {
			velocidadY=0;

			//trace("toca suelo");
			if (Estado=="saltarP") {
				if (velX==0) {
					setEstado("caer");
				} else if (velX > 0) {
					setEstado("correrD");
				} else if (velX < 0) {
					setEstado("correrI");
				}
				velY=0;
			}
		} else {
			if (gravedad==0) {
				gravedad=1.2;
			}
			velocidadY=1.1;
		}

		
		this.x+=velX;
		gravedad*=velocidadY;
		this.y+=gravedad;
		this.y+=velY;

		//trace (velocidad);
	}

	public function setEstado(estado:String) {
		switch (estado) {
			case "respirar" :
				if (Estado!="respirar") {
					gotoAndPlay("respirar");
					Estado="respirar";
				}
				break;
			case "correrD" :
				if (Estado!="correrD" && Estado!="saltarE") {
					gotoAndPlay("correr");
					this.scaleX=1;
					Estado="correrD";
				}
				break;
			case "correrI" :
				if (Estado!="correrI"&& Estado!="saltarE") {
					gotoAndPlay("correr");
					this.scaleX=-1;
					Estado="correrI";
				}
				break;
			case "saltarE" :
				if (Estado!="saltarE") {
					gotoAndPlay("saltarE");
					Estado="saltarE";
				}
				break;
			case "saltarP" :
				if (Estado=="saltarE") {
					gotoAndPlay("saltarP");
					Estado="saltarP";
				}
				break;
			case "caer" :
				if (Estado=="saltarP") {
					gotoAndPlay("caer");
					Estado="respirar";
				}
				break;
			default :
				if (Estado!="respirar") {
					Estado="respirar";
					gotoAndPlay("respirar");
				}
				break;
		}

		trace("Cambio de Estado: " + Estado);

	}
}
}

Proyecto.as:

package {
	import flash.events.*;
	import flash.display.*;

public class Proyecto extends MovieClip {

	var player:Player = new Player();

	var offsetX:int=0;
	var offsetY:int=0;


	public function Proyecto() {

		addChild(player);
		stage.addEventListener(Event.ENTER_FRAME,MainLoop);
		stage.addEventListener(KeyboardEvent.KEY_DOWN, detectKeyDown);
		stage.addEventListener(KeyboardEvent.KEY_UP, detectKeyUp);

	}
	function MainLoop(event:Event) {

		player.PlayerLoop(nivel1_mc);

		if (player.x+offsetX>450) {
			x=x-8;
			offsetX=offsetX-8;
		} else if (player.x+offsetX>360) {
			x=x-4;
			offsetX=offsetX-4;
		}

		if (player.x+offsetX<60) {
			x=x+8;
			offsetX=offsetX+8;
		} else if (player.x+offsetX<120) {
			x=x+4;
			offsetX=offsetX+4;
		}
	}

	function detectKeyDown(event:KeyboardEvent):void {
		if (event.keyCode==39) {
			if (player.x+offsetX<=578) {
				player.velX=4;					
				if (player.Estado!="correrD" && player.Estado!="saltarE") {
					player.setEstado("correrD");
					player.velY=0;
				}
			}
		}
		if (event.keyCode==37) {
			if (player.x+offsetX>=22) {
				player.velX=-4;					
				if (player.Estado!="correrI" && player.Estado!="saltarE") {
					player.setEstado("correrI");
					player.velY=0;
				}
			}
		}
		if (event.keyCode==38 && player.Estado!= "saltarP" && player.Estado!="caer") {
			if (player.Estado!="saltarE") {
				player.setEstado("saltarE");
				player.velY=-6.0;
			}
			
		}
		if (event.keyCode==68) {
			player.setEstado("respirar");
		}
	}
	function detectKeyUp(event:KeyboardEvent):void {
		if (event.keyCode==39) {
			if (player.x+offsetX<=578) {
				player.velX=0;					
				player.setEstado("respirar");
			}
		}
		if (event.keyCode==37) {
			if (player.x+offsetX>=22) {
				player.velX=0;					
				player.setEstado("respirar");
			}
		}
		if (event.keyCode==38&&player.Estado=="saltarE") {
			player.setEstado("saltarP");
			player.velY=0;
		}
		if (event.keyCode==68) {
			player.setEstado("respirar");
		}
	}
}
}

Gracias por adelantado! Saludos!

EnZo

Sin probarlo es muy dificil detectar el error. Puedes publicar el proyecto? Lo haces en Builder?

mTr

Claro, sin problemas! Quieres que suba el .swf a algun sitio, o necesitas el archivo .fla ?

EnZo

El fla si no te da reparo. Así puedo probarlo y depurarlo. Pero no te prometo nada :P

mTr

Entendido! Voy a subirlo a algún sitio. El .swf lo subí mientras esperaba tu respuesta, así que si quieres ir echándole un ojo, aquí te dejo el enlace:

http://www.swfcabin.com/open/1343976416

mTr

ahí va el .fla: http://ul.to/q62qvxda

Gracias por la ayuda!

PD: La especie de "sombra" que tiene el sprite bajo los pies, digamos que es el rectángulo que uso para la colisión, que olvide ocultarlo tras hacer unas cuantas pruebas jeje

B

Y por qué no usas un engine de físicas y te ahorrar ese jaleo?

http://box2dflash.sourceforge.net/

1 respuesta
mTr

Le estuve echando un ojo hace unos días, pero creo que me queda un poco grande. De todas formas me leeré un poco la documentación y probaré a ver que tal. Gracias!

EnZo

Tienes un problema de planteamiento. Aplicas gravedad con velocidad y hace que los calculos no te salgan bien. Yo reharia de nuevo la funcion PlayerLoop. Y tendria solo un valor a incrementar o disminuir.

this.y+=gravedad;
this.y+=velY;

Estas aplicando dos valores a .y en el mismo bucle. Y es lo que hace que te salgan mal los calculos.
Mira este ejemplo como lo hacen: http://www.flashgametuts.com/tutorials/as3/how-to-create-a-platform-game-in-as3-part-1/

Si te fijas solo tiene una variable que incremeta y. Le llama jumpSpeed y que seria el equivalente a tu velY.

De toas formas si vas a hacer un juego medianamente complejo de plataformas yo le haria caso a #7. Al principio te va a costar aprender a usarla pero una vez aprendas te vas a ahorrar el hacer calculos de movimiento y detectar colisiones.

1
mTr

Gracias a los dos, todo claro ahora :) intentaré de ambas formas, aunque empezare con el ejemplo primero, y si me aclaro, pasare a usar la engine, a ver que tal se me da jaja

Saludos!

Usuarios habituales