
About Scrapper
Scrapper is a topdown twin stick shooter, which unfortunately suffered a lot of scrapped ideas. Luckily the core gameplay stayed, shoot a lot of stuff and try not to die!
Scrapper is a topdown twin stick shooter, which unfortunately suffered a lot of scrapped ideas. Luckily the core gameplay stayed, shoot a lot of stuff and try not to die!
I have spent quite some time making this movement satisfying, I wanted the movement to be smoothed out a little bit but what kept happening is that it felt like you were sliding on ice which is obviously not ideal, that is why I chose to only have it smoothed in the first part of the movement, which turned out to be exactly how I wanted it. It also helped that I used a character controller instead of a normal rigid body because, in my opinion, it feels a lot better.
// get keyboard inputs
float x = Input.GetAxisRaw("Horizontal");
float z = Input.GetAxisRaw("Vertical");
// get orienter gameobject refrence
GameObject camera = _CameraRig.transform.GetChild(0).gameObject;
GameObject orienter = camera.transform.GetChild(0).gameObject;
// set "move" (vector3) var to be relative to orienter
orienter.transform.localRotation = Quaternion.Euler(-camera.transform.eulerAngles.x, 0, 0);
_move = orienter.transform.right * x + orienter.transform.forward * z;
// only smooth movement in the first part of the linear keyboard input
if (_move.magnitude > 0.3f)
{
_move.Normalize();
currentZ = _Wheel.transform.eulerAngles.z;
}
// set velocity
currentMoveVelocity = Vector3.SmoothDamp(currentMoveVelocity, _move * _Speed, ref moveDampVelocity, _MoveSmoothSpeed);
// apply gravity
_Controller.Move(Vector3.down * 2 * Time.deltaTime);
//only move if grounded
if (_Controller.isGrounded)
{
_Controller.Move(currentMoveVelocity * Time.deltaTime);
};
This is quite a simple camera controller, it simply follows the player around with a little bit of smoothing and is able to rotate 90 degrees at the click of a key. the "dummycam" is only used for screen shake effects, because the camera is smoothed, when I did a screenshake it would return to the wrong position, so the dummycam is always located at where the camera should return to.
private void Update()
{
// check distance to player
float distance = Vector3.Distance(transform.position, _PlayerTransform.position);
// set camera move speed
_MoveSpeed *= distance / _SmoothTime;
// only move when the distance to the player is too large
if (distance > _MaxDistanceBeforeMoving)
{
_isMoving = true;
}
if (_isMoving)
{
// set target position
Vector3 targetPos = _PlayerTransform.position + new Vector3(0, _Offset.y, 0);
// smoothly go to target position
transform.position = Vector3.SmoothDamp(transform.position, targetPos, ref _velocity, _SmoothTime, _MoveSpeed);
_DummyCam.transform.position = targetPos;
// know when to stop moving
if (_isMoving && distance < _MaxDistanceBeforeMoving + 0.1f)
{
_isMoving = false;
}
}
// move the camera when one of the buttons is clicked
if ((Input.GetKeyDown(_CamMoveKeys[0]) || Input.GetKeyDown(_CamMoveKeys[1])) && !_camMoveing)
{
// set direction for movement and start coroutine
int direction = (Input.GetKeyDown(_CamMoveKeys[0]) ? 1 : (Input.GetKeyDown(_CamMoveKeys[1]) ? -1 : 0));
StartCoroutine(MoveCam(direction));
}
// reset position
if (Input.GetKeyDown(_CamResetKey))
{
StartCoroutine(ReturnToOriginalPos());
}
}
private IEnumerator Shoot(Quaternion rotation)
{
_shooting = true;
//shake cam
_gameManager.CameraShake(0.06f);
//normal weaponns
if (!_WeaponType.IsSpecialWeapon)
{
Quaternion rot = _GunHolder.transform.rotation;
//single shot
if (_WeaponType.BulletAmount == 1 && !_WeaponType.BurstFireWeapon)
{
GameObject flash = Instantiate(_MuzzleFlash, _GunHolder.transform.position, rot * Quaternion.Euler(0, -90, 0));
Destroy(flash, 0.1f);
if (_WeaponType.AmmoType == WeaponShootBehaviours.BulletType.pistol)
{
FindObjectOfType<Audio>().PlayPistolShot();
}
else
{
FindObjectOfType<Audio>().PlayARShot();
}
GameObject bullet = Instantiate(_BulletPrefab, _GunHolder.transform.position, rotation);
_BulletAmount--;
}
//shotgun shot
else if (_WeaponType.BulletAmount > 1)
{
Tuple<Vector3[], Quaternion[]> result = MakeBulletSpread(_WeaponType.BulletAmount, _WeaponType.BulletSpreadAmount, _GunHolder.transform.position, rotation);
Vector3[] spreadPositions = result.Item1;
Quaternion[] spreadRotations are result.Item2;
for (int i = 0; i < _WeaponType.BulletAmount; i++)
{
GameObject bullet = Instantiate(_BulletPrefab, spreadPositions[i], spreadRotations[i]);
}
FindObjectOfType<Audio>().PlayShotgunShot();
yield return new WaitForSeconds(0.05f);
GameObject flash = Instantiate(_MuzzleFlash, _GunHolder.transform.position, rot * Quaternion.Euler(0, 0, 0));
Destroy(flash, 0.1f);
_BulletAmount--;
}
//burst shot
else if (_WeaponType.BurstFireWeapon)
{
for (int i = 0; i < _WeaponType.BurstFireShotAmount; i++)
{
GameObject bullet = Instantiate(_BulletPrefab, _GunHolder.transform.position, rotation);
yield return new WaitForSeconds(_WeaponType.BurstTimeBetweenShot);
_BulletAmount--;
}
}
}
}