I'm using Python 3.3 with Pygame and PygButton (low rep don't allow me more than two links)
My files at the moment are [int.py http://pastebin.com/sDRhieCG ] and [scene.py http://pastebin.com/Y2Mgsgmr ].
The idea is making a mainloop in int.py the smaller as possible. The code has a commented-out example of the start_screen buttons at the mainloop. It works, but with every new screen the mainloop would be bloated.
So I created a Scene class to apply background, texts and buttons. It works, but I can make the buttons work. E.g. the bquit button doesn't quit the screen (as it did previously when inserted into the mainloop).
I'm trying to create a scene_loop() inside the Scene() to run everything the specific scene has to offer. With a button click it would change scene and such, start a new scene_loop.
I can't seem to add specific methods after the Scene class is instanced, so I created a Scene_Start class to deal with specific methods like the scene_loop and its buttons (since the background is easily placed through the Scene class).
I'm just stuck and can't see a way to resolve this without scrapping everything and starting again.
Help?
tl;dr:
1. PygButton isn't working outside mainloop
2. How can I create a scene_loop that replaces the mainloop for that scene, "unbloating" mainloop (it would only take care of starting the app and changing scenes).
Thank You.
Problem solved. Answering my own question so it can be helpful to others.
Each class have a sceneloop method that runs and "replace" the mainloop. This allows for unbloating and isolating any problem into the scene without affecting the other components.
The mainloop:
while True:
for event in pg.event.get():
if event.type == QUIT or (event.type == KEYDOWN and event.key == K_ESCAPE):
pg.quit()
sys.exit()
scene.startscreen.draw()
scene.startscreen.sceneloop()
pg.display.update()
A sceneloop example. This is a method inside the Scene_Start(Scene) class, instanced as startscreen as show above in the main loop.
def sceneloop(self):
while self.scene_loop == True:
for event in pg.event.get():
if event.type == QUIT or (event.type == KEYDOWN and event.key == K_ESCAPE):
pg.quit()
sys.exit()
if 'click' in self.bcreate.handleEvent(event): #CREATE
startcreate.draw()
startcreate.sceneloop()
if 'click' in self.bstart.handleEvent(event): #START
pg.quit()
sys.exit()
if 'click' in self.bload.handleEvent(event): #LOAD
startload.draw()
startload.sceneloop()
if 'click' in self.boptions.handleEvent(event): #OPTIONS
startoptions.draw()
startoptions.sceneloop()
if 'click' in self.bquit.handleEvent(event): #QUIT
pg.quit()
sys.exit()
self.update()
Related
I have monster named Fungant in my 2D platform game.
It can hide as mushroom and rise to his normal form.
I try to handle it in code, but I don't know how to get information about finished animation (without it, animation of rising and hiding always was skipped).
I think the point there is to get info about complete of the one of two animations - Rise and Hide.
There is current code:
if (
fungantAnimator.GetCurrentAnimatorStateInfo(0).IsName("Fungant Rise")
)
{
fungantAnimator.SetBool("isRising", false);
isRisen = true;
fungantRigidbody.velocity = new Vector2(
walkSpeed * Mathf.Sign(
player.transform.position.x - transform.position.x),
fungantRigidbody.velocity.y
);
}
if (fungantAnimator.GetCurrentAnimatorStateInfo(0).IsName("Fungant Hide"))
{
fungantAnimator.SetBool("isHiding", false);
isRisen = false;
}
I try this two ways:
StateMachineBehaviour
I would like to get StateMachineBehaviour, but how to get it?
No idea how to process this further.
AnimationEvents
Tried to do with animation event but every tutorial have list of functions to choose (looks easy), but in my Unity I can write Function, Float, Int, String or select object (what I should do?).
I decided to write test() function with Debug only inside, and create AnimationEvents with written "test()" in function field, but nothing happens.
Same as above, no more ideas how to process this further.
I personally would use animation events for this. Just add an event to the animation and then the event plays a function after the animation transition is finished.
For more information on how to use animation events you can click here.
This post may also help you to add an event when the animation is finished.
I hope this answer helps you to solve this problem.
How do I make a script if somebody touched a brick and then maybe a GUI then shows subtitles for like a few seconds and goes the downside of your screen? (like credits after a movie)
I know the first part of creating this but I do not know the GUI part. For the first part, I think you should do something like this...
local Part = script.Parent -- This would define the part that is to be touched.
function onTouch(Brick) -- Starts the onTouch function which sends us "Brick", the triggering object.
local Player = Brick.Parent:findFirstChild("Humanoid") -- Finds Humanoid in Brick.
if (Player ~= nil) then -- Checks if the player is a real Player.
print("Hello World"")
end
end
Replace the print("Hello World!") line with the code from the GUI if you know it.
Regards, Shay!
I am trying to learn how to create a CGEvent tap using examples on SO and and elsewhere.
I know how to create an event tap using:
let eventTap = CGEvent.tapCreate(*/arguments to create the tap*/)
After that I run
let runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, eventTap, 0)
CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, .commonModes)
Some, but not all examples I've found online also add the following two lines
CGEvent.tapEnable(tap: eventTap, enable: true)
CFRunLoopRun()
Can someone briefly explain if or when is adding the last two lines are useful/recommended?
The first is easy: the docs say:
Event taps are normally enabled when created. If an event tap becomes unresponsive, or if a user requests that event taps be disabled, then a kCGEventTapDisabled event is passed to the event tap callback function. Event taps may be re-enabled by calling this function.
The second one is probably for cases where the program doesn't have a run loop (on the current thread). For example, a command-line program which doesn't use NSApplication would need to create and run its own run loop.
I have an idle player animation and I want to do a smooth transition between some animations. The idle animation is the default one and from that transition I want to be able to switch to another state(let's say fight) and then back to idle. The code for the idle character animation is currently like :
self.addChild(playerAnimation)
playerAnimation.runAction(SKAction.repeatActionForever(
SKAction.animateWithTextures(playerAnimationManager.idleManAnimation.textureArray, timePerFrame: 0.1)))
Now, this is scheduled to go on forever for now, but I would need to intercept it and add a new animation on top of that (which is the same character, in a new state). I was thinking that I should stop the idle animation, switch to the new one and then back to idle when finished but I am not convinced that this is the best way of chaining animations and I haven't really found a good resource explaining how to go about it.
Any suggestions ? Thanks !
Depending on how short your texture array is, you might be able to do this.
I will try to explain without code seeing how I use objective C and you use Swift
First make a property or variable that can be called by any subroutine in this class file. It should be Boolean and should be set to NO. You could call it idleFlag.
Next make a method that changes the animation to fight mode. This change would be by removing the idle animation and replacing it with the fight animation. This method also set's idleFlag to NO. Let's call the method "beginFightAnim"
And last, in your repeatActionForEver idle animation, right after your animateWithTextures animation, add a runBlock animation. In this block define a static variable (one that will be remembered in the calling of the block over and over) and increment it by +1, add an "if statement" that looks something like this -> if (my_static_var == number_of_frames_in_texture_animations && idleFlag). And in the "if statement" set the static variable to 0 and call "beginFightAnim"
After this all you have to do to change the animation is set idleFlag to YES.
Hope it works!
If you have any problems, please comment below.
I want to do a series of examples to make it easier to understand the matter. Suppose you have your node called playerAnimation, a typical atlasc with a plist where you have
player-idle1.png
player-idle2.png
player-idle3.png
...
If you want to intercept in real-time your animation to know what frame is running in that moment you can do:
override func update(currentTime: CFTimeInterval) {
if String(playerAnimation.texture).rangeOfString("player-idle") != nil {
print(String(playerAnimation.texture))
}
}
At this point, after you have assigned a "key" to your action (withKey:"idleAnimation") you could stop your specific idle action when you preefer to start the other next animation.
Another good thing is to build a structure to know everytime your player status and modify this variable each time you launch a new action or animation:
enum PlayerStatus: Int {
case Idle = 1
case Fight = 2
case Run = 3
case Jump = 4
case Die = 5
...
}
var currentStatus: PlayerStatus!
I got a problem in my project. I want to know that mouse cliked happend on GUI or on any game object.
I have tried this but it is showing null reference exception
EventSystem eventSystem = EventSystem.current;
if (eventSystem.IsPointerOverGameObject())
Debug.Log("left click over a gui element");
how to detect?? Is there any event available or else?
IsPointerOverGameObject() is fairly broken on mobile and some corner cases. We rolled our own for our project and it works like a champ on all platforms we've thrown it at.
private bool IsPointerOverUIObject() {
PointerEventData eventDataCurrentPosition = new PointerEventData(EventSystem.current);
eventDataCurrentPosition.position = new Vector2(Input.mousePosition.x, Input.mousePosition.y);
List<RaycastResult> results = new List<RaycastResult>();
EventSystem.current.RaycastAll(eventDataCurrentPosition, results);
return results.Count > 0;
}
Source:
http://forum.unity3d.com/threads/ispointerovereventsystemobject-always-returns-false-on-mobile.265372/
There is some approaches that you can use to detect if your mouse is over a legacy GUI element here I'll show you one that I hope will work fine for you, if not research a little about "mouse over GUI" and you'll find a lot of different ways to do it (this one is what I use on my legacy GUI projects and usually works fine with touch):
Create an easily accessible behaviour (usually a singleton) to hold your MouseOverGUI "status":
if you are using GUILayout.Button you need to catch the last drawn rect, if you are GUI.Button just use the same rect you passed as button's param like this:
// GUILayout
( Event.current.type == EventType.Repaint &&
GUILayoutUtility.GetLastRect().Contains( Event.current.mousePosition ) ) {
mouseOverGUI = true;
}
} // you need call it in your OnGUI right after the call to the element that you want to control
// GUI
( Event.current.isMouse &&
yourRect.Contains( Event.current.mousePosition ) ) {
mouseOverGUI = true;
}
}
after that you just need to test if your mouseOverGUI is true or false to allow or not your desired click actions before execute them. (a good understanding of unity loops will help you to catch and test the flag in correct timing to avoid problems expecting to get something that already changed)
edited: also remember to reset mouseOverGUI to false when it is not over GUI ;)
Finally got my answer here:
There are three ways to do this, as demonstrated in this video tutorial. this video save me:).
Use EventSystem.current.IsPointerOverGameObject
Convert your OnMouseXXX and Raycasts to an EventSystem trigger. Use a physics raycaster on the camera
Implement the various handler interfaces from the EventSystems namespace. Use a physics raycaster on the camera.