in my code I spawn a sprite every 1.5 seconds but when I touch the sprite works only on the last spawned sprite, how can I make it work with all the sprites?
My code: (not all)
void HelloWorld::spawnRedThing(float dt) {
//actions for spawning the sprite
}
bool HelloWorld::onTouchBegan(cocos2d::Touch *touch, cocos2d::Event *event)
{
//actions on touching
}
bool HelloWorld::init()
{
//create touch listener
auto listener = EventListenerTouchOneByOne::create();
listener->setSwallowTouches(true);
listener->onTouchBegan = CC_CALLBACK_2(HelloWorld::onTouchBegan, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);
//create timer for spawning sprites
this->schedule(schedule_selector(HelloWorld::spawnRedThing), 1.5);
}
yes,it works,spriteList is at outSide like this:
local spriteList = {}
local function spawnRedThing(dt)
local sprite = cc.Sprite:create("land.png")
table.insert(spriteList,sprite)
end
local function touchBegan(touch,event)
for index,obj in pairs(spriteList) do
if cc.rectContainsPoint(obj:getBoundingBox(),touch:getLocation()) then
--sprite touched
end
end
return true
end
in function onTouchBegan() you need check every sprite that you spawn,so you need to set all sprite into a list ,and check if it's be touched
my code is lua:
local spriteList = {}
for index,obj in pairs(spriteList) then
if cc.rectContainsPoint(obj:getBoundingBox(),touch.getLocation()) then
--touched
end
end
Related
I'm trying to save/load my game. In the load method, everytime I change the properties of a GameObject, those changes are applied and then get reverted shortly after. Here is my code:
public void Load()
{
SceneManager.LoadScene(sceneID);
List<GameObject> rootObjects = new List<GameObject>();
Scene scene = SceneManager.GetActiveScene();
scene.GetRootGameObjects(rootObjects);
int ncube = 0, npick = 0;
for (int i = 0; i < rootObjects.Count; ++i)
{
GameObject obj = rootObjects[i];
if (obj.CompareTag("Player"))
{
obj.transform.position = player.position;
obj.transform.rotation = player.rotation;
obj.transform.localScale = player.localScale;
}
else if (obj.CompareTag("Cube"))
{
obj.transform.position = cube[ncube].position;
obj.transform.rotation = cube[ncube].rotation;
obj.transform.localScale = cube[ncube].localScale;
++ncube;
}
else if (obj.CompareTag("Pickup"))
obj.SetActive(pickup[npick++]);
else if (obj.CompareTag("Door"))
obj.SetActive(door);
else if (obj.CompareTag("GreenWall"))
obj.SetActive(greenWall);
}
}
Those changes are applied to the GameObject, however they get aborted right away. How can I resolve this?
The script contains these lines of code is not a component of the GameObject.
Edit 1: Complete code updated.
Problem is I think that
Scene scene = SceneManager.GetActiveScene();
scene.GetRootGameObjects(rootObjects);
gets the objects from the scene before the Scene is fully loaded so they are reset.
From the Docu
When using SceneManager.LoadScene, the loading does not happen immediately, it completes in the next frame. This semi-asynchronous behavior can cause frame stuttering and can be confusing because load does not complete immediately.
I guess you rather should use SceneManager.sceneLoaded and do your stuff there like
public void Load()
{
SceneManager.LoadScene(sceneID);
}
And maybe in an extra component within the scene:
void OnEnable()
{
SceneManager.sceneLoaded += OnSceneLoaded;
}
void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
// your stuff here
}
void OnDisable()
{
SceneManager.sceneLoaded -= OnSceneLoaded;
}
though we don't know/see where player, cube[ncube] etc come from ...
for transparting values between Scenes you should get into using ScriptableObjects
The problem might be that SceneManager.LoadScene completes in the next frame. See the documentation: https://docs.unity3d.com/ScriptReference/SceneManagement.SceneManager.LoadScene.html
It says:
When using SceneManager.LoadScene, the loading does not happen
immediately, it completes in the next frame. This semi-asynchronous
behavior can cause frame stuttering and can be confusing because load
does not complete immediately.
You change the values within the same frame, thus they are overwritten when loading the scene finishes. Cou could use an event to prevent that behaviour: https://docs.unity3d.com/ScriptReference/SceneManagement.SceneManager-sceneLoaded.html
I make 7 cubes and I want to auto drop when the game starts. So I use Gravity to make objects fall. When the game start all cubes are dropped automatically but I want to make it happen again and again. I do not have any idea how to make it. So if you know, please tell me how to make it.
You can do it easily by attaching a script to falling objects to re-position them after going out of focus of the camera or reaching a specific location on the 3D space.
Some simple scripts like this would do,
//Change this to suit your needs
void Update()
{
if (renderer.IsVisibleFrom(Camera.main))
{
Debug.Log("Still Visible");
}
else
{
Debug.Log("Not visible");
transform.position = new Vector3(x, y, z);
}
}
This will not dynamically spawn object nor destroy it would rather reuse existing.
Make your cube into a prefab. Then create a GameObject somewhere in your scene and attach a script to it that spawns the cubes every x seconds.
public Transform MyPrefab;
private float timer = 0f;
void Update() {
timer += Time.deltaTime;
// Spawn a new block every second
if (timer > 1f) {
Instantiate(MyPrefab);
timer -= 1f;
}
}
In the inspector, drag your prefab to the MyPrefab property of your spawning object so it knows what to instantiate.
You should probably attach a script to your prefab cubes that calls Destroy() on them once they fall completely off screen.
I'm developing a simple game in Unity2D, in which several monsters eat things that are dragged to them. If the right object is dragged to the monster, the score goes up by one and the monster should make a happy face, otherwise, score goes down and makes a sad face. This is the code I'm using for that (minus the transitions to happy/sad):
if (transform.name.Equals ("yellow")){
if (collinfo.name.Equals ("plastic(Clone)")) {
Debug.Log ("+1");
audio.Play ();
GameSetup.playerScore += 1;
gs.GetComponent<GameSetup>().removeit(aux);
}
else {
Debug.Log ("-1");
audio.Play ();
if (GameSetup.playerScore == 0)
{}
else
{
GameSetup.playerScore -= 1;
}
gs.GetComponent<GameSetup>().removeit(aux);
}
The audio played is just a 'munching' sound.
I want the monster to change sprites to happyFace (via GameObject.GetComponent ().sprite = happyFace), wait one second and then switch back to it's normal sprite, but don't know how to implement that waiting period.
Any and all help would be much appreciated.
This can be implemented several ways, however, I would use a method that returns an IEnumerator like so…
This assumes you have a variable in your script that has a reference to the SpriteRenderer that is attached to the GameObject with this script.
SpriteRenderer sr = GetComponent <SpriteRenderer> ();
I also assume you have an original sprite and the possible sprites to change to as variables too.
public Sprite originalSprite;
public Sprite happyFaceSprite;
public Sprite sadFaceSprite;
public IEnumerator ChangeFace (Sprite changeToSprite)
{
sr.sprite = changeToSprite;
yield return new WaitForSeconds (1.0f);
sr.sprite = originalFaceSprite;
}
You would then call this function with the applicable sprite as the variable.
if (happy)
StartCoroutine (ChangeFace (happyFaceSprite);
else
StartCoroutine (ChangeFace (sadFaceSprite);
Because the ChangeFace method returns an IEnumerator, we must call that function with the StartCoroutine function. The method will run until it reaches the yield return new WaitForSeconds (1.0f) function, then wait for 1.0f seconds and then resume where it stopped last time.
Understand?
Note
I haven't tested this but I don't see why it wouldn't work.
Put a floating point variable in your monster controller, call it happyTimer or something. It should start at zero.
Then in your Update function you should check happyTimer is above zero. If it is, then subtract Time.deltaTime and check again. If happyTimer is zero or below for the second check, then call your function that resets the sprite.
When you set the sprite to "happy face", also set happyTimer = 1. This will begin the countdown starting with the next Update call.
The relevant part of Update would look like this:
if(happyTimer > 0) {
happyTimer -= Time.deltaTime;
if(happyTimer <= 0) {
resetSprite();
}
}
So I've got this script here that moves the player by -1.25 when you click it but I want it to be continuously adding -1.25 until you release the button. Right now it only moves once when you click the button. My code:
var character : GameObject;
function OnMouseDown () {
character.GetComponent(Animator).enabled = true;
BlahBlah ();
}
function OnMouseUp () {
character.GetComponent(Animator).enabled = false;
}
function BlahBlah () {
character.transform.position.x = character.transform.position.x + -1.25;
}
Does anyone have any ideas? Thanks!
You're simply forgetting to work in the Update()
var character : GameObject;
function OnMouseDown ()
{
character.GetComponent(Animator).enabled = true;
}
function OnMouseUp ()
{
character.GetComponent(Animator).enabled = false;
}
function BlahBlah ()
{
// I added time.deltaTime, since you'll be updating the value every "frame",
// and deltaTime refers to how much time passed from the last frame
// this makes your movement indipendent from the frame rate
character.transform.position.x = character.transform.position.x - (1.25* time.deltaTime);
}
// The standard Unity3D Update method runs every frame
void Update()
{
if (character.GetComponent(Animator).enabled)
{
BlahBlah ();
}
}
What I did here is using Unity logic. Almost everything works in the Update() function, which gets called every frame. Note that frame rate can vary based on machine / complexity of scene, so make sure to use always Time.deltaTime when adding something related.
Another note for you: modifying the position directly won't make your object react to collisions ( so you'll be moving through objects, but you will still "trigger" the collision ). So, if you want to manage collision, remember to use physics!
you can use Input.GetMouseButton because it registers every frame so when you hold down the mouse it gets it but because it checks every frame while the mouse is down so your object will move so fast so you may want to add a timer that if the time is reached it moves so it moves a bit slower so we check if a specified amount of time that we set in timeLeft is passed and the mouse is held down then we move our object
float timeLeft=0.5f;
void Update(){
timeLeft -= Time.deltaTime;
if (Input.GetMouseButton(0)){
if(timeLeft < 0)
{
BlahBlah ();
}
}
}
void BlahBlah () {
timeLeft=0.5f;
character.transform.position.x = character.transform.position.x + -1.25;
}
As I remember onMouseDown fires every frame if you're holding the button, so you'll need to do the movement within that function, let me check one sec.
I have a problem that iv been trying to figure out for a couple of says and i cant seem to pin point the cause of it! I have created a first person shooter that consists of a few enemies on a small map. I have two scenes (the main menu and the game level). When my player dies it is takes to the main menu from which you can choose to play the game again. This then reloads the level again. The first time the game is run it runs without any problems. However when i doe and press the play game button again it returns to me a message which states the following "MissingReferenceException: The object of type 'GameObject' has been destroyed but you are still trying to access it." from the code below I can only see two types which are of GameObject. I have tried to remove the muzzleFlash to see if that is the issue however it makes no difference. I have unticked all the static boxes as i read that this may be the cause of the problem but this did not resolve the problem. this script below is attached to an enemy, I have a PlayerShot script attached to the FPS. Please could someone help?
// speed of the AI player
public var speed:int = 5;
// speed the ai player rotates by
public var rotationSpeed:int = 3;
// the waypoints
public var waypoints:Transform[];
// current waypoint id
private var waypointId:int = 0;
// the player
public var player:GameObject;
// firing toggle
private var firing:boolean = false;
// the Mesh Renderer of the Muzzle Flash GameObject
private var muzzleFlashAgent:GameObject;
/**
Start
*/
function Start()
{
// retrieve the player
player = GameObject.Find("First Person Controller");
// retrieve the muzzle flash
muzzleFlashAgent = GameObject.Find("muzzleFlashAgent");
// disable the muzzle flash renderer
muzzleFlashAgent.active = false;
}
/**
Patrol around the waypoints
*/
function Patrol()
{
// if no waypoints have been assigned
if (waypoints.Length == 0)
{
print("You need to assign some waypoints within the Inspector");
return;
}
// if distance to waypoint is less than 2 metres then start heading toward next waypoint
if (Vector3.Distance(waypoints[waypointId].position, transform.position) < 2)
{
// increase waypoint id
waypointId++;
// make sure new waypointId isn't greater than number of waypoints
// if it is then set waypointId to 0 to head towards first waypoint again
if (waypointId >= waypoints.Length) waypointId = 0;
}
// move towards the current waypointId's position
MoveTowards(waypoints[waypointId].position);
}
/**
Move towards the targetPosition
*/
function MoveTowards(targetPosition:Vector3)
{
// calculate the direction
var direction:Vector3 = targetPosition - transform.position;
// rotate over time to face the target rotation - Quaternion.LookRotation(direction)
transform.rotation = Quaternion.Slerp (transform.rotation, Quaternion.LookRotation(direction), rotationSpeed * Time.deltaTime);
// set the x and z axis of rotation to 0 so the soldier stands upright (otherwise equals REALLY bad leaning)
transform.eulerAngles = Vector3(0, transform.eulerAngles.y, 0);
// use the CharacterController Component's SimpleMove(...) function
// multiply the soldiers forward vector by the speed to move the AI
GetComponent (CharacterController).SimpleMove(transform.forward * speed);
// play the walking animation
animation.Play("walk");
}
/**
Update
*/
function Update()
{
// calculate the distance to the player
var distanceToPlayer:int = Vector3.Distance(transform.position, player.transform.position);
// calculate vector direction to the player
var directionToPlayer:Vector3 = transform.position - player.transform.position;
// calculate the angle between AI forward vector and direction toward player
// we use Mathf.Abs to store the absolute value (i.e. always positive)
var angle:int = Mathf.Abs(Vector3.Angle(transform.forward, directionToPlayer));
// if player is within 30m and angle is greater than 130 (IN FRONT) then begin chasing the player
if (distanceToPlayer < 30 && angle > 130)
{
// move towards the players position
MoveTowards(player.transform.position);
// if not firing then start firing!
if (!firing) Fire();
}
// if player is within 5m and BEHIND then begin chasing
else if (distanceToPlayer < 5 && angle < 130)
{
// move towards the players position
MoveTowards(player.transform.position);
// if not firing then start firing!
if (!firing) Fire();
}
else
{
// patrol
Patrol();
// stop firing
firing = false;
}
}
/**
Fire at the player
*/
function Fire()
{
// toggle firing on
firing = true;
// check if still firing
while (firing)
{
// hit variable for RayCasting
var hit:RaycastHit;
// range of weapon
var range:int = 30;
// fire the ray from our position of our muzzle flash, forwards "range" metres and store whatever is detected in the variable "hit"
if (Physics.Raycast(muzzleFlashAgent.transform.position, transform.forward, hit, range))
{
// draw a line in the scene so we can see what's going on
Debug.DrawLine (muzzleFlashAgent.transform.position, hit.point);
// if we hit the player
if (hit.transform.name == "First Person Controller")
{
// inform the player that they have been shot
player.GetComponent(PlayerShot).Shot();
// play gunshot sound
audio.PlayOneShot(audio.clip);
// show muzzle flash for X seconds
muzzleFlashAgent.active = true;
yield WaitForSeconds(0.05);
muzzleFlashAgent.active = false;
// wait a second or two before firing again
yield WaitForSeconds(Random.Range(1.0, 2.0));
}
}
// wait till next frame to test again
yield;
}
}
this is the PlayerShot which destroys the gameobject.
// the sound to play when the player is shot
public var shotSound:AudioClip;
// the number of lives
public var lives:int = 3;
/**
Player has been shot
*/
function Shot ()
{
// play the shot audio clip
audio.PlayOneShot(shotSound);
// reduce lives
lives--;
// reload the level if no lives left
if (lives == 0)
{
// destroy the crosshair
Destroy(GetComponent(CrossHair));
// add the camera fade (black by default)
iTween.CameraFadeAdd();
// fade the transparency to 1 over 1 second and reload scene once complete
iTween.CameraFadeTo(iTween.Hash("amount", 1, "time", 1, "oncomplete", "ReloadScene", "oncompletetarget", gameObject));
}
}
/**
Reload the scene
*/
function ReloadScene()
{
// reload scene
Application.LoadLevel("MainMenu");
}
The script attached to the enemy along with the BasicAI is the SoldierShot Script which destroys the gameobject. below is the script.
public var ragdoll:GameObject;
/**
Function called to kill the soldier
*/
function Shot()
{
// instantiate the ragdoll at this transform's position and rotation
Instantiate(ragdoll, transform.position, transform.rotation);
Destroy(GetComponent(BasicAI));
// destroy the animated soldier gameobject
Destroy(gameObject);
}
It seems that you keep a reference to the destroyed GameObject (or am I wrong?).
As opposed to what happens in common C# (and probably javascript) programs that when you have a reference to an object, it will never be garbage collected, in Unity if you destroy the object all your references to it will go to null.
Easy fix, you could delete the gameObject in the "Game Level" and instantiate your soldier on the fly with:
var instance : GameObject = Instantiate(Resources.Load("Soldier"));
You just need to make a Resources folder in your project folder and put the prefab for your solder into it.