Posts for henke37


Editor, Experienced Forum User
Joined: 3/10/2010
Posts: 899
Location: Sweden
But the point is here isn't the license. It is the fact that the game has several sets of freestanding episodes. The first one is free.
Editor, Experienced Forum User
Joined: 3/10/2010
Posts: 899
Location: Sweden
You should try using frame advance and calculating delta values for the position when working with motion.
Editor, Experienced Forum User
Joined: 3/10/2010
Posts: 899
Location: Sweden
TheMG2 wrote:
Monkey Ball does not have RNG, but it does have some very weird collision that feels like luck. If you hit something at a slightly different speed or angle (or time when the objects are moving), you could get a radically different bounce.
Sounds like typical physics. With extreme enough situations it might as well be random, video game or not. The game doesn't seem to be in need of invisible walls quite as much, but that doesn't mean that this tas was bad. It's great.
Editor, Experienced Forum User
Joined: 3/10/2010
Posts: 899
Location: Sweden
This game needs more invisible walls. A lot more.
Editor, Experienced Forum User
Joined: 3/10/2010
Posts: 899
Location: Sweden
Uhm, it's a minimum score run. Golf is about having a low score.
Editor, Experienced Forum User
Joined: 3/10/2010
Posts: 899
Location: Sweden
Correct judging for a golf TAS should be either score or entertainment, not time. This movie has a great score and does some nice trick shots. But what about hole number 10? Couldn't you do something more entertaining there? And there is nothing wrong with entering your name at the end, I actually prefer it when people take the time to do so.
Editor, Experienced Forum User
Joined: 3/10/2010
Posts: 899
Location: Sweden
I think I will stick with good old icepunch.swf instead.
Editor, Experienced Forum User
Joined: 3/10/2010
Posts: 899
Location: Sweden
Does it give a headstart? Then it's NG+. And in either case verification is required.
Editor, Experienced Forum User
Joined: 3/10/2010
Posts: 899
Location: Sweden
Corrupting memory like a pro!
Editor, Experienced Forum User
Joined: 3/10/2010
Posts: 899
Location: Sweden
That trinket is special cased when in no death mode to make it possible to get without dying.
Editor, Experienced Forum User
Joined: 3/10/2010
Posts: 899
Location: Sweden
I vote that we hack the pool options to replace yes with "Awesome".
Editor, Experienced Forum User
Joined: 3/10/2010
Posts: 899
Location: Sweden
Here is a probability mess: A parser for a fictional bytecode format has gotten desyncronized. Given a certain distribution (your answer should work no matter what it is) between instructions with various lengths, how many instructions on average need to be decoded before the parser resynchronizes by dumb luck?
Editor, Experienced Forum User
Joined: 3/10/2010
Posts: 899
Location: Sweden
It is a rather trivial API to stub. Most games will just accept the calls doing nothing. Or we could log them and edit in fake achievement popups.
Editor, Experienced Forum User
Joined: 3/10/2010
Posts: 899
Location: Sweden
The problem is that using a library doesn't mean that the task is done for me. A library is just an aid. Not a solution. Someone still has to hook it up, deal with the resulting issues and in general tune it.
Editor, Experienced Forum User
Joined: 3/10/2010
Posts: 899
Location: Sweden
I just want to hand this over to someone else permanently. I don't like platforming code and just want to move on to more important parts of the project.
Editor, Experienced Forum User
Joined: 3/10/2010
Posts: 899
Location: Sweden
The thing is, I know not to do that. I just don't know a good alternative.
Editor, Experienced Forum User
Joined: 3/10/2010
Posts: 899
Location: Sweden
Easy, it's impossible if N is less than size and guaranteed if it is at least six.
Editor, Experienced Forum User
Joined: 3/10/2010
Posts: 899
Location: Sweden
I don't mean stability as in "won't crash", but stability as in "objects won't suddenly break the sound barrier or vibrate".
Editor, Experienced Forum User
Joined: 3/10/2010
Posts: 899
Location: Sweden
I am not a fan of "physics engines". They don't provide stable systems. And I am worried about performance when dealing with levels large enough to take more than a few seconds to cross.
Editor, Experienced Forum User
Joined: 3/10/2010
Posts: 899
Location: Sweden
Manipulating RNG entropy is one thing. Trying to pass of several hours of preparation as unimportant unranked time is another.
Editor, Experienced Forum User
Joined: 3/10/2010
Posts: 899
Location: Sweden
The default state is considered ok because it's an obvious nothing up my sleeve number. It is obvious that it wasn't selected for the purpose of cheating in a TAS.
Editor, Experienced Forum User
Joined: 3/10/2010
Posts: 899
Location: Sweden
I tried doing x and y movement in one go. It didn't work well. The player kept getting stuck in the ground. And I do not think that the code structure is wrong. The code is specific to the entity, so there is no other place where it belongs. And yes, I do know of pastebins, but I figured that it wasn't worth the effort here, since code pasting works fine.
Editor, Experienced Forum User
Joined: 3/10/2010
Posts: 899
Location: Sweden
The problem is that I don't even understand what is wrong. I at least need help debugging my code. EDIT: Here is my code.
package CopperCrew.Gameplay.PlayerStates {
	import CopperCrew.Gameplay.*;
	import CopperCrew.Gameplay.Entities.*;
	import CopperCrew.Controls.*;
	
	import HTools.Math.sgn;
	
	use namespace playerInternal;
	
	public class PlayerState {
		
		protected var maxXSpeed:Number=15;
		protected var maxYSpeed:Number=Infinity;
		
		protected var runSpeed:Number=10;
		
		protected var forwardAccl:Number=0.2;
		protected var backwardAccl:Number=-2;
		protected var coastAccl:Number=-0.2;
		
		protected var gravity:Boolean=true;
		protected var gravityAccl:Number=0.8;
		
		protected var canJump:Boolean=true;
		protected var jumpImpulse:Number=17;
		
		protected var player:Player;
		
		protected var animName:String;
		protected var animLoops:Boolean=true;
		protected var autoMirror:Boolean=true;

		public function PlayerState(player:Player) {
			if(!player) throw new ArgumentError("Player can't be null!");
			this.player=player;
		}
		
		public function init():void {
			player.char.currentAnimName=animName;
			player.char.currentAnimInst.loop=animLoops;
		}
		public function deinit():void {}
		
		public function pretick():void {
			selectState();
		}
		
		public function tick():void {
			xMovement();
			yMovement();
		}
		
		protected function selectState():void {
			const absSpeed:Number=Math.abs(player.xSpeed);
			if(player.onFloor) {
				if(absSpeed<0>=runSpeed){
					player.setState("run");
				} else {
					player.setState("walk");
				}
			}
		}
		
		protected function xMovement():void {
			horizontalControl();
			
			//cap the speed
			if(player.xSpeed>maxXSpeed) { player.xSpeed=maxXSpeed; }
			else if(player.xSpeed< -maxXSpeed) { player.xSpeed= -maxXSpeed; }
			
			if(autoMirror) {
				if(player.xSpeed<0>0) {
					player.char.scaleX=1;
				}
			}
			
			player.x+=player.xSpeed;
			
			player.applyCollisions(true,false);
		}
		
		protected function yMovement():void {
			if(canJump && player.onFloor) {
				jumpControl();
			}
			
			if(gravity) {
				player.ySpeed+=gravityAccl;
			}
			
			player.onFloor=false;
			
			if(player.ySpeed>maxYSpeed) { player.ySpeed=maxYSpeed; }
			else if(player.ySpeed< -maxYSpeed) { player.ySpeed= -maxYSpeed; }
			
			player.y+=player.ySpeed;
			
			player.applyCollisions(false,true);
		}
		
		protected function horizontalControl():void {
			var xDir:int=sgn(player.xSpeed);
			
			var controlXDir:int=0;
			
			if(controls.kDown(Keys.LEFT)) {
				controlXDir--;
			}
			if(controls.kDown(Keys.RIGHT)) {
				controlXDir++;
			}
			
			if(xDir==0) xDir=controlXDir;
			
			if(controlXDir==0) {
				player.xSpeed+=xDir*coastAccl;
			} else if(controlXDir==xDir) {			
				player.xSpeed+=xDir*forwardAccl;
			} else if(controlXDir==-xDir) {
				player.xSpeed+=xDir*backwardAccl;
			}
			
			if(Math.abs(player.xSpeed)<0.1) player.xSpeed=0;
		}
		
		protected function jumpControl():void {
			var yDir:int=sgn(player.ySpeed);
			
			if(controls.kHit(Keys.JUMP)) {
				player.ySpeed-=jumpImpulse;
				if(Math.abs(player.xSpeed)<runSpeed) {
					player.setState("jump");
				} else {
					player.setState("jump");
				}
			}
		}
		
		public function get name():String { return "Base State"; }
		
		protected final function get controls():Controls { return player.controls; }
	}
}
package CopperCrew.Gameplay.Entities {
	
	import starling.display.*;
	import starling.events.*;
	
	import CopperCrew.Chars.Man.Man;
	import CopperCrew.Chars.Woman.Woman;
	import CopperCrew.Chars.Robot.Robot;
	import CopperCrew.Chars.BaseChar;
	
	import CopperCrew.Chars.Markers.*;
	
	import CopperCrew.Controls.*;
	import CopperCrew.Gameplay.PlayerStates.*;
	import CopperCrew.Gameplay.*;
	
	import HTools.Starling.*;
	import HTools.Starling.Tilemap.*;
	
	import flash.geom.Rectangle;
	import flash.display.DisplayObject;
	
	use namespace playerInternal;
	
	public class Player extends GameEntity {
		
		public var char:BaseChar;
		
		private var state:PlayerState;
		private var states:Object;
		
		playerInternal var xSpeed:Number=0;
		playerInternal var ySpeed:Number=0;
		
		playerInternal var onFloor:Boolean;

		public function Player(gameplay:Gameplay) {
			super(gameplay);
			cameraIntrest=100;
			name="player";
			
			loadPlayerChar("robot");
			
			loadStates();
			setState("idle");			
		}
		
		private function loadPlayerChar(charName:String) {
			var cl:Class={woman:Woman, man:Man, robot:Robot}[charName];
			if(!cl) throw new ArgumentError("Bad character name");
			char=new cl();
			vis=char;
		}
		
		public override function tick():void {
			state.pretick();
			state.tick();
			
			char.tick();
		}
		
		playerInternal function applyCollisions(xDir:Boolean,yDir:Boolean):void {
			const basePlatformingBox:Rectangle=currentPlatformingBox;
			var platformingBox:Rectangle=basePlatformingBox.clone();
			platformingBox.x+=x;
			platformingBox.y+=y;
			
			if(yDir) {
				checkFloor(platformingBox);
			}
			
			if(xDir) {
				checkWall(platformingBox,-1);
				checkWall(platformingBox,1);
			}
			
			x=platformingBox.x-basePlatformingBox.x;
			y=platformingBox.y-basePlatformingBox.y;
		}
		
		private function checkFloor(platBox:Rectangle):Boolean {
			const tileMap:ITileMap=gameplay.level.bgTileMap;
			const tileWidth:Number=gameplay.level.bgTileSet.tileWidth;
			const tileHeight:Number=gameplay.level.bgTileSet.tileHeight;
			
			const leftTile:int=platBox.left/tileWidth;
			const endTile:int=Math.ceil(platBox.right/tileWidth)+1;
			const tileY:int=platBox.bottom/tileHeight;
			
			var tileRect:Rectangle=new Rectangle(0,tileY*tileHeight,tileWidth,tileHeight);
			
			var hit:Boolean=false;
			
			for(var tileX:int=leftTile;tileX<endTile;tileX++) {
				var endLoop:Boolean=false;
				var tileData:TileData=tileMap.tileAt(tileX,tileY);
				if(!tileData) continue;
				
				tileRect.x=tileX*tileWidth;
				var intersection:Rectangle=tileRect.intersection(platBox);
				if(intersection.width==0) continue;
				
				var tileInfo:TileSetTileData=gameplay.level.bgTileSet.tiles[tileData.tileId];
				
				//trace("Floor collision",tileRect);
				
				var solid:Boolean=false;
				if(tileInfo.attributes.solid) solid=true;
				
				if(tileInfo.attributes.floor) {
					if(tileInfo.attributes.oneWayFloor) {
						if(ySpeed>=0) solid=true;
					} else {
						solid=true;
					}
				}
				
				if(solid) {
					
					//nudge the platBox up to one pixel above the tileRect
					platBox.y-=intersection.height;
					
					ySpeed=0;//hitting solid ground imedetly cancels the y speed
					//endLoop=true;// won't be any other hits, since only one row was scanned
					hit=true;
					onFloor=true;
					
					dispatchEventWith("floorHit");
				}
				
				
				if(endLoop) break;
			}
			
			return hit;
		}
		
		private function checkWall(platBox:Rectangle,dir:int):Boolean {
			const tileMap:ITileMap=gameplay.level.bgTileMap;
			const tileWidth:Number=gameplay.level.bgTileSet.tileWidth;
			const tileHeight:Number=gameplay.level.bgTileSet.tileHeight;
			
			const startY:int=platBox.top/tileHeight;
			const endY:int=Math.ceil(platBox.bottom/tileHeight);
			
			const tileX:int=(
				(dir==-1)?
				Math.floor(platBox.left/tileWidth):
				Math.floor(platBox.right/tileWidth)
			);
			
			var hit:Boolean=false;
			
			
			var tileRect:Rectangle=new Rectangle(tileX*tileWidth,0,tileWidth,tileHeight);
			
			for(var tileY:int=startY;tileY<endY;++tileY) {
				var endLoop:Boolean=false;
				
				var tileData:TileData=tileMap.tileAt(tileX,tileY);
				if(!tileData) continue;
				
				tileRect.y=tileY*tileHeight;
				var intersection:Rectangle=tileRect.intersection(platBox);
				if(intersection.height==0) continue;
				
				var tileInfo:TileSetTileData=gameplay.level.bgTileSet.tiles[tileData.tileId];
				
				//trace("Wall collision",tileRect);
				
				var solid:Boolean=false;
				
				if(tileInfo.attributes.solid) solid=true;
				if(tileInfo.attributes.wall) solid=true;
				
				if(solid) {
					
					if(dir==-1) {//moving left
						platBox.x+=intersection.width;
					} else {//moving right
						platBox.x-=intersection.width;
					}
					
					xSpeed=0;
					endLoop=true;// won't be any other hits, since only one row was scanned
					hit=true;
					
					dispatchEventWith("wallHit");
				}
					
					
				if(endLoop) break;
			}
			return hit;
		}
		
		playerInternal function get currentPlatformingBox():Rectangle {
			const markers:Vector.<MarkerData>=char.markers;
			
			for each(var marker:MarkerData in markers) {
				if(!marker) continue;
				if(marker.type=="Platforming") {
					return Rectangle(marker.marker);
				}
			}
			
			return null;
		}
		
		private function loadStates():void {
			states={
				"idle": new IdleState(this),
				"walk": new WalkState(this),
				"run":  new RunState(this),
				"jump": new JumpState(this),
				"fall": new FallState(this)
			};
		}
		
		public function setState(stateName:String):void {
			if(state && state.name==stateName) return;
			
			var newState:PlayerState=states[stateName];
			if(!newState) throw new ArgumentError("Invalid player state name!");
			
			if(state) {
				state.deinit();
			}
			
			state=newState;
			
			state.init();
		}
		
		playerInternal function get controls():Controls { return gameplay.controls; }
		
		public override function get debugReprensentation():flash.display.DisplayObject {
			return char.makeDebugReprensentation();
		}

	}
	
}
I don't get why I sometimes get stuck in walls and/or floors.
Editor, Experienced Forum User
Joined: 3/10/2010
Posts: 899
Location: Sweden
Right now they are just solid rectangles on a grid. I hope to at least get some sloped tiles too.
Editor, Experienced Forum User
Joined: 3/10/2010
Posts: 899
Location: Sweden
Preexisting solutions don't work with my tilemap system. Nor my animation system. And I don't trust generic physics engines for platforming code, they are too unstable.