- Home /
What technique/code is needed for contra style aiming?
Hello,
Are there any tutorials on doing 2D aiming in the style of Contra/Metal Slug? I'm not sure if this is an animation problem, or a code problem. Any insight would be awesome.
In those games, the aiming is done via the Directional pad. The character aims, and the bullet is instantiated based on the direction that the character is pointed in.
Here's the effect I want:
1) Player presses up,left,right,right/up, left/up 2) The player character sprite moves in that direction
3) If the player presses the shoot key, the bullet moves in that direction
How do I limit rotation to a 180 degree radius (either left,right,right/up,left/up) -Do I need to break down the character into two parts? (One body part for the aiming, one for the rest of the model that handles animations, collisions, etc)
-If the aiming 'arm' is parented to the main body, how would i make it face in the same direction that the player's body is facing (IE left or right?)
I found a this forum, one of the forum commentaters breaks down the technique, but how do i implement it in code?
Here is an example sprite sheet. The top row is the desired effect?
Here's some code that I came up with, but there are two problems:
1) There is no limit on the rotation, meaning it can spin in a circle, not desired) 2) when the player faces left, the arm still faces right
using UnityEngine;
using System.Collections;
public class Aim : $$anonymous$$onoBehaviour {
public Vector3 up = new Vector3(0,0,1);
public Vector3 down = new Vector3(0,0,-1);
float lockPos = 0f;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
//transform.RotateAround(transform.parent.position, new Vector3(0, 0, 1), rotateSpeed * Time.deltaTime);
transform.rotation = Quaternion.Euler( lockPos, lockPos, transform.rotation.eulerAngles.z);
if(Input.Get$$anonymous$$ey($$anonymous$$eyCode.Z))
//transform.RotateAround(transform.parent.position, up);
transform.Rotate(up);
if(Input.Get$$anonymous$$ey($$anonymous$$eyCode.C))
//transform.RotateAround(transform.parent.position, new Vector3(0, 0,-1));
transform.Rotate(down);
}
}
Try `$$anonymous$$athf.Clamp()` for limiting the rotation.
So i did that. I was able to limit it between 90 and 180. It stops at 180 which is it's maximum. But when I get close to it's $$anonymous$$imum (90) the whole object seems to loop on itself. It does not stop at 90 which was the desired effect. Why does this happen?
Answer by robertbu · Dec 15, 2013 at 04:54 PM
Your question is too fuzzy. It potentially involves multiple issues, and you've not defined how you are going to do things like change the texture of the character or how you are going to move the character.
For setting the texture you can do:
Use a Quad and an array of textures
Use a Quad and a sprite sheet. Manipulate the material offset and scale.
Use a Quad and a texture atlas and manipulate the uv coordinates of the quad.
Use Unity's new Sprite
Use a third-party tool like NGUI or EZGUI
For movement you can:
Direct movement through the use of the transform
Use Rigidbody and 3D physics
Use Rigidbody and 2D physics
Use a character controller
I'm assuming from your sprite sheet, that you don't really want the character to rotate, but instead want to change the texture of the character. Here is a bit of code to get you started. Based on the use of 'Horizontal' and 'Vertical' in the Input manager, it sets the direction. In a new project, 'Horizontal' and 'Vertical' are setup to use the ASDF and arrow keys. Per you question, it limits the direction. to Right, UpRight, Up, UpLeft, and Left. It reports 'None' for other directions or no input. Put it on a game object, hit play, and use the ASDF or Arrow keys:
using UnityEngine;
using System.Collections;
public class Directions: MonoBehaviour {
enum Facing {Right, UpRight, Up, UpLeft, Left, None};
void Update () {
Vector3 direction = new Vector3(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical"),0.0f );
Debug.Log (FindFacing(direction));
}
Facing FindFacing(Vector3 direction) {
if (direction == Vector3.zero)
return Facing.None;
float angle = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg;
Debug.Log ("Angle: "+angle);
if (angle < 0.0f)
angle = 360.0f + angle;
angle += 22.5f;
int i = (int)(angle / 45.0f);
i = i % 8;
if (i > 4)
return Facing.None;
return (Facing)i;
}
}
Thanks! That is kind of what I'm going for. This is a great start. I apologize for the fuzzy logic too. To answer your questions:
1) I plan on using the new Unity object Sprite, using a sprite sheet eventually 2) I was doing movement via the transform/update.
I thought about this question a little more after posting. As in your example, I want the projectile to instantiate based on the direction of the player's transform.
You are correct, I don't necessarily need the Player GameObject to rotate. I just want the sprite to face in the direction of the player's input and the projectile to shoot in that same direction.
Should I I do this with branching If statements?
This is the code I found in the Unity 4.3 2D example
// If the player is facing right...
if(playerCtrl.facingRight)
{
// ... instantiate the rocket facing right and set it's velocity to the right.
Rigidbody2D bulletInstance = Instantiate(rocket, transform.position, Quaternion.Euler(new Vector3(0,0,0))) as Rigidbody2D;
bulletInstance.velocity = new Vector2(speed, 0);
}
else
{
// Otherwise instantiate the rocket facing left and set it's velocity to the left.
Rigidbody2D bulletInstance = Instantiate(rocket, transform.position, Quaternion.Euler(new Vector3(0,0,180f))) as Rigidbody2D;
bulletInstance.velocity = new Vector2(-speed, 0);
//Insert facing up, up right, up left, etc
}
I tend to avoid if/else and switch statements if I can (though it would work). I'd probably declare something like this:
private Vector2[] directions = {Vector2.right, new Vector2(1,1), Vector2.up, new Vector2(-1,12), -Vector2.right};
It is matched to the Facing enumeration above. Then the instantiate would be:
GameObject bulletInstance = Instantiate(rocket, transform.position, Quaternion.Identity)) as GameObject;
bulletInstance.transform.right = directions[currentFacing];
bulletInstance.rigidbody2D.velocity = directions[currentFacing].normalized * speed;
This assumes the 'forward' of the bullet is pointing right when the rotation is (0,0,0). Substitute 'up' as necessary.
Thanks Alot! I'm going to try this out, but this really helped clear up my thinking. I appreciate it.
Sorry for the noobishness but do I need to declare CurrentFacing somewhere? I'm getting a no context errror.
At the top of the class, you will declare 'currentFacing':
private Facing currentFacing = Facing.Right;
Then in Update() you might do something like:
Facing facing = FindFacing(direction);
if (facing != Facing.None)
currentFacing = facing;
This way 'currentFacing' will always be equal to the last valid direction (i.e. never Facing.None). 'currentFacing' can then be used for both setting the texture used by the character and by calculating the direction to fire.