• Advertisement
  • Popular Tags

  • Popular Now

  • Advertisement
  • Similar Content

    • By Michael Santer
      Hi!
      We're currently two programmers and a game designer working on a turn-based tactics fantasy board game. For reference you can search for images of "Tactics Arena Online", a fairly dated game that used to have a lot of depth and complexity.
      Our goal is to use the same combat concepts, but giving it a much needed modern touch as well as a whole new set of heroes to choose from with additional abilities. The game is a mix of isometric and 3D and we plan to release the game on Steam and hopefully Android & iOS as well.
      We are looking for someone to work with us pro-bono (just like we're doing) as a 3D character artist. The skills needed are creativity, a hard working attitude and an ability to make minor animations (things like idle, walk, block and very rudimentary attack animations). A perk to have would be the ability to make some VFX. If the game makes it on steam and money starts coming in, you'd obviously be compensated for your hard work, but as it stands this is a hobby project to garnish your portfolio.
      A bit more about the game:
      This game will be an online multiplayer game where each user gets to pick up to 10 characters to place on his half of the board (this would be done before even entering matchmaking. Think runes in League of Legends for example). The user can place his 10 units of choice anywhere he likes on his half board. Some units can be used more than once. So if you want 4 knights and 2 mages or even if you want 10 clerics, you can do as you please. You can then save your setups for future use. The goal of the game is to wipe out the enemy team.
      Each character or Hero (except premium and abyss characters) start with 1 ability and they can ascend (either by playing a certain amount of matches with the character or by forcing the ascension with real money) to gain a new ability or passive. Acquiring a new character can be done by using in-game currency that you earn from playing matches or using real money with the exception of Abyss characters which can only be acquired by winning certain rare matches. The goal is to offer a freemium game with lots of customizable elements while making sure that no user can "buy power" with real money. We want everything that a paying user can get to be available to non-paying users who play the game a lot.
      Ultimately we want this to become a competitive game that people can enjoy and really get invested in. Each character is designed with options for counterplay in mind and synergy with other heroes.
       
      We sincerely believe in what this game can become and we home to find someone just as passionate as we are to get involved in this project!
    • By CrazyApplesStudio
         Hello , i would like to showcase my first game project, a simple endless casual arcade game called Apples Mania : Apple Catcher. The game has simple goal , scoring as high as possible by collecting falling apples while the difficulty gradually increases. Different apples are worth different amount of points and there are also 2 power-ups to help you in your challenge.
        The game took me about 2 months to complete and polish and i made everything except for the music tracks and some of the sound files. Made in unity and blender3d.
        Would appreciate any kind of feedback.
      Google Play Link
       
        A trailer showing basic game-play:
       
    • By Paszq
      Troglodytes are a playable races in Arpago - they usually don't talk much and most of them lives near water sources.
    • By Paszq
      a Fox in a dungeon :)
    • By Paszq
      Fox Folk is one of 3 playable races in Arpago.
  • Advertisement
  • Advertisement
Sign in to follow this  

Unity Smash Bros Style Camera

This topic is 886 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello ladies and gentlemen! Thanks for taking the time to look at my topic. I massively appreciate it :)

 

I'm experimenting with different camera modes in my game at the moment, and I've come across a bit of a problem

regarding multiplayer. I want to create a camera which can fit all of the players in the screen at all times. I've actually

already worked out half of the problem. The camera essentially averages the positions of all players in the GameSpace

and then centers between all of them, meaning they all have equal coverage of the camera.

 

This does not, however, take zoom into account! If the players disperse too far from one another, they all leave the camera's

view, and it stays right in the center of the battle, no matter how spaced apart it may be.

 

I've spent a very long and painful few hours looking for ANYTHING explaining how to do this, but the only two tutorials which

seem to come up are a Unity one (XNA/MonoGame) do not support the functions available, and a tutorial which refers to

the indie game "Demons with Shotguns" which seems to have come up about 10 times!!

 

Could somebody possibly explain in the most unconvoluted way possible how I can take the positions of the players and

somehow convert that into a zoom factor which always keeps the players in view? I think I heard something about using

a cross product calculation, but there was no further explanation.

 

Any help would be super appreciated! Thank you :D

Share this post


Link to post
Share on other sites
Advertisement

Do you have zoom functionality available? For 2D this is actually quite simple to calculate.

 

Once you're centered you should have an x/y world coordinate that you're placing the camera at. You need to do a little (very little) vector math on the players to find out which one is farthest from that point in the x dimension and which one is farthest in the y dimension.

 

To find the relative coordinate of a player from the center-point, just:

 

relative_pos = player.pos - centerpoint

 

using 2D vectors. Create max_abs_x and max_abs_y variables and set them both to zero (or some minimum value that you decide). Iterate through the players and determine their relative positions, then abs the x and y and if either of them is larger than the value in your max variables then replace that value with the new larger one. You'll end up with a pair of values representing the half-width of the minimum area you need to represent. You can add a buffer at this point if you want so that the players aren't at the absolute screen edge.

 

Once you have that you just need to consider the size of the viewport compared to the result.

 

Say you have a viewport that's 800x600. The half-width dimensions of the viewport are 400 and 300. If your max_abs_x is 500 and your max_abs_y is 500 then you can get the ratios:

 

x_ratio = 500 / 400 = 1.25

y_ratio = 500 / 300 = 1.66~

 

So you can see that the larger of the two is the y, so you need to zoom to a factor of 1.66~.

 

Depending on how your zoom is implemented you may be able to just plug that in directly.

 

You'd only need to get a little more complicated if you're working with a 3D'ish camera and need to move the camera back and forth or play with the field of view.

Share this post


Link to post
Share on other sites

Thank you so much for such a detailed response biggrin.png

 

I'll actually post up a snippet of the code so you can see what's going on once I have the problem completed, and hopefully

people might be able to learn something from it! The positioning section seems to be working fine, but I can't get the zoom to

work properly. It seems to almost be doing the inverse, by zooming out as players get nearer, and vice versa. I also noticed the

the camera just completely snaps out of correct zoom sometimes if players cross the middle of the screen. This is really

confusing me now.

 

The top section of this code works fine - it's the second half (which I separated with a comment) that is causing all the issues!

switch (camera.cameraType)
            {
                case (Camera.CameraType.SmashBros):

                    //This section sorts the camera positioning and works fine:
                    List<float> positionsX = new List<float>();
                    List<float> positionsY = new List<float>();

                    foreach (Player P in playerList)
                    {
                        positionsX.Add(P.Position.X);
                        positionsY.Add(P.Position.Y);
                    }

                    float posXAverage = 0;
                    float posYAverage = 0;

                    foreach (float F in positionsX)
                    {
                        posXAverage += F;
                    }
                    posXAverage /= playerList.Count();

                    foreach (float F in positionsY)
                    {
                        posYAverage += F;
                    }
                    posYAverage /= playerList.Count();

                    camera.Pos = new Vector2(posXAverage, posYAverage);

                    //DOWN HERE
                    //DOWN HERE
                    //DOWN HERE
                    //HERE is where the problems start
                    //This section here sorts the zooming aspect:

                    List<Vector2> relativeList = new List<Vector2>();

                    foreach (Player P in playerList)
                    {
                        Vector2 tempVector = P.position - camera.Pos;
                        relativeList.Add(tempVector);
                    }

                    float maxX = 0, maxY = 0;

                    foreach (Vector2 v in relativeList)
                    {
                        if (v.X > Math.Abs(maxX))
                        {
                            maxX = Math.Abs(v.X);
                        }

                        if (v.Y > Math.Abs(maxY))
                        {
                            maxY = Math.Abs(v.Y);
                        }
                    }

                    float xRatio, yRatio;

                    xRatio = maxX / (Game1.screenWidth / 2);
                    yRatio = maxY / (Game1.screenHeight / 2);

                    camera.Zoom = xRatio;

                    if (maxY > maxX)
                    {
                        camera.Zoom = yRatio;
                    }

                    break;
            }

Is there possibly something just out of place here? Look forward to hearing back from you!

Edited by zuhane

Share this post


Link to post
Share on other sites

First, avoid putting long statements in switches as it quickly gets too messy. Break the subroutine out into a new function and just call it from the switch. It will make life easier for you.
 
Abs the vector components instead of the max value. If the zoom is inverted then it means the fractions for the ratios are inverted, so just flip them over (invert the comparison as well).
 
There's a cleaner way of doing this though, since you're already iterating the characters to find the camera position. Instead of finding the position and then the zoom, just find the bounding box which contains everything you want and then derive what you need from that:

Rectangle rect = new Rectangle(playerList[0].Position.X, playerList[0].Position.Y, 0, 0);

foreach (Player P in playerList)
{
    int x = (int)P.position.X;
    int y = (int)P.position.Y;
    if (x < rect.Left  ) { rect.X      = x; }
    if (x > rect.Right ) { rect.Width  = x - rect.X; }
    if (y < rect.Top   ) { rect.Y      = y; }
    if (y > rect.Bottom) { rect.Height = y - rect.Y; }
}

//You may want to increase the rect size at this point by subtracting 
//some from the x and y and adding to the width and height. Alternatively
//you could just find some factor very close to 1.0f to multiply the 'zoom'
//by before applying it.

Vector2 cameraPos = new Vector2((float)rect.X, (float)rect.Y);
cameraPos.X += (float)rect.Width  / 2;
cameraPos.Y += (float)rect.Height / 2;


//this part may be inverted??? if so flip the divisions and use max instead of min
float xZoomReq = (float)Game1.screenWidth  / rect.Width;
float yZoomReq = (float)Game1.screenHeight / rect.Height;
float zoom = Math.Min(xZoomReq, yZoomReq);

//At this point you can compare the result against min/max zoom values.
//These are numbers you should determine yourself through experimentation,
//as would be the buffer size mentioned above.

For reasons unknown to any sane person, there's no float rectangle struct, so the math is a bit rough and I may have missed some casting. You don't need super-high precision here though, since you're probably going to monkey with the final result a little anyway.

Share this post


Link to post
Share on other sites

Thanks for the swift reply!

 

I'm trying to just get the X component working first, then I'll throw Y into the equation as it'll

be incredibly simple from there. The zoom functionality still doesn't seem to be working though. I tried

a copy-paste of your code, and that didn't work, and also tried tweaking it in all different ways, as

well as modifying my own to accommodate for changes.

 

It seems to work as long as player 1 (playerList[0], used above) is further to the left than all the

other players (lower X value). I tested a map with 2 players, with player 1 on the far left

and player 2 on the far right, and the zoom worked perfectly. As the players

get closer, the zoom increases, then is capped at max zoom level. However, as player 1 begins to

run past player 2, or player 2 past player 1, the zoom just stays at maximum and no longer fits both

players within the screen.

 

Also, with more than 2 players the complexity seems to become insane and throws all kinds of weird

bugs. I'm guessing it's something to do with an absolute value?

 

Current attempt:

int margin = 200;
                    Rectangle rect = new Rectangle((int)playerList[0].Position.X - margin, (int)playerList[0].Position.Y - margin, margin, margin);

                    foreach (Player P in playerList)
                    {
                        int x = (int)P.position.X;
                        int y = (int)P.position.Y;
                        if (x < rect.Left) { rect.X = x; }
                        if (x > rect.Right) { rect.Width = x - rect.X; }
                        if (y < rect.Top) { rect.Y = y; }
                        if (y > rect.Bottom) { rect.Height = y - rect.Y; }
                    }

                    float xZoomReq = (float)Game1.screenWidth / rect.Width;
                    //float yZoomReq = (float)Game1.screenHeight / rect.Height;
                    //camera.Zoom = Math.Min(xZoomReq, yZoomReq);

                    camera.Zoom = xZoomReq;

Also, I'd just like to ask, why is the original rectangle based on player 1 (playerList[0])? It seems like the camera is mostly influenced

by his position rather than every player's position with equal importance.

Edited by zuhane

Share this post


Link to post
Share on other sites

The algorithm only expands the rect. It can't shrink it. I don't know what your coordinate system is based on, but if 0,0 is the upper-left world coord then starting the rect there would make the rect stick to that corner, since it can't shrink to fit the active play area. By setting the initial x/y to the coordinates of a character (any of them) it ensures that the initial coords are within the bounds of the final rect, so it can expand to fit everyone. It's only an initial value. It doesn't give player 1 any more influence than the other players. The loop expands the rect to fit all the players precisely. It doesn't matter what the starting coordinate is as long as it's inside the area that will be covered by the final rect. Assuming that the players can be anywhere in the play area, that means that the only points we know for sure will be inside the final rect are the player coordinates, and the only player that I know will always be present is player 1.

 

Adding the margin to the initial rect is incorrect. Add it after the bounds are determined by the loop. Again, the starting values are intended to be overwritten by the loop.

 

The reason it fails when player 1 passes player 2 is that I'm a moron and forgot to expand the width and height when moving the left and top.

if (x < rect.Left)
{
    rect.Width += rect.X - x; //keep the right side in place while moving the left side
    rect.X = x;
}

And similarly for Y.

 

Are you using the cameraPos derived from this? It's not in what you posted. Your original algo used an average of all the player positions. That's not going to work well. If you have three players on the left and one player at the far right then it's going to pull the centerpoint heavily leftward and the lone player will likely be offscreen.

Share this post


Link to post
Share on other sites


is that I'm a moron and forgot to expand the width and height when moving the left and top.

 

If anyone's the moron, it's me haha! This shouldn't be a day-long problem, but it has been for me. I'm definitely more acquainted to the

art/animation side of game development and less inclined towards the grueling maths/thinking part. It's almost 3:00am over here, so I'll have to

retire for the night and I'll post up what I've done tomorrow.

Share this post


Link to post
Share on other sites

Okay, I'm back on it again! Going back to what you said, I think you're right about using the player averages. I've finally got the

camera to a point where to can track 1-2 players perfectly, or 4 players if the players are in pairs. But what you said is true; If most

of the players move to one side, and a player moves to the other, the influence causes the camera to move way to busiest part,

which causes a player to be cut out of the view. 

 

However, your code seems to make it behave quite strange when it comes to positioning the camera. I'm not too sure how to

fix this problem, to be honest. The zoom works fine, but the positioning code of yours caused all sorts of things to pay up! If it's any help,

the camera essentially has lots of getters and setters available, and the camera.Pos refers to the top-left corner of the rectangle.

It's possible to define the center, too, if that helps make it easier.

 

Anyway, I've got a couple of videos here that kind of show what's going on. Like I say, the margins and zooming work fine with 1-2 players

only!

 

 

 

If you could recommend a better method for positioning the camera correctly, please let me know!

Share this post


Link to post
Share on other sites

If the position refers to the top left rather than the center then just set it to the x,y of the rect after adding your margin. However, if you need to take the zoom into account then it gets a bit more complicated. In that case you'll need to find the centerpoint and the halfwidth (as a 2D vector), multiply the halfwidth by the zoom value (or possibly its inverse: 1/zoom), then subtract it from the centerpoint.

Share this post


Link to post
Share on other sites

I'll be completely honest and say that I'm stuck and don't really have a clue what to do, or what the reasoning behind the

camera logic is. I just don't really understand it. I've been playing with the same few lines of code for the past few days, but

I just can't get it to work :(

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement