I'm doing a simple jumper game and have problem with collisions. In project I have Player and Platform Class. The player is overriding shouldCollide(Fixture fixtureA, Fixture fixtureB) method. My questions is, if there a way to get with fixtureA and fixtureB is the player collide with platform? I read demos at github of libgdx, but project there(Superjumper) it seems isin't using a box2D so i'm little consufed about how i should proper make collision in my project.
My current shouldCollide looks now like this:
#Override
public boolean shouldCollide(Fixture fixtureA, Fixture fixtureB) {
if(fixtureA == fixture || fixtureB == fixture){
return body.getLinearVelocity().y< 0;
}
return false;
}
Comparing both fixtures(A and B) with fixture can show me if player is one of "collision makers"(sorry for that but i cannot find proper word in english) only becouse its defined in Player class same like method.
I found that i can add string to userData in Fixture in my Platform Class, then in shoudCollide I must only get that userData, i wonder if its good way to do this.
I found that i can add string to userData in Fixture in my Platform Class, then in shoudCollide I must only get that userData, i wonder if its good way to do this.
Actually you can put any Object in your user data.
In case you really have only platform and player, you might do something like the following. Please note that this is just a quick demonstration and it doesn't cover all cases (like player vs player collision, or platform vs platform collision). For more complicated scenarios, you'd probably have to find a more generic algorithm which works using reflection.
Player player = ...;
playerFixture.setUserData(player);
Platform platform = ...;
platformFixture.setUserData(platform);
...
#Override
public boolean shouldCollide(Fixture fixtureA, Fixture fixtureB) {
if (fixtureA.getUserData() != null && fixtureB.getUserData() != null) {
Player player;
Platform platform;
if (fixtureA.getUserData() instanceof Player) {
player = fixtureA.getUserData();
platform = fixtureB.getUserData();
} else {
player = fixtureB.getUserData();
platform = fixtureA.getUserData();
}
// now you have full access to the player and the platform
}
return false;
}
For a collision filter this might be a bit too overpowered, but as soon as you have to implement collision handlers, you will need to have the real entities, instead of just Strings.
Related
I am having some issues with AS3 Object Arrays. I am trying to make an inventory system, which the user can navigate left and right (which is working). When the user presses ENTER the item should then equip.
I was going to use switch and case to equip the items, as there will only be around 8 items to the game. I get the result [object purpleSword] when using trace, but my switch isn't getting any results or firing anything. I need the equipItem function to find the purpleSword that's ben found in the arrayItems. Items are added to the arrayItems when picked up off the floor.
Does anyone have any tips for using Objects for an RPG inventory system? Many thanks in advance.
public var arrayItems: Array = new Array();
if (keyEvent.keyCode == Keyboard.ENTER) {
if (currentScreen == "inventory") {
if(inventoryCurrent >= 0) {
var actualCurrentItem = inventoryCurrent - 1;
equipItem(arrayItems[actualCurrentItem]);
}
}
}
public function equipItem(itemNumber) {
switch(itemNumber) {
case "purpleSword":
trace("equip purple sword");
break;
}
}
AS3 has a type system, you should use it to help you understand your own errors, and help others understand your code (like us).
Given the fact that you say your output gives you [object purpleSword] I can assume you have a class purpleSword. My guess is that this is an exported symbol, not a .as class file, but it could be either.
But those are all guesses because you haven't provided any type information. For example:
arrayItems:Array could contain anything, and you haven't told us what. You could use a items:Vector.<Object> to store objects, or Vector.<Sprite> to store symbols exported from your Flash library, or better yet create an InventoryItem class and use a Vector.<InventoryItem> to store them.
var actualCurrentItem should be var actualCurrentItem:int
equipItem(itemNumber) should be equipItem(itemNumber:int):void?
If you do this, you will realize (either through your own observation or the compiler telling you) that your equipItem() function is wrong: it expects an itemNumber but it will receive an object.
If my prior assumptions were correct, you could do this:
public var items:Vector.<Object> = new <Object>[];
if (keyEvent.keyCode == Keyboard.ENTER) {
if (currentScreen == "inventory") {
if(inventoryCurrent >= 0) {
var actualCurrentItem:int = inventoryCurrent - 1;
equipItem(items[actualCurrentItem]);
}
}
}
public function equipItem(item:Object):void {
switch(item.constructor) {
case purpleSword:
trace("equip purple sword");
break;
}
}
This works because Object/constructor is a reference to the class of any object, ie purpleSword class, etc. However, you really should use something more concrete than Object, which could be any kind of object and tells you nothing about what kind of properties it might have.
This is mostly a question about code design. What you see here is a very condensed version of the original code.
An example of the code is:
player.rest();
This makes the player sleep.
I have other methods such as walk, run, talk etc. which all work great. The one that is a problem is polymorph. It changes the player from a human object to another object. The solution I came up with is this:
class main
{
var human:Human = new Human;
var alien:Alien = new Alien;
var cow:Cow = new Cow;
var player = human;
enterframe loop{
//other code
if (player does something)
player.polymorph = "alien";
switch (player.polymorph)
{
case "alien":
player = alien;
break;
case "cow":
player = cow;
break;
//etc
}
player.update();
}
}
I want something that looks like this:
class main
{
var human:Human = new Human;
var alien:Alien = new Alien;
var player = human;
enterframe loop
{
player.polymorph(alien);
}
}
I know my original solution is the wrong way to go about things as it encourages spaghetti code. How could I do it differently? I don't mind a whole rewrite, but need an example to help push me in the right direction. I hope this makes sense and thanks for the help.
If the second one can work, what would the polymorph function look like?
I thought of making a class called player and changing what that extends, but to my knowledge that can't be done? Plus I would like to change the character to something already in game rather than a new object.
One solution to your problem would be using a single class, in this case, your Player class, and a finite state machine. You'd have a Player class, which can be set to different states, such as HUMAN, ALIEN, COW, etc. When a polymorph event occurs you update the Player's state, perhaps by calling an initState() method, and handle the logic for being a human, alien, cow, accordingly in whatever method updates your player.
Assuming the player has an update() method it could contain the following:
switch (state) {
case ALIEN:
// do alien stuff
case COW:
// do cow stuff
case HUMAN:
// do human stuff
}
Next, instead of handling the various polymorph states in a switch statement, your Player class could have a polyMorph method that takes a state as a parameter:
public function polymorph(newState:Int) {
state = newState;
initState(state); // You could even just call the initState method instead, and completely omit the polymorph method
}
Using a finite state machine here would eliminate the need for numerous objects.
I have been using Mvvmcross to develop Android application. I am dealing with the issue of ViewModel lifecycle during a rotation. It seems that generally ViewModel is preserved during a rotation. However this is not the case when I present ViewModels in MvxTabActivity. When the rotation happens it always calls a ViewModel constructor.
I have used similar code structure as in N+1 tutorial https://github.com/slodge/NPlus1DaysOfMvvmCross/tree/master/N-25-Tabbed.
Is there a way to modify this tutorial to keep ViewModels in memory during rotation when using MvxTabActivity?
The default ViewModel caching which attempts to workaround the Android rotation behaviour is based around IMvxSingleViewModelCache - so it's not too surprising it can't cope with multiple Activities and multiple ViewModels.
For where this interface is declared and used, see https://github.com/slodge/MvvmCross/search?q=IMvxSingleViewModelCache&ref=cmdform
If this behaviour is troubling you, then you should be able to work around it by one of :
1. Use fragment based tabs rather than Activity based ones
Android handles Fragment lifecycle differently to Activity ones.
2. Or continue using activity based tabs, but implement your own IMvxSingleViewModelCache
It should be simple, for example, to identify your child view models with by their 'Child' naming convention.
With this done you can then implement something like:
public class MyCustomViewModelCache
: IMvxSingleViewModelCache
{
private const string BundleCacheKey = "__mvxVMCacheKey";
private int _counter;
private IMvxViewModel _currentViewModel;
public void Cache(IMvxViewModel toCache, Bundle bundle)
{
if (toCache != null
&& toCache.GetType().Name.StartsWith("Child"))
{
// don't worry about caching child view models
return;
}
_currentViewModel = toCache;
_counter++;
if (_currentViewModel == null)
{
return;
}
bundle.PutInt(BundleCacheKey, _counter);
}
public IMvxViewModel GetAndClear(Bundle bundle)
{
var storedViewModel = _currentViewModel;
_currentViewModel = null;
if (bundle == null)
return null;
var key = bundle.GetInt(BundleCacheKey);
var toReturn = (key == _counter) ? storedViewModel : null;
return toReturn;
}
}
This class based on MvxSingleViewModelCache.cs with just one small addition.
You can register an instance of this class as the IMvxSingleViewModelCache singleton during the InitializeLastChance of your Setup.
Mvx.RegisterSingleton<IMvxSingleViewModelCache>(new MyCustomViewModelCache());
With this done, the home/tab activity should (I think) continue to work - and it'll pass the viewmodels down to the tab children after rotation.
(Other possibilities for IMvxSingleViewModelCache are possible - e.g. it could cache multiple view models - but please don't let it cache too many view models for too long or you may run into 'out of memory' conditions)
3. Or switch the Android rotation handling off
If you add the android:configChanges="orientation" flag (or it's monodroid equivalent Attribute) then you can just handle the rotation yourself.
I am using Box2D for the first time seriously in a medium sized Flash Game that I am working on. My current experience with Box2D is limited to creating a world, bodies and adding those bodies to the world in a functional manner.
I'm finding it easy enough to integrate Box2D into my game environment, maintaining well-written code and have completed a few tutorials that walk through dealing with collisions. The issue that I'm facing now is that my game will have many bodies, each interacting with other bodies in different ways, and I'm finding it hard to write my own b2ContactListener subclass without it getting extremely messy.
Based off a tutorial I used, I have created my own subclass of b2ContactListener and added an override of the BeginContact() method. The argument that BeginContact() receives when it is called will reference an instance of b2Contact, through which I can access two b2Fixture instances (the two instances that have collided). I am then able to access the b2Body instance associated with each of those b2Fixtures.
Problem: Currently I have a roundabout way of finding out what two things collided (i.e. whether they're a wall and a missile, or the player and a tree, etc) which uses GetUserData() and looks like this as an example:
var f1Player:Boolean = contact.GetFixtureA().GetBody().GetUserData() is Player
var f2Player:Boolean = contact.GetFixtureB().GetBody().GetUserData() is Player
var f1Tree:Boolean = contact.GetFixtureA().GetBody().GetUserData() is Tree
var f2Tree:Boolean = contact.GetFixtureB().GetBody().GetUserData() is Tree
// ... continutes with all possible combinations.
// Example of managing a collision:
if(f1Player && f2Tree)
{
// Player (FixtureA) and Tree (FixtureB)
}
if(f2Player && f1Tree)
{
// Player (FixtureB) and Tree (FixtureA)
}
As you can see, this is going to end up extremely long and unmanageable. I also have to write each set of actions to perform twice to cater for a certain element being FixtureA or FixtureB, or vice versa (obviously in the form of a function call with the parameters swapped around rather than literally re-written).
This is clearly not the correct approach, but I haven't been able to locate resources that more thoroughly explain collision detection management.
Does anyone have experience with collision detection management using Box2D that they can share? Also, is using SetUserData( entityThatOwnsTheBody ); the correct way to be using that method?
Yeah, it's a bit of a nuisance indeed. Actually I think the way you have it is quite typical.
fwiw Box2D itself has to deal with a similar problem when testing whether fixtures overlap. There are a bunch of functions such as b2CollideCircles, b2CollidePolygonAndCircle, b2CollidePolygons etc, and when two fixtures come near each other the engine chooses which of these functions should be used.
It does this by putting the function pointers in a 2-dimensional array, then looks up the appropriate function in this array by using the two shape types as index. See the first three functions in b2Contact.cpp for details.
Of course, if you can't pass around function references like this in AS3 then I guess this answer doesn't help much, but I thought I would post anyway as C/C++/JS users might come by.
I've used c++ version of Box2d, but I think the same approach will work in actionscript. I create a class Object, that contain a b2Body *_body pointer and a pointer to graphical representation. _body's UserData was set to point to Object *. class Object had the following methods:
virtual bool acceptsContacts ();
virtual void onContactBegin (const ContactData &data);
virtual void onContactEnded (const ContactData &data);
virtual void onContactPreSolve (const ContactData &data);
virtual void onContactPostSolve (const ContactData &data);
When collision was detected in b2ContactListener subclass, it checked if collided bodies have user data. If so, it casted their user data to Object* and if any of the collided objects accepted contacts - it created ContactData ( a class with all required information about collision) and put it in it's internal list to deliver later.
When b2World::update method returned, ContactListener delivers all contact information to objects to process. Delivery was delayed in order you could create new bodies, joints and so on, right when processing collision (which is not allowed while update is executing)
Also you must notify ContactListener (just put a pointer to it inside ContactData) if one of the collided body was deleted during collision processing, so it can invalidate appropriate contacts and not deliver them
I've come up with something much nicer than the original.
Firstly, I just have my Being class (which owns a b2Body) set itself as its bodies' UserData. This class will also contain an onContact() method and look similar to the below:
public class Being
{
private var _body:b2Body;
public function Being()
{
// Define the body here.
// ...
_body.SetUserData(this);
}
public function onCollision(being:Being = null):void
{
//
}
}
Then in my own b2ContactListener implementation, I simply pass the colliding Being (or null, if there is no Being assigned to the colliding b2Body's UserData) to the opposing Being's onCollision():
override public function BeginContact(contact:b2Contact):void
{
var bodyA:b2Body = contact.GetFixtureA().GetBody();
var bodyB:b2Body = contact.GetFixtureB().GetBody();
var beingA:Being = bodyA.GetUserData() as Being || null;
var beingB:Being = bodyB.GetUserData() as Being || null;
beingA && beingA.onCollision(beingB);
beingB && beingB.onCollision(beingA);
}
And finally in each of my subclasses of Being, I can easily prepare logic appropriate for a collision between other Beings of a certain type:
class Zombie extends Being
{
override public function onCollision(being:Being = null):void
{
if(being && being is Bullet)
{
// Damage this Zombie and remove the bullet.
// ...
}
}
}
How would you adhere to the "Tell, don't ask" principle (henceforth "the principle") in the following simple scenario? In a Tetris game, I have Board, BlockGrid and Piece classes relevant to the following example:
public class Board
{
private var fallingPiece:Piece;
private var blockGrid:BlockGrid;
...
public function moveFallingPiece(xDirection:int, yDirection:int):void
{
blockGrid.movePiece(fallingPiece, xDirection, yDirection);
}
}
Once fallingPiece is placed in the bottom row of BlockGrid, it should no longer be the "fallingPiece". Am I right in that I'm not violating the principle with the following?
if(blockGrid.getPiecePosition(piece).y == 0)
{
fallingPiece = null;
}
But is that really different from this, which I think clearly violates the principle?
public function moveFallingPiece(xDirection:int, yDirection:int):void
{
if(blockGrid.getPiecePosition(piece).y > 0)
{
blockGrid.movePiece(fallingPiece, xDirection, yDirection);
}
else
{
fallingPiece = null;
}
}
I'm not assuming that I've designed these class relationships in the proper way to work with the principle. Please advice on an alternate design if that's what I'm missing.
EDIT, Proposed solution:
I went with the answers proposing "command feedback" via events. Board tells BlockGrid to move a piece. BlockGrid's movePiece method dispatches MOVED_TO or MOVE_FAILED events depending on the result, which Board can listen to and use to determine whether a piece has stopped falling. Please don't hesitate to provide feedback on this solution.
public class Board
{
...
public function Board()
{
...
blockGrid.addEventListener(PieceMoveEvent.MOVE_FAILED, onPieceMoveFailed);
...
}
public function moveFallingPiece(xDirection:int, yDirection:int):void
{
blockGrid.movePiece(fallingPiece, xDirection, yDirection);
}
public function onPieceMoveFailed(event:MovePieceEvent):void
{
if(event.instance == currentlyFallingPiece && event.fromPosition.y != event.toPosition.y)
{
currentlyFallingPiece = null;
}
}
I think, to better follow the Tell, Don't Ask principle, you should have blockGrid notifying your Board class when fallingPiece has reaches it's resting point. In both scenarios above, you are asking blockGrid if the piece's position.y == 0 in order to determine whether or not fallingPiece should be null. Instead, you want blockGrid to tell the Board class that fallingPiece.y has hit 0.
What you are looking for is Event driven programming. You need a Listener interface with a method called .event() and an Event interface to represent the events. Objects will register with other objects ( callbacks ) to the Listener interface.
when you create a Piece and Board they should implement the Listener interface. Then you can set the Board with registerListener(board); Then when things happen inside Piece it will loop thru all the registered listeners and call .event(event) on each. Same with the Board, call board.registerListener(piece) each time you create a new piece, as it decides things are happening it can tell all the registered listeners what has happened. Then you can tell a piece it is no longer falling by the Board object deciding this. Here is the obligitory Wikipedia entry.
I would expect a class representing each shape (without position information), a controller containing a shape, position and orientation, and another class representing the current resulting grid of "landed" shapes. The landed-grid would have a
testLanded(shape, shapePosition, orientation)
method which would be called before/after each move operation to decide if the shape is to join the landed grid or should move and stay as the falling piece.
I'm going on the idea of not giving data to objects that shouldn't really own that data - but I've never implemented Tetris...
You may need to rethink your design. Does Board really need to track the falling piece or should that belong to BlockGrid? Iron out who owns what behavior.
Keep position information on your Piece class and possibly have your Piece class hold an instance of the BlockGrid.
You can then try something like this in your Board class...
public function moveFallingPiece(xDirection:int, yDirection:int):void
{
blockGrid.moveFallingPiece(xDirection, yDirection);
}
Then in BlockGrid's moveFallingPiece method...
public function moveFallingPiece(xDirection:int, yDirection:int):void
{
fallingPiece.move(xDirection, yDirection);
}
In Piece's move method, add your logic...
public function move(xDirection:int, yDirection:int):void
{
setPosition(xDirection, yDirection);
if (getPosition().y <= 0)
{
blockGrid.setFallingPiece(null);
// this can bubble up to Board if need be
}
}
Not sure of all the power of AS3, but it would make sense to use abstractions here. (i.e., have your Piece class depend on ITrackFallingPieces instead of BlockGrid and have BlockGrid implement ITrackFallingPieces).
Good luck!