Trying to make a 2D side scroller here
I am quite new to programming. I've tried to follow guides and tutorials with not much luck. I am aware that this is quite simple but i just cannot figure it out.
I have multiple classes for all the different characters in the game.
I have a rectangle for the main sprite character which the player will control.
But the problem is that I want to add rectangles around enemy sprites so that i can add collision into the game.
public class enemyRocks
{
public Texture2D texture;
public Vector2 position;
public Vector2 velocity;
public Rectangle rockRectangle;
public bool isVisible = true;
Random random = new Random();
int randX;
public enemyRocks(Texture2D newTexture, Vector2 newPosition)
{
texture = newTexture;
position = newPosition;
randX = -5;
velocity = new Vector2(randX, 0);
}
public void Update(GraphicsDevice graphics)
{
position += velocity;
if (position.X < 0 - texture.Width)
isVisible = false;
}
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(texture, position, Color.White);
}
}
I have genuinely tried many methods but it just doesn't seem to work.
Everything i've done so far gave me a "nullreferenceexception was unhandled" error.
I will take any criticism needed to improve.
Thank you for your help.
you need boundingBox property on your sprites
new Rectangle((int)Position.X,(int)Position.Y,texture.Width, texture.Height);
then to check collision
if (Sprite1.BoundingBox.Intersects(Sprite2.BoundingBox))
but make sure that you load your texture before any function that uses texture. i guess your error happened on update function where you try to get width of texture that is not loaded.
Related
I am working in a Game which is pretty similar to Mario. So when player touches the coin object in World Space, I need to animate by moving that coin object to Coin meter, when the render mode of Canvas is Screen Space - Overlay, I can get the sprite object position easily with below code
CoinSprite Code
GameObject coinCanvasObject = Instantiate(prefab, canvas.transform);//Instantiate coin inside Canvas view
coinCanvasObject.transform.position = Camera.main.WorldToScreenPoint(coinSpriteObject.transform.position);//getting coin position from World Space and convert to Screen Space and set to coinCanvasobject position
AnimateCoin animate = coinCanvasObject.GetComponent<AnimateCoin>();
animate.animateCoin(coinSpriteObject.transform.position);
coinSpriteObject.SetActive(false);
AnimateCoin
public class AnimateCoin : MonoBehaviour
{
private float speed = 0f;
private bool isSpawn = false;
private Vector3 screenPos;
public void animateCoin(Vector3 screenPosTemp, Camera cam, Canvas canvas)
{
screenPos = Camera.main.WorldToScreenPoint(screenPosTemp);
isSpawn = true;
}
private void Update()
{
if (isSpawn)
{
speed += 0.025f;
transform.position = Vector3.Lerp(screenPos, targetObject.transform.position, speed);
if (Vector3.Distance(transform.position, targetObject.transform.position) <= 0)
{
StartCoroutine(deActivateCoin());
}
}
}
private IEnumerator deActivateCoin()
{
isSpawn = false;
yield return new WaitForSeconds(0.2f);
gameObject.SetActive(false);
}
}
Since I need to bring particle effect into Canvas view, I am changing the Canvas render mode to Screen Space - Camera.
When I change the Canvas to this render mode I could not get the exact sprite object position to trail the coin effect.
Hope this helps:
public Camera cam; // Camera containing the canvas
public Transform target; // object in the 3D World
public RectTransform icon; // icon to place in the canvas
public Canvas canvas; // canvas with "Render mode: Screen Space - Camera"
void Update()
{
Vector3 screenPos = cam.WorldToScreenPoint(target.position);
float h = Screen.height;
float w = Screen.width;
float x = screenPos.x - (w / 2);
float y = screenPos.y - (h / 2);
float s = canvas.scaleFactor;
icon.anchoredPosition = new Vector2(x, y) / s;
}
PD: It worked perfectly for me in a 2D video game, I didn't test it in a 3D game, but I think it should work too.
I rewrote my previous solution because it might not work correctly on some devices with non-standard resolutions.
This code should always work.
uiObject.anchoredPosition = GetUIScreenPosition(myPin.position, cam3d, uiObject.anchorMin);
public static Vector2 GetUIScreenPosition(Vector3 obj3dPosition, Camera cam3d, Vector2 anchor)
{
Vector2 rootScreen = _rootCanvasRect.sizeDelta;
Vector3 screenPos = cam3d.WorldToViewportPoint(obj3dPosition);
return (rootScreen * screenPos) - (rootScreen * anchor);
}
We take the sizeDelta of our UI Canvas, because it may differ from the screen resolution of the device.
Then we cast the WorldToViewportPoint from our 3d camera to get the relative position on the screen in the format from 0 to 1 by X and Y.
With anchors in the lower left corner ((0,0)(0,0)) this is our final anchoredPosition. However with anchors for example in the center ((0.5,0.5)(0.5,0.5)) we need to adjust the positions by subtracting half the canvas size.
In this example, we will get an unpredictable result when using different min and max anchors in the final object. For example ((0,25,0.25)(0.75,0.75)). But I sincerely doubt that you really need such anchors on an object with a dynamic position depending on the 3d object.
I've been trying to achieve a scrolling background effect using a Sprite in a 2D Unity project.
I've seen this code being used on 3D objects with a MeshRenderer to achieve the effect but this does not seem to work on a Sprite with SpriteRenderer. Does anybody know why?
public class ScrollingTexture : MonoBehaviour {
public float ScrollSpeed = -0.5f;
private Vector2 _savedOffset;
private Renderer _renderer;
private void Start ()
{
_renderer = GetComponent<Renderer>();
_savedOffset = _renderer.material.mainTextureOffset;
}
private void Update()
{
float x = Mathf.Repeat (Time.time * ScrollSpeed, 1);
Vector2 offset = new Vector2(x, _savedOffset.y);
_renderer.material.mainTextureOffset = offset;
}
private void OnDisable()
{
_renderer.material.mainTextureOffset = _savedOffset;
}
}
UPDATE:
To get it to work properly I have added a new material as suggested and set its shader to Unlit/Transparent. I also had to make sure the Sprite itself had its Wrap Mode set to Repeat. I did not fix the Inspector Warning yet.
You get this warning in the inspector
I managed to get it scrolling by just creating a New Material and assigning it to the GameObject, then changing the Shader to Sprites/Diffuse.
I have been trying my hand at making a simple 2D game in Monogame. I found a tutorial online for a Camera class to be used with scrolling the screen towards where my character is moving.
This is the camera class:
public class Camera
{
Vector2 position;
Matrix viewMatrix;
public Matrix ViewMatrix
{
get { return viewMatrix; }
}
public int ScreenWidth
{
get { return GraphicsDeviceManager.DefaultBackBufferWidth; }
}
public int ScreenHeight
{
get { return GraphicsDeviceManager.DefaultBackBufferHeight; }
}
public void Update(Vector2 playerPosition)
{
position.X = playerPosition.X - (ScreenWidth / 2);
position.Y = playerPosition.Y - (ScreenHeight / 2);
if(position.X <0)
{
position.X = 0;
}
if(position.Y <0)
{
position.Y = 0;
}
viewMatrix = Matrix.CreateTranslation(new Vector3(-position, 0));
}
And in the Game1.cs I use the following Draw method:
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.Black);
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend,
null, null, null, null, Camera.ViewMatrix);
ScreenManager.Instance.Draw(spriteBatch);
spriteBatch.End();
base.Draw(gameTime);
}
When I use spriteBatch.Begin() without any arguments, the Titlescreen and mainmenu load just fine followed by the tilemap and the player.
However when I add the Camera.Viewmatrix argument the screen stays Black. It does not seem to draw anything past the Graphicsdevice.Clear(Color.Black).
I would appreciate any and all input. And please let me know if you need to see more of my code.
UPDATE: The camera and matrix are fine I believe. The problem has to do with the fact that I have many classes, for example Screenmanager, Image, Tile, Layer, TitleScreen,... that are all using an Update and most of them a Draw method.
The actual drawing is being handled as shown above in the game1.cs by a singleton instance of the ScreenManager class using its draw method.
I suspect that it is trying to apply the matrix to the fadescreen/titlescreen in the start and that is causing errors such as not progressing past the black background. Perhaps because the camera position has no player position?
I have tried using a separate spritebatch.Begin() for the Camera and Player draw methods but this of course results in the error that I'm calling a new spriteBatch.Begin before the other one has ended.
I feel like this is solvable but I might have been staring at it too long to see the solution now.
I don't want to turn this into a 'look at my entire project and fix it for me' but if anyone recognizes this situation and has input, or even has run into the same thing and fixed it, I would very much appreciate your feedback.
Also, should anyone require more code to look at, again. feel free to let me know.
Try feeding it an Identity matrix. That should work and it would confirm that something must be wrong with your matrix. It's been a while since I did this, but it think this worked.
public void Update(Vector2 playerPosition)
{
if(position.X <0)
{
position.X = 0;
}
if(position.Y <0)
{
position.Y = 0;
}
viewMatrix = Matrix.CreateTranslation(new Vector3(-playerPosition.X, -playerPosition.Y, 0.0f));
}
I am new in Game Programming but I'm interested in this domain; now I am working on a small game for my course work. I have used some ideas from the internet to make my hero jump; the code is working, but after I press first time space, the hero is jumping and is not coming back to his position, he remains on the top of the screen. Please help me to make my hero, then return to his initial position. If I press space again he is jumping, but is jumping there, on the top of the screen.
public void Initialize()
{
startY = position.Y;
jumping = false;
jumpspeed = 0;
}
public void Update(GameTime gameTime)
{
KeyboardState keyState = Keyboard.GetState();
rectangle = new Rectangle(currentFrame * frameWidth, 0, frameWidth, frameHeight);
origin = new Vector2(rectangle.Width / 2, rectangle.Height / 2);
AnimateRight(gameTime);//calling AnimateRight function to animate heroes sprite
if (jumping)
{
position.Y += jumpspeed;
jumpspeed += 1;
if (position.Y >= startY)
{
position.Y = startY;
jumping = false;
}
}
else
{
if (keyState.IsKeyDown(Keys.Space))
{
jumping = true;
jumpspeed = -14;
}
}
}
You have to set startY when pressing Space:
if (keyState.IsKeyDown(Keys.Space))
{
jumping = true;
jumpspeed = -14;
startY = position.Y;
}
I know that you are new, but I replicated a movement system that worked great if you can understand it, here is the link to see the player movement in action, and here is the web site for it. If you want to download it here is the link.
This player movement uses a couple important things,
First:
Inside the Player class there is a method called public Player, yes, you make a method that is the same name as the class. By doing this you can transfer information from the Game1 class to Player class. So you can send the player texture, position, speed, ect...
Second:
Inside the Player method the info that is called over from the Game1 class needs to be collected and stored in the Player class. So if you wanted to transfer the texture of you player you would need to do the following.
Create the Player Texture and create a the link that will allow you to create the link to the Player class:
Texture2D personTexture;
'Player player'
Then in the Load Content you need to call on the personTexture and put it into the player function:
personTexture = Content.Load <Texture2D>("Person");
player = new Player(personTexture);
Now that the Texture is now in side the Player method in the Player class you will now store it in the Player class so that you can use it, add a Texture2D Texture to your Player class then enter the following:
public Player(Texture2D Texture)
{
this.Texture = Texture;//this.Texture is the one you create in side the
Player class, the other is the Texture you stated
}
Now your done and able to use your texture in that class.
Hopefully this will help you understand how to create your jumping player.
I'm creating a 2D shooter and I would like to increase the size of certain enemies when collision occurs between that and a projectile object.
I can scale the sprite in the code by just changing the float value below
enemyAnimation.Initialize(enemyTexture, Vector2.Zero, 47, 61, 8, 30, Color.White, **2f**, true);
I can then change that float to a variable, and update the variable when a collision occurs. The only problem is, that the enemy scale does change but only for newly spawned enemies and all of them. This was obvious but what I want to be able to do (if at all possible) is change the size of the enemy that the collision occurred with and only that enemy...
Any ideas on how I might go about doing this?
EDIT:
Okay, I am a little confused. I have created a float value called scaleSize in my Enemy class. Then in collision detection in my Game1.cs I am running a for loop to iterate through my list of enemy objects
// Projectile vs Enemy Collision
for (int i = 0; i < projectiles.Count; i++)
{
for (int j = 0; j < enemies.Count; j++)
{
// Create the rectangles we need to determine if we collided with each other
// Determine if the two objects collided with each other
if (rectangle1.Intersects(rectangle2))
{
enemies[j].Health -= projectiles[i].Damage;
projectiles[i].Active = false;
*enemies[j].scaleSize += 1f;*
}
}
}
Now I realise scaleSize is not being initialized properly. But I am unsure of where I should change this. As above in the earlier code sample, the float value is changing the scale of the enemy but through the Animation class and if I change this, it changes for all enemies (afaik).
I am sorry as I know this is very vague but I just can't wrap my head around where I should set the enemies scale size. creating it enemy class is fine but it is not referencing the actual scale of the enemy.
Store the scale value in your Enemy class. That way, each instance of your Enemy objects will have their own scale value.
If you do not have an Enemy class, you should create one. You can also store the enemyTexture, and have each Enemy have their own appearance.
Edit
You most likely are not using the proper scale value in your Draw method. Take an example Enemy class:
class Enemy
{
protected float Scale { get; set; }
protected Texture2D Texture { get; set; }
protected Vector2 Position { get; set; }
public Enemy()
{
Scale = 1f;
}
public void Hit()
{
Scale = 2f;
}
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(Texture, Position, null, Color.White, 0, Vector2.Zero, Scale, SpriteEffects.None, 1);
}
}
Usage examples:
Enemy A = new Enemy();
A.Hit();
A.Draw(spriteBatch);