I'm making a 2D Shooter game in XNA. I had been working on the shooting speed of the player (Every how often can the player shoot another bullet) and made it so that the player can only shoot again once the previous bullet has traveled a certain distance like so:
if (this.bulletList[0].BULLETS[(this.bulletList[0].BULLETS.Count) - 1].X >= Pos.X + attackSpeed)
canShoot = true;
Where bulletList is the available Projectiles the player can shoot, BULLETS is the List of Bullets already shot, and attackSpeed is the rate in which the bullets should be shot, or simply put: the distance the bullet has to travel until another bullet can be shot.
Now I've been working on Collisions. My method was to dispose of a bullet after it hits a target like so:
for (int i = 0; i < player.BULLETLIST[0].BULLETS.Count; i++)
{
if (CollisionManager.PlayerBulletOnBot(player.BULLETLIST[0].BULLETS[i], bot))
player.BULLETLIST[0].BULLETS.RemoveAt(i);
}
Problem is, if the bullet has been removed upon hitting a target, I can no longer ask if that bullet has passed the given distance for another bullet to be shot.
To solve that, I'd like the bullet to turn invisible upon hit, and afterwards it'll be disposed of in another function that's already been made.
Simply have a Visible flag for a Bullet instance:
class Bullet {
public bool Visible { get; set; }
}
When it hits.. make it invisible:
// ... hit
bulletInstace.Visible = false;
Then check before drawing it:
if (bulletInstance.Visible)
drawBullet(bullet);
If it isn't visible, your drawing code should just skip over it.
When you draw an object using spriteBatch.Draw(...) you have to select a color for the sprite itself.
We all know that the color is a mixture of "red, green and blue" values (or rgb). What not many people know is that, at least in XNA, there is a fourth value called alpha.
The alpha value indicates the transparency of your object, meaning that if you use it like the code below, your object will be half invisible (or half visible).
spriteBatch.Draw(..., Color.White * 0,5f,...);
You can play with that :)
Check a little more here, on the old XNA forums.
You need rate of fire (rof) property that you increase to some maxRof value when you hold down button. and when rof is equal to maxrof then you add bullet to a list of bullets (and reset rof to 0).
Do not make it invisible, remove it from list. Every instance of bullet should have "Active" property set to true on fire. (when you fire a bullet, add it to list) And when collsition happened set this property to false. pseudo code as example:
UPDATE
for each bullet in bullets
-- update bullet position
-- check collision if happened if yes then set Active to false
end for
bullets.removeall(function(c) NOT(c.active));
DRAW
for each bullet in bullets.findall(function(c) c.active)
-- draw your bullets
end for
Related
I recently started having a look at game development with Unity and was trying to make a simple 2D character with basic movement abilities. This character is supposed to jump and move from side to side, but only if it is standing on something.
Now my question is: How do you check if a player is standing on something? / Get the distance to the next game object / collider beneath the player game object?
Would greatly apreciate any helpful answers and especially explanations on how exactly it works. Thanks!
To do this, you need to send a ray to detect the point of impact on the ground and then calculate the distance. The code below sends a ray from the center of your object down to the maximum height (3) and gives the size.
public LayerMask groundLayer;
public float maxRayLength = 3;
public void Update()
{
var hit = Physics2D.Raycast(transform.position, Vector3.down, maxRayLength, groundLayer.value);
if (hit) Debug.Log(hit.distance); // it will print current distance from pivot
}
If you want to calculate the height of the ray from the character's foot, there are two methods, one is subtracting half the height of the character from it.
Physics2D.Raycast(transform.position-transform.up*height, ....)
Next one is to use an empty object at the base of the character, which we refer to instead of the center.
public Transform pivot;
Then..
Physics2D.Raycast(pivot, ....)
There are a few ways of actually doing this.
The most usual although a bit complicated way of doing it for a beginner is using Raycasts. A Raycast is basically a small invisible line that starts and ends where you tell it to. If anything of a specific tag or layer is caught in it's crossfire you can basically pull that object from your code. Raycasts are used for a lot of things, most notably in Shooter games to shoot or in games like Skyrim to pickup objects and interact with them.
Another way to do this, which is a bit more popular in 2D games is to create a "feet" GameObject and make it the child of the player in the hierarchy. You can add a box collider on that GameObject and check the "IsTrigger". You can add a Tag to your ground objects and through your code using the OnTriggerEnter() and OnTriggerExit() Methods you can basically tell when your character is floating on air and when he is on ground.
Another popular method is to use the Physics.OverlapBox() Method which is pretty much the same as the Trigger Method but you are creating an invisible box (much like a raycast) and instead of only getting notified when Triggered (something enters or exits) you check if the invisible box is colliding with another object/tag/collider (which could be your ground).
There are also a few different things you can do with a Nav Mesh (mostly in 3D) but I think that for now these 3 should suffice!
I've been working on some game project for college work. My problem is that I have list of enemies that is moving left-right and when touching left or right edge goes down a bit, and what i want them to do is to shot bullets from random enemy while game lasts,but I have managed for bullet to show and shot from random enemy but that is it :'D, it just goes that one time and it needs to go while game lasts. So here is my method for shooting to me it looks all right and cant figure out why is just one shot.
I'm beginner so sorry if my code looks stupid.
private int MoveEnemyBullet()
{
int randomnum = r.Next(30);
shooter = enemies[randomnum];
bullet.Goto_Sprite(shooter);
bulletEnemy.Add(bullet);
bullet.SetVisible(true);
bullet.Active = true;
while (START)
{
if(bulletEnemy.Count!=0)
bullet.Y += bullet.speed;
Wait(0.01);
if (bullet.TouchingEdge())
{
bullet.SetVisible(false);
}
}
Game.StartScript(MoveEnemyBullet);
return 0;
}
Your code is hard to read since there is only a little of it. What is bullet, bulletEnemy or START? I would ask why you don't have a list of bullets also, but i think that you want to only have one bullet at a time on the screen.
There might be a problem with TouchingEdge() method. Something similar happened to me, the bullet was not destroyed when it whent out of the bounds of the screen, only when it hit its target, so the bullet was still "alive" but outside the screen, still moving. If this happened to you, the bullet was never set to invisible.
Also, it does not seem to me that you change the value of START, which would mean that your while loop never ends. If you change it to false in the SetVisible(false) method, then this is not the problem.
I believe Goto_Sprite(shooter) changes the position of the bullet to the new shooter, but you should check if that one is correct too.
I created a new empty gameobject in the hierarchy.
Attached to it a Box Collider:
And changed this settings on the Box Collider:
I set it's center property to 0,0,0
And set the size to x = 500 y = 600 z = 500
I also set the IsTrigger to be on( the checkbox is checked ).
And this is the Terrian details:
Width 500 Length 500 Height 600
When i'm looking at the scene window it seems like the box is around the terrain edges as it should be: ( Maybe in the right side there some space between the box and the terrain ? )
Scene Screenshot
This is the script attached to the empty gameobject ( InvisibleWalls ).
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BoxCollider : MonoBehaviour {
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
}
void OnTriggerExit(Collider c)
{
Destroy(c.gameObject);
}
}
This is just for the test.
I added a break point on the line:
Destroy(c.gameObject);
Just to check when the event trigger.
The player ( ThirdPersonController ) is walking at speed 10.
When it's getting to the terrain edge the event is not triggering. The player keep walking on the air for some more seconds and only then the event is trigger and stop on the break point but then the player is already out the terrain area.
Event Triggered
What i want to do is once the player is touching the wall trigger the event and do something for example keep the player walking on place so the wall is blocking him. But now the event is trigger when the player is out of the terrain area.
Well this looks like the result of starting the player inside the collider, and using OnTriggerExit. That method won't be called until all of the player's collider is outside the defined box.
You could make the box smaller, so that there is some "padding" terrain around the outside of it. This is probably the quickest, but I would recommend option 2 instead.
You could make 4 box colliders, one for each wall. Instead of having one gigantic collider and waiting for the player to step out, think of these as skinny walls placed one to each side of your terrain. Don't make them triggers, and use the OnCollisionEnter event instead. This will automatically stop the player if you are moving him via physics, and you get the event as well. You can still make them triggers and use OnTriggerEnter if you want, but why not use the physics system since its there!
I hope this helps, good luck with your project!
Edit: Found a video that explains method 2
1) You Can call OnTriggerEnter if you want the player to be detected before it crosses the Trigger.
2) Another way will be To make the triggers Colliders and they will automatically block the player to cross the terrain boundary
I am a total beginner at Unity3d. I have some background in android programming, but no C# experience whatsoever. The first thing I am trying to do is to create a clone of flappy bird game, called flappy plane, according to this tutorial
http://anwell.me/articles/unity3d-flappy-bird/
The problem is, when I tried to write a script that allows player to move (player.cs) with the code
using UnityEngine;
using System.Collections;
public class player: MonoBehaviour {
public Vector2 jumpForce = new Vector2(0,300);
public Vector2 jumpForce2 = new Vector2(0,-300);
// Use this for initialization
// Update is called once per frame
void Update () {
if (Input.GetKeyUp("space")){
Rigidbody2D.velocity = Vector2.zero;
Rigidbody2D.AddForce(jumpForce);
}
}
}
I get an error "An Object reference is required to access non-static member 'UnityEngine.Rigidbody2D.velocity'". I have googled that and it is suggested to access Rigidbody2d with GetComponent().velocity,
so I changed
Rigidbody2D.velocity = Vector2.zero;
Rigidbody2D.AddForce(jumpForce);
with
GetComponent<Rigidbody2D>().velocity = Vector2.zero;
GetComponent<Rigidbody2D>().AddForce(jumpForce);
The error is gone and I am able to add the script to the object, still I don`t get the desired action - after I hit play the object turns invisible and just falls down, does not react to spacebar button. What am I doing wrong?
Thanks for the answer.
It's possible that you're not adding enough force to have the object move upwards.
There's technically nothing wrong with your code. (Although you do have somethings mixed up in your question). The problem is in the fact that you're not adding ANY force upwards every single frame.
Essentially, at the moment, your player object is in free-fall the instant you hit the play button, and you're adding a minuscule force to the player only on the frames that the space bar is pressed.
To solve this, here's what you should be doing
Add an upward force to counter-act the force of gravity every frame. You can do this in two ways.
a. Set the rigidbody's velocity.y to 0 BEFORE detecting the space bar (this is really a hacky way, but it'll suffice and doesn't need any more code)
b. Add an upward force to the player which will nullify the effect of gravity. Just use F = mg to get the value of force you'd need to add.
You could, alternatively set the isKinematic property to true by default on the Player's rigidbody, set it to false on pressing the space bar, and back to true after a few frames (5 - 6 frames)
make sure your player object and the ground both have BoxCollider2D colliders to keep above ground.
you could keep a reference stored for the rigidBody like Rigidbody2D myRigidbody;
then in start put myRigidbody = GetComponent<Rigidbody2D>(); then you would use like myRigidbody.AddForce(jumpForce); your jumpForce2 though is shooting your player downward you should not need it in a jump as the physics and gravity will apply with the rigidbody.
incase your input is not set up in the project settings try to fire the jump with
Input.GetKeyDown(KeyCode.Space);
In my game I want to make the player object transparent for 2 seconds by scripting at run time if the player collided with a specific object during the game ... is it possible ?
Check for collision. When the collision that you want is triggered then you can change the transparency.
GameObject g;
// 50% Transparency.
g.renderer.material.color.a = 0.5f; // a is the alpha value.
// 100% Transparency.
g.renderer.material.color.a = 1.0f;
You can do just this to make your program wait time: http://docs.unity3d.com/Documentation/Manual/Coroutines.html
You will notice the example is exactly your question.
Try this extension method:
public static void ChangeAlpha(this Material mat, float alphaValue)
{
Color oldColor = mat.color;
Color newColor = new Color(oldColor.r, oldColor.g, oldColor.b, alphaValue);
mat.SetColor("_Color", newColor);
}
You can then call it by:
gameObject.renderer.material.ChangeAlpha( Your Alpha Value );
In Unity 5, the best way (TO MAKE AN OBJECT INVISIBLE) that worked for me was to:
Set all of the game object's materials you want to be invisible to transparent under the rendering mode.
Then, click on the small round button next to albedo and scroll down on the list of items given until you find one called UIMask.
Highlight it and press enter.
* Note that this is a hard fix and I'm not sure if you can change this with code.
** This was made for boundaries in roll-a-ball with a player jump function included. I needed to make the walls invisible but also collision-able to stop the air born player object.
This can be simply done with shaders, which you can quickly and efficiently change at runtime:
Create new material and set the shader to use the
Unlit/Transparent Cutout
Assign your game object to use this new material
Turn off all of the stuff in the mesh render of the game object: set cast shadows to off, receive shadows disabled, contribute to global illumination to disabled, turn off your light probes and reflections, set motion vectors to 'force no motion', turn off dynamic occlusion.
Also don't forget to remove the mesh collider of the game object.