Passing list as a parameter: player vs the world - performance

I'm creating a top-down 2D game.
Classes in question are Level and Entity.
In Level I have a Map, but let's just think of that class as a list of items like walls and other stuff you can imagine will have a body, which is actually a XNA's Rectangle.
Now, in Level's Update function, I'll be putting Entity's function that will resolve all collisions (walls, pickups, other entities, traps, etc), and I am questioning the best way of letting each Entity know what's around him. By doing that I want to achieve the freedom of creating different Entityes such as different players, enemies, bosses... Goal is a good parent class for everything that should feel alive to the player playing the game.
So, I want to get a good performance for this function (that'll resolve collisions), because I plan on making maps that'll have around 1000 different items and many entities, and can't decide how to go about it.
The structure is something like this: Level has a list of items (walls, pickups, traps...) and a list of entities (players, enemies, bosses, pets, mounts, whatever...), and in each update of level I loop trough entities and do Update for each.
Question Do I:
1) send whole list of items to each entity('s update method) and calculate distances from each item and resolve collision
2) calculate closest items to the entity in level's update method and then send smaller list of items to the entity, which will then resolve collision
3) (this I just thought of) pass list of XNA's Rectangles and type of item (that could mean I must make a new class or new function for map class that will return 2 lists: rectangles and item types)
4) pass the whole map, but in a matix (because map will be a grid, not items nor player's rectangles will rotate) of integers that'll have something like "1 for wall, 0 for nothing, 2 for trap, 3 for health-pack, etc). But this will resolve only the map, because other entities won't all be in grid coordinates (wall's positions will be like 32x32, 0x64, etc, and all will be 32x32, but entities won't. They'll be 32x16, and their position may vary. That also crossed my mind just now.
Note that both entities and items will most likely have much more than Rectangle for body. There will be textures, animations, and other basic types of variables for different purpose, and most of them won't be needed for entities collision resolution with that item. When colliding with a wall, entity won't need that items image to resolve collision, but it will need items (lets say) X value if that item is a healt potion.
How would you resolve this so the code is efficient, or how did you resolve this in your game?
I am looking for simpicity and efficiency, and that's what I will be looking for in your answer.

I haven't tested this code at all, so if it doesn't work, thats why.
Given that Entity is a struct with the following code,
struct Entity{
Rectangle pos;
Texture2D tex;
bool hasAgency;
public Entity(Rectangle pos, Texture2D tex, bool hasAgency){
this.pos = pos;
this.tex = tex;
this.hasAgency = hasAgency;
}
}
then this should work.
List<Entity> entityList = new List<Entity>//your entities are here
for(int testIndex=0; testIndex<entityList.Count; testIndex++){
for(int entityBeingTested = 0; entityBeingTested<entityList.Count; entityBeingTested++){
if(testIndex!=entityBeingTested && entityList[testIndex].hasAgency)
{
if(entityList[testIndex].pos.Intersects(entityList[entityBeingTested.pos]))
//hit logic here
}
}
}

Related

How to do interchangeable armor on character (low poly models)

I'm currently working on RPG graphically very similar to Runescape (old school), but with my own game system. I am not sure what is the best way to have interchangeable armor system. I am going to create low poly models, as i said, similar to runescape models like here, and want to have possibility to have random variations of armor like here.
There are two ways as I understand, first is just to change mesh of my character model, the second one is to create model of my character and use the bones weights to armor models. I know there is whole topic about the first option here (couldn't make 3rd link) forum.unity3d.com/threads/stitch-multiple-body-parts-into-one-character.16485/, but really? Every qeustion about something similar leads to this topic. But its like 8 years old and for Unity 2.0...Is there simplier way to achieve same results but don't study masterprompt's exhausting explanation which I'm not gonna be able to implement anyway. And for the second way I can't find any hints, except manual and script on unity web for bone weight, which is way too general for my use and my skills. I have spent looking for some solutions (tutorials) for hours, but google keeps popping the same topics, which are 4-8 years old...
Any advice how to choose the best way for changing armors and how to gain any knowledge about these issues? Thank You.
So what I'm doing in my projects is I duplicate my base character .blend file (rig, model) and I remove most of the mesh except for the body part that I want to make the clothing for (chest/legs). I pull it out a bit so the vertices doesn't overlap with base mesh and just save it.
Then in Unity I create a new prefab out of the model I just saved. The hierarchy of a prefab looks like this: parent game object with BoneReplacer.cs script -> child game object with skinned mesh renderer of my clothing.
Then all I have to do is just drag this prefab onto my character prefab so the target variable in this script points to my character's skinned mesh renderer.
This probably isn't the best way to do this but it works for me, maybe it will help you get your head around it and create some better solution.
Heres the BoneReplacer.cs script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BoneReplacer : MonoBehaviour
{
public GameObject target;
SkinnedMeshRenderer myRenderer;
Transform[] newBones;
SkinnedMeshRenderer targetRenderer;
Dictionary<string, Transform> boneMap = new Dictionary<string, Transform>();
void Start()
{
target = transform.parent.parent.gameObject;
targetRenderer = target.GetComponentInChildren<SkinnedMeshRenderer>();
foreach (Transform _bone in targetRenderer.bones)
{
boneMap[_bone.gameObject.name] = _bone;
}
myRenderer = gameObject.GetComponent<SkinnedMeshRenderer>();
newBones = new Transform[myRenderer.bones.Length];
for (int i = 0; i < myRenderer.bones.Length; i++)
{
GameObject _bone = myRenderer.bones[i].gameObject;
if (!boneMap.TryGetValue(_bone.name, out newBones[i]))
{
Debug.Log("Unable to map bone ~" + _bone.name + "~ to target skeleton!");
break;
}
}
myRenderer.bones = newBones;
myRenderer.rootBone = targetRenderer.rootBone;
}
}

How to move a SCNNode in the direction it is pointing at after an rotation is applied

My dilemma is this:
I have a spaceship positioned somewhere in space between stars and planets. The camera is added as a child of the spaceshipNode and you always look at the back of the spaceship (raised a few units above).
I use CoreMotion to rotate the spaceship like this:
func startMonitoringMotion() {
self.motionManager?.startDeviceMotionUpdates(to: OperationQueue.main, withHandler: { (data, error) in
guard let data = data else { return }
let attitude: CMAttitude = data.attitude
self.ship.eulerAngles = SCNVector3Make(Float(attitude.roll - M_PI_2), Float(attitude.yaw), Float(attitude.pitch))
})
}
and the rotation works as expected.
Now I want to move the spaceship in the direction it is facing but I have no clue how to do it. I have tried different approaches but I have failed miserably.
I have searched this forum countless times for several days but with no luck.
I hope someone can point me (and my spaceship) in the right direction.
Thank you in advance.
I've found that the easiest way to do this is to grab the third row of the node's worldTransform property, which corresponds to its z-forward axis.
func getZForward(node: SCNNode) -> SCNVector3 {
return SCNVector3(node.worldTransform.m31, node.worldTransform.m32, node.worldTransform.m33)
}
ship.position += getZForward(ship) * speed // nb scalar multiply requires overload of * func
// if node has a physics body, you might need to use the presentationNode, eg:
// getZForward(ship.presentationNode)
// though you probably don't want to be directly modifying the position of a node with a physics body
See the discussion here Getting direction that SCNNode is facing
iOS 11 update
iOS 11 adds handy convenience functions for getting the orientation of a node. In this case the worldForward property is the one you want. Also, all of the properties on SCNNode that return SCNVector and matrix types now have versions that return simd types. Because simd already has overloads for the arithmetic operators, you no longer need to add sets of arithmetic overrides for the SCNVector and SCNMatrix types.
So we can get rid of out getZForward method above, and just have the line:
ship.simdPosition += ship.simdWorldFront * speed

Performance problems with scenekit

I've got a row dimensional array of values that I want to visualize in 3D and I'm using scene kit under OS X for it. I've done it in a clumsy manner by using each column as a point on the X axis, each row as a point on the Z axis, and each value as a normalized point on the Y axis -- I place a sphere at the vector defined by each data point. It works but it doesn't look too good.
I've also done this by building a mesh of lines based on #Matthew's function in Drawing a line between two points using SceneKit (the answer he posted, not the original question). For each point I use his function to draw two lines - one between my current point and the next point to the right and another between my current point and the next point towards the front (except when there is no additional column/row, of course).
Using the second method, my results look much better... however the performance is quite hideous! It takes quite a long time to complete the initial rendering, and if I use a trackpad/mouse to rotate or translate the scene, I might as well get a cup of coffee to wait until my system is usable again (and this is not much hyperbole). Using the sphere method, things render and update very quickly.
Any advice on how to improve the performance when using the lines method? (Note that I am not trying to add both lines and spheres at the same time.) Code-wise, the only difference between approach is which of the following methods gets called (and that for each point, addPixelAt... is called once, but addLineAt... is called twice for most points).
- (SCNNode *)addPixelAtRow:(CGFloat)row Column:(CGFloat)column size:(CGFloat)size color:(NSColor *)color
{
CGFloat radius = 0.5;
SCNSphere *ball = [SCNSphere sphereWithRadius:radius*1.5];
SCNMaterial *material = [SCNMaterial material];
[[material diffuse] setContents:color];
[[material specular] setContents:color];
[ball setMaterials:#[material]];
SCNNode *ballNode = [SCNNode nodeWithGeometry:ball];
[ballNode setPosition:SCNVector3Make(column, size, row)];
[_baseNode addChildNode:ballNode];
return ballNode;
}
- (SCNNode *)addLineFromRow:(CGFloat)row1 Column:(CGFloat)column1 size:(CGFloat)size1
toRow2:(CGFloat)row2 Column2:(CGFloat)column2 size2:(CGFloat)size2 color:(NSColor *)color
{
SCNVector3 positions[] = {
SCNVector3Make(column1, size1, row1),
SCNVector3Make(column2, size2, row2)
};
int indices[] = {0, 1};
SCNGeometrySource *vertexSource = [SCNGeometrySource geometrySourceWithVertices:positions count:2];
NSData *indexData = [NSData dataWithBytes:indices length:sizeof(indices)];
SCNGeometryElement *element = [SCNGeometryElement geometryElementWithData:indexData
primitiveType:SCNGeometryPrimitiveTypeLine
primitiveCount:1
bytesPerIndex:sizeof(int)];
SCNGeometry *line = [SCNGeometry geometryWithSources:#[vertexSource] elements:#[element]];
SCNMaterial *material = [SCNMaterial material];
[[material diffuse] setContents:color];
[[material specular] setContents:color];
[line setMaterials:#[material]];
SCNNode *lineNode = [SCNNode nodeWithGeometry:line];
[_baseNode addChildNode:lineNode];
return lineNode;
}
From the data that you've shown in your question I would say that your main problem is the number of draw calls. Your's is in the tens of thousands, which is way too much. It should probably be a lot closer to ~100.
The reason why you have so many draw calls is that you have so many distinct objects in your scene (each line). The better (but more advanced solution) would probably be to generate a single element for the entire mesh that consists of all the lines. If you want to achieve the same rendering with that mesh (with a color from cold to warm based on the height) then you could do that in a shader modifier.
However, in your case I would start by flattening all the lines (since that would be the smallest code change and should still have a significant performance improvement in your case).
(Optimizing performance is always an iterative process. Once you fix one thing there will be another thing which is the most expensive operation. Without your code I can only say what would help with the current performance problem)
Create an empty node (without adding it to your scene) and generate all the lines, adding them to this node. Then create a flattened copy of that node by calling flattenedClone on the node that contains all the lines
SCNNode *nodeWithAllTheLines = [SCNNode node];
// create all the lines and add them to it...
SCNNode *flattenedNode = [nodeWithAllTheLines flattenedClone];
[_baseNode addChildNode:flattenedNode];
When you do this you should see a significant drop in the number of draw calls (the number after the diamond in the statistics) and hopefully a big increase in performance.

Random World Generation

I'm starting to go into random world generating, I have an idea on how random number generating works (Actually pseudorandom numbers), but I don't have a good idea of how to make the world look "nice", in other words not just place blocks based on a random x, y that it gives me, but make it look smooth.
This will be a 1 time generation per world. So everything is created at start.
I was thinking of an algorithm a few moments ago, but the problem is that it would just use be an endless amount of nested if loops, which would probably take a more than the necessary time. I was thinking of the following:
Choose a random location on the map and place the spawn point in that location.
Start building the street based on the spawn location, like if the spawn location is 16
spaces near the edge of the world build a house, otherwise start building a street.
Based on the previously generated street's place structures around.
Place misc.
Conceptualizing the algorithm isn't much of a problem, what I'm having difficulty with is starting the actual code from step 2 and below. Based on the above algorithm or an algorithm you think of, how would you start the code? I'm not asking for the actual code to be made, just an idea of how it would look.
I know this question isn't precise and can have multiple answers, but I've seen many questions similar to this one having a strange approach.
hmm looks like planar(or cubic) map filling. from my point of view firstly you need some databases
struct _object
{
string name,help,info; // texts for later use
int siz[3]; // grid size of object
int pos[3]; // placement pos (center or what ever)
// other stuff like: mesh-id,color,hit points,...
};
struct _dependency
{
int objid
List<int> near; // can be near this objects (can add probability)
List<int> far; // cannot be near this objects (can add probability,min distance)
};
List<_object> object; // DBS of all object types
List<_dependency> depend; // DBS of object dependency
Then you need to initialize this DBS from ini files or whatever. After that you need to create world map. For simplicity let it by only a single squared town and single layer(no sub-terrain), size and placement can be random.
List<_object> obj; // DBS of placed objects, could be lesser derivate of previous _object to conserve memory requirements
const int N=100;
int[N][N] map; // placement map, containing placed obj id, or -1 for empty space
so now you need some town generating function that fills map[N][N]:
void genere()
{
int i,j,x,y,xx,yy,objid,objix;
int _min_complexity=N/10; // this can also be random
int _max_complexity=N; // this can also be random
// clear map
for (i=0;i<N;i++)
for (j=0;j<N;j++)
map[i][j]=-1;
int complexity=_min_complexity+random(_max_complexity-_min_complexity);
for (i=0;i<complexity;)
{
// random placenet position
x=random(N);
y=random(N);
// random object, should take in mind object[].near and closest objects in map[y][x]
objid=random(object.num);
if (check if map[][] is empty enough to place object[objid] to x,y,z)
if (check if near x,y position is not bad type of object already object[].far)
{
// add new object to list
objix=obj.add(object[objid]);
// add new object to map
int *siz=obj[objix].siz
int *pos=obj[objix].pos
x+=pos[0];
y+=pos[1];
for (yy=0;yy<siz[1];yy++)
for (xx=0;xx<siz[0];xx++)
map[y+yy][x+xx]=objid;
i++;
}
}
}
also the position can be double[3] + orientation matrix and map coordinates will than be aligned to grid. There are many ways to tweak this code, its just an starting template. Hope it helps a little.
P.S.
List<type> l;
l.num - number of items in list
l[i] - i item from list
i=l.add(a) - add new item a to list and returns its index

XNA: Identifying identical sprites created with for loop

G'day all,
In short, I'm using a for loop to create a bunch of identical sprites that I want to bounce around the screen. The problem is how do I write a collision detection process for the sprites. I have used the process of placing rectangles around sprites and using the .intersects method for rectangles but in that case I created each sprite separately and could identify each one uniquely. Now I have a bunch of sprites but no apparent way to pick one from another.
In detail, if I create an object called Bouncer.cs and give it the movement instructions in it's update() method then create a bunch of sprites using this in Game.cs:
for (int i = 1; i < 5; ++i)
{
Vector2 position = new Vector2(i * 50, i * 50);
Vector2 direction = new Vector2(i * 10, i * 10);
Vector2 velocity = new Vector2(10);
Components.Add(new Bouncer(this, position, direction, velocity, i));
}
base.Initialize();
I can draw a rectangle around each one using:
foreach (Bouncer component1 in Components)
{
Bouncer thing = (Bouncer)component1;
Rectangle thingRectangle;
thingRectangle = new Rectangle((int)thing.position.X, (int)thing.position.Y, thing.sprite.Width, thing.sprite.Height);
But now, how do I check for a collision? I can hardly use:
if (thingRectangle.Intersects(thingRectangle))
I should point out I'm a teacher by trade and play with coding to keep my brain from turning to mush. Recently I have been working with Python and with Python I could just put all the sprites into a list:
sprites[];
Then I could simply refer to each as sprite[1] or sprite[2] or whatever its index in the list is. Does XNA have something like this?
Please let me know if any more code needs to be posted.
Thanks,
Andrew.
One solution, which I use in my game engine, is to have a Logic code run inside the objects for every game Update, ie. every frame. It seems you already do this, according to the variable names, which indicate you run some physics code in the objects to update their positions.
You might also want to create the collision rectangle inside the Bouncer's constructor so it's more accessible and you make good use of object oriented programming, maybe even make it an accessor, so you can make it update every time you call it instead of manually updating the bounding/collision box. For example:
public Rectangle #BoundingBox {
get { return new Rectangle(_Position.X, _Position.Y, width, height); }
}
Whichever way works, but the collision checks can be run inside the Bouncer object. You can either make the reference list of the Bouncer objects static or pass it to the objects itself. The code for collisions is very simply:
foreach(Bouncer bouncer in Components) //Components can be a static List or you can pass it on in the constructor of the Bouncer object
{
if (bouncer.BoundingBox.Intersects(this.BoundingBox))
{
//they collided
}
}

Resources