I am in need of some help making custom sliders, sort of like the ones you would use for volume buttons. I have one but it's not multi usable; as soon as I add more than one the ones before stop working, and I don't think I can use local variables because I need to use event listeners for the scrubber to slide.
All I am asking is if someone can please put a code for a multi usable slider with explanation on how it works so I can learn from it. I can show the code I am using right now but its probably useless.
public function createSlider(x:Number, y:Number, parent:DisplayObjectContainer) : void {
this.slider = new Sprite();
this.slider.graphics.beginFill(0xFFFFFF);
this.slider.graphics.drawCircle(x, y, 7);
this.slider.graphics.endFill();
this.bar = makeRoundedRect(x - 6, y - 6, 100, 11, 0xCCCCCC, 1, [10, 10, 10, 10]);
parent.addChild(bar);
parent.addChild(slider);
this.slider.addEventListener(MouseEvent.MOUSE_OVER, sliderHover);
}
private function sliderHover(e:MouseEvent) : void
{
this.slider.addEventListener(MouseEvent.MOUSE_DOWN, sliderDown);
}
private function sliderDown(e:MouseEvent) : void {
this.slider.addEventListener(MouseEvent.MOUSE_MOVE, sliderMove);
this.slider.addEventListener(MouseEvent.MOUSE_UP, sliderDone);
this.slider.addEventListener(MouseEvent.MOUSE_OUT, sliderDone);
}
private function sliderMove(e:MouseEvent) : void {
this.slider.addEventListener(MouseEvent.MOUSE_DOWN, sliderDown);
this.slider.removeEventListener(MouseEvent.MOUSE_MOVE, sliderMove);
this.slider.startDrag(false, new Rectangle(0, slider.y, 90, 0));
}
private function sliderDone(e:MouseEvent) : void {
this.temp_mouseCurX = Math.abs(this.slider.x + 10);
trace(this.temp_mouseCurX);
this.slider.stopDrag();
}
It's using a private variable which I know shouldn't be good for what I am trying to do.
You should try using e.currentTarget. instead of this.slider.
Related
void OnTriggerEnter(Collider other)
{
if (other.gameObject.CompareTag ("HealthPickUp"))
{
m_CurrentHealth += amount;
other.gameObject.SetActive (false);
SetHealthUI ();
}
if (m_CurrentHealth <= 0f && !m_Dead)
{
OnDeath ();
}
}
trying to get it that if the tank hits the pick up item it will gain 20 pointa but as of right now ive got no clue what to do
To get collisions working in Unity, you need to do the following:
Attach a Collider component to each object you want to be part of the collision. This can be a BoxCollider, SphereCollider, etc. Whatever shape makes sense.
For trigger collisions (i.e. non-physics collisions), enable the Is Trigger value in the inspector on each collider component you created in step 1.
Attach a RigidBody component to the object you want to be colliding into other things. RigidBody components are expensive, and you don't want them all over the scene, so I would suggest you put it on your Tank. You may also have to turn on the Is Kinematic property, otherwise your Tank may behave improperly (it's hard to tell with such little information in your setup).
Attach a script to your Tank that has implemented the method OnTriggerEnter. An example is below.
(Optional, strongly recommended) I would suggest you create another script and attach it to your health pickup. I will demonstrate with an example below.
(Optional) You can use layer based collisions to filter what kinds of collisions you detect to make it more efficient.
public class Tank : MonoBehaviour
{
// Setup the initial health values in the editor.
[SerializeField] private int _initialHealth = 100;
[SerializeField] private int _maxHealth = 100;
private int _health = -1;
private void Awake()
{
_health = _initialHealth;
}
private void Update()
{
// You probably want to check this in Update, since you want the tank
// to die as soon as it happens, not just when you pick up a piece of health.
if (_health <= 0)
{
OnDeath();
}
}
private void OnDeath()
{
// Your death logic.
}
private void OnTriggerEnter(Collider other)
{
if (other.gameObject.CompareTag("HealthPickup"))
{
// Get the HealthPickup component and then add the amount to the tank's
// health. This is more robust because you can now create HealthPickup
// objects with a variable amount of health.
HealthPickup healthPickup = other.gameObject.GetComponent<HealthPickup>();
if (healthPickup != null)
{
_health = Mathf.Clamp(_health + healthPickup.amount, 0, _maxHealth);
healthPickup.OnPickup();
}
}
}
}
public class HealthPickup : MonoBehaviour
{
[SerializeField] private int _amount = default;
public int amount { get { return _amount; } }
public void OnPickup()
{
Destroy(gameObject);
}
}
If you follow these steps, you should have collisions working and a flexible system for giving your Tank health pickups.
When I was using absolute layout my objects where appearing but I couldnt move them so I changed the layout to null and now my objects dont even appear. Please help.
Havent tried much, not sure what to try.
try {
enemies = new LinkedList<>();
frame = new JFrame();
frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE);
frame.setLayout(null);
frame.getContentPane().setBackground(Color.black);
frame.setPreferredSize(new Dimension(800, 800));
ActionListener spawnEnemies = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
spawnEnemies();
}
};
ActionListener moveEnemies = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
moveEnemies();
}
};
spawner = new Timer(50000, spawnEnemies);
spawner.start();
mover = new Timer(10, moveEnemies);
mover.start();
addKeyListener(new KeyInput(this));
player = new PlayerObj("white", 399, 399, frame);
player.setPreferredSize(new Dimension(50, 50));
//AddActionEvent, Keylogging, OnbuttonPress, Autogenerating enemies, timers.
frame.getContentPane().add(player);
spawnEnemies();
frame.revalidate();
frame.repaint();
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
} catch (IOException ex) {
Logger.getLogger(Game.class.getName()).log(Level.SEVERE, null, ex);
}
I am not sure what do you want with the code, but I assume you want to display enemies/players at specified locations on screen. I personally don't decommend using Components added to a JFrame to display that. This means with no layout, the JFrame will have no idea how to place these objects.
Here is an other way that will solve your problem, howewer it is a totally different approach.
You have to create a JFrame, and set its content pane to a new JPanel(recommended to extend your class from JPanel and adding itself to the JFrame, it can make things easier).
Then, you override the repaint method, by creating the following:
protected void paintComponent(Graphics g){
}
When you call the repaint() method, it will run this code. So inside here, you can paint whatewer and wherever you want (inside you JPanel). And you don't have to mess with the Layout, just leave it as default.
Examples for painting:
g.setColor(Color.blue);
g.fillRect(50,50,120,120);
//
g.drawImage(yourImage,100,100,this);
all. I have kind of a doozy of a problem, that could be solved really simply, if I just wanted to duplicate the code. I mean, really, it's a small part of a project that I'm doing just to see if I can, more than anything else, but it is bothering me since I've thought it up.
The Project
For fun, I've decided to take someone's ActionScript 3, text-based game engine and convert it to TypeScript and ultimately JavaScript using PixiJS.
The thing is, there are still 20213 errors to be fixed running tsc, so I could just leave this to a later date. But I was working on the Button class, which they defined as a subclass of MovieClip. That's fine; I just responded by reading up on PIXI buttons, and they seem fairly straightforward. Just, in the button's constructor, add something akin to the following lines:
export class Button extends PIXI.Sprite {
private _callback : Function;
private _height : number;
private _width : number;
public get callback() : Function { return this._callback; }
public set callback(fn : Function) {this._callback = fn; }
public get height() : number { return this._height; }
public set height(h : number) {this._height = h; }
public get width() : number {return this._width; }
public set width(w : number) {this._width = w; }
public constructor(width = 180, height = 90, callback: Function = null){
super(new PIXI.Texture(new PIXI.BaseTexture(GLOBAL.BTN_BACK, PIXI.SCALE_MODES.NEAREST)));
this.callback = callback;
this.width = width;
this.height = height;
this.buttonMode = true;
this.interactive = true;
this.anchor.set(0.5);
this.on('mousedown', this.callback)
.on('touchstart', this.callback);
}
}
That's a bit of a simplified version, and the version I did on Codepen uses a Container and a private _sprite field instead (as well as a ColorMatrixFilter that doesn't work too well on the black icons I picked out, but that's not really important for this question), but that's roughly the gist of how it's done.
The Problem
The problem is that, in the codepen, I'd like to do the following:
// assign `this.callback` to each of the following events:
let that = this;
['click','mousedown','touchstart'].map(evt => that.on(evt, that.callback});
with a simple call being passed in their constructors elsewhere:
for (let n = 0; n < 5; ++n){
btnArray.push(new Button(16, 16, () => console.info('You pushed button %d', n)));
}
but I'm not getting anything from them, even in the Chrome Console. I even logged that ColorMatrixFilter I mentioned earlier, to see if it was console.info that was wrong. Nope. So now, I'm confused on that. I was hoping to be able to just make a GLOBAL (a legacy static object from the AS source) key to iterate through for the events, but it looks like that's not happening.
The Questions
Is what I'm trying to do feasible, if odd? Is it blocked by a security feature (for which I'd be grateful)? If not, what am I doing wrong?
Should I even worry about setting all these different event handlers, or is just listening to click enough?
When an arrow function like your event map is executed the this context is not set, so any code that references this is going to get the current value, including any functions your map calls.
Replace your event map with the following:
['click','mousedown','touchstart'].map(function(evt) { that.on(evt, that.callback} } );
A demonstration:
function Named(x) {
this.name = x;
}
var foo = new Named("foo");
var bar = new Named("bar");
var showFunc = function show() {
// this is context dependant
console.log(this.name);
}
var showArrow;
// this is the window
showArrow = () => console.log(this.name);
var fooShowArrow;
(function() {
// this is foo
that = this;
fooShowArrow = () => console.log(that.name);
}).apply(foo);
var example = function(func) {
// For the demo, at this point, this will always be bar
func.apply(this, [ "arbitrary value" ]);
}
// explicitly set the current "this" to bar for the execution of these functions
example.apply(bar, [showFunc]); // works
example.apply(bar, [showArrow]); // fails, this is still the window
example.apply(bar, [fooShowArrow]); // fails, this is still foo
I have a script called Death which re spawns the player at the beginning location when the collision is true. I am trying to make a score count that when this collision is true it will minus 100 points but have been unsuccessful. The script bellow if from the score and death script. Any help would be much appreciated.
Score script:
var gui : GameObject;
static var score : int;
Death.death = false;
function Start ()
{
gui.GetComponent ("GUIText").text = "Score: 0";
}
function Update ()
{
gui.GetComponent ("GUIText").text = "Score: " + score;
if (death)
{
score = score - 100;
}
}
Death Script:
#pragma strict
var Ball : Transform;
public var death : boolean = false;
function OnCollisionEnter (b : Collision)
{
if (b.gameObject.tag == "Ball")
{
death = true;
Ball.transform.position.x = 1.6;
Ball.transform.position.y = 1.5;
Ball.transform.position.z = 1.1;
Ball.GetComponent.<Rigidbody>().velocity.y = 0;
Ball.GetComponent.<Rigidbody>().velocity.x = 0;
Ball.GetComponent.<Rigidbody>().velocity.z = 0;
}
}
I hope, that I can help you even though I'm using C#. It should be very easy to translate this to UnityScript.
using UnityEngine;
public class Score : MonoBehaviour
{
public GUIText guiText;
int score;
void Update()
{
if(DeathTrigger.wasTriggered)
{
DeathTrigger.wasTriggered = false;
score -= 100;
}
guiText.text = string.Format("Score: {0}", score);
}
}
public class DeathTrigger : MonoBehaviour
{
public static bool wasTriggered;
void OnCollisionEnter(Collision other)
{
if (other.gameObject.CompareTag("Ball"))
{
wasTriggered = true;
// ...
}
}
}
I assume this is a beginner's questions, so I won't say anything about how static variables are evil and so on, but I still want to post an example of where to go next for a better approach:
using System;
using UnityEngine;
using UnityEngine.UI;
public class BetterDeathTrigger : MonoBehaviour
{
// This event will be called when death is triggered.
public static event Action wasTriggered;
void OnCollisionEnter(Collision other)
{
if (other.gameObject.CompareTag("Ball"))
{
// Call the event.
if (wasTriggered != null)
wasTriggered();
// ...
}
}
}
public class BetterScore : MonoBehaviour
{
public Text uiText; // Unity 4.6 UI system
int score;
void Start()
{
// Subscribe to the event.
BetterDeathTrigger.wasTriggered += WasTriggered_Handler;
}
// This method will now be called everytime the event is called from the DeathTrigger.
private void WasTriggered_Handler()
{
score -= 100;
uiText.text = string.Format("Score: {0}", score);
}
}
A couple of things:
GUIText is pretty old and was already replaced by the new UI system since Unity version 4.6
Static variables are not smart in the long run, prefer instances of objects unless you are very sure how statics work
This is good example of where to use events. Again, it being static might lead to problems but for the first example it's the easiest.
The Unity Learn site offers a lot of tutorials about programming concepts such as "Communicating between scripts", they also have basic game examples where you can follow along with a complete project.
It's definitely worth trying what Xarbrough suggested to go with instead. Statics can be confusing and get in the way in the long run. But here's how you can do it, written in Javascript.
public class Death { // you can change the class name to something that is broad enough to hold several public static variables
public static var death : boolean;
}//This will end this class. When you make public classes like this, the script doesnt even need to be attached to a object, because it doesn't use Mono behavior
//This would be the actual DeathScript, whats above is technically not part of the Death script
var Ball : Transform;
function OnCollisionEnter (b : Collision) {
if (b.gameObject.tag == "Ball"){
Death.death = true;
Ball.transform.position.x = 1.6;
Ball.transform.position.y = 1.5;
Ball.transform.position.z = 1.1;
Ball.GetComponent.<Rigidbody>().velocity.y = 0;
Ball.GetComponent.<Rigidbody>().velocity.x = 0;
Ball.GetComponent.<Rigidbody>().velocity.z = 0;
} }
From there, anytime you want to access the static variable, just tell it where to look. Death.death.
Hope this helps!
I have started to dig in to C++ and Qt again, and have been mucking around with the WebKit Javascript/Qt bindings. I've got all the moving parts working, with the exception of my QObject subclass being "undefined" on the Javascript side. Here's the simple test app I'm having trouble with:
My main window implementation:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
// instantiate a webview
QWebView *webview = new QWebView(this);
webview->setGeometry(0, 0, 400, 300);
webview->setUrl(QUrl("file://localhost/Users/kyle/Sites/tests/qt/index.html"));
// instantiate and attach our QObject
hello *h = new hello();
QWebFrame *frame = webview->page()->mainFrame();
frame->addToJavaScriptWindowObject("Hello", h);
// show the window
webview->show();
}
Hello.cpp
...snip...
QString hello::say()
{
return QString("Kyle");
}
Hello.h
...snip includes...
class hello : public QObject
{
Q_OBJECT
public:
hello();
Q_INVOKABLE QString say();
};
The above-mentioned index.html file does a simple alert(Hello.say()) call, but doing typeof Hello, I get undefined.
I'm a bit rusty with C++, and pretty new to Qt, so I'm sure this is a noob mistake, but I'm stumped.
Objects can't be inserted in the page at any time. You should put that line:
frame->addToJavaScriptWindowObject("Hello", h);
in a slot connected to the javaScriptWindowObjectCleared() signal of the QWebFrame and move some code around, so you can access the frame from that slot.
See also the Form Extractor example included with Qt.
The core of this is really implemented in two methods, which are
shown below:
void MyApi::setWebView( QWebView *view )
{
QWebPage *page = view->page();
frame = page->mainFrame();
attachObject();
connect(frame, &QWebFrame::javaScriptWindowObjectCleared, this, &MyApi::attachObject);
// old approach
//connect( frame, SIGNAL(javaScriptWindowObjectCleared()), this, SLOT(attachObject()) );
}
void MyApi::attachObject()
{
frame->addToJavaScriptWindowObject( QString("MyApi"), this );
}
This code is all that you need in order to make all of the public slots of the
MyApi object visible to javascript. The MyApi class provides two public slots:
public slots:
void doSomething( const QString ¶m );
int doSums( int a, int b );
The first slot simply logs a message to the debug output, the second returns
the sum of its two arguments (yes, slots can return things!). They're called
from javascript like this:
MyApi.doSomething( 'Hello from JS page 2!!!!' );
sum = MyApi.doSums( 2, 3 );
alert( 'C++ says the sum is ' + sum );
The code above was tested in QT5.5, and please note all methods should be put in "public slots" section.