I was looking for a way to block other object from the same class to be dragged, when I begin dragging one and hover another it id dragged as well...
Here is my main item definition,
class DrawableObject
{
public Rectangle RectObject
public void Update(GameTime gameTime, MouseState ms)
{
if ((ButtonState.Pressed == Mouse.GetState().LeftButton))
if (RectObject.Intersects(new Rectangle(ms.X, ms.Y, 0, 0)))
Dragged = true;
else
Dragged = false;
if (Dragged)
RectObject = new Rectangle(ms.X - RectObject.Width / 2, ms.Y - RectObject.Height / 2, RectObject.Width, RectObject.Height);
}
}
The issue will be more tight as I will be creating more than 50 instance of this class.
You could keep a "global" property with the current object being dragged.
Then before accepting dragging each object will check if another is not yet dragged:
public void Update(GameTime gameTime, MouseState ms)
{
if (currentObject != null && this != currentObject) return;
if ((ButtonState.Pressed == Mouse.GetState().LeftButton))
{
if (RectObject.Intersects(new Rectangle(ms.X, ms.Y, 0, 0)))
{
Dragged = true;
currentObject = this;
}
}
else
...
}
Related
I'm working on a small game where objects are put in a boat, then a key press makes the boat "sail".
To move all the objects that are standing on the boat, i am setting the parent of each object to an empty guide object in the boat then changing the position of the boat. (I have also tried parenting the objects into the boat object itself)
The following is a script applied to the boat object.
variables set in the BoatScript class:
public class BoatScript : MonoBehaviour {
public List<string> boatList;
public KeyCode interact;
public GameObject tempObject;
public string whichSide;
public string direction;
public bool canSail;
}
Start and Update method:
void Start () {
canSail = false;
whichSide = "start";
direction = "toFinish";
speed = 0f;
}
void Update () {
if (canSail == true)
{
SetSail();
}
if (boatList.Contains("FARMER") && whichSide == "start" && Input.GetKeyDown(interact))
{
speed = 0.5f;
CharacterCheck();
}
else if (boatList.Contains("FARMER") && whichSide == "finish" && Input.GetKeyDown(interact))
{
speed = -0.05f;
CharacterCheck();
}
}
Here are my OnTrigger methods:
void OnTriggerEnter(Collider other)
{
Debug.Log(other.gameObject.name + " collided with " + gameObject.name);
promptText.text = "";
if(CheckValidObject(other.gameObject.name) == true) {
boatList.Add(other.gameObject.name);
logBox.text = logBox.text + "\nThe " + other.gameObject.name + " is in the boat";
}
if (other.gameObject.name == "FARMER")
{
promptText2.text = "Press E to set sail";
}
}
void OnTriggerExit(Collider other)
{
boatList.Remove(other.gameObject.name);
logBox.text = logBox.text + "\nThe " + other.gameObject.name + " has left the boat";
promptText.text = "";
if (other.gameObject.name == "FARMER")
{
promptText2.text = "";
}
}
Setting sail:
void SetSail()
{
promptText.text = "";
promptText2.text = "";
addParents();
if (whichSide == "sailing" && direction == "toFinish")
{
speed = 0.05f;
gameObject.transform.Translate(speed, 0, 0);
}
else if (whichSide == "sailing" && direction == "toStart")
{
speed = -0.05f;
gameObject.transform.Translate(speed, 0, 0);
}
else if (whichSide == "start" || whichSide == "finish")
{
gameObject.transform.Translate(speed, 0, 0);
removeParents();
}
}
void addParents()
{
foreach(string o in boatList)
{
GameObject obj = GameObject.Find(o);
obj.GetComponent<Rigidbody>().useGravity = false;
obj.GetComponent<Rigidbody>().isKinematic = true;
if (obj.name == "FARMER") { obj.transform.parent = playerGuide.transform; }
else {obj.transform.parent = itemGuide.transform; }
}
}
void removeParents()
{
foreach (string o in boatList)
{
GameObject obj = GameObject.Find(o);
obj.GetComponent<Rigidbody>().useGravity = true;
if(obj.name != "FARMER") {obj.GetComponent<Rigidbody>().isKinematic = false; }
obj.transform.parent = null;
}
}
The problem: Once the boat reaches and hits the collider for the other side, the boat stops as expected but the objects that were just removed from the parent begin to scale up continuously like this:
e.g 1 https://i.gyazo.com/d35ae729757b8e71c25fd1b4a3857dae.mp4
e.g 2 https://i.gyazo.com/80637919bfd114a42d187300b7faef25.mp4
I'm not too sure what is causing this. Any help is much appreciated, thank you.
Instead of setting the parent via transform.parent, use transform.SetParent(targetTransform, false);. The second, bool, parameter determines if the game object's transform will maintain it's position, orientation, and scale. By setting it to false, the transform will maintain it's current values, while setting it to true will modify the position, orientation, and scale to maintain the world position. You can check this for further info transform.SetParent
Are youu sure it is scaling up and not moving up in the Z axes? From what im looking it is going towards the camera but not scaling up. You should debug the position and scale in the update method to see whats really happening there.
Below comment: "Well then you will have to debug it more carefully, i would first try, setting canSail to false as soon as it reaches the end. Perhaps the method addParent which is always being executed is wrong, what does the object itemGuide does? edit: i just seen the second video, from my perspective that seems gravity, what you meant with problems with scaling up is because its moving out from the boat?"
Solution:
void SetSail()
{
promptText.text = "";
promptText2.text = "";
addParents();
if (whichSide == "sailing" && direction == "toFinish")
{
speed = 0.05f;
gameObject.transform.Translate(speed, 0, 0);
}
else if (whichSide == "sailing" && direction == "toStart")
{
speed = -0.05f;
gameObject.transform.Translate(speed, 0, 0);
}
else if (whichSide == "start" || whichSide == "finish")
{
gameObject.transform.Translate(speed, 0, 0);
canSail = false; //Adding this line solves the issues, must have been affecting transform properties to child objects.
removeParents();
}
}
I am currently creating a 2d platformer in monogame.
I created a block that, when hit by the player, starts dissapearing. When it dissapears, i draw a rectangle around it. Every Tile of the same type (BrittleTile) also starts dissapearing, untill the entire connected mob of BrittleTiles has dissapeared.
The problem is that for every BrittleTile that is destroyed, my game runs noticably slower, until it becomes a slideshow after 10 or so BrittleTiles destroyed. I have no idea as to what may cause this, i've been trying to ease the Update method of the class but nothing seems to help.
Any idea as to what may cause this?
class BrittleTile: Tile, IIncludeSound
{
public Rectangle DestroyedCheckRectangle;
private BrittleTile brittle;
private bool _isPlayed;
private bool _hasBroken;
private SoundEffect _sfxBreak;
private SoundEffectInstance _sfxiBreak;
private TimeSpan _breakTimer = new TimeSpan();
public Rectangle BrokenViewRectangle { get; set; }
private bool _isBreaking = false;
public BrittleTile(Texture2D texture, Rectangle baseViewRectangle, Rectangle brokenViewRectangle):base(texture, baseViewRectangle, true )
{
this.BrokenViewRectangle = brokenViewRectangle;
this.ViewRectangle = baseViewRectangle;
}
public void Update(GameTime gameTime, Hero hero, Entity[,] grid)
{
if (!this._hasBroken)
{
if (!this._isBreaking && !this._hasBroken && this.hasCollision)
_checkCollision(hero, grid);
if (this._isBreaking)
{
if (!this._isPlayed)
_sfxiBreak.Play();
this._isPlayed = true;
this._breakTimer += gameTime.ElapsedGameTime;
if (this._breakTimer.TotalMilliseconds < 250)
this.GhostMode(gameTime);
else
{
this._isBreaking = false;
this.hasCollision = false;
this._breakTimer -= this._breakTimer;
}
}
else
{
if (!this.hasCollision && this.DestroyedCheckRectangle.Width == 0)
{
this.DestroyedCheckRectangle.X = this.DestinationRectangle.X - 10;
this.DestroyedCheckRectangle.Y = this.DestinationRectangle.Y - 10;
this.DestroyedCheckRectangle.Height = this.DestinationRectangle.Height + 20;
this.DestroyedCheckRectangle.Width = this.DestinationRectangle.Width + 20;
this._hasBroken = true;
}
}
}
}
public override void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(this.Texture, this.DestinationRectangle, this.BrokenViewRectangle, Color.White);
if (this.hasCollision)
spriteBatch.Draw(this.Texture, this.DestinationRectangle, this.ViewRectangle, Color.White * this.GhostDraw * 0.9f);
spriteBatch.Draw(this.Texture, DestroyedCheckRectangle, new Rectangle(1, 1, 1, 1), Color.Yellow);
Console.WriteLine(this.DestroyedCheckRectangle.X + ", " + this.DestroyedCheckRectangle.Y + ", " + this.DestroyedCheckRectangle.Width + ", " + this.DestroyedCheckRectangle.Height);
}
private void _checkCollision(Hero hero, Entity[,] grid)
{
if (this.DestinationRectangle.Intersects(hero.AttackHitBox))
{
this._isBreaking = true;
}
foreach (Shuriken star in hero.Stars)
{
if (this.DestinationRectangle.Intersects(star.DestinationRectangle))
this._isBreaking = true;
}
foreach (Entity entityObject in grid)
{
if (hasCollision && entityObject.GetType() == typeof(BrittleTile)){
brittle = entityObject.DeepCopy() as BrittleTile;
if (this.DestinationRectangle.Intersects(brittle.DestroyedCheckRectangle))
this._isBreaking = true;
}
}
}
override public void LoadSounds(ContentManager content)
{
this._sfxBreak = content.Load<SoundEffect>("SFX/brittleBreak");
_sfxiBreak = _sfxBreak.CreateInstance();
_sfxiBreak.Volume = 0.2f;
}
}
First, this line:
if (!this._isBreaking && !this._hasBroken && this.hasCollision)
the !this._hasBroken is superfluous.
My first warning sign is this line:
brittle = entityObject.DeepCopy() as BrittleTile;
I assume DeepCopy() makes a new version of the object, and copies all it's properties, right? Seeing the code of that might help pin it down, but on that assumption...
For every Tile, you're cycling through every object in you're grid and you're completely duplicating that object as a BrittleTile, why?
My first change would be to modify that foreach to have this within it:
var brittle = entityObject as BrittleTile
if (brittle != null && hasCollision){
if (this.DestinationRectangle.Intersects(brittle.DestroyedCheckRectangle))
this._isBreaking = true;
}
}
Not sure this is the primary cause of the slowdown, but it is definitely an issue. If you're cloning an object and then immediately throwing an object away, you're almost certainly doing something wrong. If you're cloning an object and you're not editing the properties of that copy at all (and using those edits), you're definitely doing something wrong. I'd be wary before using a method like that unless you're really sure that's what you want.
I am wondering what the best way to make a button in MonoGame is. I tried to look for an answer but none seem to be out there. Is it bad practice to use WinForm buttons? If so, what viable alternatives exist?
I always like making a custom button class, this gives me a lot of flexibility for creating creative buttons.
The class creates a button with a texture and a position x and position y and a unique name, after i've done that i'll check my mouse position and see if it's inside the button or not, if it is inside the button then it can click the button and it will search the button by name and execute the given command :)
Here is an example of my button class: (not the best way, but hey it works perfectly for me)
public class Button : GameObject
{
int buttonX, buttonY;
public int ButtonX
{
get
{
return buttonX;
}
}
public int ButtonY
{
get
{
return buttonY;
}
}
public Button(string name, Texture2D texture, int buttonX, int buttonY)
{
this.Name = name;
this.Texture = texture;
this.buttonX = buttonX;
this.buttonY = buttonY;
}
/**
* #return true: If a player enters the button with mouse
*/
public bool enterButton()
{
if (MouseInput.getMouseX() < buttonX + Texture.Width &&
MouseInput.getMouseX() > buttonX &&
MouseInput.getMouseY() < buttonY + Texture.Height &&
MouseInput.getMouseY() > buttonY)
{
return true;
}
return false;
}
public void Update(GameTime gameTime)
{
if (enterButton() && MouseInput.LastMouseState.LeftButton == ButtonState.Released && MouseInput.MouseState.LeftButton == ButtonState.Pressed)
{
switch (Name)
{
case "buy_normal_fish": //the name of the button
if (Player.Gold >= 10)
{
ScreenManager.addFriendly("normal_fish", new Vector2(100, 100), 100, -3, 10, 100);
Player.Gold -= 10;
}
break;
default:
break;
}
}
}
public void Draw()
{
Screens.ScreenManager.Sprites.Draw(Texture, new Rectangle((int)ButtonX, (int)ButtonY, Texture.Width, Texture.Height), Color.White);
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Storage;
using System.IO;
using System.Xml.Serialization;
namespace ButtonGame
{
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
MouseState mouse, prevMouse;
/// <param name="gameTime">Provides a snapshot of timing values.</param>
public IAsyncResult result;
public Object stateobj;
public bool GameSaveRequested = false;
public GamePadState currentState;
public class GameImages
{
//Image Diminsions and Graphic
public Texture2D texture;
//Images position on the Viewport
public Vector2 position = new Vector2(0, 0);
}//GameImages
GameImages button;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
graphics.PreferredBackBufferWidth = 800;
graphics.PreferredBackBufferHeight = 600;
graphics.PreferMultiSampling = false;
graphics.IsFullScreen = false;
}//Game1()
protected override void Initialize()
{
button = new GameImages();
base.Initialize();
}//Initialize
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
//Gives the button the graphic "button.PNG" from resources
button.texture = Content.Load<Texture2D>("Button");
//Sets the drawing point of the button to the middle of the screen
button.position = new Vector2(300, 400);
}
protected override void Update(GameTime gameTime)
{
//Gets current position and condition of the mouse
mouse = Mouse.GetState();
//Makes the cursor visible on the screen of the game
this.IsMouseVisible = true;
//If the User has released the Left mouse button and previously had it pressed, (Left Clicked)
if (mouse.LeftButton == Microsoft.Xna.Framework.Input.ButtonState.Released && prevMouse.LeftButton == Microsoft.Xna.Framework.Input.ButtonState.Pressed)
{
//Check if the mouse was within the bounds of GameImage button
if (CheckForClick(button))
{
//Remove the button from view
button.position = new Vector2(5000, 5000);
}
if (mouse.Y > 600)
{
button.texture = Content.Load<Texture2D>("Catch - Red");
}
}
if (mouse.X < 50)
{
button.position.X += 3;
}
else if (mouse.X > 500)
{
button.position.X -= 3;
}
//If the User has released the Right mouse button and previously had it pressed, (Right Clicked)
else if ((mouse.RightButton == Microsoft.Xna.Framework.Input.ButtonState.Released && prevMouse.RightButton == Microsoft.Xna.Framework.Input.ButtonState.Pressed))
{
//Bring Back the button
//button.position = new Vector2(300,400);
InitiateSave();
}
else if ((mouse.MiddleButton == Microsoft.Xna.Framework.Input.ButtonState.Released && prevMouse.MiddleButton == Microsoft.Xna.Framework.Input.ButtonState.Pressed))
{
InitiateLoad();
}
//Store the current mouse position and conditon into a orevious state to prepare for new input
prevMouse = mouse;
base.Update(gameTime);
}//Update
/// <summary>
/// This is called when the game should draw itself.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Draw(GameTime gameTime)
{
spriteBatch.Begin();
//Background Color
GraphicsDevice.Clear(Color.CornflowerBlue);
//if button is not off the screen
if (button.position != new Vector2(5000, 5000))
{
//Draw the button
DrawImage(button);
}
spriteBatch.End();
base.Draw(gameTime);
}//Draw
public void DrawImage(GameImages image)
{
spriteBatch.Draw(image.texture, image.position, Color.White);
}//DrawImage
public bool CheckForClick(GameImages rectangle)
{
if (mouse.Y < rectangle.position.Y + rectangle.texture.Height &&
mouse.Y > rectangle.position.Y &&
mouse.X > rectangle.position.X &&
mouse.X < rectangle.position.X + rectangle.texture.Width)
return true;
else
return false;
}//CheckForClick
StorageDevice device;
string containerName="MyGamesStorage";
string filename = "mysave.sav";
public struct SaveGame
{
public Vector2 buttonPosition;
public Texture2D newbuttonTexture;
}//Save Game
private void InitiateSave()
{
device = null;
StorageDevice.BeginShowSelector(PlayerIndex.One, this.SaveToDevice, null);
}
void SaveToDevice(IAsyncResult result)
{
device = StorageDevice.EndShowSelector(result);
if (device != null && device.IsConnected)
{
SaveGame SaveData = new SaveGame()
{
buttonPosition = button.position,
newbuttonTexture = button.texture,
};
IAsyncResult r = device.BeginOpenContainer(containerName, null, null);
result.AsyncWaitHandle.WaitOne();
StorageContainer container = device.EndOpenContainer(r);
if (container.FileExists(filename))
container.DeleteFile(filename);
Stream stream = container.CreateFile(filename);
XmlSerializer serializer = new XmlSerializer(typeof(SaveGame));
serializer.Serialize(stream, SaveData);
stream.Close();
container.Dispose();
result.AsyncWaitHandle.Close();
}
}
private void InitiateLoad()
{
device = null;
StorageDevice.BeginShowSelector(PlayerIndex.One, this.LoadFromDevice, null);
}
void LoadFromDevice(IAsyncResult result)
{
device = StorageDevice.EndShowSelector(result);
IAsyncResult r = device.BeginOpenContainer(containerName, null, null);
result.AsyncWaitHandle.WaitOne();
StorageContainer container = device.EndOpenContainer(r);
result.AsyncWaitHandle.Close();
if (container.FileExists(filename))
{
Stream stream = container.OpenFile(filename, FileMode.Open);
XmlSerializer serializer = new XmlSerializer(typeof(SaveGame));
SaveGame SaveData = (SaveGame)serializer.Deserialize(stream);
stream.Close();
container.Dispose();
//Update the game based on the save game file
button.position = SaveData.buttonPosition;
button.texture = SaveData.newbuttonTexture;
}
}
}
}
I've simplified and reproduced my problem in a smaller program so its easier to share.
When I run the program and Right click to save, then move the object's location a bit so I can see a change and then middle click to load the game, I get the error.
What I did to reproduce the error:
Run the program
Right Click - This saved the game
Left click with the mouse past the bottom of the screen - This changes the button's image to "Catch - Red"
Position mouse to the left of the screen so that the button moves
Middle Click so that the game loads the previously saved data, the button should be centered with it's first image "button"
This is where I get the error message
ObjectdispsoedException was unhandled Cannot access a disposed object. Object name: 'Texture2D'.
on the spriteBatch.End(); line.
Admittedly I did just copy and past the save and load classes from the internet, I don't know how each step fully works.
Goal for the code: I want to be able to save the data, such as location, assigned content, arrays etc. So that it can be loaded again later.
First, you shouldn't be loading content in update. It should be done in "loadcontent", hence the name... You should load the 2 textures in load content and then swap them in update.
Second, the problem is where you set texture2D again in the load function. Because what content.load() does is loads the texture onto the graphics card. But if you reset it then the reference will change. This relates back to my first point. You should have already loaded the content when content.load is called. So you should separate the texture2d and the game objects.
For example (wont compile, but you get the idea):
class MyGameObject
{
public int textureIndex = 0;
public Vector2 position = new Vector2(0, 0);
}
class Game
{
Texture2D[] textures;
MyGameObject poop;
void loadContent()
{
textures = new Texture2D[2];
textures[0] = Content.Load<Texture2D>("a texture");
textures[1] = Content.Load<Texture2D>("different texture");
poop = new MyGameObject();
poop.textureIndex = 0;
}
void update()
{
if (mouse.Y > 600)
{
poop.textureIndex = 1;
}
}
void draw()
{
spriteBatch.draw(textures[poop.textureIndex], poop.position);
}
....other stuff....
}
I do not understand how to pause an animation of XNA. I can "Start" the animation of my model but not stop it.
I use SkinningSample_4_0 sample dll
Here is my code to use.
protected override void LoadContent()
{
//Model - Player
model_player = Content.Load<Model>("Models\\Player\\models");
// Look up our custom skinning information.
SkinningData skinningData = model_player.Tag as SkinningData;
if (skinningData == null)
throw new InvalidOperationException
("This model does not contain a SkinningData tag.");
// Create an animation player, and start decoding an animation clip.
animationPlayer = new AnimationPlayer(skinningData);
AnimationClip clip = skinningData.AnimationClips["ArmLowAction_006"];
animationPlayer.StartClip(clip);
}
protected overide update(GameTime gameTime)
{
KeyboardState key = Keyboard.GetState();
animationPlayer.Update(gameTime.ElapsedGameTime, true, Matrix.Identity);
// If player don't move -> stop anim
if (!key.IsKeyDown(Keys.W) && !keyStateOld.IsKeyUp(Keys.S) && !keyStateOld.IsKeyUp(Keys.A) && !keyStateOld.IsKeyUp(Keys.D))
{
//animation stop ? not exist ?
animationPlayer.Stop();
isPlayerStop = true;
}
else
{
if(isPlayerStop == true)
{
isPlayerStop = false;
animationPlayer.StartClip(Clip);
}
}
I finally found by myself ^^
if (!key.IsKeyDown(Keys.W) && !key.IsKeyDown(Keys.A) && !key.IsKeyDown(Keys.D) && !key.IsKeyDown(Keys.S))
{
//Stop animation for player walking
animationPlayer.Update(new TimeSpan(0, 0, 0), true, Matrix.Identity);
}
else
{
//Continue the animation
animationPlayer.Update(gameTime.ElapsedGameTime, true, Matrix.Identity);
}