I am just starting to learn actionscript, and to help get used to the syntax, I am challenging myself to make a simple game where you are a circle that shoots falling blocks.
For some reason every time I try to add a keyboard event listener the game doesn't run.
Here is my player file.
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.events.KeyboardEvent;
import flash.ui.Keyboard;
public class Player extends Sprite
{
//Variables
private var playerRadius:Number = 50;
private var playerX:Number = 5;
private var playerY:Number = 5;
private var speed:Number = 0;
private var xvel:Number = 0;
public function Player()
{
init();
//Drawing
drawPlayer();
//Event Listeners
this.addEventListener(Event.ENTER_FRAME, updatePlayer);
stage.addEventListener(KeyboardEvent.KEY_DOWN, controlPlayer);
}
//Update
public function updatePlayer(event:Event):void{
this.x ++;
}
//Draw
private function drawPlayer():void{
graphics.beginFill(0xFF0000);
graphics.drawCircle(10,10,50);
graphics.endFill();
}
//Control
public function controlPlayer(event:KeyboardEvent):void{
if (event.keyCode == Keyboard.RIGHT) {
speed = 5;
}
}
}
}
With this code I just get a white screen, but if I comment out
stage.addEventListener(KeyboardEvent.KEY_DOWN, controlPlayer);
it works, but I don't have control of the player.
I'd appreciate any and all help!
Using your code I was able to figure out your issue which ultimately turned out to be a couple problems with your code. I'm surprised you were not seeing the following error in the Flash 'Output' Panel when you tested the application:
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at Player()
at Player_fla::MainTimeline/frame1()
The first issue is that when you create an object of the type Player, it isn't yet added to the Stage, so it does not yet have access to the stage object.
Once the player object is added to the Stage, only then will you be able to add the listener for keyboard events to the stage; however, for this to happen, your Player class needs to be made aware of the fact that an instance of it was added to the stage so that it knows exactly when it should register the keyboard event listener.
Here is an updated version of your code that should resolve these issues:
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.events.KeyboardEvent;
import flash.ui.Keyboard;
public class Player extends Sprite
{
//Variables
private var playerRadius:Number = 50;
private var playerX:Number = 5;
private var playerY:Number = 5;
private var speed:Number = 0;
private var xvel:Number = 0;
public function Player()
{
init();
//Drawing
drawPlayer();
//Event Listeners
this.addEventListener(Event.ENTER_FRAME, updatePlayer);
this.addEventListener(Event.ADDED_TO_STAGE, initKeyboardListener);
}
public function initKeyboardListener(event:Event) {
stage.addEventListener(KeyboardEvent.KEY_DOWN, controlPlayer);
}
//Update
public function updatePlayer(event:Event):void{
this.x++;
}
//Draw
private function drawPlayer():void{
graphics.beginFill(0xFF0000);
graphics.drawCircle(10,10,50);
graphics.endFill();
}
//Control
public function controlPlayer(event:KeyboardEvent):void {
if (event.keyCode == Keyboard.RIGHT) {
this.speed = 5;
}
}
} // end class
} // end package
For all of this to work, don't forget to add the player object to the stage. I can only assume you have done this since you haven't shared any code showing where you use the Player class, but here is an example of what I am referring to:
import Player;
var player:Player = new Player();
stage.addChild(player);
Also, the keyboard listener simply alters the speed variable; however the speed variable hasn't been implemented anywhere else in your code, so you won't see the difference in the GUI until this is fixed. I verified that all the listeners were working as they should using trace statements.
Related
I want to update Progress Bar with Media Player Playing. But, after start playing my progressBar fill 100% within one second while the media is 15 seconds - 5 minutes long. I can't figure out the cause.
My codes are as follows:
public static ProgressBar progress = new ProgressBar();
ObjectBinding<TimeElapsed> elapsedBinding =createElapsedBindingByBindingsAPI(player);
DoubleBinding elapsedDoubleBinding =createDoubleBindingByBindingsAPI(elapsedBinding);
progress.progressProperty().bind(elapsedDoubleBinding);
And The methods are :
public static #NotNull ObjectBinding<TimeElapsed> createElapsedBindingByBindingsAPI(
final #NotNull MediaPlayer player
) {
return Bindings.createObjectBinding(
new Callable<TimeElapsed>() {
#Override
public TimeElapsed call() throws Exception {
return new TimeElapsed(player.getCurrentTime());
}
},
player.currentTimeProperty()
);
}
public static #NotNull DoubleBinding createDoubleBindingByBindingsAPI(
final ObjectBinding<TimeElapsed> elapsedBinding
) {
return Bindings.createDoubleBinding(
new Callable<Double>() {
#Override
public Double call() throws Exception {
return elapsedBinding.getValue().getElapsed();
}
},
elapsedBinding
);
}
And the TimeElapsed class :
static class TimeElapsed {
private final double elapsed;
TimeElapsed(#NotNull Duration duration) {
elapsed = duration.toSeconds();
}
public double getElapsed() {
return elapsed;
}
}
So, what's the code changes that 1) update the progressBar with Playing, and 2) seek the song with progress bar clicked or dragged?
The progress of a ProgressBar should be, when determinate, between the values of 0.0 and 1.0 (inclusive). This means you should be dividing the current time by the total duration to get the progress and bind the progress property of the bar to that value. Note that the duration of a Media is observable and is pretty much guaranteed to be set some time after it was instantiated.
As for being able to seek when the progress bar is clicked or dragged, the simplest way—which is what I show in the example below—is to add a MOUSE_CLICKED and a MOUSE_DRAGGED handler to the progress bar, determine the ratio between the mouse's x position and the bar's width, and then seek the calculated time. Unfortunately, this setup may not exactly match up with the visuals of the progress bar because the actual "bar" is smaller than the entire space taken up by the node (at least with default styling). You would probably have to create your own control if you want "pixel perfect" behavior.
Here is a minimal example demonstrating what's discussed above:
import java.util.Optional;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.binding.Bindings;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.ProgressBar;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.StackPane;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.scene.media.MediaView;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
import javafx.util.Duration;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
var mediaView = new MediaView();
var progressBar = new ProgressBar();
progressBar.setMaxWidth(Double.MAX_VALUE);
StackPane.setAlignment(progressBar, Pos.BOTTOM_CENTER);
StackPane.setMargin(progressBar, new Insets(10));
var root = new StackPane(mediaView, progressBar);
primaryStage.setScene(new Scene(root, 1000, 650));
primaryStage.setTitle("Video Progress Demo");
primaryStage.show();
chooseMediaFile(primaryStage)
.ifPresentOrElse(
uri -> {
var media = new Media(uri);
var mediaPlayer = new MediaPlayer(media);
mediaPlayer.setAutoPlay(true);
mediaView.setMediaPlayer(mediaPlayer);
bindProgress(mediaPlayer, progressBar);
addSeekBehavior(mediaPlayer, progressBar);
},
Platform::exit);
}
private void bindProgress(MediaPlayer player, ProgressBar bar) {
var binding =
Bindings.createDoubleBinding(
() -> {
var currentTime = player.getCurrentTime();
var duration = player.getMedia().getDuration();
if (isValidDuration(currentTime) && isValidDuration(duration)) {
return currentTime.toMillis() / duration.toMillis();
}
return ProgressBar.INDETERMINATE_PROGRESS;
},
player.currentTimeProperty(),
player.getMedia().durationProperty());
bar.progressProperty().bind(binding);
}
private void addSeekBehavior(MediaPlayer player, ProgressBar bar) {
EventHandler<MouseEvent> onClickAndOnDragHandler =
e -> {
var duration = player.getMedia().getDuration();
if (isValidDuration(duration)) {
var seekTime = duration.multiply(e.getX() / bar.getWidth());
player.seek(seekTime);
e.consume();
}
};
bar.addEventHandler(MouseEvent.MOUSE_CLICKED, onClickAndOnDragHandler);
bar.addEventHandler(MouseEvent.MOUSE_DRAGGED, onClickAndOnDragHandler);
}
private boolean isValidDuration(Duration d) {
return d != null && !d.isIndefinite() && !d.isUnknown();
}
private Optional<String> chooseMediaFile(Stage owner) {
var chooser = new FileChooser();
chooser
.getExtensionFilters()
.add(new FileChooser.ExtensionFilter("Media Files", "*.mp4", "*.mp3", "*.wav"));
var file = chooser.showOpenDialog(owner);
return Optional.ofNullable(file).map(f -> f.toPath().toUri().toString());
}
}
Please excuse me I'm a complete novice at all this but I'm trying to make a game following "Brackeys How To Make A Video Game" I'm on video 8 if that helps. I can't seem to find what i have done wrong i have added my scripts for "player movement", "player collision" and "game manager". Please if there is anything else you need to help me please ask i really don't want to give up just yet was really enjoying doing this.
Thank you all
using UnityEngine;
public class PlayerMovement : MonoBehaviour {
// This is a reference to the Rigidbody component called "rb"
public Rigidbody rb;
public float forwardForce = 2000f; // Variable that determines the forward force
public float sidewaysForce = 500f; // Variable that determines the sideways force
// We marked this as "Fixed"Update because we
// are using it to mess with physics.
void FixedUpdate ()
{
// Add a forward force
rb.AddForce(0, 0, forwardForce * Time.deltaTime);
if (Input.GetKey("d")) // If the player is pressing the "d" key
{
// Add a force to the right
rb.AddForce(sidewaysForce * Time.deltaTime, 0, 0, ForceMode.VelocityChange);
}
if (Input.GetKey("a")) // If the player is pressing the "a" key
{
// Add a force to the left
rb.AddForce(-sidewaysForce * Time.deltaTime, 0, 0, ForceMode.VelocityChange);
}
if (rb.position.y < -1f)
{
FindObjectOfType<GameManager>().EndGame();
}
}
}
using UnityEngine;
public class PlayerCollision : MonoBehaviour {
public PlayerMovement movement; // A reference to our PlayerMovement script
// This function runs when we hit another object.
// We get information about the collision and call it "collisionInfo".
void OnCollisionEnter (Collision collisionInfo)
{
// We check if the object we collided with has a tag called "Obstacle".
if (collisionInfo.collider.tag == "Obstacle")
{
movement.enabled = false; // Disable the players movement.
FindObjectOfType<GameManager>().EndGame();
}
}
}
using UnityEngine;
using UnityEngine.SceneManagement;
public class GameManager : MonoBehaviour {
bool gameHasEnded = false;
public float restartDelay = 1f;
public GameObject completeLevelUI;
public void CompleteLevel ()
{
completeLevelUI.SetActive(true);
}
public void EndGame ()
{
if (gameHasEnded == false)
{
gameHasEnded = true;
Debug.Log("GAME OVER");
Invoke("Restart", restartDelay);
}
}
void Restart ()
{
SceneManager.LoadScene(SceneManager.GetActiveScene().name);
}
}
when i fall off ground:
NullReferenceException: Object reference not set to an instance of an object
PlayerMovement.FixedUpdate () (at Assets/Scripts/PlayerMovement.cs:32)
when i hit an obstacle:
NullReferenceException: Object reference not set to an instance of an object
PlayerCollision.OnCollisionEnter (UnityEngine.Collision collisionInfo) (at Assets/Scripts/PlayerCollision.cs:15)
It seems to me that FindObjectOfType<GameManager>() is returning null, which is causing a null reference exception when you attempt to call the EndGame function. This most likely means that there is no object in your scene with the GameManager component on it. The solution to this problem is simple:
Create an empty object in your scene and add the GameManager component to it. This will fix the error in this instance, but it could happen in the future if you're not careful. It is also a good idea to check if you found an object or not before calling functions on it:
GameManager gm = FindObjectOfType<GameManager>();
if (gm != null)
{
gm.EndGame();
}
Could someone please maybe download and see my project? It is very simple, but not working as in the tutorial.
In my project, I set IsTrigger to true in either the ThirdPersonController or the AIThirdPersonController for one of the characters. This makes the character fall down from the Plane.
I also changed one of the characters to be tagged as Player and changed the state from PATROL to CHASE but that changed nothing. The other player never chases/follows the player I am controlling and moving around.
Why are the players falling down when I set IsTrigger to true in my project?
I see in the video that the instructor is using a Maze Plane. Is that a package I should import in the Assets or is it already somewhere in the Assets? I just added regular Plane for now because I could not find a Maze Plane.
Here is a link for my project from my OneDrive. The file name is Demo AI.rar:
Project in OneDrive
Here is a link for the video tutorial I am attempting to follow. It is supposes to be simple I suppose:
Tutorial
Here is the BasicAi class I'm using in my project, the same script from the tutorial video:
using System.Collections;
using UnityStandardAssets.Characters.ThirdPerson;
public class BasicAi : MonoBehaviour {
public NavMeshAgent agent;
public ThirdPersonCharacter character;
public enum State {
PATROL,
CHASE
}
public State state;
private bool alive;
// Variables for patrolling
public GameObject[] waypoints;
private int waypointInd = 0;
public float patrolSpeed = 0.5f;
// Variable for chasing
public float chaseSpeed = 1f;
public GameObject target;
// Use this for initialization
void Start () {
agent = GetComponent<NavMeshAgent> ();
character = GetComponent<ThirdPersonCharacter>();
agent.updatePosition = true;
agent.updateRotation = false;
state = BasicAi.State.PATROL;
alive = true;
StartCoroutine ("FSM");
}
IEnumerator FSM()
{
while (alive)
{
switch (state)
{
case State.PATROL:
Patrol ();
break;
case State.CHASE:
Chase ();
break;
}
yield return null;
}
}
void Patrol()
{
agent.speed = patrolSpeed;
if (Vector3.Distance (this.transform.position, waypoints [waypointInd].transform.position) >= 2) {
agent.SetDestination (waypoints [waypointInd].transform.position);
character.Move (agent.desiredVelocity, false, false);
} else if (Vector3.Distance (this.transform.position, waypoints [waypointInd].transform.position) <= 2) {
waypointInd += 1;
if (waypointInd > waypoints.Length) {
waypointInd = 0;
}
}
else
{
character.Move (Vector3.zero, false, false);
}
}
void Chase()
{
agent.speed = chaseSpeed;
agent.SetDestination (target.transform.position);
character.Move (agent.desiredVelocity, false, false);
}
void OnTriggerEnter(Collider coll)
{
if (coll.tag == "Player")
{
state = BasicAi.State.CHASE;
target = coll.gameObject;
}
}
}
Once a collider is a trigger it no longer collides with objects, your best bet is to place a child object that has a collider and setting that to the trigger, this way the original collider will still collide with your ground.
As for your other question how are you referencing your third person character, are you dragging it from the scene into the inspector, and you also have to bake your navmesh into your scene. I haven't looked at your project as that would take a lot of time, but maybe go through the tutorial again and see how they reference the character. With the inbuilt characters you normally have to access the namespace first.
I'm trying to run the most basic Haxe program but keep getting errors.
The Main.hx file looks like this:
package;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.Lib;
import flixel.FlxGame;
import flixel.FlxState;
class Main extends Sprite {
var gameWidth:Int = 640; // Width of the game in pixels (might be less / more in actual pixels depending on your zoom).
var gameHeight:Int = 480; // Height of the game in pixels (might be less / more in actual pixels depending on your zoom).
var initialState:Class<FlxState> = MenuState; // The FlxState the game starts with.
var zoom:Float = -1; // If -1, zoom is automatically calculated to fit the window dimensions.
var framerate:Int = 60; // How many frames per second the game should run at.
var skipSplash:Bool = false; // Whether to skip the flixel splash screen that appears in release mode.
var startFullscreen:Bool = false; // Whether to start the game in fullscreen on desktop targets
// You can pretty much ignore everything from here on - your code should go in your states.
public static function main():Void
{
Lib.current.addChild(new Main());
}
public function new()
{
super();
if (stage != null)
{
init();
}
else
{
addEventListener(Event.ADDED_TO_STAGE, init);
}
}
private function init(?E:Event):Void
{
if (hasEventListener(Event.ADDED_TO_STAGE))
{
removeEventListener(Event.ADDED_TO_STAGE, init);
}
setupGame();
}
private function setupGame():Void
{
var stageWidth:Int = Lib.current.stage.stageWidth;
var stageHeight:Int = Lib.current.stage.stageHeight;
if (zoom == -1)
{
var ratioX:Float = stageWidth / gameWidth;
var ratioY:Float = stageHeight / gameHeight;
zoom = Math.min(ratioX, ratioY);
gameWidth = Math.ceil(stageWidth / zoom);
gameHeight = Math.ceil(stageHeight / zoom);
}
addChild(new FlxGame(gameWidth, gameHeight, initialState, zoom, framerate, framerate, skipSplash, startFullscreen));
}
}
Just the generic template file. When I run it in Terminal (running Mac OS X El Capitan), I get this error:
Main.hx:8: characters 7-21 : Type not found : flixel.FlxGame
Haven't had problems with the installations or anything and I am new to Haxe so I don't know where to start. Any ideas?
Thanks :)
Did you add the library when you try to run your game ?
You can do that by using the command line haxe -lib flixel -main Main ....
Or by writting an hxml file containing all your CLI arguments :
-lib flixel
-main Main
Update after #Gama11 comment :
HaxeFlixel used the OpenFL format for the compilation information (see http://www.openfl.org/documentation/projects/project-files/xml-format/).
So you should include include flixel library using : <haxelib name="flixel" />in your Project.xml file.
Ok, i want to add a series of images, and then be able to drag and drop each one of them. I have all of my images embedded in a class Images. s0,s1,s2 are instances of image classes. Now this is what i've done
public function Main():void
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
function init(e:Event = null):void
{
var a:Array = new Array();
var imageContainer:Sprite = new Sprite;
var imgClass:Images = new Images();
for (var i:int = 0; i < 9; i++) {
a[i].push(imgClass.(s+String(i)));
imageContainer.addChild[a[i]];
}
stage.addChild(imageContainer);
imageContainer.addEventListener(MouseEvent.MOUSE_UP, takeIt);
imageContainer.addEventListener(MouseEvent.MOUSE_DOWN, dropIt);
function takeIt(event:MouseEvent) {
event.currentTarget.startDrag();
}
function dropIt(event:MouseEvent) {
event.currentTarget.stopDrag();
}
}
}
I have rewritten your code a bit, but I have not been able to test it sorry.
The first think I notices is that your init method was inside your Main method. Then your takeIt and dropIt method were inside the init. I am not to sure if that would actually work, but I have fixed it up in the code below.
In my code I assume that the image instances you have in the Images class are instances of Bitmap. This means that inside the for loop I had to add each one to a Sprite so you have access to startDrag and stopDrag. I listen for the MOUSE_DOWN event on each image, and set the image to the selectedImage var and do startDrag. I also listen for the MOUSE_UP on the stage, and drop the currentImage.
package
{
import flash.display.Bitmap;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
public class Main extends Sprite
{
private var selectedImage:Sprite;
public function Main():void
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
var imageContainer:Sprite = new Sprite();
var imgClass:Images = new Images();
for (var i:int = 0; i < 9; i++)
{
var imgInstance:Bitmap = imgClass['s' + i.toString()] as Bitmap;
var imgSprite:Sprite = new Sprite();
imgSprite.addChild(imgInstance); // Put image in a sprite so we can use startDrag on it.
imageContainer.addChild(imgSprite);
imgInstance.addEventListener(MouseEvent.MOUSE_DOWN, img_mouseDownHandler);
}
addChild(imageContainer);
stage.addEventListener(MouseEvent.MOUSE_UP, stage_mouseUpHandler);
}
private function dropSelectedImage():void
{
if (selectedImage)
{
selectedImage.stopDrag();
}
}
private function img_mouseDownHandler(e:MouseEvent):void
{
dropSelectedImage();
selectedImage = e.currentTarget as Sprite;
selectedImage.startDrag();
}
private function stage_mouseUpHandler(e:MouseEvent):void
{
dropSelectedImage();
}
}
}
To build your images in a loop you could also just manually build the array, then loop through the array like so:
var images:Array = [imgClass.s0, imgClass.s1, imgClass.s2, imgClass.s3, imgClass.s4, imgClass.s5, imgClass.s6, imgClass.s7, imgClass.s8];
for each (var img:Bitmap in images)
{
var imgSprite:Sprite = new Sprite();
imgSprite.addChild(img); // Put image in a sprite so we can use startDrag on it.
imageContainer.addChild(imgSprite);
imgInstance.addEventListener(MouseEvent.MOUSE_DOWN, img_mouseDownHandler);
}
Hope this help. Feel free to ask me to elaborate or explain anything else in the comments.