Help!: Objects in Main


(John) #1

Hello,

I’m pretty new to programming, and even more new to AS3 and FP. In the game I’m making I want to be able to display variables from GameWorld.as in objects created in Main.as. For example, in the following code I have a 160x160px world and a 20px TextField that I’m calling “hudPanel”. What I want do to is to be able to display data from GameWorld.as in that 20px area near the bottom of the screen.

This is probably not the ideal way to create a HUD area at the bottom of the screen, so I’m open to suggestions if anyone has other ideas of how to achieve this.

Main.as:

package 
{
	import flash.display.*;
	import net.flashpunk.*;
	
	[SWF (width = "160", height = "180")]

	public class Main extends Engine 
	{	
		public var hudPanel:TextField;
		
		public function Main()
		{
			super(160, 160, 60, false);
			hudPanel = new TextField();
			hudPanel.text = "Test";
			hudPanel.y = 160;
			addChild(hudPanel);

                        FP.screen.color = 0xFFFFFF;
                 }
		
		override public function init(): void
		{
			FP.world = new GameWorld();
		}
		

	}
	
}

GameWorld.as:

package  
{
	import flash.geom.*;
	import net.flashpunk.*;
	import net.flashpunk.graphics.*;
	import net.flashpunk.utils.*;

	public class GameWorld extends World
	{
                       public var s:String;
                
                        public function GameWorld() 
	                {
                           s = new String("Display this in the hudPanel in Main?");
                        }
         }
}



(Bimbamm) #2

I suggest instead of introducing variables in Main.as you should create them in your GameWorld.as .


(Jonathan Stoler) #3

Yes, I agree. Also, I think you want FlashPunk’s Text class rather than the TextField class. But, depending on your needs, you may have to create your own class (subclass Entity, probably) for additional functionality.

You should also be overriding your GameWorld's begin() function rather than initializing variables in the constructor.

Lastly, you don’t need to explicitly call new String to create a string, quotes will automatically do this on their own.


(John) #4

The primary reason I wanted to have the object in Main instead of GameWorld is because I want that component to operate independent of the camera and I don’t want it to interfere at all with things going on in the GameWorld.

When I create a Text in GameWorld and override begin(), the text will only ever be visible in the 160x160 area declared in Main.


(Jonathan Stoler) #5

I still think, what you want to do is:

  1. Give FlashPunk the entire screen (160x180).
  2. Create a HUDPanel class or use Text if appropriate. Add it in your GameWorld.
  3. Set the scrollX and scrollY properties of your Text to 0 so it isn’t affected by the camera.
  4. Simply don’t add anything below 160px on the y-axis.

I’m really not sure what you mean by this. If you mean visually, then just don’t add anything to the world that overlaps it. If you mean functionally (ie collisions or something else), then you’re gonna have to write the code for that, so just don’t let it interfere.


(John) #6

Ok, so. I took your advice and 1. Gave the whole screen to FlashPunk, 2. Made 2 Classes: I) an entity class for the HUD background, and a HUDCoord class to display the player’s map position.

As it stands right now,I just have the HUD elements moving around WITH the camera because when the player goes off-screen the camera shifts and the background and Coords get “left behind”. Here’s what I have(keep in mind what I said in my first post about being new at this):

Main.as:

package 
{
	import flash.display.*;
	import flash.text.TextField;
	import net.flashpunk.*;
	
	[SWF (width = "640", height = "480")]

	public class Main extends Engine 
	{		
		public function Main()
		{
			super(1600, 1200, 60, false);
		
			FP.screen.color = 0xFFFFFF;
			FP.console.enable();
			FP.screen.scale = 2;
				
		}
		
		override public function init(): void
		{
			FP.world = new GameWorld();
		}
		

	}
	
}

GameWorld.as:

package  
{
	import flash.geom.*;
	import net.flashpunk.*;
	import net.flashpunk.graphics.*;
	import net.flashpunk.utils.*;

	public class GameWorld extends World
	{
		
		[Embed(source = "assets/grid_background_1600.png")] public const BACKGROUND1:Class;
		[Embed(source = "assets/grid_game.oel", mimeType = "application/octet-stream")] public const LEVEL_MAP:Class;

public var level:Level;
		
public var time:int;		

public var xmlList:XMLList; 
public var place:XML;

public var player:Player;

public var hudPanel:Hud;
public var textBox:HudCoords;

public var xCoord:String;
public var yCoord:String;
public var currentArea:String;

public function GameWorld() 
	{
	
                level = new Level(LEVEL_MAP);
		player = new Player(new Point(0,0));
		hudPanel = new Hud();
		textBox = new HudCoords();
	        loadMap();
         }

public function loadMap(): void
		{
	
			xmlList = level.xml.entities.player;
			for each (place in list) 
			{
				add (player);
			}
                        add(hudPanel);
			add(hudWindow);
			add(level);
                 } 

public function get hudWindow():HudCoords
		{
			return textBox;
		}

override public function update (): void
	{ 
	super.update();
			
			
			
			
	if (player.x <= 304)
	{
	        camera.x = 0;
	        xCoord = "A";

			}
			
	if (player.y <= 176)
	{
	camera.y = 0;
	yCoord = "1";
	}
			
if (Input.pressed(Key.DOWN))
{
	switch(true)
	{
           case player.y > 176 && player.y <= 240: player.y = 240; break;
           case player.y > 416 && player.y <= 480: player.y = 480; break;
           case player.y > 656 && player.y <= 720: player.y = 720; break;
	   case player.y > 896 && player.y <= 960: player.y = 960; break;
	}
}
			
if (Input.pressed(Key.UP))
{
	switch(true)
	{
	   case player.y < 240 && player.y >= 176: player.y = 176; break;
	   case player.y < 480 && player.y >= 416: player.y = 416; break;
	   case player.y < 720 && player.y >= 656: player.y = 656; break;
	   case player.y < 960 && player.y >= 896: player.y = 896; break;
        }
}


					
	currentArea = xCoord + yCoord;
			
switch(true)
			
{
case player.x > 304 && player.x <= 624: camera.x = 320, xCoord = "B"; break;
case player.x > 624 && player.x <= 944: camera.x = 640, xCoord = "C"; break;
case player.x > 944 && player.x <= 1264: camera.x = 960, xCoord = "D"; break;
case player.x > 1264 && player.x <= 1584: camera.x = 1280, xCoord = "E"; break;
}
			
switch(true)
			
{
case player.y > 176 && player.y <= 464: camera.y = 240, yCoord = "2"; break;
case player.y > 416 && player.y <= 704: camera.y = 480, yCoord = "3" ; break;
case player.y > 656 && player.y <= 944: camera.y = 720, yCoord = "4" ; break;
case player.y > 896 && player.y <= 1184: camera.y = 960, yCoord = "5" ; break;
}

	hudWindow.addText(currentArea);
	hudWindow.x = camera.x;
	hudWindow.y = camera.y + 192;
	hudPanel.x = camera.x;
	hudPanel.y = camera.y + 192;					
			
        }
    }
}

Player.as:

package  
{
	import flash.display.*;
	import flash.geom.*;
	import net.flashpunk.*;
	import net.flashpunk.graphics.*;
	import net.flashpunk.utils.*;

	public class Player extends Entity
	{
		private var speed:Number = 16;
		
		public var picture:BitmapData = new BitmapData(16, 16, false, 0x0D2036);
		
		public var q:Array = new Array("solid");
		
		public function Player(position:Point) 
		{

			x = position.x;
			y = position.y;
			
			Draw.setTarget(picture);
			Draw.rectPlus(2, 2, 13,13, 0X69AAF5, 1, true, 1, 0);

			graphic = new Stamp(picture);
			
		

			setHitbox(16, 16);
			layer = -1;
			type = "solid";
		}
		
		override public function update (): void
		{
			super.update();
			
			if (Input.pressed(Key.UP))
				{
					if (!collideTypes(q,x,y-1))
					{
						this.y -= speed;
					}
				}
			
			if (Input.pressed(Key.DOWN))
				{
					if (!collideTypes(q,x,y+1))
					{
						this.y += speed;
					}			
				}
			
			if (Input.pressed(Key.RIGHT))
				{
					if (!collideTypes(q,x+1,y))
					{
						this.x += speed;
					}
				}
				
			if (Input.pressed(Key.LEFT))
				{
					if (!collideTypes(q,x-1,y)) 
					{
						this.x -= speed;
					}
				}
				
				
			if (this.x < 0)
			{
				this.x = 0;
			}
			
			if (this.y < 0)
			{
				this.y = 0;
			}
			
			if (this.x > 1584)
			{
				this.x = 1584;
			}

			if (this.y > 1136)
			{
				this.y = 1136;
			}


		}
		
	}

}

HudCoords.as

package  
{
	import net.flashpunk.Entity;
	import net.flashpunk.graphics.Text;

	public class HudCoords extends Entity
	{
		private var display:String;
		
		public function HudCoords() 
		{
			
			var txt:Text = new Text("", 0, 0);
			splashText.color = 0x888888;
			
			
			graphic = txt;

			setHitbox(320, 48);
			layer = -3
			type = "hud";
			
		
		}
		
		public function addText(coords:String):void
		{
			display = coords;
			Text(graphic).text = coords;
		}
		
	}

}

Hud.as:

package  
{
	import flash.display.*;
	import net.flashpunk.*;
	import net.flashpunk.graphics.*;
	
	public class Hud extends Entity
{
		
public function Hud()
{
			
			
var image:Image = new Image(new BitmapData(320, 48, false, 0x0));
var inner:Image = new Image(new BitmapData(319, 46, false, 0x131313));
var display:Graphiclist = new Graphiclist(image,inner);
			
graphic = display;
layer = -2;
}

		
}

}

(Jonathan Stoler) #7

Okay, first I’m going to try to address your actual question and then I’ll comment on the rest of your code.

In Hud, I think you want to do the following:

display.scrollX = 0;
display.scrollY = 0;

to make them stay in place even when the camera moves.

In HudCoords, you’ll want to do similar:

txt.scrollX = 0;
txt.scrollY = 0;

Now, about the code in general.

Main.as

Your Main class looks okay. Typically I don’t like using the * selector in my imports but that’s completely personal preference.

GameWorld.as

Now, GameWorld. Personal preference again, but I usually create a separate Assets class to statically store all my Embeds but that’s totally up to you; it just seems cleaner and easier to me.

I would recommend you override World's begin() function and initialize all your variables there. This is based off a note I heard from someone once that a lot of compilers will not optimize initializer functions but will optimize normal functions (like begin()). Either way, it doesn’t cost anything, and this way you can be sure that all the World variables are initialized and your World is ready to go before you start changing variables.

Your time variable is unused.

I really don’t understand why you’ve opted for a getter function of hudWindow when it simply returns textBox. Usually getters are used either when you want to make a private property read-only, or if some special calculation needs to be done before returning the variable.

In this case, there’s no reason why you can’t just rename textBox to be hudWindow. This is what I would recommend; there’s no point writing a getter and complicating your code if a variable will do.

In your update() function, you call super.update() at the very beginning. Usually you want this at the end instead, and I think you do in this case as well.

When checking for inputs in the way it seems your game works, you usually want to use if ... else statements rather than a bunch of ifs stacked together. Not only will this unmeasurably improve your performance, it more importantly will prevent the player from pressing multiple keys in one frame and potentially messing things up - although with your current code, it looks like this wouldn’t really cause a problem.

I wouldn’t typically use switch statements like this, and would use if ... else instead, but your code technically works. I think, as your code gets more complex, switch statements like this will begin to weigh you down. But it’s up to you.

With the new modifications to Hud, you no longer need to mess with hudWindow's coordinates at the end of your update() function.

Player.as

Instead of having Player take a Point as an argument, I would use x and y as two Number arguments, but that’s just how I do things. It would save you from having to create (and import) Point in every class where you want to add a Player object.

You should call Draw.resetTarget() after you’re done using it for the Player class.

Same notes apply as before with super.update() and keyboard inputs.


Now, a note about how you’ve structured your Hud classes.

I don’t see why you need 2 separate classes for this. Why not create a single Hud class which draws both the background and the text?

Okay, moving on…


HudCoords.as

This class is honestly a bit of a mess. As far as I can tell, either you edited it before posting, or it just doesn’t work and shouldn’t compile.

You change the color of splashText, which doesn’t exist. Presumably you mean txt?

You don’t need to change an Entity's graphic to draw to an Entity. You can use addGraphic() instead. Note these do two different things but end up with the same result; it’s your call.

You’re missing a semicolon after layer = -3.

addText, I think, should have this:

txt.text = coords;

instead of your current

Text(graphic).text = coords;

which I suspect doesn’t work (unless there’s some crazy casting going on here that I’m not understanding).

Hud.as

This looks fine.


A general note:

It could have something to do with pasting it into a forum, but your code looks very messy. There’s inconsistent tabbing and lots of random whitespace. This, of course, compiles just fine, but it’s difficult to read and will become difficult to manage as you write a larger volume of code. I would recommend cleaning it up now before it gets out of control. (A lot of IDEs/programming text editors have a built-in function to automatically tidy up for you, though obviously you won’t have the same level of control as doing it yourself.)


Hope this helps! Sorry to barrage you with a giant wall of text, I hope you can at least learn something from it though. Let me know if you have any questions or want things explained further.


(John) #8

Sorry to barrage you with a giant wall of text, I hope you can at least learn something from it though.

I was concerned that posting so much messy code would discourage anyone from replying, but you took the time to go through my code and I appreciate it!

I) Part of the reason why I truncated(*) the imports was so to keep things minimal; this is also the reason I left out my Assets.as and put the embeds right near the relevant code. As for the formatting (white space, unaligned codeblocks, etc.) that just happened because of copy+pasting the code here. sorry about that.

  1. I will use override begin() to initialize variables from here on.

3)time is going to be used for some entities that I’ve been thinking about but haven’t implemented yet. It should have been commented out.

  1. Is there a reason why calling super.update() should be called at the end of the update() functions? I’ve seen a number of examples where it is called at the beginning.

  2. I will try to get the Hud class cleaned up and I’ll get everything happening in one class with the scrollXand scrollY set to 0 so that they stay fixed.

Overall I will fix this and post the changes once they’re working and everything is cleaned up.

Thanks again for taking the time and being so thorough. It’s really nice to have some feedback here.


(Jonathan Stoler) #9

Yeah, that’s fine. It honestly doesn’t make a difference. Do whatever you want.

You might run into this once you actually use it, but depending on what time is used for, you might want a uint or Number instead of int.

Honestly, I’m not sure I’m the right person to explain this. But I’ve always done it this way and it’s never caused any problems. I suppose there are reasons to do it either way.

But I always feel like I should update my subclass (so color changes, x and y, etc.) before calling super, which then will account for those changes eventually when it reaches Entity. Depending on how you set things up, though, this can mean that super can overwrite those changes with its own changes.

That’s my thought process about this, but there might be a better explanation for either side. It works both ways, but I always feel like if you call it first, then you’re delaying your changes by one frame (not sure if this is actually true or not).

No problem, I’m always excited to see people trying to learn this stuff. Even better when they have the humility to ask for help (and then actually try to improve afterwards). Good luck!


(John) #10

Here’s my new HUD. It works perfectly thank you. Is there anyway to set the scroll and scrollY of the Hitbox to 0? I understand that the hitbox doesn’t use scrollX and scrollY but it would be nice if there were an elegant way to make sure that it “stuck” to the graphic.

package  
{
	import flash.display.*;
	import net.flashpunk.*;
	import net.flashpunk.graphics.*;
	
	public class Hud extends Entity
	{
		public var txt:Text;
		public var background:Image;
		public var display:Graphiclist;
		
		public function Hud()
		{	
			txt = new Text("", 0, 0);
			background = new Image(new BitmapData(320, 48, false, 0x111000));
			display = new Graphiclist(background, txt);
			txt.color = 0x888888;
			layer = -3;
			graphic = display;
			graphic.scrollX = 0;
			graphic.scrollY = 0;
			this.y = 192;

		}

		public function addText(coords:String):void
		{
			txt.text = coords;
		}	

	}

}

(JP Mortiboys) #11

If you’re hit-testing the HUD elements against the mouse position, use Input.mouseX and Input.mouseY instead of world.mouseX / world.mouseY, and it will ignore the camera (scroll) position.