Unity: slowdown caused by something? - unity3d

I figured out how to create an asset bundle containing an animation clip, and then loading that animation clip in another project and then overriding existing animation clip with the new one via a script. Basically the goal is to allow users to edit animations.
Everything now thankfully works, but for some reason there is a slowdown. I am not sure what is causing the slowdown when everything is being loaded in start frame:
Here is my code:
protected Animator animator;
protected AnimatorOverrideController animatorOverrideController;
protected AnimationClipOverrides clipOverrides;
void Start()
{
animator = GetComponent<Animator>();
animatorOverrideController = new AnimatorOverrideController(animator.runtimeAnimatorController);
animator.runtimeAnimatorController = animatorOverrideController;
clipOverrides = new AnimationClipOverrides(animatorOverrideController.overridesCount);
animatorOverrideController.GetOverrides(clipOverrides);
LoadAnimation();
}
public void LoadAnimation()
{
StartCoroutine(LoadAnimClip());
}
IEnumerator LoadAnimClip(string )
{
var FilePath = Application.streamingAssetsPath + "/Characters/Sonic/Animations/stand";
var req = AssetBundle.LoadFromFileAsync(FilePath);
yield return req;
AssetBundle animationAsset = req.assetBundle;
AnimationClip animation = animationAsset.LoadAsset<AnimationClip>("Stand") as AnimationClip;
clipOverrides["Idle"] = animation;
animatorOverrideController.ApplyOverrides(clipOverrides);
}
If you are wondering what is animationclipoverrides, here is the class:
public class AnimationClipOverrides : List<KeyValuePair<AnimationClip, AnimationClip>
{
public AnimationClipOverrides(int capacity) : base(capacity) { }
public AnimationClip this[string name]
{
get { return this.Find(x => x.Key.name.Equals(name)).Value; }
set
{
int index = this.FindIndex(x => x.Key.name.Equals(name));
if (index != -1)
this[index] = new KeyValuePair<AnimationClip, AnimationClip>(this[index].Key, value);
}
}
}

Related

Get list of audio mp3 files and play them in Unity 3d

I'm trying to build an audio player that gets the mp3 files from an external source along with logic for Play, Stop, Next and Prev buttons but I haven't figured out how to do it.
http://localhost:8383/Unity3d/Audio/BT - Paul Van Dyk - Namistai.mp3"
http://localhost:8383/Unity3d/Audio/Stevie Wonder - Skeletons.mp3
And then with C#, I'm opening a UnityWebRequest for the URI, save it into an AudioClip variable and then to an AudioSource variable but I'm then finding issues with using the length property/saving into some sort of Audio clip array.
Here's my code below:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Audio;
using UnityEngine.Networking;
using UnityEngine.UI;
[RequireComponent(typeof(AudioSource))]
public class AudioManager : MonoBehaviour
{
public AudioClip[] musicClips;
private int currentTrack;
private AudioSource source;
public List<string> externalAudio;
IEnumerator GetAudioClip()
{
externalAudio.Add("http://localhost:8383/Unity3d/Audio/Stevie%20Wonder%20-%20Skeletons.mp3");
externalAudio.Add("http://localhost:8383/Unity3d/Audio/York%20-%20On%20The%20Beach.mp3");
externalAudio.Add("http://localhost:8383/Unity3d/Audio/BT%20-%20Paul%20Van%20Dyk%20-%20Namistai.mp3");
externalAudio.Add("http://localhost:8383/Unity3d/Audio/S.O.S.%20BAND-JUST%20BE%20GOOD%20TO%20ME%20(SINGLE).mp3");
externalAudio.Add("http://localhost:8383/Unity3d/Audio/Michael%20Jackson%20-%20Beat%20It%20(Official%20Video).mp3");
Debug.Log("Hello World");
Debug.Log(UnityWebRequestMultimedia.GetAudioClip("http://localhost:8383/Unity3d/Audio/Stevie%20Wonder%20-%20Skeletons.mp3", AudioType.MPEG));
foreach (var audioClip in externalAudio)
{
Debug.Log(audioClip);
using (UnityWebRequest www = UnityWebRequestMultimedia.GetAudioClip(audioClip, AudioType.MPEG))
{
UnityWebRequest request = new UnityWebRequest();
yield return www.SendWebRequest();
if (request.result == UnityWebRequest.Result.ConnectionError)
{
Debug.Log(www.error);
}
else
{
musicClips = DownloadHandlerAudioClip.GetContent(www);
source.clip = musicClips;
Debug.Log("Audio is playing.");
}
}
}
}
// Start is called before the first frame update
void Start()
{
source = GetComponent<AudioSource>();
//PLAY MUSIC
PlayMusic();
}
public void PlayMusic()
{
if (source.isPlaying)
{
return;
}
GetAudioClip();
currentTrack--;
if (currentTrack < 0)
{
currentTrack = 0;
}
StartCoroutine(WaitForMusicEnd());
}
IEnumerator WaitForMusicEnd()
{
while (source.isPlaying)
{
yield return null;
}
NextTitle();
}
public void NextTitle()
{
source.Stop();
currentTrack++;
if (currentTrack > musicClips.Length - 1)
{
currentTrack = 0;
}
source.clip = musicClips[currentTrack];
source.Play();
//Show title
StartCoroutine("WaitForMusicEnd");
}
public void PreviousTitle()
{
source.Stop();
currentTrack--;
if (currentTrack < 0)
{
currentTrack = musicClips.Length - 1;
}
source.clip = musicClips[currentTrack];
source.Play();
//Show title
StartCoroutine("WaitForMusicEnd");
}
public void StopMusic()
{
StopCoroutine("WaitForMusicEnd");
source.Stop();
}
}
How can I save the external audio into an AudioClip list and then use them on the play/stop functions logic?
So this is a little bit broad but here is what I would probably do.
As said let your server provide a list of URLs for the downloads. This way you don't have to hardcode them into your client.
So with the previous point, the first thing you do is one single normal GET request to receive that list of URLs, e.g. simply separated by \n (line breaks)
So the first string message you receive could look like e.g.
http://localhost:8383/Moonbeam%20Challenge/Audio/Stevie%20Wonder%20-%20Skeletons.mp3
http://localhost:8383/Moonbeam%20Challenge/Audio/York%20-%20On%20The%20Beach.mp3
http://localhost:8383/Moonbeam%20Challenge/Audio/BT%20-%20Paul%20Van%20Dyk%20-%20Namistai.mp3
http://localhost:8383/Moonbeam%20Challenge/Audio/S.O.S.%20BAND-JUST%20BE%20GOOD%20TO%20ME%20(SINGLE).mp3
http://localhost:8383/Moonbeam%20Challenge/Audio/Michael%20Jackson%20-%20Beat%20It%20(Official%20Video).mp3
This received list you Split into the individual URLs
var urls = urlList.Split('\n');
For these you start your individual GetAudioClip requests.
The results you store in an array/a list as elements. You don't assign the entire musicClips. I would rather use a
List<AudioClip> musicClips = new List<AudioClip>();
and then from your downloads do
musicClips.Add(DownloadHandlerAudioClip.GetContent(www));
you also don't want to assign and play each downloaded clip to the AudioSource as soon as it is downloaded but rather wait until all of them are downloaded (or at least the first one, depending on your needs)
So this might look somewhat like
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Audio;
using UnityEngine.Networking;
using UnityEngine.UI;
using System.Linq;
[RequireComponent(typeof(AudioSource))]
public class AudioManager : MonoBehaviour
{
[Header("References")]
[SerializeField]
private AudioSource source;
[Header("Settings")]
[SerializeField] private string baseURL;
[SerializeField] private string[] externalAudio;
[SerializeField] private bool autoStartPlayAfterDownloads = true;
[Header("Debugging")]
[SerializeField] private List<AudioClip> musicClips = new List<AudioClip>();
[SerializeField] private int currentTrack;
[SerializeField] private bool isInitialized;
private Coroutine currentPlayTrack;
// Yes, if you make Start return IEnumerator then Units
// automatically runs it as a Coroutine
private IEnumerator Start()
{
// block input from the outside until this controller is finished with the downloads
isInitialized = false;
if (!source) source = GetComponent<AudioSource>();
// Here either use the approach with first receiving a list from the server
yield return GetAudioClipsInfo();
// OR if you already have the clip urls assigned via the Inspector use one of
yield return GetAudioClipsSequencial();
// OR
yield return GetAudioClipsParallel();
// allow to do things from this point on
isInitialized = true;
if(autoStartPlayAfterDownloads) PlayFirstTitle();
}
// This is the routine that downloads the URL list from the server
// then it starts the individual downloads
private IEnumerator GetAudioClipsInfo()
{
// Make the first request for receiving the list of URLs from the server
// If not using this but already assigning the urls
// via Inspector then simply directly use the "GetAudioClips" below
using (var request = UnityWebRequest.Get(baseURL))
{
yield return request.SendWebRequest();
switch (request.result)
{
case UnityWebRequest.Result.ConnectionError:
case UnityWebRequest.Result.DataProcessingError:
case UnityWebRequest.Result.ProtocolError:
Debug.LogError($"Could not get list of clips! Error: {request.error}", this);
yield break;
}
var urlList = request.downloadHandler.text;
externalAudio = urlList.Split('\n');
// Here you can either go for the sequencial downloads
yield return GetAudioClipsSequencial();
// OR run them all parallel
yield return GetAudioClipsParallel();
}
}
// This version starts one download at a time, waits until it is done
// then starts the next
private IEnumerator GetAudioClipsSequencial()
{
musicClips.Clear();
foreach (var url in externalAudio)
{
Debug.Log(url);
using (var www = UnityWebRequestMultimedia.GetAudioClip(url, AudioType.MPEG))
{
yield return www.SendWebRequest();
switch (www.result)
{
case UnityWebRequest.Result.ConnectionError:
case UnityWebRequest.Result.DataProcessingError:
case UnityWebRequest.Result.ProtocolError:
Debug.LogError($"Could not get clip from \"{url}\"! Error: {www.error}", this);
continue;
}
musicClips.Add(DownloadHandlerAudioClip.GetContent(www));
}
}
}
// This version starts all downloads at once and waits until they are all done
// probably faster than the sequencial version
private IEnumerator GetAudioClipsParallel()
{
musicClips.Clear();
var requests = new List<UnityWebRequest>();
foreach (var url in externalAudio)
{
Debug.Log(url);
var www = UnityWebRequestMultimedia.GetAudioClip(url, AudioType.MPEG);
// Start the request without waiting
www.SendWebRequest();
requests.Add(www);
}
// Wait for all requests to finish
yield return new WaitWhile(() => requests.Any(r => !r.isDone));
// Now examine and use all results
foreach (var www in requests)
{
switch (www.result)
{
case UnityWebRequest.Result.ConnectionError:
case UnityWebRequest.Result.DataProcessingError:
case UnityWebRequest.Result.ProtocolError:
Debug.LogError($"Could not get clip from \"{www.url}\"! Error: {www.error}", this);
continue;
}
musicClips.Add(DownloadHandlerAudioClip.GetContent(www));
www.Dispose();
}
}
public void PlayFirstTitle()
{
if (!isInitialized) return;
if (source.isPlaying) return;
if (currentPlayTrack != null)
{
StopCoroutine(currentPlayTrack);
}
currentPlayTrack = StartCoroutine(PlayTrack(0));
}
private IEnumerator PlayTrack(int index)
{
// Make sure the index is within the given clips range
index = Mathf.Clamp(index, 0, musicClips.Count);
// update the current track to make next and previous work
currentTrack = index;
// get clip by index
var clip = musicClips[currentTrack];
// Assign and play
source.clip = clip;
source.Play();
// wait for clip end
while (source.isPlaying)
{
yield return null;
}
NextTitle();
}
public void NextTitle()
{
if (!isInitialized) return;
if (currentPlayTrack != null)
{
StopCoroutine(currentPlayTrack);
}
source.Stop();
currentTrack = (currentTrack + 1) % musicClips.Count;
currentPlayTrack = StartCoroutine(PlayTrack(currentTrack));
}
public void PreviousTitle()
{
if (!isInitialized) return;
if (currentPlayTrack != null)
{
StopCoroutine(currentPlayTrack);
}
source.Stop();
currentTrack--;
if (currentTrack < 0)
{
currentTrack = musicClips.Count - 1;
}
currentPlayTrack = StartCoroutine(PlayTrack(currentTrack));
}
public void StopMusic()
{
if (!isInitialized) return;
if (currentPlayTrack != null)
{
StopCoroutine(currentPlayTrack);
}
source.Stop();
}
}

How can I create an object at the mouse point in scene view by clicking not dragging the object?

Generally, most objects are placed in the scene view by dragging or something. I want to right click the mouse (without dragging an object) to create an object in the scene view. I know this would require some editor coding but I’m not sure how to go about it.
UPDATE
After giving it some thought I realised that using a MenuItem would be quite appropriate for me. Here is my code below:
SLMenuItems:
public class SLMenuItems : MonoBehaviour {
public bool canClickSceneViewToCreatePath = false;
void Start()
{
}
[MenuItem("Component/Create Custom Object")]
static void CreateObject() {
Debug.Log("menu item selected");
canClickSceneViewToCreatePath = true;
}
}
SLMenuItemsEditor:
[CustomEditor(typeof(SLMenuItems))]
public class SLMenuItemsEditor : Editor {
SLMenuItems slMenuItems;
void OnEnable()
{
slMenuItems = (SLMenuItems)target;
}
void OnSceneGUI()
{
if (slMenuItems.canClickSceneViewToCreatePath) {
Vector3 pointsPos = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition).origin;
if (Event.current.type == EventType.MouseDown && Event.current.button == 0)
{
// create object here at pointsPos
slMenuItems.canClickSceneViewToCreatePath = false;
}
}
}
}
I keep getting the following error:
Assets/SLMenuItems.cs(23,9): error CS0120: An object reference is required to access non-static member `SLMenuItems.canClickSceneViewToCreatePath'
pointing to the line:
canClickSceneViewToCreatePath = true;
in SLMenuItems.
Your CreateObject method is static but your canClickSceneViewToCreatePath value is not.
It has nothing to do with the editor script but with your class SlMenuItems itself.
A static method is not instanced or with other words it is kind of shared between all instances of that component type while the non-static value might be different for each component.
So how should a static method - which is the same for all instances - "know", which of the instances values it should access?
So either make the method non-static or the variable static. Depending on what your further need is.
Since the MenuItem needs a static method make the variable static as well.
I would suggest you make that class not inherit from MonoBehaviour at all since it doesn't have any behaviour for a GameObject. It only brings some editor features so rather make it a static class that can "live" in the Assets without needing to be instanced.
Than you can use SceneView.onSceneGUIDelegate to register a callback for OnSceneGUI without implementing an editor script for that:
private static GameObject lastCreated;
private static bool isCreating;
public static class SLMenuItems
{
[MenuItem("Component/Create Custom Object")]
private static void CreateObject()
{
Debug.Log("menu item selected");
isCreating = true;
lastCreated = null;
// Add a callback for SceneView update
SceneView.onSceneGUIDelegate -= UpdateSceneView;
SceneView.onSceneGUIDelegate += UpdateSceneView;
}
private static void UpdateSceneView(SceneView sceneView)
{
if(lastCreated)
{
// Keep lastCreated focused
Selection.activeGameObject = lastCreated;
}
if(isCreating)
{
if (Event.current.type == EventType.MouseDown && Event.current.button == 0)
{
Vector3 pointsPos = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition).origin;
//Todo create object here at pointsPos
lastCreated = Instantiate(somePrefab);
// Avoid the current event being propagated
// I'm not sure which of both works better here
Event.current.Use();
Event.current = null;
// Keep the created object in focus
Selection.activeGameObject = lastCreated;
// exit creation mode
isCreating = false;
}
}
else
{
// Skip if event is Layout or Repaint
if(e.type == EventType.Layout || e.type == EventType.Repaint)
{
Selection.activeGameObject = lastCreated;
return;
}
// Prevent Propagation
Event.current.Use();
Event.current = null;
Selection.activeGameObject = lastCreated;
lastCreated = null;
// Remove the callback
SceneView.onSceneGUIDelegate -= UpdateSceneView;
}
}
}
But I suggest you change your questions title since this is actually not the solution to the "task" you describe before.

Photon, PlayFab, & Unity3D - Players not appearing to one another after joining Photon Room

I am working on a multiplayer game in Unity which is using Playfab and the Authentication and Photon which is hosting the multiplayer. I can successfully get players into the same room and I can load the scene after players 'join' the room, however, when 2 players are in the same room, they can not see each other.
This is my authentication service:
public class LoginWithCustomID : MonoBehaviour
{
private string _playFabPlayerIdCache;
private bool _isNewAccount;
private string _playerName;
// Use this to auth normally for PlayFab
void Awake()
{
PhotonNetwork.autoJoinLobby = false;
PhotonNetwork.automaticallySyncScene = true;
DontDestroyOnLoad(gameObject);
authenticateWithPlayfab();
}
private void authenticateWithPlayfab()
{
var request = new LoginWithCustomIDRequest
{
CustomId = "CustomId123",
CreateAccount = true,
InfoRequestParameters = new GetPlayerCombinedInfoRequestParams()
{
GetUserAccountInfo = true,
ProfileConstraints = new PlayerProfileViewConstraints()
{ ShowDisplayName = true }
}
};
PlayFabClientAPI.LoginWithCustomID(request, requestPhotonToken, OnLoginFailure);
}
private void requestPhotonToken(LoginResult result)
{
PlayerAccountService.loginResult = result;
_playFabPlayerIdCache = result.PlayFabId;
_playerName = result.InfoResultPayload.AccountInfo.TitleInfo.DisplayName;
if (result.NewlyCreated)
{
_isNewAccount = true;
setupNewPlayer(result);
}
PlayFabClientAPI.GetPhotonAuthenticationToken(new GetPhotonAuthenticationTokenRequest()
{
PhotonApplicationId = "photonId123"
}, AuthenticateWithPhoton, OnLoginFailure);
}
private void setupNewPlayer(LoginResult result)
{
PlayFabClientAPI.UpdateUserData(
new UpdateUserDataRequest()
{
Data = new Dictionary<string, string>()
{
{ "Level", "1" },
{ "xp", "0" }
}
}, success =>
{
Debug.Log("Set User Data");
}, failure =>
{
Debug.Log("Failed to set User Data..");
}
);
}
private void AuthenticateWithPhoton(GetPhotonAuthenticationTokenResult result)
{
Debug.Log("Photon token acquired: " + result.PhotonCustomAuthenticationToken);
var customAuth = new AuthenticationValues { AuthType = CustomAuthenticationType.Custom };
customAuth.AddAuthParameter("username", _playFabPlayerIdCache);
customAuth.AddAuthParameter("token", result.PhotonCustomAuthenticationToken);
PhotonNetwork.AuthValues = customAuth;
setNextScene();
}
private void setNextScene()
{
if(_isNewAccount || _playerName == null)
{
SceneManager.LoadSceneAsync("CreatePlayerName", LoadSceneMode.Single);
}
else
{
SceneManager.LoadSceneAsync("LandingScene", LoadSceneMode.Single);
}
}
private void OnLoginFailure(PlayFabError error)
{
Debug.LogWarning("something went wrong in auth login");
Debug.LogError("Here's some debug info:");
Debug.LogError(error.GenerateErrorReport());
}
}
}
This all works and a player is logged into PlayFab, as well as Photon I would assume if I got the Photon auth token. This brings me to my landing scene, which is essentially a place for an authenticated user to click a button to join a random room via Photon:
public static GameManager instance;
public static GameObject localPlayer;
private void Awake()
{
if (instance != null)
{
DestroyImmediate(instance);
return;
}
DontDestroyOnLoad(gameObject);
instance = this;
PhotonNetwork.automaticallySyncScene = true;
}
// Use this for initialization
void Start()
{
PhotonNetwork.ConnectUsingSettings("A_0.0.1");
}
public void JoinGame()
{
RoomOptions ro = new RoomOptions();
ro.MaxPlayers = 4;
PhotonNetwork.JoinOrCreateRoom("Test Room 2", ro, null);
}
public override void OnJoinedRoom()
{
Debug.Log("Joined Room!");
if (PhotonNetwork.isMasterClient)
{
PhotonNetwork.LoadLevel("Test_Map1");
}
}
private void OnLevelWasLoaded(int level)
{
if (!PhotonNetwork.inRoom)
return;
localPlayer = PhotonNetwork.Instantiate(
"Player",
new Vector3(0, 1f, 0),
Quaternion.identity,
0);
}
public void LeaveRoom()
{
PhotonNetwork.LeaveRoom();
SceneManager.LoadScene("LandingScene", LoadSceneMode.Single);
}
This loads the scene that I named "Test_scene1" successfully and I show within my scene, the room name and number of active players in the room. When I do a run and build, I get a user's playerPrefab to load into the room. When I run the game through unity, I can get a second player to log into the room. The problem is, the players do not see eachother and I can not figure out why that is. I am following the PLayerfab/Photon tutorials on their respective sites, but I can't find anything that I did wrong in either one.
From what I read, it looks like my instantiate method might be wrong but I'm not sure why. Below is my player Prefab showing the components attached to it:
I apologize for this huge question, I just wanted to provide as much information as I could.
This question was answered by the OP on PlayFab forums here.

Using PlayerPrefs (unity)

I have recently been creating a game with tutorials. Unfortunately, they didn't cover a save score feature. Thanks to another user, I was able to figure out that I needed to use playerprefs. I watched tutorials online, but none of them were helpful. If you can, please help me!
Gold Per Sec Script:
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() + " Money Per Sec";
}
public float GetGoldPerSec() {
float tick = 0;
foreach (ItemManager item in items) {
tick += item.count * item.tickValue;
}
return tick;
}
public void AutoGoldPerSec() {
click.gold += GetGoldPerSec() / 10;
}
IEnumerator AutoTick() {
while (true) {
AutoGoldPerSec();
yield return new WaitForSeconds(0.10f);
}
}
}
Gold Per Click script:
using UnityEngine;
using System.Collections;
public class Click : MonoBehaviour {
public UnityEngine.UI.Text gpc;
public UnityEngine.UI.Text goldDisplay;
public float gold = 0.00f;
public int goldperclick = 1;
void Update () {
goldDisplay.text = "" + gold.ToString("F0");
gpc.text = "Money Per Click: " + goldperclick;
}
public void Clicked(){
gold += goldperclick;
}
}
My idea was for the game to save when the game is quit, and load as soon as you load the game back up. I am a complete beginner, if anyone can tell me how to do this, please tell me! Thanks! :D
You can use unity's existing functions to achieve this.
For saving data use unity's OnApplicationQuit function like this
void OnApplicationQuit() {
PlayerPrefs.SetFloat("key", value);
}
And for Restoring the values use unity's Awake function like this
void Awake(){
value = PlayerPrefs.GetFloat("key");
}
Please note that PlayerPrefs is an easy way to save data but also an very unsafe way. The player can easily manipulate his "goldValue" since it's just stored as an integer in some file on his device. PlayerPrefs should usually just be used for values the player can changed any way within in game, like volume setting etc.
EXAMPLE CODE
void Save()
{
string filename = "/filename.dat";
BinaryFormatter bf = new BinaryFormatter();
FileStream file = File.Create(Application.persistentDataPath+filename);
bf.Serialize(file, goldValue); //Use can easily use e.g. a List if you want to store more date
file.Close();
}
bool Load()
{
string filename = "/filename.dat";
if (File.Exists(Application.persistentDataPath + filename))
{
BinaryFormatter bf = new BinaryFormatter();
FileStream file = File.Open(Application.persistentDataPath + filename, FileMode.Open);
goldValue=(int) bf.Deserialize(file);
file.Close();
return true;
}
return false;
}
Add the following code to Click class:
void Awake()
{
LoadData();
}
void OnApplicationQuit()
{
SaveData();
}
void SaveData()
{
PlayerPrefs.SetFloat("gold",gold);
}
void LoadData()
{
gold = PlayerPrefs.GetFloat("gold",0f);
}

I'm stuck at slick graphics

I'm trying to make a game, using slick2d, and lwjgl. I don't get why this code doesn't work
firstStage.java
package net.CharlesDickenson;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Image;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.state.BasicGameState;
import org.newdawn.slick.state.StateBasedGame;
public class firstStage extends BasicGameState {
public bossVar bossChecker() {
if(isBeforeMiddleBoss) return bossVar.beforeBoss;
if(isMiddleBoss) return bossVar.Middle;
if(isBeforeBoss) return bossVar.beforeBoss;
if(isBoss) return bossVar.Boss;
return null;
}
#SuppressWarnings("static-access")
public firstStage(int state) {
this.state = state;
}
#Override
public void init(GameContainer _arg0, StateBasedGame _arg1)
throws SlickException {
scoreBoard = new Image("res/scoreBoard.png");
backs = new Image("res/1stageBack.gif");
isBeforeMiddleBoss = true;
isMiddleBoss = false;
isBeforeBoss = false;
isBoss = false;
_arg0.setShowFPS(false);
}
#Override
public void render(GameContainer arg0, StateBasedGame _arg1, Graphics _g)
throws SlickException {
this._g = _g;
new Mob().getGraphics(_g);//i passed graphics
new Char().getGraphics(_g);//i passed graphics
new Bullet().getGraphics(_g);//i passed graphics
_g.drawImage(scoreBoard, 550, 5);
_g.drawImage(backs, 10, 10);
_g.drawString(fps, 580, 570);
_g.drawString("High Score-> Not avaiable", 560, 60);
_g.drawString("Score-> " + currScore, 595, 80);
}
#Override
public void update(GameContainer _arg0, StateBasedGame _arg1, int arg2)
throws SlickException {
fps = "Frame Per Second-> " + _arg0.getFPS();
bossVar b = bossChecker();
switch(b) {
case beforeMiddle :
break;
case Boss :
break;
default:
break;
}
}
#SuppressWarnings("static-access")
#Override
public int getID() {
return this.state;
}
private static int state;
private static int currScore = 0;
private static final int originX = 270;
private static final int originY = 490;
public static int X = originX;
public static int Y = originY;
private static String fps;
private Image scoreBoard;
private Image backs;
private Graphics _g;
public boolean isBeforeMiddleBoss;
public boolean isMiddleBoss;
public boolean isBeforeBoss;
public boolean isBoss;
}
Char.java
package net.CharlesDickenson;
import org.lwjgl.input.Keyboard;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Image;
import org.newdawn.slick.SlickException;
public class Char extends Bullet implements Entity {
#Override
public void getGraphics(Graphics _g) {
this._g = _g;//so i got graphics, but
if(!isInit) return;
_g.drawImage(Char, getCharX(), getCharY());//this codes doesn't works.
}
#Override
public int getCharX() {
switch(VarTracker.stage) {
case 1:
return firstStage.X;
}
return 0;
}
#Override
public int getCharY() {
switch(VarTracker.stage) {
case 1:
return firstStage.Y;
}
return 0;
}
public void setCharX(int i) {
System.out.println("asdgagsd");
switch(VarTracker.stage) {
case 1:
firstStage.X += i;
}
}
public void setCharY(int i) {
System.out.println("asdgagsd");
switch(VarTracker.stage) {
case 1:
firstStage.Y += i;
}
}
#Override
public void update() {
if(!isInit) return;
_g.drawImage(Char, getCharX(), getCharY());//this code doesn't work, too.
up = Keyboard.isKeyDown(Keyboard.KEY_UP);
down = Keyboard.isKeyDown(Keyboard.KEY_DOWN);
left = Keyboard.isKeyDown(Keyboard.KEY_LEFT);
right = Keyboard.isKeyDown(Keyboard.KEY_RIGHT);
shift = Keyboard.isKeyDown(Keyboard.KEY_LSHIFT);
z = Keyboard.isKeyDown(Keyboard.KEY_Z);
if(up && !shift) {
setCharY(6);
}
if(down && !shift) {
setCharY(-6);
}
if(left && !shift) {
setCharX(-6);
}
if(right && !shift) {
setCharX(6);
}
if(up && shift) {
setCharY(2);
}
if(down && shift) {
setCharY(-2);
}
if(left && shift) {
setCharX(-2);
}
if(right && shift) {
setCharX(2);
}
if(z) {
new Bullet().isFiring = true;
}
if(!z) {
new Bullet().isFiring = false;
}
}
#Override
public void init() {
System.out.println("<Char> Initializing...");
isInit = false;
try {
Char = new Image("res/char.png");
} catch (SlickException e) {
e.printStackTrace();
}
isInit = true;
System.out.println("<Char> Done with init()");
}
private boolean up;
private boolean down;
private boolean left;
private boolean right;
private boolean shift;
private boolean z;
private boolean isInit;
private Image Char;
private Graphics _g;
}
I passed graphics to other class using getGraphics method, to put a image, but it doesn't work.
at render method, it worked, but I can't put a image in other class.
The reason that it doesn't work is that you are using Graphics incorrectly. When Slick2d draws something, it uses the render method. This method is passed an instance of Graphics, to which you can draw stuff. When the call ends the Graphics object is no longer useful for anything. There is thus no reason to pass it to anything that doesn't use it immediately.
What you want to do is create a render method in your Mob, Char and Bullet classes. Make instances of said classes outside of the render method, for instance in init and store them in some data structure, for instance a List. In the render method, you simple traverse the list and call render or draw on each element. A quick example:
// Give the Entity interface two methods if they don't exist already:
public interface Entity {
void render(Graphics g);
void update(int delta);
}
// In firststage.java
List<Entity> list;
// In the init() method
public void init(GameContainer container, StateBasedGame game)
throws SlickException {
...
list = new ArrayList<Entity>();
list.add(new Mob());
list.add(new Char());
list.add(new Bullet());
}
// In the render method
public void render(GameContainer container, StateBasedGame game, Graphics g)
throws SlickException {
...
for (Entity e : list) {
e.draw(g);
}
}
// In the update method
public void update(GameContainer container, StateBasedGame game, int delta)
throws SlickException {
...
for (Entity e : list) {
e.update(delta);
}
}
TL;DR version: The Graphics object exists only to be drawn to in a single render call.
Render is called many times a second, so object creation in that method is not recommended.
Object oriented programming is good at modeling objects. Games tend to model a lot of objects. Make use of it.