In few last days trying to implement TinyKeep's dungeon generation algorithm myself.
Link to TinyKeep's dungeon generation algorithm
I don't understand it perfectly by 100%, because of it here am I :)
Firstly I generated set of rooms in circle
Going for each room in set. Pick it and going with another for loop again in set to compare every room intersection.
If room intersects, I added force, in which I will be apply separation. After that nested loop ended, I move current room, from first loop, according to that force vector. And so on. It happening until every room is not overlapped with others.
Also I picked center(Middle) point of rects ( x+width/2f, y+height/2f) to calculate that force vector
If vector is normalized, then rooms tighly packed, but if no - rooms have much space between them...
I wanna just recreate and understand TinyKeep's algorithm, but results not the same...
Also I getting weird results, then tall/wide rooms or always going in corners, tall go upper-left corner of map, wide - bottom-right corner. And all sometimes have overall diagonal separate direction
// Main method
private void Separate()
{
do
{
for (int i = 0; i < rooms.Count; i++)
{
Vector2 force = Vector2.zero;
int overlapCounter = 0;
for (int j = 0; j < rooms.Count; j++)
{
if (i == j) continue;
if (!rooms[i].IsOverlapped(rooms[j])) continue;
force += rooms[j].Middle - rooms[i].Middle;
overlapCounter++;
}
if (overlapCounter == 0) continue;
force /= overlapCounter;
force.Normalize();
force *= -1f;
rooms[i].Move(force);
}
} while (IsAnyRoomOverlapped());
StopTimer(true);
}
// Room.Move()
public void Move(Vector2 move)
{
x += Mathf.CeilToInt(move.x)* TILE_SIZE;
y += Mathf.CeilToInt(move.y)* TILE_SIZE;
}
// Constructor
public Dungeon(int roomAmount, int seed,float radius)
{
StartTimer();
this.roomAmount = roomAmount;
this.radius = radius;
Seed = seed;
InitializeRandom();
PopulateDungeonWithRooms();
}
While trying to figure out how solve this problem I read some questions and look their source code. I find that they not only move room after every overlapped neighbour found but also move neighbour in other direction!
What about directional behaviour of separation? It's my mistake or misunderstanding of rounding to integer
What about perfomance? Generating 512 rooms inside circle with radius of 128 units using normal distribution give 1100 ms
Now, code looks like:
private void SeparateRooms()
{
do
{
for (int current = 0; current < rooms.Count; current++)
{
for (int other = 0; other < rooms.Count; other++)
{
if (current == other || !rooms[current].IsOverlapping(rooms[other])) continue;
var direction = (rooms[other].Middle - rooms[current].Middle).normalized;
rooms[current].Move(-direction, TILE_SIZE);
rooms[other].Move(direction, TILE_SIZE);
}
}
}
while (IsAnyRoomOverlapped());
StopTimer(true);
}
And Room's Move() method:
public void Move(Vector2 move,int tileSize=1)
{
x += Mathf.RoundToInt(move.x)*tileSize;
y += Mathf.RoundToInt(move.y)*tileSize;
}
Related
I would like to retrieve the Transform/Position of an animationClip at a given time/frame.
I can actually set an animationClip to a given time with animationClip.SampleAnimation()(https://docs.unity3d.com/ScriptReference/AnimationClip.SampleAnimation.html)
Therefore I could eventually create a clone, put it on a specific frame and get his position, but it would be too heavy for each frame.
If you have any solutions, or maybe some functions that I didn't see I would be glad.
Thank you
I've found the solution, it takes a lot of process, but as it's done only in Editor it doesn't affect the game.
I am getting the curve of the animationclip and I store 10 position, each corresponding to 10% of the animation.
For this I need to compute each x, y and z axis curves :
void OnValidate()
{
//Check if we are in the Editor, and the animationClip is getting change
if (Application.isEditor && !Application.isPlaying && previousClip != animationClip)
{
previousClip = animationClip;
m_checkPoints = new Vector3[10];
int index = 0;
//Taking the curves form the animation clip
AnimationCurve curve;
var curveBindings = AnimationUtility.GetCurveBindings(animationClip);
//Going into each curves
foreach (var curveBinding in curveBindings)
{
//Checking curve's name, as we only need those about the position
if (curveBinding.propertyName == "m_LocalPosition.x")
index = 0;
else if (curveBinding.propertyName == "m_LocalPosition.y")
index = 1;
else if (curveBinding.propertyName == "m_LocalPosition.z")
index = 2;
else
continue;
//Get the curveform the editor
curve = AnimationUtility.GetEditorCurve(animationClip, curveBinding);
for (float i = 0; i < 10; i++)
{
//Evaluate the curves at a given time
m_checkPoints[(int)i][index] = curve.Evaluate(animationClip.length * (i / 10f));
}
}
}
}
I am a fairly new programmer and after learning my c# basics i am trying to get into game development with Unity. Right now i am coding a small mobile game. I want to add an one screen multiplayer to it. I had an easy script set up which gathered the starting and ending position of the swipe and calculated the path between the two points. then it compared the absolute of Δx with the absolute of Δy and finally it testet whether the coordinate is below or above 0. this works quite nicely but obviously it would not work for my planned one screen multiplayer. first i tried just testing whether the starting point of a swipe is located to the left or right of the screen center. this also worked quite nicely but it could obviously not track two swipes at the same time. then i tried changing the variables to arrays and adding a for (later a foreach loop). now whenever i swipe in one direction it repeats the signal every frame even if i clear the slot in the array at the beginning of the loop... after literally one and a half days of trying stuff out and searching for answers i now came around to adding my own question. thank you in advance.
public class HopefullyWorkingSwipeDetector
{
Vector2[] av2_TouchPos1L = new Vector2[5];
Vector2[] av2_TouchPos2L = new Vector2[5];
Vector2[] av2_TouchPathL = new Vector2[5];
public int[] aint_TouchDirectionL = new int[5]; // Up: 0; Down: 1; Right: 2; Left: 3; n/a: 4;
public int int_SwipePendingL;
public int int_CountTouchesL = 0;
public void ListenForSwipeP1()
{
int_CountTouchesL = 0;
int_SwipePendingL = 0;
foreach (Touch touch in Input.touches)
{
if (Input.touchCount > 0 && Input.GetTouch(int_CountTouchesL).phase == TouchPhase.Began && Input.GetTouch(int_CountTouchesL).position.x < Screen.width / 2)
{
int_SwipePendingL = int_CountTouchesL;
av2_TouchPos1L[int_SwipePendingL] = Input.GetTouch(int_SwipePendingL).position;
}
else if (Input.touchCount > 0 && Input.GetTouch(int_SwipePendingL).phase == TouchPhase.Ended && Input.GetTouch(int_SwipePendingL).position.x < Screen.width / 2)
{
av2_TouchPos2L[int_SwipePendingL] = Input.GetTouch(int_SwipePendingL).position;
av2_TouchPathL[int_SwipePendingL] = av2_TouchPos2L[int_SwipePendingL] - av2_TouchPos1L[int_SwipePendingL];
if (Mathf.Abs(av2_TouchPathL[int_SwipePendingL].x) < Mathf.Abs(av2_TouchPathL[int_SwipePendingL].y)) //Vertical
{
if (av2_TouchPathL[int_SwipePendingL].y > 0) //up
{
aint_TouchDirectionL[int_SwipePendingL] = 0;
}
else if (av2_TouchPathL[int_SwipePendingL].y < 0) //Down
{
aint_TouchDirectionL[int_SwipePendingL] = 1;
}
}
else if (Mathf.Abs(av2_TouchPathL[int_SwipePendingL].x) > Mathf.Abs(av2_TouchPathL[int_SwipePendingL].y)) //horizontal
{
if (av2_TouchPathL[int_SwipePendingL].x > 0) //Right
{
aint_TouchDirectionL[int_SwipePendingL] = 2;
}
else if (av2_TouchPathL[int_SwipePendingL].x < 0) //left
{
aint_TouchDirectionL[int_SwipePendingL] = 3;
}
}
}
else
{
aint_TouchDirectionL[int_CountTouchesL] = 4;
}
int_CountTouchesL++;
}
}
}
Currently I try to write a 2D roulette wheel in C# using Monogame as framework.
I'm quiet experienced with Monogame but I never had to manage fast moving textures to stick together tho.
The idea is that 3 textures(black, red, green) are connected to each other in a line of 15 objects.
That's fine as long as I don't start to scroll all these objects to actually "make the wheel move".
After moving for a while, the textures are no more connected to each other. They get some space in between or start to overlap.
I made a short Video to clarify the problem: https://puu.sh/vwbyU/d396c6ad99.mp4 (It's about 10 MB, some Browsers may have download it before it shows up)
This is the most important code:
const int _roulleteOffset = 170; // X coordinate to start at
Sprite[] fieldList = new Sprite[15]; // Represents my wheel (Array of my roulette fields/textures)
Rectangle scrollArea; // Fixed Area for the complete fieldList
float scrollSpeed = 0.0f; // Scrollspeed of the wheel. 0 on start.
// First I call the Content.Load to fill fieldList.Texture then
// this is called to position the "wheel" objects
private void AdditionalInit()
{
for (int i = 0; i < fieldList.Length; i++)
{
fieldList[i].Position = new Vector2(_roulleteOffset + i * fieldList[i].Texture.Width, Statics.GAME_WINDOW_HEIGHT / 2 - fieldList[i].Texture.Height / 2);
}
scrollArea = new Rectangle((int)fieldList[0].Position.X, (int)fieldList[0].Position.Y, fieldList[0].Texture.Height * fieldList.Length + 30, fieldList[0].Texture.Height);
}
// This Method is called in Update() - And I guess the problem has to be fixed here
private void ScrollRoulette()
{
for (int i = 0; i < fieldList.Length; i++)
{
fieldList[i].position.X += scrollSpeed; // scrollSpeed is set with pressing + or - on keyboard
if (fieldList[i].Position.X >= scrollArea.Width + fieldList[i].Texture.Width)
{
// After leaving the "scrollArea" set it to the start of it (Leaving on right side and entering at the left side again)
fieldList[i].position.X = scrollArea.X - fieldList[i].Texture.Width;
}
}
}
// The part of my Draw Method. But I don't think that I made a mistake here
public override void Draw(GameTime gameTime)
{
Statics.SPRITEBATCH.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend);
for (int i = 0; i < fieldList.Length; i++)
{
Statics.SPRITEBATCH.Draw(fieldList[i].Texture, fieldList[i].Position, null, Color.White, 0f, Vector2.Zero, 1f, SpriteEffects.None, 0f);
}
Statics.SPRITEBATCH.End();
}
Just watch the Video to understand what I'm talking about. Maybe you can help me with it. Even on slow speed the textures starts to disconnect or overlap over time.
With help from another german forum I resolved the problem! Thanks god. Took me a whole day these 1 line. I just had to adjust the positioning of the incoming tile. Not just set pos.x to the start.
private void ScrollRoulette()
{
for (int i = 0; i < fieldList.Length; i++)
{
fieldList[i].position.X += scrollSpeed;
if (fieldList[i].Position.X >= scrollArea.Width + (fieldList[i].Texture.Width * 2))
{
// This works now
fieldList[i].position.X = scrollArea.X + (fieldList[i].Position.X - (scrollArea.Width + scrollArea.X) );
}
}
}
I am developing a game server and currently I need to be able to get spectators within an area, however I fear the one I am using is really ugly and "slow" but I haven't experienced any performance hits yet as I am testing it locally not on a live server.
This is my GetSpectators Function:
public void GetSpectators(ref HashSet<Player> Players, Coordinate_t coordinate, bool MultiFloor = false)
{
for (int x = coordinate.X - 11; x != coordinate.X + 11; x++)
{
for (int y = coordinate.Y - 11; y != coordinate.Y + 11; y++)
{
if (MultiFloor)
{
for (int z = coordinate.Z - 2; z != coordinate.Z + 2; z++)
{
Tile tile = GetTile(x, y, z);
if (tile != null)
{
foreach (Player p in tile.Creatures)
{
Players.Add(p);
}
}
}
}
else
{
Tile tile = GetTile(x, y, coordinate.Z);
if (tile != null)
{
foreach (Player p in tile.Creatures)
{
Players.Add(p);
}
}
}
}
}
}
I have this class Map which holds this other dictionary with class Tile, each tile is represented with X, Y, and Z coordinates, each tile holds a list of this class called Player, some tiles have players some don't.
I need a good way and not ugly to get e.g:
All players within x=100, y=100, z=7 in radius 11 for example.
I think it would be smart to reference tiles in your Player class if you're not already doing so, and then pass the all the players to the GetSpectators() method...
Something like...
public class Player
{
// a reference to the tile that the player is currently on.
public Tile CurrentTile { get; set; }
}
This would allow you to loop through the players instead of so many tiles. And it should be cleaner and more efficient to find players the way you want without all the loop nesting. For ex:
public List<Player> GetSpectators(Hashset<Player> playersInGame, Coordinate coord)
{
var playersInRange = new List<Player>();
// iterate through each player.
foreach (var p in playersInGame)
{
// check if the tile the player is sitting on is in range of radius given.
if ((p.CurrentTile.X < coord.X + 6 || p.CurrentTile.X > coord.X - 6)
&&
(p.CurrentTile.Y < coord.Y + 6 || p.CurrentTile.Y > coord.Y - 6))
{
// Player is within radius.
playersInRange.Add(p);
}
}
return playersInRange;
}
You can add in the additional check for Z coordinate, and any other conditional statements. But as you can see, this would allow you to use one loop rather than 3 nested loops. You may or may not find it useful. But I hope it helps.
You can use circle equation to check whether player lies in the given radius of other player i.e
if
x1=100,y1=100,z=7 and r=11
then
(x-x1)^2+(y-y1)^2+(z-z1)^2=r^2.
Any point which satisfy this equation will lie in the region.
I am attempting to create a 2d scrolling XNA game as a learning exercise, but have run into some issues with the scrolling background. I am loading a level from a text file, parsing through to create the appropriate tiles and store them in a matrix (tiles[,]).
I then have an update method which alters the position of the tile so when it is redrawn it will move.
Currently, I loop through all tiles to draw them all before moving. This is clearly not very efficient. Ideally, I only want to draw the tiles on the screen. I can do this by taking the viewport and using the height/width of a tile to determine how many tiles will fit on the screen and only loop through those tiles, as follows:
private void DrawTiles(SpriteBatch spriteBatch)
{
float tileWidth = 40;
float tileHeight = 32;
for (int y = 0; y < (int)Math.Ceiling(mViewport.Height / tileHeight); ++y)
{
for (int x = 0; x < (int)Math.Ceiling(mViewport.Width / tileWidth); ++x)
{
tiles[x, y].Draw(spriteBatch);
}
}
}
However, this only draws the iles in the original viewport. Tiles outside will never be drawn even though their position does come into view.
I think this can be resolved by using a counter to start and end the loop, incrementing it each time the draw method is called. However, I do not think this is a great solution, but alas I cannot think of a better way to ensure only tiles in the viewport are drawn.
You need to keep track of the starting X and Y of the ViewPort, as you're always starting at 0 in your example. e.g.
var startX = 10; // Should increment as viewport scrolls
var startY = 10; // Should increment as viewport scrolls
...
for (int y = startY; y < (int)Math.Ceiling(mViewport.Height / tileHeight); ++y)
{
for (int x = startX; x < (int)Math.Ceiling(mViewport.Width / tileWidth); ++x)
{
tiles[x, y].Draw(spriteBatch);
}
}
On a side note, your ViewPort probably has a Top and Left or X and Y to keep track of this as well. In that case, replace startX and startY with the appropriate property from your ViewPort.
What I implemented in my design was an inherited interface that contained the properties IsInView and a collision property or in your case a position could be substituted. I then created a seperate thread that would loop through and determine if the object is in view. you can then in each object have the InView and OutView add and remove it from a draw list.
Run from seperate thread with a loop. -- This could be adapted to determine if the tile is visible
public void CalculateObjsInView()
{
foreach (Obj o in new List<Obj>(ObjInstanceList))
{
if (o == null)
continue;
if (Camera.CollisionMask.Intersects(o.CollisionMask))
o.IsInView = true;
else
o.IsInView = false;
}
}
In Obj class
private bool _isInView = false;
public bool IsInView
{
get { return _isInView; }
set
{
if (_isInView != value)
{
if (value)
InView();
else
OutView();
}
_isInView = value;
}
}
private void InView()
{
Game.ObjectDrawEventHandler.Add(Draw);
}
private void OutView()
{
Game.ObjectDrawEventHandler.Remove(Draw);
}