Andengine Tiledmap How to make sprites impassable by another? - andengine

I have a working collision system to sprites that i dont want "player" to pass. Problem is that i have no idea what should i execute on collision to make player not pass sprites.
wallCollision() method is currently empty.
if(tmxTileProperties.containsTMXProperty("collision", "1")) {
Rectangle rect = new Rectangle(tmxTile.getTileX(), tmxTile.getTileY() ,128, 128, mEngine.getVertexBufferObjectManager())
{
#Override
protected void onManagedUpdate(float pSecondsElapsed)
{
if (player.collidesWith(this))
{
wallCollision();
}
}
};
rect.setVisible(false);
mainScene.attachChild(rect);
}

The question located here addresses this. The method below creates a JBox2D body at the same position as the blocked tile. I'm not sure how this works in conjunction with the pathfinding to exclude blocked tiles, but I've seen the same approach used in other places, assuming you're using GLES2. Hope this helps.
private void createUnwalkableObjects(TMXTiledMap map){
// Loop through the object groups
for(final TMXObjectGroup group: this.mTMXTiledMap.getTMXObjectGroups()) {
if(group.getTMXObjectGroupProperties().containsTMXProperty("wall", "true")){
// This is our "wall" layer. Create the boxes from it
for(final TMXObject object : group.getTMXObjects()) {
final Rectangle rect = new Rectangle(object.getX(), object.getY(),object.getWidth(), object.getHeight());
final FixtureDef boxFixtureDef = PhysicsFactory.createFixtureDef(0, 0, 1f);
PhysicsFactory.createBoxBody(this.mPhysicsWorld, rect, BodyType.StaticBody, boxFixtureDef);
rect.setVisible(false);
mScene.attachChild(rect);
}
}
}
}

Related

Best way to create a 2d top down race track procedurally

I am attempting to create a 2d top-down car racing game. This game will have a random road map each time the player plays the game. I have thought about doing this in two different ways: A tilemap, or just generate the roads by placing different prefabs (straight roads, turns, etc). I have decided to go with the prefab route.
The way I believe it should work is to have prefab square "tiles" which have their own colliders set on the edges so I can tell if a player goes off the track in which case they blow up. I would have a MapGenerator Script which will generate an initial random map by keeping track of the last tile placed (including its location and road type: left turn, straight, right, etc). This script will then keep adding onto the road randomly as the player gets closer and closer to the end which makes it an infinite road.
I just want to know if this is just not efficient or if I am thinking of this completely wrong.
Here are a couple of images showing my road tiles which I made in photoshop and then one prefab for a straight road (take note of the colliders on its edges).
A similar game to one I want to make is Sling Drift which I can provide the link if you want. I don't know the policy on adding links to forum chat.
Also, here is my code for the map generator:
//Type of tyle, types are normal (straight road or horizontal road) and turns
public enum MapTileType
{
NORMAL,
N_E,
N_W,
S_E,
S_W
}
//structure for holding the last tile location and its type.
public struct TypedTileLocation
{
public TypedTileLocation(Vector2 pos, MapTileType tyleType)
{
m_tileType = tyleType;
m_position = pos;
}
public Vector2 m_position;
public MapTileType m_tileType;
}
public class MapGenerator : MonoBehaviour
{
//Map Tiles
public GameObject m_roadTile;
public GameObject m_turnNorthWestTile;
//holds all the tiles made in the game
private List<GameObject> m_allTiles;
//Map Tile Widths and Height
private float m_roadTileWidth, m_roadTileHeight;
//Used for generating next tile
TypedTileLocation m_lastTilePlaced;
private void Awake()
{
//store the initial beginning tile location (0,0)
m_lastTilePlaced = new TypedTileLocation(new Vector2(0,0), MapTileType.NORMAL);
//set height and width of tiles
m_roadTileWidth = m_roadTile.GetComponent<Renderer>().bounds.size.x;
m_roadTileHeight = m_roadTile.GetComponent<Renderer>().bounds.size.y;
m_allTiles = new List<GameObject>();
}
// Start is called before the first frame update
void Start()
{
SetupMap();
}
void SetupMap()
{
//starting at the beginning, just put a few tiles in straight before any turns occur
for (int i = 0; i < 6; ++i)
{
GameObject newTempTile = Instantiate(m_roadTile, new Vector2(0, m_roadTileHeight * i), Quaternion.identity);
m_lastTilePlaced.m_tileType = MapTileType.NORMAL;
m_lastTilePlaced.m_position.x = newTempTile.transform.position.x;
m_lastTilePlaced.m_position.y = newTempTile.transform.position.y;
m_allTiles.Add(newTempTile);
}
//now lets create a starter map of 100 road tiles (including turns and straigt-aways)
for (int i = 0; i < 100; ++i)
{
//first check if its time to create a turn. Maybe I'll randomly choose to either create a turn or not here
//draw either turn or straight road, if the tile was a turn decide which direction we are now going (N, W, E, S).
//this helps us determine which turns we can take next
//repeat this process.
}
}
void GenerateMoreMap()
{
//this will generate more map onto the already existing road and then will delete some of the others
}
// Update is called once per frame
void Update()
{
}
private void OnDrawGizmos()
{
}
}
Thanks!
Have you tried splines? They let you make curvy paths like race tracks easily. If not, here is a video that might help: https://www.youtube.com/watch?v=7j_BNf9s0jM.

TrailRenderer start point on click

I followed Brackeys tutorial on how to create a Fruit Ninja Replica (youtube).
When creating the blade, though, the behaviour I got wasn't exactly the same.
Expected behaviour
Actual behaviour
The difference is that in the Actual behaviour, the trail starts where it stopped the last time it was shown. The code responsible for this is exactly the same as the video:
public class BladeController : MonoBehaviour
{
bool isCutting = false;
public GameObject bladeTrailPrefab;
GameObject currentBlade;
// Update is called once per frame
void Update()
{
if (Input.GetMouseButtonDown(0)) {
StartCutting();
} else if (Input.GetMouseButtonUp(0)) {
StopCutting();
}
if (isCutting) {
UpdateCut();
}
}
void UpdateCut()
{
GetComponent<Rigidbody2D>().position = Camera.main.ScreenToWorldPoint(Input.mousePosition);
}
void StartCutting()
{
isCutting = true;
this.currentBlade = Instantiate(bladeTrailPrefab, transform);
}
void StopCutting()
{
isCutting = false;
Destroy(currentBlade, 1f);
}
}
After understanding the code, I thought the problem was that I instantiated the bladeTrail before actually moving the Blade to the new position, but tried moving the Instantiate method to UpdateCut after changing the position and only if this.currentBlade == null.
I've search a lot about this, and even found some other posts with the same problem but no answer.
It seams the Instantiate is using the last mouse position to instiantiate the prefab.
Maybe use:
Instantiate(bladeTrailPrefab, Camera.main.ScreenToWorldPoint(Input.mousePosition), Quaternion.identity)
I ran into this problem following the tutorial as well.
It's a few years later but for those of you who hit this page, I found a solution for me that while isn't fantastic, it's better than having the streaks shown in the post.
Before instantiating the trail vfx, make sure to wait until fixed update is called after you set the position of the parent transform.
I did this with a Coroutine like so:
private IEnumerator StartCutting()
{
// When we begin cutting, move the blade object to the input position
m_isCutting = true;
m_previousPosition = m_camera.ScreenToWorldPoint(Input.mousePosition);
m_rigidBody.position = m_previousPosition;
// Then for positions to be updated so that the vfx doesn't get confused
yield return m_waitForFixedUpdate; // new WaitForFixedUpdate(); <-- cache this
// Instantiate the trail at this new position
m_currentTrail = Instantiate(m_trailPrefab, m_rigidBody.transform);
m_collider.enabled = false;
}

Spawn sprites on action

I'm trying to make a Pinata GameObject, that when clicked bursts and gives a variable number of Gift GameObjects with various images and behaviors in them.
I'm also not sure what the unity vocabulary for this is so as to look this up in unity docs.
Can anyone please lend me a hand here? Thanks!
There are several ways to handle this.
The simple way is to use Object.Instantiate, Object Instantiation is the vocab you're after.
This will create a copy of a predefined Unity object, this can be a gameobject or any other object derived from UnityEngine.Object, check the docs for more info https://docs.unity3d.com/ScriptReference/Object.Instantiate.html.
In your case, your Pinata would have an array, or list, of prefabs. These prefabs are created by you with a certain behaviour and sprite for each one. When the Pinata bursts, you instantiate random prefabs at random positions surrounding the Pinata, up to you how to position these objects.
Something along these lines should do the trick:
class Pinata : Monobehaviour
{
public GameObject[] pickupPrefabs;
public int numberOfItemsToSpawn; //This can be random
//any other variables that influence spawning
//Other methods
public void Burst()
{
for(int i = 0; i < numberOfItemsToSpawn; i++)
{
//Length - 1 because the range is inclusive, may return
//the length of the array otherwise, and throw exceptions
int randomItem = Random.Range(0, pickupPrefabs.Length - 1);
GameObject pickup = (GameObject)Instantiate(pickupPrefabs[randomItem]);
pickup.transform.position = transform.position;
//the position can be randomised, you can also do other cool effects like apply an explosive force or something
}
}
}
Bare in mind, if you want the game to be consistent, then each behaviour prefab would have there own predefined sprite, this would not be randomised. The only thing randomised would be the spawning and positioning.
If you did want to randomise the sprites for the behaviours then you'd have to add this to the Pinata class:
public class Pinata : Monobehaviour
{
//An array of all possible sprites
public Sprite[] objectSprites;
public void Burst()
{
//the stuff I mentioned earlier
int randomSprite = Random.Range(0, objectSprites.Length - 1);
SpriteRenderer renderer = pickup.GetComponent<SpriteRenderer>();
//Set the sprite of the renderer to a random one
renderer.sprite = objectSprites[randomSprite];
float flip = Random.value;
//not essential, but can make it more random
if(flip > 0.5)
{
renderer.flipX = true;
}
}
}
You can use Unity random for all your random needs, https://docs.unity3d.com/ScriptReference/Random.html
Hopefully this'll lead you in the right direction.

XNA multi class collision

I am trying to make the enemy spawning / movement system for a side scrolling game.
What is supposed to happen is the enemies are to spawn and move right until they collide with a specific object then they will travel in the opposite direction.
I have done research and asked question to get me this far:
I have made an enemy class and then made a list that can add more enemies and set their individual spawning positions. Then I have made an EnemyBlock class so I can set where the various collision objects will be (In this case they are just brick squares).
I am having some trouble
A. In making the enemies turn around when they leave the game screen.
And B. writing collision code for the enemies and enemyblocks as when I try and write collision code in the Game1.cs Update section under foreach (Enemy enemy in enemies) it doesn't pick the the enemyblock's rectangle. If that makes sense. Im sorry but I am pretty new to XNA code.
Game1.cs code
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
public Rectangle bounds;
List<Enemy> Enemies = new List<Enemy>();
List<EnemyBlock> Blocks = new List<EnemyBlock>();
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
protected override void Initialize()
{
// TODO: Add your initialization logic here
base.Initialize();
}
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
Blocks.Add(new EnemyBlock(Content.Load<Texture2D>("02Brick"), new Vector2(50, 100)));
Enemies.Add(new Enemy(Content.Load<Texture2D>("Mario_Sprite"), new Vector2(100, 100), new Vector2(1, 0)));
Blocks.Add(new EnemyBlock(Content.Load<Texture2D>("02Brick"), new Vector2(500, 100)));
Blocks.Add(new EnemyBlock(Content.Load<Texture2D>("02Brick"), new Vector2(50, 200)));
Enemies.Add(new Enemy(Content.Load<Texture2D>("Mario_Sprite"), new Vector2(100, 200), new Vector2(1, 0)));
Blocks.Add(new EnemyBlock(Content.Load<Texture2D>("02Brick"), new Vector2(400, 200)));
foreach (Enemy enemy in Enemies)
{
enemy.bounds = new Rectangle((int)(enemy.position.X - enemy.texture.Width), (int)(enemy.position.Y - enemy.texture.Height), enemy.texture.Width, enemy.texture.Height);
}
foreach (EnemyBlock block in Blocks)
{
block.bounds = new Rectangle((int)(block.position.X - block.texture.Width), (int)(block.position.Y - block.texture.Height), block.texture.Width, block.texture.Height);
}
}
protected override void UnloadContent()
{
// TODO: Unload any non ContentManager content here
}
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
foreach (Enemy enemy in Enemies)
{
if (!GraphicsDevice.Viewport.Bounds.Contains(enemy.bounds))
{
enemy.velocity = -enemy.velocity;
enemy.position += enemy.velocity;
}
else
{
enemy.position += enemy.velocity;
}
}
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
foreach (Enemy enemy in Enemies)
{
spriteBatch.Draw(enemy.texture, enemy.position, Color.White);
}
foreach (EnemyBlock block in Blocks)
{
spriteBatch.Draw(block.texture, block.position, Color.White);
}
spriteBatch.End();
base.Draw(gameTime);
}
}
}
Enemy class code
class Enemy
{
public Texture2D texture;
public Rectangle bounds;
public Vector2 position;
public Vector2 velocity;
public Enemy(Texture2D Texture, Vector2 Position, Vector2 Velocity)
{
texture = Texture;
position = Position;
velocity = Velocity;
}
}
EnemyBlock class code
class EnemyBlock
{
public Texture2D texture;
public Rectangle bounds;
public Vector2 position;
public EnemyBlock(Texture2D Texture, Vector2 Position)
{
texture = Texture;
position = Position;
}
}
Your code seems to be very well structured and organized. Makes it a lot easier to be able to find any of these problems your having so thanks and keep your code organized. It's a good habit and it makes larger projects much easier.
Anyways I think I might have the answer to your problem.
The reason your rectangles aren't being picked up is because you are initializing the rectangles for your enemies and blocks in your load content method.
This is fine except that you don't appear to update the position of the rectangles. You update the velocity and position of the enemies and blocks though you check for collision with the bounding rectangles.
This means that your enemies will be able to move off screen and through objects because your the draw position has moved but the rectangle hasn't meaning it won't detect the collision.
I believe other problem is with specifying the rectangle position. I believe your code maybe a bit off but if it works fine then leave it. But if the collision detection is a little off then try the following. Your code
enemy.bounds = new Rectangle((int)(enemy.position.X - enemy.texture.Width), (int)(enemy.position.Y - enemy.texture.Height), enemy.texture.Width, enemy.texture.Height);
should look like
enemy.bounds = new Rectangle(enemy.position.X, enemy.position.Y, enemy.texture.Width, enemy.texture.Height);
based on how you are drawing your images.
The constructor of the rectangle specifies the top left corner's x, y position and the width/height of the rectangle. Rectangle r = new Rectangle(100, 100, 200, 200) creates a rectangle at 100, 100 and 200 wide and 200 tall.
This will match up with how you draw your enemies and blocks.
And lastly the collision code is fairly simple:
foreach(Enemy enemy in Enemies)
{
foreach(EnemyBlock block in Blocks)
{
if(enemy.bounds.Contains(block.bounds))
{
//what to do on collision
}
}
}
I hope this is all correct and helps.
I'm not proficient on XNA, anyway,
try removing negation, because the code looks like it will always reverse the velocity while not on viewport's edge
if (GraphicsDevice.Viewport.Bounds.Contains(enemy.bounds))
{
enemy.velocity *= -1;
}
enemy.position += enemy.velocity;
with this, the enemy velocity will reverse only when it reaches the boundary.
No need to put an else statement since the enemy will always be moving.
As for the collision with enemy blocks, here is a good tutorial from MSDN on making 2D side scrolling games like mario. CLICK HERE
in the tutorial everything is treated as a tile object on 2d array map and on update, it checks against a tile of the array where the enemy is currently standing (enemy's position)

Andengine 2d side-scroller like mario

I have a question there.
How i make character with gravity and available to walk properly i.e. what functions i need to use and how do i define fixtures? And do i need box2d physics world(i'm using tiled maps)?
So if you can, please tell me how to do 2d side scrolling platformer like mario with andengine.
My code what i'm trying to do :
// Character:
charactersprite = new Sprite(40, 0, this.character);
charactersprite.setScaleX(0.65f);
this.mScene.setOnSceneTouchListener( this);
// PHYSICS
final FixtureDef characterfictur = PhysicsFactory.createFixtureDef(0, 0f,0.5f);
this.mScene.registerUpdateHandler(this.mPhysicsWorld);
final Body body = PhysicsFactory.createBoxBody(this.mPhysicsWorld, charactersprite, BodyType.DynamicBody, characterfictur);
this.mPhysicsWorld.registerPhysicsConnector(new PhysicsConnector(charactersprite, body, true, false));
mScene.attachChild(charactersprite);
createUnwalkableObjects(mTMXTiledMap);
final PhysicsHandler physicsHandler = new PhysicsHandler(charactersprite);
charactersprite.registerUpdateHandler(physicsHandler);
// HUD
HUD my = new HUD();
Sprite forward = new Sprite( 50, CAMERA_HEIGHT - 170, forwardr){
#Override
public boolean onAreaTouched(TouchEvent pEvent, float pX, float pY){
if(!pEvent.isActionUp()){
charactersprite.getTextureRegion().setFlippedHorizontal(false);
body.setLinearVelocity(new Vector2(CHAR_MOVING_SPEED,body.getLinearVelocity().y)); // Don't look at there
//body.applyLinearImpulse(new Vector2(2,0), body.getPosition());
}else{
//body.applyLinearImpulse(new Vector2(0,0), body.getPosition());
physicsHandler.setVelocity(0, 0);
body.setLinearVelocity(new Vector2(0,body.getLinearVelocity().y)); // Don't look at there
}
return false;
}
};
And little forward :
private void createUnwalkableObjects(TMXTiledMap map){
// Loop through the object groups
for(final TMXObjectGroup group: map.getTMXObjectGroups()) {
//if(group.getTMXObjectGroupProperties().containsTMXProperty("Zeme", "true")){
// This is our "wall" layer. Create the boxes from it
for(final TMXObject object : group.getTMXObjects()) {
final Rectangle rect = new Rectangle(object.getX(), object.getY(),object.getWidth(), object.getHeight());
final FixtureDef boxFixtureDef = PhysicsFactory.createFixtureDef(0, 0,1f);
PhysicsFactory.createBoxBody(this.mPhysicsWorld, rect, BodyType.StaticBody, boxFixtureDef);
rect.setVisible(false);
mScene.attachChild(rect);
}
//}
}
}
So it didn't work properly. So what i'm doing wrong? Please help me.
Thank you very much!
Things you will need:
BoundCamera (to make bounds for your map)
chase entity (your player, so camera will follow your entity)
FixtureDef with little elasticity (to prevent player stopping suddenly on the ground)
create box bodies for your static objects (such as walls and so on)
things like jump - simply use setLinearVelocity
Every 'feature' mentioned above, has its example - simply check and engine examples.
In this thread, I provided some more tips about how to code such game: CLICK