Among the functions provided by LeanTween,
Is there a function that functions like iTeeen's RotateBy?
(RotateBy(GameObject obj,Hashtable hash))
What I want to do is,
After completing the animation, the function is executed through the string.
For example, in a card-matching game,
If you click on the card, the following event will occur.
WordReviewManager.cs:
public void onTuchHandler(object obj, EventArgs e)
{
TouchEventTypes t_evt = e as TouchEventTypes;
Debug.Log("GameObject : " + t_evt.go + " / " + "Card : " + t_evt.card);
Debug.Log("Card Index : " + t_evt.card_idx + " / " + "Card UniqueIndex : " + t_evt.card_snum);
Debug.Log("================================================================================");
WordReviewUtil.testAni(this.gameObject, t_evt.go, t_evt.card, t_evt.delay, t_evt.complete);
}
The function that receives the event is shown below.
WordReviewUtil.cs:
public static Hashtable testAni(GameObject listener, GameObject go, Card card, float delay = 0f, string complete = "testGood")
{
Debug.Log("hello TEST ANIMATION ~~ ");
Hashtable hash = new Hashtable();
GameObject goz = go as GameObject;
Debug.Log("goz >>>> " + goz);
hash.Add("gameObj", goz);
hash.Add("onComplete", complete);
return hash;
}
Here is what I expect to see afterwards.
WordReviewManager.cs:
public void testGood(Hashtable table)
{
Debug.Log("hello Moto ~?!");
}
That is, the testGood function is executed.
iTween has a function that gives me the functionality I want.
Immediately, RotateBy function.
But I am currently using the LeanTween library, not iTween.
Also, the LeanTween library does not provide the functionality I want.
I just need to call the function. Without any parameters.
How do I implement what I want to implement?
The main design change between iTween and LeanTween for the complete callback is that iTween takes the method name as string and internally calls the evil SendMessage method.
LeanTween uses the Action delegate, which can be considered as pointer to a method. You can see in WordReviewManager.Start() how you can just assign the testGood method to the field Action onCompleteCallback of TouchEventTypes and feed that into your system.
public class Card : MonoBehaviour { }
public class TouchEventTypes : EventArgs
{
public Card card;
public float delay;
public Action onCompleteCallback;
}
public class WordReviewManager : MonoBehaviour
{
void Start()
{
TouchEventTypes e = new TouchEventTypes();
e.onCompleteCallback = testGood;
//TODO: feed this into your touch event system.
}
public void testGood()
{
Debug.Log("hello Moto ~?!");
}
public void onTouchHandler(object obj, EventArgs e)
{
TouchEventTypes eventArgs = e as TouchEventTypes;
WordReviewUtil.RotateCard(
card: eventArgs.card,
delay: eventArgs.delay,
callback: eventArgs.onCompleteCallback
);
}
}
public static class WordReviewUtil
{
public static void RotateCard(Card card, float delay, Action callback)
{
LTDescr tween = LeanTween.rotateAround(card.gameObject,
axis: new Vector3(0,0,1),
add: 360f,
time: 2.0f
).setDelay(delay);
tween.setOnComplete(callback);
}
}
Related
I'm sending info from 3 input fields on a mobile app made in Unity (Coded in C#) to Firebase database, but as you can see it seems to send each input field's data individually then stacks it on top of one another.See attached Ideally I'd only want the last set of complete information.
using System.Collections;
using System.Collections.Generic;
using Proyecto26;
using UnityEngine;
using UnityEngine.UI;
public class PlayerScores : MonoBehaviour
{
public InputField dateText;
public InputField classText;
public InputField informationText;
User user = new User();
public static string Information;
public static string Class;
public static string Date;
// Start is called before the first frame update
private void Start()
{
}
public void OnSubmit()
{
Date = dateText.text;
PostToDatabase();
{
Class = classText.text;
PostToDatabase();
}
{
Information = informationText.text;
PostToDatabase();
}
}
public void OnGetScore()
{
RetrieveFromDatabase();
}
private void PostToDatabase()
{
User user = new User();
RestClient.Put("https://anti-bullying-demo.firebaseio.com/" + Date + Class + Information + ".json", user);
}
private void RetrieveFromDatabase()
{
RestClient.Get<User>("https://anti-bullying-demo.firebaseio.com/" + Date + Class + Information + ".json").Then(response =>
{
user = response;
});
}
}
In your OnSubmit() function call, you call PostToDatabase() three times - you only need call it once at the end.
public void OnSubmit()
{
Date = dateText.text;
{
Class = classText.text;
}
{
Information = informationText.text;
}
PostToDatabase();
}
I have a GameScreenManger that will show or hide a panel based on the game status. I have a AdManager gameObject that holds a script that handles ads. I am able to show the ad, but on onAdclosed if i tried to make a reference of GameScreenManager that holds a script in Admanager Script and call a function when onAdclosed event listeners function, the call is triggering, but the actions are not working. Could some one help me in this?
using UnityEngine;
using GoogleMobileAds.Api;
using System;
public class AdManager : MonoBehaviour
{
public static AdManager instance;
private string appId = "";
private InterstitialAd InterstitialAd;
private string InterstitialAdId = "interstitial_Ad_Id";
private RewardedAd RewardedVideoAd;
private string RewardedVideoAdId = "rewarded_video_ad_Id ";
public GameObject RewardPanel;
public GameScreenManager gameManager;
public bool isRewardedVideo;
private bool RewardedVideoLoaded = false;
public void Awake()
{
if(instance == null)
{
instance = this;
} else
{
Destroy(this);
}
MobileAds.Initialize(initStatus => { });
}
private void Start()
{
RequestInterstitial();
RewardedVideoAd = new RewardedAd(RewardedVideoAdId);
RequestRewardedVideo();
// Called when an ad request has successfully loaded.
this.RewardedVideoAd.OnAdLoaded += HandleRewardedAdLoaded;
// Called when an ad request failed to load.
this.RewardedVideoAd.OnAdFailedToLoad += HandleRewardedAdFailedToLoad;
// Called when an ad is shown.
this.RewardedVideoAd.OnAdOpening += HandleRewardedAdOpening;
// Called when an ad request failed to show.
this.RewardedVideoAd.OnAdFailedToShow += HandleRewardedAdFailedToShow;
// Called when the user should be rewarded for interacting with the ad.
this.RewardedVideoAd.OnUserEarnedReward += HandleUserEarnedReward;
// Called when the ad is closed.
this.RewardedVideoAd.OnAdClosed += HandleRewardedAdClosed;
}
private void Update()
{
if (RewardedVideoLoaded == false)
{
RequestRewardedVideo();
}
}
private void RequestInterstitial()
{
string adUnitId = InterstitialAdId;
// Initialize an InterstitialAd.
this.InterstitialAd = new InterstitialAd(adUnitId);
// Create an empty ad request.
AdRequest request = new AdRequest.Builder().Build();
// Load the interstitial with the request.
this.InterstitialAd.LoadAd(request);
}
public void ShowInterstitial()
{
if (this.InterstitialAd.IsLoaded())
{
this.InterstitialAd.Show();
}
}
public void RequestRewardedVideo()
{
// Create an empty ad request.
AdRequest request = new AdRequest.Builder().Build();
// Load the interstitial with the request.
this.RewardedVideoAd.LoadAd(request);
if (this.RewardedVideoAd.IsLoaded())
{
isRewardedVideo = true;
RewardedVideoLoaded = true;
} else
{
isRewardedVideo = false;
RewardedVideoLoaded = false;
}
}
public void ShowRewardedVideo()
{
if (this.RewardedVideoAd.IsLoaded())
{
this.RewardedVideoAd.Show();
}
}
public void HandleRewardedAdLoaded(object sender, EventArgs args)
{
MonoBehaviour.print("HandleRewardedAdLoaded event received");
}
public void HandleRewardedAdFailedToLoad(object sender, AdErrorEventArgs args)
{
MonoBehaviour.print(
"HandleRewardedAdFailedToLoad event received with message: "
+ args.Message);
}
public void HandleRewardedAdOpening(object sender, EventArgs args)
{
MonoBehaviour.print("HandleRewardedAdOpening event received");
}
public void HandleRewardedAdFailedToShow(object sender, AdErrorEventArgs args)
{
MonoBehaviour.print(
"HandleRewardedAdFailedToShow event received with message: "
+ args.Message);
}
public void HandleRewardedAdClosed(object sender, EventArgs args)
{
MonoBehaviour.print("HandleRewardedAdClosed event received");
Debug.Log("{lo} OnClosed called sender = " + sender);
RequestRewardedVideo();
gameManager.CheckForLives(); //This is not working.
this.RewardPanel.SetActive(true);
}
public void HandleUserEarnedReward(object sender, Reward args)
{
Debug.Log("{lo} Earned a Reward HandleUserEarnedReward called!");
string type = args.Type;
double amount = args.Amount;
this.RewardPanel.SetActive(true);
}
}
GameScreen Script
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
public class GameScreenManager : MonoBehaviour
{
public GameObject PauseScreen;
public GameObject OutOfLifeScreen;
public GameObject PauseButton;
public GameObject Scoretext;
public GameObject Livesbutton;
public Text MusicText;
public void LoadPause()
{
PauseScreen.SetActive(true);
bool audioPlaying = FindObjectOfType<AudioManager>().audioPlaying;
MusicText.text = audioPlaying ? "MUSIC ON" : "MUSIC OFF";
Time.timeScale = 0f;
}
public void ShowResume()
{
PauseScreen.SetActive(false);
Time.timeScale = 1f;
}
public void ShowMainMenu()
{
Time.timeScale = 1f;
SceneManager.LoadScene("Menu");
}
public void ShowOutOfLives()
{
OutOfLifeScreen.SetActive(true);
PauseButton.SetActive(false);
Time.timeScale = 0f;
}
public void CloseOutOfLives()
{
Debug.Log(" {lo} Entered CloseOutOfLives");
OutOfLifeScreen.SetActive(false);
PauseButton.SetActive(true);
Time.timeScale = 1f;
}
public void TogggleSound()
{
FindObjectOfType<AudioManager>().ToggleMute();
bool audioPlaying = FindObjectOfType<AudioManager>().audioPlaying;
MusicText.text = audioPlaying ? "MUSIC ON" : "MUSIC OFF";
PlayerPrefs.SetInt("audioNeeded", audioPlaying ? 1 : 0);
}
public void Quit()
{
Application.Quit();
}
}
Because the callbacks are coming from a non-main thread, and unity is a single threaded environment, so some unity APIs are inaccessible from non-main threads, for example you can't use GameObject.SetActive or many more component functions except from the main thread, so what you need to do is dispatch the callback to the main thread first, then all statements in your function will execute.
Here's how.
1) A simple dispatcher that executes methods on unity's main thread.
create an empty game object in your scene, and attach this to it.
using System;
using System.Collections.Generic;
/// <summary>
/// Helps dispatch task results to the main thread to be able to operate on unity's API like SetActive, enabled etc...
/// </summary>
public class MainThreadDispatcher : MonoBehaviour
{
Queue<Action> jobs = new Queue<Action>();
static MainThreadDispatcher Instance = null;
private void Awake()
{
Instance = this;
}
private void Update()
{
while (jobs.Count > 0)
{
var next = jobs.Dequeue();
if(next != null)
{
next.Invoke();
}
}
}
/// <summary>
/// Dispatches a function to be executed on unity's main thread to be able to use unity's API.
/// </summary>
/// <param name="newJob"></param>
public static void Dispatch(Action newJob)
{
if (newJob == null)
return;
Instance.jobs.Enqueue(newJob);
}
}
2) Edit your on ad closed callback to dispatch to the main thread.
public void HandleRewardedAdClosed(object sender, EventArgs args)
{
// simply give unity control back.
// you can pick and choose to execute what on main thread,
// but I'm just gonna dispatch the whole block.
MainThreadDispatcher.Dispatch(() =>
{
MonoBehaviour.print("HandleRewardedAdClosed event received");
Debug.Log("{lo} OnClosed called sender = " + sender);
RequestRewardedVideo();
gameManager.CheckForLives();
this.RewardPanel.SetActive(true);
});
}
It seems like you don't have a reference to your object in the second script:
Ad Script
public GameScreenManager gsmanagerRef; //drag and drop on the editor or find it on initialization
then you should be able to call
gsmanagerRef.ShowResume(); //or any other function
Hope this helps!
I'm writing a game in Unity where one has different game modes but eventually uses the same level, it is only that things behave differently.
The difference is only in how the player has to aim for example, so s/he has to quickly find the same places for the targets (the targets appear by the same order) or they appear randomly.
It is the same stage but with different rules so I thought an interface would be beneficial - the GameManager class implements it based on the game mode. Of course I could write different Game Managers or use a switch in one but I wish to keep things organized for a change.
Question is, how to do it?
This is how you setup a simple state machine:
//state
public enum GameMode { Normal, Endless, Campaign, Idle, Count }
private GameMode gameMode;
//state machine array
private delegate void UpdateDelegate();
private UpdateDelegate[] UpdateDelegates;
void Awake()
{
//setup all UpdateDelegates here to avoid runtime memory allocation
UpdateDelegates = new UpdateDelegate[(int)GameMode.Count];
//and then each UpdateDelegate
UpdateDelegates[(int)GameMode.Normal] = UpdateNormalState;
UpdateDelegates[(int)GameMode.Endless] = UpdateEndlessState;
UpdateDelegates[(int)GameMode.Campaign] = UpdateCampaignState;
UpdateDelegates[(int)GameMode.Idle] = UpdateIdleState
gameMode = GameMode.Idle;
}
void Update()
{
//call the update method of current state
if(UpdateDelegates[(int)gameMode]!=null)
UpdateDelegates[(int)gameMode]();
}
Now you can separate the logic of each state:
void UpdateNormalState() {
//...
//write logic for normal state
}
//...
//same for other states
This way when you change gameMode, the update method of new state will be iteratively called after end of current frame.
for more info you can watch this video
The good thing about state machines is that they are easy to handle (compared with switch-case or many ifs). you have an array of methods and can do anything you want with them and still be sure that only one of them can run at a time. the maximum delay for changing states is always as short as Time.deltaTime (if Update method is used to call state machine methods)
You can even make the state machine 2D. but make sure you assign all of UpdateDelegates
public enum GameMode { Normal, Endless, Campaign, Idle, Count }
public enum GameState { Playing, Paused, GameOver, Idle, Count }
private UpdateDelegate[,] UpdateDelegates;
UpdateDelegates = new UpdateDelegate[(int)GameMode.Count, (int)GameState.Count];
If it's not enough for your game you can use an advanced state machine. here's a sample code I copied from somewhere and haven't tested yet:
This approach uses transitions between states. e.g. call MoveNext with a given Command and it changes the state to next ProcessState considering the current ProcessState of state machine and the given command.
using System;
using System.Collections.Generic;
namespace Juliet
{
public enum ProcessState
{
Inactive,
Active,
Paused,
Terminated
}
public enum Command
{
Begin,
End,
Pause,
Resume,
Exit
}
public class Process
{
class StateTransition
{
readonly ProcessState CurrentState;
readonly Command Command;
public StateTransition(ProcessState currentState, Command command)
{
CurrentState = currentState;
Command = command;
}
public override int GetHashCode()
{
return 17 + 31 * CurrentState.GetHashCode() + 31 * Command.GetHashCode();
}
public override bool Equals(object obj)
{
StateTransition other = obj as StateTransition;
return other != null && this.CurrentState == other.CurrentState && this.Command == other.Command;
}
}
Dictionary<StateTransition, ProcessState> transitions;
public ProcessState CurrentState { get; private set; }
public Process()
{
CurrentState = ProcessState.Inactive;
transitions = new Dictionary<StateTransition, ProcessState>
{
{ new StateTransition(ProcessState.Inactive, Command.Exit), ProcessState.Terminated },
{ new StateTransition(ProcessState.Inactive, Command.Begin), ProcessState.Active },
{ new StateTransition(ProcessState.Active, Command.End), ProcessState.Inactive },
{ new StateTransition(ProcessState.Active, Command.Pause), ProcessState.Paused },
{ new StateTransition(ProcessState.Paused, Command.End), ProcessState.Inactive },
{ new StateTransition(ProcessState.Paused, Command.Resume), ProcessState.Active }
};
}
public ProcessState GetNext(Command command)
{
StateTransition transition = new StateTransition(CurrentState, command);
ProcessState nextState;
if (!transitions.TryGetValue(transition, out nextState))
throw new Exception("Invalid transition: " + CurrentState + " -> " + command);
return nextState;
}
public ProcessState MoveNext(Command command)
{
CurrentState = GetNext(command);
return CurrentState;
}
}
public class Program
{
static void Main(string[] args)
{
Process p = new Process();
Console.WriteLine("Current State = " + p.CurrentState);
Console.WriteLine("Command.Begin: Current State = " + p.MoveNext(Command.Begin));
Console.WriteLine("Command.Pause: Current State = " + p.MoveNext(Command.Pause));
Console.WriteLine("Command.End: Current State = " + p.MoveNext(Command.End));
Console.WriteLine("Command.Exit: Current State = " + p.MoveNext(Command.Exit));
Console.ReadLine();
}
}
}
Not entirely sure why I'm getting this error. Looked up and down the code for a few hours but I assuming it's a simple fix. Some of the code is copied over from a video and his works perfectly fine, so I don't know why it'd cause me any issues:
using UnityEngine;
using System.Collections;
public class GoldPerSec : MonoBehaviour {
public UnityEngine.UI.Text gpsDisplay();
public Click click;
public ItemManager[] items;
void Start() {
StartCoroutine(AutoTick());
}
void Update() {
gpsDisplay.text = GetGoldPerSec() + " gold/sec";
}
public int GetGoldPerSec(){
int tick = 0;
foreach (ItemManager item in items) {
tick += item.count * item.tickValue;
}
return tick;
}
public void AutoGoldPerSec() {
click.gold += GetGoldPerSec();
}
IEnumerator AutoTick() {
while (true) {
AutoGoldPerSec();
yield return new WaitForSeconds(1);
}
}
}
The problem is in
public UnityEngine.UI.Text gpsDisplay();
That is a method declaration, but there's no code inside the method.
It's unclear from the context what that should actually be. If it's a method, you can either implement it in this class, like
public UnityEngine.UI.Text gpsDisplay()
{
return <something useful>;
}
Maybe it shall be a method and you want to implement it in a subclass, then mark the class as abstract:
public abstract class GoldPerSec : MonoBehaviour
Perhaps it should have been a field, then use
public UnityEngine.UI.Text gpsDisplay;
without the parentheses.
I got this error when I mistakenly added ; before method body. Removing ; stops compiler error.
==My Code. Look ; on very first line ===
public string ReadPopMessage(String identifierOfElement, String elementKey);
{
//string elementID;
elementID = ConfigurationManager.AppSettings.Get(elementKey);
Console.WriteLine("The value of" + elementKey + "is " + elementID);
//MessageBox.Show(elementID);
string strPopupText = oWD.FindElement(By.CssSelector(elementID)).Text;
return elementID;
}
I'm trying to build a class called GameObject (for consoleApplication game), and that GameObject should have a function "onFrame" that is called, let's say, every 0.1 seconds.
But the catch is, that this function (void) should be unique for every gameObject - let's say I have GameObject: G1, G2. G1 will increase a variable by 1 in it's onFrame, and G2 will print something to the console (just examples).
Is it possible to do that?
I tried doing that in this way:
class GameObject
{
public void onFrame;
public GameObject (void of) //constructor
{
onFrame = of;
Thread t = new Thread(runOnFrame);
t.isBackgroundThread = true;
t.Start();
}
protected void runOnFrame ()
{
while (true)
{
Thread.Sleep(100);
if (onFrame != null) onFrame(); //EDIT: that (0) was typed by mistake
}
}
}
And the main function:
public static int i = 0;
static void Main (string[] args)
{
GameObject G1 = new GameObject(new void (){
i++;
});
GameObject G2 = new GameObject(new void () {
Console.WriteLine("OnFrame is being called!");
})
}
But it doesn't seem like being the right way to do that...
Is it possible? And how do I do that?
What you're looking for is an Action, which is the same as a void delegate:
class GameObject
{
public Action onFrame;
public GameObject (Action of) //constructor
{
onFrame = of;
Thread t = new Thread(runOnFrame);
t.isBackgroundThread = true;
t.Start();
}
protected void runOnFrame ()
{
while (true)
{
Thread.Sleep(100);
if (onFrame != null) onFrame();
}
}
}
However I would suggest using a Timer instead of calling thread.Sleep in a continuous loop.
One way to pass in a delegate is to use lambda syntax:
GameObject G1 = new GameObject(() => i++ );
The () is a placeholder for an empty input parameter set:
What you need is a delegate.
Your "onFrame" definition should look something like this:
public delegate void SimpleDelegate();
public SimpleDelegate onFrame;
Your constructor would become this:
public GameObject (SimpleDelegate of)
{
onFrame = of;
Thread t = new Thread(runOnFrame);
t.isBackgroundThread = true;
t.Start();
}
Then later, something like this:
GameObject G1 = new GameObject(new SimpleDelegate(() => {
i++;
}));
.....